Skip to content

Commit

Permalink
Port babel-parser changes from 2023-01-11 to 2023-03-14 (#786)
Browse files Browse the repository at this point in the history
Instructions: https://github.com/alangpierce/sucrase/wiki/Porting-changes-from-Babel's-parser

Fixes #783

f7e231fc97 Allow negative number in ambient const initializer (#15338)
🚫 Only affects error handling.

89f38880ce v7.20.13
🚫 Release only.

41aac8b803 fix: `new (foo?.bar)()` incorrectly throws exception `OptionalChainingNoNew` (#15377)
🚫 Only affects error handling.

91b24d5d55 chore: Remove meaningless `typeof undefined` (#15395)
🚫 Babel-internal change.

3aee4e367a Disallows specifiers after export * as ns (#15385)
🚫 Only affects error handling.

e5e923d99c Disallow await as bound name in using declaration (#15391)
🚫 Only affects error handling.

6e1cc6e958 v7.20.15
🚫 Release only.

812ad554ab polish: improve "`await` as identifier" error in modules (#15400)
🚫 Only affects error handling.

d3bd1a3f2f [ts] Fix restrictions for optional parameters (#15414)
🚫 Appears to only affect error handling.

9be2c7fd79 [ts] treat single type param with a constraint as unambiguous (#15436)
🚫 Only affects error handling.

3c26949819 Add `annexb: false` parser option to disable Annex B (#15320)
🚫 I believe all Annex B syntax support was removed long ago.

6e8ce9da64 [ts] Support `export type * from` (#15381)
✅ Ported and added test.

2a7495f2c8 Parser option to allow `new.target` outside functions (#15114)
🚫 Only affects error handling.

eae47c9ec8 Implement decorators as presented at `2023-01` TC39 meeting (#15405)
✅ No parser changes were necessary, but added support for decorators after export with imports transform.

2f3ef392d6 [ts] Support `const` modifier in type parameters (#15384)
✅ This was already accidentally working, but I added some logic to make it work intentionally and added a test.

34136c53f8 docs: fix typos (#15432)
🚫 Babel-internal change.

de7d75a78b v7.21.0
🚫 Release only.

7feaa36ad5 Fix problems found while publishing 7.21.0 (#15440)
🚫 Not relevant to Sucrase.

fa77313884 v7.21.1
🚫 Release only.

a2fdc207ce fix: Throws on `new foo?.bar!()` (#15439)
🚫 Only affects error handling.

fc33467911 v7.21.2
🚫 Release only.

6e3dffe51a disallow mixins/implements in flow interface (#15479)
🚫 Only affects error handling.

4035521068 chore: Enable rule `no-confusing-void-expression` (#15485)
🚫 Babel-internal change.

80863c220b [ts] Allow keywords in tuple labels (#15423)
✅ Type parsing already allowed keywords, added a test for this case.

fbfbd1da8c v7.21.3
🚫 Release only.
  • Loading branch information
alangpierce committed Mar 20, 2023
1 parent c65dd7b commit 4b03ee3
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 18 deletions.
2 changes: 0 additions & 2 deletions spec-compliance-tests/babel-tests/check-babel-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ es2015/yield/without-argument
es2018/async-generators/for-await-async-of
es2020/bigint/decimal-as-property-name
estree/class-private-property/flow
experimental/decorators/export-decorated-class
experimental/decorators/export-default-decorated-class
experimental/decorators/parenthesized // Uses obsolete syntax @(a)()
experimental/decorators/parenthesized-createParenthesizedExpressions // Uses obsolete syntax @(a)()
flow/anonymous-function-no-parens-types/good_15
Expand Down
12 changes: 10 additions & 2 deletions src/parser/plugins/typescript.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,8 +196,10 @@ function tsParseImportType(): void {
}

function tsParseTypeParameter(): void {
eat(tt._const);
const hadIn = eat(tt._in);
const hadOut = eatContextual(ContextualKeyword._out);
eat(tt._const);
if ((hadIn || hadOut) && !match(tt.name)) {
// The "in" or "out" keyword must have actually been the type parameter
// name, so set it as the name.
Expand Down Expand Up @@ -1298,8 +1300,14 @@ export function tsTryParseExport(): boolean {
semicolon();
return true;
} else {
if (isContextual(ContextualKeyword._type) && lookaheadType() === tt.braceL) {
next();
if (isContextual(ContextualKeyword._type)) {
const nextType = lookaheadType();
// export type {foo} from 'a';
// export type * from 'a';'
// export type * as ns from 'a';'
if (nextType === tt.braceL || nextType === tt.star) {
next();
}
}
return false;
}
Expand Down
57 changes: 48 additions & 9 deletions src/transformers/CJSImportTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ export default class CJSImportTransformer extends Transformer {
return true;
} else if (
this.tokens.matches2(tt._export, tt._class) ||
this.tokens.matches3(tt._export, tt._abstract, tt._class)
this.tokens.matches3(tt._export, tt._abstract, tt._class) ||
this.tokens.matches2(tt._export, tt.at)
) {
this.processExportClass();
return true;
Expand All @@ -315,16 +316,31 @@ export default class CJSImportTransformer extends Transformer {
this.processExportStar();
return true;
} else if (
this.tokens.matches3(tt._export, tt.name, tt.braceL) &&
this.tokens.matches2(tt._export, tt.name) &&
this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, ContextualKeyword._type)
) {
// TS `export type {` case: just remove the export entirely.
// export type {a};
// export type {a as b};
// export type {a} from './b';
// export type * from './b';
// export type * as ns from './b';
this.tokens.removeInitialToken();
while (!this.tokens.matches1(tt.braceR)) {
this.tokens.removeToken();
if (this.tokens.matches1(tt.braceL)) {
while (!this.tokens.matches1(tt.braceR)) {
this.tokens.removeToken();
}
this.tokens.removeToken();
} else {
// *
this.tokens.removeToken();
if (this.tokens.matches1(tt._as)) {
// as
this.tokens.removeToken();
// ns
this.tokens.removeToken();
}
}
this.tokens.removeToken();

// Remove type re-export `... } from './T'`
if (
this.tokens.matchesContextual(ContextualKeyword._from) &&
Expand Down Expand Up @@ -483,17 +499,17 @@ export default class CJSImportTransformer extends Transformer {
this.tokens.appendCode(` exports.default = ${name};`);
} else if (
this.tokens.matches4(tt._export, tt._default, tt._class, tt.name) ||
this.tokens.matches5(tt._export, tt._default, tt._abstract, tt._class, tt.name)
this.tokens.matches5(tt._export, tt._default, tt._abstract, tt._class, tt.name) ||
this.tokens.matches3(tt._export, tt._default, tt.at)
) {
this.tokens.removeInitialToken();
this.tokens.removeToken();
this.copyDecorators();
if (this.tokens.matches1(tt._abstract)) {
this.tokens.removeToken();
}
const name = this.rootTransformer.processNamedClass();
this.tokens.appendCode(` exports.default = ${name};`);
} else if (this.tokens.matches3(tt._export, tt._default, tt.at)) {
throw new Error("Export default statements with decorators are not yet supported.");
// After this point, this is a plain "export default E" statement.
} else if (
shouldElideDefaultExport(this.isTypeScriptTransformEnabled, this.tokens, this.declarationInfo)
Expand All @@ -520,6 +536,28 @@ export default class CJSImportTransformer extends Transformer {
}
}

private copyDecorators(): void {
while (this.tokens.matches1(tt.at)) {
this.tokens.copyToken();
if (this.tokens.matches1(tt.parenL)) {
this.tokens.copyExpectedToken(tt.parenL);
this.rootTransformer.processBalancedCode();
this.tokens.copyExpectedToken(tt.parenR);
} else {
this.tokens.copyExpectedToken(tt.name);
while (this.tokens.matches1(tt.dot)) {
this.tokens.copyExpectedToken(tt.dot);
this.tokens.copyExpectedToken(tt.name);
}
if (this.tokens.matches1(tt.parenL)) {
this.tokens.copyExpectedToken(tt.parenL);
this.rootTransformer.processBalancedCode();
this.tokens.copyExpectedToken(tt.parenR);
}
}
}
}

/**
* Transform a declaration like `export var`, `export let`, or `export const`.
*/
Expand Down Expand Up @@ -719,6 +757,7 @@ export default class CJSImportTransformer extends Transformer {
*/
private processExportClass(): void {
this.tokens.removeInitialToken();
this.copyDecorators();
if (this.tokens.matches1(tt._abstract)) {
this.tokens.removeToken();
}
Expand Down
25 changes: 20 additions & 5 deletions src/transformers/ESMImportTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,31 @@ export default class ESMImportTransformer extends Transformer {
return this.processNamedExports();
}
if (
this.tokens.matches3(tt._export, tt.name, tt.braceL) &&
this.tokens.matches2(tt._export, tt.name) &&
this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, ContextualKeyword._type)
) {
// TS `export type {` case: just remove the export entirely.
// export type {a};
// export type {a as b};
// export type {a} from './b';
// export type * from './b';
// export type * as ns from './b';
this.tokens.removeInitialToken();
while (!this.tokens.matches1(tt.braceR)) {
this.tokens.removeToken();
if (this.tokens.matches1(tt.braceL)) {
while (!this.tokens.matches1(tt.braceR)) {
this.tokens.removeToken();
}
this.tokens.removeToken();
} else {
// *
this.tokens.removeToken();
if (this.tokens.matches1(tt._as)) {
// as
this.tokens.removeToken();
// ns
this.tokens.removeToken();
}
}
this.tokens.removeToken();

// Remove type re-export `... } from './T'`
if (
this.tokens.matchesContextual(ContextualKeyword._from) &&
Expand Down
16 changes: 16 additions & 0 deletions test/imports-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1409,6 +1409,22 @@ module.exports = exports.default;
);
});

it("allows decorators before or after export in CJS", () => {
assertResult(
`
@dec1 export @dec2 class Foo {}
@dec3 export default @dec4 class Bar {}
export default @(1 + 1) @(foo.bar()) @a.b.c @d.e() @g.h(1, 2, 3) class Baz {}
`,
`"use strict";${ESMODULE_PREFIX}
@dec1 @dec2 class Foo {} exports.Foo = Foo;
@dec3 @dec4 class Bar {} exports.default = Bar;
@(1 + 1) @(foo.bar()) @a.b.c @d.e() @g.h(1, 2, 3) class Baz {} exports.default = Baz;
`,
{transforms: ["imports"]},
);
});

it("implements basic live bindings", () => {
assertMultiFileOutput(
{
Expand Down
14 changes: 14 additions & 0 deletions test/sucrase-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1608,6 +1608,20 @@ describe("sucrase", () => {
);
});

it("allows decorators before and after export keyword", () => {
assertResult(
`
@dec1 export @dec2 class Foo {}
@dec3 export default @dec4 class Bar {}
`,
`
@dec1 export @dec2 class Foo {}
@dec3 export default @dec4 class Bar {}
`,
{disableESTransforms: true, transforms: []},
);
});

it("allows destructuring private fields", () => {
// Example from https://github.com/tc39/proposal-destructuring-private
assertResult(
Expand Down
64 changes: 64 additions & 0 deletions test/typescript-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2410,6 +2410,32 @@ describe("typescript transform", () => {
);
});

it("supports `export type * from` in CJS mode", () => {
assertTypeScriptResult(
`
export type * from './T';
export type * as ns from './T';
`,
`"use strict";${ESMODULE_PREFIX}
;
;
`,
);
});

it("supports `export type * from` in ESM mode", () => {
assertTypeScriptESMResult(
`
export type * from './T';
export type * as ns from './T';
`,
`
;
;
`,
);
});

it("properly handles default args in constructors", () => {
assertTypeScriptResult(
`
Expand Down Expand Up @@ -3589,4 +3615,42 @@ describe("typescript transform", () => {
{transforms: ["typescript"], disableESTransforms: true},
);
});

it("allows const modifier on type parameters", () => {
assertResult(
`
function a<const T>() {}
function b<const T extends U>() {}
class C<const T> {}
class D<in const T> {}
class E<const in T> {}
`,
`
function a() {}
function b() {}
class C {}
class D {}
class E {}
`,
{transforms: ["typescript"]},
);
});

it("allows keywords in tuple labels", () => {
assertResult(
`
type T = [
function: () => {},
string: string
]
`,
`
`,
{transforms: ["typescript"]},
);
});
});

0 comments on commit 4b03ee3

Please sign in to comment.