Simplifiy tracking of valid JSX positions (#13891)
Remove `state.inPropertyName` and simplifies `state.canStartJSXElement` tracking
This commit is contained in:
parent
de28707dfe
commit
7250d2562b
@ -22,12 +22,12 @@ import {
|
||||
tokenCanStartExpression,
|
||||
tokenIsAssignment,
|
||||
tokenIsIdentifier,
|
||||
tokenIsKeyword,
|
||||
tokenIsKeywordOrIdentifier,
|
||||
tokenIsOperator,
|
||||
tokenIsPostfix,
|
||||
tokenIsPrefix,
|
||||
tokenIsRightAssociative,
|
||||
tokenKeywordOrIdentifierIsKeyword,
|
||||
tokenLabelName,
|
||||
tokenOperatorPrecedence,
|
||||
tt,
|
||||
@ -2237,8 +2237,6 @@ export default class ExpressionParser extends LValParser {
|
||||
prop.key = this.parseMaybeAssignAllowIn();
|
||||
this.expect(tt.bracketR);
|
||||
} else {
|
||||
const oldInPropertyName = this.state.inPropertyName;
|
||||
this.state.inPropertyName = true;
|
||||
// We check if it's valid for it to be a private name when we push it.
|
||||
const type = this.state.type;
|
||||
(prop: $FlowFixMe).key =
|
||||
@ -2253,8 +2251,6 @@ export default class ExpressionParser extends LValParser {
|
||||
// ClassPrivateProperty is never computed, so we don't assign in that case.
|
||||
prop.computed = false;
|
||||
}
|
||||
|
||||
this.state.inPropertyName = oldInPropertyName;
|
||||
}
|
||||
|
||||
return prop.key;
|
||||
@ -2584,12 +2580,16 @@ export default class ExpressionParser extends LValParser {
|
||||
throw this.unexpected();
|
||||
}
|
||||
|
||||
const tokenIsKeyword = tokenKeywordOrIdentifierIsKeyword(type);
|
||||
|
||||
if (liberal) {
|
||||
// If the current token is not used as a keyword, set its type to "tt.name".
|
||||
// This will prevent this.next() from throwing about unexpected escapes.
|
||||
this.state.type = tt.name;
|
||||
if (tokenIsKeyword) {
|
||||
this.replaceToken(tt.name);
|
||||
}
|
||||
} else {
|
||||
this.checkReservedWord(name, start, tokenIsKeyword(type), false);
|
||||
this.checkReservedWord(name, start, tokenIsKeyword, false);
|
||||
}
|
||||
|
||||
this.next();
|
||||
|
||||
@ -21,10 +21,6 @@ import { isIdentifierChar, isIdentifierStart } from "../../util/identifier";
|
||||
import type { Position } from "../../util/location";
|
||||
import { isNewLine } from "../../util/whitespace";
|
||||
import { Errors, makeErrorTemplates, ErrorCodes } from "../../parser/error";
|
||||
import type { LookaheadState } from "../../tokenizer/state";
|
||||
import State from "../../tokenizer/state";
|
||||
|
||||
type JSXLookaheadState = LookaheadState & { inPropertyName: boolean };
|
||||
|
||||
const HEX_NUMBER = /^[\da-fA-F]+$/;
|
||||
const DECIMAL_NUMBER = /^\d+$/;
|
||||
@ -106,7 +102,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
case charCodes.lessThan:
|
||||
case charCodes.leftCurlyBrace:
|
||||
if (this.state.pos === this.state.start) {
|
||||
if (ch === charCodes.lessThan && this.state.exprAllowed) {
|
||||
if (ch === charCodes.lessThan && this.state.canStartJSXElement) {
|
||||
++this.state.pos;
|
||||
return this.finishToken(tt.jsxTagStart);
|
||||
}
|
||||
@ -556,24 +552,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
) {
|
||||
// In case we encounter an lt token here it will always be the start of
|
||||
// jsx as the lt sign is not allowed in places that expect an expression
|
||||
this.finishToken(tt.jsxTagStart);
|
||||
this.replaceToken(tt.jsxTagStart);
|
||||
return this.jsxParseElement();
|
||||
} else {
|
||||
return super.parseExprAtom(refExpressionErrors);
|
||||
}
|
||||
}
|
||||
|
||||
createLookaheadState(state: State): JSXLookaheadState {
|
||||
const lookaheadState = ((super.createLookaheadState(
|
||||
state,
|
||||
): any): JSXLookaheadState);
|
||||
lookaheadState.inPropertyName = state.inPropertyName;
|
||||
return lookaheadState;
|
||||
}
|
||||
|
||||
getTokenFromCode(code: number): void {
|
||||
if (this.state.inPropertyName) return super.getTokenFromCode(code);
|
||||
|
||||
const context = this.curContext();
|
||||
|
||||
if (context === tc.j_expr) {
|
||||
@ -600,7 +586,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
|
||||
if (
|
||||
code === charCodes.lessThan &&
|
||||
this.state.exprAllowed &&
|
||||
this.state.canStartJSXElement &&
|
||||
this.input.charCodeAt(this.state.pos + 1) !== charCodes.exclamationMark
|
||||
) {
|
||||
++this.state.pos;
|
||||
@ -617,7 +603,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
// do not consider JSX expr -> JSX open tag -> ... anymore
|
||||
// reconsider as closing tag context
|
||||
context.splice(-2, 2, tc.j_cTag);
|
||||
this.state.exprAllowed = false;
|
||||
this.state.canStartJSXElement = false;
|
||||
} else if (type === tt.jsxTagStart) {
|
||||
context.push(
|
||||
tc.j_expr, // treat as beginning of JSX expression
|
||||
@ -627,17 +613,13 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
const out = context.pop();
|
||||
if ((out === tc.j_oTag && prevType === tt.slash) || out === tc.j_cTag) {
|
||||
context.pop();
|
||||
this.state.exprAllowed = context[context.length - 1] === tc.j_expr;
|
||||
this.state.canStartJSXElement =
|
||||
context[context.length - 1] === tc.j_expr;
|
||||
} else {
|
||||
this.state.exprAllowed = true;
|
||||
this.state.canStartJSXElement = true;
|
||||
}
|
||||
} else if (
|
||||
tokenIsKeyword(type) &&
|
||||
(prevType === tt.dot || prevType === tt.questionDot)
|
||||
) {
|
||||
this.state.exprAllowed = false;
|
||||
} else {
|
||||
this.state.exprAllowed = tokenComesBeforeExpression(type);
|
||||
this.state.canStartJSXElement = tokenComesBeforeExpression(type);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -2125,7 +2125,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
||||
// When ! is consumed as a postfix operator (non-null assertion),
|
||||
// disallow JSX tag forming after. e.g. When parsing `p! < n.p!`
|
||||
// `<n.p` can not be a start of JSX tag
|
||||
this.state.exprAllowed = false;
|
||||
this.state.canStartJSXElement = false;
|
||||
this.next();
|
||||
|
||||
const nonNullExpression: N.TsNonNullExpression = this.startNodeAt(
|
||||
|
||||
@ -482,7 +482,7 @@ export default class Tokenizer extends ParserErrors {
|
||||
}
|
||||
|
||||
// Called at the end of every token. Sets `end`, `val`, and
|
||||
// maintains `context` and `exprAllowed`, and skips the space after
|
||||
// maintains `context` and `canStartJSXElement`, and skips the space after
|
||||
// the token, so that the next one's `start` will point at the
|
||||
// right position.
|
||||
|
||||
@ -498,6 +498,14 @@ export default class Tokenizer extends ParserErrors {
|
||||
}
|
||||
}
|
||||
|
||||
replaceToken(type: TokenType): void {
|
||||
this.state.type = type;
|
||||
// the prevType of updateContext is required
|
||||
// only when the new type is tt.slash/tt.jsxTagEnd
|
||||
// $FlowIgnore
|
||||
this.updateContext();
|
||||
}
|
||||
|
||||
// ### Token reading
|
||||
|
||||
// This is the function that is called to fetch the next token. It
|
||||
|
||||
@ -68,7 +68,6 @@ export default class State {
|
||||
maybeInArrowParameters: boolean = false;
|
||||
inType: boolean = false;
|
||||
noAnonFunctionType: boolean = false;
|
||||
inPropertyName: boolean = false;
|
||||
hasFlowComment: boolean = false;
|
||||
isAmbientContext: boolean = false;
|
||||
inAbstractClass: boolean = false;
|
||||
@ -127,7 +126,7 @@ export default class State {
|
||||
// or ends a string template
|
||||
context: Array<TokContext> = [ct.brace];
|
||||
// Used to track whether a JSX element is allowed to form
|
||||
exprAllowed: boolean = true;
|
||||
canStartJSXElement: boolean = true;
|
||||
|
||||
// Used to signal to callers of `readWord1` whether the word
|
||||
// contained any escape sequences. This is needed because words with
|
||||
|
||||
@ -332,6 +332,12 @@ export function tokenIsIdentifier(token: TokenType): boolean {
|
||||
return token >= tt._as && token <= tt.name;
|
||||
}
|
||||
|
||||
export function tokenKeywordOrIdentifierIsKeyword(token: TokenType): boolean {
|
||||
// we can remove the token >= tt._in check when we
|
||||
// know a token is either keyword or identifier
|
||||
return token <= tt._while;
|
||||
}
|
||||
|
||||
export function tokenIsKeywordOrIdentifier(token: TokenType): boolean {
|
||||
return token >= tt._in && token <= tt.name;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user