Skip to content

Commit

Permalink
Handle .mts and .cts files in @babel/preset-typescript (#13838)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicolo-ribaudo committed Oct 28, 2021
1 parent 381277a commit 718c6cb
Show file tree
Hide file tree
Showing 56 changed files with 619 additions and 38 deletions.
4 changes: 3 additions & 1 deletion packages/babel-helper-fixtures/src/index.ts
Expand Up @@ -64,7 +64,7 @@ function shouldIgnore(name, ignore?: Array<string>) {
);
}

const EXTENSIONS = [".js", ".mjs", ".ts", ".tsx"];
const EXTENSIONS = [".js", ".mjs", ".ts", ".tsx", ".cts", ".mts"];

function findFile(filepath: string, allowJSON?: boolean) {
const matches = [];
Expand Down Expand Up @@ -134,6 +134,7 @@ function pushTask(taskName, taskDir, suite, suiteName) {
? taskOpts.BABEL_8_BREAKING === false
: taskOpts.BABEL_8_BREAKING === true),
options: taskOpts,
doNotSetSourceType: taskOpts.DO_NOT_SET_SOURCE_TYPE,
externalHelpers:
taskOpts.externalHelpers ??
!!tryResolve("@babel/plugin-external-helpers"),
Expand Down Expand Up @@ -162,6 +163,7 @@ function pushTask(taskName, taskDir, suite, suiteName) {
};

delete taskOpts.BABEL_8_BREAKING;
delete taskOpts.DO_NOT_SET_SOURCE_TYPE;

// If there's node requirement, check it before pushing task
if (taskOpts.minNodeVersion) {
Expand Down
Expand Up @@ -230,6 +230,7 @@ function run(task) {
expect: expected,
exec,
options: opts,
doNotSetSourceType,
optionsDir,
validateLogs,
ignoreOutput,
Expand All @@ -245,7 +246,7 @@ function run(task) {
filename: self.loc,
filenameRelative: self.filename,
sourceFileName: self.filename,
sourceType: "script",
...(doNotSetSourceType ? {} : { sourceType: "script" }),
babelrc: false,
configFile: false,
inputSourceMap: task.inputSourceMap || undefined,
Expand Down
52 changes: 49 additions & 3 deletions packages/babel-parser/src/plugins/typescript/index.js
Expand Up @@ -135,6 +135,10 @@ const TSErrors = makeErrorTemplates(
"Private elements cannot have an accessibility modifier ('%0').",
ReadonlyForMethodSignature:
"'readonly' modifier can only appear on a property declaration or index signature.",
ReservedArrowTypeParam:
"This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma, as in `<T,>() => ...`.",
ReservedTypeAssertion:
"This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead.",
SetAccesorCannotHaveOptionalParameter:
"A 'set' accessor cannot have an optional parameter.",
SetAccesorCannotHaveRestParameter:
Expand Down Expand Up @@ -359,12 +363,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
tsParseDelimitedList<T: N.Node>(
kind: ParsingContext,
parseElement: () => T,
refTrailingCommaPos?: { value: number },
): T[] {
return nonNull(
this.tsParseDelimitedListWorker(
kind,
parseElement,
/* expectSuccess */ true,
refTrailingCommaPos,
),
);
}
Expand All @@ -377,13 +383,16 @@ export default (superClass: Class<Parser>): Class<Parser> =>
kind: ParsingContext,
parseElement: () => ?T,
expectSuccess: boolean,
refTrailingCommaPos?: { value: number },
): ?(T[]) {
const result = [];
let trailingCommaPos = -1;

for (;;) {
if (this.tsIsListTerminator(kind)) {
break;
}
trailingCommaPos = -1;

const element = parseElement();
if (element == null) {
Expand All @@ -392,6 +401,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
result.push(element);

if (this.eat(tt.comma)) {
trailingCommaPos = this.state.lastTokStart;
continue;
}

Expand All @@ -406,6 +416,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return undefined;
}

if (refTrailingCommaPos) {
refTrailingCommaPos.value = trailingCommaPos;
}

return result;
}

Expand All @@ -414,6 +428,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
parseElement: () => T,
bracket: boolean,
skipFirstToken: boolean,
refTrailingCommaPos?: { value: number },
): T[] {
if (!skipFirstToken) {
if (bracket) {
Expand All @@ -423,7 +438,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
}

const result = this.tsParseDelimitedList(kind, parseElement);
const result = this.tsParseDelimitedList(
kind,
parseElement,
refTrailingCommaPos,
);

if (bracket) {
this.expect(tt.bracketR);
Expand Down Expand Up @@ -524,15 +543,21 @@ export default (superClass: Class<Parser>): Class<Parser> =>
this.unexpected();
}
const refTrailingCommaPos = { value: -1 };
node.params = this.tsParseBracketedList(
"TypeParametersOrArguments",
this.tsParseTypeParameter.bind(this),
/* bracket */ false,
/* skipFirstToken */ true,
refTrailingCommaPos,
);
if (node.params.length === 0) {
this.raise(node.start, TSErrors.EmptyTypeParameters);
}
if (refTrailingCommaPos.value !== -1) {
this.addExtra(node, "trailingComma", refTrailingCommaPos.value);
}
return this.finishNode(node, "TSTypeParameterDeclaration");
}
Expand Down Expand Up @@ -1403,6 +1428,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}

tsParseTypeAssertion(): N.TsTypeAssertion {
if (this.getPluginOption("typescript", "disallowAmbiguousJSXLike")) {
this.raise(this.state.start, TSErrors.ReservedTypeAssertion);
}

const node: N.TsTypeAssertion = this.startNode();
const _const = this.tsTryNextParseConstantContext();
node.typeAnnotation = _const || this.tsNextThenParseType();
Expand Down Expand Up @@ -2854,7 +2883,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>

// Either way, we're looking at a '<': tt.jsxTagStart or relational.

let typeParameters: N.TsTypeParameterDeclaration;
let typeParameters: ?N.TsTypeParameterDeclaration;
state = state || this.state.clone();

const arrow = this.tryParse(abort => {
Expand All @@ -2878,7 +2907,13 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}, state);

/*:: invariant(arrow.node != null) */
if (!arrow.error && !arrow.aborted) return arrow.node;
if (!arrow.error && !arrow.aborted) {
// This error is reported outside of the this.tryParse call so that
// in case of <T>(x) => 2, we don't consider <T>(x) as a type assertion
// because of this error.
if (typeParameters) this.reportReservedArrowTypeParam(typeParameters);
return arrow.node;
}

if (!jsx) {
// Try parsing a type cast instead of an arrow function.
Expand All @@ -2903,6 +2938,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (arrow.node) {
/*:: invariant(arrow.failState) */
this.state = arrow.failState;
if (typeParameters) this.reportReservedArrowTypeParam(typeParameters);
return arrow.node;
}

Expand All @@ -2919,6 +2955,16 @@ export default (superClass: Class<Parser>): Class<Parser> =>
throw jsx?.error || arrow.error || typeCast?.error;
}

reportReservedArrowTypeParam(node: any) {
if (
node.params.length === 1 &&
!node.extra?.trailingComma &&
this.getPluginOption("typescript", "disallowAmbiguousJSXLike")
) {
this.raise(node.start, TSErrors.ReservedArrowTypeParam);
}
}

// Handle type assertions
parseMaybeUnary(refExpressionErrors?: ?ExpressionErrors): N.Expression {
if (!this.hasPlugin("jsx") && this.isRelational("<")) {
Expand Down
@@ -0,0 +1,3 @@
{
"plugins": [["typescript", { "disallowAmbiguousJSXLike": true }]]
}
@@ -0,0 +1 @@
<T>x;
@@ -0,0 +1,38 @@
{
"type": "File",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5}},
"errors": [
"SyntaxError: This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead. (1:0)"
],
"program": {
"type": "Program",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":5,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":5}},
"expression": {
"type": "TSTypeAssertion",
"start":0,"end":4,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":4}},
"typeAnnotation": {
"type": "TSTypeReference",
"start":1,"end":2,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":2}},
"typeName": {
"type": "Identifier",
"start":1,"end":2,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":2},"identifierName":"T"},
"name": "T"
}
},
"expression": {
"type": "Identifier",
"start":3,"end":4,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":4},"identifierName":"x"},
"name": "x"
}
}
}
],
"directives": []
}
}
@@ -0,0 +1,2 @@
<T>() => 1;
<T>(x) => 1;
@@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": false
}
@@ -0,0 +1,87 @@
{
"type": "File",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":12}},
"errors": [
"SyntaxError: This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma, as in `<T,>() => ...`. (1:0)",
"SyntaxError: This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma, as in `<T,>() => ...`. (2:0)"
],
"program": {
"type": "Program",
"start":0,"end":24,"loc":{"start":{"line":1,"column":0},"end":{"line":2,"column":12}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":11,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":11}},
"expression": {
"type": "ArrowFunctionExpression",
"start":0,"end":10,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":10}},
"id": null,
"generator": false,
"async": false,
"params": [],
"body": {
"type": "NumericLiteral",
"start":9,"end":10,"loc":{"start":{"line":1,"column":9},"end":{"line":1,"column":10}},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
},
"typeParameters": {
"type": "TSTypeParameterDeclaration",
"start":0,"end":3,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":3}},
"params": [
{
"type": "TSTypeParameter",
"start":1,"end":2,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":2}},
"name": "T"
}
]
}
}
},
{
"type": "ExpressionStatement",
"start":12,"end":24,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":12}},
"expression": {
"type": "ArrowFunctionExpression",
"start":12,"end":23,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":11}},
"id": null,
"generator": false,
"async": false,
"params": [
{
"type": "Identifier",
"start":16,"end":17,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":5},"identifierName":"x"},
"name": "x"
}
],
"body": {
"type": "NumericLiteral",
"start":22,"end":23,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":11}},
"extra": {
"rawValue": 1,
"raw": "1"
},
"value": 1
},
"typeParameters": {
"type": "TSTypeParameterDeclaration",
"start":12,"end":15,"loc":{"start":{"line":2,"column":0},"end":{"line":2,"column":3}},
"params": [
{
"type": "TSTypeParameter",
"start":13,"end":14,"loc":{"start":{"line":2,"column":1},"end":{"line":2,"column":2}},
"name": "T"
}
]
}
}
}
],
"directives": []
}
}
@@ -0,0 +1,2 @@
<T,>() => 1;
<T,>(x) => 1;
@@ -0,0 +1,3 @@
{
"BABEL_8_BREAKING": false
}

0 comments on commit 718c6cb

Please sign in to comment.