/
swc.ts
120 lines (113 loc) · 3.6 KB
/
swc.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import type * as ts from 'typescript';
import type * as swcWasm from '@swc/wasm';
import type * as swcTypes from '@swc/core';
import type { CreateTranspilerOptions, Transpiler } from './types';
export interface SwcTranspilerOptions extends CreateTranspilerOptions {
/**
* swc compiler to use for compilation
* Set to '@swc/wasm' to use swc's WASM compiler
* Default: '@swc/core', falling back to '@swc/wasm'
*/
swc?: string | typeof swcWasm;
}
export function create(createOptions: SwcTranspilerOptions): Transpiler {
const {
swc,
service: { config },
} = createOptions;
// Load swc compiler
let swcInstance: typeof swcWasm;
if (typeof swc === 'string') {
swcInstance = require(swc) as typeof swcWasm;
} else if (swc == null) {
let swcResolved;
try {
swcResolved = require.resolve('@swc/core');
} catch (e) {
try {
swcResolved = require.resolve('@swc/wasm');
} catch (e) {
throw new Error(
'swc compiler requires either @swc/core or @swc/wasm to be installed as dependencies'
);
}
}
swcInstance = require(swcResolved) as typeof swcWasm;
} else {
swcInstance = swc;
}
// Prepare SWC options derived from typescript compiler options
const compilerOptions = config.options;
const {
esModuleInterop,
sourceMap,
importHelpers,
experimentalDecorators,
emitDecoratorMetadata,
target,
jsxFactory,
jsxFragmentFactory,
} = compilerOptions;
const nonTsxOptions = createSwcOptions(false);
const tsxOptions = createSwcOptions(true);
function createSwcOptions(isTsx: boolean): swcTypes.Options {
const swcTarget = targetMapping.get(target!) ?? 'es3';
const keepClassNames = target! >= /* ts.ScriptTarget.ES2016 */ 3;
return {
sourceMaps: sourceMap,
// isModule: true,
module: {
type: 'commonjs',
noInterop: !esModuleInterop,
},
swcrc: false,
jsc: {
externalHelpers: importHelpers,
parser: {
syntax: 'typescript',
tsx: isTsx,
decorators: experimentalDecorators,
dynamicImport: true,
},
target: swcTarget,
transform: {
decoratorMetadata: emitDecoratorMetadata,
legacyDecorator: true,
react: {
throwIfNamespace: false,
development: false,
useBuiltins: false,
pragma: jsxFactory!,
pragmaFrag: jsxFragmentFactory!,
} as swcTypes.ReactConfig,
},
keepClassNames,
} as swcTypes.JscConfig,
};
}
const transpile: Transpiler['transpile'] = (input, transpileOptions) => {
const { fileName } = transpileOptions;
const swcOptions =
fileName.endsWith('.tsx') || fileName.endsWith('.jsx')
? tsxOptions
: nonTsxOptions;
const { code, map } = swcInstance.transformSync(input, {
...swcOptions,
filename: fileName,
});
return { outputText: code, sourceMapText: map };
};
return {
transpile,
};
}
const targetMapping = new Map<ts.ScriptTarget, swcTypes.JscTarget>();
targetMapping.set(/* ts.ScriptTarget.ES3 */ 0, 'es3');
targetMapping.set(/* ts.ScriptTarget.ES5 */ 1, 'es5');
targetMapping.set(/* ts.ScriptTarget.ES2015 */ 2, 'es2015');
targetMapping.set(/* ts.ScriptTarget.ES2016 */ 3, 'es2016');
targetMapping.set(/* ts.ScriptTarget.ES2017 */ 4, 'es2017');
targetMapping.set(/* ts.ScriptTarget.ES2018 */ 5, 'es2018');
targetMapping.set(/* ts.ScriptTarget.ES2019 */ 6, 'es2019');
targetMapping.set(/* ts.ScriptTarget.ES2020 */ 7, 'es2019');
targetMapping.set(/* ts.ScriptTarget.ESNext */ 99, 'es2019');