Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Support auto accessors with TypeScript annotations #15209

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/babel-parser/src/parse-error/standard-errors.ts
Expand Up @@ -35,10 +35,10 @@ export default {
AwaitNotInAsyncContext:
"'await' is only allowed within async functions and at the top levels of modules.",
AwaitNotInAsyncFunction: "'await' is only allowed within async functions.",
BadGetterArity: "A 'get' accesor must not have any formal parameters.",
BadSetterArity: "A 'set' accesor must have exactly one formal parameter.",
BadGetterArity: "A 'get' accessor must not have any formal parameters.",
BadSetterArity: "A 'set' accessor must have exactly one formal parameter.",
BadSetterRestParameter:
"A 'set' accesor function argument must not be a rest parameter.",
"A 'set' accessor function argument must not be a rest parameter.",
ConstructorClassField: "Classes may not have a field named 'constructor'.",
ConstructorClassPrivateField:
"Classes may not have a private field named '#constructor'.",
Expand Down
23 changes: 20 additions & 3 deletions packages/babel-parser/src/plugins/typescript/index.ts
Expand Up @@ -93,6 +93,8 @@ const TSErrors = ParseErrorEnum`typescript`({
AccesorCannotDeclareThisParameter:
"'get' and 'set' accessors cannot declare 'this' parameters.",
AccesorCannotHaveTypeParameters: "An accessor cannot have type parameters.",
AccessorCannotBeOptional:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can (and should) fix the error messages now (i.e. BadSetterArity/BetGetterArity), but we should wait until Babel 8 to fix typos in error codes.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do error codes refer to the property names? These seem to be only visible from the inside.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes they are the property names; and they are public. For example, prettier relies on them: https://github.com/prettier/prettier/blob/b50dfd1974d33abb980e9b4df949913932eeb478/src/language-js/parse/babel.js#L183

"An 'accessor' property cannot be declared optional.",
ClassMethodHasDeclare: "Class methods cannot have the 'declare' modifier.",
ClassMethodHasReadonly: "Class methods cannot have the 'readonly' modifier.",
ConstInitiailizerMustBeStringOrNumericLiteralOrLiteralEnumReference:
Expand Down Expand Up @@ -194,6 +196,7 @@ const TSErrors = ParseErrorEnum`typescript`({
"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.",
// TODO: Accesor -> Accessor
SetAccesorCannotHaveOptionalParameter:
"A 'set' accessor cannot have an optional parameter.",
SetAccesorCannotHaveRestParameter:
Expand Down Expand Up @@ -3124,10 +3127,14 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
}

parseClassPropertyAnnotation(
node: N.ClassProperty | N.ClassPrivateProperty,
node: N.ClassProperty | N.ClassPrivateProperty | N.ClassAccessorProperty,
): void {
if (!node.optional && this.eat(tt.bang)) {
node.definite = true;
if (!node.optional) {
if (this.eat(tt.bang)) {
node.definite = true;
} else if (this.eat(tt.question)) {
node.optional = true;
}
}

const type = this.tsTryParseTypeAnnotation();
Expand Down Expand Up @@ -3181,6 +3188,16 @@ export default (superClass: ClassWithMixin<typeof Parser, IJSXParserMixin>) =>
return super.parseClassPrivateProperty(node);
}

parseClassAccessorProperty(
node: N.ClassAccessorProperty,
): N.ClassAccessorProperty {
this.parseClassPropertyAnnotation(node);
if (node.optional) {
this.raise(TSErrors.AccessorCannotBeOptional, { at: node });
}
return super.parseClassAccessorProperty(node);
}

pushClassMethod(
classBody: N.ClassBody,
method: N.ClassMethod,
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":15,"index":15}},
"errors": [
"SyntaxError: A 'set' accesor must have exactly one formal parameter. (1:3)"
"SyntaxError: A 'set' accessor must have exactly one formal parameter. (1:3)"
],
"program": {
"type": "Program",
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":31,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":31}},
"errors": [
"SyntaxError: A 'get' accesor must not have any formal parameters. (2:2)"
"SyntaxError: A 'get' accessor must not have any formal parameters. (2:2)"
],
"program": {
"type": "Program",
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":29,"index":29}},
"errors": [
"SyntaxError: A 'set' accesor must have exactly one formal parameter. (1:10)"
"SyntaxError: A 'set' accessor must have exactly one formal parameter. (1:10)"
],
"program": {
"type": "Program",
Expand Down
@@ -1,44 +1,44 @@
{
"type": "File",
"start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}},
"start":0,"end":17,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":17}},
"errors": [
"SyntaxError: A 'set' accesor must have exactly one formal parameter. (1:3)"
"SyntaxError: A 'set' accessor must have exactly one formal parameter. (1:3)"
],
"program": {
"type": "Program",
"start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}},
"start":0,"end":17,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":17}},
"sourceType": "script",
"interpreter": null,
"body": [
{
"type": "ExpressionStatement",
"start":0,"end":17,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":17,"index":17}},
"start":0,"end":17,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":17}},
"expression": {
"type": "ObjectExpression",
"start":1,"end":16,"loc":{"start":{"line":1,"column":1,"index":1},"end":{"line":1,"column":16,"index":16}},
"start":1,"end":16,"loc":{"start":{"line":1,"column":1},"end":{"line":1,"column":16}},
"properties": [
{
"type": "Property",
"start":3,"end":14,"loc":{"start":{"line":1,"column":3,"index":3},"end":{"line":1,"column":14,"index":14}},
"start":3,"end":14,"loc":{"start":{"line":1,"column":3},"end":{"line":1,"column":14}},
"method": false,
"key": {
"type": "Identifier",
"start":7,"end":8,"loc":{"start":{"line":1,"column":7,"index":7},"end":{"line":1,"column":8,"index":8},"identifierName":"s"},
"start":7,"end":8,"loc":{"start":{"line":1,"column":7},"end":{"line":1,"column":8},"identifierName":"s"},
"name": "s"
},
"computed": false,
"kind": "set",
"value": {
"type": "FunctionExpression",
"start":8,"end":14,"loc":{"start":{"line":1,"column":8,"index":8},"end":{"line":1,"column":14,"index":14}},
"start":8,"end":14,"loc":{"start":{"line":1,"column":8},"end":{"line":1,"column":14}},
"id": null,
"generator": false,
"async": false,
"expression": false,
"params": [],
"body": {
"type": "BlockStatement",
"start":11,"end":14,"loc":{"start":{"line":1,"column":11,"index":11},"end":{"line":1,"column":14,"index":14}},
"start":11,"end":14,"loc":{"start":{"line":1,"column":11},"end":{"line":1,"column":14}},
"body": []
}
},
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":22,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":1,"column":22,"index":22}},
"errors": [
"SyntaxError: A 'set' accesor function argument must not be a rest parameter. (1:6)"
"SyntaxError: A 'set' accessor function argument must not be a rest parameter. (1:6)"
],
"program": {
"type": "Program",
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":15,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":15}},
"errors": [
"SyntaxError: A 'set' accesor must have exactly one formal parameter. (1:3)"
"SyntaxError: A 'set' accessor must have exactly one formal parameter. (1:3)"
],
"program": {
"type": "Program",
Expand Down Expand Up @@ -53,4 +53,4 @@
}
]
}
}
}
Expand Up @@ -2,8 +2,8 @@
"type": "File",
"start":0,"end":85,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":18}},
"errors": [
"SyntaxError: A 'set' accesor must have exactly one formal parameter. (3:3)",
"SyntaxError: A 'get' accesor must not have any formal parameters. (4:3)"
"SyntaxError: A 'set' accessor must have exactly one formal parameter. (3:3)",
"SyntaxError: A 'get' accessor must not have any formal parameters. (4:3)"
],
"program": {
"type": "Program",
Expand Down Expand Up @@ -200,4 +200,4 @@
}
]
}
}
}
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":37,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":37}},
"errors": [
"SyntaxError: A 'get' accesor must not have any formal parameters. (2:2)"
"SyntaxError: A 'get' accessor must not have any formal parameters. (2:2)"
],
"program": {
"type": "Program",
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":41,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":41}},
"errors": [
"SyntaxError: A 'get' accesor must not have any formal parameters. (2:2)"
"SyntaxError: A 'get' accessor must not have any formal parameters. (2:2)"
],
"program": {
"type": "Program",
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":29,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":29}},
"errors": [
"SyntaxError: A 'set' accesor must have exactly one formal parameter. (2:2)"
"SyntaxError: A 'set' accessor must have exactly one formal parameter. (2:2)"
],
"program": {
"type": "Program",
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":33,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":33}},
"errors": [
"SyntaxError: A 'set' accesor function argument must not be a rest parameter. (2:2)"
"SyntaxError: A 'set' accessor function argument must not be a rest parameter. (2:2)"
],
"program": {
"type": "Program",
Expand Down
Expand Up @@ -2,7 +2,7 @@
"type": "File",
"start":0,"end":40,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":40}},
"errors": [
"SyntaxError: A 'get' accesor must not have any formal parameters. (2:2)",
"SyntaxError: A 'get' accessor must not have any formal parameters. (2:2)",
"SyntaxError: A getter cannot have a `this` parameter. (2:10)"
],
"program": {
Expand Down
Expand Up @@ -3,7 +3,7 @@
"start":0,"end":43,"loc":{"start":{"line":1,"column":0,"index":0},"end":{"line":3,"column":1,"index":43}},
"errors": [
"SyntaxError: A setter cannot have a `this` parameter. (2:10)",
"SyntaxError: A 'set' accesor must have exactly one formal parameter. (2:2)"
"SyntaxError: A 'set' accessor must have exactly one formal parameter. (2:2)"
],
"program": {
"type": "Program",
Expand Down
@@ -0,0 +1,15 @@
abstract class Foo {
declare accessor prop7: number;
JLHwung marked this conversation as resolved.
Show resolved Hide resolved
private accessor #p: any;

accessor a!;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TS will throw Declarations with definite assignment assertions must also have type annotations., we can address that in a separate PR.

abstract accessor #s;
accessor #d?;
abstract accessor f = 1;
readonly accessor g;
}

declare class C {
accessor x = 1;
#y = 1;
}
@@ -0,0 +1,6 @@
{
"plugins": [
"typescript",
"decoratorAutoAccessors"
]
}