From 40f488bc608a723896ccace121c0d945085ade7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 17 Nov 2020 16:44:52 -0500 Subject: [PATCH 01/13] refactor: introduce isPrivateName and getPrivateNameSV --- .../babel-parser/src/parser/expression.js | 11 ++++++---- packages/babel-parser/src/parser/statement.js | 21 ++++++++++++------- packages/babel-parser/src/parser/util.js | 17 +++++++++++++++ 3 files changed, 38 insertions(+), 11 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 9e11259a47e9..d15afd39ac34 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -518,7 +518,7 @@ export default class ExpressionParser extends LValParser { } else if ( (arg.type === "MemberExpression" || arg.type === "OptionalMemberExpression") && - arg.property.type === "PrivateName" + this.isPrivateName(arg.property) ) { this.raise(node.start, Errors.DeletePrivateField); } @@ -662,11 +662,14 @@ export default class ExpressionParser extends LValParser { ? this.parseExpression() : this.parseMaybePrivateName(true); - if (property.type === "PrivateName") { + if (this.isPrivateName(property)) { if (node.object.type === "Super") { this.raise(startPos, Errors.SuperPrivateField); } - this.classScope.usePrivateName(property.id.name, property.start); + this.classScope.usePrivateName( + this.getPrivateNameSV(property), + property.start, + ); } node.property = property; @@ -1923,7 +1926,7 @@ export default class ExpressionParser extends LValParser { ? this.parseExprAtom() : this.parseMaybePrivateName(isPrivateNameAllowed); - if (prop.key.type !== "PrivateName") { + if (!this.isPrivateName(prop.key)) { // ClassPrivateProperty is never computed, so we don't assign in that case. prop.computed = false; } diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 3a72687b2531..cf3ddc2306f7 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -1346,7 +1346,7 @@ export default class StatementParser extends ExpressionParser { method.kind = "method"; this.parseClassElementName(method); - if (method.key.type === "PrivateName") { + if (this.isPrivateName(method.key)) { // Private generator method this.pushClassPrivateMethod(classBody, privateMethod, true, false); return; @@ -1370,7 +1370,7 @@ export default class StatementParser extends ExpressionParser { const containsEsc = this.state.containsEsc; const key = this.parseClassElementName(member); - const isPrivate = key.type === "PrivateName"; + const isPrivate = this.isPrivateName(key); // Check the key is not a computed expression or string literal. const isSimple = key.type === "Identifier"; const maybeQuestionTokenStart = this.state.start; @@ -1431,7 +1431,7 @@ export default class StatementParser extends ExpressionParser { this.parseClassElementName(method); this.parsePostMemberNameModifiers(publicMember); - if (method.key.type === "PrivateName") { + if (this.isPrivateName(method.key)) { // private async method this.pushClassPrivateMethod( classBody, @@ -1465,7 +1465,7 @@ export default class StatementParser extends ExpressionParser { // The so-called parsed name would have been "get/set": get the real name. this.parseClassElementName(publicMethod); - if (method.key.type === "PrivateName") { + if (this.isPrivateName(method.key)) { // private getter/setter this.pushClassPrivateMethod(classBody, privateMethod, false, false); } else { @@ -1508,7 +1508,10 @@ export default class StatementParser extends ExpressionParser { this.raise(key.start, Errors.StaticPrototype); } - if (key.type === "PrivateName" && key.id.name === "constructor") { + if ( + this.isPrivateName(key) && + this.getPrivateNameSV(key) === "constructor" + ) { this.raise(key.start, Errors.ConstructorClassPrivateField); } @@ -1571,7 +1574,7 @@ export default class StatementParser extends ExpressionParser { classBody.body.push(node); this.classScope.declarePrivateName( - node.key.id.name, + this.getPrivateNameSV(node.key), CLASS_ELEMENT_OTHER, node.key.start, ); @@ -1627,7 +1630,11 @@ export default class StatementParser extends ExpressionParser { ? CLASS_ELEMENT_STATIC_SETTER : CLASS_ELEMENT_INSTANCE_SETTER : CLASS_ELEMENT_OTHER; - this.classScope.declarePrivateName(node.key.id.name, kind, node.key.start); + this.classScope.declarePrivateName( + this.getPrivateNameSV(node.key), + kind, + node.key.start, + ); } // Overridden in typescript.js diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index 80f0532f1fe3..47c6a27ad8f5 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -252,6 +252,23 @@ export default class UtilParser extends Tokenizer { this.match(tt.decimal) ); } + + /* + * Test if given node is a PrivateName + * will be overridden in ESTree plugin + */ + isPrivateName(node: Node): boolean { + return node.type === "PrivateName"; + } + + /* + * Return the string value of a given private name + * WITHOUT `#` + * @see {@link https://tc39.es/proposal-class-fields/#sec-private-names-static-semantics-stringvalue} + */ + getPrivateNameSV(node: Node): string { + return node.id.name; + } } /** From 054e7db91a4bc8fdff6e2b4d125ea83757d8e472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 13:36:08 -0500 Subject: [PATCH 02/13] feat: check recoverable errors on estree-throw --- .../test/helpers/runFixtureTests.js | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/packages/babel-parser/test/helpers/runFixtureTests.js b/packages/babel-parser/test/helpers/runFixtureTests.js index 4b03ee14fbae..2ce9e888d5ba 100644 --- a/packages/babel-parser/test/helpers/runFixtureTests.js +++ b/packages/babel-parser/test/helpers/runFixtureTests.js @@ -83,7 +83,13 @@ export function runThrowTestsWithEstree(fixturesPath, parseFunction) { Object.keys(fixtures).forEach(function (name) { fixtures[name].forEach(function (testSuite) { testSuite.tests.forEach(function (task) { - if (!task.options.throws) return; + if (!task.options.throws) { + const hasErrors = + !task.disabled && "errors" in JSON.parse(task.expect.code); + if (!hasErrors) { + return; + } + } task.options.plugins = task.options.plugins || []; task.options.plugins.push("estree"); @@ -92,7 +98,7 @@ export function runThrowTestsWithEstree(fixturesPath, parseFunction) { testFn(name + "/" + testSuite.title + "/" + task.title, function () { try { - runTest(task, parseFunction); + runTest(task, parseFunction, true); } catch (err) { const fixturePath = `${path.relative( rootPath, @@ -126,7 +132,19 @@ function save(test, ast) { ); } -function runTest(test, parseFunction) { +/** + * run parser on given tests + * + * @param {Test} A {@link packages/babel-helper-fixtures/src/index.js Test} instance + generated from `getFixtures` + * @param {*} parseFunction A parser with the same interface of `@babel/parser#parse` + * @param {boolean} [compareErrorsOnly=false] Whether we should only compare the "errors" + * of generated ast against the expected AST. Used for `runThrowTestsWithEstree` where an + * ESTree AST is generated but we want to make sure `@babel/parser` still throws expected + * recoverable errors on given code locations. + * @returns {void} + */ +function runTest(test, parseFunction, compareErrorsOnly = false) { const opts = test.options; if (opts.throws && test.expect.code) { @@ -189,6 +207,11 @@ function runTest(test, parseFunction) { throw new Error( "Expected error message: " + opts.throws + ". But parsing succeeded.", ); + } else if (compareErrorsOnly) { + const mis = misMatch(JSON.parse(test.expect.code).errors, ast.errors); + if (mis) { + throw new Error(mis); + } } else { const mis = misMatch(JSON.parse(test.expect.code), ast); From 6dcca23ce987d7a3171e56974f04ad130c6238e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 15:59:34 -0500 Subject: [PATCH 03/13] fix: pass through all params of parseBlockBody --- packages/babel-parser/src/plugins/estree.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index c96478e1511f..aef62b84771c 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -170,11 +170,9 @@ export default (superClass: Class): Class => parseBlockBody( node: N.BlockStatementLike, - allowDirectives: ?boolean, - topLevel: boolean, - end: TokenType, + ...args: [?boolean, boolean, TokenType, void | (boolean => void)] ): void { - super.parseBlockBody(node, allowDirectives, topLevel, end); + super.parseBlockBody(node, ...args); const directiveStatements = node.directives.map(d => this.directiveToStmt(d), From ab0e2c0b3e0634af8506a178bdd3df5be41c40e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 16:10:56 -0500 Subject: [PATCH 04/13] fix: set bigInt to null when invalid bigInt value is parsed e.g. 0.1n --- packages/babel-parser/src/plugins/estree.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index aef62b84771c..8b47b9d8ab6d 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -35,8 +35,13 @@ export default (superClass: Class): Class => estreeParseBigIntLiteral(value: any): N.Node { // https://github.com/estree/estree/blob/master/es2020.md#bigintliteral - // $FlowIgnore - const bigInt = typeof BigInt !== "undefined" ? BigInt(value) : null; + let bigInt; + try { + // $FlowIgnore + bigInt = BigInt(value); + } catch { + bigInt = null; + } const node = this.estreeParseLiteral(bigInt); node.bigint = String(node.value || value); From 3391585b4f3eb79824d3c2e1da88a0223843b05b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 16:20:55 -0500 Subject: [PATCH 05/13] fix: use string literal value in error message When estree plugin is enabled, stringLiteral#extra.raw is not accessible. Use StringLiteral#value instead. --- packages/babel-parser/src/parser/error-message.js | 2 +- packages/babel-parser/src/parser/statement.js | 2 +- .../string-exported-binding-without-from/output.json | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/babel-parser/src/parser/error-message.js b/packages/babel-parser/src/parser/error-message.js index 7ad94f3256de..90df3c5f38a2 100644 --- a/packages/babel-parser/src/parser/error-message.js +++ b/packages/babel-parser/src/parser/error-message.js @@ -51,7 +51,7 @@ export const ErrorMessages = Object.freeze({ ElementAfterRest: "Rest element must be last element", EscapedCharNotAnIdentifier: "Invalid Unicode escape", ExportBindingIsString: - "A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { %0 as '%1' } from 'some-module'`?", + "A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { '%0' as '%1' } from 'some-module'`?", ExportDefaultFromAsIdentifier: "'from' is not allowed as an identifier after 'export default'", ForInOfLoopInitializer: diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index cf3ddc2306f7..986d242ee9d1 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -1987,7 +1987,7 @@ export default class StatementParser extends ExpressionParser { this.raise( specifier.start, Errors.ExportBindingIsString, - local.extra.raw, + local.value, exportedName, ); } else { diff --git a/packages/babel-parser/test/fixtures/experimental/module-string-names/string-exported-binding-without-from/output.json b/packages/babel-parser/test/fixtures/experimental/module-string-names/string-exported-binding-without-from/output.json index ddab0a530b70..5bfdc8b3f96e 100644 --- a/packages/babel-parser/test/fixtures/experimental/module-string-names/string-exported-binding-without-from/output.json +++ b/packages/babel-parser/test/fixtures/experimental/module-string-names/string-exported-binding-without-from/output.json @@ -2,8 +2,8 @@ "type": "File", "start":0,"end":45,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":45}}, "errors": [ - "SyntaxError: A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { \"學而時習之,不亦說乎?\" as '學而時習之,不亦說乎?' } from 'some-module'`? (1:9)", - "SyntaxError: A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { \"吾道一以貫之。\" as '忠恕。' } from 'some-module'`? (1:24)" + "SyntaxError: A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { '學而時習之,不亦說乎?' as '學而時習之,不亦說乎?' } from 'some-module'`? (1:9)", + "SyntaxError: A string literal cannot be used as an exported binding without `from`.\n- Did you mean `export { '吾道一以貫之。' as '忠恕。' } from 'some-module'`? (1:24)" ], "program": { "type": "Program", From 18eeedc57fdffa49a79cd90f4c6ed0a9794256c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 16:36:02 -0500 Subject: [PATCH 06/13] refactor: introduce hasPropertyAsPrivateName --- packages/babel-parser/src/parser/expression.js | 6 +----- packages/babel-parser/src/parser/util.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index d15afd39ac34..33f5e37f7b51 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -515,11 +515,7 @@ export default class ExpressionParser extends LValParser { if (arg.type === "Identifier") { this.raise(node.start, Errors.StrictDelete); - } else if ( - (arg.type === "MemberExpression" || - arg.type === "OptionalMemberExpression") && - this.isPrivateName(arg.property) - ) { + } else if (this.hasPropertyAsPrivateName(arg)) { this.raise(node.start, Errors.DeletePrivateField); } } diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index 47c6a27ad8f5..8c31fb1d5d64 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -269,6 +269,19 @@ export default class UtilParser extends Tokenizer { getPrivateNameSV(node: Node): string { return node.id.name; } + + /* + * Return whether the given node is a member/optional chain that + * contains a private name as its property + * It is overridden in ESTree plugin + */ + hasPropertyAsPrivateName(node: Node): boolean { + return ( + (node.type === "MemberExpression" || + node.type === "OptionalMemberExpression") && + this.isPrivateName(node.property) + ); + } } /** From eeee5daa4762b29562f0effb1d431ee6d6630013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 16:40:02 -0500 Subject: [PATCH 07/13] fix: adapt to ChainExpression --- packages/babel-parser/src/plugins/estree.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index 8b47b9d8ab6d..afbeb4f7fe39 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -453,4 +453,11 @@ export default (superClass: Class): Class => return node; } + + hasPropertyAsPrivateName(node: N.Node): boolean { + if (node.type === "ChainExpression") { + node = node.expression; + } + return super.hasPropertyAsPrivateName(node); + } }; From 356c1969b19cf8b06868ebb3c205c9881a1adbe6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 16:59:35 -0500 Subject: [PATCH 08/13] fix: port checkLVal early return for method in object pattern --- packages/babel-parser/src/plugins/estree.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index afbeb4f7fe39..abd635c9619c 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -128,6 +128,12 @@ export default (superClass: Class): Class => switch (expr.type) { case "ObjectPattern": expr.properties.forEach(prop => { + // If we find here a method or accessor, it's because this was originally + // an ObjectExpression which has then been converted. + // toAssignable already reported this error with a nicer message. + if (prop.kind === "get" || prop.kind === "set" || prop.method) { + return; + } this.checkLVal( prop.type === "Property" ? prop.value : prop, "object destructuring pattern", @@ -351,9 +357,9 @@ export default (superClass: Class): Class => toAssignableObjectExpressionProp(prop: N.Node, ...args) { if (prop.kind === "get" || prop.kind === "set") { - throw this.raise(prop.key.start, Errors.PatternHasAccessor); + this.raise(prop.key.start, Errors.PatternHasAccessor); } else if (prop.method) { - throw this.raise(prop.key.start, Errors.PatternHasMethod); + this.raise(prop.key.start, Errors.PatternHasMethod); } else { super.toAssignableObjectExpressionProp(prop, ...args); } From 5ddb9513a2dee45c1a5b94019b06e5bab13b460a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 17:36:35 -0500 Subject: [PATCH 09/13] fix: throw new a?.() on estree --- packages/babel-parser/src/parser/expression.js | 8 ++------ packages/babel-parser/src/parser/util.js | 7 +++++++ packages/babel-parser/src/plugins/estree.js | 4 ++++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 33f5e37f7b51..034b58e057c4 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -614,12 +614,12 @@ export default class ExpressionParser extends LValParser { let optional = false; if (this.match(tt.questionDot)) { - state.optionalChainMember = optional = true; if (noCalls && this.lookaheadCharCode() === charCodes.leftParenthesis) { // stop at `?.` when parsing `new a?.()` state.stop = true; return base; } + state.optionalChainMember = optional = true; this.next(); } @@ -1495,13 +1495,9 @@ export default class ExpressionParser extends LValParser { // https://tc39.es/ecma262/#prod-NewExpression parseNew(node: N.Expression): N.NewExpression { node.callee = this.parseNoCallExpr(); - if (node.callee.type === "Import") { this.raise(node.callee.start, Errors.ImportCallNotNewExpression); - } else if ( - node.callee.type === "OptionalMemberExpression" || - node.callee.type === "OptionalCallExpression" - ) { + } else if (this.isOptionalChain(node.callee)) { this.raise(this.state.lastTokEnd, Errors.OptionalChainingNoNew); } else if (this.eat(tt.questionDot)) { this.raise(this.state.start, Errors.OptionalChainingNoNew); diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index 8c31fb1d5d64..8839788e3eb2 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -282,6 +282,13 @@ export default class UtilParser extends Tokenizer { this.isPrivateName(node.property) ); } + + isOptionalChain(node: Node): boolean { + return ( + node.type === "OptionalMemberExpression" || + node.type === "OptionalCallExpression" + ); + } } /** diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index abd635c9619c..7a8c5845965c 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -466,4 +466,8 @@ export default (superClass: Class): Class => } return super.hasPropertyAsPrivateName(node); } + + isOptionalChain(node) { + return node.type === "ChainExpression"; + } }; From 105c2cc469cfdca3135f50d6fba620a8913cff02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 17:45:34 -0500 Subject: [PATCH 10/13] fix: early return for __proto__ in accessors --- packages/babel-parser/src/plugins/estree.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index 7a8c5845965c..309ae7d67ce2 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -131,7 +131,7 @@ export default (superClass: Class): Class => // If we find here a method or accessor, it's because this was originally // an ObjectExpression which has then been converted. // toAssignable already reported this error with a nicer message. - if (prop.kind === "get" || prop.kind === "set" || prop.method) { + if (this.isMethodOrAccessor(prop)) { return; } this.checkLVal( @@ -146,17 +146,18 @@ export default (superClass: Class): Class => } } + isMethodOrAccessor(node: N.Node): boolean { + return node.method || node.kind === "get" || node.kind === "set"; + } + checkProto( prop: N.ObjectMember | N.SpreadElement, - isRecord: boolean, - protoRef: { used: boolean }, - refExpressionErrors: ?ExpressionErrors, + ...args: [boolean, { used: boolean }, ?ExpressionErrors] ): void { - // $FlowIgnore: check prop.method and fallback to super method - if (prop.method) { + if (this.isMethodOrAccessor(prop)) { return; } - super.checkProto(prop, isRecord, protoRef, refExpressionErrors); + super.checkProto(prop, ...args); } isValidDirective(stmt: N.Statement): boolean { From 85268f90002448297fce1d2a8194431a943585b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 18:04:44 -0500 Subject: [PATCH 11/13] fix: test record element via isObjectProperty --- packages/babel-parser/src/parser/expression.js | 2 +- packages/babel-parser/src/parser/lval.js | 2 +- packages/babel-parser/src/parser/util.js | 4 ++++ packages/babel-parser/src/plugins/estree.js | 6 +++++- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 034b58e057c4..23898bfadad4 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -1599,7 +1599,7 @@ export default class ExpressionParser extends LValParser { if ( isRecord && - prop.type !== "ObjectProperty" && + !this.isObjectProperty(prop) && prop.type !== "SpreadElement" ) { this.raise(prop.start, Errors.InvalidRecordProperty); diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index 14ca1fd61e72..d77802393a83 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -445,7 +445,7 @@ export default class LValParser extends NodeUtils { case "ObjectPattern": for (let prop of expr.properties) { - if (prop.type === "ObjectProperty") prop = prop.value; + if (this.isObjectProperty(prop)) prop = prop.value; // If we find here an ObjectMethod, it's because this was originally // an ObjectExpression which has then been converted. // toAssignable already reported this error with a nicer message. diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index 8839788e3eb2..1350ceff6ec6 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -289,6 +289,10 @@ export default class UtilParser extends Tokenizer { node.type === "OptionalCallExpression" ); } + + isObjectProperty(node: Node): boolean { + return node.type === "ObjectProperty"; + } } /** diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index 309ae7d67ce2..fce70af8ad92 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -468,7 +468,11 @@ export default (superClass: Class): Class => return super.hasPropertyAsPrivateName(node); } - isOptionalChain(node) { + isOptionalChain(node: N.Node): boolean { return node.type === "ChainExpression"; } + + isObjectProperty(node: N.Node): boolean { + return node.type === "Property" && node.kind === "init" && !node.method; + } }; From 3cc4e5ece76845c0e28e54e232e909774f264367 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 18:31:56 -0500 Subject: [PATCH 12/13] fix: pass through isLHS in toAssignable --- packages/babel-parser/src/parser/lval.js | 2 +- packages/babel-parser/src/plugins/estree.js | 15 +++------------ 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index d77802393a83..14ca1fd61e72 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -445,7 +445,7 @@ export default class LValParser extends NodeUtils { case "ObjectPattern": for (let prop of expr.properties) { - if (this.isObjectProperty(prop)) prop = prop.value; + if (prop.type === "ObjectProperty") prop = prop.value; // If we find here an ObjectMethod, it's because this was originally // an ObjectExpression which has then been converted. // toAssignable already reported this error with a nicer message. diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index fce70af8ad92..f0cfca39f0a2 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -8,15 +8,6 @@ import type { Position } from "../util/location"; import { type BindingTypes } from "../util/scopeflags"; import { Errors } from "../parser/error"; -function isSimpleProperty(node: N.Node): boolean { - return ( - node != null && - node.type === "Property" && - node.kind === "init" && - node.method === false - ); -} - export default (superClass: Class): Class => class extends superClass { estreeParseRegExpLiteral({ pattern, flags }: N.RegExpLiteral): N.Node { @@ -103,7 +94,7 @@ export default (superClass: Class): Class => } checkDeclaration(node: N.Pattern | N.ObjectProperty): void { - if (isSimpleProperty(node)) { + if (node != null && this.isObjectProperty(node)) { this.checkDeclaration(((node: any): N.EstreeProperty).value); } else { super.checkDeclaration(node); @@ -347,8 +338,8 @@ export default (superClass: Class): Class => } toAssignable(node: N.Node, isLHS: boolean = false): N.Node { - if (isSimpleProperty(node)) { - this.toAssignable(node.value); + if (node != null && this.isObjectProperty(node)) { + this.toAssignable(node.value, isLHS); return node; } From c962cb3d3fdea5d20ad3e11869e1d059180b4191 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Thu, 19 Nov 2020 18:38:48 -0500 Subject: [PATCH 13/13] refactor: introduce isObjectMethod methods --- .../babel-parser/src/parser/expression.js | 3 +- packages/babel-parser/src/parser/lval.js | 4 +- packages/babel-parser/src/parser/util.js | 4 ++ packages/babel-parser/src/plugins/estree.js | 50 ++----------------- 4 files changed, 12 insertions(+), 49 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 23898bfadad4..d534c5a9acb6 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -94,8 +94,9 @@ export default class ExpressionParser extends LValParser { ): void { if ( prop.type === "SpreadElement" || - prop.type === "ObjectMethod" || + this.isObjectMethod(prop) || prop.computed || + // $FlowIgnore prop.shorthand ) { return; diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index 14ca1fd61e72..4da763b144b4 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -445,11 +445,11 @@ export default class LValParser extends NodeUtils { case "ObjectPattern": for (let prop of expr.properties) { - if (prop.type === "ObjectProperty") prop = prop.value; + if (this.isObjectProperty(prop)) prop = prop.value; // If we find here an ObjectMethod, it's because this was originally // an ObjectExpression which has then been converted. // toAssignable already reported this error with a nicer message. - else if (prop.type === "ObjectMethod") continue; + else if (this.isObjectMethod(prop)) continue; this.checkLVal( prop, diff --git a/packages/babel-parser/src/parser/util.js b/packages/babel-parser/src/parser/util.js index 1350ceff6ec6..9244cc983e51 100644 --- a/packages/babel-parser/src/parser/util.js +++ b/packages/babel-parser/src/parser/util.js @@ -293,6 +293,10 @@ export default class UtilParser extends Tokenizer { isObjectProperty(node: Node): boolean { return node.type === "ObjectProperty"; } + + isObjectMethod(node: Node): boolean { + return node.type === "ObjectMethod"; + } } /** diff --git a/packages/babel-parser/src/plugins/estree.js b/packages/babel-parser/src/plugins/estree.js index f0cfca39f0a2..3368b0f1386b 100644 --- a/packages/babel-parser/src/plugins/estree.js +++ b/packages/babel-parser/src/plugins/estree.js @@ -5,7 +5,6 @@ import type Parser from "../parser"; import type { ExpressionErrors } from "../parser/util"; import * as N from "../types"; import type { Position } from "../util/location"; -import { type BindingTypes } from "../util/scopeflags"; import { Errors } from "../parser/error"; export default (superClass: Class): Class => @@ -106,51 +105,6 @@ export default (superClass: Class): Class => .params; } - checkLVal( - expr: N.Expression, - contextDescription: string, - ...args: [ - BindingTypes | void, - ?Set, - boolean | void, - boolean | void, - ] - ): void { - switch (expr.type) { - case "ObjectPattern": - expr.properties.forEach(prop => { - // If we find here a method or accessor, it's because this was originally - // an ObjectExpression which has then been converted. - // toAssignable already reported this error with a nicer message. - if (this.isMethodOrAccessor(prop)) { - return; - } - this.checkLVal( - prop.type === "Property" ? prop.value : prop, - "object destructuring pattern", - ...args, - ); - }); - break; - default: - super.checkLVal(expr, contextDescription, ...args); - } - } - - isMethodOrAccessor(node: N.Node): boolean { - return node.method || node.kind === "get" || node.kind === "set"; - } - - checkProto( - prop: N.ObjectMember | N.SpreadElement, - ...args: [boolean, { used: boolean }, ?ExpressionErrors] - ): void { - if (this.isMethodOrAccessor(prop)) { - return; - } - super.checkProto(prop, ...args); - } - isValidDirective(stmt: N.Statement): boolean { return ( stmt.type === "ExpressionStatement" && @@ -466,4 +420,8 @@ export default (superClass: Class): Class => isObjectProperty(node: N.Node): boolean { return node.type === "Property" && node.kind === "init" && !node.method; } + + isObjectMethod(node: N.Node): boolean { + return node.method || node.kind === "get" || node.kind === "set"; + } };