swc.js 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.createSwcOptions = exports.targetMapping = exports.create = void 0;
  4. const ts_internals_1 = require("../ts-internals");
  5. function create(createOptions) {
  6. const { swc, service: { config, projectLocalResolveHelper }, transpilerConfigLocalResolveHelper, nodeModuleEmitKind, } = createOptions;
  7. // Load swc compiler
  8. let swcInstance;
  9. // Used later in diagnostics; merely needs to be human-readable.
  10. let swcDepName = 'swc';
  11. if (typeof swc === 'string') {
  12. swcDepName = swc;
  13. swcInstance = require(transpilerConfigLocalResolveHelper(swc, true));
  14. }
  15. else if (swc == null) {
  16. let swcResolved;
  17. try {
  18. swcDepName = '@swc/core';
  19. swcResolved = transpilerConfigLocalResolveHelper(swcDepName, true);
  20. }
  21. catch (e) {
  22. try {
  23. swcDepName = '@swc/wasm';
  24. swcResolved = transpilerConfigLocalResolveHelper(swcDepName, true);
  25. }
  26. catch (e) {
  27. throw new Error('swc compiler requires either @swc/core or @swc/wasm to be installed as a dependency. See https://typestrong.org/ts-node/docs/transpilers');
  28. }
  29. }
  30. swcInstance = require(swcResolved);
  31. }
  32. else {
  33. swcInstance = swc;
  34. }
  35. // Prepare SWC options derived from typescript compiler options
  36. const { nonTsxOptions, tsxOptions } = createSwcOptions(config.options, nodeModuleEmitKind, swcInstance, swcDepName);
  37. const transpile = (input, transpileOptions) => {
  38. const { fileName } = transpileOptions;
  39. const swcOptions = fileName.endsWith('.tsx') || fileName.endsWith('.jsx') ? tsxOptions : nonTsxOptions;
  40. const { code, map } = swcInstance.transformSync(input, {
  41. ...swcOptions,
  42. filename: fileName,
  43. });
  44. return { outputText: code, sourceMapText: map };
  45. };
  46. return {
  47. transpile,
  48. };
  49. }
  50. exports.create = create;
  51. /** @internal */
  52. exports.targetMapping = new Map();
  53. exports.targetMapping.set(/* ts.ScriptTarget.ES3 */ 0, 'es3');
  54. exports.targetMapping.set(/* ts.ScriptTarget.ES5 */ 1, 'es5');
  55. exports.targetMapping.set(/* ts.ScriptTarget.ES2015 */ 2, 'es2015');
  56. exports.targetMapping.set(/* ts.ScriptTarget.ES2016 */ 3, 'es2016');
  57. exports.targetMapping.set(/* ts.ScriptTarget.ES2017 */ 4, 'es2017');
  58. exports.targetMapping.set(/* ts.ScriptTarget.ES2018 */ 5, 'es2018');
  59. exports.targetMapping.set(/* ts.ScriptTarget.ES2019 */ 6, 'es2019');
  60. exports.targetMapping.set(/* ts.ScriptTarget.ES2020 */ 7, 'es2020');
  61. exports.targetMapping.set(/* ts.ScriptTarget.ES2021 */ 8, 'es2021');
  62. exports.targetMapping.set(/* ts.ScriptTarget.ES2022 */ 9, 'es2022');
  63. exports.targetMapping.set(/* ts.ScriptTarget.ESNext */ 99, 'esnext');
  64. /**
  65. * @internal
  66. * We use this list to downgrade to a prior target when we probe swc to detect if it supports a particular target
  67. */
  68. const swcTargets = [
  69. 'es3',
  70. 'es5',
  71. 'es2015',
  72. 'es2016',
  73. 'es2017',
  74. 'es2018',
  75. 'es2019',
  76. 'es2020',
  77. 'es2021',
  78. 'es2022',
  79. 'esnext',
  80. ];
  81. const ModuleKind = {
  82. None: 0,
  83. CommonJS: 1,
  84. AMD: 2,
  85. UMD: 3,
  86. System: 4,
  87. ES2015: 5,
  88. ES2020: 6,
  89. ESNext: 99,
  90. Node16: 100,
  91. NodeNext: 199,
  92. };
  93. const JsxEmit = {
  94. ReactJSX: /* ts.JsxEmit.ReactJSX */ 4,
  95. ReactJSXDev: /* ts.JsxEmit.ReactJSXDev */ 5,
  96. };
  97. /**
  98. * Prepare SWC options derived from typescript compiler options.
  99. * @internal exported for testing
  100. */
  101. function createSwcOptions(compilerOptions, nodeModuleEmitKind, swcInstance, swcDepName) {
  102. var _a;
  103. const { esModuleInterop, sourceMap, importHelpers, experimentalDecorators, emitDecoratorMetadata, target, module, jsx, jsxFactory, jsxFragmentFactory, strict, alwaysStrict, noImplicitUseStrict, jsxImportSource, } = compilerOptions;
  104. let swcTarget = (_a = exports.targetMapping.get(target)) !== null && _a !== void 0 ? _a : 'es3';
  105. // Downgrade to lower target if swc does not support the selected target.
  106. // Perhaps project has an older version of swc.
  107. // TODO cache the results of this; slightly faster
  108. let swcTargetIndex = swcTargets.indexOf(swcTarget);
  109. for (; swcTargetIndex >= 0; swcTargetIndex--) {
  110. try {
  111. swcInstance.transformSync('', {
  112. jsc: { target: swcTargets[swcTargetIndex] },
  113. });
  114. break;
  115. }
  116. catch (e) { }
  117. }
  118. swcTarget = swcTargets[swcTargetIndex];
  119. const keepClassNames = target >= /* ts.ScriptTarget.ES2016 */ 3;
  120. const isNodeModuleKind = module === ModuleKind.Node16 || module === ModuleKind.NodeNext;
  121. // swc only supports these 4x module options [MUST_UPDATE_FOR_NEW_MODULEKIND]
  122. const moduleType = module === ModuleKind.CommonJS
  123. ? 'commonjs'
  124. : module === ModuleKind.AMD
  125. ? 'amd'
  126. : module === ModuleKind.UMD
  127. ? 'umd'
  128. : isNodeModuleKind && nodeModuleEmitKind === 'nodecjs'
  129. ? 'commonjs'
  130. : isNodeModuleKind && nodeModuleEmitKind === 'nodeesm'
  131. ? 'es6'
  132. : 'es6';
  133. // In swc:
  134. // strictMode means `"use strict"` is *always* emitted for non-ES module, *never* for ES module where it is assumed it can be omitted.
  135. // (this assumption is invalid, but that's the way swc behaves)
  136. // tsc is a bit more complex:
  137. // alwaysStrict will force emitting it always unless `import`/`export` syntax is emitted which implies it per the JS spec.
  138. // if not alwaysStrict, will emit implicitly whenever module target is non-ES *and* transformed module syntax is emitted.
  139. // For node, best option is to assume that all scripts are modules (commonjs or esm) and thus should get tsc's implicit strict behavior.
  140. // Always set strictMode, *unless* alwaysStrict is disabled and noImplicitUseStrict is enabled
  141. const strictMode =
  142. // if `alwaysStrict` is disabled, remembering that `strict` defaults `alwaysStrict` to true
  143. (alwaysStrict === false || (alwaysStrict !== true && strict !== true)) &&
  144. // if noImplicitUseStrict is enabled
  145. noImplicitUseStrict === true
  146. ? false
  147. : true;
  148. const jsxRuntime = jsx === JsxEmit.ReactJSX || jsx === JsxEmit.ReactJSXDev ? 'automatic' : undefined;
  149. const jsxDevelopment = jsx === JsxEmit.ReactJSXDev ? true : undefined;
  150. const useDefineForClassFields = (0, ts_internals_1.getUseDefineForClassFields)(compilerOptions);
  151. const nonTsxOptions = createVariant(false);
  152. const tsxOptions = createVariant(true);
  153. return { nonTsxOptions, tsxOptions };
  154. function createVariant(isTsx) {
  155. const swcOptions = {
  156. sourceMaps: sourceMap,
  157. // isModule: true,
  158. module: moduleType
  159. ? {
  160. type: moduleType,
  161. ...(moduleType === 'amd' || moduleType === 'commonjs' || moduleType === 'umd'
  162. ? {
  163. noInterop: !esModuleInterop,
  164. strictMode,
  165. // For NodeNext and Node12, emit as CJS but do not transform dynamic imports
  166. ignoreDynamic: nodeModuleEmitKind === 'nodecjs',
  167. }
  168. : {}),
  169. }
  170. : undefined,
  171. swcrc: false,
  172. jsc: {
  173. externalHelpers: importHelpers,
  174. parser: {
  175. syntax: 'typescript',
  176. tsx: isTsx,
  177. decorators: experimentalDecorators,
  178. dynamicImport: true,
  179. importAssertions: true,
  180. },
  181. target: swcTarget,
  182. transform: {
  183. decoratorMetadata: emitDecoratorMetadata,
  184. legacyDecorator: true,
  185. react: {
  186. throwIfNamespace: false,
  187. development: jsxDevelopment,
  188. useBuiltins: false,
  189. pragma: jsxFactory,
  190. pragmaFrag: jsxFragmentFactory,
  191. runtime: jsxRuntime,
  192. importSource: jsxImportSource,
  193. },
  194. useDefineForClassFields,
  195. },
  196. keepClassNames,
  197. experimental: {
  198. keepImportAttributes: true,
  199. emitAssertForImportAttributes: true,
  200. },
  201. },
  202. };
  203. // Throw a helpful error if swc version is old, for example, if it rejects `ignoreDynamic`
  204. try {
  205. swcInstance.transformSync('', swcOptions);
  206. }
  207. catch (e) {
  208. throw new Error(`${swcDepName} threw an error when attempting to validate swc compiler options.\n` +
  209. 'You may be using an old version of swc which does not support the options used by ts-node.\n' +
  210. 'Try upgrading to the latest version of swc.\n' +
  211. 'Error message from swc:\n' +
  212. (e === null || e === void 0 ? void 0 : e.message));
  213. }
  214. return swcOptions;
  215. }
  216. }
  217. exports.createSwcOptions = createSwcOptions;
  218. //# sourceMappingURL=swc.js.map