From de0fe043f0eeb70b852a8a469b2c460010bf2bf4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 27 Jul 2021 21:05:07 -0400 Subject: [PATCH 1/4] update benchmark babel parser version --- benchmark/package.json | 2 +- yarn.lock | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/benchmark/package.json b/benchmark/package.json index d746d27fc59f..e2ce02ee6577 100644 --- a/benchmark/package.json +++ b/benchmark/package.json @@ -5,7 +5,7 @@ "devDependencies": { "@babel-baseline/generator": "npm:@babel/generator@7.14.5", "@babel-baseline/helper-validator-identifier": "npm:@babel/helper-validator-identifier@7.10.4", - "@babel-baseline/parser": "npm:@babel/parser@7.14.5", + "@babel-baseline/parser": "npm:@babel/parser@7.14.8", "@babel/generator": "workspace:*", "@babel/helper-validator-identifier": "workspace:*", "@babel/parser": "workspace:*", diff --git a/yarn.lock b/yarn.lock index 2c6c9423aadf..856e895dcb38 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,12 +23,12 @@ __metadata: languageName: node linkType: hard -"@babel-baseline/parser@npm:@babel/parser@7.14.5": - version: 7.14.5 - resolution: "@babel/parser@npm:7.14.5" +"@babel-baseline/parser@npm:@babel/parser@7.14.8": + version: 7.14.8 + resolution: "@babel/parser@npm:7.14.8" bin: parser: ./bin/babel-parser.js - checksum: 55c14793888cb7d54275811e7f13136875df1ee4fc368f3f10cff46ebdf95b6a072e706a0486be0ac5686a597cbfb82f33b5f66aa6ba80ff50b73bca945035c6 + checksum: 1f900e92675bac6120dfb3e9ea86841fdaba11d338a220017dbcb9e95815a3854ea479da8027e80acaa7f0e618b96e59bbbf3a230a05aaa3407c9419eb742cfe languageName: node linkType: hard @@ -87,7 +87,7 @@ __metadata: dependencies: "@babel-baseline/generator": "npm:@babel/generator@7.14.5" "@babel-baseline/helper-validator-identifier": "npm:@babel/helper-validator-identifier@7.10.4" - "@babel-baseline/parser": "npm:@babel/parser@7.14.5" + "@babel-baseline/parser": "npm:@babel/parser@7.14.8" "@babel/generator": "workspace:*" "@babel/helper-validator-identifier": "workspace:*" "@babel/parser": "workspace:*" From 2d44607723ebdbcff36894254e839ec2ffd979c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Tue, 27 Jul 2021 21:05:56 -0400 Subject: [PATCH 2/4] perf: replace generic __clone by specific methods MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit baseline 256 length-1 named export: 4_704 ops/sec ±1.59% (0.213ms) baseline 512 length-1 named export: 2_426 ops/sec ±0.52% (0.412ms) baseline 1024 length-1 named export: 1_118 ops/sec ±1.23% (0.895ms) baseline 2048 length-1 named export: 556 ops/sec ±0.77% (1.799ms) current 256 length-1 named export: 7_073 ops/sec ±33.67% (0.141ms) current 512 length-1 named export: 4_441 ops/sec ±0.79% (0.225ms) current 1024 length-1 named export: 2_142 ops/sec ±1.09% (0.467ms) current 2048 length-1 named export: 943 ops/sec ±2.12% (1.06ms) --- .../babel-parser/src/parser/expression.js | 7 ++-- packages/babel-parser/src/parser/node.js | 41 +++++++++++++++++++ packages/babel-parser/src/parser/statement.js | 17 +++++--- .../babel-parser/src/plugins/flow/index.js | 7 ++-- packages/babel-parser/src/types.js | 1 + 5 files changed, 62 insertions(+), 11 deletions(-) diff --git a/packages/babel-parser/src/parser/expression.js b/packages/babel-parser/src/parser/expression.js index 08a9d0c15b56..369b09202fea 100644 --- a/packages/babel-parser/src/parser/expression.js +++ b/packages/babel-parser/src/parser/expression.js @@ -57,6 +57,7 @@ import { import { Errors, SourceTypeModuleErrors } from "./error"; import type { ParsingError } from "./error"; import { setInnerComments } from "./comments"; +import { cloneIdentifier } from "./node"; /*:: import type { SourceType } from "../options"; @@ -1938,7 +1939,7 @@ export default class ExpressionParser extends LValParser { prop.value = this.parseMaybeDefault( startPos, startLoc, - prop.key.__clone(), + cloneIdentifier(prop.key), ); } else if (this.match(tt.eq) && refExpressionErrors) { if (refExpressionErrors.shorthandAssign === -1) { @@ -1947,10 +1948,10 @@ export default class ExpressionParser extends LValParser { prop.value = this.parseMaybeDefault( startPos, startLoc, - prop.key.__clone(), + cloneIdentifier(prop.key), ); } else { - prop.value = prop.key.__clone(); + prop.value = cloneIdentifier(prop.key); } prop.shorthand = true; diff --git a/packages/babel-parser/src/parser/node.js b/packages/babel-parser/src/parser/node.js index 6f77812b3e99..495996fa5824 100644 --- a/packages/babel-parser/src/parser/node.js +++ b/packages/babel-parser/src/parser/node.js @@ -27,6 +27,7 @@ class Node implements NodeBase { innerComments: Array; extra: { [key: string]: any }; + // todo(Babel 8): remove this method in Babel 8 __clone(): this { // $FlowIgnore const newNode: any = new Node(); @@ -47,6 +48,46 @@ class Node implements NodeBase { return newNode; } } +const NodePrototype = Node.prototype; + +function clonePlaceholder(node: any): any { + return cloneIdentifier(node); +} + +export function cloneIdentifier(node: any): any { + // We don't need to clone `typeAnnotations` and `optional`: because + // cloneIdentifier is only used in object shorthand and named import/export. + // Neither of them allow type annotations after the identifier or optional identifier + const { type, start, end, loc, range, extra, name } = node; + const cloned = Object.create(NodePrototype); + cloned.type = type; + cloned.start = start; + cloned.end = end; + cloned.loc = loc; + cloned.range = range; + cloned.extra = extra; + cloned.name = name; + if (type === "Placeholder") { + cloned.expectedNode = node.expectedNode; + } + return cloned; +} + +export function cloneStringLiteral(node: any): any { + const { type, start, end, loc, range, extra } = node; + if (type === "Placeholder") { + return clonePlaceholder(node); + } + const cloned = Object.create(NodePrototype); + cloned.type = "StringLiteral"; + cloned.start = start; + cloned.end = end; + cloned.loc = loc; + cloned.range = range; + cloned.extra = extra; + cloned.value = node.value; + return cloned; +} export class NodeUtils extends UtilParser { startNode(): T { diff --git a/packages/babel-parser/src/parser/statement.js b/packages/babel-parser/src/parser/statement.js index fb51dd01587c..8634676ca4e4 100644 --- a/packages/babel-parser/src/parser/statement.js +++ b/packages/babel-parser/src/parser/statement.js @@ -34,6 +34,7 @@ import { import type { SourceType } from "../options"; import { Token } from "../tokenizer"; import { Position } from "../util/location"; +import { cloneStringLiteral, cloneIdentifier } from "./node"; const loopLabel = { kind: "loop" }, switchLabel = { kind: "switch" }; @@ -2144,10 +2145,16 @@ export default class StatementParser extends ExpressionParser { } const node = this.startNode(); - node.local = this.parseModuleExportName(); - node.exported = this.eatContextual("as") - ? this.parseModuleExportName() - : node.local.__clone(); + const isString = this.match(tt.string); + const local = this.parseModuleExportName(); + node.local = local; + if (this.eatContextual("as")) { + node.exported = this.parseModuleExportName(); + } else if (isString) { + node.exported = cloneStringLiteral(local); + } else { + node.exported = cloneIdentifier(local); + } nodes.push(this.finishNode(node, "ExportSpecifier")); } @@ -2423,7 +2430,7 @@ export default class StatementParser extends ExpressionParser { ); } this.checkReservedWord(imported.name, specifier.start, true, true); - specifier.local = imported.__clone(); + specifier.local = cloneIdentifier(imported); } this.checkLVal(specifier.local, "import specifier", BIND_LEXICAL); node.specifiers.push(this.finishNode(specifier, "ImportSpecifier")); diff --git a/packages/babel-parser/src/plugins/flow/index.js b/packages/babel-parser/src/plugins/flow/index.js index dbb95972673a..a57a75acaee2 100644 --- a/packages/babel-parser/src/plugins/flow/index.js +++ b/packages/babel-parser/src/plugins/flow/index.js @@ -25,6 +25,7 @@ import { } from "../../util/scopeflags"; import type { ExpressionErrors } from "../../parser/util"; import { Errors, makeErrorTemplates, ErrorCodes } from "../../parser/error"; +import { cloneIdentifier } from "../../parser/node"; const reservedTypes = new Set([ "_", @@ -2655,7 +2656,7 @@ export default (superClass: Class): Class => // `import {type as ,` or `import {type as }` specifier.imported = as_ident; specifier.importKind = specifierTypeKind; - specifier.local = as_ident.__clone(); + specifier.local = cloneIdentifier(as_ident); } else { // `import {type as foo` specifier.imported = firstIdent; @@ -2673,7 +2674,7 @@ export default (superClass: Class): Class => specifier.local = this.parseIdentifier(); } else { isBinding = true; - specifier.local = specifier.imported.__clone(); + specifier.local = cloneIdentifier(specifier.imported); } } else { if (firstIdentIsString) { @@ -2688,7 +2689,7 @@ export default (superClass: Class): Class => isBinding = true; specifier.imported = firstIdent; specifier.importKind = null; - specifier.local = specifier.imported.__clone(); + specifier.local = cloneIdentifier(specifier.imported); } const nodeIsTypeImport = hasTypeImportKind(node); diff --git a/packages/babel-parser/src/types.js b/packages/babel-parser/src/types.js index 825d6d29139a..cef0987a6864 100644 --- a/packages/babel-parser/src/types.js +++ b/packages/babel-parser/src/types.js @@ -98,6 +98,7 @@ export type Identifier = PatternBase & { type: "Identifier", name: string, + // @deprecated __clone(): Identifier, // TypeScript only. Used in case of an optional parameter. From fc9a8af3a677e6039727740377ba812f472967e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 28 Jul 2021 16:07:02 -0400 Subject: [PATCH 3/4] breaking: remove Node#__clone in Babel 8 --- packages/babel-parser/src/parser/node.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/babel-parser/src/parser/node.js b/packages/babel-parser/src/parser/node.js index 495996fa5824..df41ff3fec7d 100644 --- a/packages/babel-parser/src/parser/node.js +++ b/packages/babel-parser/src/parser/node.js @@ -26,9 +26,12 @@ class Node implements NodeBase { trailingComments: Array; innerComments: Array; extra: { [key: string]: any }; +} +const NodePrototype = Node.prototype; - // todo(Babel 8): remove this method in Babel 8 - __clone(): this { +if (!process.env.BABEL_8_BREAKING) { + // $FlowIgnore + NodePrototype.__clone = function (): Node { // $FlowIgnore const newNode: any = new Node(); const keys = Object.keys(this); @@ -40,15 +43,13 @@ class Node implements NodeBase { key !== "trailingComments" && key !== "innerComments" ) { - // $FlowIgnore newNode[key] = this[key]; } } return newNode; - } + }; } -const NodePrototype = Node.prototype; function clonePlaceholder(node: any): any { return cloneIdentifier(node); From 4bbf05d70cc7959ce61f6546371a1203b309a643 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hu=C3=A1ng=20J=C3=B9nli=C3=A0ng?= Date: Wed, 28 Jul 2021 16:18:18 -0400 Subject: [PATCH 4/4] test: use t.cloneNode --- packages/babel-traverse/test/replacement.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/babel-traverse/test/replacement.js b/packages/babel-traverse/test/replacement.js index e04d831e99f3..47dbec3433a0 100644 --- a/packages/babel-traverse/test/replacement.js +++ b/packages/babel-traverse/test/replacement.js @@ -122,7 +122,7 @@ describe("path/replacement", function () { OptionalMemberExpression(path) { path.node.type = "MemberExpression"; // force `replaceWith` to replace `path.node` - path.replaceWith(path.node.__clone()); + path.replaceWith(t.cloneNode(path.node)); path.parentPath.ensureBlock(); const aQuestionDotBNode = path.node.object.expression;