Skip to content

Commit

Permalink
add Target ES2021 mapping in transpilers/swc (#1521)
Browse files Browse the repository at this point in the history
* add Target ES2021 mapping in transpilers/swc

I was getting error: `jsc.target should be es5 or upper to use getter / setter` 
and after investigation I've isolated issue and here is the "fix"

* fix and add tests

* fix

* lintfix

Co-authored-by: Andrew Bradley <cspotcode@gmail.com>
  • Loading branch information
safareli and cspotcode committed Oct 22, 2021
1 parent 8cde25b commit 56b70da
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 4 deletions.
47 changes: 47 additions & 0 deletions src/test/transpilers.spec.ts
@@ -0,0 +1,47 @@
// third-party transpiler and swc transpiler tests
// TODO: at the time of writing, other transpiler tests have not been moved into this file.
// Should consolidate them here.

import { context } from './testlib';
import { contextTsNodeUnderTest, testsDirRequire } from './helpers';
import * as expect from 'expect';

const test = context(contextTsNodeUnderTest);

test.suite('swc', (test) => {
test('verify that TS->SWC target mappings suppport all possible values from both TS and SWC', async (t) => {
const swcTranspiler = testsDirRequire(
'ts-node/transpilers/swc-experimental'
) as typeof import('../transpilers/swc');

// Detect when mapping is missing any ts.ScriptTargets
const ts = testsDirRequire('typescript') as typeof import('typescript');
for (const key of Object.keys(ts.ScriptTarget)) {
if (/^\d+$/.test(key)) continue;
if (key === 'JSON') continue;
expect(
swcTranspiler.targetMapping.has(ts.ScriptTarget[key as any] as any)
).toBe(true);
}

// Detect when mapping is missing any swc targets
// Assuming that tests/package.json declares @swc/core: latest
const swc = testsDirRequire('@swc/core');
let msg: string | undefined = undefined;
try {
swc.transformSync('', { jsc: { target: 'invalid' } });
} catch (e) {
msg = (e as Error).message;
}
expect(msg).toBeDefined();
// Error looks like:
// unknown variant `invalid`, expected one of `es3`, `es5`, `es2015`, `es2016`, `es2017`, `es2018`, `es2019`, `es2020`, `es2021` at line 1 column 28
const match = msg!.match(/unknown variant.*, expected one of (.*) at line/);
expect(match).toBeDefined();
const targets = match![1].split(', ').map((v: string) => v.slice(1, -1));

for (const target of targets) {
expect([...swcTranspiler.targetMapping.values()]).toContain(target);
}
});
});
40 changes: 36 additions & 4 deletions src/transpilers/swc.ts
Expand Up @@ -56,7 +56,20 @@ export function create(createOptions: SwcTranspilerOptions): Transpiler {
const nonTsxOptions = createSwcOptions(false);
const tsxOptions = createSwcOptions(true);
function createSwcOptions(isTsx: boolean): swcTypes.Options {
const swcTarget = targetMapping.get(target!) ?? 'es3';
let swcTarget = targetMapping.get(target!) ?? 'es3';
// Downgrade to lower target if swc does not support the selected target.
// Perhaps project has an older version of swc.
// TODO cache the results of this; slightly faster
let swcTargetIndex = swcTargets.indexOf(swcTarget);
for (; swcTargetIndex >= 0; swcTargetIndex--) {
try {
swcInstance.transformSync('', {
jsc: { target: swcTargets[swcTargetIndex] },
});
break;
} catch (e) {}
}
swcTarget = swcTargets[swcTargetIndex];
const keepClassNames = target! >= /* ts.ScriptTarget.ES2016 */ 3;
const moduleType =
module === ModuleKind.CommonJS
Expand Down Expand Up @@ -119,16 +132,35 @@ export function create(createOptions: SwcTranspilerOptions): Transpiler {
};
}

const targetMapping = new Map<ts.ScriptTarget, swcTypes.JscTarget>();
/** @internal */
export const targetMapping = new Map<ts.ScriptTarget, SwcTarget>();
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');
targetMapping.set(/* ts.ScriptTarget.ES2020 */ 7, 'es2020');
targetMapping.set(/* ts.ScriptTarget.ES2021 */ 8, 'es2021');
targetMapping.set(/* ts.ScriptTarget.ESNext */ 99, 'es2021');

type SwcTarget = typeof swcTargets[number];
/**
* @internal
* We use this list to downgrade to a prior target when we probe swc to detect if it supports a particular target
*/
const swcTargets = [
'es3',
'es5',
'es2015',
'es2016',
'es2017',
'es2018',
'es2019',
'es2020',
'es2021',
] as const;

const ModuleKind = {
None: 0,
Expand Down

0 comments on commit 56b70da

Please sign in to comment.