Make sure babel parser throws exactly same recoverable errors when estree plugin is enabled (#12375)

* refactor: introduce isPrivateName and getPrivateNameSV

* feat: check recoverable errors on estree-throw

* fix: pass through all params of parseBlockBody

* fix: set bigInt to null when invalid bigInt value is parsed

e.g. 0.1n

* fix: use string literal value in error message

When estree plugin is enabled, stringLiteral#extra.raw is not accessible. Use StringLiteral#value instead.

* refactor: introduce hasPropertyAsPrivateName

* fix: adapt to ChainExpression

* fix: port checkLVal early return for method in object pattern

* fix: throw new a?.() on estree

* fix: early return for __proto__ in accessors

* fix: test record element via isObjectProperty

* fix: pass through isLHS in toAssignable

* refactor: introduce isObjectMethod methods
This commit is contained in:
Huáng Jùnliàng
2020-12-03 03:36:54 -05:00
committed by GitHub
parent c6aea4e85d
commit 8478027d1a
8 changed files with 136 additions and 91 deletions

View File

@@ -5,18 +5,8 @@ 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";
function isSimpleProperty(node: N.Node): boolean {
return (
node != null &&
node.type === "Property" &&
node.kind === "init" &&
node.method === false
);
}
export default (superClass: Class<Parser>): Class<Parser> =>
class extends superClass {
estreeParseRegExpLiteral({ pattern, flags }: N.RegExpLiteral): N.Node {
@@ -35,8 +25,13 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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);
@@ -98,7 +93,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
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);
@@ -110,44 +105,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
.params;
}
checkLVal(
expr: N.Expression,
contextDescription: string,
...args: [
BindingTypes | void,
?Set<string>,
boolean | void,
boolean | void,
]
): void {
switch (expr.type) {
case "ObjectPattern":
expr.properties.forEach(prop => {
this.checkLVal(
prop.type === "Property" ? prop.value : prop,
"object destructuring pattern",
...args,
);
});
break;
default:
super.checkLVal(expr, contextDescription, ...args);
}
}
checkProto(
prop: N.ObjectMember | N.SpreadElement,
isRecord: boolean,
protoRef: { used: boolean },
refExpressionErrors: ?ExpressionErrors,
): void {
// $FlowIgnore: check prop.method and fallback to super method
if (prop.method) {
return;
}
super.checkProto(prop, isRecord, protoRef, refExpressionErrors);
}
isValidDirective(stmt: N.Statement): boolean {
return (
stmt.type === "ExpressionStatement" &&
@@ -170,11 +127,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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),
@@ -337,8 +292,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
}
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;
}
@@ -348,9 +303,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
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);
}
@@ -450,4 +405,23 @@ export default (superClass: Class<Parser>): Class<Parser> =>
return node;
}
hasPropertyAsPrivateName(node: N.Node): boolean {
if (node.type === "ChainExpression") {
node = node.expression;
}
return super.hasPropertyAsPrivateName(node);
}
isOptionalChain(node: N.Node): boolean {
return node.type === "ChainExpression";
}
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";
}
};