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:
@@ -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";
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user