swc.js 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.createSwcOptions = exports.targetMapping = exports.create = void 0;
  4. function create(createOptions) {
  5. const { swc, service: { config, projectLocalResolveHelper }, transpilerConfigLocalResolveHelper, nodeModuleEmitKind, } = createOptions;
  6. // Load swc compiler
  7. let swcInstance;
  8. // Used later in diagnostics; merely needs to be human-readable.
  9. let swcDepName = 'swc';
  10. if (typeof swc === 'string') {
  11. swcDepName = swc;
  12. swcInstance = require(transpilerConfigLocalResolveHelper(swc, true));
  13. }
  14. else if (swc == null) {
  15. let swcResolved;
  16. try {
  17. swcDepName = '@swc/core';
  18. swcResolved = transpilerConfigLocalResolveHelper(swcDepName, true);
  19. }
  20. catch (e) {
  21. try {
  22. swcDepName = '@swc/wasm';
  23. swcResolved = transpilerConfigLocalResolveHelper(swcDepName, true);
  24. }
  25. catch (e) {
  26. 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');
  27. }
  28. }
  29. swcInstance = require(swcResolved);
  30. }
  31. else {
  32. swcInstance = swc;
  33. }
  34. // Prepare SWC options derived from typescript compiler options
  35. const { nonTsxOptions, tsxOptions } = createSwcOptions(config.options, nodeModuleEmitKind, swcInstance, swcDepName);
  36. const transpile = (input, transpileOptions) => {
  37. const { fileName } = transpileOptions;
  38. const swcOptions = fileName.endsWith('.tsx') || fileName.endsWith('.jsx')
  39. ? tsxOptions
  40. : nonTsxOptions;
  41. const { code, map } = swcInstance.transformSync(input, {
  42. ...swcOptions,
  43. filename: fileName,
  44. });
  45. return { outputText: code, sourceMapText: map };
  46. };
  47. return {
  48. transpile,
  49. };
  50. }
  51. exports.create = create;
  52. /** @internal */
  53. exports.targetMapping = new Map();
  54. exports.targetMapping.set(/* ts.ScriptTarget.ES3 */ 0, 'es3');
  55. exports.targetMapping.set(/* ts.ScriptTarget.ES5 */ 1, 'es5');
  56. exports.targetMapping.set(/* ts.ScriptTarget.ES2015 */ 2, 'es2015');
  57. exports.targetMapping.set(/* ts.ScriptTarget.ES2016 */ 3, 'es2016');
  58. exports.targetMapping.set(/* ts.ScriptTarget.ES2017 */ 4, 'es2017');
  59. exports.targetMapping.set(/* ts.ScriptTarget.ES2018 */ 5, 'es2018');
  60. exports.targetMapping.set(/* ts.ScriptTarget.ES2019 */ 6, 'es2019');
  61. exports.targetMapping.set(/* ts.ScriptTarget.ES2020 */ 7, 'es2020');
  62. exports.targetMapping.set(/* ts.ScriptTarget.ES2021 */ 8, 'es2021');
  63. exports.targetMapping.set(/* ts.ScriptTarget.ES2022 */ 9, 'es2022');
  64. exports.targetMapping.set(/* ts.ScriptTarget.ESNext */ 99, 'es2022');
  65. /**
  66. * @internal
  67. * We use this list to downgrade to a prior target when we probe swc to detect if it supports a particular target
  68. */
  69. const swcTargets = [
  70. 'es3',
  71. 'es5',
  72. 'es2015',
  73. 'es2016',
  74. 'es2017',
  75. 'es2018',
  76. 'es2019',
  77. 'es2020',
  78. 'es2021',
  79. 'es2022',
  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, } = 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
  149. ? 'automatic'
  150. : undefined;
  151. const jsxDevelopment = jsx === JsxEmit.ReactJSXDev ? true : undefined;
  152. const nonTsxOptions = createVariant(false);
  153. const tsxOptions = createVariant(true);
  154. return { nonTsxOptions, tsxOptions };
  155. function createVariant(isTsx) {
  156. const swcOptions = {
  157. sourceMaps: sourceMap,
  158. // isModule: true,
  159. module: moduleType
  160. ? {
  161. noInterop: !esModuleInterop,
  162. type: moduleType,
  163. strictMode,
  164. // For NodeNext and Node12, emit as CJS but do not transform dynamic imports
  165. ignoreDynamic: nodeModuleEmitKind === 'nodecjs',
  166. }
  167. : undefined,
  168. swcrc: false,
  169. jsc: {
  170. externalHelpers: importHelpers,
  171. parser: {
  172. syntax: 'typescript',
  173. tsx: isTsx,
  174. decorators: experimentalDecorators,
  175. dynamicImport: true,
  176. importAssertions: true,
  177. },
  178. target: swcTarget,
  179. transform: {
  180. decoratorMetadata: emitDecoratorMetadata,
  181. legacyDecorator: true,
  182. react: {
  183. throwIfNamespace: false,
  184. development: jsxDevelopment,
  185. useBuiltins: false,
  186. pragma: jsxFactory,
  187. pragmaFrag: jsxFragmentFactory,
  188. runtime: jsxRuntime,
  189. },
  190. },
  191. keepClassNames,
  192. experimental: {
  193. keepImportAssertions: true,
  194. },
  195. },
  196. };
  197. // Throw a helpful error if swc version is old, for example, if it rejects `ignoreDynamic`
  198. try {
  199. swcInstance.transformSync('', swcOptions);
  200. }
  201. catch (e) {
  202. throw new Error(`${swcDepName} threw an error when attempting to validate swc compiler options.\n` +
  203. 'You may be using an old version of swc which does not support the options used by ts-node.\n' +
  204. 'Try upgrading to the latest version of swc.\n' +
  205. 'Error message from swc:\n' +
  206. (e === null || e === void 0 ? void 0 : e.message));
  207. }
  208. return swcOptions;
  209. }
  210. }
  211. exports.createSwcOptions = createSwcOptions;
  212. //# sourceMappingURL=swc.js.map