index.js 7.8 KB

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