index.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214
  1. #!/usr/bin/env node
  2. "use strict";
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. const _path = /*#__PURE__*/ _interopRequireDefault(require("path"));
  7. const _arg = /*#__PURE__*/ _interopRequireDefault(require("arg"));
  8. const _fs = /*#__PURE__*/ _interopRequireDefault(require("fs"));
  9. const _build = require("./build");
  10. const _help = require("./help");
  11. const _init = require("./init");
  12. function _interopRequireDefault(obj) {
  13. return obj && obj.__esModule ? obj : {
  14. default: obj
  15. };
  16. }
  17. // ---
  18. function oneOf(...options) {
  19. return Object.assign((value = true)=>{
  20. for (let option of options){
  21. let parsed = option(value);
  22. if (parsed === value) {
  23. return parsed;
  24. }
  25. }
  26. throw new Error("...");
  27. }, {
  28. manualParsing: true
  29. });
  30. }
  31. let commands = {
  32. init: {
  33. run: _init.init,
  34. args: {
  35. "--esm": {
  36. type: Boolean,
  37. description: `Initialize configuration file as ESM`
  38. },
  39. "--ts": {
  40. type: Boolean,
  41. description: `Initialize configuration file as TypeScript`
  42. },
  43. "--full": {
  44. type: Boolean,
  45. description: `Include the default values for all options in the generated configuration file`
  46. },
  47. "-f": "--full"
  48. }
  49. },
  50. build: {
  51. run: _build.build,
  52. args: {
  53. "--input": {
  54. type: String,
  55. description: "Input file"
  56. },
  57. "--output": {
  58. type: String,
  59. description: "Output file"
  60. },
  61. "--watch": {
  62. type: oneOf(String, Boolean),
  63. description: "Watch for changes and rebuild as needed"
  64. },
  65. "--poll": {
  66. type: Boolean,
  67. description: "Use polling instead of filesystem events when watching"
  68. },
  69. "--content": {
  70. type: String,
  71. description: "Content paths to use for removing unused classes"
  72. },
  73. "--minify": {
  74. type: Boolean,
  75. description: "Minify the output"
  76. },
  77. "--config": {
  78. type: String,
  79. description: "Path to a custom config file"
  80. },
  81. "-c": "--config",
  82. "-i": "--input",
  83. "-o": "--output",
  84. "-m": "--minify",
  85. "-w": "--watch",
  86. "-p": "--poll"
  87. }
  88. }
  89. };
  90. let sharedFlags = {
  91. "--help": {
  92. type: Boolean,
  93. description: "Display usage information"
  94. },
  95. "-h": "--help"
  96. };
  97. if (process.stdout.isTTY /* Detect redirecting output to a file */ && (process.argv[2] === undefined || process.argv.slice(2).every((flag)=>sharedFlags[flag] !== undefined))) {
  98. (0, _help.help)({
  99. usage: [
  100. "tailwindcss [--input input.css] [--output output.css] [--watch] [options...]",
  101. "tailwindcss init [--full] [options...]"
  102. ],
  103. commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`),
  104. options: {
  105. ...commands.build.args,
  106. ...sharedFlags
  107. }
  108. });
  109. process.exit(0);
  110. }
  111. let command = ((arg = "")=>arg.startsWith("-") ? undefined : arg)(process.argv[2]) || "build";
  112. if (commands[command] === undefined) {
  113. if (_fs.default.existsSync(_path.default.resolve(command))) {
  114. // TODO: Deprecate this in future versions
  115. // Check if non-existing command, might be a file.
  116. command = "build";
  117. } else {
  118. (0, _help.help)({
  119. message: `Invalid command: ${command}`,
  120. usage: [
  121. "tailwindcss <command> [options]"
  122. ],
  123. commands: Object.keys(commands).filter((command)=>command !== "build").map((command)=>`${command} [options]`),
  124. options: sharedFlags
  125. });
  126. process.exit(1);
  127. }
  128. }
  129. // Execute command
  130. let { args: flags , run } = commands[command];
  131. let args = (()=>{
  132. try {
  133. let result = (0, _arg.default)(Object.fromEntries(Object.entries({
  134. ...flags,
  135. ...sharedFlags
  136. }).filter(([_key, value])=>{
  137. var _value_type;
  138. return !(value === null || value === void 0 ? void 0 : (_value_type = value.type) === null || _value_type === void 0 ? void 0 : _value_type.manualParsing);
  139. }).map(([key, value])=>[
  140. key,
  141. typeof value === "object" ? value.type : value
  142. ])), {
  143. permissive: true
  144. });
  145. // Manual parsing of flags to allow for special flags like oneOf(Boolean, String)
  146. for(let i = result["_"].length - 1; i >= 0; --i){
  147. let flag = result["_"][i];
  148. if (!flag.startsWith("-")) continue;
  149. let [flagName, flagValue] = flag.split("=");
  150. let handler = flags[flagName];
  151. // Resolve flagName & handler
  152. while(typeof handler === "string"){
  153. flagName = handler;
  154. handler = flags[handler];
  155. }
  156. if (!handler) continue;
  157. let args = [];
  158. let offset = i + 1;
  159. // --flag value syntax was used so we need to pull `value` from `args`
  160. if (flagValue === undefined) {
  161. // Parse args for current flag
  162. while(result["_"][offset] && !result["_"][offset].startsWith("-")){
  163. args.push(result["_"][offset++]);
  164. }
  165. // Cleanup manually parsed flags + args
  166. result["_"].splice(i, 1 + args.length);
  167. // No args were provided, use default value defined in handler
  168. // One arg was provided, use that directly
  169. // Multiple args were provided so pass them all in an array
  170. flagValue = args.length === 0 ? undefined : args.length === 1 ? args[0] : args;
  171. } else {
  172. // Remove the whole flag from the args array
  173. result["_"].splice(i, 1);
  174. }
  175. // Set the resolved value in the `result` object
  176. result[flagName] = handler.type(flagValue, flagName);
  177. }
  178. // Ensure that the `command` is always the first argument in the `args`.
  179. // This is important so that we don't have to check if a default command
  180. // (build) was used or not from within each plugin.
  181. //
  182. // E.g.: tailwindcss input.css -> _: ['build', 'input.css']
  183. // E.g.: tailwindcss build input.css -> _: ['build', 'input.css']
  184. if (result["_"][0] !== command) {
  185. result["_"].unshift(command);
  186. }
  187. return result;
  188. } catch (err) {
  189. if (err.code === "ARG_UNKNOWN_OPTION") {
  190. (0, _help.help)({
  191. message: err.message,
  192. usage: [
  193. "tailwindcss <command> [options]"
  194. ],
  195. options: sharedFlags
  196. });
  197. process.exit(1);
  198. }
  199. throw err;
  200. }
  201. })();
  202. if (args["--help"]) {
  203. (0, _help.help)({
  204. options: {
  205. ...flags,
  206. ...sharedFlags
  207. },
  208. usage: [
  209. `tailwindcss ${command} [options]`
  210. ]
  211. });
  212. process.exit(0);
  213. }
  214. run(args);