Disallow escape sequences in contextual keywords (#9618)

* Disallow escape sequences in async

* Disallow escape sequences in get, set and async in class

* invalid escape tests

* Update whitelist

* tests for async in parens

* Add test for invalid newline between params and arrow

* Move canInsertSemilcolon() into shouldPArseAsyncArrow
This commit is contained in:
Daniel Tschinder
2019-03-05 17:20:36 -08:00
committed by GitHub
parent 349c0d4836
commit 29999007f6
58 changed files with 530 additions and 22 deletions

View File

@@ -524,12 +524,21 @@ export default class ExpressionParser extends LValParser {
startLoc: Position,
noCalls?: ?boolean,
): N.Expression {
const maybeAsyncArrow = this.atPossibleAsync(base);
const state = {
optionalChainMember: false,
stop: false,
};
do {
base = this.parseSubscript(base, startPos, startLoc, noCalls, state);
base = this.parseSubscript(
base,
startPos,
startLoc,
noCalls,
state,
maybeAsyncArrow,
);
} while (!state.stop);
return base;
}
@@ -544,6 +553,7 @@ export default class ExpressionParser extends LValParser {
startLoc: Position,
noCalls: ?boolean,
state: N.ParseSubscriptState,
maybeAsyncArrow: boolean,
): N.Expression {
if (!noCalls && this.eat(tt.doubleColon)) {
const node = this.startNodeAt(startPos, startLoc);
@@ -575,13 +585,8 @@ export default class ExpressionParser extends LValParser {
this.expect(tt.bracketR);
return this.finishNode(node, "OptionalMemberExpression");
} else if (this.eat(tt.parenL)) {
const possibleAsync = this.atPossibleAsync(base);
node.callee = base;
node.arguments = this.parseCallExpressionArguments(
tt.parenR,
possibleAsync,
);
node.arguments = this.parseCallExpressionArguments(tt.parenR, false);
node.optional = true;
return this.finishNode(node, "OptionalCallExpression");
} else {
@@ -620,7 +625,6 @@ export default class ExpressionParser extends LValParser {
this.state.yieldPos = 0;
this.state.awaitPos = 0;
const possibleAsync = this.atPossibleAsync(base);
this.next();
let node = this.startNodeAt(startPos, startLoc);
@@ -631,7 +635,7 @@ export default class ExpressionParser extends LValParser {
node.arguments = this.parseCallExpressionArguments(
tt.parenR,
possibleAsync,
maybeAsyncArrow,
base.type === "Import",
base.type !== "Super",
);
@@ -641,7 +645,7 @@ export default class ExpressionParser extends LValParser {
this.finishOptionalCallExpression(node);
}
if (possibleAsync && this.shouldParseAsyncArrow()) {
if (maybeAsyncArrow && this.shouldParseAsyncArrow()) {
state.stop = true;
this.checkCommaAfterRestFromSpread();
@@ -704,11 +708,11 @@ export default class ExpressionParser extends LValParser {
atPossibleAsync(base: N.Expression): boolean {
return (
!this.state.containsEsc &&
this.state.potentialArrowAt === base.start &&
base.type === "Identifier" &&
base.name === "async" &&
!this.canInsertSemicolon()
this.state.lastTokEnd === base.end &&
!this.canInsertSemicolon() &&
this.state.input.slice(base.start, base.end) === "async"
);
}
@@ -791,7 +795,7 @@ export default class ExpressionParser extends LValParser {
}
shouldParseAsyncArrow(): boolean {
return this.match(tt.arrow);
return this.match(tt.arrow) && !this.canInsertSemicolon();
}
parseAsyncArrowFromCallExpression(
@@ -891,6 +895,7 @@ export default class ExpressionParser extends LValParser {
return this.parseFunction(node, undefined, true);
} else if (
canBeArrow &&
!containsEsc &&
id.name === "async" &&
this.match(tt.name) &&
!this.canInsertSemicolon()

View File

@@ -1321,6 +1321,7 @@ export default class StatementParser extends ExpressionParser {
return;
}
const containsEsc = this.state.containsEsc;
const key = this.parseClassPropertyName(member);
const isPrivate = key.type === "PrivateName";
// Check the key is not a computed expression or string literal.
@@ -1371,7 +1372,12 @@ export default class StatementParser extends ExpressionParser {
} else {
this.pushClassProperty(classBody, publicProp);
}
} else if (isSimple && key.name === "async" && !this.isLineTerminator()) {
} else if (
isSimple &&
key.name === "async" &&
!containsEsc &&
!this.isLineTerminator()
) {
// an async method
const isGenerator = this.eat(tt.star);
@@ -1407,6 +1413,7 @@ export default class StatementParser extends ExpressionParser {
} else if (
isSimple &&
(key.name === "get" || key.name === "set") &&
!containsEsc &&
!(this.match(tt.star) && this.isLineTerminator())
) {
// `get\n*` is an uninitialized property named 'get' followed by a generator.

View File

@@ -2619,6 +2619,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
startLoc: Position,
noCalls: ?boolean,
subscriptState: N.ParseSubscriptState,
maybeAsyncArrow: boolean,
): N.Expression {
if (this.match(tt.questionDot) && this.isLookaheadRelational("<")) {
this.expectPlugin("optionalChaining");
@@ -2671,6 +2672,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
startLoc,
noCalls,
subscriptState,
maybeAsyncArrow,
);
}

View File

@@ -1498,6 +1498,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
startLoc: Position,
noCalls: ?boolean,
state: N.ParseSubscriptState,
maybeAsyncArrow: boolean,
): N.Expression {
if (!this.hasPrecedingLineBreak() && this.match(tt.bang)) {
this.state.exprAllowed = false;
@@ -1560,7 +1561,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
if (result) return result;
}
return super.parseSubscript(base, startPos, startLoc, noCalls, state);
return super.parseSubscript(
base,
startPos,
startLoc,
noCalls,
state,
maybeAsyncArrow,
);
}
parseNewArguments(node: N.NewExpression): void {