From 36c5403fff6fed86e2fb75ba9a9e3f8bef2cd98c Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Sat, 15 Jun 2019 10:54:47 +0800 Subject: [PATCH 1/3] Disallow "let" as name at lexical bindings --- packages/babel-parser/src/parser/statement.js | 25 +++++++++++++++++++ .../let/let-at-binding-list-fail-1/input.js | 1 + .../let-at-binding-list-fail-1/options.json | 3 +++ .../let/let-at-binding-list-fail-2/input.js | 1 + .../let-at-binding-list-fail-2/options.json | 3 +++ .../let/let-at-binding-list-fail-3/input.js | 1 + .../let-at-binding-list-fail-3/options.json | 3 +++ .../let/let-at-binding-list-fail-4/input.js | 1 + .../let-at-binding-list-fail-4/options.json | 3 +++ 9 files changed, 41 insertions(+) create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/options.json create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/options.json create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/options.json create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/options.json diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index f47b80448b10..8949822cbf74 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -1014,6 +1014,15 @@ export default class StatementParser extends ExpressionParser { this.unexpected(null, "let is disallowed as a lexically bound name"); } decl.id = this.parseBindingAtom(); + if (kind === "const" || kind === "let") { + const invalid = this.checkVarIdHasLet(decl.id); + if (invalid) { + this.raise( + invalid.start, + "'let' is not allowed to be used as a name in 'let' or 'const' declarations.", + ); + } + } this.checkLVal( decl.id, kind === "var" ? BIND_VAR : BIND_LEXICAL, @@ -1022,6 +1031,22 @@ export default class StatementParser extends ExpressionParser { ); } + checkVarIdHasLet(id: ?N.Pattern): ?N.Identifier { + if (!id) { + return null; + } else if (id.type === "ArrayPattern") { + return id.elements.find(element => this.checkVarIdHasLet(element)); + } else if (id.type === "ObjectPattern") { + return id.properties.find(property => + this.checkVarIdHasLet(property.value), + ); + } else if (id.type === "Identifier" && id.name === "let") { + return id; + } else { + return null; + } + } + // Parse a function declaration or literal (depending on the // `isStatement` parameter). diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/input.js new file mode 100644 index 000000000000..c1eb32d32577 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/input.js @@ -0,0 +1 @@ +let { let } = {}; diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/options.json b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/options.json new file mode 100644 index 000000000000..f57eb3dfe6c2 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-1/options.json @@ -0,0 +1,3 @@ +{ + "throws": "'let' is not allowed to be used as a name in 'let' or 'const' declarations. (1:6)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/input.js new file mode 100644 index 000000000000..24c395ad2c48 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/input.js @@ -0,0 +1 @@ +const { let } = {}; diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/options.json b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/options.json new file mode 100644 index 000000000000..365d76ddf46e --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-2/options.json @@ -0,0 +1,3 @@ +{ + "throws": "'let' is not allowed to be used as a name in 'let' or 'const' declarations. (1:8)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/input.js new file mode 100644 index 000000000000..346cb602094b --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/input.js @@ -0,0 +1 @@ +let [let] = []; diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/options.json b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/options.json new file mode 100644 index 000000000000..d83275e4a85a --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-3/options.json @@ -0,0 +1,3 @@ +{ + "throws": "'let' is not allowed to be used as a name in 'let' or 'const' declarations. (1:5)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/input.js new file mode 100644 index 000000000000..8c5f4099aed6 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/input.js @@ -0,0 +1 @@ +const [let] = []; diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/options.json b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/options.json new file mode 100644 index 000000000000..456948bdd272 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-4/options.json @@ -0,0 +1,3 @@ +{ + "throws": "'let' is not allowed to be used as a name in 'let' or 'const' declarations. (1:7)" +} \ No newline at end of file From e93c823933063016c42b3f1e4cf4fac9ff8df4b9 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Sat, 15 Jun 2019 21:00:50 +0800 Subject: [PATCH 2/3] Simplify --- packages/babel-parser/src/parser/lval.js | 8 +++++++- packages/babel-parser/src/parser/statement.js | 12 ------------ .../es2015/let/let-at-binding-list-fail-5/input.js | 1 + .../let/let-at-binding-list-fail-5/options.json | 3 +++ .../es2015/let/let-at-binding-list-fail-6/input.js | 1 + .../let/let-at-binding-list-fail-6/options.json | 3 +++ 6 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/options.json create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/input.js create mode 100644 packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/options.json diff --git a/packages/babel-parser/src/parser/lval.js b/packages/babel-parser/src/parser/lval.js index c50e5cc1414b..b4281ab2ffb7 100644 --- a/packages/babel-parser/src/parser/lval.js +++ b/packages/babel-parser/src/parser/lval.js @@ -16,7 +16,7 @@ import type { import type { Pos, Position } from "../util/location"; import { isStrictBindReservedWord } from "../util/identifier"; import { NodeUtils } from "./node"; -import { type BindingTypes, BIND_NONE } from "../util/scopeflags"; +import { type BindingTypes, BIND_NONE, BIND_LEXICAL } from "../util/scopeflags"; export default class LValParser extends NodeUtils { // Forward-declaration: defined in expression.js @@ -363,6 +363,12 @@ export default class LValParser extends NodeUtils { checkClashes[key] = true; } } + if (bindingType === BIND_LEXICAL && expr.name === "let") { + this.raise( + expr.start, + "'let' is not allowed to be used as a name in 'let' or 'const' declarations.", + ); + } if (!(bindingType & BIND_NONE)) { this.scope.declareName(expr.name, bindingType, expr.start); } diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 8949822cbf74..26e2de49406c 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -1010,19 +1010,7 @@ export default class StatementParser extends ExpressionParser { } parseVarId(decl: N.VariableDeclarator, kind: "var" | "let" | "const"): void { - if ((kind === "const" || kind === "let") && this.isContextual("let")) { - this.unexpected(null, "let is disallowed as a lexically bound name"); - } decl.id = this.parseBindingAtom(); - if (kind === "const" || kind === "let") { - const invalid = this.checkVarIdHasLet(decl.id); - if (invalid) { - this.raise( - invalid.start, - "'let' is not allowed to be used as a name in 'let' or 'const' declarations.", - ); - } - } this.checkLVal( decl.id, kind === "var" ? BIND_VAR : BIND_LEXICAL, diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/input.js new file mode 100644 index 000000000000..27fcc4afa2f1 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/input.js @@ -0,0 +1 @@ +let let diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/options.json b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/options.json new file mode 100644 index 000000000000..4ca932f989ae --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-5/options.json @@ -0,0 +1,3 @@ +{ + "throws": "'let' is not allowed to be used as a name in 'let' or 'const' declarations. (1:4)" +} \ No newline at end of file diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/input.js b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/input.js new file mode 100644 index 000000000000..9514d67a4443 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/input.js @@ -0,0 +1 @@ +const let = '' diff --git a/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/options.json b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/options.json new file mode 100644 index 000000000000..f57eb3dfe6c2 --- /dev/null +++ b/packages/babel-parser/test/fixtures/es2015/let/let-at-binding-list-fail-6/options.json @@ -0,0 +1,3 @@ +{ + "throws": "'let' is not allowed to be used as a name in 'let' or 'const' declarations. (1:6)" +} \ No newline at end of file From 23ddcf007c7335b002686e4abbc3426a65b026e3 Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Sat, 15 Jun 2019 21:02:05 +0800 Subject: [PATCH 3/3] Clean up --- packages/babel-parser/src/parser/statement.js | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index 26e2de49406c..ad29af252975 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -1019,22 +1019,6 @@ export default class StatementParser extends ExpressionParser { ); } - checkVarIdHasLet(id: ?N.Pattern): ?N.Identifier { - if (!id) { - return null; - } else if (id.type === "ArrayPattern") { - return id.elements.find(element => this.checkVarIdHasLet(element)); - } else if (id.type === "ObjectPattern") { - return id.properties.find(property => - this.checkVarIdHasLet(property.value), - ); - } else if (id.type === "Identifier" && id.name === "let") { - return id; - } else { - return null; - } - } - // Parse a function declaration or literal (depending on the // `isStatement` parameter).