Tokenize keywords-like identifier as new tokens (#13769)
* refactor: add more identifier token helpers * refactor: explode tt.name into multiple tokens * fix: disallow escape in interface keyword * refactor: simplify isMaybeDefaultImport * review comments * refactor: avoid string comparison
This commit is contained in:
parent
613ae6fac7
commit
178d43ff17
@ -21,7 +21,9 @@
|
|||||||
import {
|
import {
|
||||||
tokenCanStartExpression,
|
tokenCanStartExpression,
|
||||||
tokenIsAssignment,
|
tokenIsAssignment,
|
||||||
|
tokenIsIdentifier,
|
||||||
tokenIsKeyword,
|
tokenIsKeyword,
|
||||||
|
tokenIsKeywordOrIdentifier,
|
||||||
tokenIsOperator,
|
tokenIsOperator,
|
||||||
tokenIsPostfix,
|
tokenIsPostfix,
|
||||||
tokenIsPrefix,
|
tokenIsPrefix,
|
||||||
@ -273,7 +275,7 @@ export default class ExpressionParser extends LValParser {
|
|||||||
): N.Expression {
|
): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
if (this.isContextual("yield")) {
|
if (this.isContextual(tt._yield)) {
|
||||||
if (this.prodParam.hasYield) {
|
if (this.prodParam.hasYield) {
|
||||||
let left = this.parseYield();
|
let left = this.parseYield();
|
||||||
if (afterLeftParse) {
|
if (afterLeftParse) {
|
||||||
@ -290,8 +292,9 @@ export default class ExpressionParser extends LValParser {
|
|||||||
refExpressionErrors = new ExpressionErrors();
|
refExpressionErrors = new ExpressionErrors();
|
||||||
ownExpressionErrors = true;
|
ownExpressionErrors = true;
|
||||||
}
|
}
|
||||||
|
const { type } = this.state;
|
||||||
|
|
||||||
if (this.match(tt.parenL) || this.match(tt.name)) {
|
if (type === tt.parenL || tokenIsIdentifier(type)) {
|
||||||
this.state.potentialArrowAt = this.state.start;
|
this.state.potentialArrowAt = this.state.start;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -446,11 +449,7 @@ export default class ExpressionParser extends LValParser {
|
|||||||
op === tt.pipeline &&
|
op === tt.pipeline &&
|
||||||
this.getPluginOption("pipelineOperator", "proposal") === "minimal"
|
this.getPluginOption("pipelineOperator", "proposal") === "minimal"
|
||||||
) {
|
) {
|
||||||
if (
|
if (this.state.type === tt._await && this.prodParam.hasAwait) {
|
||||||
this.match(tt.name) &&
|
|
||||||
this.state.value === "await" &&
|
|
||||||
this.prodParam.hasAwait
|
|
||||||
) {
|
|
||||||
throw this.raise(
|
throw this.raise(
|
||||||
this.state.start,
|
this.state.start,
|
||||||
Errors.UnexpectedAwaitAfterPipelineBody,
|
Errors.UnexpectedAwaitAfterPipelineBody,
|
||||||
@ -498,7 +497,7 @@ export default class ExpressionParser extends LValParser {
|
|||||||
|
|
||||||
case "smart":
|
case "smart":
|
||||||
return this.withTopicBindingContext(() => {
|
return this.withTopicBindingContext(() => {
|
||||||
if (this.prodParam.hasYield && this.isContextual("yield")) {
|
if (this.prodParam.hasYield && this.isContextual(tt._yield)) {
|
||||||
throw this.raise(
|
throw this.raise(
|
||||||
this.state.start,
|
this.state.start,
|
||||||
Errors.PipeBodyIsTighter,
|
Errors.PipeBodyIsTighter,
|
||||||
@ -577,7 +576,7 @@ export default class ExpressionParser extends LValParser {
|
|||||||
): N.Expression {
|
): N.Expression {
|
||||||
const startPos = this.state.start;
|
const startPos = this.state.start;
|
||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
const isAwait = this.isContextual("await");
|
const isAwait = this.isContextual(tt._await);
|
||||||
|
|
||||||
if (isAwait && this.isAwaitAllowed()) {
|
if (isAwait && this.isAwaitAllowed()) {
|
||||||
this.next();
|
this.next();
|
||||||
@ -1053,7 +1052,8 @@ export default class ExpressionParser extends LValParser {
|
|||||||
parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression {
|
parseExprAtom(refExpressionErrors?: ?ExpressionErrors): N.Expression {
|
||||||
let node;
|
let node;
|
||||||
|
|
||||||
switch (this.state.type) {
|
const { type } = this.state;
|
||||||
|
switch (type) {
|
||||||
case tt._super:
|
case tt._super:
|
||||||
return this.parseSuper();
|
return this.parseSuper();
|
||||||
|
|
||||||
@ -1074,61 +1074,6 @@ export default class ExpressionParser extends LValParser {
|
|||||||
this.next();
|
this.next();
|
||||||
return this.finishNode(node, "ThisExpression");
|
return this.finishNode(node, "ThisExpression");
|
||||||
|
|
||||||
case tt.name: {
|
|
||||||
if (
|
|
||||||
this.isContextual("module") &&
|
|
||||||
this.lookaheadCharCode() === charCodes.leftCurlyBrace &&
|
|
||||||
!this.hasFollowingLineBreak()
|
|
||||||
) {
|
|
||||||
return this.parseModuleExpression();
|
|
||||||
}
|
|
||||||
const canBeArrow = this.state.potentialArrowAt === this.state.start;
|
|
||||||
const containsEsc = this.state.containsEsc;
|
|
||||||
const id = this.parseIdentifier();
|
|
||||||
|
|
||||||
if (!containsEsc && id.name === "async" && !this.canInsertSemicolon()) {
|
|
||||||
if (this.match(tt._function)) {
|
|
||||||
this.resetPreviousNodeTrailingComments(id);
|
|
||||||
this.next();
|
|
||||||
return this.parseFunction(
|
|
||||||
this.startNodeAtNode(id),
|
|
||||||
undefined,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
} else if (this.match(tt.name)) {
|
|
||||||
// If the next token begins with "=", commit to parsing an async
|
|
||||||
// arrow function. (Peeking ahead for "=" lets us avoid a more
|
|
||||||
// expensive full-token lookahead on this common path.)
|
|
||||||
if (this.lookaheadCharCode() === charCodes.equalsTo) {
|
|
||||||
// although `id` is not used in async arrow unary function,
|
|
||||||
// we don't need to reset `async`'s trailing comments because
|
|
||||||
// it will be attached to the upcoming async arrow binding identifier
|
|
||||||
return this.parseAsyncArrowUnaryFunction(
|
|
||||||
this.startNodeAtNode(id),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Otherwise, treat "async" as an identifier and let calling code
|
|
||||||
// deal with the current tt.name token.
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
} else if (this.match(tt._do)) {
|
|
||||||
this.resetPreviousNodeTrailingComments(id);
|
|
||||||
return this.parseDo(this.startNodeAtNode(id), true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (canBeArrow && this.match(tt.arrow) && !this.canInsertSemicolon()) {
|
|
||||||
this.next();
|
|
||||||
return this.parseArrowExpression(
|
|
||||||
this.startNodeAtNode(id),
|
|
||||||
[id],
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
case tt._do: {
|
case tt._do: {
|
||||||
return this.parseDo(this.startNode(), false);
|
return this.parseDo(this.startNode(), false);
|
||||||
}
|
}
|
||||||
@ -1308,9 +1253,73 @@ export default class ExpressionParser extends LValParser {
|
|||||||
|
|
||||||
// fall through
|
// fall through
|
||||||
default:
|
default:
|
||||||
|
if (tokenIsIdentifier(type)) {
|
||||||
|
if (
|
||||||
|
this.isContextual(tt._module) &&
|
||||||
|
this.lookaheadCharCode() === charCodes.leftCurlyBrace &&
|
||||||
|
!this.hasFollowingLineBreak()
|
||||||
|
) {
|
||||||
|
return this.parseModuleExpression();
|
||||||
|
}
|
||||||
|
const canBeArrow = this.state.potentialArrowAt === this.state.start;
|
||||||
|
const containsEsc = this.state.containsEsc;
|
||||||
|
const id = this.parseIdentifier();
|
||||||
|
|
||||||
|
if (
|
||||||
|
!containsEsc &&
|
||||||
|
id.name === "async" &&
|
||||||
|
!this.canInsertSemicolon()
|
||||||
|
) {
|
||||||
|
const { type } = this.state;
|
||||||
|
if (type === tt._function) {
|
||||||
|
this.resetPreviousNodeTrailingComments(id);
|
||||||
|
this.next();
|
||||||
|
return this.parseFunction(
|
||||||
|
this.startNodeAtNode(id),
|
||||||
|
undefined,
|
||||||
|
true,
|
||||||
|
);
|
||||||
|
} else if (tokenIsIdentifier(type)) {
|
||||||
|
// If the next token begins with "=", commit to parsing an async
|
||||||
|
// arrow function. (Peeking ahead for "=" lets us avoid a more
|
||||||
|
// expensive full-token lookahead on this common path.)
|
||||||
|
if (this.lookaheadCharCode() === charCodes.equalsTo) {
|
||||||
|
// although `id` is not used in async arrow unary function,
|
||||||
|
// we don't need to reset `async`'s trailing comments because
|
||||||
|
// it will be attached to the upcoming async arrow binding identifier
|
||||||
|
return this.parseAsyncArrowUnaryFunction(
|
||||||
|
this.startNodeAtNode(id),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// Otherwise, treat "async" as an identifier and let calling code
|
||||||
|
// deal with the current tt.name token.
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
} else if (type === tt._do) {
|
||||||
|
this.resetPreviousNodeTrailingComments(id);
|
||||||
|
return this.parseDo(this.startNodeAtNode(id), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
canBeArrow &&
|
||||||
|
this.match(tt.arrow) &&
|
||||||
|
!this.canInsertSemicolon()
|
||||||
|
) {
|
||||||
|
this.next();
|
||||||
|
return this.parseArrowExpression(
|
||||||
|
this.startNodeAtNode(id),
|
||||||
|
[id],
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return id;
|
||||||
|
} else {
|
||||||
throw this.unexpected();
|
throw this.unexpected();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This helper method attempts to finish the given `node`
|
// This helper method attempts to finish the given `node`
|
||||||
// into a topic-reference node for the given `pipeProposal`.
|
// into a topic-reference node for the given `pipeProposal`.
|
||||||
@ -1519,6 +1528,13 @@ export default class ExpressionParser extends LValParser {
|
|||||||
"function",
|
"function",
|
||||||
);
|
);
|
||||||
this.next(); // eat `.`
|
this.next(); // eat `.`
|
||||||
|
// https://github.com/tc39/proposal-function.sent#syntax-1
|
||||||
|
if (this.match(tt._sent)) {
|
||||||
|
this.expectPlugin("functionSent");
|
||||||
|
} else if (!this.hasPlugin("functionSent")) {
|
||||||
|
// The code wasn't `function.sent` but just `function.`, so a simple error is less confusing.
|
||||||
|
this.unexpected();
|
||||||
|
}
|
||||||
return this.parseMetaProperty(node, meta, "sent");
|
return this.parseMetaProperty(node, meta, "sent");
|
||||||
}
|
}
|
||||||
return this.parseFunction(node);
|
return this.parseFunction(node);
|
||||||
@ -1531,16 +1547,6 @@ export default class ExpressionParser extends LValParser {
|
|||||||
): N.MetaProperty {
|
): N.MetaProperty {
|
||||||
node.meta = meta;
|
node.meta = meta;
|
||||||
|
|
||||||
if (meta.name === "function" && propertyName === "sent") {
|
|
||||||
// https://github.com/tc39/proposal-function.sent#syntax-1
|
|
||||||
if (this.isContextual(propertyName)) {
|
|
||||||
this.expectPlugin("functionSent");
|
|
||||||
} else if (!this.hasPlugin("functionSent")) {
|
|
||||||
// The code wasn't `function.sent` but just `function.`, so a simple error is less confusing.
|
|
||||||
this.unexpected();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const containsEsc = this.state.containsEsc;
|
const containsEsc = this.state.containsEsc;
|
||||||
|
|
||||||
node.property = this.parseIdentifier(true);
|
node.property = this.parseIdentifier(true);
|
||||||
@ -1562,7 +1568,7 @@ export default class ExpressionParser extends LValParser {
|
|||||||
const id = this.createIdentifier(this.startNodeAtNode(node), "import");
|
const id = this.createIdentifier(this.startNodeAtNode(node), "import");
|
||||||
this.next(); // eat `.`
|
this.next(); // eat `.`
|
||||||
|
|
||||||
if (this.isContextual("meta")) {
|
if (this.isContextual(tt._meta)) {
|
||||||
if (!this.inModule) {
|
if (!this.inModule) {
|
||||||
this.raise(id.start, SourceTypeModuleErrors.ImportMetaOutsideModule);
|
this.raise(id.start, SourceTypeModuleErrors.ImportMetaOutsideModule);
|
||||||
}
|
}
|
||||||
@ -2537,10 +2543,8 @@ export default class ExpressionParser extends LValParser {
|
|||||||
|
|
||||||
const { start, type } = this.state;
|
const { start, type } = this.state;
|
||||||
|
|
||||||
if (type === tt.name) {
|
if (tokenIsKeywordOrIdentifier(type)) {
|
||||||
name = this.state.value;
|
name = this.state.value;
|
||||||
} else if (tokenIsKeyword(type)) {
|
|
||||||
name = tokenLabelName(type);
|
|
||||||
} else {
|
} else {
|
||||||
throw this.unexpected();
|
throw this.unexpected();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import * as N from "../types";
|
import * as N from "../types";
|
||||||
import {
|
import {
|
||||||
|
tokenIsIdentifier,
|
||||||
tokenIsLoop,
|
tokenIsLoop,
|
||||||
tt,
|
tt,
|
||||||
type TokenType,
|
type TokenType,
|
||||||
@ -178,7 +179,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isLet(context: ?string): boolean {
|
isLet(context: ?string): boolean {
|
||||||
if (!this.isContextual("let")) {
|
if (!this.isContextual(tt._let)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return this.isLetKeyword(context);
|
return this.isLetKeyword(context);
|
||||||
@ -378,7 +379,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
const expr = this.parseExpression();
|
const expr = this.parseExpression();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
starttype === tt.name &&
|
tokenIsIdentifier(starttype) &&
|
||||||
expr.type === "Identifier" &&
|
expr.type === "Identifier" &&
|
||||||
this.eat(tt.colon)
|
this.eat(tt.colon)
|
||||||
) {
|
) {
|
||||||
@ -572,7 +573,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
this.state.labels.push(loopLabel);
|
this.state.labels.push(loopLabel);
|
||||||
|
|
||||||
let awaitAt = -1;
|
let awaitAt = -1;
|
||||||
if (this.isAwaitAllowed() && this.eatContextual("await")) {
|
if (this.isAwaitAllowed() && this.eatContextual(tt._await)) {
|
||||||
awaitAt = this.state.lastTokStart;
|
awaitAt = this.state.lastTokStart;
|
||||||
}
|
}
|
||||||
this.scope.enter(SCOPE_OTHER);
|
this.scope.enter(SCOPE_OTHER);
|
||||||
@ -585,7 +586,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
return this.parseFor(node, null);
|
return this.parseFor(node, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
const startsWithLet = this.isContextual("let");
|
const startsWithLet = this.isContextual(tt._let);
|
||||||
const isLet = startsWithLet && this.isLetKeyword();
|
const isLet = startsWithLet && this.isLetKeyword();
|
||||||
if (this.match(tt._var) || this.match(tt._const) || isLet) {
|
if (this.match(tt._var) || this.match(tt._const) || isLet) {
|
||||||
const init = this.startNode();
|
const init = this.startNode();
|
||||||
@ -595,7 +596,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
this.finishNode(init, "VariableDeclaration");
|
this.finishNode(init, "VariableDeclaration");
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(this.match(tt._in) || this.isContextual("of")) &&
|
(this.match(tt._in) || this.isContextual(tt._of)) &&
|
||||||
init.declarations.length === 1
|
init.declarations.length === 1
|
||||||
) {
|
) {
|
||||||
return this.parseForIn(node, init, awaitAt);
|
return this.parseForIn(node, init, awaitAt);
|
||||||
@ -608,12 +609,11 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
|
|
||||||
// Check whether the first token is possibly a contextual keyword, so that
|
// Check whether the first token is possibly a contextual keyword, so that
|
||||||
// we can forbid `for (async of` if this turns out to be a for-of loop.
|
// we can forbid `for (async of` if this turns out to be a for-of loop.
|
||||||
const startsWithUnescapedName =
|
const startsWithAsync = this.isContextual(tt._async);
|
||||||
this.match(tt.name) && !this.state.containsEsc;
|
|
||||||
|
|
||||||
const refExpressionErrors = new ExpressionErrors();
|
const refExpressionErrors = new ExpressionErrors();
|
||||||
const init = this.parseExpression(true, refExpressionErrors);
|
const init = this.parseExpression(true, refExpressionErrors);
|
||||||
const isForOf = this.isContextual("of");
|
const isForOf = this.isContextual(tt._of);
|
||||||
if (isForOf) {
|
if (isForOf) {
|
||||||
// Check for leading tokens that are forbidden in for-of loops:
|
// Check for leading tokens that are forbidden in for-of loops:
|
||||||
if (startsWithLet) {
|
if (startsWithLet) {
|
||||||
@ -621,9 +621,8 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
} else if (
|
} else if (
|
||||||
// `for await (async of []);` is allowed.
|
// `for await (async of []);` is allowed.
|
||||||
awaitAt === -1 &&
|
awaitAt === -1 &&
|
||||||
startsWithUnescapedName &&
|
startsWithAsync &&
|
||||||
init.type === "Identifier" &&
|
init.type === "Identifier"
|
||||||
init.name === "async"
|
|
||||||
) {
|
) {
|
||||||
// This catches the case where the `async` in `for (async of` was
|
// This catches the case where the `async` in `for (async of` was
|
||||||
// parsed as an identifier. If it was parsed as the start of an async
|
// parsed as an identifier. If it was parsed as the start of an async
|
||||||
@ -1119,7 +1118,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
kind === "const" &&
|
kind === "const" &&
|
||||||
!(this.match(tt._in) || this.isContextual("of"))
|
!(this.match(tt._in) || this.isContextual(tt._of))
|
||||||
) {
|
) {
|
||||||
// `const` with no initializer is allowed in TypeScript.
|
// `const` with no initializer is allowed in TypeScript.
|
||||||
// It could be a declaration like `const x: number;`.
|
// It could be a declaration like `const x: number;`.
|
||||||
@ -1132,7 +1131,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
decl.id.type !== "Identifier" &&
|
decl.id.type !== "Identifier" &&
|
||||||
!(isFor && (this.match(tt._in) || this.isContextual("of")))
|
!(isFor && (this.match(tt._in) || this.isContextual(tt._of)))
|
||||||
) {
|
) {
|
||||||
this.raise(
|
this.raise(
|
||||||
this.state.lastTokEnd,
|
this.state.lastTokEnd,
|
||||||
@ -1219,7 +1218,9 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseFunctionId(requireId?: boolean): ?N.Identifier {
|
parseFunctionId(requireId?: boolean): ?N.Identifier {
|
||||||
return requireId || this.match(tt.name) ? this.parseIdentifier() : null;
|
return requireId || tokenIsIdentifier(this.state.type)
|
||||||
|
? this.parseIdentifier()
|
||||||
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
parseFunctionParams(node: N.Function, allowModifiers?: boolean): void {
|
parseFunctionParams(node: N.Function, allowModifiers?: boolean): void {
|
||||||
@ -1405,7 +1406,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
member: N.ClassMember,
|
member: N.ClassMember,
|
||||||
state: N.ParseClassMemberState,
|
state: N.ParseClassMemberState,
|
||||||
): void {
|
): void {
|
||||||
const isStatic = this.isContextual("static");
|
const isStatic = this.isContextual(tt._static);
|
||||||
|
|
||||||
if (isStatic) {
|
if (isStatic) {
|
||||||
if (this.parseClassMemberFromModifier(classBody, member)) {
|
if (this.parseClassMemberFromModifier(classBody, member)) {
|
||||||
@ -1465,7 +1466,8 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const isContextual = this.match(tt.name) && !this.state.containsEsc;
|
const isContextual =
|
||||||
|
tokenIsIdentifier(this.state.type) && !this.state.containsEsc;
|
||||||
const isPrivate = this.match(tt.privateName);
|
const isPrivate = this.match(tt.privateName);
|
||||||
const key = this.parseClassElementName(member);
|
const key = this.parseClassElementName(member);
|
||||||
const maybeQuestionTokenStart = this.state.start;
|
const maybeQuestionTokenStart = this.state.start;
|
||||||
@ -1758,7 +1760,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
optionalId: ?boolean,
|
optionalId: ?boolean,
|
||||||
bindingType: BindingTypes = BIND_CLASS,
|
bindingType: BindingTypes = BIND_CLASS,
|
||||||
): void {
|
): void {
|
||||||
if (this.match(tt.name)) {
|
if (tokenIsIdentifier(this.state.type)) {
|
||||||
node.id = this.parseIdentifier();
|
node.id = this.parseIdentifier();
|
||||||
if (isStatement) {
|
if (isStatement) {
|
||||||
this.checkLVal(node.id, "class name", bindingType);
|
this.checkLVal(node.id, "class name", bindingType);
|
||||||
@ -1848,7 +1850,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
maybeParseExportNamespaceSpecifier(node: N.Node): boolean {
|
maybeParseExportNamespaceSpecifier(node: N.Node): boolean {
|
||||||
if (this.isContextual("as")) {
|
if (this.isContextual(tt._as)) {
|
||||||
if (!node.specifiers) node.specifiers = [];
|
if (!node.specifiers) node.specifiers = [];
|
||||||
|
|
||||||
const specifier = this.startNodeAt(
|
const specifier = this.startNodeAt(
|
||||||
@ -1891,7 +1893,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isAsyncFunction(): boolean {
|
isAsyncFunction(): boolean {
|
||||||
if (!this.isContextual("async")) return false;
|
if (!this.isContextual(tt._async)) return false;
|
||||||
const next = this.nextTokenStart();
|
const next = this.nextTokenStart();
|
||||||
return (
|
return (
|
||||||
!lineBreak.test(this.input.slice(this.state.pos, next)) &&
|
!lineBreak.test(this.input.slice(this.state.pos, next)) &&
|
||||||
@ -1941,23 +1943,23 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
isExportDefaultSpecifier(): boolean {
|
isExportDefaultSpecifier(): boolean {
|
||||||
if (this.match(tt.name)) {
|
const { type } = this.state;
|
||||||
const value = this.state.value;
|
if (tokenIsIdentifier(type)) {
|
||||||
if ((value === "async" && !this.state.containsEsc) || value === "let") {
|
if ((type === tt._async && !this.state.containsEsc) || type === tt._let) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
(value === "type" || value === "interface") &&
|
(type === tt._type || type === tt._interface) &&
|
||||||
!this.state.containsEsc
|
!this.state.containsEsc
|
||||||
) {
|
) {
|
||||||
const l = this.lookahead();
|
const { type: nextType } = this.lookahead();
|
||||||
// If we see any variable name other than `from` after `type` keyword,
|
// If we see any variable name other than `from` after `type` keyword,
|
||||||
// we consider it as flow/typescript type exports
|
// we consider it as flow/typescript type exports
|
||||||
// note that this approach may fail on some pedantic cases
|
// note that this approach may fail on some pedantic cases
|
||||||
// export type from = number
|
// export type from = number
|
||||||
if (
|
if (
|
||||||
(l.type === tt.name && l.value !== "from") ||
|
(tokenIsIdentifier(nextType) && nextType !== tt._from) ||
|
||||||
l.type === tt.braceL
|
nextType === tt.braceL
|
||||||
) {
|
) {
|
||||||
this.expectOnePlugin(["flow", "typescript"]);
|
this.expectOnePlugin(["flow", "typescript"]);
|
||||||
return false;
|
return false;
|
||||||
@ -1971,7 +1973,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
const hasFrom = this.isUnparsedContextual(next, "from");
|
const hasFrom = this.isUnparsedContextual(next, "from");
|
||||||
if (
|
if (
|
||||||
this.input.charCodeAt(next) === charCodes.comma ||
|
this.input.charCodeAt(next) === charCodes.comma ||
|
||||||
(this.match(tt.name) && hasFrom)
|
(tokenIsIdentifier(this.state.type) && hasFrom)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1989,7 +1991,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseExportFrom(node: N.ExportNamedDeclaration, expect?: boolean): void {
|
parseExportFrom(node: N.ExportNamedDeclaration, expect?: boolean): void {
|
||||||
if (this.eatContextual("from")) {
|
if (this.eatContextual(tt._from)) {
|
||||||
node.source = this.parseImportSource();
|
node.source = this.parseImportSource();
|
||||||
this.checkExport(node);
|
this.checkExport(node);
|
||||||
const assertions = this.maybeParseImportAssertions();
|
const assertions = this.maybeParseImportAssertions();
|
||||||
@ -2169,7 +2171,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
const isString = this.match(tt.string);
|
const isString = this.match(tt.string);
|
||||||
const local = this.parseModuleExportName();
|
const local = this.parseModuleExportName();
|
||||||
node.local = local;
|
node.local = local;
|
||||||
if (this.eatContextual("as")) {
|
if (this.eatContextual(tt._as)) {
|
||||||
node.exported = this.parseModuleExportName();
|
node.exported = this.parseModuleExportName();
|
||||||
} else if (isString) {
|
} else if (isString) {
|
||||||
node.exported = cloneStringLiteral(local);
|
node.exported = cloneStringLiteral(local);
|
||||||
@ -2222,7 +2224,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
// now we check if we need to parse the next imports
|
// now we check if we need to parse the next imports
|
||||||
// but only if they are not importing * (everything)
|
// but only if they are not importing * (everything)
|
||||||
if (parseNext && !hasStar) this.parseNamedImportSpecifiers(node);
|
if (parseNext && !hasStar) this.parseNamedImportSpecifiers(node);
|
||||||
this.expectContextual("from");
|
this.expectContextual(tt._from);
|
||||||
}
|
}
|
||||||
node.source = this.parseImportSource();
|
node.source = this.parseImportSource();
|
||||||
// https://github.com/tc39/proposal-import-assertions
|
// https://github.com/tc39/proposal-import-assertions
|
||||||
@ -2249,7 +2251,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
|
|
||||||
// eslint-disable-next-line no-unused-vars
|
// eslint-disable-next-line no-unused-vars
|
||||||
shouldParseDefaultImport(node: N.ImportDeclaration): boolean {
|
shouldParseDefaultImport(node: N.ImportDeclaration): boolean {
|
||||||
return this.match(tt.name);
|
return tokenIsIdentifier(this.state.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseImportSpecifierLocal(
|
parseImportSpecifierLocal(
|
||||||
@ -2368,7 +2370,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
|
|
||||||
maybeParseImportAssertions() {
|
maybeParseImportAssertions() {
|
||||||
// [no LineTerminator here] AssertClause
|
// [no LineTerminator here] AssertClause
|
||||||
if (this.isContextual("assert") && !this.hasPrecedingLineBreak()) {
|
if (this.isContextual(tt._assert) && !this.hasPrecedingLineBreak()) {
|
||||||
this.expectPlugin("importAssertions");
|
this.expectPlugin("importAssertions");
|
||||||
this.next(); // eat `assert`
|
this.next(); // eat `assert`
|
||||||
} else {
|
} else {
|
||||||
@ -2401,7 +2403,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
if (this.match(tt.star)) {
|
if (this.match(tt.star)) {
|
||||||
const specifier = this.startNode();
|
const specifier = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
this.expectContextual("as");
|
this.expectContextual(tt._as);
|
||||||
|
|
||||||
this.parseImportSpecifierLocal(
|
this.parseImportSpecifierLocal(
|
||||||
node,
|
node,
|
||||||
@ -2439,7 +2441,7 @@ export default class StatementParser extends ExpressionParser {
|
|||||||
const specifier = this.startNode();
|
const specifier = this.startNode();
|
||||||
const importedIsString = this.match(tt.string);
|
const importedIsString = this.match(tt.string);
|
||||||
specifier.imported = this.parseModuleExportName();
|
specifier.imported = this.parseModuleExportName();
|
||||||
if (this.eatContextual("as")) {
|
if (this.eatContextual(tt._as)) {
|
||||||
specifier.local = this.parseIdentifier();
|
specifier.local = this.parseIdentifier();
|
||||||
} else {
|
} else {
|
||||||
const { imported } = specifier;
|
const { imported } = specifier;
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
isTokenType,
|
isTokenType,
|
||||||
tokenIsKeyword,
|
tokenIsLiteralPropertyName,
|
||||||
tokenLabelName,
|
tokenLabelName,
|
||||||
tt,
|
tt,
|
||||||
type TokenType,
|
type TokenType,
|
||||||
@ -68,12 +68,8 @@ export default class UtilParser extends Tokenizer {
|
|||||||
|
|
||||||
// Tests whether parsed token is a contextual keyword.
|
// Tests whether parsed token is a contextual keyword.
|
||||||
|
|
||||||
isContextual(name: string): boolean {
|
isContextual(token: TokenType): boolean {
|
||||||
return (
|
return this.state.type === token && !this.state.containsEsc;
|
||||||
this.match(tt.name) &&
|
|
||||||
this.state.value === name &&
|
|
||||||
!this.state.containsEsc
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isUnparsedContextual(nameStart: number, name: string): boolean {
|
isUnparsedContextual(nameStart: number, name: string): boolean {
|
||||||
@ -98,14 +94,18 @@ export default class UtilParser extends Tokenizer {
|
|||||||
|
|
||||||
// Consumes contextual keyword if possible.
|
// Consumes contextual keyword if possible.
|
||||||
|
|
||||||
eatContextual(name: string): boolean {
|
eatContextual(token: TokenType): boolean {
|
||||||
return this.isContextual(name) && this.eat(tt.name);
|
if (this.isContextual(token)) {
|
||||||
|
this.next();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Asserts that following token is given contextual keyword.
|
// Asserts that following token is given contextual keyword.
|
||||||
|
|
||||||
expectContextual(name: string, template?: ErrorTemplate): void {
|
expectContextual(token: TokenType, template?: ErrorTemplate): void {
|
||||||
if (!this.eatContextual(name)) this.unexpected(null, template);
|
if (!this.eatContextual(token)) this.unexpected(null, template);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test whether a semicolon can be inserted at the current position.
|
// Test whether a semicolon can be inserted at the current position.
|
||||||
@ -306,14 +306,7 @@ export default class UtilParser extends Tokenizer {
|
|||||||
* BigIntLiteral
|
* BigIntLiteral
|
||||||
*/
|
*/
|
||||||
isLiteralPropertyName(): boolean {
|
isLiteralPropertyName(): boolean {
|
||||||
return (
|
return tokenIsLiteralPropertyName(this.state.type);
|
||||||
this.match(tt.name) ||
|
|
||||||
tokenIsKeyword(this.state.type) ||
|
|
||||||
this.match(tt.string) ||
|
|
||||||
this.match(tt.num) ||
|
|
||||||
this.match(tt.bigint) ||
|
|
||||||
this.match(tt.decimal)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -7,16 +7,20 @@
|
|||||||
|
|
||||||
import type Parser from "../../parser";
|
import type Parser from "../../parser";
|
||||||
import {
|
import {
|
||||||
|
tokenIsIdentifier,
|
||||||
tokenIsKeyword,
|
tokenIsKeyword,
|
||||||
|
tokenIsKeywordOrIdentifier,
|
||||||
|
tokenIsLiteralPropertyName,
|
||||||
tokenLabelName,
|
tokenLabelName,
|
||||||
tt,
|
tt,
|
||||||
type TokenType,
|
type TokenType,
|
||||||
|
tokenIsFlowInterfaceOrTypeOrOpaque,
|
||||||
} from "../../tokenizer/types";
|
} from "../../tokenizer/types";
|
||||||
import * as N from "../../types";
|
import * as N from "../../types";
|
||||||
import type { Position } from "../../util/location";
|
import type { Position } from "../../util/location";
|
||||||
import { types as tc } from "../../tokenizer/context";
|
import { types as tc } from "../../tokenizer/context";
|
||||||
import * as charCodes from "charcodes";
|
import * as charCodes from "charcodes";
|
||||||
import { isIteratorStart, isKeyword } from "../../util/identifier";
|
import { isIteratorStart } from "../../util/identifier";
|
||||||
import FlowScopeHandler from "./scope";
|
import FlowScopeHandler from "./scope";
|
||||||
import {
|
import {
|
||||||
type BindingTypes,
|
type BindingTypes,
|
||||||
@ -160,11 +164,8 @@ function hasTypeImportKind(node: N.Node): boolean {
|
|||||||
return node.importKind === "type" || node.importKind === "typeof";
|
return node.importKind === "type" || node.importKind === "typeof";
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMaybeDefaultImport(state: { type: TokenType, value: any }): boolean {
|
function isMaybeDefaultImport(type: TokenType): boolean {
|
||||||
return (
|
return tokenIsKeywordOrIdentifier(type) && type !== tt._from;
|
||||||
(state.type === tt.name || tokenIsKeyword(state.type)) &&
|
|
||||||
state.value !== "from"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const exportSuggestions = {
|
const exportSuggestions = {
|
||||||
@ -266,7 +267,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
const moduloPos = this.state.start;
|
const moduloPos = this.state.start;
|
||||||
this.next(); // eat `%`
|
this.next(); // eat `%`
|
||||||
this.expectContextual("checks");
|
this.expectContextual(tt._checks);
|
||||||
// Force '%' and 'checks' to be adjacent
|
// Force '%' and 'checks' to be adjacent
|
||||||
if (this.state.lastTokStart > moduloPos + 1) {
|
if (this.state.lastTokStart > moduloPos + 1) {
|
||||||
this.raise(moduloPos, FlowErrors.UnexpectedSpaceBetweenModuloChecks);
|
this.raise(moduloPos, FlowErrors.UnexpectedSpaceBetweenModuloChecks);
|
||||||
@ -360,7 +361,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
return this.flowParseDeclareFunction(node);
|
return this.flowParseDeclareFunction(node);
|
||||||
} else if (this.match(tt._var)) {
|
} else if (this.match(tt._var)) {
|
||||||
return this.flowParseDeclareVariable(node);
|
return this.flowParseDeclareVariable(node);
|
||||||
} else if (this.eatContextual("module")) {
|
} else if (this.eatContextual(tt._module)) {
|
||||||
if (this.match(tt.dot)) {
|
if (this.match(tt.dot)) {
|
||||||
return this.flowParseDeclareModuleExports(node);
|
return this.flowParseDeclareModuleExports(node);
|
||||||
} else {
|
} else {
|
||||||
@ -369,11 +370,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
return this.flowParseDeclareModule(node);
|
return this.flowParseDeclareModule(node);
|
||||||
}
|
}
|
||||||
} else if (this.isContextual("type")) {
|
} else if (this.isContextual(tt._type)) {
|
||||||
return this.flowParseDeclareTypeAlias(node);
|
return this.flowParseDeclareTypeAlias(node);
|
||||||
} else if (this.isContextual("opaque")) {
|
} else if (this.isContextual(tt._opaque)) {
|
||||||
return this.flowParseDeclareOpaqueType(node);
|
return this.flowParseDeclareOpaqueType(node);
|
||||||
} else if (this.isContextual("interface")) {
|
} else if (this.isContextual(tt._interface)) {
|
||||||
return this.flowParseDeclareInterface(node);
|
return this.flowParseDeclareInterface(node);
|
||||||
} else if (this.match(tt._export)) {
|
} else if (this.match(tt._export)) {
|
||||||
return this.flowParseDeclareExportDeclaration(node, insideModule);
|
return this.flowParseDeclareExportDeclaration(node, insideModule);
|
||||||
@ -411,7 +412,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
if (this.match(tt._import)) {
|
if (this.match(tt._import)) {
|
||||||
this.next();
|
this.next();
|
||||||
if (!this.isContextual("type") && !this.match(tt._typeof)) {
|
if (!this.isContextual(tt._type) && !this.match(tt._typeof)) {
|
||||||
this.raise(
|
this.raise(
|
||||||
this.state.lastTokStart,
|
this.state.lastTokStart,
|
||||||
FlowErrors.InvalidNonTypeImportInDeclareModule,
|
FlowErrors.InvalidNonTypeImportInDeclareModule,
|
||||||
@ -420,7 +421,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
this.parseImport(bodyNode);
|
this.parseImport(bodyNode);
|
||||||
} else {
|
} else {
|
||||||
this.expectContextual(
|
this.expectContextual(
|
||||||
"declare",
|
tt._declare,
|
||||||
FlowErrors.UnsupportedStatementInDeclareModule,
|
FlowErrors.UnsupportedStatementInDeclareModule,
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -492,7 +493,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (
|
if (
|
||||||
this.match(tt._const) ||
|
this.match(tt._const) ||
|
||||||
this.isLet() ||
|
this.isLet() ||
|
||||||
((this.isContextual("type") || this.isContextual("interface")) &&
|
((this.isContextual(tt._type) || this.isContextual(tt._interface)) &&
|
||||||
!insideModule)
|
!insideModule)
|
||||||
) {
|
) {
|
||||||
const label = this.state.value;
|
const label = this.state.value;
|
||||||
@ -510,7 +511,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
this.match(tt._var) || // declare export var ...
|
this.match(tt._var) || // declare export var ...
|
||||||
this.match(tt._function) || // declare export function ...
|
this.match(tt._function) || // declare export function ...
|
||||||
this.match(tt._class) || // declare export class ...
|
this.match(tt._class) || // declare export class ...
|
||||||
this.isContextual("opaque") // declare export opaque ..
|
this.isContextual(tt._opaque) // declare export opaque ..
|
||||||
) {
|
) {
|
||||||
node.declaration = this.flowParseDeclare(this.startNode());
|
node.declaration = this.flowParseDeclare(this.startNode());
|
||||||
node.default = false;
|
node.default = false;
|
||||||
@ -519,9 +520,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
} else if (
|
} else if (
|
||||||
this.match(tt.star) || // declare export * from ''
|
this.match(tt.star) || // declare export * from ''
|
||||||
this.match(tt.braceL) || // declare export {} ...
|
this.match(tt.braceL) || // declare export {} ...
|
||||||
this.isContextual("interface") || // declare export interface ...
|
this.isContextual(tt._interface) || // declare export interface ...
|
||||||
this.isContextual("type") || // declare export type ...
|
this.isContextual(tt._type) || // declare export type ...
|
||||||
this.isContextual("opaque") // declare export opaque type ...
|
this.isContextual(tt._opaque) // declare export opaque type ...
|
||||||
) {
|
) {
|
||||||
node = this.parseExport(node);
|
node = this.parseExport(node);
|
||||||
if (node.type === "ExportNamedDeclaration") {
|
if (node.type === "ExportNamedDeclaration") {
|
||||||
@ -547,7 +548,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
node: N.FlowDeclareModuleExports,
|
node: N.FlowDeclareModuleExports,
|
||||||
): N.FlowDeclareModuleExports {
|
): N.FlowDeclareModuleExports {
|
||||||
this.next();
|
this.next();
|
||||||
this.expectContextual("exports");
|
this.expectContextual(tt._exports);
|
||||||
node.typeAnnotation = this.flowParseTypeAnnotation();
|
node.typeAnnotation = this.flowParseTypeAnnotation();
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
|
|
||||||
@ -615,14 +616,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
} while (!isClass && this.eat(tt.comma));
|
} while (!isClass && this.eat(tt.comma));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isContextual("mixins")) {
|
if (this.isContextual(tt._mixins)) {
|
||||||
this.next();
|
this.next();
|
||||||
do {
|
do {
|
||||||
node.mixins.push(this.flowParseInterfaceExtends());
|
node.mixins.push(this.flowParseInterfaceExtends());
|
||||||
} while (this.eat(tt.comma));
|
} while (this.eat(tt.comma));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isContextual("implements")) {
|
if (this.isContextual(tt._implements)) {
|
||||||
this.next();
|
this.next();
|
||||||
do {
|
do {
|
||||||
node.implements.push(this.flowParseInterfaceExtends());
|
node.implements.push(this.flowParseInterfaceExtends());
|
||||||
@ -707,7 +708,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
node: N.FlowOpaqueType,
|
node: N.FlowOpaqueType,
|
||||||
declare: boolean,
|
declare: boolean,
|
||||||
): N.FlowOpaqueType {
|
): N.FlowOpaqueType {
|
||||||
this.expectContextual("type");
|
this.expectContextual(tt._type);
|
||||||
node.id = this.flowParseRestrictedIdentifier(
|
node.id = this.flowParseRestrictedIdentifier(
|
||||||
/* liberal */ true,
|
/* liberal */ true,
|
||||||
/* declaration */ true,
|
/* declaration */ true,
|
||||||
@ -844,7 +845,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
flowParseInterfaceType(): N.FlowInterfaceType {
|
flowParseInterfaceType(): N.FlowInterfaceType {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.expectContextual("interface");
|
this.expectContextual(tt._interface);
|
||||||
|
|
||||||
node.extends = [];
|
node.extends = [];
|
||||||
if (this.eat(tt._extends)) {
|
if (this.eat(tt._extends)) {
|
||||||
@ -1008,7 +1009,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
let inexactStart: ?number = null;
|
let inexactStart: ?number = null;
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
|
|
||||||
if (allowProto && this.isContextual("proto")) {
|
if (allowProto && this.isContextual(tt._proto)) {
|
||||||
const lookahead = this.lookahead();
|
const lookahead = this.lookahead();
|
||||||
|
|
||||||
if (lookahead.type !== tt.colon && lookahead.type !== tt.question) {
|
if (lookahead.type !== tt.colon && lookahead.type !== tt.question) {
|
||||||
@ -1018,7 +1019,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allowStatic && this.isContextual("static")) {
|
if (allowStatic && this.isContextual(tt._static)) {
|
||||||
const lookahead = this.lookahead();
|
const lookahead = this.lookahead();
|
||||||
|
|
||||||
// static is a valid identifier name
|
// static is a valid identifier name
|
||||||
@ -1059,13 +1060,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
} else {
|
} else {
|
||||||
let kind = "init";
|
let kind = "init";
|
||||||
|
|
||||||
if (this.isContextual("get") || this.isContextual("set")) {
|
if (this.isContextual(tt._get) || this.isContextual(tt._set)) {
|
||||||
const lookahead = this.lookahead();
|
const lookahead = this.lookahead();
|
||||||
if (
|
if (tokenIsLiteralPropertyName(lookahead.type)) {
|
||||||
lookahead.type === tt.name ||
|
|
||||||
lookahead.type === tt.string ||
|
|
||||||
lookahead.type === tt.num
|
|
||||||
) {
|
|
||||||
kind = this.state.value;
|
kind = this.state.value;
|
||||||
this.next();
|
this.next();
|
||||||
}
|
}
|
||||||
@ -1432,18 +1429,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
|
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
|
||||||
|
|
||||||
switch (this.state.type) {
|
switch (this.state.type) {
|
||||||
case tt.name:
|
|
||||||
if (this.isContextual("interface")) {
|
|
||||||
return this.flowParseInterfaceType();
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.flowIdentToTypeAnnotation(
|
|
||||||
startPos,
|
|
||||||
startLoc,
|
|
||||||
node,
|
|
||||||
this.parseIdentifier(),
|
|
||||||
);
|
|
||||||
|
|
||||||
case tt.braceL:
|
case tt.braceL:
|
||||||
return this.flowParseObjectType({
|
return this.flowParseObjectType({
|
||||||
allowStatic: false,
|
allowStatic: false,
|
||||||
@ -1491,7 +1476,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
// Check to see if this is actually a grouped type
|
// Check to see if this is actually a grouped type
|
||||||
if (!this.match(tt.parenR) && !this.match(tt.ellipsis)) {
|
if (!this.match(tt.parenR) && !this.match(tt.ellipsis)) {
|
||||||
if (this.match(tt.name) || this.match(tt._this)) {
|
if (tokenIsIdentifier(this.state.type) || this.match(tt._this)) {
|
||||||
const token = this.lookahead().type;
|
const token = this.lookahead().type;
|
||||||
isGroupedType = token !== tt.question && token !== tt.colon;
|
isGroupedType = token !== tt.question && token !== tt.colon;
|
||||||
} else {
|
} else {
|
||||||
@ -1619,6 +1604,17 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
const label = tokenLabelName(this.state.type);
|
const label = tokenLabelName(this.state.type);
|
||||||
this.next();
|
this.next();
|
||||||
return super.createIdentifier(node, label);
|
return super.createIdentifier(node, label);
|
||||||
|
} else if (tokenIsIdentifier(this.state.type)) {
|
||||||
|
if (this.isContextual(tt._interface)) {
|
||||||
|
return this.flowParseInterfaceType();
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.flowIdentToTypeAnnotation(
|
||||||
|
startPos,
|
||||||
|
startLoc,
|
||||||
|
node,
|
||||||
|
this.parseIdentifier(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1823,18 +1819,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
// interfaces and enums
|
// interfaces and enums
|
||||||
parseStatement(context: ?string, topLevel?: boolean): N.Statement {
|
parseStatement(context: ?string, topLevel?: boolean): N.Statement {
|
||||||
// strict mode handling of `interface` since it's a reserved word
|
// strict mode handling of `interface` since it's a reserved word
|
||||||
if (
|
if (this.state.strict && this.isContextual(tt._interface)) {
|
||||||
this.state.strict &&
|
|
||||||
this.match(tt.name) &&
|
|
||||||
this.state.value === "interface"
|
|
||||||
) {
|
|
||||||
const lookahead = this.lookahead();
|
const lookahead = this.lookahead();
|
||||||
if (lookahead.type === tt.name || isKeyword(lookahead.value)) {
|
if (tokenIsKeywordOrIdentifier(lookahead.type)) {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
return this.flowParseInterface(node);
|
return this.flowParseInterface(node);
|
||||||
}
|
}
|
||||||
} else if (this.shouldParseEnums() && this.isContextual("enum")) {
|
} else if (this.shouldParseEnums() && this.isContextual(tt._enum)) {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
return this.flowParseEnumDeclaration(node);
|
return this.flowParseEnumDeclaration(node);
|
||||||
@ -1856,14 +1848,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (expr.name === "declare") {
|
if (expr.name === "declare") {
|
||||||
if (
|
if (
|
||||||
this.match(tt._class) ||
|
this.match(tt._class) ||
|
||||||
this.match(tt.name) ||
|
tokenIsIdentifier(this.state.type) ||
|
||||||
this.match(tt._function) ||
|
this.match(tt._function) ||
|
||||||
this.match(tt._var) ||
|
this.match(tt._var) ||
|
||||||
this.match(tt._export)
|
this.match(tt._export)
|
||||||
) {
|
) {
|
||||||
return this.flowParseDeclare(node);
|
return this.flowParseDeclare(node);
|
||||||
}
|
}
|
||||||
} else if (this.match(tt.name)) {
|
} else if (tokenIsIdentifier(this.state.type)) {
|
||||||
if (expr.name === "interface") {
|
if (expr.name === "interface") {
|
||||||
return this.flowParseInterface(node);
|
return this.flowParseInterface(node);
|
||||||
} else if (expr.name === "type") {
|
} else if (expr.name === "type") {
|
||||||
@ -1879,31 +1871,30 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
// export type
|
// export type
|
||||||
shouldParseExportDeclaration(): boolean {
|
shouldParseExportDeclaration(): boolean {
|
||||||
return (
|
const { type } = this.state;
|
||||||
this.isContextual("type") ||
|
if (
|
||||||
this.isContextual("interface") ||
|
tokenIsFlowInterfaceOrTypeOrOpaque(type) ||
|
||||||
this.isContextual("opaque") ||
|
(this.shouldParseEnums() && type === tt._enum)
|
||||||
(this.shouldParseEnums() && this.isContextual("enum")) ||
|
) {
|
||||||
super.shouldParseExportDeclaration()
|
return !this.state.containsEsc;
|
||||||
);
|
}
|
||||||
|
return super.shouldParseExportDeclaration();
|
||||||
}
|
}
|
||||||
|
|
||||||
isExportDefaultSpecifier(): boolean {
|
isExportDefaultSpecifier(): boolean {
|
||||||
|
const { type } = this.state;
|
||||||
if (
|
if (
|
||||||
this.match(tt.name) &&
|
tokenIsFlowInterfaceOrTypeOrOpaque(type) ||
|
||||||
(this.state.value === "type" ||
|
(this.shouldParseEnums() && type === tt._enum)
|
||||||
this.state.value === "interface" ||
|
|
||||||
this.state.value === "opaque" ||
|
|
||||||
(this.shouldParseEnums() && this.state.value === "enum"))
|
|
||||||
) {
|
) {
|
||||||
return false;
|
return this.state.containsEsc;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.isExportDefaultSpecifier();
|
return super.isExportDefaultSpecifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
parseExportDefaultExpression(): N.Expression | N.Declaration {
|
parseExportDefaultExpression(): N.Expression | N.Declaration {
|
||||||
if (this.shouldParseEnums() && this.isContextual("enum")) {
|
if (this.shouldParseEnums() && this.isContextual(tt._enum)) {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
return this.flowParseEnumDeclaration(node);
|
return this.flowParseEnumDeclaration(node);
|
||||||
@ -2124,7 +2115,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseExportDeclaration(node: N.ExportNamedDeclaration): ?N.Declaration {
|
parseExportDeclaration(node: N.ExportNamedDeclaration): ?N.Declaration {
|
||||||
if (this.isContextual("type")) {
|
if (this.isContextual(tt._type)) {
|
||||||
node.exportKind = "type";
|
node.exportKind = "type";
|
||||||
|
|
||||||
const declarationNode = this.startNode();
|
const declarationNode = this.startNode();
|
||||||
@ -2139,19 +2130,19 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
// export type Foo = Bar;
|
// export type Foo = Bar;
|
||||||
return this.flowParseTypeAlias(declarationNode);
|
return this.flowParseTypeAlias(declarationNode);
|
||||||
}
|
}
|
||||||
} else if (this.isContextual("opaque")) {
|
} else if (this.isContextual(tt._opaque)) {
|
||||||
node.exportKind = "type";
|
node.exportKind = "type";
|
||||||
|
|
||||||
const declarationNode = this.startNode();
|
const declarationNode = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
// export opaque type Foo = Bar;
|
// export opaque type Foo = Bar;
|
||||||
return this.flowParseOpaqueType(declarationNode, false);
|
return this.flowParseOpaqueType(declarationNode, false);
|
||||||
} else if (this.isContextual("interface")) {
|
} else if (this.isContextual(tt._interface)) {
|
||||||
node.exportKind = "type";
|
node.exportKind = "type";
|
||||||
const declarationNode = this.startNode();
|
const declarationNode = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
return this.flowParseInterface(declarationNode);
|
return this.flowParseInterface(declarationNode);
|
||||||
} else if (this.shouldParseEnums() && this.isContextual("enum")) {
|
} else if (this.shouldParseEnums() && this.isContextual(tt._enum)) {
|
||||||
node.exportKind = "value";
|
node.exportKind = "value";
|
||||||
const declarationNode = this.startNode();
|
const declarationNode = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
@ -2164,7 +2155,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
eatExportStar(node: N.Node): boolean {
|
eatExportStar(node: N.Node): boolean {
|
||||||
if (super.eatExportStar(...arguments)) return true;
|
if (super.eatExportStar(...arguments)) return true;
|
||||||
|
|
||||||
if (this.isContextual("type") && this.lookahead().type === tt.star) {
|
if (this.isContextual(tt._type) && this.lookahead().type === tt.star) {
|
||||||
node.exportKind = "type";
|
node.exportKind = "type";
|
||||||
this.next();
|
this.next();
|
||||||
this.next();
|
this.next();
|
||||||
@ -2196,7 +2187,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
state: N.ParseClassMemberState,
|
state: N.ParseClassMemberState,
|
||||||
): void {
|
): void {
|
||||||
const pos = this.state.start;
|
const pos = this.state.start;
|
||||||
if (this.isContextual("declare")) {
|
if (this.isContextual(tt._declare)) {
|
||||||
if (this.parseClassMemberFromModifier(classBody, member)) {
|
if (this.parseClassMemberFromModifier(classBody, member)) {
|
||||||
// 'declare' is a class element name
|
// 'declare' is a class element name
|
||||||
return;
|
return;
|
||||||
@ -2456,7 +2447,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (node.superClass && this.isRelational("<")) {
|
if (node.superClass && this.isRelational("<")) {
|
||||||
node.superTypeParameters = this.flowParseTypeParameterInstantiation();
|
node.superTypeParameters = this.flowParseTypeParameterInstantiation();
|
||||||
}
|
}
|
||||||
if (this.isContextual("implements")) {
|
if (this.isContextual(tt._implements)) {
|
||||||
this.next();
|
this.next();
|
||||||
const implemented: N.FlowClassImplements[] = (node.implements = []);
|
const implemented: N.FlowClassImplements[] = (node.implements = []);
|
||||||
do {
|
do {
|
||||||
@ -2585,7 +2576,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
return super.shouldParseDefaultImport(node);
|
return super.shouldParseDefaultImport(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
return isMaybeDefaultImport(this.state);
|
return isMaybeDefaultImport(this.state.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
parseImportSpecifierLocal(
|
parseImportSpecifierLocal(
|
||||||
@ -2612,21 +2603,22 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
let kind = null;
|
let kind = null;
|
||||||
if (this.match(tt._typeof)) {
|
if (this.match(tt._typeof)) {
|
||||||
kind = "typeof";
|
kind = "typeof";
|
||||||
} else if (this.isContextual("type")) {
|
} else if (this.isContextual(tt._type)) {
|
||||||
kind = "type";
|
kind = "type";
|
||||||
}
|
}
|
||||||
if (kind) {
|
if (kind) {
|
||||||
const lh = this.lookahead();
|
const lh = this.lookahead();
|
||||||
|
const { type } = lh;
|
||||||
|
|
||||||
// import type * is not allowed
|
// import type * is not allowed
|
||||||
if (kind === "type" && lh.type === tt.star) {
|
if (kind === "type" && type === tt.star) {
|
||||||
this.unexpected(lh.start);
|
this.unexpected(lh.start);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isMaybeDefaultImport(lh) ||
|
isMaybeDefaultImport(type) ||
|
||||||
lh.type === tt.braceL ||
|
type === tt.braceL ||
|
||||||
lh.type === tt.star
|
type === tt.star
|
||||||
) {
|
) {
|
||||||
this.next();
|
this.next();
|
||||||
node.importKind = kind;
|
node.importKind = kind;
|
||||||
@ -2652,12 +2644,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
let isBinding = false;
|
let isBinding = false;
|
||||||
if (this.isContextual("as") && !this.isLookaheadContextual("as")) {
|
if (this.isContextual(tt._as) && !this.isLookaheadContextual("as")) {
|
||||||
const as_ident = this.parseIdentifier(true);
|
const as_ident = this.parseIdentifier(true);
|
||||||
if (
|
if (
|
||||||
specifierTypeKind !== null &&
|
specifierTypeKind !== null &&
|
||||||
!this.match(tt.name) &&
|
!tokenIsKeywordOrIdentifier(this.state.type)
|
||||||
!tokenIsKeyword(this.state.type)
|
|
||||||
) {
|
) {
|
||||||
// `import {type as ,` or `import {type as }`
|
// `import {type as ,` or `import {type as }`
|
||||||
specifier.imported = as_ident;
|
specifier.imported = as_ident;
|
||||||
@ -2672,7 +2663,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
} else {
|
} else {
|
||||||
if (
|
if (
|
||||||
specifierTypeKind !== null &&
|
specifierTypeKind !== null &&
|
||||||
(this.match(tt.name) || tokenIsKeyword(this.state.type))
|
tokenIsKeywordOrIdentifier(this.state.type)
|
||||||
) {
|
) {
|
||||||
// `import {type foo`
|
// `import {type foo`
|
||||||
specifier.imported = this.parseIdentifier(true);
|
specifier.imported = this.parseIdentifier(true);
|
||||||
@ -2691,7 +2682,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
specifier.importKind = null;
|
specifier.importKind = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.eatContextual("as")) {
|
if (this.eatContextual(tt._as)) {
|
||||||
specifier.local = this.parseIdentifier();
|
specifier.local = this.parseIdentifier();
|
||||||
} else {
|
} else {
|
||||||
isBinding = true;
|
isBinding = true;
|
||||||
@ -3546,8 +3537,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}: {
|
}: {
|
||||||
enumName: string,
|
enumName: string,
|
||||||
}): EnumExplicitType {
|
}): EnumExplicitType {
|
||||||
if (this.eatContextual("of")) {
|
if (this.eatContextual(tt._of)) {
|
||||||
if (!this.match(tt.name)) {
|
if (!tokenIsIdentifier(this.state.type)) {
|
||||||
throw this.flowEnumErrorInvalidExplicitType(this.state.start, {
|
throw this.flowEnumErrorInvalidExplicitType(this.state.start, {
|
||||||
enumName,
|
enumName,
|
||||||
suppliedType: null,
|
suppliedType: null,
|
||||||
|
|||||||
@ -163,7 +163,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
// Replicate the original checks that lead to looking ahead for an
|
// Replicate the original checks that lead to looking ahead for an
|
||||||
// identifier.
|
// identifier.
|
||||||
if (!this.isContextual("let")) {
|
if (!this.isContextual(tt._let)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (context) return false;
|
if (context) return false;
|
||||||
@ -263,7 +263,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
const placeholder = this.parsePlaceholder("Identifier");
|
const placeholder = this.parsePlaceholder("Identifier");
|
||||||
if (!placeholder) return super.parseExport(...arguments);
|
if (!placeholder) return super.parseExport(...arguments);
|
||||||
|
|
||||||
if (!this.isContextual("from") && !this.match(tt.comma)) {
|
if (!this.isContextual(tt._from) && !this.match(tt.comma)) {
|
||||||
// export %%DECL%%;
|
// export %%DECL%%;
|
||||||
node.specifiers = [];
|
node.specifiers = [];
|
||||||
node.source = null;
|
node.source = null;
|
||||||
@ -324,7 +324,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
node.specifiers = [];
|
node.specifiers = [];
|
||||||
|
|
||||||
if (!this.isContextual("from") && !this.match(tt.comma)) {
|
if (!this.isContextual(tt._from) && !this.match(tt.comma)) {
|
||||||
// import %%STRING%%;
|
// import %%STRING%%;
|
||||||
node.source = this.finishPlaceholder(placeholder, "StringLiteral");
|
node.source = this.finishPlaceholder(placeholder, "StringLiteral");
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
@ -345,7 +345,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (!hasStarImport) this.parseNamedImportSpecifiers(node);
|
if (!hasStarImport) this.parseNamedImportSpecifiers(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.expectContextual("from");
|
this.expectContextual(tt._from);
|
||||||
node.source = this.parseImportSource();
|
node.source = this.parseImportSource();
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(node, "ImportDeclaration");
|
return this.finishNode(node, "ImportDeclaration");
|
||||||
|
|||||||
@ -5,9 +5,15 @@
|
|||||||
// Error messages are colocated with the plugin.
|
// Error messages are colocated with the plugin.
|
||||||
/* eslint-disable @babel/development-internal/dry-error-messages */
|
/* eslint-disable @babel/development-internal/dry-error-messages */
|
||||||
|
|
||||||
import type { TokenType } from "../../tokenizer/types";
|
|
||||||
import type State from "../../tokenizer/state";
|
import type State from "../../tokenizer/state";
|
||||||
import { tokenOperatorPrecedence, tt } from "../../tokenizer/types";
|
import {
|
||||||
|
tokenIsIdentifier,
|
||||||
|
tokenIsTSDeclarationStart,
|
||||||
|
tokenIsTSTypeOperator,
|
||||||
|
tokenOperatorPrecedence,
|
||||||
|
tt,
|
||||||
|
type TokenType,
|
||||||
|
} from "../../tokenizer/types";
|
||||||
import { types as ct } from "../../tokenizer/context";
|
import { types as ct } from "../../tokenizer/context";
|
||||||
import * as N from "../../types";
|
import * as N from "../../types";
|
||||||
import type { Position } from "../../util/location";
|
import type { Position } from "../../util/location";
|
||||||
@ -206,7 +212,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
tsIsIdentifier(): boolean {
|
tsIsIdentifier(): boolean {
|
||||||
// TODO: actually a bit more complex in TypeScript, but shouldn't matter.
|
// TODO: actually a bit more complex in TypeScript, but shouldn't matter.
|
||||||
// See https://github.com/Microsoft/TypeScript/issues/15008
|
// See https://github.com/Microsoft/TypeScript/issues/15008
|
||||||
return this.match(tt.name);
|
return tokenIsIdentifier(this.state.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
tsTokenCanFollowModifier() {
|
tsTokenCanFollowModifier() {
|
||||||
@ -235,7 +241,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
allowedModifiers: T[],
|
allowedModifiers: T[],
|
||||||
stopOnStartOfClassStaticBlock?: boolean,
|
stopOnStartOfClassStaticBlock?: boolean,
|
||||||
): ?T {
|
): ?T {
|
||||||
if (!this.match(tt.name)) {
|
if (!tokenIsIdentifier(this.state.type)) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,7 +603,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsIsUnambiguouslyIndexSignature() {
|
tsIsUnambiguouslyIndexSignature() {
|
||||||
this.next(); // Skip '{'
|
this.next(); // Skip '{'
|
||||||
return this.eat(tt.name) && this.match(tt.colon);
|
if (tokenIsIdentifier(this.state.type)) {
|
||||||
|
this.next();
|
||||||
|
return this.match(tt.colon);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
tsTryParseIndexSignature(node: N.Node): ?N.TsIndexSignature {
|
tsTryParseIndexSignature(node: N.Node): ?N.TsIndexSignature {
|
||||||
@ -771,9 +781,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
tsIsStartOfMappedType(): boolean {
|
tsIsStartOfMappedType(): boolean {
|
||||||
this.next();
|
this.next();
|
||||||
if (this.eat(tt.plusMin)) {
|
if (this.eat(tt.plusMin)) {
|
||||||
return this.isContextual("readonly");
|
return this.isContextual(tt._readonly);
|
||||||
}
|
}
|
||||||
if (this.isContextual("readonly")) {
|
if (this.isContextual(tt._readonly)) {
|
||||||
this.next();
|
this.next();
|
||||||
}
|
}
|
||||||
if (!this.match(tt.bracketL)) {
|
if (!this.match(tt.bracketL)) {
|
||||||
@ -802,14 +812,14 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (this.match(tt.plusMin)) {
|
if (this.match(tt.plusMin)) {
|
||||||
node.readonly = this.state.value;
|
node.readonly = this.state.value;
|
||||||
this.next();
|
this.next();
|
||||||
this.expectContextual("readonly");
|
this.expectContextual(tt._readonly);
|
||||||
} else if (this.eatContextual("readonly")) {
|
} else if (this.eatContextual(tt._readonly)) {
|
||||||
node.readonly = true;
|
node.readonly = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.expect(tt.bracketL);
|
this.expect(tt.bracketL);
|
||||||
node.typeParameter = this.tsParseMappedTypeParameter();
|
node.typeParameter = this.tsParseMappedTypeParameter();
|
||||||
node.nameType = this.eatContextual("as") ? this.tsParseType() : null;
|
node.nameType = this.eatContextual(tt._as) ? this.tsParseType() : null;
|
||||||
|
|
||||||
this.expect(tt.bracketR);
|
this.expect(tt.bracketR);
|
||||||
|
|
||||||
@ -978,7 +988,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsParseThisTypeOrThisTypePredicate(): N.TsThisType | N.TsTypePredicate {
|
tsParseThisTypeOrThisTypePredicate(): N.TsThisType | N.TsTypePredicate {
|
||||||
const thisKeyword = this.tsParseThisTypeNode();
|
const thisKeyword = this.tsParseThisTypeNode();
|
||||||
if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
|
if (this.isContextual(tt._is) && !this.hasPrecedingLineBreak()) {
|
||||||
return this.tsParseThisTypePredicate(thisKeyword);
|
return this.tsParseThisTypePredicate(thisKeyword);
|
||||||
} else {
|
} else {
|
||||||
return thisKeyword;
|
return thisKeyword;
|
||||||
@ -987,24 +997,6 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsParseNonArrayType(): N.TsType {
|
tsParseNonArrayType(): N.TsType {
|
||||||
switch (this.state.type) {
|
switch (this.state.type) {
|
||||||
case tt.name:
|
|
||||||
case tt._void:
|
|
||||||
case tt._null: {
|
|
||||||
const type = this.match(tt._void)
|
|
||||||
? "TSVoidKeyword"
|
|
||||||
: this.match(tt._null)
|
|
||||||
? "TSNullKeyword"
|
|
||||||
: keywordTypeFromName(this.state.value);
|
|
||||||
if (
|
|
||||||
type !== undefined &&
|
|
||||||
this.lookaheadCharCode() !== charCodes.dot
|
|
||||||
) {
|
|
||||||
const node: N.TsKeywordType = this.startNode();
|
|
||||||
this.next();
|
|
||||||
return this.finishNode(node, type);
|
|
||||||
}
|
|
||||||
return this.tsParseTypeReference();
|
|
||||||
}
|
|
||||||
case tt.string:
|
case tt.string:
|
||||||
case tt.num:
|
case tt.num:
|
||||||
case tt.bigint:
|
case tt.bigint:
|
||||||
@ -1050,6 +1042,30 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
return this.tsParseParenthesizedType();
|
return this.tsParseParenthesizedType();
|
||||||
case tt.backQuote:
|
case tt.backQuote:
|
||||||
return this.tsParseTemplateLiteralType();
|
return this.tsParseTemplateLiteralType();
|
||||||
|
default: {
|
||||||
|
const { type } = this.state;
|
||||||
|
if (
|
||||||
|
tokenIsIdentifier(type) ||
|
||||||
|
type === tt._void ||
|
||||||
|
type === tt._null
|
||||||
|
) {
|
||||||
|
const nodeType =
|
||||||
|
type === tt._void
|
||||||
|
? "TSVoidKeyword"
|
||||||
|
: type === tt._null
|
||||||
|
? "TSNullKeyword"
|
||||||
|
: keywordTypeFromName(this.state.value);
|
||||||
|
if (
|
||||||
|
nodeType !== undefined &&
|
||||||
|
this.lookaheadCharCode() !== charCodes.dot
|
||||||
|
) {
|
||||||
|
const node: N.TsKeywordType = this.startNode();
|
||||||
|
this.next();
|
||||||
|
return this.finishNode(node, nodeType);
|
||||||
|
}
|
||||||
|
return this.tsParseTypeReference();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw this.unexpected();
|
throw this.unexpected();
|
||||||
@ -1074,11 +1090,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
tsParseTypeOperator(
|
tsParseTypeOperator(): N.TsTypeOperator {
|
||||||
operator: "keyof" | "unique" | "readonly",
|
|
||||||
): N.TsTypeOperator {
|
|
||||||
const node: N.TsTypeOperator = this.startNode();
|
const node: N.TsTypeOperator = this.startNode();
|
||||||
this.expectContextual(operator);
|
const operator = this.state.value;
|
||||||
|
this.next(); // eat operator
|
||||||
node.operator = operator;
|
node.operator = operator;
|
||||||
node.typeAnnotation = this.tsParseTypeOperatorOrHigher();
|
node.typeAnnotation = this.tsParseTypeOperatorOrHigher();
|
||||||
|
|
||||||
@ -1101,7 +1116,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsParseInferType(): N.TsInferType {
|
tsParseInferType(): N.TsInferType {
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.expectContextual("infer");
|
this.expectContextual(tt._infer);
|
||||||
const typeParameter = this.startNode();
|
const typeParameter = this.startNode();
|
||||||
typeParameter.name = this.tsParseTypeParameterName();
|
typeParameter.name = this.tsParseTypeParameterName();
|
||||||
node.typeParameter = this.finishNode(typeParameter, "TSTypeParameter");
|
node.typeParameter = this.finishNode(typeParameter, "TSTypeParameter");
|
||||||
@ -1109,12 +1124,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
tsParseTypeOperatorOrHigher(): N.TsType {
|
tsParseTypeOperatorOrHigher(): N.TsType {
|
||||||
const operator = ["keyof", "unique", "readonly"].find(kw =>
|
const isTypeOperator =
|
||||||
this.isContextual(kw),
|
tokenIsTSTypeOperator(this.state.type) && !this.state.containsEsc;
|
||||||
);
|
return isTypeOperator
|
||||||
return operator
|
? this.tsParseTypeOperator()
|
||||||
? this.tsParseTypeOperator(operator)
|
: this.isContextual(tt._infer)
|
||||||
: this.isContextual("infer")
|
|
||||||
? this.tsParseInferType()
|
? this.tsParseInferType()
|
||||||
: this.tsParseArrayTypeOrHigher();
|
: this.tsParseArrayTypeOrHigher();
|
||||||
}
|
}
|
||||||
@ -1164,7 +1178,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
tsSkipParameterStart(): boolean {
|
tsSkipParameterStart(): boolean {
|
||||||
if (this.match(tt.name) || this.match(tt._this)) {
|
if (tokenIsIdentifier(this.state.type) || this.match(tt._this)) {
|
||||||
this.next();
|
this.next();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1309,19 +1323,19 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsParseTypePredicatePrefix(): ?N.Identifier {
|
tsParseTypePredicatePrefix(): ?N.Identifier {
|
||||||
const id = this.parseIdentifier();
|
const id = this.parseIdentifier();
|
||||||
if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
|
if (this.isContextual(tt._is) && !this.hasPrecedingLineBreak()) {
|
||||||
this.next();
|
this.next();
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tsParseTypePredicateAsserts(): boolean {
|
tsParseTypePredicateAsserts(): boolean {
|
||||||
if (!this.match(tt.name) || this.state.value !== "asserts") {
|
if (this.state.type !== tt._asserts) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const containsEsc = this.state.containsEsc;
|
const containsEsc = this.state.containsEsc;
|
||||||
this.next();
|
this.next();
|
||||||
if (!this.match(tt.name) && !this.match(tt._this)) {
|
if (!tokenIsIdentifier(this.state.type) && !this.match(tt._this)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1366,7 +1380,9 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
isAbstractConstructorSignature(): boolean {
|
isAbstractConstructorSignature(): boolean {
|
||||||
return this.isContextual("abstract") && this.lookahead().type === tt._new;
|
return (
|
||||||
|
this.isContextual(tt._abstract) && this.lookahead().type === tt._new
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
tsParseNonConditionalType(): N.TsType {
|
tsParseNonConditionalType(): N.TsType {
|
||||||
@ -1427,7 +1443,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
tsParseInterfaceDeclaration(
|
tsParseInterfaceDeclaration(
|
||||||
node: N.TsInterfaceDeclaration,
|
node: N.TsInterfaceDeclaration,
|
||||||
): N.TsInterfaceDeclaration {
|
): N.TsInterfaceDeclaration {
|
||||||
if (this.match(tt.name)) {
|
if (tokenIsIdentifier(this.state.type)) {
|
||||||
node.id = this.parseIdentifier();
|
node.id = this.parseIdentifier();
|
||||||
this.checkLVal(
|
this.checkLVal(
|
||||||
node.id,
|
node.id,
|
||||||
@ -1460,7 +1476,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
this.expect(tt.eq);
|
this.expect(tt.eq);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.isContextual("intrinsic") &&
|
this.isContextual(tt._intrinsic) &&
|
||||||
this.lookahead().type !== tt.dot
|
this.lookahead().type !== tt.dot
|
||||||
) {
|
) {
|
||||||
const node: N.TsKeywordType = this.startNode();
|
const node: N.TsKeywordType = this.startNode();
|
||||||
@ -1599,7 +1615,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
tsParseAmbientExternalModuleDeclaration(
|
tsParseAmbientExternalModuleDeclaration(
|
||||||
node: N.TsModuleDeclaration,
|
node: N.TsModuleDeclaration,
|
||||||
): N.TsModuleDeclaration {
|
): N.TsModuleDeclaration {
|
||||||
if (this.isContextual("global")) {
|
if (this.isContextual(tt._global)) {
|
||||||
node.global = true;
|
node.global = true;
|
||||||
node.id = this.parseIdentifier();
|
node.id = this.parseIdentifier();
|
||||||
} else if (this.match(tt.string)) {
|
} else if (this.match(tt.string)) {
|
||||||
@ -1642,7 +1658,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsIsExternalModuleReference(): boolean {
|
tsIsExternalModuleReference(): boolean {
|
||||||
return (
|
return (
|
||||||
this.isContextual("require") &&
|
this.isContextual(tt._require) &&
|
||||||
this.lookaheadCharCode() === charCodes.leftParenthesis
|
this.lookaheadCharCode() === charCodes.leftParenthesis
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -1655,7 +1671,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsParseExternalModuleReference(): N.TsExternalModuleReference {
|
tsParseExternalModuleReference(): N.TsExternalModuleReference {
|
||||||
const node: N.TsExternalModuleReference = this.startNode();
|
const node: N.TsExternalModuleReference = this.startNode();
|
||||||
this.expectContextual("require");
|
this.expectContextual(tt._require);
|
||||||
this.expect(tt.parenL);
|
this.expect(tt.parenL);
|
||||||
if (!this.match(tt.string)) {
|
if (!this.match(tt.string)) {
|
||||||
throw this.unexpected();
|
throw this.unexpected();
|
||||||
@ -1701,7 +1717,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
let starttype = this.state.type;
|
let starttype = this.state.type;
|
||||||
let kind;
|
let kind;
|
||||||
|
|
||||||
if (this.isContextual("let")) {
|
if (this.isContextual(tt._let)) {
|
||||||
starttype = tt._var;
|
starttype = tt._var;
|
||||||
kind = "let";
|
kind = "let";
|
||||||
}
|
}
|
||||||
@ -1728,19 +1744,22 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (this.match(tt._const) && this.isLookaheadContextual("enum")) {
|
if (this.match(tt._const) && this.isLookaheadContextual("enum")) {
|
||||||
// `const enum = 0;` not allowed because "enum" is a strict mode reserved word.
|
// `const enum = 0;` not allowed because "enum" is a strict mode reserved word.
|
||||||
this.expect(tt._const);
|
this.expect(tt._const);
|
||||||
this.expectContextual("enum");
|
this.expectContextual(tt._enum);
|
||||||
return this.tsParseEnumDeclaration(nany, /* isConst */ true);
|
return this.tsParseEnumDeclaration(nany, /* isConst */ true);
|
||||||
}
|
}
|
||||||
// falls through
|
// falls through
|
||||||
case tt._var:
|
case tt._var:
|
||||||
kind = kind || this.state.value;
|
kind = kind || this.state.value;
|
||||||
return this.parseVarStatement(nany, kind);
|
return this.parseVarStatement(nany, kind);
|
||||||
case tt.name: {
|
case tt._global:
|
||||||
const value = this.state.value;
|
|
||||||
if (value === "global") {
|
|
||||||
return this.tsParseAmbientExternalModuleDeclaration(nany);
|
return this.tsParseAmbientExternalModuleDeclaration(nany);
|
||||||
} else {
|
default: {
|
||||||
return this.tsParseDeclaration(nany, value, /* next */ true);
|
if (tokenIsIdentifier(starttype)) {
|
||||||
|
return this.tsParseDeclaration(
|
||||||
|
nany,
|
||||||
|
this.state.value,
|
||||||
|
/* next */ true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1798,21 +1817,24 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
case "abstract":
|
case "abstract":
|
||||||
if (
|
if (
|
||||||
this.tsCheckLineTerminator(next) &&
|
this.tsCheckLineTerminator(next) &&
|
||||||
(this.match(tt._class) || this.match(tt.name))
|
(this.match(tt._class) || tokenIsIdentifier(this.state.type))
|
||||||
) {
|
) {
|
||||||
return this.tsParseAbstractDeclaration(node);
|
return this.tsParseAbstractDeclaration(node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "enum":
|
case "enum":
|
||||||
if (next || this.match(tt.name)) {
|
if (next || tokenIsIdentifier(this.state.type)) {
|
||||||
if (next) this.next();
|
if (next) this.next();
|
||||||
return this.tsParseEnumDeclaration(node, /* isConst */ false);
|
return this.tsParseEnumDeclaration(node, /* isConst */ false);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "interface":
|
case "interface":
|
||||||
if (this.tsCheckLineTerminator(next) && this.match(tt.name)) {
|
if (
|
||||||
|
this.tsCheckLineTerminator(next) &&
|
||||||
|
tokenIsIdentifier(this.state.type)
|
||||||
|
) {
|
||||||
return this.tsParseInterfaceDeclaration(node);
|
return this.tsParseInterfaceDeclaration(node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1821,20 +1843,26 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (this.tsCheckLineTerminator(next)) {
|
if (this.tsCheckLineTerminator(next)) {
|
||||||
if (this.match(tt.string)) {
|
if (this.match(tt.string)) {
|
||||||
return this.tsParseAmbientExternalModuleDeclaration(node);
|
return this.tsParseAmbientExternalModuleDeclaration(node);
|
||||||
} else if (this.match(tt.name)) {
|
} else if (tokenIsIdentifier(this.state.type)) {
|
||||||
return this.tsParseModuleOrNamespaceDeclaration(node);
|
return this.tsParseModuleOrNamespaceDeclaration(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "namespace":
|
case "namespace":
|
||||||
if (this.tsCheckLineTerminator(next) && this.match(tt.name)) {
|
if (
|
||||||
|
this.tsCheckLineTerminator(next) &&
|
||||||
|
tokenIsIdentifier(this.state.type)
|
||||||
|
) {
|
||||||
return this.tsParseModuleOrNamespaceDeclaration(node);
|
return this.tsParseModuleOrNamespaceDeclaration(node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "type":
|
case "type":
|
||||||
if (this.tsCheckLineTerminator(next) && this.match(tt.name)) {
|
if (
|
||||||
|
this.tsCheckLineTerminator(next) &&
|
||||||
|
tokenIsIdentifier(this.state.type)
|
||||||
|
) {
|
||||||
return this.tsParseTypeAliasDeclaration(node);
|
return this.tsParseTypeAliasDeclaration(node);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -1907,20 +1935,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
tsIsDeclarationStart(): boolean {
|
tsIsDeclarationStart(): boolean {
|
||||||
if (this.match(tt.name)) {
|
return tokenIsTSDeclarationStart(this.state.type);
|
||||||
switch (this.state.value) {
|
|
||||||
case "abstract":
|
|
||||||
case "declare":
|
|
||||||
case "enum":
|
|
||||||
case "interface":
|
|
||||||
case "module":
|
|
||||||
case "namespace":
|
|
||||||
case "type":
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ======================================================
|
// ======================================================
|
||||||
@ -2197,7 +2212,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (
|
if (
|
||||||
tokenOperatorPrecedence(tt._in) > minPrec &&
|
tokenOperatorPrecedence(tt._in) > minPrec &&
|
||||||
!this.hasPrecedingLineBreak() &&
|
!this.hasPrecedingLineBreak() &&
|
||||||
this.isContextual("as")
|
this.isContextual(tt._as)
|
||||||
) {
|
) {
|
||||||
const node: N.TsAsExpression = this.startNodeAt(
|
const node: N.TsAsExpression = this.startNodeAt(
|
||||||
leftStartPos,
|
leftStartPos,
|
||||||
@ -2244,15 +2259,19 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
parseImport(node: N.Node): N.AnyImport {
|
parseImport(node: N.Node): N.AnyImport {
|
||||||
node.importKind = "value";
|
node.importKind = "value";
|
||||||
if (this.match(tt.name) || this.match(tt.star) || this.match(tt.braceL)) {
|
if (
|
||||||
|
tokenIsIdentifier(this.state.type) ||
|
||||||
|
this.match(tt.star) ||
|
||||||
|
this.match(tt.braceL)
|
||||||
|
) {
|
||||||
let ahead = this.lookahead();
|
let ahead = this.lookahead();
|
||||||
|
|
||||||
if (
|
if (
|
||||||
this.isContextual("type") &&
|
this.isContextual(tt._type) &&
|
||||||
// import type, { a } from "b";
|
// import type, { a } from "b";
|
||||||
ahead.type !== tt.comma &&
|
ahead.type !== tt.comma &&
|
||||||
// import type from "a";
|
// import type from "a";
|
||||||
!(ahead.type === tt.name && ahead.value === "from") &&
|
ahead.type !== tt._from &&
|
||||||
// import type = require("a");
|
// import type = require("a");
|
||||||
ahead.type !== tt.eq
|
ahead.type !== tt.eq
|
||||||
) {
|
) {
|
||||||
@ -2261,7 +2280,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
ahead = this.lookahead();
|
ahead = this.lookahead();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.match(tt.name) && ahead.type === tt.eq) {
|
if (tokenIsIdentifier(this.state.type) && ahead.type === tt.eq) {
|
||||||
return this.tsParseImportEqualsDeclaration(node);
|
return this.tsParseImportEqualsDeclaration(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2290,7 +2309,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
// `export import A = B;`
|
// `export import A = B;`
|
||||||
this.next(); // eat `tt._import`
|
this.next(); // eat `tt._import`
|
||||||
if (
|
if (
|
||||||
this.isContextual("type") &&
|
this.isContextual(tt._type) &&
|
||||||
this.lookaheadCharCode() !== charCodes.equalsTo
|
this.lookaheadCharCode() !== charCodes.equalsTo
|
||||||
) {
|
) {
|
||||||
node.importKind = "type";
|
node.importKind = "type";
|
||||||
@ -2305,16 +2324,19 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
assign.expression = this.parseExpression();
|
assign.expression = this.parseExpression();
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(assign, "TSExportAssignment");
|
return this.finishNode(assign, "TSExportAssignment");
|
||||||
} else if (this.eatContextual("as")) {
|
} else if (this.eatContextual(tt._as)) {
|
||||||
// `export as namespace A;`
|
// `export as namespace A;`
|
||||||
const decl: N.TsNamespaceExportDeclaration = node;
|
const decl: N.TsNamespaceExportDeclaration = node;
|
||||||
// See `parseNamespaceExportDeclaration` in TypeScript's own parser
|
// See `parseNamespaceExportDeclaration` in TypeScript's own parser
|
||||||
this.expectContextual("namespace");
|
this.expectContextual(tt._namespace);
|
||||||
decl.id = this.parseIdentifier();
|
decl.id = this.parseIdentifier();
|
||||||
this.semicolon();
|
this.semicolon();
|
||||||
return this.finishNode(decl, "TSNamespaceExportDeclaration");
|
return this.finishNode(decl, "TSNamespaceExportDeclaration");
|
||||||
} else {
|
} else {
|
||||||
if (this.isContextual("type") && this.lookahead().type === tt.braceL) {
|
if (
|
||||||
|
this.isContextual(tt._type) &&
|
||||||
|
this.lookahead().type === tt.braceL
|
||||||
|
) {
|
||||||
this.next();
|
this.next();
|
||||||
node.exportKind = "type";
|
node.exportKind = "type";
|
||||||
} else {
|
} else {
|
||||||
@ -2327,7 +2349,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
isAbstractClass(): boolean {
|
isAbstractClass(): boolean {
|
||||||
return (
|
return (
|
||||||
this.isContextual("abstract") && this.lookahead().type === tt._class
|
this.isContextual(tt._abstract) && this.lookahead().type === tt._class
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2342,7 +2364,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
// export default interface allowed in:
|
// export default interface allowed in:
|
||||||
// https://github.com/Microsoft/TypeScript/pull/16040
|
// https://github.com/Microsoft/TypeScript/pull/16040
|
||||||
if (this.state.value === "interface") {
|
if (this.match(tt._interface)) {
|
||||||
const interfaceNode = this.startNode();
|
const interfaceNode = this.startNode();
|
||||||
this.next();
|
this.next();
|
||||||
const result = this.tsParseInterfaceDeclaration(interfaceNode);
|
const result = this.tsParseInterfaceDeclaration(interfaceNode);
|
||||||
@ -2355,10 +2377,10 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
parseStatementContent(context: ?string, topLevel: ?boolean): N.Statement {
|
parseStatementContent(context: ?string, topLevel: ?boolean): N.Statement {
|
||||||
if (this.state.type === tt._const) {
|
if (this.state.type === tt._const) {
|
||||||
const ahead = this.lookahead();
|
const ahead = this.lookahead();
|
||||||
if (ahead.type === tt.name && ahead.value === "enum") {
|
if (ahead.type === tt._enum) {
|
||||||
const node: N.TsEnumDeclaration = this.startNode();
|
const node: N.TsEnumDeclaration = this.startNode();
|
||||||
this.expect(tt._const);
|
this.next(); // eat 'const'
|
||||||
this.expectContextual("enum");
|
this.expectContextual(tt._enum);
|
||||||
return this.tsParseEnumDeclaration(node, /* isConst */ true);
|
return this.tsParseEnumDeclaration(node, /* isConst */ true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2380,7 +2402,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
tsIsStartOfStaticBlocks() {
|
tsIsStartOfStaticBlocks() {
|
||||||
return (
|
return (
|
||||||
this.isContextual("static") &&
|
this.isContextual(tt._static) &&
|
||||||
this.lookaheadCharCode() === charCodes.leftCurlyBrace
|
this.lookaheadCharCode() === charCodes.leftCurlyBrace
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -2584,11 +2606,11 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
const startLoc = this.state.startLoc;
|
const startLoc = this.state.startLoc;
|
||||||
|
|
||||||
// "export declare" is equivalent to just "export".
|
// "export declare" is equivalent to just "export".
|
||||||
const isDeclare = this.eatContextual("declare");
|
const isDeclare = this.eatContextual(tt._declare);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isDeclare &&
|
isDeclare &&
|
||||||
(this.isContextual("declare") || !this.shouldParseExportDeclaration())
|
(this.isContextual(tt._declare) || !this.shouldParseExportDeclaration())
|
||||||
) {
|
) {
|
||||||
throw this.raise(
|
throw this.raise(
|
||||||
this.state.start,
|
this.state.start,
|
||||||
@ -2598,7 +2620,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
|
|
||||||
let declaration: ?N.Declaration;
|
let declaration: ?N.Declaration;
|
||||||
|
|
||||||
if (this.match(tt.name)) {
|
if (tokenIsIdentifier(this.state.type)) {
|
||||||
declaration = this.tsTryParseExportDeclaration();
|
declaration = this.tsTryParseExportDeclaration();
|
||||||
}
|
}
|
||||||
if (!declaration) {
|
if (!declaration) {
|
||||||
@ -2628,7 +2650,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
isStatement: boolean,
|
isStatement: boolean,
|
||||||
optionalId: ?boolean,
|
optionalId: ?boolean,
|
||||||
): void {
|
): void {
|
||||||
if ((!isStatement || optionalId) && this.isContextual("implements")) {
|
if ((!isStatement || optionalId) && this.isContextual(tt._implements)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2738,7 +2760,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
if (node.superClass && this.isRelational("<")) {
|
if (node.superClass && this.isRelational("<")) {
|
||||||
node.superTypeParameters = this.tsParseTypeArguments();
|
node.superTypeParameters = this.tsParseTypeArguments();
|
||||||
}
|
}
|
||||||
if (this.eatContextual("implements")) {
|
if (this.eatContextual(tt._implements)) {
|
||||||
node.implements = this.tsParseHeritageClause("implements");
|
node.implements = this.tsParseHeritageClause("implements");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3225,7 +3247,7 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
/* isStatement */ true,
|
/* isStatement */ true,
|
||||||
/* optionalId */ false,
|
/* optionalId */ false,
|
||||||
);
|
);
|
||||||
} else if (this.isContextual("interface")) {
|
} else if (this.isContextual(tt._interface)) {
|
||||||
// for invalid abstract interface
|
// for invalid abstract interface
|
||||||
|
|
||||||
// To avoid
|
// To avoid
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type Parser from "../parser";
|
import type Parser from "../parser";
|
||||||
import { tt } from "../tokenizer/types";
|
import { tokenIsIdentifier, tt } from "../tokenizer/types";
|
||||||
import * as N from "../types";
|
import * as N from "../types";
|
||||||
|
|
||||||
export default (superClass: Class<Parser>): Class<Parser> =>
|
export default (superClass: Class<Parser>): Class<Parser> =>
|
||||||
@ -9,8 +9,8 @@ export default (superClass: Class<Parser>): Class<Parser> =>
|
|||||||
const v8IntrinsicStart = this.state.start;
|
const v8IntrinsicStart = this.state.start;
|
||||||
// let the `loc` of Identifier starts from `%`
|
// let the `loc` of Identifier starts from `%`
|
||||||
const node = this.startNode();
|
const node = this.startNode();
|
||||||
this.eat(tt.modulo);
|
this.next(); // eat '%'
|
||||||
if (this.match(tt.name)) {
|
if (tokenIsIdentifier(this.state.type)) {
|
||||||
const name = this.parseIdentifierName(this.state.start);
|
const name = this.parseIdentifierName(this.state.start);
|
||||||
const identifier = this.createIdentifier(node, name);
|
const identifier = this.createIdentifier(node, name);
|
||||||
identifier.type = "V8IntrinsicIdentifier";
|
identifier.type = "V8IntrinsicIdentifier";
|
||||||
|
|||||||
@ -180,8 +180,13 @@ export default class Tokenizer extends ParserErrors {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
/**
|
||||||
|
* Whether current token matches given type
|
||||||
|
*
|
||||||
|
* @param {TokenType} type
|
||||||
|
* @returns {boolean}
|
||||||
|
* @memberof Tokenizer
|
||||||
|
*/
|
||||||
match(type: TokenType): boolean {
|
match(type: TokenType): boolean {
|
||||||
return this.state.type === type;
|
return this.state.type === type;
|
||||||
}
|
}
|
||||||
@ -1565,8 +1570,14 @@ export default class Tokenizer extends ParserErrors {
|
|||||||
|
|
||||||
readWord(firstCode: number | void): void {
|
readWord(firstCode: number | void): void {
|
||||||
const word = this.readWord1(firstCode);
|
const word = this.readWord1(firstCode);
|
||||||
const type = keywordTypes.get(word) || tt.name;
|
const type = keywordTypes.get(word);
|
||||||
this.finishToken(type, word);
|
if (type !== undefined) {
|
||||||
|
// We don't use word as state.value here because word is a dynamic string
|
||||||
|
// while token label is a shared constant string
|
||||||
|
this.finishToken(type, tokenLabelName(type));
|
||||||
|
} else {
|
||||||
|
this.finishToken(tt.name, word);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
checkKeywordEscapes(): void {
|
checkKeywordEscapes(): void {
|
||||||
|
|||||||
@ -78,6 +78,7 @@ export class ExportedTokenType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A map from keyword/keyword-like string value to the token type
|
||||||
export const keywords = new Map<string, TokenType>();
|
export const keywords = new Map<string, TokenType>();
|
||||||
|
|
||||||
function createKeyword(name: string, options: TokenOptions = {}): TokenType {
|
function createKeyword(name: string, options: TokenOptions = {}): TokenType {
|
||||||
@ -111,19 +112,27 @@ function createToken(name: string, options: TokenOptions = {}): TokenType {
|
|||||||
return tokenTypeCounter;
|
return tokenTypeCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function createKeywordLike(
|
||||||
|
name: string,
|
||||||
|
options: TokenOptions = {},
|
||||||
|
): TokenType {
|
||||||
|
++tokenTypeCounter;
|
||||||
|
keywords.set(name, tokenTypeCounter);
|
||||||
|
tokenLabels.push(name);
|
||||||
|
tokenBinops.push(options.binop ?? -1);
|
||||||
|
tokenBeforeExprs.push(options.beforeExpr ?? false);
|
||||||
|
tokenStartsExprs.push(options.startsExpr ?? false);
|
||||||
|
tokenPrefixes.push(options.prefix ?? false);
|
||||||
|
// In the exported token type, we set the label as "name" for backward compatibility with Babel 7
|
||||||
|
tokenTypes.push(new ExportedTokenType("name", options));
|
||||||
|
|
||||||
|
return tokenTypeCounter;
|
||||||
|
}
|
||||||
|
|
||||||
// For performance the token type helpers depend on the following declarations order.
|
// For performance the token type helpers depend on the following declarations order.
|
||||||
// When adding new token types, please also check if the token helpers need update.
|
// When adding new token types, please also check if the token helpers need update.
|
||||||
|
|
||||||
export const tt: { [name: string]: TokenType } = {
|
export const tt: { [name: string]: TokenType } = {
|
||||||
num: createToken("num", { startsExpr }),
|
|
||||||
bigint: createToken("bigint", { startsExpr }),
|
|
||||||
decimal: createToken("decimal", { startsExpr }),
|
|
||||||
regexp: createToken("regexp", { startsExpr }),
|
|
||||||
string: createToken("string", { startsExpr }),
|
|
||||||
name: createToken("name", { startsExpr }),
|
|
||||||
privateName: createToken("#name", { startsExpr }),
|
|
||||||
eof: createToken("eof"),
|
|
||||||
|
|
||||||
// Punctuation token types.
|
// Punctuation token types.
|
||||||
bracketL: createToken("[", { beforeExpr, startsExpr }),
|
bracketL: createToken("[", { beforeExpr, startsExpr }),
|
||||||
bracketHashL: createToken("#[", { beforeExpr, startsExpr }),
|
bracketHashL: createToken("#[", { beforeExpr, startsExpr }),
|
||||||
@ -207,6 +216,7 @@ export const tt: { [name: string]: TokenType } = {
|
|||||||
// Keywords
|
// Keywords
|
||||||
// Don't forget to update packages/babel-helper-validator-identifier/src/keyword.js
|
// Don't forget to update packages/babel-helper-validator-identifier/src/keyword.js
|
||||||
// when new keywords are added
|
// when new keywords are added
|
||||||
|
// start: isLiteralPropertyName
|
||||||
// start: isKeyword
|
// start: isKeyword
|
||||||
_in: createKeyword("in", { beforeExpr, binop: 7 }),
|
_in: createKeyword("in", { beforeExpr, binop: 7 }),
|
||||||
_instanceof: createKeyword("instanceof", { beforeExpr, binop: 7 }),
|
_instanceof: createKeyword("instanceof", { beforeExpr, binop: 7 }),
|
||||||
@ -248,6 +258,63 @@ export const tt: { [name: string]: TokenType } = {
|
|||||||
// end: isLoop
|
// end: isLoop
|
||||||
// end: isKeyword
|
// end: isKeyword
|
||||||
|
|
||||||
|
// Primary literals
|
||||||
|
// start: isIdentifier
|
||||||
|
_as: createKeywordLike("as", { startsExpr }),
|
||||||
|
_assert: createKeywordLike("assert", { startsExpr }),
|
||||||
|
_async: createKeywordLike("async", { startsExpr }),
|
||||||
|
_await: createKeywordLike("await", { startsExpr }),
|
||||||
|
_from: createKeywordLike("from", { startsExpr }),
|
||||||
|
_get: createKeywordLike("get", { startsExpr }),
|
||||||
|
_let: createKeywordLike("let", { startsExpr }),
|
||||||
|
_meta: createKeywordLike("meta", { startsExpr }),
|
||||||
|
_of: createKeywordLike("of", { startsExpr }),
|
||||||
|
_sent: createKeywordLike("sent", { startsExpr }),
|
||||||
|
_set: createKeywordLike("set", { startsExpr }),
|
||||||
|
_static: createKeywordLike("static", { startsExpr }),
|
||||||
|
_yield: createKeywordLike("yield", { startsExpr }),
|
||||||
|
|
||||||
|
// Flow and TypeScript Keywordlike
|
||||||
|
_asserts: createKeywordLike("asserts", { startsExpr }),
|
||||||
|
_checks: createKeywordLike("checks", { startsExpr }),
|
||||||
|
_exports: createKeywordLike("exports", { startsExpr }),
|
||||||
|
_global: createKeywordLike("global", { startsExpr }),
|
||||||
|
_implements: createKeywordLike("implements", { startsExpr }),
|
||||||
|
_intrinsic: createKeywordLike("intrinsic", { startsExpr }),
|
||||||
|
_infer: createKeywordLike("infer", { startsExpr }),
|
||||||
|
_is: createKeywordLike("is", { startsExpr }),
|
||||||
|
_mixins: createKeywordLike("mixins", { startsExpr }),
|
||||||
|
_proto: createKeywordLike("proto", { startsExpr }),
|
||||||
|
_require: createKeywordLike("require", { startsExpr }),
|
||||||
|
// start: isTSTypeOperator
|
||||||
|
_keyof: createKeywordLike("keyof", { startsExpr }),
|
||||||
|
_readonly: createKeywordLike("readonly", { startsExpr }),
|
||||||
|
_unique: createKeywordLike("unique", { startsExpr }),
|
||||||
|
// end: isTSTypeOperator
|
||||||
|
// start: isTSDeclarationStart
|
||||||
|
_abstract: createKeywordLike("abstract", { startsExpr }),
|
||||||
|
_declare: createKeywordLike("declare", { startsExpr }),
|
||||||
|
_enum: createKeywordLike("enum", { startsExpr }),
|
||||||
|
_module: createKeywordLike("module", { startsExpr }),
|
||||||
|
_namespace: createKeywordLike("namespace", { startsExpr }),
|
||||||
|
// start: isFlowInterfaceOrTypeOrOpaque
|
||||||
|
_interface: createKeywordLike("interface", { startsExpr }),
|
||||||
|
_type: createKeywordLike("type", { startsExpr }),
|
||||||
|
// end: isTSDeclarationStart
|
||||||
|
_opaque: createKeywordLike("opaque", { startsExpr }),
|
||||||
|
// end: isFlowInterfaceOrTypeOrOpaque
|
||||||
|
name: createToken("name", { startsExpr }),
|
||||||
|
// end: isIdentifier
|
||||||
|
|
||||||
|
string: createToken("string", { startsExpr }),
|
||||||
|
num: createToken("num", { startsExpr }),
|
||||||
|
bigint: createToken("bigint", { startsExpr }),
|
||||||
|
decimal: createToken("decimal", { startsExpr }),
|
||||||
|
// end: isLiteralPropertyName
|
||||||
|
regexp: createToken("regexp", { startsExpr }),
|
||||||
|
privateName: createToken("#name", { startsExpr }),
|
||||||
|
eof: createToken("eof"),
|
||||||
|
|
||||||
// jsx plugin
|
// jsx plugin
|
||||||
jsxName: createToken("jsxName"),
|
jsxName: createToken("jsxName"),
|
||||||
jsxText: createToken("jsxText", { beforeExpr: true }),
|
jsxText: createToken("jsxText", { beforeExpr: true }),
|
||||||
@ -258,6 +325,18 @@ export const tt: { [name: string]: TokenType } = {
|
|||||||
placeholder: createToken("%%", { startsExpr: true }),
|
placeholder: createToken("%%", { startsExpr: true }),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export function tokenIsIdentifier(token: TokenType): boolean {
|
||||||
|
return token >= tt._as && token <= tt.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tokenIsKeywordOrIdentifier(token: TokenType): boolean {
|
||||||
|
return token >= tt._in && token <= tt.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tokenIsLiteralPropertyName(token: TokenType): boolean {
|
||||||
|
return token >= tt._in && token <= tt.decimal;
|
||||||
|
}
|
||||||
|
|
||||||
export function tokenComesBeforeExpression(token: TokenType): boolean {
|
export function tokenComesBeforeExpression(token: TokenType): boolean {
|
||||||
return tokenBeforeExprs[token];
|
return tokenBeforeExprs[token];
|
||||||
}
|
}
|
||||||
@ -270,6 +349,10 @@ export function tokenIsAssignment(token: TokenType): boolean {
|
|||||||
return token >= tt.eq && token <= tt.moduloAssign;
|
return token >= tt.eq && token <= tt.moduloAssign;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tokenIsFlowInterfaceOrTypeOrOpaque(token: TokenType): boolean {
|
||||||
|
return token >= tt._interface && token <= tt._opaque;
|
||||||
|
}
|
||||||
|
|
||||||
export function tokenIsLoop(token: TokenType): boolean {
|
export function tokenIsLoop(token: TokenType): boolean {
|
||||||
return token >= tt._do && token <= tt._while;
|
return token >= tt._do && token <= tt._while;
|
||||||
}
|
}
|
||||||
@ -290,6 +373,14 @@ export function tokenIsPrefix(token: TokenType): boolean {
|
|||||||
return tokenPrefixes[token];
|
return tokenPrefixes[token];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function tokenIsTSTypeOperator(token: TokenType): boolean {
|
||||||
|
return token >= tt._keyof && token <= tt._unique;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function tokenIsTSDeclarationStart(token: TokenType): boolean {
|
||||||
|
return token >= tt._abstract && token <= tt._type;
|
||||||
|
}
|
||||||
|
|
||||||
export function tokenLabelName(token: TokenType): string {
|
export function tokenLabelName(token: TokenType): string {
|
||||||
return tokenLabels[token];
|
return tokenLabels[token];
|
||||||
}
|
}
|
||||||
|
|||||||
1
packages/babel-parser/test/fixtures/flow/interface-types/escape-in-interface/input.js
vendored
Normal file
1
packages/babel-parser/test/fixtures/flow/interface-types/escape-in-interface/input.js
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
interf\u{61}ce A {}
|
||||||
38
packages/babel-parser/test/fixtures/flow/interface-types/escape-in-interface/output.json
vendored
Normal file
38
packages/babel-parser/test/fixtures/flow/interface-types/escape-in-interface/output.json
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}},
|
||||||
|
"errors": [
|
||||||
|
"SyntaxError: Unexpected reserved word 'interface'. (1:0)"
|
||||||
|
],
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "InterfaceDeclaration",
|
||||||
|
"start":0,"end":19,"loc":{"start":{"line":1,"column":0},"end":{"line":1,"column":19}},
|
||||||
|
"id": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":15,"end":16,"loc":{"start":{"line":1,"column":15},"end":{"line":1,"column":16},"identifierName":"A"},
|
||||||
|
"name": "A"
|
||||||
|
},
|
||||||
|
"typeParameters": null,
|
||||||
|
"extends": [],
|
||||||
|
"implements": [],
|
||||||
|
"mixins": [],
|
||||||
|
"body": {
|
||||||
|
"type": "ObjectTypeAnnotation",
|
||||||
|
"start":17,"end":19,"loc":{"start":{"line":1,"column":17},"end":{"line":1,"column":19}},
|
||||||
|
"callProperties": [],
|
||||||
|
"properties": [],
|
||||||
|
"indexers": [],
|
||||||
|
"internalSlots": [],
|
||||||
|
"exact": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
3
packages/babel-parser/test/fixtures/flow/object-types/getter-key-is-keyword/input.js
vendored
Normal file
3
packages/babel-parser/test/fixtures/flow/object-types/getter-key-is-keyword/input.js
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
type B = {
|
||||||
|
get if(): number;
|
||||||
|
}
|
||||||
60
packages/babel-parser/test/fixtures/flow/object-types/getter-key-is-keyword/output.json
vendored
Normal file
60
packages/babel-parser/test/fixtures/flow/object-types/getter-key-is-keyword/output.json
vendored
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
{
|
||||||
|
"type": "File",
|
||||||
|
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
|
||||||
|
"program": {
|
||||||
|
"type": "Program",
|
||||||
|
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
|
||||||
|
"sourceType": "module",
|
||||||
|
"interpreter": null,
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "TypeAlias",
|
||||||
|
"start":0,"end":32,"loc":{"start":{"line":1,"column":0},"end":{"line":3,"column":1}},
|
||||||
|
"id": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":5,"end":6,"loc":{"start":{"line":1,"column":5},"end":{"line":1,"column":6},"identifierName":"B"},
|
||||||
|
"name": "B"
|
||||||
|
},
|
||||||
|
"typeParameters": null,
|
||||||
|
"right": {
|
||||||
|
"type": "ObjectTypeAnnotation",
|
||||||
|
"start":9,"end":32,"loc":{"start":{"line":1,"column":9},"end":{"line":3,"column":1}},
|
||||||
|
"callProperties": [],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"type": "ObjectTypeProperty",
|
||||||
|
"start":13,"end":29,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":18}},
|
||||||
|
"key": {
|
||||||
|
"type": "Identifier",
|
||||||
|
"start":17,"end":19,"loc":{"start":{"line":2,"column":6},"end":{"line":2,"column":8},"identifierName":"if"},
|
||||||
|
"name": "if"
|
||||||
|
},
|
||||||
|
"static": false,
|
||||||
|
"proto": false,
|
||||||
|
"kind": "get",
|
||||||
|
"method": true,
|
||||||
|
"value": {
|
||||||
|
"type": "FunctionTypeAnnotation",
|
||||||
|
"start":13,"end":29,"loc":{"start":{"line":2,"column":2},"end":{"line":2,"column":18}},
|
||||||
|
"params": [],
|
||||||
|
"rest": null,
|
||||||
|
"typeParameters": null,
|
||||||
|
"this": null,
|
||||||
|
"returnType": {
|
||||||
|
"type": "NumberTypeAnnotation",
|
||||||
|
"start":23,"end":29,"loc":{"start":{"line":2,"column":12},"end":{"line":2,"column":18}}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"optional": false
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"indexers": [],
|
||||||
|
"internalSlots": [],
|
||||||
|
"exact": false,
|
||||||
|
"inexact": false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"directives": []
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user