Нет описания

cli.js 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }/* eslint-disable no-console */
  2. var _commander = require('commander'); var _commander2 = _interopRequireDefault(_commander);
  3. var _glob = require('glob'); var _glob2 = _interopRequireDefault(_glob);
  4. var _fs = require('mz/fs');
  5. var _path = require('path');
  6. var _util = require('util');
  7. var _index = require('./index');
  8. const glob = _util.promisify.call(void 0, _glob2.default);
  9. function run() {
  10. _commander2.default
  11. .description(`Sucrase: super-fast Babel alternative.`)
  12. .usage("[options] <srcDir>")
  13. .option(
  14. "-d, --out-dir <out>",
  15. "Compile an input directory of modules into an output directory.",
  16. )
  17. .option(
  18. "-p, --project <dir>",
  19. "Compile a TypeScript project, will read from tsconfig.json in <dir>",
  20. )
  21. .option("--out-extension <extension>", "File extension to use for all output files.", "js")
  22. .option("--exclude-dirs <paths>", "Names of directories that should not be traversed.")
  23. .option("-t, --transforms <transforms>", "Comma-separated list of transforms to run.")
  24. .option("-q, --quiet", "Don't print the names of converted files.")
  25. .option(
  26. "--enable-legacy-typescript-module-interop",
  27. "Use default TypeScript ESM/CJS interop strategy.",
  28. )
  29. .option("--enable-legacy-babel5-module-interop", "Use Babel 5 ESM/CJS interop strategy.")
  30. .option("--jsx-pragma <string>", "Element creation function, defaults to `React.createElement`")
  31. .option("--jsx-fragment-pragma <string>", "Fragment component, defaults to `React.Fragment`")
  32. .option("--production", "Disable debugging information from JSX in output.")
  33. .parse(process.argv);
  34. if (_commander2.default.project) {
  35. if (
  36. _commander2.default.outDir ||
  37. _commander2.default.transforms ||
  38. _commander2.default.args[0] ||
  39. _commander2.default.enableLegacyTypescriptModuleInterop
  40. ) {
  41. console.error(
  42. "If TypeScript project is specified, out directory, transforms, source " +
  43. "directory, and --enable-legacy-typescript-module-interop may not be specified.",
  44. );
  45. process.exit(1);
  46. }
  47. } else {
  48. if (!_commander2.default.outDir) {
  49. console.error("Out directory is required");
  50. process.exit(1);
  51. }
  52. if (!_commander2.default.transforms) {
  53. console.error("Transforms option is required.");
  54. process.exit(1);
  55. }
  56. if (!_commander2.default.args[0]) {
  57. console.error("Source directory is required.");
  58. process.exit(1);
  59. }
  60. }
  61. const options = {
  62. outDirPath: _commander2.default.outDir,
  63. srcDirPath: _commander2.default.args[0],
  64. project: _commander2.default.project,
  65. outExtension: _commander2.default.outExtension,
  66. excludeDirs: _commander2.default.excludeDirs ? _commander2.default.excludeDirs.split(",") : [],
  67. quiet: _commander2.default.quiet,
  68. sucraseOptions: {
  69. transforms: _commander2.default.transforms ? _commander2.default.transforms.split(",") : [],
  70. enableLegacyTypeScriptModuleInterop: _commander2.default.enableLegacyTypescriptModuleInterop,
  71. enableLegacyBabel5ModuleInterop: _commander2.default.enableLegacyBabel5ModuleInterop,
  72. jsxPragma: _commander2.default.jsxPragma || "React.createElement",
  73. jsxFragmentPragma: _commander2.default.jsxFragmentPragma || "React.Fragment",
  74. production: _commander2.default.production,
  75. },
  76. };
  77. buildDirectory(options).catch((e) => {
  78. process.exitCode = 1;
  79. console.error(e);
  80. });
  81. } exports.default = run;
  82. async function findFiles(options) {
  83. const outDirPath = options.outDirPath;
  84. const srcDirPath = options.srcDirPath;
  85. const extensions = options.sucraseOptions.transforms.includes("typescript")
  86. ? [".ts", ".tsx"]
  87. : [".js", ".jsx"];
  88. if (!(await _fs.exists.call(void 0, outDirPath))) {
  89. await _fs.mkdir.call(void 0, outDirPath);
  90. }
  91. const outArr = [];
  92. for (const child of await _fs.readdir.call(void 0, srcDirPath)) {
  93. if (["node_modules", ".git"].includes(child) || options.excludeDirs.includes(child)) {
  94. continue;
  95. }
  96. const srcChildPath = _path.join.call(void 0, srcDirPath, child);
  97. const outChildPath = _path.join.call(void 0, outDirPath, child);
  98. if ((await _fs.stat.call(void 0, srcChildPath)).isDirectory()) {
  99. const innerOptions = {...options};
  100. innerOptions.srcDirPath = srcChildPath;
  101. innerOptions.outDirPath = outChildPath;
  102. const innerFiles = await findFiles(innerOptions);
  103. outArr.push(...innerFiles);
  104. } else if (extensions.some((ext) => srcChildPath.endsWith(ext))) {
  105. const outPath = outChildPath.replace(/\.\w+$/, `.${options.outExtension}`);
  106. outArr.push({
  107. srcPath: srcChildPath,
  108. outPath,
  109. });
  110. }
  111. }
  112. return outArr;
  113. }
  114. async function runGlob(options) {
  115. const tsConfigPath = _path.join.call(void 0, options.project, "tsconfig.json");
  116. let str;
  117. try {
  118. str = await _fs.readFile.call(void 0, tsConfigPath, "utf8");
  119. } catch (err) {
  120. console.error("Could not find project tsconfig.json");
  121. console.error(` --project=${options.project}`);
  122. console.error(err);
  123. process.exit(1);
  124. }
  125. const json = JSON.parse(str);
  126. const foundFiles = [];
  127. const files = json.files;
  128. const include = json.include;
  129. const absProject = _path.join.call(void 0, process.cwd(), options.project);
  130. const outDirs = [];
  131. if (!(await _fs.exists.call(void 0, options.outDirPath))) {
  132. await _fs.mkdir.call(void 0, options.outDirPath);
  133. }
  134. if (files) {
  135. for (const file of files) {
  136. if (file.endsWith(".d.ts")) {
  137. continue;
  138. }
  139. if (!file.endsWith(".ts") && !file.endsWith(".js")) {
  140. continue;
  141. }
  142. const srcFile = _path.join.call(void 0, absProject, file);
  143. const outFile = _path.join.call(void 0, options.outDirPath, file);
  144. const outPath = outFile.replace(/\.\w+$/, `.${options.outExtension}`);
  145. const outDir = _path.dirname.call(void 0, outPath);
  146. if (!outDirs.includes(outDir)) {
  147. outDirs.push(outDir);
  148. }
  149. foundFiles.push({
  150. srcPath: srcFile,
  151. outPath,
  152. });
  153. }
  154. }
  155. if (include) {
  156. for (const pattern of include) {
  157. const globFiles = await glob(_path.join.call(void 0, absProject, pattern));
  158. for (const file of globFiles) {
  159. if (!file.endsWith(".ts") && !file.endsWith(".js")) {
  160. continue;
  161. }
  162. if (file.endsWith(".d.ts")) {
  163. continue;
  164. }
  165. const relativeFile = _path.relative.call(void 0, absProject, file);
  166. const outFile = _path.join.call(void 0, options.outDirPath, relativeFile);
  167. const outPath = outFile.replace(/\.\w+$/, `.${options.outExtension}`);
  168. const outDir = _path.dirname.call(void 0, outPath);
  169. if (!outDirs.includes(outDir)) {
  170. outDirs.push(outDir);
  171. }
  172. foundFiles.push({
  173. srcPath: file,
  174. outPath,
  175. });
  176. }
  177. }
  178. }
  179. for (const outDirPath of outDirs) {
  180. if (!(await _fs.exists.call(void 0, outDirPath))) {
  181. await _fs.mkdir.call(void 0, outDirPath);
  182. }
  183. }
  184. // TODO: read exclude
  185. return foundFiles;
  186. }
  187. async function updateOptionsFromProject(options) {
  188. /**
  189. * Read the project information and assign the following.
  190. * - outDirPath
  191. * - transform: imports
  192. * - transform: typescript
  193. * - enableLegacyTypescriptModuleInterop: true/false.
  194. */
  195. const tsConfigPath = _path.join.call(void 0, options.project, "tsconfig.json");
  196. let str;
  197. try {
  198. str = await _fs.readFile.call(void 0, tsConfigPath, "utf8");
  199. } catch (err) {
  200. console.error("Could not find project tsconfig.json");
  201. console.error(` --project=${options.project}`);
  202. console.error(err);
  203. process.exit(1);
  204. }
  205. const json = JSON.parse(str);
  206. const sucraseOpts = options.sucraseOptions;
  207. if (!sucraseOpts.transforms.includes("typescript")) {
  208. sucraseOpts.transforms.push("typescript");
  209. }
  210. const compilerOpts = json.compilerOptions;
  211. if (compilerOpts.outDir) {
  212. options.outDirPath = _path.join.call(void 0, process.cwd(), options.project, compilerOpts.outDir);
  213. }
  214. if (compilerOpts.esModuleInterop !== true) {
  215. sucraseOpts.enableLegacyTypeScriptModuleInterop = true;
  216. }
  217. if (compilerOpts.module === "commonjs") {
  218. if (!sucraseOpts.transforms.includes("imports")) {
  219. sucraseOpts.transforms.push("imports");
  220. }
  221. }
  222. }
  223. async function buildDirectory(options) {
  224. let files;
  225. if (options.outDirPath && options.srcDirPath) {
  226. files = await findFiles(options);
  227. } else if (options.project) {
  228. await updateOptionsFromProject(options);
  229. files = await runGlob(options);
  230. } else {
  231. console.error("Project or Source directory required.");
  232. process.exit(1);
  233. }
  234. for (const file of files) {
  235. await buildFile(file.srcPath, file.outPath, options);
  236. }
  237. }
  238. async function buildFile(srcPath, outPath, options) {
  239. if (!options.quiet) {
  240. console.log(`${srcPath} -> ${outPath}`);
  241. }
  242. const code = (await _fs.readFile.call(void 0, srcPath)).toString();
  243. const transformedCode = _index.transform.call(void 0, code, {...options.sucraseOptions, filePath: srcPath}).code;
  244. await _fs.writeFile.call(void 0, outPath, transformedCode);
  245. }