From 54c539ecc12a70706e642ef9354b2ece6360444a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Fri, 12 Nov 2021 10:11:46 -0500 Subject: [PATCH] Refactor bindingProperty parsing (#13929) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: inline parseMaybePrivateName * correct test case * perf: fast exit in checkExpressionErrors * refactor: add parseBindingProperty * fix: private property with variance * Update packages/babel-parser/src/parser/expression.js Co-authored-by: Nicolò Ribaudo * chore: update testcase * refactor: remove refExpressionErrors for record/tuple They are always non-ambiguous. Co-authored-by: Nicolò Ribaudo --- .../babel-parser/src/parser/expression.js | 111 +++++++++--------- packages/babel-parser/src/parser/lval.js | 49 ++++++++ packages/babel-parser/src/parser/statement.js | 20 ++-- packages/babel-parser/src/parser/util.js | 27 +++-- .../babel-parser/src/plugins/flow/index.js | 13 +- .../src/plugins/typescript/index.js | 4 +- packages/babel-parser/src/types.js | 6 + .../invalid-object-method/input.js | 2 +- .../invalid-object-method/output.json | 37 +++--- .../invalid-object-property/input.js | 3 + .../invalid-object-property/output.json | 80 +++++++++++++ .../invalid-decorator-object-pattern/input.js | 1 + .../options.json | 4 + .../class-private-property/variance/input.js | 4 + .../variance/output.json | 69 +++++++++++ 15 files changed, 322 insertions(+), 108 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/input.js create mode 100644 packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/output.json create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/input.js create mode 100644 packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/options.json create mode 100644 packages/babel-parser/test/fixtures/flow/class-private-property/variance/input.js create mode 100644 packages/babel-parser/test/fixtures/flow/class-private-property/variance/output.json diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 1bf8e5a01f32..3b0af6521f11 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -124,7 +124,7 @@ export default class ExpressionParser extends LValParser { checkProto( prop: N.ObjectMember | N.SpreadElement, - isRecord: boolean, + isRecord: ?boolean, protoRef: { used: boolean }, refExpressionErrors: ?ExpressionErrors, ): void { @@ -402,7 +402,7 @@ export default class ExpressionParser extends LValParser { minPrec: number, ): N.Expression { if (this.isPrivateName(left)) { - // https://tc39.es/proposal-private-fields-in-in + // https://tc39.es/ecma262/#prod-RelationalExpression // RelationalExpression [In, Yield, Await] // [+In] PrivateIdentifier in ShiftExpression[?Yield, ?Await] @@ -1120,7 +1120,6 @@ export default class ExpressionParser extends LValParser { this.state.type === tt.bracketBarL ? tt.bracketBarR : tt.bracketR, /* canBePattern */ false, /* isTuple */ true, - refExpressionErrors, ); } case tt.bracketL: { @@ -1137,7 +1136,6 @@ export default class ExpressionParser extends LValParser { this.state.type === tt.braceBarL ? tt.braceBarR : tt.braceR, /* isPattern */ false, /* isRecord */ true, - refExpressionErrors, ); } case tt.braceL: { @@ -1513,21 +1511,6 @@ export default class ExpressionParser extends LValParser { return this.finishNode(node, "Super"); } - parseMaybePrivateName( - isPrivateNameAllowed: boolean, - ): N.PrivateName | N.Identifier { - const isPrivate = this.match(tt.privateName); - - if (isPrivate) { - if (!isPrivateNameAllowed) { - this.raise(this.state.start + 1, Errors.UnexpectedPrivateField); - } - return this.parsePrivateName(); - } else { - return this.parseIdentifier(true); - } - } - parsePrivateName(): N.PrivateName { const node = this.startNode(); const id = this.startNodeAt( @@ -1925,9 +1908,11 @@ export default class ExpressionParser extends LValParser { } } - const prop = this.parsePropertyDefinition(isPattern, refExpressionErrors); - if (!isPattern) { - // $FlowIgnore RestElement will never be returned if !isPattern + let prop; + if (isPattern) { + prop = this.parseBindingProperty(); + } else { + prop = this.parsePropertyDefinition(refExpressionErrors); this.checkProto(prop, isRecord, propHash, refExpressionErrors); } @@ -1974,9 +1959,8 @@ export default class ExpressionParser extends LValParser { // https://tc39.es/ecma262/#prod-PropertyDefinition parsePropertyDefinition( - isPattern: boolean, refExpressionErrors?: ?ExpressionErrors, - ): N.ObjectMember | N.SpreadElement | N.RestElement { + ): N.ObjectMember | N.SpreadElement { let decorators = []; if (this.match(tt.at)) { if (this.hasPlugin("decorators")) { @@ -1991,7 +1975,6 @@ export default class ExpressionParser extends LValParser { } const prop = this.startNode(); - let isGenerator = false; let isAsync = false; let isAccessor = false; let startPos; @@ -1999,14 +1982,6 @@ export default class ExpressionParser extends LValParser { if (this.match(tt.ellipsis)) { if (decorators.length) this.unexpected(); - if (isPattern) { - this.next(); - // Don't use parseRestBinding() as we only allow Identifier here. - prop.argument = this.parseIdentifier(); - this.checkCommaAfterRest(charCodes.rightCurlyBrace); - return this.finishNode(prop, "RestElement"); - } - return this.parseSpread(); } @@ -2017,24 +1992,17 @@ export default class ExpressionParser extends LValParser { prop.method = false; - if (isPattern || refExpressionErrors) { + if (refExpressionErrors) { startPos = this.state.start; startLoc = this.state.startLoc; } - if (!isPattern) { - isGenerator = this.eat(tt.star); - } - + let isGenerator = this.eat(tt.star); + this.parsePropertyNamePrefixOperator(prop); const containsEsc = this.state.containsEsc; - const key = this.parsePropertyName(prop, /* isPrivateNameAllowed */ false); + const key = this.parsePropertyName(prop); - if ( - !isPattern && - !isGenerator && - !containsEsc && - this.maybeAsyncOrAccessorProp(prop) - ) { + if (!isGenerator && !containsEsc && this.maybeAsyncOrAccessorProp(prop)) { const keyName = key.name; // https://tc39.es/ecma262/#prod-AsyncMethod // https://tc39.es/ecma262/#prod-AsyncGeneratorMethod @@ -2042,7 +2010,7 @@ export default class ExpressionParser extends LValParser { isAsync = true; this.resetPreviousNodeTrailingComments(key); isGenerator = this.eat(tt.star); - this.parsePropertyName(prop, /* isPrivateNameAllowed */ false); + this.parsePropertyName(prop); } // get PropertyName[?Yield, ?Await] () { FunctionBody[~Yield, ~Await] } // set PropertyName[?Yield, ?Await] ( PropertySetParameterList ) { FunctionBody[~Yield, ~Await] } @@ -2055,7 +2023,7 @@ export default class ExpressionParser extends LValParser { this.raise(this.state.pos, Errors.AccessorIsGenerator, keyName); this.next(); } - this.parsePropertyName(prop, /* isPrivateNameAllowed */ false); + this.parsePropertyName(prop); } } @@ -2065,7 +2033,7 @@ export default class ExpressionParser extends LValParser { startLoc, isGenerator, isAsync, - isPattern, + false /* isPattern */, isAccessor, refExpressionErrors, ); @@ -2231,7 +2199,6 @@ export default class ExpressionParser extends LValParser { parsePropertyName( prop: N.ObjectOrClassMember | N.ClassMember | N.TsNamedTypeElementBase, - isPrivateNameAllowed: boolean, ): N.Expression | N.Identifier { if (this.eat(tt.bracketL)) { (prop: $FlowSubtype).computed = true; @@ -2239,15 +2206,37 @@ export default class ExpressionParser extends LValParser { this.expect(tt.bracketR); } else { // We check if it's valid for it to be a private name when we push it. - const type = this.state.type; - (prop: $FlowFixMe).key = - type === tt.num || - type === tt.string || - type === tt.bigint || - type === tt.decimal - ? this.parseExprAtom() - : this.parseMaybePrivateName(isPrivateNameAllowed); - + const { type, value } = this.state; + let key; + // most un-computed property names are identifiers + if (tokenIsKeywordOrIdentifier(type)) { + key = this.parseIdentifier(true); + } else { + switch (type) { + case tt.num: + key = this.parseNumericLiteral(value); + break; + case tt.string: + key = this.parseStringLiteral(value); + break; + case tt.bigint: + key = this.parseBigIntLiteral(value); + break; + case tt.decimal: + key = this.parseDecimalLiteral(value); + break; + case tt.privateName: { + // the class private key has been handled in parseClassElementName + const privateKeyPos = this.state.start + 1; + this.raise(privateKeyPos, Errors.UnexpectedPrivateField); + key = this.parsePrivateName(); + break; + } + default: + throw this.unexpected(); + } + } + (prop: $FlowFixMe).key = key; if (type !== tt.privateName) { // ClassPrivateProperty is never computed, so we don't assign in that case. prop.computed = false; @@ -2974,4 +2963,10 @@ export default class ExpressionParser extends LValParser { this.eat(tt.braceR); return this.finishNode(node, "ModuleExpression"); } + + // Used in Flow plugin + parsePropertyNamePrefixOperator( + // eslint-disable-next-line no-unused-vars + prop: N.ObjectOrClassMember | N.ClassMember, + ): void {} } diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index 7b862be08f50..7cbb35e4c516 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -11,6 +11,10 @@ import type { Pattern, RestElement, SpreadElement, + /*:: ObjectOrClassMember, */ + /*:: ClassMember, */ + /*:: ObjectMember, */ + /*:: TsNamedTypeElementBase, */ /*:: Identifier, */ /*:: ObjectExpression, */ /*:: ObjectPattern, */ @@ -46,6 +50,19 @@ export default class LValParser extends NodeUtils { isRecord?: ?boolean, refExpressionErrors?: ?ExpressionErrors, ) => T; + +parseObjPropValue: ( + prop: any, + startPos: ?number, + startLoc: ?Position, + isGenerator: boolean, + isAsync: boolean, + isPattern: boolean, + isAccessor: boolean, + refExpressionErrors?: ?ExpressionErrors, + ) => void; + +parsePropertyName: ( + prop: ObjectOrClassMember | ClassMember | TsNamedTypeElementBase, + ) => Expression | Identifier; */ // Forward-declaration: defined in statement.js /*:: @@ -386,6 +403,38 @@ export default class LValParser extends NodeUtils { return elts; } + // https://tc39.es/ecma262/#prod-BindingRestProperty + parseBindingRestProperty(prop: RestElement): RestElement { + this.next(); // eat '...' + // Don't use parseRestBinding() as we only allow Identifier here. + prop.argument = this.parseIdentifier(); + this.checkCommaAfterRest(charCodes.rightCurlyBrace); + return this.finishNode(prop, "RestElement"); + } + + // https://tc39.es/ecma262/#prod-BindingProperty + parseBindingProperty(): ObjectMember | RestElement { + const prop = this.startNode(); + const { type, start: startPos, startLoc } = this.state; + if (type === tt.ellipsis) { + return this.parseBindingRestProperty(prop); + } else { + this.parsePropertyName(prop); + } + prop.method = false; + this.parseObjPropValue( + prop, + startPos, + startLoc, + false /* isGenerator */, + false /* isAsync */, + true /* isPattern */, + false /* isAccessor */, + ); + + return prop; + } + parseAssignableListItem( allowModifiers: ?boolean, decorators: Decorator[], diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 1170a7a9cc77..bb6cba97b93d 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -1437,6 +1437,7 @@ export default class StatementParser extends ExpressionParser { const publicMember: typeof publicMethod | typeof publicProp = publicMethod; member.static = isStatic; + this.parsePropertyNamePrefixOperator(member); if (this.eat(tt.star)) { // a generator @@ -1597,7 +1598,7 @@ export default class StatementParser extends ExpressionParser { } } - // https://tc39.es/proposal-class-fields/#prod-ClassElementName + // https://tc39.es/ecma262/#prod-ClassElementName parseClassElementName(member: N.ClassMember): N.Expression | N.Identifier { const { type, value, start } = this.state; if ( @@ -1608,11 +1609,16 @@ export default class StatementParser extends ExpressionParser { this.raise(start, Errors.StaticPrototype); } - if (type === tt.privateName && value === "constructor") { - this.raise(start, Errors.ConstructorClassPrivateField); + if (type === tt.privateName) { + if (value === "constructor") { + this.raise(start, Errors.ConstructorClassPrivateField); + } + const key = this.parsePrivateName(); + member.key = key; + return key; } - return this.parsePropertyName(member, /* isPrivateNameAllowed */ true); + return this.parsePropertyName(member); } parseClassStaticBlock( @@ -1733,7 +1739,7 @@ export default class StatementParser extends ExpressionParser { methodOrProp: N.ClassMethod | N.ClassProperty, ): void {} - // https://tc39.es/proposal-class-fields/#prod-FieldDefinition + // https://tc39.es/ecma262/#prod-FieldDefinition parseClassPrivateProperty( node: N.ClassPrivateProperty, ): N.ClassPrivateProperty { @@ -1742,14 +1748,14 @@ export default class StatementParser extends ExpressionParser { return this.finishNode(node, "ClassPrivateProperty"); } - // https://tc39.es/proposal-class-fields/#prod-FieldDefinition + // https://tc39.es/ecma262/#prod-FieldDefinition parseClassProperty(node: N.ClassProperty): N.ClassProperty { this.parseInitializer(node); this.semicolon(); return this.finishNode(node, "ClassProperty"); } - // https://tc39.es/proposal-class-fields/#prod-Initializer + // https://tc39.es/ecma262/#prod-Initializer parseInitializer(node: N.ClassProperty | N.ClassPrivateProperty): void { this.scope.enter(SCOPE_CLASS | SCOPE_SUPER); this.expressionScope.enter(newExpressionScope()); diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index da64aa526483..3ad3bc4b795e 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -264,19 +264,20 @@ export default class UtilParser extends Tokenizer { if (!refExpressionErrors) return false; const { shorthandAssign, doubleProto, optionalParameters } = refExpressionErrors; + // shorthandAssign >= 0 || doubleProto >= 0 || optionalParameters >= 0 + const hasErrors = shorthandAssign + doubleProto + optionalParameters > -3; if (!andThrow) { - return ( - shorthandAssign >= 0 || doubleProto >= 0 || optionalParameters >= 0 - ); - } - if (shorthandAssign >= 0) { - this.unexpected(shorthandAssign); - } - if (doubleProto >= 0) { - this.raise(doubleProto, Errors.DuplicateProto); - } - if (optionalParameters >= 0) { - this.unexpected(optionalParameters); + return hasErrors; + } else if (hasErrors) { + if (shorthandAssign >= 0) { + this.unexpected(shorthandAssign); + } + if (doubleProto >= 0) { + this.raise(doubleProto, Errors.DuplicateProto); + } + if (optionalParameters >= 0) { + this.unexpected(optionalParameters); + } } } @@ -304,7 +305,7 @@ export default class UtilParser extends Tokenizer { /* * Return the string value of a given private name * WITHOUT `#` - * @see {@link https://tc39.es/proposal-class-fields/#sec-private-names-static-semantics-stringvalue} + * @see {@link https://tc39.es/ecma262/#sec-static-semantics-stringvalue} */ getPrivateNameSV(node: Node): string { return node.id.name; diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index a9e309bdb72c..660fcb593e14 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -2475,15 +2475,10 @@ export default (superClass: Class): Class => } } - parsePropertyName( - node: N.ObjectOrClassMember | N.ClassMember | N.TsNamedTypeElementBase, - isPrivateNameAllowed: boolean, - ): N.Identifier { - const variance = this.flowParseVariance(); - const key = super.parsePropertyName(node, isPrivateNameAllowed); - // $FlowIgnore ("variance" not defined on TsNamedTypeElementBase) - node.variance = variance; - return key; + parsePropertyNamePrefixOperator( + node: N.ObjectOrClassMember | N.ClassMember, + ): void { + node.variance = this.flowParseVariance(); } // parse type parameters for object method shorthand diff --git a/packages/babel-parser/src/plugins/typescript/index.js b/packages/babel-parser/src/plugins/typescript/index.js index f4f2580a2415..c749d838655f 100644 --- a/packages/babel-parser/src/plugins/typescript/index.js +++ b/packages/babel-parser/src/plugins/typescript/index.js @@ -780,7 +780,7 @@ export default (superClass: Class): Class => return idx; } - this.parsePropertyName(node, /* isPrivateNameAllowed */ false); + this.parsePropertyName(node); if ( !node.computed && node.key.type === "Identifier" && @@ -788,7 +788,7 @@ export default (superClass: Class): Class => this.tsTokenCanFollowModifier() ) { node.kind = node.key.name; - this.parsePropertyName(node, /* isPrivateNameAllowed */ false); + this.parsePropertyName(node); } return this.tsParsePropertyOrMethodSignature(node, !!node.readonly); } diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index de307580843b..f967774c78d3 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -816,6 +816,7 @@ export type ClassPrivateMethod = NodeBase & type: "ClassPrivateMethod", key: PrivateName, computed: false, + variance?: ?FlowVariance, // TODO: Not in spec }; export type ClassProperty = ClassMemberBase & @@ -825,6 +826,8 @@ export type ClassProperty = ClassMemberBase & value: ?Expression, // TODO: Not in spec that this is nullable. typeAnnotation?: ?TypeAnnotationBase, // TODO: Not in spec + + // Flow only: variance?: ?FlowVariance, // TODO: Not in spec // TypeScript only: (TODO: Not in spec) @@ -847,6 +850,9 @@ export type ClassPrivateProperty = NodeBase & { definite?: true, readonly?: true, override?: true, + + // Flow only + variance?: ?FlowVariance, }; export type OptClassDeclaration = ClassBase & diff --git a/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/input.js b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/input.js index 234c9a49371e..8223b3e1a1c9 100644 --- a/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/input.js +++ b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/input.js @@ -1,3 +1,3 @@ class C { - #p = ({ #x: 42 }); + #p = ({ #x() {} }); } diff --git a/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/output.json b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/output.json index 7c27ba1380b6..10e0158086e0 100644 --- a/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/output.json +++ b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-method/output.json @@ -1,18 +1,18 @@ { "type": "File", - "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, "errors": [ "SyntaxError: Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p). (2:11)" ], "program": { "type": "Program", - "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, "sourceType": "script", "interpreter": null, "body": [ { "type": "ClassDeclaration", - "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "start":0,"end":33,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, "id": { "type": "Identifier", "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, @@ -21,11 +21,11 @@ "superClass": null, "body": { "type": "ClassBody", - "start":8,"end":32,"loc":{"start":{"line":1,"column":8},"end":{"line":3,"column":1}}, + "start":8,"end":33,"loc":{"start":{"line":1,"column":8},"end":{"line":3,"column":1}}, "body": [ { "type": "ClassPrivateProperty", - "start":12,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":20}}, + "start":12,"end":31,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":21}}, "static": false, "key": { "type": "PrivateName", @@ -38,12 +38,12 @@ }, "value": { "type": "ObjectExpression", - "start":18,"end":28,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":18}}, + "start":18,"end":29,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":19}}, "properties": [ { - "type": "ObjectProperty", - "start":20,"end":26,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":16}}, - "method": false, + "type": "ObjectMethod", + "start":20,"end":27,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":17}}, + "method": true, "key": { "type": "PrivateName", "start":20,"end":22,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":12}}, @@ -53,15 +53,16 @@ "name": "x" } }, - "shorthand": false, - "value": { - "type": "NumericLiteral", - "start":24,"end":26,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":16}}, - "extra": { - "rawValue": 42, - "raw": "42" - }, - "value": 42 + "kind": "method", + "id": null, + "generator": false, + "async": false, + "params": [], + "body": { + "type": "BlockStatement", + "start":25,"end":27,"loc":{"start":{"line":2,"column":15},"end":{"line":2,"column":17}}, + "body": [], + "directives": [] } } ], diff --git a/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/input.js b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/input.js new file mode 100644 index 000000000000..234c9a49371e --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/input.js @@ -0,0 +1,3 @@ +class C { + #p = ({ #x: 42 }); +} diff --git a/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/output.json b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/output.json new file mode 100644 index 000000000000..7c27ba1380b6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2022/class-private-properties/invalid-object-property/output.json @@ -0,0 +1,80 @@ +{ + "type": "File", + "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "errors": [ + "SyntaxError: Private names can only be used as the name of a class element (i.e. class C { #p = 42; #m() {} } )\n or a property of member expression (i.e. this.#p). (2:11)" + ], + "program": { + "type": "Program", + "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "sourceType": "script", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"C"}, + "name": "C" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":32,"loc":{"start":{"line":1,"column":8},"end":{"line":3,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":12,"end":30,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":20}}, + "static": false, + "key": { + "type": "PrivateName", + "start":12,"end":14,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":4}}, + "id": { + "type": "Identifier", + "start":13,"end":14,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":4},"identifierName":"p"}, + "name": "p" + } + }, + "value": { + "type": "ObjectExpression", + "start":18,"end":28,"loc":{"start":{"line":2,"column":8},"end":{"line":2,"column":18}}, + "properties": [ + { + "type": "ObjectProperty", + "start":20,"end":26,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":16}}, + "method": false, + "key": { + "type": "PrivateName", + "start":20,"end":22,"loc":{"start":{"line":2,"column":10},"end":{"line":2,"column":12}}, + "id": { + "type": "Identifier", + "start":21,"end":22,"loc":{"start":{"line":2,"column":11},"end":{"line":2,"column":12},"identifierName":"x"}, + "name": "x" + } + }, + "shorthand": false, + "value": { + "type": "NumericLiteral", + "start":24,"end":26,"loc":{"start":{"line":2,"column":14},"end":{"line":2,"column":16}}, + "extra": { + "rawValue": 42, + "raw": "42" + }, + "value": 42 + } + } + ], + "extra": { + "parenthesized": true, + "parenStart": 17 + } + } + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/input.js b/packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/input.js new file mode 100644 index 000000000000..2742bdba5bbd --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/input.js @@ -0,0 +1 @@ +var { @foo foo } = foo; diff --git a/packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/options.json b/packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/options.json new file mode 100644 index 000000000000..d362b696ed5f --- /dev/null +++ b/packages/babel-parser/test/fixtures/experimental/decorators/invalid-decorator-object-pattern/options.json @@ -0,0 +1,4 @@ +{ + "plugins": [["decorators-legacy"]], + "throws": "Unexpected token (1:6)" +} diff --git a/packages/babel-parser/test/fixtures/flow/class-private-property/variance/input.js b/packages/babel-parser/test/fixtures/flow/class-private-property/variance/input.js new file mode 100644 index 000000000000..045503523dfb --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/class-private-property/variance/input.js @@ -0,0 +1,4 @@ +class A { + +#foo; + -#bar; +} diff --git a/packages/babel-parser/test/fixtures/flow/class-private-property/variance/output.json b/packages/babel-parser/test/fixtures/flow/class-private-property/variance/output.json new file mode 100644 index 000000000000..838966d5c986 --- /dev/null +++ b/packages/babel-parser/test/fixtures/flow/class-private-property/variance/output.json @@ -0,0 +1,69 @@ +{ + "type": "File", + "start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "program": { + "type": "Program", + "start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "sourceType": "module", + "interpreter": null, + "body": [ + { + "type": "ClassDeclaration", + "start":0,"end":29,"loc":{"start":{"line":1,"column":0},"end":{"line":4,"column":1}}, + "id": { + "type": "Identifier", + "start":6,"end":7,"loc":{"start":{"line":1,"column":6},"end":{"line":1,"column":7},"identifierName":"A"}, + "name": "A" + }, + "superClass": null, + "body": { + "type": "ClassBody", + "start":8,"end":29,"loc":{"start":{"line":1,"column":8},"end":{"line":4,"column":1}}, + "body": [ + { + "type": "ClassPrivateProperty", + "start":12,"end":18,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":8}}, + "static": false, + "variance": { + "type": "Variance", + "start":12,"end":13,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":3}}, + "kind": "plus" + }, + "key": { + "type": "PrivateName", + "start":13,"end":17,"loc":{"start":{"line":2,"column":3},"end":{"line":2,"column":7}}, + "id": { + "type": "Identifier", + "start":14,"end":17,"loc":{"start":{"line":2,"column":4},"end":{"line":2,"column":7},"identifierName":"foo"}, + "name": "foo" + } + }, + "value": null + }, + { + "type": "ClassPrivateProperty", + "start":21,"end":27,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":8}}, + "static": false, + "variance": { + "type": "Variance", + "start":21,"end":22,"loc":{"start":{"line":3,"column":2},"end":{"line":3,"column":3}}, + "kind": "minus" + }, + "key": { + "type": "PrivateName", + "start":22,"end":26,"loc":{"start":{"line":3,"column":3},"end":{"line":3,"column":7}}, + "id": { + "type": "Identifier", + "start":23,"end":26,"loc":{"start":{"line":3,"column":4},"end":{"line":3,"column":7},"identifierName":"bar"}, + "name": "bar" + } + }, + "value": null + } + ] + } + } + ], + "directives": [] + } +} \ No newline at end of file