Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

sucrase

Package Overview
Dependencies
Maintainers
1
Versions
82
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

sucrase - npm Package Compare versions

Comparing version 1.12.1 to 1.13.0

dist/sucrase-babylon/tokenizer/readWord.d.ts

2

dist/src/cli.js

@@ -61,4 +61,4 @@ "use strict";

const code = (await fs_1.readFile(srcPath)).toString();
const transformedCode = index_1.transform(code, { transforms });
const transformedCode = index_1.transform(code, { transforms, filePath: srcPath });
await fs_1.writeFile(outPath, transformedCode);
}

@@ -1,3 +0,3 @@

import { Token } from "../sucrase-babylon/tokenizer";
import { Scope } from "../sucrase-babylon/tokenizer/state";
import TokenProcessor from "./TokenProcessor";
/**

@@ -7,2 +7,2 @@ * Traverse the given tokens and modify them if necessary to indicate that some names shadow global

*/
export default function identifyShadowedGlobals(tokens: Array<Token>, scopes: Array<Scope>, globalNames: Set<string>): void;
export default function identifyShadowedGlobals(tokens: TokenProcessor, scopes: Array<Scope>, globalNames: Set<string>): void;

@@ -20,7 +20,7 @@ "use strict";

function hasShadowedGlobals(tokens, globalNames) {
for (const token of tokens) {
if (token.type.label === "name" &&
for (const token of tokens.tokens) {
if (token.type === 2048 /* name */ &&
(token.identifierRole === tokenizer_1.IdentifierRole.FunctionScopedDeclaration ||
token.identifierRole === tokenizer_1.IdentifierRole.BlockScopedDeclaration) &&
globalNames.has(token.value)) {
globalNames.has(tokens.identifierNameForToken(token))) {
return true;

@@ -36,3 +36,3 @@ }

// good stack by going backwards through them.
for (let i = tokens.length - 1;; i--) {
for (let i = tokens.tokens.length - 1;; i--) {
while (scopeStack.length > 0 && scopeStack[scopeStack.length - 1].startTokenIndex === i + 1) {

@@ -49,6 +49,7 @@ scopeStack.pop();

}
const token = tokens[i];
if (token.type.label === "name" && globalNames.has(token.value)) {
const token = tokens.tokens[i];
const name = tokens.identifierNameForToken(token);
if (scopeStack.length > 1 && token.type === 2048 /* name */ && globalNames.has(name)) {
if (token.identifierRole === tokenizer_1.IdentifierRole.BlockScopedDeclaration) {
markShadowedForScope(scopeStack[scopeStack.length - 1], tokens, token.value);
markShadowedForScope(scopeStack[scopeStack.length - 1], tokens, name);
}

@@ -63,3 +64,3 @@ else if (token.identifierRole === tokenizer_1.IdentifierRole.FunctionScopedDeclaration) {

}
markShadowedForScope(scopeStack[stackIndex], tokens, token.value);
markShadowedForScope(scopeStack[stackIndex], tokens, name);
}

@@ -74,4 +75,4 @@ }

for (let i = scope.startTokenIndex; i < scope.endTokenIndex; i++) {
const token = tokens[i];
if (token.type.label === "name" && token.value === name) {
const token = tokens.tokens[i];
if (token.type === 2048 /* name */ && tokens.identifierNameForToken(token) === name) {
token.shadowsGlobal = true;

@@ -78,0 +79,0 @@ }

@@ -54,8 +54,8 @@ "use strict";

for (let i = 0; i < this.tokens.tokens.length; i++) {
if (this.tokens.matchesAtIndex(i, ["import"]) &&
!this.tokens.matchesAtIndex(i, ["import", "name", "="])) {
if (this.tokens.matchesAtIndex(i, [43024 /* _import */]) &&
!this.tokens.matchesAtIndex(i, [43024 /* _import */, 2048 /* name */, 14368 /* eq */])) {
this.preprocessImportAtIndex(i);
}
if (this.tokens.matchesAtIndex(i, ["export"]) &&
!this.tokens.matchesAtIndex(i, ["export", "="])) {
if (this.tokens.matchesAtIndex(i, [42512 /* _export */]) &&
!this.tokens.matchesAtIndex(i, [42512 /* _export */, 14368 /* eq */])) {
this.preprocessExportAtIndex(i);

@@ -73,3 +73,3 @@ }

for (const token of this.tokens.tokens) {
if (token.type.label === "name" &&
if (token.type === 2048 /* name */ &&
!token.isType &&

@@ -79,3 +79,3 @@ (token.identifierRole === tokenizer_1.IdentifierRole.Access ||

token.identifierRole === tokenizer_1.IdentifierRole.ExportAccess)) {
nonTypeIdentifiers.add(token.value);
nonTypeIdentifiers.add(this.tokens.identifierNameForToken(token));
}

@@ -175,39 +175,37 @@ }

index++;
if (
// Ideally "type" would be a token type label, but for now, it's just an identifier.
(this.tokens.matchesNameAtIndex(index, "type") ||
this.tokens.matchesAtIndex(index, ["typeof"])) &&
!this.tokens.matchesAtIndex(index + 1, [","]) &&
!this.tokens.matchesNameAtIndex(index + 1, "from")) {
if ((this.tokens.matchesContextualAtIndex(index, 28 /* _type */) ||
this.tokens.matchesAtIndex(index, [46736 /* _typeof */])) &&
!this.tokens.matchesAtIndex(index + 1, [7168 /* comma */]) &&
!this.tokens.matchesContextualAtIndex(index + 1, 10 /* _from */)) {
// import type declaration, so no need to process anything.
return;
}
if (this.tokens.matchesAtIndex(index, ["("])) {
if (this.tokens.matchesAtIndex(index, [6144 /* parenL */])) {
// Dynamic import, so nothing to do
return;
}
if (this.tokens.matchesAtIndex(index, ["name"])) {
defaultNames.push(this.tokens.tokens[index].value);
if (this.tokens.matchesAtIndex(index, [2048 /* name */])) {
defaultNames.push(this.tokens.identifierNameAtIndex(index));
index++;
if (this.tokens.matchesAtIndex(index, [","])) {
if (this.tokens.matchesAtIndex(index, [7168 /* comma */])) {
index++;
}
}
if (this.tokens.matchesAtIndex(index, ["*"])) {
if (this.tokens.matchesAtIndex(index, [24587 /* star */])) {
// * as
index += 2;
wildcardNames.push(this.tokens.tokens[index].value);
wildcardNames.push(this.tokens.identifierNameAtIndex(index));
index++;
}
if (this.tokens.matchesAtIndex(index, ["{"])) {
if (this.tokens.matchesAtIndex(index, [4096 /* braceL */])) {
index++;
({ newIndex: index, namedImports } = this.getNamedImports(index));
}
if (this.tokens.matchesNameAtIndex(index, "from")) {
if (this.tokens.matchesContextualAtIndex(index, 10 /* _from */)) {
index++;
}
if (!this.tokens.matchesAtIndex(index, ["string"])) {
if (!this.tokens.matchesAtIndex(index, [1536 /* string */])) {
throw new Error("Expected string token at the end of import statement.");
}
const path = this.tokens.tokens[index].value;
const path = this.tokens.stringValueAtIndex(index);
const importInfo = this.getImportInfo(path);

@@ -222,18 +220,21 @@ importInfo.defaultNames.push(...defaultNames);

preprocessExportAtIndex(index) {
if (this.tokens.matchesAtIndex(index, ["export", "var"]) ||
this.tokens.matchesAtIndex(index, ["export", "let"]) ||
this.tokens.matchesAtIndex(index, ["export", "const"]) ||
this.tokens.matchesAtIndex(index, ["export", "function"]) ||
this.tokens.matchesAtIndex(index, ["export", "class"])) {
const exportName = this.tokens.tokens[index + 2].value;
if (this.tokens.matchesAtIndex(index, [42512 /* _export */, 37392 /* _var */]) ||
this.tokens.matchesAtIndex(index, [42512 /* _export */, 37904 /* _let */]) ||
this.tokens.matchesAtIndex(index, [42512 /* _export */, 38416 /* _const */])) {
const exportName = this.tokens.identifierNameAtIndex(index + 2);
this.identifierReplacements.set(exportName, `exports.${exportName}`);
}
else if (this.tokens.matchesAtIndex(index, [42512 /* _export */, 34320 /* _function */]) ||
this.tokens.matchesAtIndex(index, [42512 /* _export */, 41488 /* _class */])) {
const exportName = this.tokens.identifierNameAtIndex(index + 2);
this.exportBindingsByLocalName.set(exportName, exportName);
}
else if (this.tokens.matchesAtIndex(index, ["export", "name", "function"])) {
const exportName = this.tokens.tokens[index + 3].value;
else if (this.tokens.matchesAtIndex(index, [42512 /* _export */, 2048 /* name */, 34320 /* _function */])) {
const exportName = this.tokens.identifierNameAtIndex(index + 3);
this.exportBindingsByLocalName.set(exportName, exportName);
}
else if (this.tokens.matchesAtIndex(index, ["export", "{"])) {
else if (this.tokens.matchesAtIndex(index, [42512 /* _export */, 4096 /* braceL */])) {
this.preprocessNamedExportAtIndex(index);
}
else if (this.tokens.matchesAtIndex(index, ["export", "*"])) {
else if (this.tokens.matchesAtIndex(index, [42512 /* _export */, 24587 /* star */])) {
this.preprocessExportStarAtIndex(index);

@@ -252,3 +253,3 @@ }

index = newIndex;
if (this.tokens.matchesNameAtIndex(index, "from")) {
if (this.tokens.matchesContextualAtIndex(index, 10 /* _from */)) {
index++;

@@ -263,6 +264,6 @@ }

}
if (!this.tokens.matchesAtIndex(index, ["string"])) {
if (!this.tokens.matchesAtIndex(index, [1536 /* string */])) {
throw new Error("Expected string token at the end of import statement.");
}
const path = this.tokens.tokens[index].value;
const path = this.tokens.stringValueAtIndex(index);
const importInfo = this.getImportInfo(path);

@@ -273,6 +274,6 @@ importInfo.namedExports.push(...namedImports);

let exportedName = null;
if (this.tokens.matchesAtIndex(index, ["export", "*", "as"])) {
if (this.tokens.matchesAtIndex(index, [42512 /* _export */, 24587 /* star */, 53264 /* _as */])) {
// export * as
index += 3;
exportedName = this.tokens.tokens[index].value;
exportedName = this.tokens.identifierNameAtIndex(index);
// foo from

@@ -285,6 +286,6 @@ index += 2;

}
if (!this.tokens.matchesAtIndex(index, ["string"])) {
if (!this.tokens.matchesAtIndex(index, [1536 /* string */])) {
throw new Error("Expected string token at the end of star export statement.");
}
const path = this.tokens.tokens[index].value;
const path = this.tokens.stringValueAtIndex(index);
const importInfo = this.getImportInfo(path);

@@ -303,15 +304,15 @@ if (exportedName !== null) {

let isTypeImport = false;
if ((this.tokens.matchesAtIndex(index, ["type"]) ||
this.tokens.matchesAtIndex(index, ["typeof"])) &&
this.tokens.matchesAtIndex(index + 1, ["name"]) &&
!this.tokens.matchesNameAtIndex(index + 1, "as")) {
if ((this.tokens.matchesContextualAtIndex(index, 28 /* _type */) ||
this.tokens.matchesAtIndex(index, [46736 /* _typeof */])) &&
this.tokens.matchesAtIndex(index + 1, [2048 /* name */]) &&
!this.tokens.matchesContextualAtIndex(index + 1, 2 /* _as */)) {
isTypeImport = true;
index++;
}
const importedName = this.tokens.tokens[index].value;
const importedName = this.tokens.identifierNameAtIndex(index);
let localName;
index++;
if (this.tokens.matchesNameAtIndex(index, "as")) {
if (this.tokens.matchesContextualAtIndex(index, 2 /* _as */)) {
index++;
localName = this.tokens.tokens[index].value;
localName = this.tokens.identifierNameAtIndex(index);
index++;

@@ -325,15 +326,15 @@ }

}
if (this.tokens.matchesAtIndex(index, [",", "}"])) {
if (this.tokens.matchesAtIndex(index, [7168 /* comma */, 5120 /* braceR */])) {
index += 2;
break;
}
else if (this.tokens.matchesAtIndex(index, ["}"])) {
else if (this.tokens.matchesAtIndex(index, [5120 /* braceR */])) {
index++;
break;
}
else if (this.tokens.matchesAtIndex(index, [","])) {
else if (this.tokens.matchesAtIndex(index, [7168 /* comma */])) {
index++;
}
else {
throw new Error(`Unexpected token: ${JSON.stringify(this.tokens.currentToken())}`);
throw new Error(`Unexpected token: ${JSON.stringify(this.tokens.tokens[index])}`);
}

@@ -340,0 +341,0 @@ }

@@ -60,4 +60,4 @@ "use strict";

}
identifyShadowedGlobals_1.default(tokens, scopes, importProcessor.getGlobalNames());
identifyShadowedGlobals_1.default(tokenProcessor, scopes, importProcessor.getGlobalNames());
return { tokenProcessor, scopes, nameManager, importProcessor };
}

@@ -9,5 +9,5 @@ "use strict";

preprocessNames() {
for (const token of this.tokens.tokens) {
if (token.type.label === "name") {
this.usedNames.add(token.value);
for (let i = 0; i < this.tokens.tokens.length; i++) {
if (this.tokens.matchesAtIndex(i, [2048 /* name */])) {
this.usedNames.add(this.tokens.identifierNameAtIndex(i));
}

@@ -14,0 +14,0 @@ }

@@ -1,2 +0,2 @@

import { Token } from "../sucrase-babylon/tokenizer";
import { ContextualKeyword, Token } from "../sucrase-babylon/tokenizer";
import { TokenType } from "../sucrase-babylon/tokenizer/types";

@@ -21,4 +21,10 @@ export declare type TokenProcessorSnapshot = {

reset(): void;
matchesAtIndex(index: number, tagLabels: Array<string>): boolean;
matchesNameAtIndex(index: number, name: string): boolean;
matchesAtIndex(index: number, types: Array<TokenType>): boolean;
matchesContextualAtIndex(index: number, contextualKeyword: ContextualKeyword): boolean;
identifierNameAtIndex(index: number): string;
identifierName(): string;
identifierNameForToken(token: Token): string;
stringValueAtIndex(index: number): string;
stringValue(): string;
stringValueForToken(token: Token): string;
matches1(t1: TokenType): boolean;

@@ -29,3 +35,3 @@ matches2(t1: TokenType, t2: TokenType): boolean;

matches5(t1: TokenType, t2: TokenType, t3: TokenType, t4: TokenType, t5: TokenType): boolean;
matchesName(name: string): boolean;
matchesContextual(contextualKeyword: ContextualKeyword): boolean;
matchesContextIdAndLabel(type: TokenType, contextId: number): boolean;

@@ -37,3 +43,3 @@ previousWhitespace(): string;

removeToken(): void;
copyExpectedToken(label: string): void;
copyExpectedToken(tokenType: TokenType): void;
copyToken(): void;

@@ -40,0 +46,0 @@ appendCode(code: string): void;

@@ -30,11 +30,11 @@ "use strict";

}
matchesAtIndex(index, tagLabels) {
matchesAtIndex(index, types) {
if (index < 0) {
return false;
}
for (let i = 0; i < tagLabels.length; i++) {
for (let i = 0; i < types.length; i++) {
if (index + i >= this.tokens.length) {
return false;
}
if (this.tokens[index + i].type.label !== tagLabels[i]) {
if (this.tokens[index + i].type !== types[i]) {
return false;

@@ -45,5 +45,29 @@ }

}
matchesNameAtIndex(index, name) {
return this.matchesAtIndex(index, ["name"]) && this.tokens[index].value === name;
matchesContextualAtIndex(index, contextualKeyword) {
return (this.matchesAtIndex(index, [2048 /* name */]) &&
this.tokens[index].contextualKeyword === contextualKeyword);
}
identifierNameAtIndex(index) {
// TODO: We need to process escapes since technically you can have unicode escapes in variable
// names.
return this.identifierNameForToken(this.tokens[index]);
}
identifierName() {
return this.identifierNameForToken(this.currentToken());
}
identifierNameForToken(token) {
return this.code.slice(token.start, token.end);
}
stringValueAtIndex(index) {
return this.stringValueForToken(this.tokens[index]);
}
stringValue() {
return this.stringValueForToken(this.currentToken());
}
stringValueForToken(token) {
// This is used to identify when two imports are the same and to resolve TypeScript enum keys.
// Ideally we'd process escapes within the strings, but for now we pretty much take the raw
// code.
return this.code.slice(token.start + 1, token.end - 1);
}
matches1(t1) {

@@ -73,4 +97,4 @@ return this.tokens[this.tokenIndex].type === t1;

}
matchesName(name) {
return this.matchesNameAtIndex(this.tokenIndex, name);
matchesContextual(contextualKeyword) {
return this.matchesContextualAtIndex(this.tokenIndex, contextualKeyword);
}

@@ -99,5 +123,5 @@ matchesContextIdAndLabel(type, contextId) {

}
copyExpectedToken(label) {
if (this.tokens[this.tokenIndex].type.label !== label) {
throw new Error(`Expected token ${label}`);
copyExpectedToken(tokenType) {
if (this.tokens[this.tokenIndex].type !== tokenType) {
throw new Error(`Expected token ${tokenType}`);
}

@@ -104,0 +128,0 @@ this.copyToken();

@@ -44,3 +44,3 @@ import ImportProcessor from "../ImportProcessor";

* into this:
* const x = exports.x = 1;
* exports.x = 1;
*/

@@ -47,0 +47,0 @@ private processExportVar();

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tokenizer_1 = require("../../sucrase-babylon/tokenizer");
const types_1 = require("../../sucrase-babylon/tokenizer/types");
const Transformer_1 = require("./Transformer");

@@ -31,22 +30,22 @@ class ImportTransformer extends Transformer_1.default {

process() {
if (this.tokens.matches3(types_1.types._import, types_1.types.name, types_1.types.eq)) {
if (this.tokens.matches3(43024 /* _import */, 2048 /* name */, 14368 /* eq */)) {
this.tokens.replaceToken("const");
return true;
}
if (this.tokens.matches1(types_1.types._import)) {
if (this.tokens.matches1(43024 /* _import */)) {
this.processImport();
return true;
}
if (this.tokens.matches2(types_1.types._export, types_1.types.eq)) {
if (this.tokens.matches2(42512 /* _export */, 14368 /* eq */)) {
this.tokens.replaceToken("module.exports");
return true;
}
if (this.tokens.matches1(types_1.types._export) && !this.tokens.currentToken().isType) {
if (this.tokens.matches1(42512 /* _export */) && !this.tokens.currentToken().isType) {
this.hadExport = true;
return this.processExport();
}
if (this.tokens.matches1(types_1.types.name) || this.tokens.matches1(types_1.types.jsxName)) {
if (this.tokens.matches1(2048 /* name */) || this.tokens.matches1(26112 /* jsxName */)) {
return this.processIdentifier();
}
if (this.tokens.matches1(types_1.types.eq)) {
if (this.tokens.matches1(14368 /* eq */)) {
return this.processAssignment();

@@ -66,3 +65,3 @@ }

processImport() {
if (this.tokens.matches2(types_1.types._import, types_1.types.parenL)) {
if (this.tokens.matches2(43024 /* _import */, 6144 /* parenL */)) {
this.tokens.replaceToken("Promise.resolve().then(() => require");

@@ -74,3 +73,3 @@ const contextId = this.tokens.currentToken().contextId;

this.tokens.copyToken();
while (!this.tokens.matchesContextIdAndLabel(types_1.types.parenR, contextId)) {
while (!this.tokens.matchesContextIdAndLabel(6656 /* parenR */, contextId)) {
this.rootTransformer.processToken();

@@ -86,7 +85,7 @@ }

else {
const path = this.tokens.currentToken().value;
const path = this.tokens.stringValue();
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path));
this.tokens.appendCode(this.importProcessor.claimImportCode(path));
}
if (this.tokens.matches1(types_1.types.semi)) {
if (this.tokens.matches1(7680 /* semi */)) {
this.tokens.removeToken();

@@ -103,5 +102,5 @@ }

this.tokens.removeInitialToken();
if (this.tokens.matchesName("type") &&
!this.tokens.matchesAtIndex(this.tokens.currentIndex() + 1, [","]) &&
!this.tokens.matchesNameAtIndex(this.tokens.currentIndex() + 1, "from")) {
if (this.tokens.matchesContextual(28 /* _type */) &&
!this.tokens.matchesAtIndex(this.tokens.currentIndex() + 1, [7168 /* comma */]) &&
!this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, 10 /* _from */)) {
// This is an "import type" statement, so exit early.

@@ -111,3 +110,3 @@ this.removeRemainingImport();

}
if (this.tokens.matches1(types_1.types.name) || this.tokens.matches1(types_1.types.star)) {
if (this.tokens.matches1(2048 /* name */) || this.tokens.matches1(24587 /* star */)) {
// We have a default import or namespace import, so there must be some

@@ -118,3 +117,3 @@ // non-type import.

}
if (this.tokens.matches1(types_1.types.string)) {
if (this.tokens.matches1(1536 /* string */)) {
// This is a bare import, so we should proceed with the import.

@@ -124,11 +123,11 @@ return false;

let foundNonType = false;
while (!this.tokens.matches1(types_1.types.string)) {
while (!this.tokens.matches1(1536 /* string */)) {
// Check if any named imports are of the form "foo" or "foo as bar", with
// no leading "type".
if ((!foundNonType && this.tokens.matches1(types_1.types.braceL)) || this.tokens.matches1(types_1.types.comma)) {
if ((!foundNonType && this.tokens.matches1(4096 /* braceL */)) || this.tokens.matches1(7168 /* comma */)) {
this.tokens.removeToken();
if (this.tokens.matches2(types_1.types.name, types_1.types.comma) ||
this.tokens.matches2(types_1.types.name, types_1.types.braceR) ||
this.tokens.matches4(types_1.types.name, types_1.types.name, types_1.types.name, types_1.types.comma) ||
this.tokens.matches4(types_1.types.name, types_1.types.name, types_1.types.name, types_1.types.braceR)) {
if (this.tokens.matches2(2048 /* name */, 7168 /* comma */) ||
this.tokens.matches2(2048 /* name */, 5120 /* braceR */) ||
this.tokens.matches4(2048 /* name */, 2048 /* name */, 2048 /* name */, 7168 /* comma */) ||
this.tokens.matches4(2048 /* name */, 2048 /* name */, 2048 /* name */, 5120 /* braceR */)) {
foundNonType = true;

@@ -142,3 +141,3 @@ }

removeRemainingImport() {
while (!this.tokens.matches1(types_1.types.string)) {
while (!this.tokens.matches1(1536 /* string */)) {
this.tokens.removeToken();

@@ -158,13 +157,26 @@ }

}
const replacement = this.importProcessor.getIdentifierReplacement(token.value);
const replacement = this.importProcessor.getIdentifierReplacement(this.tokens.identifierNameForToken(token));
if (!replacement) {
return false;
}
// For now, always use the (0, a) syntax so that non-expression replacements
// are more likely to become syntax errors.
this.tokens.replaceToken(`(0, ${replacement})`);
// We need to change to (0, f) if this is a function call, so that it won't be interpreted as a
// method access. This can also happen in situations like (f)(), so a following close-paren
// should trigger this behavior as well if it eventually has an open-paren. In some cases, like
// export assignees, we must NOT turn the identifier into a normal expression, so we need to
// just to the regular replacement.
let possibleOpenParenIndex = this.tokens.currentIndex() + 1;
while (possibleOpenParenIndex < this.tokens.tokens.length &&
this.tokens.tokens[possibleOpenParenIndex].type === 6656 /* parenR */) {
possibleOpenParenIndex++;
}
if (this.tokens.tokens[possibleOpenParenIndex].type === 6144 /* parenL */) {
this.tokens.replaceToken(`(0, ${replacement})`);
}
else {
this.tokens.replaceToken(replacement);
}
return true;
}
processObjectShorthand() {
const identifier = this.tokens.currentToken().value;
const identifier = this.tokens.identifierName();
const replacement = this.importProcessor.getIdentifierReplacement(identifier);

@@ -178,8 +190,8 @@ if (!replacement) {

processExport() {
if (this.tokens.matches2(types_1.types._export, types_1.types._enum) ||
this.tokens.matches3(types_1.types._export, types_1.types._const, types_1.types._enum)) {
if (this.tokens.matches2(42512 /* _export */, 53776 /* _enum */) ||
this.tokens.matches3(42512 /* _export */, 38416 /* _const */, 53776 /* _enum */)) {
// Let the TypeScript transform handle it.
return false;
}
if (this.tokens.matches2(types_1.types._export, types_1.types._default)) {
if (this.tokens.matches2(42512 /* _export */, 31760 /* _default */)) {
this.processExportDefault();

@@ -190,23 +202,23 @@ this.hadDefaultExport = true;

this.hadNamedExport = true;
if (this.tokens.matches2(types_1.types._export, types_1.types._var) ||
this.tokens.matches2(types_1.types._export, types_1.types._let) ||
this.tokens.matches2(types_1.types._export, types_1.types._const)) {
if (this.tokens.matches2(42512 /* _export */, 37392 /* _var */) ||
this.tokens.matches2(42512 /* _export */, 37904 /* _let */) ||
this.tokens.matches2(42512 /* _export */, 38416 /* _const */)) {
this.processExportVar();
return true;
}
else if (this.tokens.matches2(types_1.types._export, types_1.types._function) ||
this.tokens.matches3(types_1.types._export, types_1.types.name, types_1.types._function)) {
else if (this.tokens.matches2(42512 /* _export */, 34320 /* _function */) ||
this.tokens.matches3(42512 /* _export */, 2048 /* name */, 34320 /* _function */)) {
this.processExportFunction();
return true;
}
else if (this.tokens.matches2(types_1.types._export, types_1.types._class) ||
this.tokens.matches3(types_1.types._export, types_1.types._abstract, types_1.types._class)) {
else if (this.tokens.matches2(42512 /* _export */, 41488 /* _class */) ||
this.tokens.matches3(42512 /* _export */, 50704 /* _abstract */, 41488 /* _class */)) {
this.processExportClass();
return true;
}
else if (this.tokens.matches2(types_1.types._export, types_1.types.braceL)) {
else if (this.tokens.matches2(42512 /* _export */, 4096 /* braceL */)) {
this.processExportBindings();
return true;
}
else if (this.tokens.matches2(types_1.types._export, types_1.types.star)) {
else if (this.tokens.matches2(42512 /* _export */, 24587 /* star */)) {
this.processExportStar();

@@ -222,10 +234,10 @@ return true;

const identifierToken = this.tokens.tokens[index - 1];
if (identifierToken.type.label !== "name") {
if (identifierToken.type !== 2048 /* name */) {
return false;
}
if (this.tokens.matchesAtIndex(index - 2, ["."])) {
if (this.tokens.matchesAtIndex(index - 2, [9216 /* dot */])) {
return false;
}
if (index - 2 >= 0 &&
["var", "let", "const"].includes(this.tokens.tokens[index - 2].type.label)) {
[37392 /* _var */, 37904 /* _let */, 38416 /* _const */].includes(this.tokens.tokens[index - 2].type)) {
// Declarations don't need an extra assignment. This doesn't avoid the

@@ -236,3 +248,3 @@ // assignment for comma-separated declarations, but it's still correct

}
const exportedName = this.importProcessor.resolveExportBinding(identifierToken.value);
const exportedName = this.importProcessor.resolveExportBinding(this.tokens.identifierNameForToken(identifierToken));
if (!exportedName) {

@@ -246,5 +258,5 @@ return false;

processExportDefault() {
if (this.tokens.matches4(types_1.types._export, types_1.types._default, types_1.types._function, types_1.types.name) ||
if (this.tokens.matches4(42512 /* _export */, 31760 /* _default */, 34320 /* _function */, 2048 /* name */) ||
// export default aysnc function
this.tokens.matches5(types_1.types._export, types_1.types._default, types_1.types.name, types_1.types._function, types_1.types.name)) {
this.tokens.matches5(42512 /* _export */, 31760 /* _default */, 2048 /* name */, 34320 /* _function */, 2048 /* name */)) {
this.tokens.removeInitialToken();

@@ -257,7 +269,7 @@ this.tokens.removeToken();

}
else if (this.tokens.matches4(types_1.types._export, types_1.types._default, types_1.types._class, types_1.types.name) ||
this.tokens.matches5(types_1.types._export, types_1.types._default, types_1.types._abstract, types_1.types._class, types_1.types.name)) {
else if (this.tokens.matches4(42512 /* _export */, 31760 /* _default */, 41488 /* _class */, 2048 /* name */) ||
this.tokens.matches5(42512 /* _export */, 31760 /* _default */, 50704 /* _abstract */, 41488 /* _class */, 2048 /* name */)) {
this.tokens.removeInitialToken();
this.tokens.removeToken();
if (this.tokens.matches1(types_1.types._abstract)) {
if (this.tokens.matches1(50704 /* _abstract */)) {
this.tokens.removeToken();

@@ -278,13 +290,16 @@ }

* into this:
* const x = exports.x = 1;
* exports.x = 1;
*/
processExportVar() {
this.tokens.replaceToken("");
this.tokens.copyToken();
if (!this.tokens.matches1(types_1.types.name)) {
this.tokens.removeInitialToken();
this.tokens.removeToken();
if (!this.tokens.matches1(2048 /* name */)) {
throw new Error("Expected a regular identifier after export var/let/const.");
}
const name = this.tokens.currentToken().value;
this.tokens.copyToken();
this.tokens.appendCode(` = exports.${name}`);
const name = this.tokens.identifierName();
const replacement = this.importProcessor.getIdentifierReplacement(name);
if (replacement === null) {
throw new Error("Expected a replacement for `export var` syntax..");
}
this.tokens.replaceToken(replacement);
}

@@ -306,7 +321,7 @@ /**

processNamedFunction() {
if (this.tokens.matches1(types_1.types._function)) {
if (this.tokens.matches1(34320 /* _function */)) {
this.tokens.copyToken();
}
else if (this.tokens.matches2(types_1.types.name, types_1.types._function)) {
if (this.tokens.currentToken().value !== "async") {
else if (this.tokens.matches2(2048 /* name */, 34320 /* _function */)) {
if (!this.tokens.matchesContextual(3 /* _async */)) {
throw new Error("Expected async keyword in function export.");

@@ -317,6 +332,6 @@ }

}
if (!this.tokens.matches1(types_1.types.name)) {
if (!this.tokens.matches1(2048 /* name */)) {
throw new Error("Expected identifier for exported function name.");
}
const name = this.tokens.currentToken().value;
const name = this.tokens.identifierName();
this.tokens.copyToken();

@@ -329,9 +344,9 @@ if (this.tokens.currentToken().isType) {

}
this.tokens.copyExpectedToken("(");
this.tokens.copyExpectedToken(6144 /* parenL */);
this.rootTransformer.processBalancedCode();
this.tokens.copyExpectedToken(")");
this.tokens.copyExpectedToken(6656 /* parenR */);
this.rootTransformer.processPossibleTypeRange();
this.tokens.copyExpectedToken("{");
this.tokens.copyExpectedToken(4096 /* braceL */);
this.rootTransformer.processBalancedCode();
this.tokens.copyExpectedToken("}");
this.tokens.copyExpectedToken(5120 /* braceR */);
return name;

@@ -347,3 +362,3 @@ }

this.tokens.removeInitialToken();
if (this.tokens.matches1(types_1.types._abstract)) {
if (this.tokens.matches1(50704 /* _abstract */)) {
this.tokens.removeToken();

@@ -371,8 +386,8 @@ }

while (true) {
const localName = this.tokens.currentToken().value;
const localName = this.tokens.identifierName();
let exportedName;
this.tokens.removeToken();
if (this.tokens.matchesName("as")) {
if (this.tokens.matchesContextual(2 /* _as */)) {
this.tokens.removeToken();
exportedName = this.tokens.currentToken().value;
exportedName = this.tokens.identifierName();
this.tokens.removeToken();

@@ -385,7 +400,7 @@ }

exportStatements.push(`exports.${exportedName} = ${newLocalName || localName};`);
if (this.tokens.matches1(types_1.types.braceR)) {
if (this.tokens.matches1(5120 /* braceR */)) {
this.tokens.removeToken();
break;
}
if (this.tokens.matches2(types_1.types.comma, types_1.types.braceR)) {
if (this.tokens.matches2(7168 /* comma */, 5120 /* braceR */)) {
this.tokens.removeToken();

@@ -395,3 +410,3 @@ this.tokens.removeToken();

}
else if (this.tokens.matches1(types_1.types.comma)) {
else if (this.tokens.matches1(7168 /* comma */)) {
this.tokens.removeToken();

@@ -403,7 +418,7 @@ }

}
if (this.tokens.matchesName("from")) {
if (this.tokens.matchesContextual(10 /* _from */)) {
// This is an export...from, so throw away the normal named export code
// and use the Object.defineProperty code from ImportProcessor.
this.tokens.removeToken();
const path = this.tokens.currentToken().value;
const path = this.tokens.stringValue();
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path));

@@ -415,3 +430,3 @@ }

}
if (this.tokens.matches1(types_1.types.semi)) {
if (this.tokens.matches1(7680 /* semi */)) {
this.tokens.removeToken();

@@ -422,8 +437,8 @@ }

this.tokens.removeInitialToken();
while (!this.tokens.matches1(types_1.types.string)) {
while (!this.tokens.matches1(1536 /* string */)) {
this.tokens.removeToken();
}
const path = this.tokens.currentToken().value;
const path = this.tokens.stringValue();
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path));
if (this.tokens.matches1(types_1.types.semi)) {
if (this.tokens.matches1(7680 /* semi */)) {
this.tokens.removeToken();

@@ -430,0 +445,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../../sucrase-babylon/tokenizer/types");
const xhtml_1 = require("../../sucrase-babylon/plugins/jsx/xhtml");
const Transformer_1 = require("./Transformer");
const HEX_NUMBER = /^[\da-fA-F]+$/;
const DECIMAL_NUMBER = /^\d+$/;
class JSXTransformer extends Transformer_1.default {

@@ -18,3 +20,3 @@ constructor(rootTransformer, tokens, importProcessor, nameManager, filePath) {

process() {
if (this.tokens.matches1(types_1.types.jsxTagStart)) {
if (this.tokens.matches1(27136 /* jsxTagStart */)) {
this.processJSXTag();

@@ -56,3 +58,3 @@ return true;

const devProps = `__self: this, __source: {fileName: ${this.getFilenameVarName()}, lineNumber: ${lineNumber}}`;
if (!this.tokens.matches1(types_1.types.jsxName) && !this.tokens.matches1(types_1.types.braceL)) {
if (!this.tokens.matches1(26112 /* jsxName */) && !this.tokens.matches1(4096 /* braceL */)) {
this.tokens.appendCode(`, {${devProps}}`);

@@ -63,5 +65,6 @@ return;

while (true) {
if (this.tokens.matches2(types_1.types.jsxName, types_1.types.eq)) {
if (this.tokens.currentToken().value.includes("-")) {
this.tokens.replaceToken(`'${this.tokens.currentToken().value}'`);
if (this.tokens.matches2(26112 /* jsxName */, 14368 /* eq */)) {
const keyName = this.tokens.identifierName();
if (keyName.includes("-")) {
this.tokens.replaceToken(`'${keyName}'`);
}

@@ -72,3 +75,3 @@ else {

this.tokens.replaceToken(": ");
if (this.tokens.matches1(types_1.types.braceL)) {
if (this.tokens.matches1(4096 /* braceL */)) {
this.tokens.replaceToken("");

@@ -82,7 +85,7 @@ this.rootTransformer.processBalancedCode();

}
else if (this.tokens.matches1(types_1.types.jsxName)) {
else if (this.tokens.matches1(26112 /* jsxName */)) {
this.tokens.copyToken();
this.tokens.appendCode(": true");
}
else if (this.tokens.matches1(types_1.types.braceL)) {
else if (this.tokens.matches1(4096 /* braceL */)) {
this.tokens.replaceToken("");

@@ -100,5 +103,6 @@ this.rootTransformer.processBalancedCode();

processStringPropValue() {
const value = this.tokens.currentToken().value;
const replacementCode = formatJSXTextReplacement(value);
const literalCode = formatJSXStringValueLiteral(value);
const token = this.tokens.currentToken();
const valueCode = this.tokens.code.slice(token.start + 1, token.end - 1);
const replacementCode = formatJSXTextReplacement(valueCode);
const literalCode = formatJSXStringValueLiteral(valueCode);
this.tokens.replaceToken(literalCode + replacementCode);

@@ -116,11 +120,13 @@ }

let introEnd = this.tokens.currentIndex() + 1;
while (!this.tokens.matchesAtIndex(introEnd - 1, ["jsxName", "jsxName"]) &&
!this.tokens.matchesAtIndex(introEnd, ["{"]) &&
!this.tokens.matchesAtIndex(introEnd, ["jsxTagEnd"]) &&
!this.tokens.matchesAtIndex(introEnd, ["/", "jsxTagEnd"])) {
while (!this.tokens.matchesAtIndex(introEnd - 1, [26112 /* jsxName */, 26112 /* jsxName */]) &&
!this.tokens.matchesAtIndex(introEnd, [4096 /* braceL */]) &&
!this.tokens.matchesAtIndex(introEnd, [27648 /* jsxTagEnd */]) &&
!this.tokens.matchesAtIndex(introEnd, [25099 /* slash */, 27648 /* jsxTagEnd */])) {
introEnd++;
}
if (introEnd === this.tokens.currentIndex() + 1 &&
startsWithLowerCase(this.tokens.currentToken().value)) {
this.tokens.replaceToken(`'${this.tokens.currentToken().value}'`);
if (introEnd === this.tokens.currentIndex() + 1) {
const tagName = this.tokens.identifierName();
if (startsWithLowerCase(tagName)) {
this.tokens.replaceToken(`'${tagName}'`);
}
}

@@ -133,8 +139,8 @@ while (this.tokens.currentIndex() < introEnd) {

while (true) {
if (this.tokens.matches2(types_1.types.jsxTagStart, types_1.types.slash)) {
if (this.tokens.matches2(27136 /* jsxTagStart */, 25099 /* slash */)) {
// Closing tag, so no more children.
return;
}
if (this.tokens.matches1(types_1.types.braceL)) {
if (this.tokens.matches2(types_1.types.braceL, types_1.types.braceR)) {
if (this.tokens.matches1(4096 /* braceL */)) {
if (this.tokens.matches2(4096 /* braceL */, 5120 /* braceR */)) {
// Empty interpolations and comment-only interpolations are allowed

@@ -152,3 +158,3 @@ // and don't create an extra child arg.

}
else if (this.tokens.matches1(types_1.types.jsxTagStart)) {
else if (this.tokens.matches1(27136 /* jsxTagStart */)) {
// Child JSX element

@@ -158,3 +164,3 @@ this.tokens.appendCode(", ");

}
else if (this.tokens.matches1(types_1.types.jsxText)) {
else if (this.tokens.matches1(26624 /* jsxText */)) {
this.processChildTextElement();

@@ -168,5 +174,6 @@ }

processChildTextElement() {
const value = this.tokens.currentToken().value;
const replacementCode = formatJSXTextReplacement(value);
const literalCode = formatJSXTextLiteral(value);
const token = this.tokens.currentToken();
const valueCode = this.tokens.code.slice(token.start, token.end);
const replacementCode = formatJSXTextReplacement(valueCode);
const literalCode = formatJSXTextLiteral(valueCode);
if (literalCode === '""') {

@@ -186,3 +193,3 @@ this.tokens.replaceToken(replacementCode);

this.processProps(firstTokenStart);
if (this.tokens.matches2(types_1.types.slash, types_1.types.jsxTagEnd)) {
if (this.tokens.matches2(25099 /* slash */, 27648 /* jsxTagEnd */)) {
// Self-closing tag.

@@ -192,7 +199,7 @@ this.tokens.replaceToken("");

}
else if (this.tokens.matches1(types_1.types.jsxTagEnd)) {
else if (this.tokens.matches1(27648 /* jsxTagEnd */)) {
this.tokens.replaceToken("");
// Tag with children.
this.processChildren();
while (!this.tokens.matches1(types_1.types.jsxTagEnd)) {
while (!this.tokens.matches1(27648 /* jsxTagEnd */)) {
this.tokens.replaceToken("");

@@ -225,4 +232,5 @@ }

let seenNonWhitespace = false;
for (const c of text) {
if (c === " " || c === "\t") {
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (c === " " || c === "\t" || c === "\r") {
if (!isInInitialLineWhitespace) {

@@ -242,3 +250,10 @@ whitespace += c;

whitespace = "";
result += c;
if (c === "&") {
const { entity, newI } = processEntity(text, i + 1);
i = newI - 1;
result += entity;
}
else {
result += c;
}
seenNonWhitespace = true;

@@ -279,3 +294,64 @@ isInInitialLineWhitespace = false;

function formatJSXStringValueLiteral(text) {
return JSON.stringify(text.replace(/\n\s+/g, " "));
let result = "";
for (let i = 0; i < text.length; i++) {
const c = text[i];
if (c === "\n") {
if (/\s/.test(text[i + 1])) {
result += " ";
while (i < text.length && /\s/.test(text[i + 1])) {
i++;
}
}
else {
result += "\n";
}
}
else if (c === "&") {
const { entity, newI } = processEntity(text, i + 1);
result += entity;
i = newI - 1;
}
else {
result += c;
}
}
return JSON.stringify(result);
}
/**
* Modified from jsxReadString in Babylon.
*/
function processEntity(text, indexAfterAmpersand) {
let str = "";
let count = 0;
let entity;
let i = indexAfterAmpersand;
while (i < text.length && count++ < 10) {
const ch = text[i];
i++;
if (ch === ";") {
if (str[0] === "#") {
if (str[1] === "x") {
str = str.substr(2);
if (HEX_NUMBER.test(str)) {
entity = String.fromCodePoint(parseInt(str, 16));
}
}
else {
str = str.substr(1);
if (DECIMAL_NUMBER.test(str)) {
entity = String.fromCodePoint(parseInt(str, 10));
}
}
}
else {
entity = xhtml_1.default[str];
}
break;
}
str += ch;
}
if (!entity) {
return { entity: "&", newI: indexAfterAmpersand };
}
return { entity, newI: i };
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../../sucrase-babylon/tokenizer/types");
const Transformer_1 = require("./Transformer");

@@ -11,3 +10,3 @@ class NumericSeparatorTransformer extends Transformer_1.default {

process() {
if (this.tokens.matches1(types_1.types.num)) {
if (this.tokens.matches1(0 /* num */)) {
const code = this.tokens.currentTokenCode();

@@ -14,0 +13,0 @@ if (code.includes("_")) {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../../sucrase-babylon/tokenizer/types");
const Transformer_1 = require("./Transformer");

@@ -12,3 +11,3 @@ class OptionalCatchBindingTransformer extends Transformer_1.default {

process() {
if (this.tokens.matches2(types_1.types._catch, types_1.types.braceL)) {
if (this.tokens.matches2(30224 /* _catch */, 4096 /* braceL */)) {
this.tokens.copyToken();

@@ -15,0 +14,0 @@ this.tokens.appendCode(` (${this.nameManager.claimFreeName("e")})`);

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tokenizer_1 = require("../../sucrase-babylon/tokenizer");
const types_1 = require("../../sucrase-babylon/tokenizer/types");
const Transformer_1 = require("./Transformer");

@@ -23,3 +22,3 @@ /**

const startIndex = this.tokens.currentIndex();
if (this.tokens.matchesName("createReactClass")) {
if (this.tokens.matchesContextual(32 /* _createReactClass */)) {
const newName = this.importProcessor.getIdentifierReplacement("createReactClass");

@@ -35,5 +34,5 @@ if (newName) {

}
if (this.tokens.matches3(types_1.types.name, types_1.types.dot, types_1.types.name) &&
this.tokens.matchesName("React") &&
this.tokens.matchesNameAtIndex(this.tokens.currentIndex() + 2, "createClass")) {
if (this.tokens.matches3(2048 /* name */, 9216 /* dot */, 2048 /* name */) &&
this.tokens.matchesContextual(30 /* _React */) &&
this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 2, 31 /* _createClass */)) {
const newName = this.importProcessor.getIdentifierReplacement("React");

@@ -64,20 +63,20 @@ if (newName) {

if (this.classNeedsDisplayName()) {
this.tokens.copyExpectedToken("(");
this.tokens.copyExpectedToken("{");
this.tokens.copyExpectedToken(6144 /* parenL */);
this.tokens.copyExpectedToken(4096 /* braceL */);
this.tokens.appendCode(`displayName: '${displayName}',`);
this.rootTransformer.processBalancedCode();
this.tokens.copyExpectedToken("}");
this.tokens.copyExpectedToken(")");
this.tokens.copyExpectedToken(5120 /* braceR */);
this.tokens.copyExpectedToken(6656 /* parenR */);
}
}
findDisplayName(startIndex) {
if (this.tokens.matchesAtIndex(startIndex - 2, ["name", "="]) &&
!this.tokens.matchesAtIndex(startIndex - 3, ["."])) {
if (this.tokens.matchesAtIndex(startIndex - 2, [2048 /* name */, 14368 /* eq */]) &&
!this.tokens.matchesAtIndex(startIndex - 3, [9216 /* dot */])) {
// This is an assignment (or declaration) with an identifier LHS, so use
// that identifier name.
return this.tokens.tokens[startIndex - 2].value;
return this.tokens.identifierNameAtIndex(startIndex - 2);
}
if (this.tokens.tokens[startIndex - 2].identifierRole === tokenizer_1.IdentifierRole.ObjectKey) {
// This is an object literal value.
return this.tokens.tokens[startIndex - 2].value;
return this.tokens.identifierNameAtIndex(startIndex - 2);
}

@@ -93,3 +92,3 @@ return null;

let index = this.tokens.currentIndex();
if (!this.tokens.matches2(types_1.types.parenL, types_1.types.braceL)) {
if (!this.tokens.matches2(6144 /* parenL */, 4096 /* braceL */)) {
return false;

@@ -107,7 +106,7 @@ }

const token = this.tokens.tokens[index];
if (token.type.label === "}" && token.contextId === objectContextId) {
if (token.type === 5120 /* braceR */ && token.contextId === objectContextId) {
index++;
break;
}
if (this.tokens.matchesNameAtIndex(index, "displayName") &&
if (this.tokens.matchesContextualAtIndex(index, 33 /* _displayName */) &&
this.tokens.tokens[index].identifierRole === tokenizer_1.IdentifierRole.ObjectKey &&

@@ -124,5 +123,6 @@ token.contextId === objectContextId) {

// display name, so we want to proceed as long as that was the only argument.
return (this.tokens.matchesAtIndex(index, [")"]) || this.tokens.matchesAtIndex(index, [",", ")"]));
return (this.tokens.matchesAtIndex(index, [6656 /* parenR */]) ||
this.tokens.matchesAtIndex(index, [7168 /* comma */, 6656 /* parenR */]));
}
}
exports.default = ReactDisplayNameTransformer;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../../sucrase-babylon/tokenizer/types");
const getClassInfo_1 = require("../util/getClassInfo");

@@ -70,6 +69,6 @@ const FlowTransformer_1 = require("./FlowTransformer");

while (!this.tokens.isAtEnd()) {
if (this.tokens.matches1(types_1.types.braceL) || this.tokens.matches1(types_1.types.dollarBraceL)) {
if (this.tokens.matches1(4096 /* braceL */) || this.tokens.matches1(12800 /* dollarBraceL */)) {
braceDepth++;
}
else if (this.tokens.matches1(types_1.types.braceR)) {
else if (this.tokens.matches1(5120 /* braceR */)) {
if (braceDepth === 0) {

@@ -80,6 +79,6 @@ return;

}
if (this.tokens.matches1(types_1.types.parenL)) {
if (this.tokens.matches1(6144 /* parenL */)) {
parenDepth++;
}
else if (this.tokens.matches1(types_1.types.parenR)) {
else if (this.tokens.matches1(6656 /* parenR */)) {
if (parenDepth === 0) {

@@ -94,3 +93,3 @@ return;

processToken() {
if (this.tokens.matches1(types_1.types._class)) {
if (this.tokens.matches1(41488 /* _class */)) {
this.processClass();

@@ -111,6 +110,6 @@ return;

processNamedClass() {
if (!this.tokens.matches2(types_1.types._class, types_1.types.name)) {
if (!this.tokens.matches2(41488 /* _class */, 2048 /* name */)) {
throw new Error("Expected identifier for exported class name.");
}
const name = this.tokens.tokens[this.tokens.currentIndex() + 1].value;
const name = this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 1);
this.processClass();

@@ -133,4 +132,4 @@ return name;

}
this.tokens.copyExpectedToken("class");
while (!this.tokens.matchesContextIdAndLabel(types_1.types.braceL, contextId)) {
this.tokens.copyExpectedToken(41488 /* _class */);
while (!this.tokens.matchesContextIdAndLabel(4096 /* braceL */, contextId)) {
this.processToken();

@@ -158,3 +157,3 @@ }

}
this.tokens.copyExpectedToken("{");
this.tokens.copyExpectedToken(4096 /* braceL */);
if (constructorInsertPos === null && initializerStatements.length > 0) {

@@ -170,3 +169,3 @@ const initializersCode = initializerStatements.join(";");

}
while (!this.tokens.matchesContextIdAndLabel(types_1.types.braceR, classContextId)) {
while (!this.tokens.matchesContextIdAndLabel(5120 /* braceR */, classContextId)) {
if (fieldIndex < fieldRanges.length &&

@@ -191,3 +190,3 @@ this.tokens.currentIndex() === fieldRanges[fieldIndex].start) {

}
this.tokens.copyExpectedToken("}");
this.tokens.copyExpectedToken(5120 /* braceR */);
}

@@ -194,0 +193,0 @@ processPossibleTypeRange() {

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../../sucrase-babylon/tokenizer/types");
const isIdentifier_1 = require("../util/isIdentifier");

@@ -17,17 +16,17 @@ const Transformer_1 = require("./Transformer");

}
if (this.tokens.matches1(types_1.types._public) ||
this.tokens.matches1(types_1.types._protected) ||
this.tokens.matches1(types_1.types._private) ||
this.tokens.matches1(types_1.types._abstract) ||
this.tokens.matches1(types_1.types._readonly) ||
this.tokens.matches1(types_1.types.nonNullAssertion)) {
if (this.tokens.matches1(51728 /* _public */) ||
this.tokens.matches1(52752 /* _protected */) ||
this.tokens.matches1(52240 /* _private */) ||
this.tokens.matches1(50704 /* _abstract */) ||
this.tokens.matches1(50192 /* _readonly */) ||
this.tokens.matches1(28672 /* nonNullAssertion */)) {
this.tokens.removeInitialToken();
return true;
}
if (this.tokens.matches1(types_1.types._enum) || this.tokens.matches2(types_1.types._const, types_1.types._enum)) {
if (this.tokens.matches1(53776 /* _enum */) || this.tokens.matches2(38416 /* _const */, 53776 /* _enum */)) {
this.processEnum();
return true;
}
if (this.tokens.matches2(types_1.types._export, types_1.types._enum) ||
this.tokens.matches3(types_1.types._export, types_1.types._const, types_1.types._enum)) {
if (this.tokens.matches2(42512 /* _export */, 53776 /* _enum */) ||
this.tokens.matches3(42512 /* _export */, 38416 /* _const */, 53776 /* _enum */)) {
this.processEnum(true);

@@ -41,11 +40,11 @@ return true;

this.tokens.removeInitialToken();
while (this.tokens.matches1(types_1.types._const) || this.tokens.matches1(types_1.types._enum)) {
while (this.tokens.matches1(38416 /* _const */) || this.tokens.matches1(53776 /* _enum */)) {
this.tokens.removeToken();
}
const enumName = this.tokens.currentToken().value;
const enumName = this.tokens.identifierName();
this.tokens.removeToken();
this.tokens.appendCode(`var ${enumName}; (function (${enumName})`);
this.tokens.copyExpectedToken("{");
this.tokens.copyExpectedToken(4096 /* braceL */);
this.processEnumBody(enumName);
this.tokens.copyExpectedToken("}");
this.tokens.copyExpectedToken(5120 /* braceR */);
if (isExport) {

@@ -67,3 +66,3 @@ this.tokens.appendCode(`)(${enumName} || (exports.${enumName} = ${enumName} = {}));`);

while (true) {
if (this.tokens.matches1(types_1.types.braceR)) {
if (this.tokens.matches1(5120 /* braceR */)) {
break;

@@ -75,9 +74,9 @@ }

let nameStringCode;
if (nameToken.type.label === "name") {
name = nameToken.value;
if (nameToken.type === 2048 /* name */) {
name = this.tokens.identifierNameForToken(nameToken);
isValidIdentifier = true;
nameStringCode = `"${name}"`;
}
else if (nameToken.type.label === "string") {
name = nameToken.value;
else if (nameToken.type === 1536 /* string */) {
name = this.tokens.stringValueForToken(nameToken);
isValidIdentifier = isIdentifier_1.default(name);

@@ -92,3 +91,3 @@ nameStringCode = this.tokens.code.slice(nameToken.start, nameToken.end);

let valueCode;
if (this.tokens.matches1(types_1.types.eq)) {
if (this.tokens.matches1(14368 /* eq */)) {
const rhsEndIndex = this.tokens.currentToken().rhsEndIndex;

@@ -99,4 +98,4 @@ if (rhsEndIndex == null) {

this.tokens.removeToken();
if (this.tokens.matches2(types_1.types.string, types_1.types.comma) ||
this.tokens.matches2(types_1.types.string, types_1.types.braceR)) {
if (this.tokens.matches2(1536 /* string */, 7168 /* comma */) ||
this.tokens.matches2(1536 /* string */, 5120 /* braceR */)) {
valueIsString = true;

@@ -124,3 +123,3 @@ }

}
if (this.tokens.matches1(types_1.types.comma)) {
if (this.tokens.matches1(7168 /* comma */)) {
this.tokens.removeToken();

@@ -127,0 +126,0 @@ }

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const lines_and_columns_1 = require("lines-and-columns");
const types_1 = require("../../sucrase-babylon/tokenizer/types");
function formatTokens(code, tokens) {

@@ -10,3 +11,3 @@ if (tokens.length === 0) {

const typeKeys = Object.keys(tokens[0].type).filter((k) => k !== "label" && k !== "keyword");
const headings = ["Location", "Label", "Value", ...tokenKeys, ...typeKeys];
const headings = ["Location", "Label", "Raw", ...tokenKeys, ...typeKeys];
const lines = new lines_and_columns_1.default(code);

@@ -24,6 +25,7 @@ const rows = [headings, ...tokens.map(getTokenComponents)];

function getTokenComponents(token) {
const raw = code.slice(token.start, token.end);
return [
formatRange(token.start, token.end),
token.type.label,
token.value != null ? truncate(String(token.value), 14) : "",
types_1.formatTokenType(token.type),
truncate(String(raw), 14),
...tokenKeys.map((key) => formatValue(token[key], key)),

@@ -30,0 +32,0 @@ ...typeKeys.map((key) => formatValue(token.type[key], key)),

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../../sucrase-babylon/tokenizer/types");
/**

@@ -21,7 +20,7 @@ * Get information about the class fields for this class, given a token processor pointing to the

tokens.nextToken();
while (!tokens.matchesContextIdAndLabel(types_1.types.braceR, classContextId)) {
if (tokens.matchesName("constructor")) {
while (!tokens.matchesContextIdAndLabel(5120 /* braceR */, classContextId)) {
if (tokens.matchesContextual(6 /* _constructor */)) {
({ constructorInitializers, constructorInsertPos } = processConstructor(tokens));
}
else if (tokens.matches1(types_1.types.semi)) {
else if (tokens.matches1(7680 /* semi */)) {
tokens.nextToken();

@@ -34,3 +33,3 @@ }

while (isAccessModifier(tokens.currentToken())) {
if (tokens.matches1(types_1.types._static)) {
if (tokens.matches1(51216 /* _static */)) {
isStatic = true;

@@ -40,3 +39,3 @@ }

}
if (tokens.matchesName("constructor")) {
if (tokens.matchesContextual(6 /* _constructor */)) {
({ constructorInitializers, constructorInsertPos } = processConstructor(tokens));

@@ -46,3 +45,3 @@ continue;

const nameCode = getNameCode(tokens);
if (tokens.matches1(types_1.types.lessThan) || tokens.matches1(types_1.types.parenL)) {
if (tokens.matches1(21000 /* lessThan */) || tokens.matches1(6144 /* parenL */)) {
// This is a method, so just skip to the next method/field. To do that, we seek forward to

@@ -63,3 +62,3 @@ // the next start of a class name (either an open bracket or an identifier, or the closing

}
if (tokens.matches1(types_1.types.eq)) {
if (tokens.matches1(14368 /* eq */)) {
const valueEnd = tokens.currentToken().rhsEndIndex;

@@ -113,7 +112,7 @@ if (valueEnd == null) {

tokens.nextToken();
if (tokens.matches1(types_1.types.name)) {
className = tokens.currentToken().value;
if (tokens.matches1(2048 /* name */)) {
className = tokens.identifierName();
}
while (!tokens.matchesContextIdAndLabel(types_1.types.braceL, contextId)) {
if (tokens.matches1(types_1.types._extends)) {
while (!tokens.matchesContextIdAndLabel(4096 /* braceL */, contextId)) {
if (tokens.matches1(42000 /* _extends */)) {
hasSuperclass = true;

@@ -137,3 +136,3 @@ }

// Advance through parameters looking for access modifiers.
while (!tokens.matchesContextIdAndLabel(types_1.types.parenR, constructorContextId)) {
while (!tokens.matchesContextIdAndLabel(6656 /* parenR */, constructorContextId)) {
if (isAccessModifier(tokens.currentToken())) {

@@ -145,6 +144,6 @@ tokens.nextToken();

const token = tokens.currentToken();
if (token.type.label !== "name") {
if (token.type !== 2048 /* name */) {
throw new Error("Expected identifier after access modifiers in constructor arg.");
}
const name = token.value;
const name = tokens.identifierNameForToken(token);
constructorInitializers.push(`this.${name} = ${name}`);

@@ -158,4 +157,4 @@ }

// Advance through body looking for a super call.
while (!tokens.matchesContextIdAndLabel(types_1.types.braceR, constructorContextId)) {
if (tokens.matches1(types_1.types._super)) {
while (!tokens.matchesContextIdAndLabel(5120 /* braceR */, constructorContextId)) {
if (tokens.matches1(40976 /* _super */)) {
tokens.nextToken();

@@ -166,3 +165,3 @@ const superCallContextId = tokens.currentToken().contextId;

}
while (!tokens.matchesContextIdAndLabel(types_1.types.parenR, superCallContextId)) {
while (!tokens.matchesContextIdAndLabel(6656 /* parenR */, superCallContextId)) {
tokens.nextToken();

@@ -183,13 +182,14 @@ }

return [
"async",
"get",
"set",
"+/-",
"readonly",
"static",
"public",
"private",
"protected",
"abstract",
].includes(token.type.label);
48144 /* _async */,
48656 /* _get */,
49168 /* _set */,
23178 /* plus */,
23690 /* minus */,
50192 /* _readonly */,
51216 /* _static */,
51728 /* _public */,
52240 /* _private */,
52752 /* _protected */,
50704 /* _abstract */,
].includes(token.type);
}

@@ -203,3 +203,3 @@ /**

function getNameCode(tokens) {
if (tokens.matches1(types_1.types.bracketL)) {
if (tokens.matches1(3072 /* bracketL */)) {
const startToken = tokens.currentToken();

@@ -210,3 +210,3 @@ const classContextId = startToken.contextId;

}
while (!tokens.matchesContextIdAndLabel(types_1.types.bracketR, classContextId)) {
while (!tokens.matchesContextIdAndLabel(3584 /* bracketR */, classContextId)) {
tokens.nextToken();

@@ -221,9 +221,9 @@ }

tokens.nextToken();
if (nameToken.type.label === "string" || nameToken.type.label === "num") {
if (nameToken.type === 1536 /* string */ || nameToken.type === 0 /* num */) {
return `[${tokens.code.slice(nameToken.start, nameToken.end)}]`;
}
else {
return `.${nameToken.value}`;
return `.${tokens.identifierNameForToken(nameToken)}`;
}
}
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const parser_1 = require("./parser");
const flow_1 = require("./plugins/flow");
const jsx_1 = require("./plugins/jsx");
const typescript_1 = require("./plugins/typescript");
const base_1 = require("./parser/base");
function parse(input, plugins) {
return getParser(plugins, input).parse();
}
exports.parse = parse;
function getParser(plugins, input) {
if (plugins.includes("flow") && plugins.includes("typescript")) {
throw new Error("Cannot combine flow and typescript plugins.");
}
if (plugins.includes("typescript")) {
return new typescript_1.default(input, plugins);
}
else if (plugins.includes("flow")) {
return new flow_1.default(input, plugins);
}
else if (plugins.includes("jsx")) {
return new jsx_1.default(input, plugins);
}
else {
return new parser_1.default(input, plugins);
}
base_1.initParser(input, plugins);
return parser_1.parseFile();
}
exports.parse = parse;
import State from "../tokenizer/state";
export default class BaseParser {
plugins: {
[key: string]: boolean;
};
state: State;
input: string;
hasPlugin(name: string): boolean;
raise(pos: number, message: string, missingPluginNames?: Array<string>): never;
}
export declare let plugins: {
[key: string]: boolean;
};
export declare let state: State;
export declare let input: string;
export declare let nextContextId: number;
export declare function getNextContextId(): number;
export declare function hasPlugin(name: string): boolean;
export declare function raise(pos: number, message: string): never;
export declare function initParser(inputCode: string, pluginList: Array<string>): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const lines_and_columns_1 = require("lines-and-columns");
class BaseParser {
hasPlugin(name) {
return Boolean(this.plugins[name]);
const state_1 = require("../tokenizer/state");
function getNextContextId() {
return exports.nextContextId++;
}
exports.getNextContextId = getNextContextId;
function hasPlugin(name) {
return Boolean(exports.plugins[name]);
}
exports.hasPlugin = hasPlugin;
// This function is used to raise exceptions on parse errors. It
// takes an offset integer (into the current `input`) to indicate
// the location of the error, attaches the position to the end
// of the error message, and then raises a `SyntaxError` with that
// message.
function raise(pos, message) {
let loc = new lines_and_columns_1.default(exports.input).locationForIndex(pos);
if (!loc) {
loc = { line: 0, column: 0 };
}
// This function is used to raise exceptions on parse errors. It
// takes an offset integer (into the current `input`) to indicate
// the location of the error, attaches the position to the end
// of the error message, and then raises a `SyntaxError` with that
// message.
raise(pos, message, missingPluginNames) {
let loc = new lines_and_columns_1.default(this.input).locationForIndex(pos);
if (!loc) {
loc = { line: 0, column: 0 };
}
message += ` (${loc.line}:${loc.column})`;
// tslint:disable-next-line no-any
const err = new SyntaxError(message);
err.pos = pos;
err.loc = loc;
if (missingPluginNames) {
// @ts-ignore
err.missingPlugin = missingPluginNames;
}
throw err;
}
message += ` (${loc.line}:${loc.column})`;
// tslint:disable-next-line no-any
const err = new SyntaxError(message);
err.pos = pos;
err.loc = loc;
throw err;
}
exports.default = BaseParser;
exports.raise = raise;
function initParser(inputCode, pluginList) {
exports.input = inputCode;
exports.state = new state_1.default();
exports.state.init();
exports.nextContextId = 1;
exports.plugins = pluginList.reduce((obj, p) => (Object.assign({}, obj, { [p]: true })), {});
}
exports.initParser = initParser;
import { TokenType } from "../tokenizer/types";
import LValParser from "./lval";
export default abstract class ExpressionParser extends LValParser {
abstract parseBlock(allowDirectives?: boolean, isFunctionScope?: boolean, contextId?: number): void;
abstract parseClass(isStatement: boolean, optionalId?: boolean): void;
abstract parseDecorators(allowExport?: boolean): void;
abstract parseFunction(functionStart: number, isStatement: boolean, allowExpressionBody?: boolean, optionalId?: boolean): void;
abstract parseFunctionParams(allowModifiers?: boolean, funcContextId?: number): void;
parseExpression(noIn?: boolean): void;
parseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): boolean;
parseMaybeConditional(noIn: boolean | null): boolean;
parseConditional(noIn: boolean | null, startPos: number): void;
parseExprOps(noIn: boolean | null): boolean;
parseExprOp(minPrec: number, noIn: boolean | null): void;
parseMaybeUnary(): boolean;
parseExprSubscripts(): boolean;
parseSubscripts(startPos: number, noCalls?: boolean | null): void;
/** Set 'state.stop = true' to indicate that we should stop parsing subscripts. */
parseSubscript(startPos: number, noCalls: boolean | null, state: {
stop: boolean;
}): void;
atPossibleAsync(): boolean;
parseCallExpressionArguments(close: TokenType): void;
shouldParseAsyncArrow(): boolean;
parseAsyncArrowFromCallExpression(functionStart: number, startTokenIndex: number): void;
parseNoCallExpr(): void;
parseExprAtom(): boolean;
parseMaybePrivateName(): void;
parseFunctionExpression(): void;
parseMetaProperty(): void;
parseImportMetaProperty(): void;
parseLiteral(): void;
parseParenExpression(): void;
parseParenAndDistinguishExpression(canBeArrow: boolean): boolean;
shouldParseArrow(): boolean;
parseArrow(): boolean;
parseParenItem(): void;
parseNew(): void;
parseNewArguments(): void;
parseTemplate(): void;
parseObj(isPattern: boolean, isBlockScope: boolean): void;
isGetterOrSetterMethod(isPattern: boolean): boolean;
parseObjectMethod(isGenerator: boolean, isPattern: boolean, objectContextId: number): boolean;
parseObjectProperty(isPattern: boolean, isBlockScope: boolean): void;
parseObjPropValue(isGenerator: boolean, isPattern: boolean, isBlockScope: boolean, objectContextId: number): void;
parsePropertyName(objectContextId: number): void;
parseMethod(functionStart: number, isGenerator: boolean, isConstructor: boolean): void;
parseArrowExpression(functionStart: number, startTokenIndex: number): void;
parseFunctionBodyAndFinish(functionStart: number, isGenerator: boolean, allowExpressionBody?: boolean | null, funcContextId?: number): void;
parseFunctionBody(functionStart: number, isGenerator: boolean, allowExpression: boolean | null, funcContextId?: number): void;
parseExprList(close: TokenType, allowEmpty?: boolean | null): void;
parseExprListItem(allowEmpty: boolean | null): void;
parseIdentifier(): void;
parseAwait(): void;
parseYield(): void;
}
export declare function parseExpression(noIn?: boolean): void;
export declare function parseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): boolean;
export declare function baseParseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): boolean;
export declare function baseParseConditional(noIn: boolean | null, startPos: number): void;
export declare function parseMaybeUnary(): boolean;
export declare function parseExprSubscripts(): boolean;
export declare function baseParseSubscripts(startPos: number, noCalls?: boolean | null): void;
/** Set 'state.stop = true' to indicate that we should stop parsing subscripts. */
export declare function baseParseSubscript(startPos: number, noCalls: boolean | null, stopState: {
stop: boolean;
}): void;
export declare function atPossibleAsync(): boolean;
export declare function parseCallExpressionArguments(close: TokenType): void;
export declare function parseExprAtom(): boolean;
export declare function parseLiteral(): void;
export declare function parseParenExpression(): void;
export declare function parseArrow(): boolean;
export declare function parseObj(isPattern: boolean, isBlockScope: boolean): void;
export declare function parsePropertyName(objectContextId: number): void;
export declare function parseMethod(functionStart: number, isGenerator: boolean, isConstructor: boolean): void;
export declare function parseArrowExpression(functionStart: number, startTokenIndex: number): void;
export declare function parseFunctionBodyAndFinish(functionStart: number, isGenerator: boolean, allowExpressionBody?: boolean | null, funcContextId?: number): void;
export declare function parseFunctionBody(functionStart: number, isGenerator: boolean, allowExpression: boolean | null, funcContextId?: number): void;
export declare function parseIdentifier(): void;

@@ -21,691 +21,811 @@ "use strict";

// [opp]: http://en.wikipedia.org/wiki/Operator-precedence_parser
const flow_1 = require("../plugins/flow");
const jsx_1 = require("../plugins/jsx");
const types_1 = require("../plugins/types");
const typescript_1 = require("../plugins/typescript");
const tokenizer_1 = require("../tokenizer");
const types_1 = require("../tokenizer/types");
const base_1 = require("./base");
const lval_1 = require("./lval");
class ExpressionParser extends lval_1.default {
// ### Expression parsing
// These nest, from the most general expression type at the top to
// 'atomic', nondivisible expression types at the bottom. Most of
// the functions will simply let the function (s) below them parse,
// and, *if* the syntactic construct they handle is present, wrap
// the AST node that the inner parser gave them in another node.
// Parse a full expression. The optional arguments are used to
// forbid the `in` operator (in for loops initialization expressions)
// and provide reference for storing '=' operator inside shorthand
// property assignment in contexts where both object expression
// and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position).
parseExpression(noIn) {
this.parseMaybeAssign(noIn);
if (this.match(types_1.types.comma)) {
while (this.eat(types_1.types.comma)) {
this.parseMaybeAssign(noIn);
}
const statement_1 = require("./statement");
const util_1 = require("./util");
// ### Expression parsing
// These nest, from the most general expression type at the top to
// 'atomic', nondivisible expression types at the bottom. Most of
// the functions will simply let the function (s) below them parse,
// and, *if* the syntactic construct they handle is present, wrap
// the AST node that the inner parser gave them in another node.
// Parse a full expression. The optional arguments are used to
// forbid the `in` operator (in for loops initialization expressions)
// and provide reference for storing '=' operator inside shorthand
// property assignment in contexts where both object expression
// and object pattern might appear (so it's possible to raise
// delayed syntax error at correct position).e
function parseExpression(noIn) {
parseMaybeAssign(noIn);
if (tokenizer_1.match(7168 /* comma */)) {
while (tokenizer_1.eat(7168 /* comma */)) {
parseMaybeAssign(noIn);
}
}
// Parse an assignment expression. This includes applications of
// operators like `+=`.
// Returns true if the expression was an arrow function.
parseMaybeAssign(noIn = null, afterLeftParse) {
if (this.match(types_1.types._yield)) {
this.parseYield();
if (afterLeftParse) {
afterLeftParse.call(this);
}
return false;
}
if (this.match(types_1.types.parenL) || this.match(types_1.types.name) || this.match(types_1.types._yield)) {
this.state.potentialArrowAt = this.state.start;
}
const wasArrow = this.parseMaybeConditional(noIn);
}
exports.parseExpression = parseExpression;
function parseMaybeAssign(noIn = null, afterLeftParse) {
if (base_1.hasPlugin("typescript")) {
return typescript_1.tsParseMaybeAssign(noIn, afterLeftParse);
}
else if (base_1.hasPlugin("flow")) {
return flow_1.flowParseMaybeAssign(noIn, afterLeftParse);
}
else {
return baseParseMaybeAssign(noIn, afterLeftParse);
}
}
exports.parseMaybeAssign = parseMaybeAssign;
// Parse an assignment expression. This includes applications of
// operators like `+=`.
// Returns true if the expression was an arrow function.
function baseParseMaybeAssign(noIn = null, afterLeftParse) {
if (tokenizer_1.match(43536 /* _yield */)) {
parseYield();
if (afterLeftParse) {
afterLeftParse.call(this);
afterLeftParse();
}
if (this.state.type.isAssign) {
this.next();
this.parseMaybeAssign(noIn);
return false;
}
return wasArrow;
}
// Parse a ternary conditional (`?:`) operator.
// Returns true if the expression was an arrow function.
parseMaybeConditional(noIn) {
const startPos = this.state.start;
const wasArrow = this.parseExprOps(noIn);
if (wasArrow) {
return true;
}
this.parseConditional(noIn, startPos);
return false;
}
parseConditional(noIn, startPos) {
if (this.eat(types_1.types.question)) {
this.parseMaybeAssign();
this.expect(types_1.types.colon);
this.parseMaybeAssign(noIn);
}
if (tokenizer_1.match(6144 /* parenL */) || tokenizer_1.match(2048 /* name */) || tokenizer_1.match(43536 /* _yield */)) {
base_1.state.potentialArrowAt = base_1.state.start;
}
// Start the precedence parser.
// Returns true if this was an arrow function
parseExprOps(noIn) {
const wasArrow = this.parseMaybeUnary();
if (wasArrow) {
return true;
}
this.parseExprOp(-1, noIn);
const wasArrow = parseMaybeConditional(noIn);
if (afterLeftParse) {
afterLeftParse();
}
if (base_1.state.type & 32 /* IS_ASSIGN */) {
tokenizer_1.next();
parseMaybeAssign(noIn);
return false;
}
// Parse binary operators with the operator precedence parsing
// algorithm. `left` is the left-hand side of the operator.
// `minPrec` provides context that allows the function to stop and
// defer further parser to one of its callers when it encounters an
// operator that has a lower precedence than the set it is parsing.
parseExprOp(minPrec, noIn) {
const prec = this.state.type.binop;
if (prec != null && (!noIn || !this.match(types_1.types._in))) {
if (prec > minPrec) {
const operator = this.state.value;
const op = this.state.type;
this.next();
if (operator === "|>") {
// Support syntax such as 10 |> x => x + 1
this.state.potentialArrowAt = this.state.start;
}
this.parseMaybeUnary();
this.parseExprOp(op.rightAssociative ? prec - 1 : prec, noIn);
this.parseExprOp(minPrec, noIn);
return wasArrow;
}
exports.baseParseMaybeAssign = baseParseMaybeAssign;
// Parse a ternary conditional (`?:`) operator.
// Returns true if the expression was an arrow function.
function parseMaybeConditional(noIn) {
const startPos = base_1.state.start;
const wasArrow = parseExprOps(noIn);
if (wasArrow) {
return true;
}
parseConditional(noIn, startPos);
return false;
}
function parseConditional(noIn, startPos) {
if (base_1.hasPlugin("typescript") || base_1.hasPlugin("flow")) {
types_1.typedParseConditional(noIn, startPos);
}
else {
baseParseConditional(noIn, startPos);
}
}
function baseParseConditional(noIn, startPos) {
if (tokenizer_1.eat(9728 /* question */)) {
parseMaybeAssign();
util_1.expect(8192 /* colon */);
parseMaybeAssign(noIn);
}
}
exports.baseParseConditional = baseParseConditional;
// Start the precedence parser.
// Returns true if this was an arrow function
function parseExprOps(noIn) {
const wasArrow = parseMaybeUnary();
if (wasArrow) {
return true;
}
parseExprOp(-1, noIn);
return false;
}
// Parse binary operators with the operator precedence parsing
// algorithm. `left` is the left-hand side of the operator.
// `minPrec` provides context that allows the function to stop and
// defer further parser to one of its callers when it encounters an
// operator that has a lower precedence than the set it is parsing.
function parseExprOp(minPrec, noIn) {
if (base_1.hasPlugin("typescript") &&
(45592 /* _in */ & 15 /* PRECEDENCE_MASK */) > minPrec &&
!util_1.hasPrecedingLineBreak() &&
util_1.eatContextual(2 /* _as */)) {
base_1.state.tokens[base_1.state.tokens.length - 1].type = 53264 /* _as */;
tokenizer_1.runInTypeContext(1, () => {
typescript_1.tsParseType();
});
parseExprOp(minPrec, noIn);
return;
}
const prec = base_1.state.type & 15 /* PRECEDENCE_MASK */;
if (prec > 0 && (!noIn || !tokenizer_1.match(45592 /* _in */))) {
if (prec > minPrec) {
const op = base_1.state.type;
tokenizer_1.next();
if (op === 16897 /* pipeline */) {
// Support syntax such as 10 |> x => x + 1
base_1.state.potentialArrowAt = base_1.state.start;
}
parseMaybeUnary();
parseExprOp(op & 64 /* IS_RIGHT_ASSOCIATIVE */ ? prec - 1 : prec, noIn);
parseExprOp(minPrec, noIn);
}
}
// Parse unary operators, both prefix and postfix.
// Returns true if this was an arrow function.
parseMaybeUnary() {
if (this.state.type.prefix) {
this.next();
this.parseMaybeUnary();
return false;
}
const wasArrow = this.parseExprSubscripts();
if (wasArrow) {
return true;
}
while (this.state.type.postfix && !this.canInsertSemicolon()) {
this.next();
}
}
// Parse unary operators, both prefix and postfix.
// Returns true if this was an arrow function.
function parseMaybeUnary() {
if (base_1.hasPlugin("typescript") && !base_1.hasPlugin("jsx") && tokenizer_1.eat(21000 /* lessThan */)) {
typescript_1.tsParseTypeAssertion();
return false;
}
// Parse call, dot, and `[]`-subscript expressions.
// Returns true if this was an arrow function.
parseExprSubscripts() {
const startPos = this.state.start;
const wasArrow = this.parseExprAtom();
if (wasArrow) {
return true;
}
this.parseSubscripts(startPos);
if (base_1.state.type & 128 /* IS_PREFIX */) {
tokenizer_1.next();
parseMaybeUnary();
return false;
}
parseSubscripts(startPos, noCalls = null) {
const state = { stop: false };
do {
this.parseSubscript(startPos, noCalls, state);
} while (!state.stop);
const wasArrow = parseExprSubscripts();
if (wasArrow) {
return true;
}
/** Set 'state.stop = true' to indicate that we should stop parsing subscripts. */
parseSubscript(startPos, noCalls, state) {
if (!noCalls && this.eat(types_1.types.doubleColon)) {
this.parseNoCallExpr();
state.stop = true;
this.parseSubscripts(startPos, noCalls);
while (base_1.state.type & 256 /* IS_POSTFIX */ && !util_1.canInsertSemicolon()) {
tokenizer_1.next();
}
return false;
}
exports.parseMaybeUnary = parseMaybeUnary;
// Parse call, dot, and `[]`-subscript expressions.
// Returns true if this was an arrow function.
function parseExprSubscripts() {
const startPos = base_1.state.start;
const wasArrow = parseExprAtom();
if (wasArrow) {
return true;
}
parseSubscripts(startPos);
return false;
}
exports.parseExprSubscripts = parseExprSubscripts;
function parseSubscripts(startPos, noCalls = null) {
if (base_1.hasPlugin("flow")) {
flow_1.flowParseSubscripts(startPos, noCalls);
}
else {
baseParseSubscripts(startPos, noCalls);
}
}
function baseParseSubscripts(startPos, noCalls = null) {
const stopState = { stop: false };
do {
parseSubscript(startPos, noCalls, stopState);
} while (!stopState.stop);
}
exports.baseParseSubscripts = baseParseSubscripts;
function parseSubscript(startPos, noCalls, stopState) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsParseSubscript(startPos, noCalls, stopState);
}
else {
baseParseSubscript(startPos, noCalls, stopState);
}
}
/** Set 'state.stop = true' to indicate that we should stop parsing subscripts. */
function baseParseSubscript(startPos, noCalls, stopState) {
if (!noCalls && tokenizer_1.eat(8704 /* doubleColon */)) {
parseNoCallExpr();
stopState.stop = true;
parseSubscripts(startPos, noCalls);
}
else if (tokenizer_1.match(10240 /* questionDot */)) {
if (noCalls && tokenizer_1.lookaheadType() === 6144 /* parenL */) {
stopState.stop = true;
return;
}
else if (this.match(types_1.types.questionDot)) {
if (noCalls && this.lookaheadType() === types_1.types.parenL) {
state.stop = true;
return;
}
this.next();
if (this.eat(types_1.types.bracketL)) {
this.parseExpression();
this.expect(types_1.types.bracketR);
}
else if (this.eat(types_1.types.parenL)) {
this.parseCallExpressionArguments(types_1.types.parenR);
}
else {
this.parseIdentifier();
}
tokenizer_1.next();
if (tokenizer_1.eat(3072 /* bracketL */)) {
parseExpression();
util_1.expect(3584 /* bracketR */);
}
else if (this.eat(types_1.types.dot)) {
this.parseMaybePrivateName();
else if (tokenizer_1.eat(6144 /* parenL */)) {
parseCallExpressionArguments(6656 /* parenR */);
}
else if (this.eat(types_1.types.bracketL)) {
this.parseExpression();
this.expect(types_1.types.bracketR);
else {
parseIdentifier();
}
else if (!noCalls && this.match(types_1.types.parenL)) {
const possibleAsync = this.atPossibleAsync();
// We see "async", but it's possible it's a usage of the name "async". Parse as if it's a
// function call, and if we see an arrow later, backtrack and re-parse as a parameter list.
const snapshotForAsyncArrow = possibleAsync ? this.state.snapshot() : null;
const startTokenIndex = this.state.tokens.length;
this.next();
const callContextId = this.nextContextId++;
this.state.tokens[this.state.tokens.length - 1].contextId = callContextId;
this.parseCallExpressionArguments(types_1.types.parenR);
this.state.tokens[this.state.tokens.length - 1].contextId = callContextId;
if (possibleAsync && this.shouldParseAsyncArrow()) {
// We hit an arrow, so backtrack and start again parsing function parameters.
this.state.restoreFromSnapshot(snapshotForAsyncArrow);
state.stop = true;
this.parseFunctionParams();
this.parseAsyncArrowFromCallExpression(startPos, startTokenIndex);
}
}
else if (tokenizer_1.eat(9216 /* dot */)) {
parseMaybePrivateName();
}
else if (tokenizer_1.eat(3072 /* bracketL */)) {
parseExpression();
util_1.expect(3584 /* bracketR */);
}
else if (!noCalls && tokenizer_1.match(6144 /* parenL */)) {
const possibleAsync = atPossibleAsync();
// We see "async", but it's possible it's a usage of the name "async". Parse as if it's a
// function call, and if we see an arrow later, backtrack and re-parse as a parameter list.
const snapshotForAsyncArrow = possibleAsync ? base_1.state.snapshot() : null;
const startTokenIndex = base_1.state.tokens.length;
tokenizer_1.next();
const callContextId = base_1.getNextContextId();
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = callContextId;
parseCallExpressionArguments(6656 /* parenR */);
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = callContextId;
if (possibleAsync && shouldParseAsyncArrow()) {
// We hit an arrow, so backtrack and start again parsing function parameters.
base_1.state.restoreFromSnapshot(snapshotForAsyncArrow);
stopState.stop = true;
statement_1.parseFunctionParams();
parseAsyncArrowFromCallExpression(startPos, startTokenIndex);
}
else if (this.match(types_1.types.backQuote)) {
// Tagged template expression.
this.parseTemplate();
}
else if (tokenizer_1.match(12288 /* backQuote */)) {
// Tagged template expression.
parseTemplate();
}
else {
stopState.stop = true;
}
}
exports.baseParseSubscript = baseParseSubscript;
function atPossibleAsync() {
// This was made less strict than the original version to avoid passing around nodes, but it
// should be safe to have rare false positives here.
return (base_1.state.tokens[base_1.state.tokens.length - 1].contextualKeyword === 3 /* _async */ &&
!util_1.canInsertSemicolon());
}
exports.atPossibleAsync = atPossibleAsync;
function parseCallExpressionArguments(close) {
let first = true;
while (!tokenizer_1.eat(close)) {
if (first) {
first = false;
}
else {
state.stop = true;
util_1.expect(7168 /* comma */);
if (tokenizer_1.eat(close))
break;
}
parseExprListItem(false);
}
atPossibleAsync() {
// This was made less strict than the original version to avoid passing around nodes, but it
// should be safe to have rare false positives here.
return (this.state.tokens[this.state.tokens.length - 1].value === "async" &&
!this.canInsertSemicolon());
}
exports.parseCallExpressionArguments = parseCallExpressionArguments;
function shouldParseAsyncArrow() {
return tokenizer_1.match(8192 /* colon */) || tokenizer_1.match(10752 /* arrow */);
}
function parseAsyncArrowFromCallExpression(functionStart, startTokenIndex) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsStartParseAsyncArrowFromCallExpression();
}
parseCallExpressionArguments(close) {
let first = true;
while (!this.eat(close)) {
if (first) {
first = false;
}
else {
this.expect(types_1.types.comma);
if (this.eat(close))
break;
}
this.parseExprListItem(false);
}
else if (base_1.hasPlugin("flow")) {
flow_1.flowStartParseAsyncArrowFromCallExpression();
}
shouldParseAsyncArrow() {
return this.match(types_1.types.arrow);
util_1.expect(10752 /* arrow */);
parseArrowExpression(functionStart, startTokenIndex);
}
// Parse a no-call expression (like argument of `new` or `::` operators).
function parseNoCallExpr() {
const startPos = base_1.state.start;
parseExprAtom();
parseSubscripts(startPos, true);
}
// Parse an atomic expression — either a single token that is an
// expression, an expression started by a keyword like `function` or
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.
// Returns true if the parsed expression was an arrow function.
function parseExprAtom() {
if (tokenizer_1.match(26624 /* jsxText */)) {
parseLiteral();
return false;
}
parseAsyncArrowFromCallExpression(functionStart, startTokenIndex) {
this.expect(types_1.types.arrow);
this.parseArrowExpression(functionStart, startTokenIndex);
else if (tokenizer_1.match(21000 /* lessThan */) && base_1.hasPlugin("jsx")) {
base_1.state.type = 27136 /* jsxTagStart */;
jsx_1.jsxParseElement();
tokenizer_1.next();
return false;
}
// Parse a no-call expression (like argument of `new` or `::` operators).
parseNoCallExpr() {
const startPos = this.state.start;
this.parseExprAtom();
this.parseSubscripts(startPos, true);
}
// Parse an atomic expression — either a single token that is an
// expression, an expression started by a keyword like `function` or
// `new`, or an expression wrapped in punctuation like `()`, `[]`,
// or `{}`.
// Returns true if the parsed expression was an arrow function.
parseExprAtom() {
const canBeArrow = this.state.potentialArrowAt === this.state.start;
switch (this.state.type) {
case types_1.types.slash:
case types_1.types.assign:
this.retokenizeSlashAsRegex();
// Fall through.
case types_1.types._super:
case types_1.types._this:
case types_1.types.regexp:
case types_1.types.num:
case types_1.types.bigint:
case types_1.types.string:
case types_1.types._null:
case types_1.types._true:
case types_1.types._false:
this.next();
const canBeArrow = base_1.state.potentialArrowAt === base_1.state.start;
switch (base_1.state.type) {
case 25099 /* slash */:
case 14880 /* assign */:
tokenizer_1.retokenizeSlashAsRegex();
// Fall through.
case 40976 /* _super */:
case 40464 /* _this */:
case 1024 /* regexp */:
case 0 /* num */:
case 512 /* bigint */:
case 1536 /* string */:
case 44048 /* _null */:
case 44560 /* _true */:
case 45072 /* _false */:
tokenizer_1.next();
return false;
case 43024 /* _import */:
if (tokenizer_1.lookaheadType() === 9216 /* dot */) {
parseImportMetaProperty();
return false;
case types_1.types._import:
if (this.lookaheadType() === types_1.types.dot) {
this.parseImportMetaProperty();
return false;
}
this.next();
}
tokenizer_1.next();
return false;
case 2048 /* name */: {
const startTokenIndex = base_1.state.tokens.length;
const functionStart = base_1.state.start;
const contextualKeyword = base_1.state.contextualKeyword;
parseIdentifier();
if (contextualKeyword === 4 /* _await */) {
parseAwait();
return false;
case types_1.types.name: {
const startTokenIndex = this.state.tokens.length;
const functionStart = this.state.start;
const name = this.state.value;
this.parseIdentifier();
if (name === "await") {
this.parseAwait();
return false;
}
else if (name === "async" && this.match(types_1.types._function) && !this.canInsertSemicolon()) {
this.next();
this.parseFunction(functionStart, false, false);
return false;
}
else if (canBeArrow && name === "async" && this.match(types_1.types.name)) {
this.parseIdentifier();
this.expect(types_1.types.arrow);
// let foo = bar => {};
this.parseArrowExpression(functionStart, startTokenIndex);
return true;
}
if (canBeArrow && !this.canInsertSemicolon() && this.eat(types_1.types.arrow)) {
this.parseArrowExpression(functionStart, startTokenIndex);
return true;
}
this.state.tokens[this.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.Access;
return false;
}
case types_1.types._do: {
this.next();
this.parseBlock(false);
else if (contextualKeyword === 3 /* _async */ &&
tokenizer_1.match(34320 /* _function */) &&
!util_1.canInsertSemicolon()) {
tokenizer_1.next();
statement_1.parseFunction(functionStart, false, false);
return false;
}
case types_1.types.parenL: {
const wasArrow = this.parseParenAndDistinguishExpression(canBeArrow);
return wasArrow;
else if (canBeArrow && contextualKeyword === 3 /* _async */ && tokenizer_1.match(2048 /* name */)) {
parseIdentifier();
util_1.expect(10752 /* arrow */);
// let foo = bar => {};
parseArrowExpression(functionStart, startTokenIndex);
return true;
}
case types_1.types.bracketL:
this.next();
this.parseExprList(types_1.types.bracketR, true);
return false;
case types_1.types.braceL:
this.parseObj(false, false);
return false;
case types_1.types._function:
this.parseFunctionExpression();
return false;
case types_1.types.at:
this.parseDecorators();
// Fall through.
case types_1.types._class:
this.parseClass(false);
return false;
case types_1.types._new:
this.parseNew();
return false;
case types_1.types.backQuote:
this.parseTemplate();
return false;
case types_1.types.doubleColon: {
this.next();
this.parseNoCallExpr();
return false;
if (canBeArrow && !util_1.canInsertSemicolon() && tokenizer_1.eat(10752 /* arrow */)) {
parseArrowExpression(functionStart, startTokenIndex);
return true;
}
default:
throw this.unexpected();
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.Access;
return false;
}
case 32272 /* _do */: {
tokenizer_1.next();
statement_1.parseBlock(false);
return false;
}
case 6144 /* parenL */: {
const wasArrow = parseParenAndDistinguishExpression(canBeArrow);
return wasArrow;
}
case 3072 /* bracketL */:
tokenizer_1.next();
parseExprList(3584 /* bracketR */, true);
return false;
case 4096 /* braceL */:
parseObj(false, false);
return false;
case 34320 /* _function */:
parseFunctionExpression();
return false;
case 13312 /* at */:
statement_1.parseDecorators();
// Fall through.
case 41488 /* _class */:
statement_1.parseClass(false);
return false;
case 39952 /* _new */:
parseNew();
return false;
case 12288 /* backQuote */:
parseTemplate();
return false;
case 8704 /* doubleColon */: {
tokenizer_1.next();
parseNoCallExpr();
return false;
}
default:
throw util_1.unexpected();
}
parseMaybePrivateName() {
this.eat(types_1.types.hash);
this.parseIdentifier();
}
exports.parseExprAtom = parseExprAtom;
function parseMaybePrivateName() {
tokenizer_1.eat(13824 /* hash */);
parseIdentifier();
}
function parseFunctionExpression() {
const functionStart = base_1.state.start;
parseIdentifier();
if (tokenizer_1.eat(9216 /* dot */)) {
// function.sent
parseMetaProperty();
}
parseFunctionExpression() {
const functionStart = this.state.start;
this.parseIdentifier();
if (this.eat(types_1.types.dot)) {
// function.sent
this.parseMetaProperty();
statement_1.parseFunction(functionStart, false);
}
function parseMetaProperty() {
parseIdentifier();
}
function parseImportMetaProperty() {
parseIdentifier();
util_1.expect(9216 /* dot */);
// import.meta
parseMetaProperty();
}
function parseLiteral() {
tokenizer_1.next();
}
exports.parseLiteral = parseLiteral;
function parseParenExpression() {
util_1.expect(6144 /* parenL */);
parseExpression();
util_1.expect(6656 /* parenR */);
}
exports.parseParenExpression = parseParenExpression;
// Returns true if this was an arrow expression.
function parseParenAndDistinguishExpression(canBeArrow) {
// Assume this is a normal parenthesized expression, but if we see an arrow, we'll bail and
// start over as a parameter list.
const snapshot = base_1.state.snapshot();
const startTokenIndex = base_1.state.tokens.length;
util_1.expect(6144 /* parenL */);
const exprList = [];
let first = true;
let spreadStart;
let optionalCommaStart;
while (!tokenizer_1.match(6656 /* parenR */)) {
if (first) {
first = false;
}
this.parseFunction(functionStart, false);
}
parseMetaProperty() {
this.parseIdentifier();
}
parseImportMetaProperty() {
this.parseIdentifier();
this.expect(types_1.types.dot);
// import.meta
this.parseMetaProperty();
}
parseLiteral() {
this.next();
}
parseParenExpression() {
this.expect(types_1.types.parenL);
this.parseExpression();
this.expect(types_1.types.parenR);
}
// Returns true if this was an arrow expression.
parseParenAndDistinguishExpression(canBeArrow) {
// Assume this is a normal parenthesized expression, but if we see an arrow, we'll bail and
// start over as a parameter list.
const snapshot = this.state.snapshot();
const startTokenIndex = this.state.tokens.length;
this.expect(types_1.types.parenL);
const exprList = [];
let first = true;
let spreadStart;
let optionalCommaStart;
while (!this.match(types_1.types.parenR)) {
if (first) {
first = false;
}
else {
this.expect(types_1.types.comma);
if (this.match(types_1.types.parenR)) {
optionalCommaStart = this.state.start;
break;
}
}
if (this.match(types_1.types.ellipsis)) {
spreadStart = this.state.start;
this.parseRest(false /* isBlockScope */);
this.parseParenItem();
if (this.match(types_1.types.comma) && this.lookaheadType() === types_1.types.parenR) {
this.raise(this.state.start, "A trailing comma is not permitted after the rest element");
}
else {
util_1.expect(7168 /* comma */);
if (tokenizer_1.match(6656 /* parenR */)) {
optionalCommaStart = base_1.state.start;
break;
}
else {
exprList.push(this.parseMaybeAssign(false, this.parseParenItem));
}
}
this.expect(types_1.types.parenR);
if (canBeArrow && this.shouldParseArrow()) {
const wasArrow = this.parseArrow();
if (wasArrow) {
// It was an arrow function this whole time, so start over and parse it as params so that we
// get proper token annotations.
this.state.restoreFromSnapshot(snapshot);
// We don't need to worry about functionStart for arrow functions, so just use something.
const functionStart = this.state.start;
// Don't specify a context ID because arrow function don't need a context ID.
this.parseFunctionParams();
this.parseArrow();
this.parseArrowExpression(functionStart, startTokenIndex);
return true;
if (tokenizer_1.match(11776 /* ellipsis */)) {
spreadStart = base_1.state.start;
lval_1.parseRest(false /* isBlockScope */);
parseParenItem();
if (tokenizer_1.match(7168 /* comma */) && tokenizer_1.lookaheadType() === 6656 /* parenR */) {
base_1.raise(base_1.state.start, "A trailing comma is not permitted after the rest element");
}
break;
}
if (optionalCommaStart)
this.unexpected(optionalCommaStart);
if (spreadStart)
this.unexpected(spreadStart);
return false;
else {
exprList.push(parseMaybeAssign(false, parseParenItem));
}
}
shouldParseArrow() {
return !this.canInsertSemicolon();
}
// Returns whether there was an arrow token.
parseArrow() {
if (this.eat(types_1.types.arrow)) {
util_1.expect(6656 /* parenR */);
if (canBeArrow && shouldParseArrow()) {
const wasArrow = parseArrow();
if (wasArrow) {
// It was an arrow function this whole time, so start over and parse it as params so that we
// get proper token annotations.
base_1.state.restoreFromSnapshot(snapshot);
// We don't need to worry about functionStart for arrow functions, so just use something.
const functionStart = base_1.state.start;
// Don't specify a context ID because arrow function don't need a context ID.
statement_1.parseFunctionParams();
parseArrow();
parseArrowExpression(functionStart, startTokenIndex);
return true;
}
return false;
}
parseParenItem() { }
// New's precedence is slightly tricky. It must allow its argument to
// be a `[]` or dot subscript expression, but not a call — at least,
// not without wrapping it in parentheses. Thus, it uses the noCalls
// argument to parseSubscripts to prevent it from consuming the
// argument list.
parseNew() {
this.parseIdentifier();
if (this.eat(types_1.types.dot)) {
// new.target
this.parseMetaProperty();
return;
}
this.parseNoCallExpr();
this.eat(types_1.types.questionDot);
this.parseNewArguments();
if (optionalCommaStart)
util_1.unexpected(optionalCommaStart);
if (spreadStart)
util_1.unexpected(spreadStart);
return false;
}
function shouldParseArrow() {
return tokenizer_1.match(8192 /* colon */) || !util_1.canInsertSemicolon();
}
// Returns whether there was an arrow token.
function parseArrow() {
if (base_1.hasPlugin("typescript")) {
return typescript_1.tsParseArrow();
}
parseNewArguments() {
if (this.eat(types_1.types.parenL)) {
this.parseExprList(types_1.types.parenR);
}
else if (base_1.hasPlugin("flow")) {
return flow_1.flowParseArrow();
}
parseTemplate() {
// Finish `, read quasi
this.nextTemplateToken();
// Finish quasi, read ${
this.nextTemplateToken();
while (!this.match(types_1.types.backQuote)) {
this.expect(types_1.types.dollarBraceL);
this.parseExpression();
// Finish }, read quasi
this.nextTemplateToken();
// Finish quasi, read either ${ or `
this.nextTemplateToken();
else {
return tokenizer_1.eat(10752 /* arrow */);
}
}
exports.parseArrow = parseArrow;
function parseParenItem() {
if (base_1.hasPlugin("typescript") || base_1.hasPlugin("flow")) {
types_1.typedParseParenItem();
}
}
// New's precedence is slightly tricky. It must allow its argument to
// be a `[]` or dot subscript expression, but not a call — at least,
// not without wrapping it in parentheses. Thus, it uses the noCalls
// argument to parseSubscripts to prevent it from consuming the
// argument list.
function parseNew() {
parseIdentifier();
if (tokenizer_1.eat(9216 /* dot */)) {
// new.target
parseMetaProperty();
return;
}
parseNoCallExpr();
tokenizer_1.eat(10240 /* questionDot */);
parseNewArguments();
}
function parseNewArguments() {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsStartParseNewArguments();
}
if (tokenizer_1.eat(6144 /* parenL */)) {
parseExprList(6656 /* parenR */);
}
}
function parseTemplate() {
// Finish `, read quasi
tokenizer_1.nextTemplateToken();
// Finish quasi, read ${
tokenizer_1.nextTemplateToken();
while (!tokenizer_1.match(12288 /* backQuote */)) {
util_1.expect(12800 /* dollarBraceL */);
parseExpression();
// Finish }, read quasi
tokenizer_1.nextTemplateToken();
// Finish quasi, read either ${ or `
tokenizer_1.nextTemplateToken();
}
tokenizer_1.next();
}
// Parse an object literal or binding pattern.
function parseObj(isPattern, isBlockScope) {
// Attach a context ID to the object open and close brace and each object key.
const contextId = base_1.getNextContextId();
let first = true;
tokenizer_1.next();
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = contextId;
let firstRestLocation = null;
while (!tokenizer_1.eat(5120 /* braceR */)) {
if (first) {
first = false;
}
this.next();
}
// Parse an object literal or binding pattern.
parseObj(isPattern, isBlockScope) {
// Attach a context ID to the object open and close brace and each object key.
const contextId = this.nextContextId++;
let first = true;
this.next();
this.state.tokens[this.state.tokens.length - 1].contextId = contextId;
let firstRestLocation = null;
while (!this.eat(types_1.types.braceR)) {
if (first) {
first = false;
else {
util_1.expect(7168 /* comma */);
if (tokenizer_1.eat(5120 /* braceR */)) {
break;
}
else {
this.expect(types_1.types.comma);
if (this.eat(types_1.types.braceR)) {
}
let isGenerator = false;
if (tokenizer_1.match(11776 /* ellipsis */)) {
// Note that this is labeled as an access on the token even though it might be an
// assignment.
lval_1.parseSpread();
if (isPattern) {
const position = base_1.state.start;
if (firstRestLocation !== null) {
util_1.unexpected(firstRestLocation, "Cannot have multiple rest elements when destructuring");
}
else if (tokenizer_1.eat(5120 /* braceR */)) {
break;
}
}
let isGenerator = false;
if (this.match(types_1.types.ellipsis)) {
// Note that this is labeled as an access on the token even though it might be an
// assignment.
this.parseSpread();
if (isPattern) {
const position = this.state.start;
if (firstRestLocation !== null) {
this.unexpected(firstRestLocation, "Cannot have multiple rest elements when destructuring");
}
else if (this.eat(types_1.types.braceR)) {
break;
}
else if (this.match(types_1.types.comma) && this.lookaheadType() === types_1.types.braceR) {
this.unexpected(position, "A trailing comma is not permitted after the rest element");
}
else {
firstRestLocation = position;
continue;
}
else if (tokenizer_1.match(7168 /* comma */) && tokenizer_1.lookaheadType() === 5120 /* braceR */) {
util_1.unexpected(position, "A trailing comma is not permitted after the rest element");
}
else {
firstRestLocation = position;
continue;
}
}
if (!isPattern) {
isGenerator = this.eat(types_1.types.star);
}
if (!isPattern && this.isContextual("async")) {
if (isGenerator)
this.unexpected();
this.parseIdentifier();
if (this.match(types_1.types.colon) ||
this.match(types_1.types.parenL) ||
this.match(types_1.types.braceR) ||
this.match(types_1.types.eq) ||
this.match(types_1.types.comma)) {
// This is a key called "async" rather than an async function.
}
else {
if (this.match(types_1.types.star)) {
this.next();
isGenerator = true;
}
this.parsePropertyName(contextId);
}
}
else {
this.parsePropertyName(contextId);
continue;
}
this.parseObjPropValue(isGenerator, isPattern, isBlockScope, contextId);
}
this.state.tokens[this.state.tokens.length - 1].contextId = contextId;
}
isGetterOrSetterMethod(isPattern) {
// We go off of the next and don't bother checking if the node key is actually "get" or "set".
// This lets us avoid generating a node, and should only make the validation worse.
return (!isPattern &&
(this.match(types_1.types.string) || // get "string"() {}
this.match(types_1.types.num) || // get 1() {}
this.match(types_1.types.bracketL) || // get ["string"]() {}
this.match(types_1.types.name) || // get foo() {}
!!this.state.type.keyword) // get debugger() {}
);
}
// Returns true if this was a method.
parseObjectMethod(isGenerator, isPattern, objectContextId) {
// We don't need to worry about modifiers because object methods can't have optional bodies, so
// the start will never be used.
const functionStart = this.state.start;
if (this.match(types_1.types.parenL)) {
if (isPattern)
this.unexpected();
this.parseMethod(functionStart, isGenerator, /* isConstructor */ false);
return true;
if (!isPattern) {
isGenerator = tokenizer_1.eat(24587 /* star */);
}
if (this.isGetterOrSetterMethod(isPattern)) {
this.parsePropertyName(objectContextId);
this.parseMethod(functionStart, /* isGenerator */ false, /* isConstructor */ false);
return true;
}
return false;
}
parseObjectProperty(isPattern, isBlockScope) {
if (this.eat(types_1.types.colon)) {
if (isPattern) {
this.parseMaybeDefault(isBlockScope);
if (!isPattern && util_1.isContextual(3 /* _async */)) {
if (isGenerator)
util_1.unexpected();
parseIdentifier();
if (tokenizer_1.match(8192 /* colon */) ||
tokenizer_1.match(6144 /* parenL */) ||
tokenizer_1.match(5120 /* braceR */) ||
tokenizer_1.match(14368 /* eq */) ||
tokenizer_1.match(7168 /* comma */)) {
// This is a key called "async" rather than an async function.
}
else {
this.parseMaybeAssign(false);
if (tokenizer_1.match(24587 /* star */)) {
tokenizer_1.next();
isGenerator = true;
}
parsePropertyName(contextId);
}
return;
}
// Since there's no colon, we assume this is an object shorthand.
// If we're in a destructuring, we've now discovered that the key was actually an assignee, so
// we need to tag it as a declaration with the appropriate scope. Otherwise, we might need to
// transform it on access, so mark it as an object shorthand.
if (isPattern) {
this.state.tokens[this.state.tokens.length - 1].identifierRole = isBlockScope
? tokenizer_1.IdentifierRole.BlockScopedDeclaration
: tokenizer_1.IdentifierRole.FunctionScopedDeclaration;
}
else {
this.state.tokens[this.state.tokens.length - 1].identifierRole =
tokenizer_1.IdentifierRole.ObjectShorthand;
parsePropertyName(contextId);
}
// Regardless of whether we know this to be a pattern or if we're in an ambiguous context, allow
// parsing as if there's a default value.
this.parseMaybeDefault(isBlockScope, true);
parseObjPropValue(isGenerator, isPattern, isBlockScope, contextId);
}
parseObjPropValue(isGenerator, isPattern, isBlockScope, objectContextId) {
const wasMethod = this.parseObjectMethod(isGenerator, isPattern, objectContextId);
if (!wasMethod) {
this.parseObjectProperty(isPattern, isBlockScope);
}
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = contextId;
}
exports.parseObj = parseObj;
function isGetterOrSetterMethod(isPattern) {
// We go off of the next and don't bother checking if the node key is actually "get" or "set".
// This lets us avoid generating a node, and should only make the validation worse.
return (!isPattern &&
(tokenizer_1.match(1536 /* string */) || // get "string"() {}
tokenizer_1.match(0 /* num */) || // get 1() {}
tokenizer_1.match(3072 /* bracketL */) || // get ["string"]() {}
tokenizer_1.match(2048 /* name */) || // get foo() {}
!!(base_1.state.type & 16 /* IS_KEYWORD */)) // get debugger() {}
);
}
// Returns true if this was a method.
function parseObjectMethod(isGenerator, isPattern, objectContextId) {
// We don't need to worry about modifiers because object methods can't have optional bodies, so
// the start will never be used.
const functionStart = base_1.state.start;
if (tokenizer_1.match(6144 /* parenL */)) {
if (isPattern)
util_1.unexpected();
parseMethod(functionStart, isGenerator, /* isConstructor */ false);
return true;
}
parsePropertyName(objectContextId) {
if (this.eat(types_1.types.bracketL)) {
this.state.tokens[this.state.tokens.length - 1].contextId = objectContextId;
this.parseMaybeAssign();
this.expect(types_1.types.bracketR);
this.state.tokens[this.state.tokens.length - 1].contextId = objectContextId;
if (isGetterOrSetterMethod(isPattern)) {
parsePropertyName(objectContextId);
parseMethod(functionStart, /* isGenerator */ false, /* isConstructor */ false);
return true;
}
return false;
}
function parseObjectProperty(isPattern, isBlockScope) {
if (tokenizer_1.eat(8192 /* colon */)) {
if (isPattern) {
lval_1.parseMaybeDefault(isBlockScope);
}
else {
if (this.match(types_1.types.num) || this.match(types_1.types.string)) {
this.parseExprAtom();
}
else {
this.parseMaybePrivateName();
}
this.state.tokens[this.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.ObjectKey;
this.state.tokens[this.state.tokens.length - 1].contextId = objectContextId;
parseMaybeAssign(false);
}
return;
}
// Parse object or class method.
parseMethod(functionStart, isGenerator, isConstructor) {
const funcContextId = this.nextContextId++;
const startTokenIndex = this.state.tokens.length;
const allowModifiers = isConstructor; // For TypeScript parameter properties
this.parseFunctionParams(allowModifiers, funcContextId);
this.parseFunctionBodyAndFinish(functionStart, isGenerator, null /* allowExpressionBody */, funcContextId);
const endTokenIndex = this.state.tokens.length;
this.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: true });
// Since there's no colon, we assume this is an object shorthand.
// If we're in a destructuring, we've now discovered that the key was actually an assignee, so
// we need to tag it as a declaration with the appropriate scope. Otherwise, we might need to
// transform it on access, so mark it as an object shorthand.
if (isPattern) {
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = isBlockScope
? tokenizer_1.IdentifierRole.BlockScopedDeclaration
: tokenizer_1.IdentifierRole.FunctionScopedDeclaration;
}
// Parse arrow function expression.
// If the parameters are provided, they will be converted to an
// assignable list.
parseArrowExpression(functionStart, startTokenIndex) {
this.parseFunctionBody(functionStart, false /* isGenerator */, true);
const endTokenIndex = this.state.tokens.length;
this.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: true });
else {
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.ObjectShorthand;
}
parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody = null, funcContextId) {
this.parseFunctionBody(functionStart, isGenerator, allowExpressionBody, funcContextId);
// Regardless of whether we know this to be a pattern or if we're in an ambiguous context, allow
// parsing as if there's a default value.
lval_1.parseMaybeDefault(isBlockScope, true);
}
function parseObjPropValue(isGenerator, isPattern, isBlockScope, objectContextId) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsStartParseObjPropValue();
}
// Parse function body and check parameters.
parseFunctionBody(functionStart, isGenerator, allowExpression, funcContextId) {
const isExpression = allowExpression && !this.match(types_1.types.braceL);
if (isExpression) {
this.parseMaybeAssign();
else if (base_1.hasPlugin("flow")) {
flow_1.flowStartParseObjPropValue();
}
const wasMethod = parseObjectMethod(isGenerator, isPattern, objectContextId);
if (!wasMethod) {
parseObjectProperty(isPattern, isBlockScope);
}
}
function parsePropertyName(objectContextId) {
if (base_1.hasPlugin("flow")) {
flow_1.flowParseVariance();
}
if (tokenizer_1.eat(3072 /* bracketL */)) {
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = objectContextId;
parseMaybeAssign();
util_1.expect(3584 /* bracketR */);
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = objectContextId;
}
else {
if (tokenizer_1.match(0 /* num */) || tokenizer_1.match(1536 /* string */)) {
parseExprAtom();
}
else {
this.parseBlock(true /* allowDirectives */, true /* isFunctionScope */, funcContextId);
parseMaybePrivateName();
}
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.ObjectKey;
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = objectContextId;
}
// Parses a comma-separated list of expressions, and returns them as
// an array. `close` is the token type that ends the list, and
// `allowEmpty` can be turned on to allow subsequent commas with
// nothing in between them to be parsed as `null` (which is needed
// for array literals).
parseExprList(close, allowEmpty = null) {
let first = true;
while (!this.eat(close)) {
if (first) {
first = false;
}
else {
this.expect(types_1.types.comma);
if (this.eat(close))
break;
}
this.parseExprListItem(allowEmpty);
}
}
exports.parsePropertyName = parsePropertyName;
// Parse object or class method.
function parseMethod(functionStart, isGenerator, isConstructor) {
const funcContextId = base_1.getNextContextId();
const startTokenIndex = base_1.state.tokens.length;
const allowModifiers = isConstructor; // For TypeScript parameter properties
statement_1.parseFunctionParams(allowModifiers, funcContextId);
parseFunctionBodyAndFinish(functionStart, isGenerator, null /* allowExpressionBody */, funcContextId);
const endTokenIndex = base_1.state.tokens.length;
base_1.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: true });
}
exports.parseMethod = parseMethod;
// Parse arrow function expression.
// If the parameters are provided, they will be converted to an
// assignable list.
function parseArrowExpression(functionStart, startTokenIndex) {
parseFunctionBody(functionStart, false /* isGenerator */, true);
const endTokenIndex = base_1.state.tokens.length;
base_1.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: true });
}
exports.parseArrowExpression = parseArrowExpression;
function parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody = null, funcContextId) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsParseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody, funcContextId);
}
parseExprListItem(allowEmpty) {
if (allowEmpty && this.match(types_1.types.comma)) {
// Empty item; nothing more to parse for this item.
else if (base_1.hasPlugin("flow")) {
flow_1.flowParseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody, funcContextId);
}
else {
parseFunctionBody(functionStart, isGenerator, allowExpressionBody, funcContextId);
}
}
exports.parseFunctionBodyAndFinish = parseFunctionBodyAndFinish;
// Parse function body and check parameters.
function parseFunctionBody(functionStart, isGenerator, allowExpression, funcContextId) {
const isExpression = allowExpression && !tokenizer_1.match(4096 /* braceL */);
if (isExpression) {
parseMaybeAssign();
}
else {
statement_1.parseBlock(true /* allowDirectives */, true /* isFunctionScope */, funcContextId);
}
}
exports.parseFunctionBody = parseFunctionBody;
// Parses a comma-separated list of expressions, and returns them as
// an array. `close` is the token type that ends the list, and
// `allowEmpty` can be turned on to allow subsequent commas with
// nothing in between them to be parsed as `null` (which is needed
// for array literals).
function parseExprList(close, allowEmpty = null) {
let first = true;
while (!tokenizer_1.eat(close)) {
if (first) {
first = false;
}
else if (this.match(types_1.types.ellipsis)) {
this.parseSpread();
}
else {
this.parseMaybeAssign(false, this.parseParenItem);
util_1.expect(7168 /* comma */);
if (tokenizer_1.eat(close))
break;
}
parseExprListItem(allowEmpty);
}
// Parse the next token as an identifier. If `liberal` is true (used
// when parsing properties), it will also convert keywords into
// identifiers.
parseIdentifier() {
this.next();
this.state.tokens[this.state.tokens.length - 1].type = types_1.types.name;
}
function parseExprListItem(allowEmpty) {
if (allowEmpty && tokenizer_1.match(7168 /* comma */)) {
// Empty item; nothing more to parse for this item.
}
// Parses await expression inside async function.
parseAwait() {
this.parseMaybeUnary();
else if (tokenizer_1.match(11776 /* ellipsis */)) {
lval_1.parseSpread();
}
// Parses yield expression inside generator.
parseYield() {
this.next();
if (!this.match(types_1.types.semi) && !this.canInsertSemicolon()) {
this.eat(types_1.types.star);
this.parseMaybeAssign();
}
else {
parseMaybeAssign(false, parseParenItem);
}
if (base_1.hasPlugin("flow") && tokenizer_1.match(8192 /* colon */)) {
flow_1.flowParseTypeAnnotation();
}
}
exports.default = ExpressionParser;
// Parse the next token as an identifier.
function parseIdentifier() {
tokenizer_1.next();
base_1.state.tokens[base_1.state.tokens.length - 1].type = 2048 /* name */;
}
exports.parseIdentifier = parseIdentifier;
// Parses await expression inside async function.
function parseAwait() {
parseMaybeUnary();
}
// Parses yield expression inside generator.
function parseYield() {
tokenizer_1.next();
if (!tokenizer_1.match(7680 /* semi */) && !util_1.canInsertSemicolon()) {
tokenizer_1.eat(24587 /* star */);
parseMaybeAssign();
}
}
import { File } from "../index";
import StatementParser from "./statement";
export declare type Pos = {
start: number;
};
export default class Parser extends StatementParser {
constructor(input: string, plugins: Array<string>);
parse(): File;
}
export declare function parseFile(): File;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tokenizer_1 = require("../tokenizer");
const base_1 = require("./base");
const statement_1 = require("./statement");
class Parser extends statement_1.default {
constructor(input, plugins) {
super(input);
this.input = input;
this.plugins = plugins.reduce((obj, p) => (Object.assign({}, obj, { [p]: true })), {});
// If enabled, skip leading hashbang line.
if (this.state.pos === 0 && this.input[0] === "#" && this.input[1] === "!") {
this.skipLineComment(2);
}
function parseFile() {
// If enabled, skip leading hashbang line.
if (base_1.state.pos === 0 && base_1.input[0] === "#" && base_1.input[1] === "!") {
tokenizer_1.skipLineComment(2);
}
parse() {
this.nextToken();
return this.parseTopLevel();
}
tokenizer_1.nextToken();
return statement_1.parseTopLevel();
}
exports.default = Parser;
exports.parseFile = parseFile;
import { TokenType } from "../tokenizer/types";
import UtilParser from "./util";
export default abstract class LValParser extends UtilParser {
abstract parseIdentifier(): void;
abstract parseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): void;
abstract parseObj(isPattern: boolean, isBlockScope: boolean): void;
abstract parseDecorator(): void;
parseSpread(): void;
parseRest(isBlockScope: boolean): void;
parseBindingIdentifier(): void;
parseBindingAtom(isBlockScope: boolean): void;
parseBindingList(close: TokenType, isBlockScope: boolean, allowEmpty?: boolean, allowModifiers?: boolean | null): void;
parseAssignableListItem(allowModifiers: boolean | null, isBlockScope: boolean): void;
parseAssignableListItemTypes(): void;
parseMaybeDefault(isBlockScope: boolean, leftAlreadyParsed?: boolean): void;
}
export declare function parseSpread(): void;
export declare function parseRest(isBlockScope: boolean): void;
export declare function parseBindingIdentifier(): void;
export declare function parseBindingAtom(isBlockScope: boolean): void;
export declare function parseBindingList(close: TokenType, isBlockScope: boolean, allowEmpty?: boolean, allowModifiers?: boolean | null): void;
export declare function parseMaybeDefault(isBlockScope: boolean, leftAlreadyParsed?: boolean): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const flow_1 = require("../plugins/flow");
const typescript_1 = require("../plugins/typescript");
const tokenizer_1 = require("../tokenizer");
const types_1 = require("../tokenizer/types");
const base_1 = require("./base");
const expression_1 = require("./expression");
const util_1 = require("./util");
class LValParser extends util_1.default {
// Parses spread element.
parseSpread() {
this.next();
this.parseMaybeAssign(false);
function parseSpread() {
tokenizer_1.next();
expression_1.parseMaybeAssign(false);
}
exports.parseSpread = parseSpread;
function parseRest(isBlockScope) {
tokenizer_1.next();
parseBindingAtom(isBlockScope);
}
exports.parseRest = parseRest;
function parseBindingIdentifier() {
expression_1.parseIdentifier();
}
exports.parseBindingIdentifier = parseBindingIdentifier;
// Parses lvalue (assignable) atom.
function parseBindingAtom(isBlockScope) {
switch (base_1.state.type) {
case 40464 /* _this */:
// In TypeScript, "this" may be the name of a parameter, so allow it.
tokenizer_1.runInTypeContext(0, () => {
tokenizer_1.next();
});
return;
case 43536 /* _yield */:
case 2048 /* name */: {
base_1.state.type = 2048 /* name */;
parseBindingIdentifier();
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = isBlockScope
? tokenizer_1.IdentifierRole.BlockScopedDeclaration
: tokenizer_1.IdentifierRole.FunctionScopedDeclaration;
return;
}
case 3072 /* bracketL */: {
tokenizer_1.next();
parseBindingList(3584 /* bracketR */, isBlockScope, true /* allowEmpty */);
return;
}
case 4096 /* braceL */:
expression_1.parseObj(true, isBlockScope);
return;
default:
throw util_1.unexpected();
}
parseRest(isBlockScope) {
this.next();
this.parseBindingAtom(isBlockScope);
}
parseBindingIdentifier() {
this.parseIdentifier();
}
// Parses lvalue (assignable) atom.
parseBindingAtom(isBlockScope) {
switch (this.state.type) {
case types_1.types._yield:
case types_1.types.name: {
this.state.type = types_1.types.name;
this.parseBindingIdentifier();
this.state.tokens[this.state.tokens.length - 1].identifierRole = isBlockScope
? tokenizer_1.IdentifierRole.BlockScopedDeclaration
: tokenizer_1.IdentifierRole.FunctionScopedDeclaration;
return;
}
case types_1.types.bracketL: {
this.next();
this.parseBindingList(types_1.types.bracketR, isBlockScope, true /* allowEmpty */);
return;
}
case types_1.types.braceL:
this.parseObj(true, isBlockScope);
return;
default:
throw this.unexpected();
}
exports.parseBindingAtom = parseBindingAtom;
function parseBindingList(close, isBlockScope, allowEmpty, allowModifiers = null) {
let first = true;
let hasRemovedComma = false;
const firstItemTokenIndex = base_1.state.tokens.length;
while (!tokenizer_1.eat(close)) {
if (first) {
first = false;
}
}
parseBindingList(close, isBlockScope, allowEmpty, allowModifiers = null) {
let first = true;
let hasRemovedComma = false;
const firstItemTokenIndex = this.state.tokens.length;
while (!this.eat(close)) {
if (first) {
first = false;
else {
util_1.expect(7168 /* comma */);
// After a "this" type in TypeScript, we need to set the following comma (if any) to also be
// a type token so that it will be removed.
if (!hasRemovedComma && base_1.state.tokens[firstItemTokenIndex].isType) {
base_1.state.tokens[base_1.state.tokens.length - 1].isType = true;
hasRemovedComma = true;
}
else {
this.expect(types_1.types.comma);
// After a "this" type in TypeScript, we need to set the following comma (if any) to also be
// a type token so that it will be removed.
if (!hasRemovedComma && this.state.tokens[firstItemTokenIndex].isType) {
this.state.tokens[this.state.tokens.length - 1].isType = true;
hasRemovedComma = true;
}
}
if (allowEmpty && this.match(types_1.types.comma)) {
// Empty item; nothing further to parse for this item.
}
else if (this.eat(close)) {
break;
}
else if (this.match(types_1.types.ellipsis)) {
this.parseRest(isBlockScope);
this.parseAssignableListItemTypes();
this.expect(close);
break;
}
else {
this.parseAssignableListItem(allowModifiers, isBlockScope);
}
}
}
parseAssignableListItem(allowModifiers, isBlockScope) {
this.parseMaybeDefault(isBlockScope);
this.parseAssignableListItemTypes();
this.parseMaybeDefault(isBlockScope, true /* leftAlreadyParsed */);
}
parseAssignableListItemTypes() { }
// Parses assignment pattern around given atom if possible.
parseMaybeDefault(isBlockScope, leftAlreadyParsed = false) {
if (!leftAlreadyParsed) {
this.parseBindingAtom(isBlockScope);
if (allowEmpty && tokenizer_1.match(7168 /* comma */)) {
// Empty item; nothing further to parse for this item.
}
if (!this.eat(types_1.types.eq)) {
return;
else if (tokenizer_1.eat(close)) {
break;
}
this.parseMaybeAssign();
else if (tokenizer_1.match(11776 /* ellipsis */)) {
parseRest(isBlockScope);
parseAssignableListItemTypes();
util_1.expect(close);
break;
}
else {
parseAssignableListItem(allowModifiers, isBlockScope);
}
}
}
exports.default = LValParser;
exports.parseBindingList = parseBindingList;
function parseAssignableListItem(allowModifiers, isBlockScope) {
if (allowModifiers) {
typescript_1.tsParseAccessModifier();
typescript_1.tsParseModifier([25 /* _readonly */]);
}
parseMaybeDefault(isBlockScope);
parseAssignableListItemTypes();
parseMaybeDefault(isBlockScope, true /* leftAlreadyParsed */);
}
function parseAssignableListItemTypes() {
if (base_1.hasPlugin("flow")) {
flow_1.flowParseAssignableListItemTypes();
}
else if (base_1.hasPlugin("typescript")) {
typescript_1.tsParseAssignableListItemTypes();
}
}
// Parses assignment pattern around given atom if possible.
function parseMaybeDefault(isBlockScope, leftAlreadyParsed = false) {
if (!leftAlreadyParsed) {
parseBindingAtom(isBlockScope);
}
if (!tokenizer_1.eat(14368 /* eq */)) {
return;
}
expression_1.parseMaybeAssign();
}
exports.parseMaybeDefault = parseMaybeDefault;
import { File } from "../index";
import { TokenType } from "../tokenizer/types";
import ExpressionParser from "./expression";
export default class StatementParser extends ExpressionParser {
parseTopLevel(): File;
parseStatement(declaration: boolean, topLevel?: boolean): void;
parseStatementContent(declaration: boolean, topLevel: boolean): void;
parseDecorators(): void;
parseDecorator(): void;
parseBreakContinueStatement(): void;
parseDebuggerStatement(): void;
parseDoStatement(): void;
parseForStatement(): void;
parseAmbiguousForStatement(): void;
parseFunctionStatement(): void;
parseIfStatement(): void;
parseReturnStatement(): void;
parseSwitchStatement(): void;
parseThrowStatement(): void;
parseTryStatement(): void;
parseVarStatement(kind: TokenType): void;
parseWhileStatement(): void;
parseEmptyStatement(): void;
parseLabeledStatement(): void;
/**
* Parse a statement starting with an identifier of the given name. Subclasses match on the name
* to handle statements like "declare".
*/
parseIdentifierStatement(name: string): void;
parseBlock(allowDirectives?: boolean, isFunctionScope?: boolean, contextId?: number): void;
parseBlockBody(topLevel: boolean, end: TokenType): void;
parseFor(): void;
parseForIn(forAwait: boolean): void;
parseVar(isFor: boolean, kind: TokenType): void;
parseVarHead(isBlockScope: boolean): void;
parseFunction(functionStart: number, isStatement: boolean, allowExpressionBody?: boolean, optionalId?: boolean): void;
parseFunctionParams(allowModifiers?: boolean, funcContextId?: number): void;
parseClass(isStatement: boolean, optionalId?: boolean): void;
isClassProperty(): boolean;
isClassMethod(): boolean;
parseClassBody(classContextId: number): void;
parseClassMember(memberStart: number, classContextId: number): void;
parseClassMemberWithIsStatic(memberStart: number, isStatic: boolean, classContextId: number): void;
parseClassMethod(functionStart: number, isGenerator: boolean, isConstructor: boolean): void;
parseClassPropertyName(classContextId: number): void;
parsePostMemberNameModifiers(): void;
parseClassProperty(): void;
parseClassId(isStatement: boolean, optionalId?: boolean): void;
parseClassSuper(): boolean;
parseExport(): void;
parseExportDefaultExpression(): void;
parseExportDeclaration(): void;
isExportDefaultSpecifier(): boolean;
parseExportSpecifiersMaybe(): void;
parseExportFrom(): void;
shouldParseExportStar(): boolean;
parseExportStar(): void;
parseExportNamespace(): void;
shouldParseExportDeclaration(): boolean;
parseExportSpecifiers(): void;
parseImport(): void;
shouldParseDefaultImport(): boolean;
parseImportSpecifierLocal(): void;
parseImportSpecifiers(): void;
parseImportSpecifier(): void;
}
export declare function parseTopLevel(): File;
export declare function parseStatement(declaration: boolean, topLevel?: boolean): void;
export declare function parseDecorators(): void;
export declare function parseVarStatement(kind: TokenType): void;
export declare function parseBlock(allowDirectives?: boolean, isFunctionScope?: boolean, contextId?: number): void;
export declare function parseBlockBody(topLevel: boolean, end: TokenType): void;
export declare function parseFunction(functionStart: number, isStatement: boolean, allowExpressionBody?: boolean, optionalId?: boolean): void;
export declare function parseFunctionParams(allowModifiers?: boolean, funcContextId?: number): void;
export declare function parseClass(isStatement: boolean, optionalId?: boolean): void;
export declare function parseClassPropertyName(classContextId: number): void;
export declare function parsePostMemberNameModifiers(): void;
export declare function parseClassProperty(): void;
export declare function parseExport(): void;
export declare function parseExportFrom(): void;
export declare function baseParseExportStar(): void;
export declare function parseExportSpecifiers(): void;
export declare function parseImport(): void;
"use strict";
/* eslint max-len: 0 */
Object.defineProperty(exports, "__esModule", { value: true });
const flow_1 = require("../plugins/flow");
const typescript_1 = require("../plugins/typescript");
const tokenizer_1 = require("../tokenizer");
const types_1 = require("../tokenizer/types");
const base_1 = require("./base");
const expression_1 = require("./expression");
class StatementParser extends expression_1.default {
// ### Statement parsing
parseTopLevel() {
this.parseBlockBody(true, types_1.types.eof);
this.state.scopes.push({
startTokenIndex: 0,
endTokenIndex: this.state.tokens.length,
isFunctionScope: true,
});
return {
tokens: this.state.tokens,
scopes: this.state.scopes,
};
const lval_1 = require("./lval");
const util_1 = require("./util");
function parseTopLevel() {
parseBlockBody(true, 2560 /* eof */);
base_1.state.scopes.push({
startTokenIndex: 0,
endTokenIndex: base_1.state.tokens.length,
isFunctionScope: true,
});
return {
tokens: base_1.state.tokens,
scopes: base_1.state.scopes,
};
}
exports.parseTopLevel = parseTopLevel;
// Parse a single statement.
//
// If expecting a statement and finding a slash operator, parse a
// regular expression literal. This is to handle cases like
// `if (foo) /blah/.exec(foo)`, where looking at the previous token
// does not help.
function parseStatement(declaration, topLevel = false) {
if (base_1.hasPlugin("flow")) {
if (flow_1.flowTryParseStatement()) {
return;
}
}
// Parse a single statement.
//
// If expecting a statement and finding a slash operator, parse a
// regular expression literal. This is to handle cases like
// `if (foo) /blah/.exec(foo)`, where looking at the previous token
// does not help.
parseStatement(declaration, topLevel = false) {
if (this.match(types_1.types.at)) {
this.parseDecorators();
if (tokenizer_1.match(13312 /* at */)) {
parseDecorators();
}
parseStatementContent(declaration, topLevel);
}
exports.parseStatement = parseStatement;
function parseStatementContent(declaration, topLevel) {
if (base_1.hasPlugin("typescript")) {
if (typescript_1.tsTryParseStatementContent()) {
return;
}
this.parseStatementContent(declaration, topLevel);
}
parseStatementContent(declaration, topLevel) {
const starttype = this.state.type;
// Most types of statements are recognized by the keyword they
// start with. Many are trivial to parse, some require a bit of
// complexity.
switch (starttype) {
case types_1.types._break:
case types_1.types._continue:
this.parseBreakContinueStatement();
return;
case types_1.types._debugger:
this.parseDebuggerStatement();
return;
case types_1.types._do:
this.parseDoStatement();
return;
case types_1.types._for:
this.parseForStatement();
return;
case types_1.types._function:
if (this.lookaheadType() === types_1.types.dot)
break;
if (!declaration)
this.unexpected();
this.parseFunctionStatement();
return;
case types_1.types._class:
if (!declaration)
this.unexpected();
this.parseClass(true);
return;
case types_1.types._if:
this.parseIfStatement();
return;
case types_1.types._return:
this.parseReturnStatement();
return;
case types_1.types._switch:
this.parseSwitchStatement();
return;
case types_1.types._throw:
this.parseThrowStatement();
return;
case types_1.types._try:
this.parseTryStatement();
return;
case types_1.types._let:
case types_1.types._const:
if (!declaration)
this.unexpected(); // NOTE: falls through to _var
case types_1.types._var:
this.parseVarStatement(starttype);
return;
case types_1.types._while:
this.parseWhileStatement();
return;
case types_1.types.braceL:
this.parseBlock();
return;
case types_1.types.semi:
this.parseEmptyStatement();
return;
case types_1.types._export:
case types_1.types._import: {
const nextType = this.lookaheadType();
if (nextType === types_1.types.parenL || nextType === types_1.types.dot) {
break;
const starttype = base_1.state.type;
// Most types of statements are recognized by the keyword they
// start with. Many are trivial to parse, some require a bit of
// complexity.
switch (starttype) {
case 29200 /* _break */:
case 30736 /* _continue */:
parseBreakContinueStatement();
return;
case 31248 /* _debugger */:
parseDebuggerStatement();
return;
case 32272 /* _do */:
parseDoStatement();
return;
case 33808 /* _for */:
parseForStatement();
return;
case 34320 /* _function */:
if (tokenizer_1.lookaheadType() === 9216 /* dot */)
break;
if (!declaration)
util_1.unexpected();
parseFunctionStatement();
return;
case 41488 /* _class */:
if (!declaration)
util_1.unexpected();
parseClass(true);
return;
case 34832 /* _if */:
parseIfStatement();
return;
case 35344 /* _return */:
parseReturnStatement();
return;
case 35856 /* _switch */:
parseSwitchStatement();
return;
case 36496 /* _throw */:
parseThrowStatement();
return;
case 36880 /* _try */:
parseTryStatement();
return;
case 37904 /* _let */:
case 38416 /* _const */:
if (!declaration)
util_1.unexpected(); // NOTE: falls through to _var
case 37392 /* _var */:
parseVarStatement(starttype);
return;
case 38928 /* _while */:
parseWhileStatement();
return;
case 4096 /* braceL */:
parseBlock();
return;
case 7680 /* semi */:
parseEmptyStatement();
return;
case 42512 /* _export */:
case 43024 /* _import */: {
const nextType = tokenizer_1.lookaheadType();
if (nextType === 6144 /* parenL */ || nextType === 9216 /* dot */) {
break;
}
tokenizer_1.next();
if (starttype === 43024 /* _import */) {
parseImport();
}
else {
parseExport();
}
return;
}
case 2048 /* name */:
if (base_1.state.contextualKeyword === 3 /* _async */) {
const functionStart = base_1.state.start;
// peek ahead and see if next token is a function
const snapshot = base_1.state.snapshot();
tokenizer_1.next();
if (tokenizer_1.match(34320 /* _function */) && !util_1.canInsertSemicolon()) {
util_1.expect(34320 /* _function */);
parseFunction(functionStart, true, false);
return;
}
this.next();
if (starttype === types_1.types._import) {
this.parseImport();
}
else {
this.parseExport();
base_1.state.restoreFromSnapshot(snapshot);
}
return;
}
case types_1.types.name:
if (this.state.value === "async") {
const functionStart = this.state.start;
// peek ahead and see if next token is a function
const snapshot = this.state.snapshot();
this.next();
if (this.match(types_1.types._function) && !this.canInsertSemicolon()) {
this.expect(types_1.types._function);
this.parseFunction(functionStart, true, false);
return;
}
else {
this.state.restoreFromSnapshot(snapshot);
}
}
default:
// Do nothing.
break;
}
// If the statement does not start with a statement keyword or a
// brace, it's an ExpressionStatement or LabeledStatement. We
// simply start parsing an expression, and afterwards, if the
// next token is a colon and the expression was a simple
// Identifier node, we switch to interpreting it as a label.
const initialTokensLength = this.state.tokens.length;
this.parseExpression();
let simpleName = null;
if (this.state.tokens.length === initialTokensLength + 1) {
const token = this.state.tokens[this.state.tokens.length - 1];
if (token.type === types_1.types.name) {
simpleName = token.value;
}
}
if (simpleName == null) {
this.semicolon();
return;
}
if (this.eat(types_1.types.colon)) {
this.parseLabeledStatement();
}
else {
// This was an identifier, so we might want to handle flow/typescript-specific cases.
this.parseIdentifierStatement(simpleName);
}
default:
// Do nothing.
break;
}
parseDecorators() {
while (this.match(types_1.types.at)) {
this.parseDecorator();
// If the statement does not start with a statement keyword or a
// brace, it's an ExpressionStatement or LabeledStatement. We
// simply start parsing an expression, and afterwards, if the
// next token is a colon and the expression was a simple
// Identifier node, we switch to interpreting it as a label.
const initialTokensLength = base_1.state.tokens.length;
expression_1.parseExpression();
let simpleName = null;
if (base_1.state.tokens.length === initialTokensLength + 1) {
const token = base_1.state.tokens[base_1.state.tokens.length - 1];
if (token.type === 2048 /* name */) {
simpleName = token.contextualKeyword;
}
}
parseDecorator() {
this.next();
this.parseIdentifier();
while (this.eat(types_1.types.dot)) {
this.parseIdentifier();
}
if (this.eat(types_1.types.parenL)) {
this.parseCallExpressionArguments(types_1.types.parenR);
}
if (simpleName == null) {
util_1.semicolon();
return;
}
parseBreakContinueStatement() {
this.next();
if (!this.isLineTerminator()) {
this.parseIdentifier();
this.semicolon();
}
if (tokenizer_1.eat(8192 /* colon */)) {
parseLabeledStatement();
}
parseDebuggerStatement() {
this.next();
this.semicolon();
else {
// This was an identifier, so we might want to handle flow/typescript-specific cases.
parseIdentifierStatement(simpleName);
}
parseDoStatement() {
this.next();
this.parseStatement(false);
this.expect(types_1.types._while);
this.parseParenExpression();
this.eat(types_1.types.semi);
}
function parseDecorators() {
while (tokenizer_1.match(13312 /* at */)) {
parseDecorator();
}
parseForStatement() {
const startTokenIndex = this.state.tokens.length;
this.parseAmbiguousForStatement();
const endTokenIndex = this.state.tokens.length;
this.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: false });
}
exports.parseDecorators = parseDecorators;
function parseDecorator() {
tokenizer_1.next();
expression_1.parseIdentifier();
while (tokenizer_1.eat(9216 /* dot */)) {
expression_1.parseIdentifier();
}
// Disambiguating between a `for` and a `for`/`in` or `for`/`of`
// loop is non-trivial. Basically, we have to parse the init `var`
// statement or expression, disallowing the `in` operator (see
// the second parameter to `parseExpression`), and then check
// whether the next token is `in` or `of`. When there is no init
// part (semicolon immediately after the opening parenthesis), it
// is a regular `for` loop.
parseAmbiguousForStatement() {
this.next();
let forAwait = false;
if (this.isContextual("await")) {
forAwait = true;
this.next();
if (tokenizer_1.eat(6144 /* parenL */)) {
expression_1.parseCallExpressionArguments(6656 /* parenR */);
}
}
function parseBreakContinueStatement() {
tokenizer_1.next();
if (!util_1.isLineTerminator()) {
expression_1.parseIdentifier();
util_1.semicolon();
}
}
function parseDebuggerStatement() {
tokenizer_1.next();
util_1.semicolon();
}
function parseDoStatement() {
tokenizer_1.next();
parseStatement(false);
util_1.expect(38928 /* _while */);
expression_1.parseParenExpression();
tokenizer_1.eat(7680 /* semi */);
}
function parseForStatement() {
const startTokenIndex = base_1.state.tokens.length;
parseAmbiguousForStatement();
const endTokenIndex = base_1.state.tokens.length;
base_1.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: false });
}
// Disambiguating between a `for` and a `for`/`in` or `for`/`of`
// loop is non-trivial. Basically, we have to parse the init `var`
// statement or expression, disallowing the `in` operator (see
// the second parameter to `parseExpression`), and then check
// whether the next token is `in` or `of`. When there is no init
// part (semicolon immediately after the opening parenthesis), it
// is a regular `for` loop.
function parseAmbiguousForStatement() {
tokenizer_1.next();
let forAwait = false;
if (util_1.isContextual(4 /* _await */)) {
forAwait = true;
tokenizer_1.next();
}
util_1.expect(6144 /* parenL */);
if (tokenizer_1.match(7680 /* semi */)) {
if (forAwait) {
util_1.unexpected();
}
this.expect(types_1.types.parenL);
if (this.match(types_1.types.semi)) {
if (forAwait) {
this.unexpected();
}
this.parseFor();
parseFor();
return;
}
if (tokenizer_1.match(37392 /* _var */) || tokenizer_1.match(37904 /* _let */) || tokenizer_1.match(38416 /* _const */)) {
const varKind = base_1.state.type;
tokenizer_1.next();
parseVar(true, varKind);
if (tokenizer_1.match(45592 /* _in */) || util_1.isContextual(20 /* _of */)) {
parseForIn(forAwait);
return;
}
if (this.match(types_1.types._var) || this.match(types_1.types._let) || this.match(types_1.types._const)) {
const varKind = this.state.type;
this.next();
this.parseVar(true, varKind);
if (this.match(types_1.types._in) || this.isContextual("of")) {
this.parseForIn(forAwait);
return;
}
this.parseFor();
return;
}
this.parseExpression(true);
if (this.match(types_1.types._in) || this.isContextual("of")) {
this.parseForIn(forAwait);
return;
}
if (forAwait) {
this.unexpected();
}
this.parseFor();
parseFor();
return;
}
parseFunctionStatement() {
const functionStart = this.state.start;
this.next();
this.parseFunction(functionStart, true);
expression_1.parseExpression(true);
if (tokenizer_1.match(45592 /* _in */) || util_1.isContextual(20 /* _of */)) {
parseForIn(forAwait);
return;
}
parseIfStatement() {
this.next();
this.parseParenExpression();
this.parseStatement(false);
if (this.eat(types_1.types._else)) {
this.parseStatement(false);
}
if (forAwait) {
util_1.unexpected();
}
parseReturnStatement() {
this.next();
// In `return` (and `break`/`continue`), the keywords with
// optional arguments, we eagerly look for a semicolon or the
// possibility to insert one.
if (!this.isLineTerminator()) {
this.parseExpression();
this.semicolon();
}
parseFor();
}
function parseFunctionStatement() {
const functionStart = base_1.state.start;
tokenizer_1.next();
parseFunction(functionStart, true);
}
function parseIfStatement() {
tokenizer_1.next();
expression_1.parseParenExpression();
parseStatement(false);
if (tokenizer_1.eat(32784 /* _else */)) {
parseStatement(false);
}
parseSwitchStatement() {
this.next();
this.parseParenExpression();
const startTokenIndex = this.state.tokens.length;
this.expect(types_1.types.braceL);
// Don't bother validation; just go through any sequence of cases, defaults, and statements.
while (!this.match(types_1.types.braceR)) {
if (this.match(types_1.types._case) || this.match(types_1.types._default)) {
const isCase = this.match(types_1.types._case);
this.next();
if (isCase) {
this.parseExpression();
}
this.expect(types_1.types.colon);
}
function parseReturnStatement() {
tokenizer_1.next();
// In `return` (and `break`/`continue`), the keywords with
// optional arguments, we eagerly look for a semicolon or the
// possibility to insert one.
if (!util_1.isLineTerminator()) {
expression_1.parseExpression();
util_1.semicolon();
}
}
function parseSwitchStatement() {
tokenizer_1.next();
expression_1.parseParenExpression();
const startTokenIndex = base_1.state.tokens.length;
util_1.expect(4096 /* braceL */);
// Don't bother validation; just go through any sequence of cases, defaults, and statements.
while (!tokenizer_1.match(5120 /* braceR */)) {
if (tokenizer_1.match(29712 /* _case */) || tokenizer_1.match(31760 /* _default */)) {
const isCase = tokenizer_1.match(29712 /* _case */);
tokenizer_1.next();
if (isCase) {
expression_1.parseExpression();
}
else {
this.parseStatement(true);
}
util_1.expect(8192 /* colon */);
}
this.next(); // Closing brace
const endTokenIndex = this.state.tokens.length;
this.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: false });
else {
parseStatement(true);
}
}
parseThrowStatement() {
this.next();
this.parseExpression();
this.semicolon();
}
parseTryStatement() {
this.next();
this.parseBlock();
if (this.match(types_1.types._catch)) {
this.next();
let catchBindingStartTokenIndex = null;
if (this.match(types_1.types.parenL)) {
catchBindingStartTokenIndex = this.state.tokens.length;
this.expect(types_1.types.parenL);
this.parseBindingAtom(true /* isBlockScope */);
this.expect(types_1.types.parenR);
}
this.parseBlock();
if (catchBindingStartTokenIndex != null) {
// We need a special scope for the catch binding which includes the binding itself and the
// catch block.
const endTokenIndex = this.state.tokens.length;
this.state.scopes.push({
startTokenIndex: catchBindingStartTokenIndex,
endTokenIndex,
isFunctionScope: false,
});
}
tokenizer_1.next(); // Closing brace
const endTokenIndex = base_1.state.tokens.length;
base_1.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: false });
}
function parseThrowStatement() {
tokenizer_1.next();
expression_1.parseExpression();
util_1.semicolon();
}
function parseTryStatement() {
tokenizer_1.next();
parseBlock();
if (tokenizer_1.match(30224 /* _catch */)) {
tokenizer_1.next();
let catchBindingStartTokenIndex = null;
if (tokenizer_1.match(6144 /* parenL */)) {
catchBindingStartTokenIndex = base_1.state.tokens.length;
util_1.expect(6144 /* parenL */);
lval_1.parseBindingAtom(true /* isBlockScope */);
util_1.expect(6656 /* parenR */);
}
if (this.eat(types_1.types._finally)) {
this.parseBlock();
parseBlock();
if (catchBindingStartTokenIndex != null) {
// We need a special scope for the catch binding which includes the binding itself and the
// catch block.
const endTokenIndex = base_1.state.tokens.length;
base_1.state.scopes.push({
startTokenIndex: catchBindingStartTokenIndex,
endTokenIndex,
isFunctionScope: false,
});
}
}
parseVarStatement(kind) {
this.next();
this.parseVar(false, kind);
this.semicolon();
if (tokenizer_1.eat(33296 /* _finally */)) {
parseBlock();
}
parseWhileStatement() {
this.next();
this.parseParenExpression();
this.parseStatement(false);
}
function parseVarStatement(kind) {
tokenizer_1.next();
parseVar(false, kind);
util_1.semicolon();
}
exports.parseVarStatement = parseVarStatement;
function parseWhileStatement() {
tokenizer_1.next();
expression_1.parseParenExpression();
parseStatement(false);
}
function parseEmptyStatement() {
tokenizer_1.next();
}
function parseLabeledStatement() {
parseStatement(true);
}
/**
* Parse a statement starting with an identifier of the given name. Subclasses match on the name
* to handle statements like "declare".
*/
function parseIdentifierStatement(contextualKeyword) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsParseIdentifierStatement(contextualKeyword);
}
parseEmptyStatement() {
this.next();
else if (base_1.hasPlugin("flow")) {
flow_1.flowParseIdentifierStatement(contextualKeyword);
}
parseLabeledStatement() {
this.parseStatement(true);
else {
util_1.semicolon();
}
/**
* Parse a statement starting with an identifier of the given name. Subclasses match on the name
* to handle statements like "declare".
*/
parseIdentifierStatement(name) {
this.semicolon();
}
// Parse a semicolon-enclosed block of statements, handling `"use
// strict"` declarations when `allowStrict` is true (used for
// function bodies).
function parseBlock(allowDirectives = false, isFunctionScope = false, contextId) {
const startTokenIndex = base_1.state.tokens.length;
util_1.expect(4096 /* braceL */);
if (contextId) {
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = contextId;
}
// Parse a semicolon-enclosed block of statements, handling `"use
// strict"` declarations when `allowStrict` is true (used for
// function bodies).
parseBlock(allowDirectives = false, isFunctionScope = false, contextId) {
const startTokenIndex = this.state.tokens.length;
this.expect(types_1.types.braceL);
if (contextId) {
this.state.tokens[this.state.tokens.length - 1].contextId = contextId;
}
this.parseBlockBody(false, types_1.types.braceR);
if (contextId) {
this.state.tokens[this.state.tokens.length - 1].contextId = contextId;
}
const endTokenIndex = this.state.tokens.length;
this.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope });
parseBlockBody(false, 5120 /* braceR */);
if (contextId) {
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = contextId;
}
parseBlockBody(topLevel, end) {
while (!this.eat(end)) {
this.parseStatement(true, topLevel);
}
const endTokenIndex = base_1.state.tokens.length;
base_1.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope });
}
exports.parseBlock = parseBlock;
function parseBlockBody(topLevel, end) {
while (!tokenizer_1.eat(end)) {
parseStatement(true, topLevel);
}
// Parse a regular `for` loop. The disambiguation code in
// `parseStatement` will already have parsed the init statement or
// expression.
parseFor() {
this.expect(types_1.types.semi);
if (!this.match(types_1.types.semi)) {
this.parseExpression();
}
this.expect(types_1.types.semi);
if (!this.match(types_1.types.parenR)) {
this.parseExpression();
}
this.expect(types_1.types.parenR);
this.parseStatement(false);
}
exports.parseBlockBody = parseBlockBody;
// Parse a regular `for` loop. The disambiguation code in
// `parseStatement` will already have parsed the init statement or
// expression.
function parseFor() {
util_1.expect(7680 /* semi */);
if (!tokenizer_1.match(7680 /* semi */)) {
expression_1.parseExpression();
}
// Parse a `for`/`in` and `for`/`of` loop, which are almost
// same from parser's perspective.
parseForIn(forAwait) {
if (forAwait) {
this.eatContextual("of");
}
else {
this.next();
}
this.parseExpression();
this.expect(types_1.types.parenR);
this.parseStatement(false);
util_1.expect(7680 /* semi */);
if (!tokenizer_1.match(6656 /* parenR */)) {
expression_1.parseExpression();
}
// Parse a list of variable declarations.
parseVar(isFor, kind) {
while (true) {
const isBlockScope = kind === types_1.types._const || kind === types_1.types._let;
this.parseVarHead(isBlockScope);
if (this.eat(types_1.types.eq)) {
this.parseMaybeAssign(isFor);
}
if (!this.eat(types_1.types.comma))
break;
}
util_1.expect(6656 /* parenR */);
parseStatement(false);
}
// Parse a `for`/`in` and `for`/`of` loop, which are almost
// same from parser's perspective.
function parseForIn(forAwait) {
if (forAwait) {
util_1.eatContextual(20 /* _of */);
}
parseVarHead(isBlockScope) {
this.parseBindingAtom(isBlockScope);
else {
tokenizer_1.next();
}
// Parse a function declaration or literal (depending on the
// `isStatement` parameter).
parseFunction(functionStart, isStatement, allowExpressionBody, optionalId) {
let isGenerator = false;
if (this.match(types_1.types.star)) {
isGenerator = true;
this.next();
expression_1.parseExpression();
util_1.expect(6656 /* parenR */);
parseStatement(false);
}
// Parse a list of variable declarations.
function parseVar(isFor, kind) {
while (true) {
const isBlockScope = kind === 38416 /* _const */ || kind === 37904 /* _let */;
parseVarHead(isBlockScope);
if (tokenizer_1.eat(14368 /* eq */)) {
expression_1.parseMaybeAssign(isFor);
}
if (isStatement && !optionalId && !this.match(types_1.types.name) && !this.match(types_1.types._yield)) {
this.unexpected();
}
let nameScopeStartTokenIndex = null;
if (this.match(types_1.types.name)) {
// Expression-style functions should limit their name's scope to the function body, so we make
// a new function scope to enforce that.
if (!isStatement) {
nameScopeStartTokenIndex = this.state.tokens.length;
}
this.parseBindingIdentifier();
this.state.tokens[this.state.tokens.length - 1].identifierRole =
tokenizer_1.IdentifierRole.FunctionScopedDeclaration;
}
const startTokenIndex = this.state.tokens.length;
this.parseFunctionParams();
this.parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody);
const endTokenIndex = this.state.tokens.length;
// In addition to the block scope of the function body, we need a separate function-style scope
// that includes the params.
this.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: true });
if (nameScopeStartTokenIndex !== null) {
this.state.scopes.push({
startTokenIndex: nameScopeStartTokenIndex,
endTokenIndex,
isFunctionScope: true,
});
}
if (!tokenizer_1.eat(7168 /* comma */))
break;
}
parseFunctionParams(allowModifiers, funcContextId) {
this.expect(types_1.types.parenL);
if (funcContextId) {
this.state.tokens[this.state.tokens.length - 1].contextId = funcContextId;
}
this.parseBindingList(types_1.types.parenR, false /* isBlockScope */, false /* allowEmpty */, allowModifiers);
if (funcContextId) {
this.state.tokens[this.state.tokens.length - 1].contextId = funcContextId;
}
}
function parseVarHead(isBlockScope) {
lval_1.parseBindingAtom(isBlockScope);
if (base_1.hasPlugin("typescript")) {
typescript_1.tsAfterParseVarHead();
}
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
parseClass(isStatement, optionalId = false) {
// Put a context ID on the class keyword, the open-brace, and the close-brace, so that later
// code can easily navigate to meaningful points on the class.
const contextId = this.nextContextId++;
this.next();
this.state.tokens[this.state.tokens.length - 1].contextId = contextId;
this.state.tokens[this.state.tokens.length - 1].isExpression = !isStatement;
// Like with functions, we declare a special "name scope" from the start of the name to the end
// of the class, but only with expression-style classes, to represent the fact that the name is
// available to the body of the class but not an outer declaration.
let nameScopeStartTokenIndex = null;
else if (base_1.hasPlugin("flow")) {
flow_1.flowAfterParseVarHead();
}
}
// Parse a function declaration or literal (depending on the
// `isStatement` parameter).
function parseFunction(functionStart, isStatement, allowExpressionBody, optionalId) {
let isGenerator = false;
if (tokenizer_1.match(24587 /* star */)) {
isGenerator = true;
tokenizer_1.next();
}
if (isStatement && !optionalId && !tokenizer_1.match(2048 /* name */) && !tokenizer_1.match(43536 /* _yield */)) {
util_1.unexpected();
}
let nameScopeStartTokenIndex = null;
if (tokenizer_1.match(2048 /* name */)) {
// Expression-style functions should limit their name's scope to the function body, so we make
// a new function scope to enforce that.
if (!isStatement) {
nameScopeStartTokenIndex = this.state.tokens.length;
nameScopeStartTokenIndex = base_1.state.tokens.length;
}
this.parseClassId(isStatement, optionalId);
this.parseClassSuper();
const openBraceIndex = this.state.tokens.length;
this.parseClassBody(contextId);
this.state.tokens[openBraceIndex].contextId = contextId;
this.state.tokens[this.state.tokens.length - 1].contextId = contextId;
if (nameScopeStartTokenIndex !== null) {
const endTokenIndex = this.state.tokens.length;
this.state.scopes.push({
startTokenIndex: nameScopeStartTokenIndex,
endTokenIndex,
isFunctionScope: false,
});
}
lval_1.parseBindingIdentifier();
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.FunctionScopedDeclaration;
}
isClassProperty() {
return this.match(types_1.types.eq) || this.match(types_1.types.semi) || this.match(types_1.types.braceR);
const startTokenIndex = base_1.state.tokens.length;
parseFunctionParams();
expression_1.parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody);
const endTokenIndex = base_1.state.tokens.length;
// In addition to the block scope of the function body, we need a separate function-style scope
// that includes the params.
base_1.state.scopes.push({ startTokenIndex, endTokenIndex, isFunctionScope: true });
if (nameScopeStartTokenIndex !== null) {
base_1.state.scopes.push({
startTokenIndex: nameScopeStartTokenIndex,
endTokenIndex,
isFunctionScope: true,
});
}
isClassMethod() {
return this.match(types_1.types.parenL);
}
exports.parseFunction = parseFunction;
function parseFunctionParams(allowModifiers, funcContextId) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsStartParseFunctionParams();
}
parseClassBody(classContextId) {
this.expect(types_1.types.braceL);
while (!this.eat(types_1.types.braceR)) {
if (this.eat(types_1.types.semi)) {
continue;
}
if (this.match(types_1.types.at)) {
this.parseDecorator();
continue;
}
const memberStart = this.state.start;
this.parseClassMember(memberStart, classContextId);
}
else if (base_1.hasPlugin("flow")) {
flow_1.flowStartParseFunctionParams();
}
parseClassMember(memberStart, classContextId) {
let isStatic = false;
if (this.match(types_1.types.name) && this.state.value === "static") {
this.parseIdentifier(); // eats 'static'
if (this.isClassMethod()) {
this.parseClassMethod(memberStart, false, /* isConstructor */ false);
return;
}
else if (this.isClassProperty()) {
this.parseClassProperty();
return;
}
// otherwise something static
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._static;
isStatic = true;
util_1.expect(6144 /* parenL */);
if (funcContextId) {
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = funcContextId;
}
lval_1.parseBindingList(6656 /* parenR */, false /* isBlockScope */, false /* allowEmpty */, allowModifiers);
if (funcContextId) {
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = funcContextId;
}
}
exports.parseFunctionParams = parseFunctionParams;
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
function parseClass(isStatement, optionalId = false) {
// Put a context ID on the class keyword, the open-brace, and the close-brace, so that later
// code can easily navigate to meaningful points on the class.
const contextId = base_1.getNextContextId();
tokenizer_1.next();
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = contextId;
base_1.state.tokens[base_1.state.tokens.length - 1].isExpression = !isStatement;
// Like with functions, we declare a special "name scope" from the start of the name to the end
// of the class, but only with expression-style classes, to represent the fact that the name is
// available to the body of the class but not an outer declaration.
let nameScopeStartTokenIndex = null;
if (!isStatement) {
nameScopeStartTokenIndex = base_1.state.tokens.length;
}
parseClassId(isStatement, optionalId);
parseClassSuper();
const openBraceIndex = base_1.state.tokens.length;
parseClassBody(contextId);
base_1.state.tokens[openBraceIndex].contextId = contextId;
base_1.state.tokens[base_1.state.tokens.length - 1].contextId = contextId;
if (nameScopeStartTokenIndex !== null) {
const endTokenIndex = base_1.state.tokens.length;
base_1.state.scopes.push({
startTokenIndex: nameScopeStartTokenIndex,
endTokenIndex,
isFunctionScope: false,
});
}
}
exports.parseClass = parseClass;
function isClassProperty() {
return tokenizer_1.match(14368 /* eq */) || tokenizer_1.match(7680 /* semi */) || tokenizer_1.match(5120 /* braceR */) || tokenizer_1.match(8192 /* colon */);
}
function isClassMethod() {
return tokenizer_1.match(6144 /* parenL */) || tokenizer_1.match(21000 /* lessThan */);
}
function parseClassBody(classContextId) {
util_1.expect(4096 /* braceL */);
while (!tokenizer_1.eat(5120 /* braceR */)) {
if (tokenizer_1.eat(7680 /* semi */)) {
continue;
}
this.parseClassMemberWithIsStatic(memberStart, isStatic, classContextId);
if (tokenizer_1.match(13312 /* at */)) {
parseDecorator();
continue;
}
const memberStart = base_1.state.start;
parseClassMember(memberStart, classContextId);
}
parseClassMemberWithIsStatic(memberStart, isStatic, classContextId) {
if (this.eat(types_1.types.star)) {
// a generator
this.parseClassPropertyName(classContextId);
this.parseClassMethod(memberStart, true, /* isConstructor */ false);
}
function parseClassMember(memberStart, classContextId) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsParseAccessModifier();
}
let isStatic = false;
if (tokenizer_1.match(2048 /* name */) && base_1.state.contextualKeyword === 27 /* _static */) {
expression_1.parseIdentifier(); // eats 'static'
if (isClassMethod()) {
parseClassMethod(memberStart, false, /* isConstructor */ false);
return;
}
// Get the identifier name so we can tell if it's actually a keyword like "async", "get", or
// "set".
this.parseClassPropertyName(classContextId);
let simpleName = null;
let isConstructor = false;
const token = this.state.tokens[this.state.tokens.length - 1];
if (token.type === types_1.types.name) {
simpleName = token.value;
else if (isClassProperty()) {
parseClassProperty();
return;
}
// We allow "constructor" as either an identifier or a string.
if (token.value === "constructor") {
isConstructor = true;
// otherwise something static
base_1.state.tokens[base_1.state.tokens.length - 1].type = 51216 /* _static */;
isStatic = true;
}
parseClassMemberWithIsStatic(memberStart, isStatic, classContextId);
}
function parseClassMemberWithIsStatic(memberStart, isStatic, classContextId) {
if (base_1.hasPlugin("typescript")) {
if (typescript_1.tsTryParseClassMemberWithIsStatic(isStatic, classContextId)) {
return;
}
this.parsePostMemberNameModifiers();
if (this.isClassMethod()) {
this.parseClassMethod(memberStart, false, isConstructor);
}
else if (this.isClassProperty()) {
this.parseClassProperty();
}
else if (simpleName === "async" && !this.isLineTerminator()) {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._async;
// an async method
const isGenerator = this.match(types_1.types.star);
if (isGenerator) {
this.next();
}
// The so-called parsed name would have been "async": get the real name.
this.parseClassPropertyName(classContextId);
this.parseClassMethod(memberStart, isGenerator, false /* isConstructor */);
}
else if ((simpleName === "get" || simpleName === "set") &&
!(this.isLineTerminator() && this.match(types_1.types.star))) {
if (simpleName === "get") {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._get;
}
else {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._set;
}
// `get\n*` is an uninitialized property named 'get' followed by a generator.
// a getter or setter
// The so-called parsed name would have been "get/set": get the real name.
this.parseClassPropertyName(classContextId);
this.parseClassMethod(memberStart, false, /* isConstructor */ false);
}
else if (this.isLineTerminator()) {
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
this.parseClassProperty();
}
else {
this.unexpected();
}
}
parseClassMethod(functionStart, isGenerator, isConstructor) {
this.parseMethod(functionStart, isGenerator, isConstructor);
if (tokenizer_1.eat(24587 /* star */)) {
// a generator
parseClassPropertyName(classContextId);
parseClassMethod(memberStart, true, /* isConstructor */ false);
return;
}
// Return the name of the class property, if it is a simple identifier.
parseClassPropertyName(classContextId) {
this.parsePropertyName(classContextId);
// Get the identifier name so we can tell if it's actually a keyword like "async", "get", or
// "set".
parseClassPropertyName(classContextId);
let isConstructor = false;
const token = base_1.state.tokens[base_1.state.tokens.length - 1];
// We allow "constructor" as either an identifier or a string.
if (token.contextualKeyword === 6 /* _constructor */) {
isConstructor = true;
}
// Overridden in typescript.js
parsePostMemberNameModifiers() { }
parseClassProperty() {
if (this.match(types_1.types.eq)) {
const equalsTokenIndex = this.state.tokens.length;
this.next();
this.parseMaybeAssign();
this.state.tokens[equalsTokenIndex].rhsEndIndex = this.state.tokens.length;
}
this.semicolon();
parsePostMemberNameModifiers();
if (isClassMethod()) {
parseClassMethod(memberStart, false, isConstructor);
}
parseClassId(isStatement, optionalId = false) {
if (this.match(types_1.types.name)) {
this.parseIdentifier();
this.state.tokens[this.state.tokens.length - 1].identifierRole =
tokenizer_1.IdentifierRole.BlockScopedDeclaration;
}
else if (isClassProperty()) {
parseClassProperty();
}
// Returns true if there was a superclass.
parseClassSuper() {
if (this.eat(types_1.types._extends)) {
this.parseExprSubscripts();
return true;
else if (token.contextualKeyword === 3 /* _async */ && !util_1.isLineTerminator()) {
base_1.state.tokens[base_1.state.tokens.length - 1].type = 48144 /* _async */;
// an async method
const isGenerator = tokenizer_1.match(24587 /* star */);
if (isGenerator) {
tokenizer_1.next();
}
return false;
// The so-called parsed name would have been "async": get the real name.
parseClassPropertyName(classContextId);
parseClassMethod(memberStart, isGenerator, false /* isConstructor */);
}
// Parses module export declaration.
parseExport() {
// export * from '...'
if (this.shouldParseExportStar()) {
this.parseExportStar();
else if ((token.contextualKeyword === 11 /* _get */ ||
token.contextualKeyword === 29 /* _set */) &&
!(util_1.isLineTerminator() && tokenizer_1.match(24587 /* star */))) {
if (token.contextualKeyword === 11 /* _get */) {
base_1.state.tokens[base_1.state.tokens.length - 1].type = 48656 /* _get */;
}
else if (this.isExportDefaultSpecifier()) {
// export default from
this.parseIdentifier();
if (this.match(types_1.types.comma) && this.lookaheadType() === types_1.types.star) {
this.expect(types_1.types.comma);
this.expect(types_1.types.star);
this.expectContextual("as");
this.parseIdentifier();
}
else {
this.parseExportSpecifiersMaybe();
}
this.parseExportFrom();
}
else if (this.eat(types_1.types._default)) {
// export default ...
this.parseExportDefaultExpression();
}
else if (this.shouldParseExportDeclaration()) {
this.parseExportDeclaration();
}
else {
// export { x, y as z } [from '...']
this.parseExportSpecifiers();
this.parseExportFrom();
base_1.state.tokens[base_1.state.tokens.length - 1].type = 49168 /* _set */;
}
// `get\n*` is an uninitialized property named 'get' followed by a generator.
// a getter or setter
// The so-called parsed name would have been "get/set": get the real name.
parseClassPropertyName(classContextId);
parseClassMethod(memberStart, false, /* isConstructor */ false);
}
parseExportDefaultExpression() {
const functionStart = this.state.start;
if (this.eat(types_1.types._function)) {
this.parseFunction(functionStart, true, false, true);
else if (util_1.isLineTerminator()) {
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
parseClassProperty();
}
else {
util_1.unexpected();
}
}
function parseClassMethod(functionStart, isGenerator, isConstructor) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsTryParseTypeParameters();
}
else if (base_1.hasPlugin("flow")) {
if (tokenizer_1.match(21000 /* lessThan */)) {
flow_1.flowParseTypeParameterDeclaration();
}
else if (this.isContextual("async") && this.lookaheadType() === types_1.types._function) {
// async function declaration
this.eatContextual("async");
this.eat(types_1.types._function);
this.parseFunction(functionStart, true, false, true);
}
else if (this.match(types_1.types._class)) {
this.parseClass(true, true);
}
else {
this.parseMaybeAssign();
this.semicolon();
}
}
// eslint-disable-next-line no-unused-vars
parseExportDeclaration() {
this.parseStatement(true);
expression_1.parseMethod(functionStart, isGenerator, isConstructor);
}
// Return the name of the class property, if it is a simple identifier.
function parseClassPropertyName(classContextId) {
expression_1.parsePropertyName(classContextId);
}
exports.parseClassPropertyName = parseClassPropertyName;
// Overridden in typescript.js
function parsePostMemberNameModifiers() {
if (base_1.hasPlugin("typescript")) {
tokenizer_1.eat(9728 /* question */);
}
isExportDefaultSpecifier() {
if (this.match(types_1.types.name)) {
return this.state.value !== "async";
}
exports.parsePostMemberNameModifiers = parsePostMemberNameModifiers;
function parseClassProperty() {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsTryParseTypeAnnotation();
}
else if (base_1.hasPlugin("flow")) {
if (tokenizer_1.match(8192 /* colon */)) {
flow_1.flowParseTypeAnnotation();
}
if (!this.match(types_1.types._default)) {
return false;
}
const lookahead = this.lookaheadTypeAndValue();
return (lookahead.type === types_1.types.comma || (lookahead.type === types_1.types.name && lookahead.value === "from"));
}
parseExportSpecifiersMaybe() {
if (this.eat(types_1.types.comma)) {
this.parseExportSpecifiers();
if (tokenizer_1.match(14368 /* eq */)) {
const equalsTokenIndex = base_1.state.tokens.length;
tokenizer_1.next();
expression_1.parseMaybeAssign();
base_1.state.tokens[equalsTokenIndex].rhsEndIndex = base_1.state.tokens.length;
}
util_1.semicolon();
}
exports.parseClassProperty = parseClassProperty;
function parseClassId(isStatement, optionalId = false) {
if (base_1.hasPlugin("typescript") &&
(!isStatement || optionalId) &&
util_1.isContextual(13 /* _implements */)) {
return;
}
if (tokenizer_1.match(2048 /* name */)) {
expression_1.parseIdentifier();
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.BlockScopedDeclaration;
}
if (base_1.hasPlugin("typescript")) {
typescript_1.tsTryParseTypeParameters();
}
else if (base_1.hasPlugin("flow")) {
if (tokenizer_1.match(21000 /* lessThan */)) {
flow_1.flowParseTypeParameterDeclaration();
}
}
parseExportFrom() {
if (this.eatContextual("from")) {
this.parseExprAtom();
}
// Returns true if there was a superclass.
function parseClassSuper() {
let hasSuper;
if (tokenizer_1.eat(42000 /* _extends */)) {
expression_1.parseExprSubscripts();
hasSuper = true;
}
else {
hasSuper = false;
}
if (base_1.hasPlugin("typescript")) {
typescript_1.tsAfterParseClassSuper(hasSuper);
}
else if (base_1.hasPlugin("flow")) {
flow_1.flowAfterParseClassSuper(hasSuper);
}
}
// Parses module export declaration.
function parseExport() {
if (base_1.hasPlugin("typescript")) {
if (typescript_1.tsTryParseExport()) {
return;
}
this.semicolon();
}
shouldParseExportStar() {
return this.match(types_1.types.star);
// export * from '...'
if (shouldParseExportStar()) {
parseExportStar();
}
parseExportStar() {
this.expect(types_1.types.star);
if (this.isContextual("as")) {
this.parseExportNamespace();
else if (isExportDefaultSpecifier()) {
// export default from
expression_1.parseIdentifier();
if (tokenizer_1.match(7168 /* comma */) && tokenizer_1.lookaheadType() === 24587 /* star */) {
util_1.expect(7168 /* comma */);
util_1.expect(24587 /* star */);
util_1.expectContextual(2 /* _as */);
expression_1.parseIdentifier();
}
else {
this.parseExportFrom();
parseExportSpecifiersMaybe();
}
parseExportFrom();
}
parseExportNamespace() {
this.next();
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._as;
this.parseIdentifier();
this.parseExportSpecifiersMaybe();
this.parseExportFrom();
else if (tokenizer_1.eat(31760 /* _default */)) {
// export default ...
parseExportDefaultExpression();
}
shouldParseExportDeclaration() {
return (this.state.type.keyword === "var" ||
this.state.type.keyword === "const" ||
this.state.type.keyword === "let" ||
this.state.type.keyword === "function" ||
this.state.type.keyword === "class" ||
this.isContextual("async") ||
this.match(types_1.types.at));
else if (shouldParseExportDeclaration()) {
parseExportDeclaration();
}
// Parses a comma-separated list of module exports.
parseExportSpecifiers() {
let first = true;
else {
// export { x, y as z } [from '...']
this.expect(types_1.types.braceL);
while (!this.eat(types_1.types.braceR)) {
if (first) {
first = false;
}
else {
this.expect(types_1.types.comma);
if (this.eat(types_1.types.braceR))
break;
}
this.parseIdentifier();
this.state.tokens[this.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.ExportAccess;
if (this.eatContextual("as")) {
this.parseIdentifier();
}
parseExportSpecifiers();
parseExportFrom();
}
}
exports.parseExport = parseExport;
function parseExportDefaultExpression() {
if (base_1.hasPlugin("typescript")) {
if (typescript_1.tsTryParseExportDefaultExpression()) {
return;
}
}
// Parses import declaration.
parseImport() {
// import '...'
if (this.match(types_1.types.string)) {
this.parseExprAtom();
const functionStart = base_1.state.start;
if (tokenizer_1.eat(34320 /* _function */)) {
parseFunction(functionStart, true, false, true);
}
else if (util_1.isContextual(3 /* _async */) && tokenizer_1.lookaheadType() === 34320 /* _function */) {
// async function declaration
util_1.eatContextual(3 /* _async */);
tokenizer_1.eat(34320 /* _function */);
parseFunction(functionStart, true, false, true);
}
else if (tokenizer_1.match(41488 /* _class */)) {
parseClass(true, true);
}
else {
expression_1.parseMaybeAssign();
util_1.semicolon();
}
}
function parseExportDeclaration() {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsParseExportDeclaration();
}
else if (base_1.hasPlugin("flow")) {
flow_1.flowParseExportDeclaration();
}
else {
parseStatement(true);
}
}
function isExportDefaultSpecifier() {
if (base_1.hasPlugin("typescript") && typescript_1.tsIsDeclarationStart()) {
return false;
}
else if (base_1.hasPlugin("flow") && flow_1.flowShouldDisallowExportDefaultSpecifier()) {
return false;
}
if (tokenizer_1.match(2048 /* name */)) {
return base_1.state.contextualKeyword !== 3 /* _async */;
}
if (!tokenizer_1.match(31760 /* _default */)) {
return false;
}
const lookahead = tokenizer_1.lookaheadTypeAndKeyword();
return (lookahead.type === 7168 /* comma */ ||
(lookahead.type === 2048 /* name */ && lookahead.contextualKeyword === 10 /* _from */));
}
function parseExportSpecifiersMaybe() {
if (tokenizer_1.eat(7168 /* comma */)) {
parseExportSpecifiers();
}
}
function parseExportFrom() {
if (util_1.eatContextual(10 /* _from */)) {
expression_1.parseExprAtom();
}
util_1.semicolon();
}
exports.parseExportFrom = parseExportFrom;
function shouldParseExportStar() {
if (base_1.hasPlugin("flow")) {
return flow_1.flowShouldParseExportStar();
}
else {
return tokenizer_1.match(24587 /* star */);
}
}
function parseExportStar() {
if (base_1.hasPlugin("flow")) {
flow_1.flowParseExportStar();
}
else {
baseParseExportStar();
}
}
function baseParseExportStar() {
util_1.expect(24587 /* star */);
if (util_1.isContextual(2 /* _as */)) {
parseExportNamespace();
}
else {
parseExportFrom();
}
}
exports.baseParseExportStar = baseParseExportStar;
function parseExportNamespace() {
tokenizer_1.next();
base_1.state.tokens[base_1.state.tokens.length - 1].type = 53264 /* _as */;
expression_1.parseIdentifier();
parseExportSpecifiersMaybe();
parseExportFrom();
}
function shouldParseExportDeclaration() {
return ((base_1.hasPlugin("typescript") && typescript_1.tsIsDeclarationStart()) ||
(base_1.hasPlugin("flow") && flow_1.flowShouldParseExportDeclaration()) ||
base_1.state.type === 37392 /* _var */ ||
base_1.state.type === 38416 /* _const */ ||
base_1.state.type === 37904 /* _let */ ||
base_1.state.type === 34320 /* _function */ ||
base_1.state.type === 41488 /* _class */ ||
util_1.isContextual(3 /* _async */) ||
tokenizer_1.match(13312 /* at */));
}
// Parses a comma-separated list of module exports.
function parseExportSpecifiers() {
let first = true;
// export { x, y as z } [from '...']
util_1.expect(4096 /* braceL */);
while (!tokenizer_1.eat(5120 /* braceR */)) {
if (first) {
first = false;
}
else {
this.parseImportSpecifiers();
this.expectContextual("from");
this.parseExprAtom();
util_1.expect(7168 /* comma */);
if (tokenizer_1.eat(5120 /* braceR */))
break;
}
this.semicolon();
expression_1.parseIdentifier();
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.ExportAccess;
if (util_1.eatContextual(2 /* _as */)) {
expression_1.parseIdentifier();
}
}
// eslint-disable-next-line no-unused-vars
shouldParseDefaultImport() {
return this.match(types_1.types.name);
}
exports.parseExportSpecifiers = parseExportSpecifiers;
// Parses import declaration.
function parseImport() {
if (base_1.hasPlugin("typescript") && tokenizer_1.match(2048 /* name */) && tokenizer_1.lookaheadType() === 14368 /* eq */) {
typescript_1.tsParseImportEqualsDeclaration();
return;
}
parseImportSpecifierLocal() {
this.parseIdentifier();
// import '...'
if (tokenizer_1.match(1536 /* string */)) {
expression_1.parseExprAtom();
}
// Parses a comma-separated list of module imports.
parseImportSpecifiers() {
let first = true;
if (this.shouldParseDefaultImport()) {
// import defaultObj, { x, y as z } from '...'
this.parseImportSpecifierLocal();
if (!this.eat(types_1.types.comma))
return;
}
if (this.match(types_1.types.star)) {
this.next();
this.expectContextual("as");
this.parseImportSpecifierLocal();
else {
parseImportSpecifiers();
util_1.expectContextual(10 /* _from */);
expression_1.parseExprAtom();
}
util_1.semicolon();
}
exports.parseImport = parseImport;
// eslint-disable-next-line no-unused-vars
function shouldParseDefaultImport() {
return tokenizer_1.match(2048 /* name */);
}
function parseImportSpecifierLocal() {
expression_1.parseIdentifier();
}
// Parses a comma-separated list of module imports.
function parseImportSpecifiers() {
if (base_1.hasPlugin("flow")) {
flow_1.flowStartParseImportSpecifiers();
}
let first = true;
if (shouldParseDefaultImport()) {
// import defaultObj, { x, y as z } from '...'
parseImportSpecifierLocal();
if (!tokenizer_1.eat(7168 /* comma */))
return;
}
if (tokenizer_1.match(24587 /* star */)) {
tokenizer_1.next();
util_1.expectContextual(2 /* _as */);
parseImportSpecifierLocal();
return;
}
util_1.expect(4096 /* braceL */);
while (!tokenizer_1.eat(5120 /* braceR */)) {
if (first) {
first = false;
}
this.expect(types_1.types.braceL);
while (!this.eat(types_1.types.braceR)) {
if (first) {
first = false;
else {
// Detect an attempt to deep destructure
if (tokenizer_1.eat(8192 /* colon */)) {
util_1.unexpected(null, "ES2015 named imports do not destructure. Use another statement for destructuring after the import.");
}
else {
// Detect an attempt to deep destructure
if (this.eat(types_1.types.colon)) {
this.unexpected(null, "ES2015 named imports do not destructure. Use another statement for destructuring after the import.");
}
this.expect(types_1.types.comma);
if (this.eat(types_1.types.braceR))
break;
}
this.parseImportSpecifier();
util_1.expect(7168 /* comma */);
if (tokenizer_1.eat(5120 /* braceR */))
break;
}
parseImportSpecifier();
}
parseImportSpecifier() {
this.parseIdentifier();
if (this.eatContextual("as")) {
this.parseIdentifier();
}
}
function parseImportSpecifier() {
if (base_1.hasPlugin("flow")) {
flow_1.flowParseImportSpecifier();
return;
}
expression_1.parseIdentifier();
if (util_1.eatContextual(2 /* _as */)) {
expression_1.parseIdentifier();
}
}
exports.default = StatementParser;

@@ -1,14 +0,12 @@

import Tokenizer from "../tokenizer";
import { ContextualKeyword } from "../tokenizer";
import { TokenType } from "../tokenizer/types";
export default class UtilParser extends Tokenizer {
isContextual(name: string): boolean;
isLookaheadContextual(name: string): boolean;
eatContextual(name: string): boolean;
expectContextual(name: string, message?: string): void;
canInsertSemicolon(): boolean;
hasPrecedingLineBreak(): boolean;
isLineTerminator(): boolean;
semicolon(): void;
expect(type: TokenType, pos?: number | null): void;
unexpected(pos?: number | null, messageOrType?: string | TokenType): never;
}
export declare function isContextual(contextualKeyword: ContextualKeyword): boolean;
export declare function isLookaheadContextual(contextualKeyword: ContextualKeyword): boolean;
export declare function eatContextual(contextualKeyword: ContextualKeyword): boolean;
export declare function expectContextual(contextualKeyword: ContextualKeyword): void;
export declare function canInsertSemicolon(): boolean;
export declare function hasPrecedingLineBreak(): boolean;
export declare function isLineTerminator(): boolean;
export declare function semicolon(): void;
export declare function expect(type: TokenType, pos?: number | null): void;
export declare function unexpected(pos?: number | null, messageOrType?: string | TokenType): never;

@@ -6,56 +6,65 @@ "use strict";

const whitespace_1 = require("../util/whitespace");
const base_1 = require("./base");
// ## Parser utilities
class UtilParser extends tokenizer_1.default {
// Tests whether parsed token is a contextual keyword.
isContextual(name) {
return this.match(types_1.types.name) && this.state.value === name;
// Tests whether parsed token is a contextual keyword.
function isContextual(contextualKeyword) {
return base_1.state.contextualKeyword === contextualKeyword;
}
exports.isContextual = isContextual;
function isLookaheadContextual(contextualKeyword) {
const l = tokenizer_1.lookaheadTypeAndKeyword();
return l.type === 2048 /* name */ && l.contextualKeyword === contextualKeyword;
}
exports.isLookaheadContextual = isLookaheadContextual;
// Consumes contextual keyword if possible.
function eatContextual(contextualKeyword) {
return base_1.state.contextualKeyword === contextualKeyword && tokenizer_1.eat(2048 /* name */);
}
exports.eatContextual = eatContextual;
// Asserts that following token is given contextual keyword.
function expectContextual(contextualKeyword) {
if (!eatContextual(contextualKeyword)) {
unexpected(null);
}
isLookaheadContextual(name) {
const l = this.lookaheadTypeAndValue();
return l.type === types_1.types.name && l.value === name;
}
exports.expectContextual = expectContextual;
// Test whether a semicolon can be inserted at the current position.
function canInsertSemicolon() {
return tokenizer_1.match(2560 /* eof */) || tokenizer_1.match(5120 /* braceR */) || hasPrecedingLineBreak();
}
exports.canInsertSemicolon = canInsertSemicolon;
function hasPrecedingLineBreak() {
const prevToken = base_1.state.tokens[base_1.state.tokens.length - 1];
const lastTokEnd = prevToken ? prevToken.end : 0;
return whitespace_1.lineBreak.test(base_1.input.slice(lastTokEnd, base_1.state.start));
}
exports.hasPrecedingLineBreak = hasPrecedingLineBreak;
function isLineTerminator() {
return tokenizer_1.eat(7680 /* semi */) || canInsertSemicolon();
}
exports.isLineTerminator = isLineTerminator;
// Consume a semicolon, or, failing that, see if we are allowed to
// pretend that there is a semicolon at this position.
function semicolon() {
if (!isLineTerminator())
unexpected(null, 7680 /* semi */);
}
exports.semicolon = semicolon;
// Expect a token of a given type. If found, consume it, otherwise,
// raise an unexpected token error at given pos.
function expect(type, pos) {
const matched = tokenizer_1.eat(type);
if (!matched) {
unexpected(pos, type);
}
// Consumes contextual keyword if possible.
eatContextual(name) {
return this.state.value === name && this.eat(types_1.types.name);
}
exports.expect = expect;
// Raise an unexpected token error. Can take the expected token type
// instead of a message string.
function unexpected(pos = null, messageOrType = "Unexpected token") {
if (typeof messageOrType !== "string") {
messageOrType = `Unexpected token, expected "${types_1.formatTokenType(messageOrType)}"`;
}
// Asserts that following token is given contextual keyword.
expectContextual(name, message) {
if (!this.eatContextual(name))
this.unexpected(null, message);
}
// Test whether a semicolon can be inserted at the current position.
canInsertSemicolon() {
return this.match(types_1.types.eof) || this.match(types_1.types.braceR) || this.hasPrecedingLineBreak();
}
hasPrecedingLineBreak() {
const prevToken = this.state.tokens[this.state.tokens.length - 1];
const lastTokEnd = prevToken ? prevToken.end : 0;
return whitespace_1.lineBreak.test(this.input.slice(lastTokEnd, this.state.start));
}
isLineTerminator() {
return this.eat(types_1.types.semi) || this.canInsertSemicolon();
}
// Consume a semicolon, or, failing that, see if we are allowed to
// pretend that there is a semicolon at this position.
semicolon() {
if (!this.isLineTerminator())
this.unexpected(null, types_1.types.semi);
}
// Expect a token of a given type. If found, consume it, otherwise,
// raise an unexpected token error at given pos.
expect(type, pos) {
const matched = this.eat(type);
if (!matched) {
this.unexpected(pos, type);
}
}
// Raise an unexpected token error. Can take the expected token type
// instead of a message string.
unexpected(pos = null, messageOrType = "Unexpected token") {
if (typeof messageOrType !== "string") {
messageOrType = `Unexpected token, expected "${messageOrType.label}"`;
}
throw this.raise(pos != null ? pos : this.state.start, messageOrType);
}
throw base_1.raise(pos != null ? pos : base_1.state.start, messageOrType);
}
exports.default = UtilParser;
exports.unexpected = unexpected;

@@ -1,75 +0,23 @@

import { TokenType } from "../tokenizer/types";
import TypeParser from "./types";
export default class FlowParser extends TypeParser {
flowParseTypeInitialiser(tok?: TokenType): void;
flowParsePredicate(): void;
flowParseTypeAndPredicateInitialiser(): void;
flowParseDeclareClass(): void;
flowParseDeclareFunction(): void;
flowParseDeclare(): void;
flowParseDeclareVariable(): void;
flowParseDeclareModule(): void;
flowParseDeclareExportDeclaration(): void;
flowParseDeclareModuleExports(): void;
flowParseDeclareTypeAlias(): void;
flowParseDeclareOpaqueType(): void;
flowParseDeclareInterface(): void;
flowParseInterfaceish(isClass?: boolean): void;
flowParseInterfaceExtends(): void;
flowParseInterface(): void;
flowParseRestrictedIdentifier(): void;
flowParseTypeAlias(): void;
flowParseOpaqueType(declare: boolean): void;
flowParseTypeParameter(): void;
flowParseTypeParameterDeclaration(): void;
flowParseTypeParameterInstantiation(): void;
flowParseObjectPropertyKey(): void;
flowParseObjectTypeIndexer(): void;
flowParseObjectTypeMethodish(): void;
flowParseObjectTypeCallProperty(): void;
flowParseObjectType(allowStatic: boolean, allowExact: boolean): void;
flowParseObjectTypeProperty(): void;
flowObjectTypeSemicolon(): void;
flowParseQualifiedTypeIdentifier(initialIdAlreadyParsed: boolean): void;
flowParseGenericType(): void;
flowParseTypeofType(): void;
flowParseTupleType(): void;
flowParseFunctionTypeParam(): void;
flowParseFunctionTypeParams(): void;
flowIdentToTypeAnnotation(name: string): void;
flowParsePrimaryType(): void;
flowParsePostfixType(): void;
flowParsePrefixType(): void;
flowParseAnonFunctionWithoutParens(): void;
flowParseIntersectionType(): void;
flowParseUnionType(): void;
flowParseType(): void;
parseTypeAnnotation(): void;
flowParseTypeAnnotatableIdentifier(): void;
flowParseVariance(): void;
parseFunctionBodyAndFinish(functionStart: number, isGenerator: boolean, allowExpressionBody?: boolean, funcContextId?: number): void;
parseStatement(declaration: boolean, topLevel?: boolean): void;
parseIdentifierStatement(name: string): void;
shouldParseExportDeclaration(): boolean;
isExportDefaultSpecifier(): boolean;
parseExportDeclaration(): void;
shouldParseExportStar(): boolean;
parseExportStar(): void;
parseClassId(isStatement: boolean, optionalId?: boolean): void;
parseExprListItem(allowEmpty: boolean | null): void;
parseClassProperty(): void;
parseClassMethod(functionStart: number, isGenerator: boolean, isConstructor: boolean): void;
parseClassSuper(): boolean;
parsePropertyName(classContextId: number): void;
parseObjPropValue(isGenerator: boolean, isPattern: boolean, isBlockScope: boolean, objectContextId: number): void;
parseAssignableListItemTypes(): void;
parseImportSpecifiers(): void;
parseImportSpecifier(): void;
parseFunctionParams(allowModifiers?: boolean, contextId?: number): void;
parseVarHead(isBlockScope: boolean): void;
parseAsyncArrowFromCallExpression(functionStart: number, startTokenIndex: number): void;
parseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): boolean;
parseArrow(): boolean;
parseSubscripts(startPos: number, noCalls?: boolean | null): void;
parseAsyncArrowWithTypeParameters(startPos: number): boolean;
}
import { ContextualKeyword } from "../tokenizer";
export declare function flowParseTypeParameterDeclaration(): void;
export declare function flowParseTypeAnnotation(): void;
export declare function flowParseVariance(): void;
export declare function flowParseFunctionBodyAndFinish(functionStart: number, isGenerator: boolean, allowExpressionBody?: boolean | null, funcContextId?: number): void;
export declare function flowTryParseStatement(): boolean;
export declare function flowParseIdentifierStatement(contextualKeyword: ContextualKeyword): void;
export declare function flowShouldParseExportDeclaration(): boolean;
export declare function flowShouldDisallowExportDefaultSpecifier(): boolean;
export declare function flowParseExportDeclaration(): void;
export declare function flowShouldParseExportStar(): boolean;
export declare function flowParseExportStar(): void;
export declare function flowAfterParseClassSuper(hasSuper: boolean): void;
export declare function flowStartParseObjPropValue(): void;
export declare function flowParseAssignableListItemTypes(): void;
export declare function flowStartParseImportSpecifiers(): void;
export declare function flowParseImportSpecifier(): void;
export declare function flowStartParseFunctionParams(): void;
export declare function flowAfterParseVarHead(): void;
export declare function flowStartParseAsyncArrowFromCallExpression(): void;
export declare function flowParseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): boolean;
export declare function flowParseArrow(): boolean;
export declare function flowParseSubscripts(startPos: number, noCalls?: boolean | null): void;
"use strict";
/* eslint max-len: 0 */
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../tokenizer/types");
const types_2 = require("./types");
// tslint:disable-next-line no-any
const base_1 = require("../parser/base");
const expression_1 = require("../parser/expression");
const statement_1 = require("../parser/statement");
const util_1 = require("../parser/util");
const tokenizer_1 = require("../tokenizer");
function isMaybeDefaultImport(lookahead) {
return (lookahead.type === types_1.types.name || !!lookahead.type.keyword) && lookahead.value !== "from";
return ((lookahead.type === 2048 /* name */ || !!(lookahead.type & 16 /* IS_KEYWORD */)) &&
lookahead.contextualKeyword !== 10 /* _from */);
}
class FlowParser extends types_2.default {
flowParseTypeInitialiser(tok) {
this.runInTypeContext(0, () => {
this.expect(tok || types_1.types.colon);
this.flowParseType();
});
function flowParseTypeInitialiser(tok) {
tokenizer_1.runInTypeContext(0, () => {
util_1.expect(tok || 8192 /* colon */);
flowParseType();
});
}
function flowParsePredicate() {
util_1.expect(24075 /* modulo */);
util_1.expectContextual(5 /* _checks */);
if (tokenizer_1.eat(6144 /* parenL */)) {
expression_1.parseExpression();
util_1.expect(6656 /* parenR */);
}
flowParsePredicate() {
this.expect(types_1.types.modulo);
this.expectContextual("checks");
if (this.eat(types_1.types.parenL)) {
this.parseExpression();
this.expect(types_1.types.parenR);
}
function flowParseTypeAndPredicateInitialiser() {
tokenizer_1.runInTypeContext(0, () => {
util_1.expect(8192 /* colon */);
if (tokenizer_1.match(24075 /* modulo */)) {
flowParsePredicate();
}
}
flowParseTypeAndPredicateInitialiser() {
this.runInTypeContext(0, () => {
this.expect(types_1.types.colon);
if (this.match(types_1.types.modulo)) {
this.flowParsePredicate();
else {
flowParseType();
if (tokenizer_1.match(24075 /* modulo */)) {
flowParsePredicate();
}
else {
this.flowParseType();
if (this.match(types_1.types.modulo)) {
this.flowParsePredicate();
}
}
});
}
});
}
function flowParseDeclareClass() {
tokenizer_1.next();
flowParseInterfaceish(/* isClass */ true);
}
function flowParseDeclareFunction() {
tokenizer_1.next();
expression_1.parseIdentifier();
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterDeclaration();
}
flowParseDeclareClass() {
this.next();
this.flowParseInterfaceish(/* isClass */ true);
util_1.expect(6144 /* parenL */);
flowParseFunctionTypeParams();
util_1.expect(6656 /* parenR */);
flowParseTypeAndPredicateInitialiser();
util_1.semicolon();
}
function flowParseDeclare() {
if (tokenizer_1.match(41488 /* _class */)) {
flowParseDeclareClass();
}
flowParseDeclareFunction() {
this.next();
this.parseIdentifier();
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
}
this.expect(types_1.types.parenL);
this.flowParseFunctionTypeParams();
this.expect(types_1.types.parenR);
this.flowParseTypeAndPredicateInitialiser();
this.semicolon();
else if (tokenizer_1.match(34320 /* _function */)) {
flowParseDeclareFunction();
}
flowParseDeclare() {
if (this.match(types_1.types._class)) {
this.flowParseDeclareClass();
else if (tokenizer_1.match(37392 /* _var */)) {
flowParseDeclareVariable();
}
else if (util_1.isContextual(18 /* _module */)) {
if (tokenizer_1.lookaheadType() === 9216 /* dot */) {
flowParseDeclareModuleExports();
}
else if (this.match(types_1.types._function)) {
this.flowParseDeclareFunction();
}
else if (this.match(types_1.types._var)) {
this.flowParseDeclareVariable();
}
else if (this.isContextual("module")) {
if (this.lookaheadType() === types_1.types.dot) {
this.flowParseDeclareModuleExports();
}
else {
this.flowParseDeclareModule();
}
}
else if (this.isContextual("type")) {
this.flowParseDeclareTypeAlias();
}
else if (this.isContextual("opaque")) {
this.flowParseDeclareOpaqueType();
}
else if (this.isContextual("interface")) {
this.flowParseDeclareInterface();
}
else if (this.match(types_1.types._export)) {
this.flowParseDeclareExportDeclaration();
}
else {
throw this.unexpected();
flowParseDeclareModule();
}
}
flowParseDeclareVariable() {
this.next();
this.flowParseTypeAnnotatableIdentifier();
this.semicolon();
else if (util_1.isContextual(28 /* _type */)) {
flowParseDeclareTypeAlias();
}
flowParseDeclareModule() {
this.next();
if (this.match(types_1.types.string)) {
this.parseExprAtom();
else if (util_1.isContextual(21 /* _opaque */)) {
flowParseDeclareOpaqueType();
}
else if (util_1.isContextual(14 /* _interface */)) {
flowParseDeclareInterface();
}
else if (tokenizer_1.match(42512 /* _export */)) {
flowParseDeclareExportDeclaration();
}
else {
throw util_1.unexpected();
}
}
function flowParseDeclareVariable() {
tokenizer_1.next();
flowParseTypeAnnotatableIdentifier();
util_1.semicolon();
}
function flowParseDeclareModule() {
tokenizer_1.next();
if (tokenizer_1.match(1536 /* string */)) {
expression_1.parseExprAtom();
}
else {
expression_1.parseIdentifier();
}
util_1.expect(4096 /* braceL */);
while (!tokenizer_1.match(5120 /* braceR */)) {
if (tokenizer_1.match(43024 /* _import */)) {
tokenizer_1.next();
statement_1.parseImport();
}
else {
this.parseIdentifier();
}
this.expect(types_1.types.braceL);
while (!this.match(types_1.types.braceR)) {
if (this.match(types_1.types._import)) {
this.next();
this.parseImport();
}
}
this.expect(types_1.types.braceR);
}
flowParseDeclareExportDeclaration() {
this.expect(types_1.types._export);
if (this.eat(types_1.types._default)) {
if (this.match(types_1.types._function) || this.match(types_1.types._class)) {
// declare export default class ...
// declare export default function ...
this.flowParseDeclare();
}
else {
// declare export default [type];
this.flowParseType();
this.semicolon();
}
util_1.expect(5120 /* braceR */);
}
function flowParseDeclareExportDeclaration() {
util_1.expect(42512 /* _export */);
if (tokenizer_1.eat(31760 /* _default */)) {
if (tokenizer_1.match(34320 /* _function */) || tokenizer_1.match(41488 /* _class */)) {
// declare export default class ...
// declare export default function ...
flowParseDeclare();
}
else if (this.match(types_1.types._var) || // declare export var ...
this.match(types_1.types._function) || // declare export function ...
this.match(types_1.types._class) || // declare export class ...
this.isContextual("opaque") // declare export opaque ..
) {
this.flowParseDeclare();
}
else if (this.match(types_1.types.star) || // declare export * from ''
this.match(types_1.types.braceL) || // declare export {} ...
this.isContextual("interface") || // declare export interface ...
this.isContextual("type") || // declare export type ...
this.isContextual("opaque") // declare export opaque type ...
) {
this.parseExport();
}
else {
throw this.unexpected();
// declare export default [type];
flowParseType();
util_1.semicolon();
}
}
flowParseDeclareModuleExports() {
this.expectContextual("module");
this.expect(types_1.types.dot);
this.expectContextual("exports");
this.parseTypeAnnotation();
this.semicolon();
else if (tokenizer_1.match(37392 /* _var */) || // declare export var ...
tokenizer_1.match(34320 /* _function */) || // declare export function ...
tokenizer_1.match(41488 /* _class */) || // declare export class ...
util_1.isContextual(21 /* _opaque */) // declare export opaque ..
) {
flowParseDeclare();
}
flowParseDeclareTypeAlias() {
this.next();
this.flowParseTypeAlias();
else if (tokenizer_1.match(24587 /* star */) || // declare export * from ''
tokenizer_1.match(4096 /* braceL */) || // declare export {} ...
util_1.isContextual(14 /* _interface */) || // declare export interface ...
util_1.isContextual(28 /* _type */) || // declare export type ...
util_1.isContextual(21 /* _opaque */) // declare export opaque type ...
) {
statement_1.parseExport();
}
flowParseDeclareOpaqueType() {
this.next();
this.flowParseOpaqueType(true);
else {
throw util_1.unexpected();
}
flowParseDeclareInterface() {
this.next();
this.flowParseInterfaceish();
}
function flowParseDeclareModuleExports() {
util_1.expectContextual(18 /* _module */);
util_1.expect(9216 /* dot */);
util_1.expectContextual(9 /* _exports */);
flowParseTypeAnnotation();
util_1.semicolon();
}
function flowParseDeclareTypeAlias() {
tokenizer_1.next();
flowParseTypeAlias();
}
function flowParseDeclareOpaqueType() {
tokenizer_1.next();
flowParseOpaqueType(true);
}
function flowParseDeclareInterface() {
tokenizer_1.next();
flowParseInterfaceish();
}
// Interfaces
function flowParseInterfaceish(isClass) {
flowParseRestrictedIdentifier();
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterDeclaration();
}
// Interfaces
flowParseInterfaceish(isClass) {
this.flowParseRestrictedIdentifier();
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
}
if (this.eat(types_1.types._extends)) {
do {
this.flowParseInterfaceExtends();
} while (!isClass && this.eat(types_1.types.comma));
}
if (this.isContextual("mixins")) {
this.next();
do {
this.flowParseInterfaceExtends();
} while (this.eat(types_1.types.comma));
}
this.flowParseObjectType(true, false);
if (tokenizer_1.eat(42000 /* _extends */)) {
do {
flowParseInterfaceExtends();
} while (!isClass && tokenizer_1.eat(7168 /* comma */));
}
flowParseInterfaceExtends() {
this.flowParseQualifiedTypeIdentifier(false);
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterInstantiation();
}
if (util_1.isContextual(17 /* _mixins */)) {
tokenizer_1.next();
do {
flowParseInterfaceExtends();
} while (tokenizer_1.eat(7168 /* comma */));
}
flowParseInterface() {
this.flowParseInterfaceish();
flowParseObjectType(true, false);
}
function flowParseInterfaceExtends() {
flowParseQualifiedTypeIdentifier(false);
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterInstantiation();
}
flowParseRestrictedIdentifier() {
this.parseIdentifier();
}
function flowParseInterface() {
flowParseInterfaceish();
}
function flowParseRestrictedIdentifier() {
expression_1.parseIdentifier();
}
function flowParseTypeAlias() {
flowParseRestrictedIdentifier();
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterDeclaration();
}
// Type aliases
flowParseTypeAlias() {
this.flowParseRestrictedIdentifier();
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
}
this.flowParseTypeInitialiser(types_1.types.eq);
this.semicolon();
flowParseTypeInitialiser(14368 /* eq */);
util_1.semicolon();
}
function flowParseOpaqueType(declare) {
util_1.expectContextual(28 /* _type */);
flowParseRestrictedIdentifier();
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterDeclaration();
}
flowParseOpaqueType(declare) {
this.expectContextual("type");
this.flowParseRestrictedIdentifier();
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
// Parse the supertype
if (tokenizer_1.match(8192 /* colon */)) {
flowParseTypeInitialiser(8192 /* colon */);
}
if (!declare) {
flowParseTypeInitialiser(14368 /* eq */);
}
util_1.semicolon();
}
function flowParseTypeParameter() {
flowParseVariance();
flowParseTypeAnnotatableIdentifier();
if (tokenizer_1.eat(14368 /* eq */)) {
flowParseType();
}
}
function flowParseTypeParameterDeclaration() {
tokenizer_1.runInTypeContext(0, () => {
// istanbul ignore else: this condition is already checked at all call sites
if (tokenizer_1.match(21000 /* lessThan */) || tokenizer_1.match(28160 /* typeParameterStart */)) {
tokenizer_1.next();
}
// Parse the supertype
if (this.match(types_1.types.colon)) {
this.flowParseTypeInitialiser(types_1.types.colon);
else {
util_1.unexpected();
}
if (!declare) {
this.flowParseTypeInitialiser(types_1.types.eq);
do {
flowParseTypeParameter();
if (!tokenizer_1.match(21512 /* greaterThan */)) {
util_1.expect(7168 /* comma */);
}
} while (!tokenizer_1.match(21512 /* greaterThan */));
util_1.expect(21512 /* greaterThan */);
});
}
exports.flowParseTypeParameterDeclaration = flowParseTypeParameterDeclaration;
function flowParseTypeParameterInstantiation() {
tokenizer_1.runInTypeContext(0, () => {
util_1.expect(21000 /* lessThan */);
while (!tokenizer_1.match(21512 /* greaterThan */)) {
flowParseType();
if (!tokenizer_1.match(21512 /* greaterThan */)) {
util_1.expect(7168 /* comma */);
}
}
this.semicolon();
util_1.expect(21512 /* greaterThan */);
});
}
function flowParseObjectPropertyKey() {
if (tokenizer_1.match(0 /* num */) || tokenizer_1.match(1536 /* string */)) {
expression_1.parseExprAtom();
}
// Type annotations
flowParseTypeParameter() {
this.flowParseVariance();
this.flowParseTypeAnnotatableIdentifier();
if (this.eat(types_1.types.eq)) {
this.flowParseType();
}
else {
expression_1.parseIdentifier();
}
flowParseTypeParameterDeclaration() {
this.runInTypeContext(0, () => {
// istanbul ignore else: this condition is already checked at all call sites
if (this.match(types_1.types.lessThan) || this.match(types_1.types.typeParameterStart)) {
this.next();
}
else {
this.unexpected();
}
do {
this.flowParseTypeParameter();
if (!this.match(types_1.types.greaterThan)) {
this.expect(types_1.types.comma);
}
} while (!this.match(types_1.types.greaterThan));
this.expect(types_1.types.greaterThan);
});
}
function flowParseObjectTypeIndexer() {
util_1.expect(3072 /* bracketL */);
if (tokenizer_1.lookaheadType() === 8192 /* colon */) {
flowParseObjectPropertyKey();
flowParseTypeInitialiser();
}
flowParseTypeParameterInstantiation() {
this.runInTypeContext(0, () => {
this.expect(types_1.types.lessThan);
while (!this.match(types_1.types.greaterThan)) {
this.flowParseType();
if (!this.match(types_1.types.greaterThan)) {
this.expect(types_1.types.comma);
}
}
this.expect(types_1.types.greaterThan);
});
else {
flowParseType();
}
flowParseObjectPropertyKey() {
if (this.match(types_1.types.num) || this.match(types_1.types.string)) {
this.parseExprAtom();
}
else {
this.parseIdentifier();
}
util_1.expect(3584 /* bracketR */);
flowParseTypeInitialiser();
}
function flowParseObjectTypeMethodish() {
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterDeclaration();
}
flowParseObjectTypeIndexer() {
this.expect(types_1.types.bracketL);
if (this.lookaheadType() === types_1.types.colon) {
this.flowParseObjectPropertyKey();
this.flowParseTypeInitialiser();
util_1.expect(6144 /* parenL */);
while (!tokenizer_1.match(6656 /* parenR */) && !tokenizer_1.match(11776 /* ellipsis */)) {
flowParseFunctionTypeParam();
if (!tokenizer_1.match(6656 /* parenR */)) {
util_1.expect(7168 /* comma */);
}
else {
this.flowParseType();
}
this.expect(types_1.types.bracketR);
this.flowParseTypeInitialiser();
}
flowParseObjectTypeMethodish() {
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
if (tokenizer_1.eat(11776 /* ellipsis */)) {
flowParseFunctionTypeParam();
}
util_1.expect(6656 /* parenR */);
flowParseTypeInitialiser();
}
function flowParseObjectTypeCallProperty() {
flowParseObjectTypeMethodish();
}
function flowParseObjectType(allowStatic, allowExact) {
let endDelim;
if (allowExact && tokenizer_1.match(4608 /* braceBarL */)) {
util_1.expect(4608 /* braceBarL */);
endDelim = 5632 /* braceBarR */;
}
else {
util_1.expect(4096 /* braceL */);
endDelim = 5120 /* braceR */;
}
while (!tokenizer_1.match(endDelim)) {
let isStatic = false;
if (allowStatic && util_1.isContextual(27 /* _static */) && tokenizer_1.lookaheadType() !== 8192 /* colon */) {
tokenizer_1.next();
isStatic = true;
}
this.expect(types_1.types.parenL);
while (!this.match(types_1.types.parenR) && !this.match(types_1.types.ellipsis)) {
this.flowParseFunctionTypeParam();
if (!this.match(types_1.types.parenR)) {
this.expect(types_1.types.comma);
}
flowParseVariance();
if (tokenizer_1.match(3072 /* bracketL */)) {
flowParseObjectTypeIndexer();
}
if (this.eat(types_1.types.ellipsis)) {
this.flowParseFunctionTypeParam();
else if (tokenizer_1.match(6144 /* parenL */) || tokenizer_1.match(21000 /* lessThan */)) {
flowParseObjectTypeCallProperty();
}
this.expect(types_1.types.parenR);
this.flowParseTypeInitialiser();
}
flowParseObjectTypeCallProperty() {
this.flowParseObjectTypeMethodish();
}
flowParseObjectType(allowStatic, allowExact) {
let endDelim;
if (allowExact && this.match(types_1.types.braceBarL)) {
this.expect(types_1.types.braceBarL);
endDelim = types_1.types.braceBarR;
}
else {
this.expect(types_1.types.braceL);
endDelim = types_1.types.braceR;
}
while (!this.match(endDelim)) {
let isStatic = false;
if (allowStatic && this.isContextual("static") && this.lookaheadType() !== types_1.types.colon) {
this.next();
isStatic = true;
}
this.flowParseVariance();
if (this.match(types_1.types.bracketL)) {
this.flowParseObjectTypeIndexer();
}
else if (this.match(types_1.types.parenL) || this.match(types_1.types.lessThan)) {
this.flowParseObjectTypeCallProperty();
}
else {
if (this.isContextual("get") || this.isContextual("set")) {
const lookaheadType = this.lookaheadType();
if (lookaheadType === types_1.types.name ||
lookaheadType === types_1.types.string ||
lookaheadType === types_1.types.num) {
this.next();
}
if (util_1.isContextual(11 /* _get */) || util_1.isContextual(29 /* _set */)) {
const lookahead = tokenizer_1.lookaheadType();
if (lookahead === 2048 /* name */ || lookahead === 1536 /* string */ || lookahead === 0 /* num */) {
tokenizer_1.next();
}
this.flowParseObjectTypeProperty();
}
this.flowObjectTypeSemicolon();
flowParseObjectTypeProperty();
}
this.expect(endDelim);
flowObjectTypeSemicolon();
}
flowParseObjectTypeProperty() {
if (this.match(types_1.types.ellipsis)) {
this.expect(types_1.types.ellipsis);
this.flowParseType();
util_1.expect(endDelim);
}
function flowParseObjectTypeProperty() {
if (tokenizer_1.match(11776 /* ellipsis */)) {
util_1.expect(11776 /* ellipsis */);
flowParseType();
}
else {
flowParseObjectPropertyKey();
if (tokenizer_1.match(21000 /* lessThan */) || tokenizer_1.match(6144 /* parenL */)) {
// This is a method property
flowParseObjectTypeMethodish();
}
else {
this.flowParseObjectPropertyKey();
if (this.match(types_1.types.lessThan) || this.match(types_1.types.parenL)) {
// This is a method property
this.flowParseObjectTypeMethodish();
}
else {
this.eat(types_1.types.question);
this.flowParseTypeInitialiser();
}
tokenizer_1.eat(9728 /* question */);
flowParseTypeInitialiser();
}
}
flowObjectTypeSemicolon() {
if (!this.eat(types_1.types.semi) &&
!this.eat(types_1.types.comma) &&
!this.match(types_1.types.braceR) &&
!this.match(types_1.types.braceBarR)) {
this.unexpected();
}
}
function flowObjectTypeSemicolon() {
if (!tokenizer_1.eat(7680 /* semi */) && !tokenizer_1.eat(7168 /* comma */) && !tokenizer_1.match(5120 /* braceR */) && !tokenizer_1.match(5632 /* braceBarR */)) {
util_1.unexpected();
}
flowParseQualifiedTypeIdentifier(initialIdAlreadyParsed) {
if (!initialIdAlreadyParsed) {
this.parseIdentifier();
}
while (this.eat(types_1.types.dot)) {
this.parseIdentifier();
}
}
function flowParseQualifiedTypeIdentifier(initialIdAlreadyParsed) {
if (!initialIdAlreadyParsed) {
expression_1.parseIdentifier();
}
flowParseGenericType() {
this.flowParseQualifiedTypeIdentifier(true);
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterInstantiation();
}
while (tokenizer_1.eat(9216 /* dot */)) {
expression_1.parseIdentifier();
}
flowParseTypeofType() {
this.expect(types_1.types._typeof);
this.flowParsePrimaryType();
}
function flowParseGenericType() {
flowParseQualifiedTypeIdentifier(true);
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterInstantiation();
}
flowParseTupleType() {
this.expect(types_1.types.bracketL);
// We allow trailing commas
while (this.state.pos < this.input.length && !this.match(types_1.types.bracketR)) {
this.flowParseType();
if (this.match(types_1.types.bracketR)) {
break;
}
this.expect(types_1.types.comma);
}
function flowParseTypeofType() {
util_1.expect(46736 /* _typeof */);
flowParsePrimaryType();
}
function flowParseTupleType() {
util_1.expect(3072 /* bracketL */);
// We allow trailing commas
while (base_1.state.pos < base_1.input.length && !tokenizer_1.match(3584 /* bracketR */)) {
flowParseType();
if (tokenizer_1.match(3584 /* bracketR */)) {
break;
}
this.expect(types_1.types.bracketR);
util_1.expect(7168 /* comma */);
}
flowParseFunctionTypeParam() {
const lookaheadType = this.lookaheadType();
if (lookaheadType === types_1.types.colon || lookaheadType === types_1.types.question) {
this.parseIdentifier();
this.eat(types_1.types.question);
this.flowParseTypeInitialiser();
}
else {
this.flowParseType();
}
util_1.expect(3584 /* bracketR */);
}
function flowParseFunctionTypeParam() {
const lookahead = tokenizer_1.lookaheadType();
if (lookahead === 8192 /* colon */ || lookahead === 9728 /* question */) {
expression_1.parseIdentifier();
tokenizer_1.eat(9728 /* question */);
flowParseTypeInitialiser();
}
flowParseFunctionTypeParams() {
while (!this.match(types_1.types.parenR) && !this.match(types_1.types.ellipsis)) {
this.flowParseFunctionTypeParam();
if (!this.match(types_1.types.parenR)) {
this.expect(types_1.types.comma);
}
else {
flowParseType();
}
}
function flowParseFunctionTypeParams() {
while (!tokenizer_1.match(6656 /* parenR */) && !tokenizer_1.match(11776 /* ellipsis */)) {
flowParseFunctionTypeParam();
if (!tokenizer_1.match(6656 /* parenR */)) {
util_1.expect(7168 /* comma */);
}
if (this.eat(types_1.types.ellipsis)) {
this.flowParseFunctionTypeParam();
}
}
flowIdentToTypeAnnotation(name) {
switch (name) {
case "any":
case "void":
case "bool":
case "boolean":
case "mixed":
case "empty":
case "number":
case "string":
return;
default:
this.flowParseGenericType();
if (tokenizer_1.eat(11776 /* ellipsis */)) {
flowParseFunctionTypeParam();
}
}
// The parsing of types roughly parallels the parsing of expressions, and
// primary types are kind of like primary expressions...they're the
// primitives with which other types are constructed.
function flowParsePrimaryType() {
let isGroupedType = false;
const oldNoAnonFunctionType = base_1.state.noAnonFunctionType;
switch (base_1.state.type) {
case 2048 /* name */: {
expression_1.parseIdentifier();
flowParseGenericType();
return;
}
}
// The parsing of types roughly parallels the parsing of expressions, and
// primary types are kind of like primary expressions...they're the
// primitives with which other types are constructed.
flowParsePrimaryType() {
let isGroupedType = false;
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
switch (this.state.type) {
case types_1.types.name: {
this.parseIdentifier();
const name = this.state.tokens[this.state.tokens.length - 1].value;
this.flowIdentToTypeAnnotation(name);
return;
}
case types_1.types.braceL:
this.flowParseObjectType(false, false);
return;
case types_1.types.braceBarL:
this.flowParseObjectType(false, true);
return;
case types_1.types.bracketL:
this.flowParseTupleType();
return;
case types_1.types.lessThan:
this.flowParseTypeParameterDeclaration();
this.expect(types_1.types.parenL);
this.flowParseFunctionTypeParams();
this.expect(types_1.types.parenR);
this.expect(types_1.types.arrow);
this.flowParseType();
return;
case types_1.types.parenL:
this.next();
// Check to see if this is actually a grouped type
if (!this.match(types_1.types.parenR) && !this.match(types_1.types.ellipsis)) {
if (this.match(types_1.types.name)) {
const token = this.lookaheadType();
isGroupedType = token !== types_1.types.question && token !== types_1.types.colon;
}
else {
isGroupedType = true;
}
case 4096 /* braceL */:
flowParseObjectType(false, false);
return;
case 4608 /* braceBarL */:
flowParseObjectType(false, true);
return;
case 3072 /* bracketL */:
flowParseTupleType();
return;
case 21000 /* lessThan */:
flowParseTypeParameterDeclaration();
util_1.expect(6144 /* parenL */);
flowParseFunctionTypeParams();
util_1.expect(6656 /* parenR */);
util_1.expect(10752 /* arrow */);
flowParseType();
return;
case 6144 /* parenL */:
tokenizer_1.next();
// Check to see if this is actually a grouped type
if (!tokenizer_1.match(6656 /* parenR */) && !tokenizer_1.match(11776 /* ellipsis */)) {
if (tokenizer_1.match(2048 /* name */)) {
const token = tokenizer_1.lookaheadType();
isGroupedType = token !== 9728 /* question */ && token !== 8192 /* colon */;
}
if (isGroupedType) {
this.state.noAnonFunctionType = false;
this.flowParseType();
this.state.noAnonFunctionType = oldNoAnonFunctionType;
// A `,` or a `) =>` means this is an anonymous function type
if (this.state.noAnonFunctionType ||
!(this.match(types_1.types.comma) || (this.match(types_1.types.parenR) && this.lookaheadType() === types_1.types.arrow))) {
this.expect(types_1.types.parenR);
return;
}
else {
// Eat a comma if there is one
this.eat(types_1.types.comma);
}
else {
isGroupedType = true;
}
this.flowParseFunctionTypeParams();
this.expect(types_1.types.parenR);
this.expect(types_1.types.arrow);
this.flowParseType();
return;
case types_1.types.plusMin:
// Only allow negative signs, not plus signs.
if (this.state.value === "-") {
this.next();
this.parseLiteral();
}
if (isGroupedType) {
base_1.state.noAnonFunctionType = false;
flowParseType();
base_1.state.noAnonFunctionType = oldNoAnonFunctionType;
// A `,` or a `) =>` means this is an anonymous function type
if (base_1.state.noAnonFunctionType ||
!(tokenizer_1.match(7168 /* comma */) || (tokenizer_1.match(6656 /* parenR */) && tokenizer_1.lookaheadType() === 10752 /* arrow */))) {
util_1.expect(6656 /* parenR */);
return;
}
throw this.unexpected();
case types_1.types.string:
case types_1.types.num:
case types_1.types._true:
case types_1.types._false:
case types_1.types._null:
case types_1.types._this:
case types_1.types._void:
case types_1.types.star:
this.next();
else {
// Eat a comma if there is one
tokenizer_1.eat(7168 /* comma */);
}
}
flowParseFunctionTypeParams();
util_1.expect(6656 /* parenR */);
util_1.expect(10752 /* arrow */);
flowParseType();
return;
case 23690 /* minus */:
tokenizer_1.next();
expression_1.parseLiteral();
return;
case 1536 /* string */:
case 0 /* num */:
case 44560 /* _true */:
case 45072 /* _false */:
case 44048 /* _null */:
case 40464 /* _this */:
case 47248 /* _void */:
case 24587 /* star */:
tokenizer_1.next();
return;
default:
if (base_1.state.type === 46736 /* _typeof */) {
flowParseTypeofType();
return;
default:
if (this.state.type.keyword === "typeof") {
this.flowParseTypeofType();
return;
}
}
throw this.unexpected();
}
}
flowParsePostfixType() {
this.flowParsePrimaryType();
while (!this.canInsertSemicolon() && this.match(types_1.types.bracketL)) {
this.expect(types_1.types.bracketL);
this.expect(types_1.types.bracketR);
}
throw util_1.unexpected();
}
function flowParsePostfixType() {
flowParsePrimaryType();
while (!util_1.canInsertSemicolon() && tokenizer_1.match(3072 /* bracketL */)) {
util_1.expect(3072 /* bracketL */);
util_1.expect(3584 /* bracketR */);
}
flowParsePrefixType() {
if (this.eat(types_1.types.question)) {
this.flowParsePrefixType();
}
else {
this.flowParsePostfixType();
}
}
function flowParsePrefixType() {
if (tokenizer_1.eat(9728 /* question */)) {
flowParsePrefixType();
}
flowParseAnonFunctionWithoutParens() {
this.flowParsePrefixType();
if (!this.state.noAnonFunctionType && this.eat(types_1.types.arrow)) {
this.flowParseType();
}
else {
flowParsePostfixType();
}
flowParseIntersectionType() {
this.eat(types_1.types.bitwiseAND);
this.flowParseAnonFunctionWithoutParens();
while (this.eat(types_1.types.bitwiseAND)) {
this.flowParseAnonFunctionWithoutParens();
}
}
function flowParseAnonFunctionWithoutParens() {
flowParsePrefixType();
if (!base_1.state.noAnonFunctionType && tokenizer_1.eat(10752 /* arrow */)) {
flowParseType();
}
flowParseUnionType() {
this.eat(types_1.types.bitwiseOR);
this.flowParseIntersectionType();
while (this.eat(types_1.types.bitwiseOR)) {
this.flowParseIntersectionType();
}
}
function flowParseIntersectionType() {
tokenizer_1.eat(19974 /* bitwiseAND */);
flowParseAnonFunctionWithoutParens();
while (tokenizer_1.eat(19974 /* bitwiseAND */)) {
flowParseAnonFunctionWithoutParens();
}
flowParseType() {
this.flowParseUnionType();
}
function flowParseUnionType() {
tokenizer_1.eat(18948 /* bitwiseOR */);
flowParseIntersectionType();
while (tokenizer_1.eat(18948 /* bitwiseOR */)) {
flowParseIntersectionType();
}
parseTypeAnnotation() {
this.flowParseTypeInitialiser();
}
function flowParseType() {
flowParseUnionType();
}
function flowParseTypeAnnotation() {
flowParseTypeInitialiser();
}
exports.flowParseTypeAnnotation = flowParseTypeAnnotation;
function flowParseTypeAnnotatableIdentifier() {
expression_1.parseIdentifier();
if (tokenizer_1.match(8192 /* colon */)) {
flowParseTypeAnnotation();
}
flowParseTypeAnnotatableIdentifier() {
this.parseIdentifier();
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
}
}
function flowParseVariance() {
if (tokenizer_1.match(23178 /* plus */) || tokenizer_1.match(23690 /* minus */)) {
tokenizer_1.next();
}
flowParseVariance() {
if (this.match(types_1.types.plusMin)) {
this.next();
}
}
exports.flowParseVariance = flowParseVariance;
// ==================================
// Overrides
// ==================================
function flowParseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody = null, funcContextId) {
// For arrow functions, `parseArrow` handles the return type itself.
if (!allowExpressionBody && tokenizer_1.match(8192 /* colon */)) {
flowParseTypeAndPredicateInitialiser();
}
// ==================================
// Overrides
// ==================================
parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody, funcContextId) {
// For arrow functions, `parseArrow` handles the return type itself.
if (!allowExpressionBody && this.match(types_1.types.colon)) {
this.flowParseTypeAndPredicateInitialiser();
expression_1.parseFunctionBody(functionStart, isGenerator, allowExpressionBody, funcContextId);
}
exports.flowParseFunctionBodyAndFinish = flowParseFunctionBodyAndFinish;
// interfaces
function flowTryParseStatement() {
if (tokenizer_1.match(2048 /* name */) && base_1.state.contextualKeyword === 14 /* _interface */) {
tokenizer_1.runInTypeContext(0, () => {
tokenizer_1.next();
flowParseInterface();
});
return true;
}
else {
return false;
}
}
exports.flowTryParseStatement = flowTryParseStatement;
// declares, interfaces and type aliases
function flowParseIdentifierStatement(contextualKeyword) {
if (contextualKeyword === 7 /* _declare */) {
if (tokenizer_1.match(41488 /* _class */) ||
tokenizer_1.match(2048 /* name */) ||
tokenizer_1.match(34320 /* _function */) ||
tokenizer_1.match(37392 /* _var */) ||
tokenizer_1.match(42512 /* _export */)) {
tokenizer_1.runInTypeContext(1, () => {
flowParseDeclare();
});
}
super.parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody, funcContextId);
}
// interfaces
parseStatement(declaration, topLevel) {
if (this.match(types_1.types.name) && this.state.value === "interface") {
this.runInTypeContext(0, () => {
this.next();
this.flowParseInterface();
else if (tokenizer_1.match(2048 /* name */)) {
if (contextualKeyword === 14 /* _interface */) {
tokenizer_1.runInTypeContext(1, () => {
flowParseInterface();
});
}
else {
super.parseStatement(declaration, topLevel);
else if (contextualKeyword === 28 /* _type */) {
tokenizer_1.runInTypeContext(1, () => {
flowParseTypeAlias();
});
}
else if (contextualKeyword === 21 /* _opaque */) {
tokenizer_1.runInTypeContext(1, () => {
flowParseOpaqueType(false);
});
}
}
// declares, interfaces and type aliases
parseIdentifierStatement(name) {
if (name === "declare") {
if (this.match(types_1.types._class) ||
this.match(types_1.types.name) ||
this.match(types_1.types._function) ||
this.match(types_1.types._var) ||
this.match(types_1.types._export)) {
this.runInTypeContext(1, () => {
this.flowParseDeclare();
});
util_1.semicolon();
}
exports.flowParseIdentifierStatement = flowParseIdentifierStatement;
// export type
function flowShouldParseExportDeclaration() {
return (util_1.isContextual(28 /* _type */) ||
util_1.isContextual(14 /* _interface */) ||
util_1.isContextual(21 /* _opaque */));
}
exports.flowShouldParseExportDeclaration = flowShouldParseExportDeclaration;
function flowShouldDisallowExportDefaultSpecifier() {
return (tokenizer_1.match(2048 /* name */) &&
(base_1.state.contextualKeyword === 28 /* _type */ ||
base_1.state.contextualKeyword === 14 /* _interface */ ||
base_1.state.contextualKeyword === 21 /* _opaque */));
}
exports.flowShouldDisallowExportDefaultSpecifier = flowShouldDisallowExportDefaultSpecifier;
function flowParseExportDeclaration() {
if (util_1.isContextual(28 /* _type */)) {
tokenizer_1.runInTypeContext(1, () => {
tokenizer_1.next();
if (tokenizer_1.match(4096 /* braceL */)) {
// export type { foo, bar };
statement_1.parseExportSpecifiers();
statement_1.parseExportFrom();
}
}
else if (this.match(types_1.types.name)) {
if (name === "interface") {
this.runInTypeContext(1, () => {
this.flowParseInterface();
});
else {
// export type Foo = Bar;
flowParseTypeAlias();
}
else if (name === "type") {
this.runInTypeContext(1, () => {
this.flowParseTypeAlias();
});
}
else if (name === "opaque") {
this.runInTypeContext(1, () => {
this.flowParseOpaqueType(false);
});
}
}
super.parseIdentifierStatement(name);
});
}
// export type
shouldParseExportDeclaration() {
return (this.isContextual("type") ||
this.isContextual("interface") ||
this.isContextual("opaque") ||
super.shouldParseExportDeclaration());
else if (util_1.isContextual(21 /* _opaque */)) {
tokenizer_1.runInTypeContext(1, () => {
tokenizer_1.next();
// export opaque type Foo = Bar;
flowParseOpaqueType(false);
});
}
isExportDefaultSpecifier() {
if (this.match(types_1.types.name) &&
(this.state.value === "type" ||
this.state.value === "interface" ||
this.state.value === "opaque")) {
return false;
}
return super.isExportDefaultSpecifier();
else if (util_1.isContextual(14 /* _interface */)) {
tokenizer_1.runInTypeContext(1, () => {
tokenizer_1.next();
flowParseInterface();
});
}
parseExportDeclaration() {
if (this.isContextual("type")) {
this.runInTypeContext(1, () => {
this.next();
if (this.match(types_1.types.braceL)) {
// export type { foo, bar };
this.parseExportSpecifiers();
this.parseExportFrom();
else {
statement_1.parseStatement(true);
}
}
exports.flowParseExportDeclaration = flowParseExportDeclaration;
function flowShouldParseExportStar() {
return tokenizer_1.match(24587 /* star */) || (util_1.isContextual(28 /* _type */) && tokenizer_1.lookaheadType() === 24587 /* star */);
}
exports.flowShouldParseExportStar = flowShouldParseExportStar;
function flowParseExportStar() {
if (util_1.eatContextual(28 /* _type */)) {
tokenizer_1.runInTypeContext(2, () => {
statement_1.baseParseExportStar();
});
}
else {
statement_1.baseParseExportStar();
}
}
exports.flowParseExportStar = flowParseExportStar;
// parse a the super class type parameters and implements
function flowAfterParseClassSuper(hasSuper) {
if (hasSuper && tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterInstantiation();
}
if (util_1.isContextual(13 /* _implements */)) {
base_1.state.tokens[base_1.state.tokens.length - 1].type = 54800 /* _implements */;
tokenizer_1.runInTypeContext(0, () => {
tokenizer_1.next();
do {
flowParseRestrictedIdentifier();
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterInstantiation();
}
else {
// export type Foo = Bar;
this.flowParseTypeAlias();
}
});
}
else if (this.isContextual("opaque")) {
this.runInTypeContext(1, () => {
this.next();
// export opaque type Foo = Bar;
this.flowParseOpaqueType(false);
});
}
else if (this.isContextual("interface")) {
this.runInTypeContext(1, () => {
this.next();
this.flowParseInterface();
});
}
else {
super.parseExportDeclaration();
}
} while (tokenizer_1.eat(7168 /* comma */));
});
}
shouldParseExportStar() {
return (super.shouldParseExportStar() ||
(this.isContextual("type") && this.lookaheadType() === types_1.types.star));
}
exports.flowAfterParseClassSuper = flowAfterParseClassSuper;
// parse type parameters for object method shorthand
function flowStartParseObjPropValue() {
// method shorthand
if (tokenizer_1.match(21000 /* lessThan */)) {
flowParseTypeParameterDeclaration();
if (!tokenizer_1.match(6144 /* parenL */))
util_1.unexpected();
}
parseExportStar() {
if (this.eatContextual("type")) {
this.runInTypeContext(2, () => {
super.parseExportStar();
});
}
exports.flowStartParseObjPropValue = flowStartParseObjPropValue;
function flowParseAssignableListItemTypes() {
tokenizer_1.runInTypeContext(0, () => {
tokenizer_1.eat(9728 /* question */);
if (tokenizer_1.match(8192 /* colon */)) {
flowParseTypeAnnotation();
}
else {
super.parseExportStar();
}
});
}
exports.flowParseAssignableListItemTypes = flowParseAssignableListItemTypes;
// parse typeof and type imports
function flowStartParseImportSpecifiers() {
let kind = null;
if (tokenizer_1.match(46736 /* _typeof */)) {
kind = "typeof";
}
parseClassId(isStatement, optionalId = false) {
super.parseClassId(isStatement, optionalId);
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
}
else if (util_1.isContextual(28 /* _type */)) {
kind = "type";
}
// parse an item inside a expression list eg. `(NODE, NODE)` where NODE represents
// the position where this function is called
parseExprListItem(allowEmpty) {
super.parseExprListItem(allowEmpty);
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
if (kind) {
const lh = tokenizer_1.lookaheadTypeAndKeyword();
if (isMaybeDefaultImport(lh) || lh.type === 4096 /* braceL */ || lh.type === 24587 /* star */) {
tokenizer_1.next();
}
}
// parse class property type annotations
parseClassProperty() {
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
}
super.parseClassProperty();
}
exports.flowStartParseImportSpecifiers = flowStartParseImportSpecifiers;
// parse import-type/typeof shorthand
function flowParseImportSpecifier() {
const isTypeKeyword = base_1.state.contextualKeyword === 28 /* _type */ || base_1.state.type === 46736 /* _typeof */;
if (isTypeKeyword) {
tokenizer_1.next();
}
// parse type parameters for class methods
parseClassMethod(functionStart, isGenerator, isConstructor) {
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
}
super.parseClassMethod(functionStart, isGenerator, isConstructor);
else {
expression_1.parseIdentifier();
}
// parse a the super class type parameters and implements
parseClassSuper() {
const hadSuper = super.parseClassSuper();
if (hadSuper && this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterInstantiation();
if (util_1.isContextual(2 /* _as */) && !util_1.isLookaheadContextual(2 /* _as */)) {
expression_1.parseIdentifier();
if (isTypeKeyword && !tokenizer_1.match(2048 /* name */) && !(base_1.state.type & 16 /* IS_KEYWORD */)) {
// `import {type as ,` or `import {type as }`
}
if (this.isContextual("implements")) {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._implements;
this.runInTypeContext(0, () => {
this.next();
do {
this.flowParseRestrictedIdentifier();
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterInstantiation();
}
} while (this.eat(types_1.types.comma));
});
else {
// `import {type as foo`
expression_1.parseIdentifier();
}
return hadSuper;
}
parsePropertyName(classContextId) {
this.flowParseVariance();
super.parsePropertyName(classContextId);
}
// parse type parameters for object method shorthand
parseObjPropValue(isGenerator, isPattern, isBlockScope, objectContextId) {
// method shorthand
if (this.match(types_1.types.lessThan)) {
this.flowParseTypeParameterDeclaration();
if (!this.match(types_1.types.parenL))
this.unexpected();
else if (isTypeKeyword && (tokenizer_1.match(2048 /* name */) || !!(base_1.state.type & 16 /* IS_KEYWORD */))) {
// `import {type foo`
expression_1.parseIdentifier();
if (util_1.eatContextual(2 /* _as */)) {
expression_1.parseIdentifier();
}
super.parseObjPropValue(isGenerator, isPattern, isBlockScope, objectContextId);
}
parseAssignableListItemTypes() {
this.runInTypeContext(0, () => {
this.eat(types_1.types.question);
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
}
}
exports.flowParseImportSpecifier = flowParseImportSpecifier;
// parse function type parameters - function foo<T>() {}
function flowStartParseFunctionParams() {
// Originally this checked if the method is a getter/setter, but if it was, we'd crash soon
// anyway, so don't try to propagate that information.
if (tokenizer_1.match(21000 /* lessThan */)) {
tokenizer_1.runInTypeContext(0, () => {
flowParseTypeParameterDeclaration();
});
}
// parse typeof and type imports
parseImportSpecifiers() {
let kind = null;
if (this.match(types_1.types._typeof)) {
kind = "typeof";
}
else if (this.isContextual("type")) {
kind = "type";
}
if (kind) {
const lh = this.lookaheadTypeAndValue();
if (isMaybeDefaultImport(lh) || lh.type === types_1.types.braceL || lh.type === types_1.types.star) {
this.next();
}
}
super.parseImportSpecifiers();
}
exports.flowStartParseFunctionParams = flowStartParseFunctionParams;
// parse flow type annotations on variable declarator heads - let foo: string = bar
function flowAfterParseVarHead() {
if (tokenizer_1.match(8192 /* colon */)) {
flowParseTypeAnnotation();
}
// parse import-type/typeof shorthand
parseImportSpecifier() {
this.parseIdentifier();
const firstIdentName = this.state.tokens[this.state.tokens.length - 1].value;
let specifierTypeKind = null;
if (firstIdentName === "type") {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._type;
specifierTypeKind = "type";
}
exports.flowAfterParseVarHead = flowAfterParseVarHead;
// parse the return type of an async arrow function - let foo = (async (): number => {});
function flowStartParseAsyncArrowFromCallExpression() {
if (tokenizer_1.match(8192 /* colon */)) {
const oldNoAnonFunctionType = base_1.state.noAnonFunctionType;
base_1.state.noAnonFunctionType = true;
flowParseTypeAnnotation();
base_1.state.noAnonFunctionType = oldNoAnonFunctionType;
}
}
exports.flowStartParseAsyncArrowFromCallExpression = flowStartParseAsyncArrowFromCallExpression;
// We need to support type parameter declarations for arrow functions. This
// is tricky. There are three situations we need to handle
//
// 1. This is either JSX or an arrow function. We'll try JSX first. If that
// fails, we'll try an arrow function. If that fails, we'll throw the JSX
// error.
// 2. This is an arrow function. We'll parse the type parameter declaration,
// parse the rest, make sure the rest is an arrow function, and go from
// there
// 3. This is neither. Just call the super method
function flowParseMaybeAssign(noIn, afterLeftParse) {
let jsxError = null;
if (tokenizer_1.match(21000 /* lessThan */)) {
const snapshot = base_1.state.snapshot();
try {
return expression_1.baseParseMaybeAssign(noIn, afterLeftParse);
}
else if (firstIdentName === "typeof") {
specifierTypeKind = "typeof";
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._typeof;
}
if (this.isContextual("as") && !this.isLookaheadContextual("as")) {
this.parseIdentifier();
if (specifierTypeKind !== null && !this.match(types_1.types.name) && !this.state.type.keyword) {
// `import {type as ,` or `import {type as }`
catch (err) {
if (err instanceof SyntaxError) {
base_1.state.restoreFromSnapshot(snapshot);
base_1.state.type = 28160 /* typeParameterStart */;
jsxError = err;
}
else {
// `import {type as foo`
this.parseIdentifier();
// istanbul ignore next: no such error is expected
throw err;
}
}
else if (specifierTypeKind !== null && (this.match(types_1.types.name) || this.state.type.keyword)) {
// `import {type foo`
this.parseIdentifier();
if (this.eatContextual("as")) {
this.parseIdentifier();
}
}
}
// parse function type parameters - function foo<T>() {}
parseFunctionParams(allowModifiers, contextId) {
// Originally this checked if the method is a getter/setter, but if it was, we'd crash soon
// anyway, so don't try to propagate that information.
if (this.match(types_1.types.lessThan)) {
this.runInTypeContext(0, () => {
this.flowParseTypeParameterDeclaration();
if (jsxError != null || tokenizer_1.match(21000 /* lessThan */)) {
let wasArrow = false;
try {
tokenizer_1.runInTypeContext(0, () => {
flowParseTypeParameterDeclaration();
});
wasArrow = expression_1.baseParseMaybeAssign(noIn, afterLeftParse);
}
super.parseFunctionParams(allowModifiers, contextId);
}
// parse flow type annotations on variable declarator heads - let foo: string = bar
parseVarHead(isBlockScope) {
super.parseVarHead(isBlockScope);
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
catch (err) {
throw jsxError || err;
}
}
// parse the return type of an async arrow function - let foo = (async (): number => {});
parseAsyncArrowFromCallExpression(functionStart, startTokenIndex) {
if (this.match(types_1.types.colon)) {
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
this.state.noAnonFunctionType = true;
this.parseTypeAnnotation();
this.state.noAnonFunctionType = oldNoAnonFunctionType;
if (wasArrow) {
return true;
}
super.parseAsyncArrowFromCallExpression(functionStart, startTokenIndex);
util_1.unexpected();
}
// We need to support type parameter declarations for arrow functions. This
// is tricky. There are three situations we need to handle
//
// 1. This is either JSX or an arrow function. We'll try JSX first. If that
// fails, we'll try an arrow function. If that fails, we'll throw the JSX
// error.
// 2. This is an arrow function. We'll parse the type parameter declaration,
// parse the rest, make sure the rest is an arrow function, and go from
// there
// 3. This is neither. Just call the super method
parseMaybeAssign(noIn, afterLeftParse) {
let jsxError = null;
if (this.match(types_1.types.lessThan)) {
const snapshot = this.state.snapshot();
return expression_1.baseParseMaybeAssign(noIn, afterLeftParse);
}
exports.flowParseMaybeAssign = flowParseMaybeAssign;
// handle return types for arrow functions
function flowParseArrow() {
if (tokenizer_1.match(8192 /* colon */)) {
tokenizer_1.runInTypeContext(0, () => {
const snapshot = base_1.state.snapshot();
try {
return super.parseMaybeAssign(noIn, afterLeftParse);
const oldNoAnonFunctionType = base_1.state.noAnonFunctionType;
base_1.state.noAnonFunctionType = true;
flowParseTypeAndPredicateInitialiser();
base_1.state.noAnonFunctionType = oldNoAnonFunctionType;
if (util_1.canInsertSemicolon())
util_1.unexpected();
if (!tokenizer_1.match(10752 /* arrow */))
util_1.unexpected();
}
catch (err) {
if (err instanceof SyntaxError) {
this.state.restoreFromSnapshot(snapshot);
this.state.type = types_1.types.typeParameterStart;
jsxError = err;
base_1.state.restoreFromSnapshot(snapshot);
}

@@ -856,85 +847,42 @@ else {

}
}
if (jsxError != null || this.match(types_1.types.lessThan)) {
let wasArrow = false;
try {
this.runInTypeContext(0, () => {
this.flowParseTypeParameterDeclaration();
});
wasArrow = super.parseMaybeAssign(noIn, afterLeftParse);
}
catch (err) {
throw jsxError || err;
}
});
}
return tokenizer_1.eat(10752 /* arrow */);
}
exports.flowParseArrow = flowParseArrow;
function flowParseSubscripts(startPos, noCalls) {
if (base_1.state.tokens[base_1.state.tokens.length - 1].contextualKeyword === 3 /* _async */ &&
tokenizer_1.match(21000 /* lessThan */)) {
const snapshot = base_1.state.snapshot();
let error;
try {
const wasArrow = parseAsyncArrowWithTypeParameters(startPos);
if (wasArrow) {
return true;
return;
}
this.unexpected();
}
return super.parseMaybeAssign(noIn, afterLeftParse);
}
// handle return types for arrow functions
parseArrow() {
if (this.match(types_1.types.colon)) {
this.runInTypeContext(0, () => {
const snapshot = this.state.snapshot();
try {
const oldNoAnonFunctionType = this.state.noAnonFunctionType;
this.state.noAnonFunctionType = true;
this.flowParseTypeAndPredicateInitialiser();
this.state.noAnonFunctionType = oldNoAnonFunctionType;
if (this.canInsertSemicolon())
this.unexpected();
if (!this.match(types_1.types.arrow))
this.unexpected();
}
catch (err) {
if (err instanceof SyntaxError) {
this.state.restoreFromSnapshot(snapshot);
}
else {
// istanbul ignore next: no such error is expected
throw err;
}
}
});
catch (e) {
error = e;
}
return super.parseArrow();
}
parseSubscripts(startPos, noCalls) {
if (this.state.tokens[this.state.tokens.length - 1].value === "async" &&
this.match(types_1.types.lessThan)) {
const snapshot = this.state.snapshot();
let error;
try {
const wasArrow = this.parseAsyncArrowWithTypeParameters(startPos);
if (wasArrow) {
return;
}
}
catch (e) {
error = e;
}
this.state.restoreFromSnapshot(snapshot);
try {
super.parseSubscripts(startPos, noCalls);
return;
}
catch (e) {
throw error || e;
}
base_1.state.restoreFromSnapshot(snapshot);
try {
expression_1.baseParseSubscripts(startPos, noCalls);
return;
}
super.parseSubscripts(startPos, noCalls);
}
// Returns true if there was an arrow function here.
parseAsyncArrowWithTypeParameters(startPos) {
const startTokenIndex = this.state.tokens.length;
this.parseFunctionParams();
if (!this.parseArrow()) {
return false;
catch (e) {
throw error || e;
}
this.parseArrowExpression(startPos, startTokenIndex);
return true;
}
expression_1.baseParseSubscripts(startPos, noCalls);
}
exports.default = FlowParser;
exports.flowParseSubscripts = flowParseSubscripts;
// Returns true if there was an arrow function here.
function parseAsyncArrowWithTypeParameters(startPos) {
const startTokenIndex = base_1.state.tokens.length;
statement_1.parseFunctionParams();
if (!expression_1.parseArrow()) {
return false;
}
expression_1.parseArrowExpression(startPos, startTokenIndex);
return true;
}

@@ -1,23 +0,1 @@

import Parser from "../../parser";
export default class JSXParser extends Parser {
jsxReadToken(): void;
jsxReadNewLine(normalizeCRLF: boolean): string;
jsxReadString(quote: number): void;
jsxReadEntity(): string;
jsxReadWord(): void;
jsxParseIdentifier(): void;
jsxParseNamespacedName(): void;
jsxParseElementName(): void;
jsxParseAttributeValue(): void;
jsxParseEmptyExpression(): void;
jsxParseSpreadChild(): void;
jsxParseExpressionContainer(): void;
jsxParseAttribute(): void;
jsxParseOpeningElement(): boolean;
jsxParseClosingElement(): void;
jsxParseElementAt(): void;
jsxParseElement(): void;
parseExprAtom(): boolean;
nextJSXTagToken(): void;
nextJSXExprToken(): void;
}
export declare function jsxParseElement(): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const parser_1 = require("../../parser");
const base_1 = require("../../parser/base");
const expression_1 = require("../../parser/expression");
const util_1 = require("../../parser/util");
const tokenizer_1 = require("../../tokenizer");
const types_1 = require("../../tokenizer/types");
const charCodes = require("../../util/charcodes");
const identifier_1 = require("../../util/identifier");
const whitespace_1 = require("../../util/whitespace");
const xhtml_1 = require("./xhtml");
const HEX_NUMBER = /^[\da-fA-F]+$/;
const DECIMAL_NUMBER = /^\d+$/;
class JSXParser extends parser_1.default {
// Reads inline JSX contents token.
jsxReadToken() {
let out = "";
let chunkStart = this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
this.raise(this.state.start, "Unterminated JSX contents");
}
const ch = this.input.charCodeAt(this.state.pos);
switch (ch) {
case charCodes.lessThan:
case charCodes.leftCurlyBrace:
if (this.state.pos === this.state.start) {
if (ch === charCodes.lessThan) {
++this.state.pos;
this.finishToken(types_1.types.jsxTagStart);
return;
}
this.getTokenFromCode(ch);
// Reads inline JSX contents token.
function jsxReadToken() {
for (;;) {
if (base_1.state.pos >= base_1.input.length) {
base_1.raise(base_1.state.start, "Unterminated JSX contents");
}
const ch = base_1.input.charCodeAt(base_1.state.pos);
switch (ch) {
case 60 /* lessThan */:
case 123 /* leftCurlyBrace */:
if (base_1.state.pos === base_1.state.start) {
if (ch === 60 /* lessThan */) {
base_1.state.pos++;
tokenizer_1.finishToken(27136 /* jsxTagStart */);
return;
}
out += this.input.slice(chunkStart, this.state.pos);
this.finishToken(types_1.types.jsxText, out);
tokenizer_1.getTokenFromCode(ch);
return;
case charCodes.ampersand:
out += this.input.slice(chunkStart, this.state.pos);
out += this.jsxReadEntity();
chunkStart = this.state.pos;
break;
default:
if (whitespace_1.isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.jsxReadNewLine(true);
chunkStart = this.state.pos;
}
else {
++this.state.pos;
}
}
}
tokenizer_1.finishToken(26624 /* jsxText */);
return;
default:
base_1.state.pos++;
}
}
jsxReadNewLine(normalizeCRLF) {
const ch = this.input.charCodeAt(this.state.pos);
let out;
++this.state.pos;
if (ch === charCodes.carriageReturn &&
this.input.charCodeAt(this.state.pos) === charCodes.lineFeed) {
++this.state.pos;
out = normalizeCRLF ? "\n" : "\r\n";
}
function jsxReadString(quote) {
base_1.state.pos++;
for (;;) {
if (base_1.state.pos >= base_1.input.length) {
base_1.raise(base_1.state.start, "Unterminated string constant");
}
else {
out = String.fromCharCode(ch);
const ch = base_1.input.charCodeAt(base_1.state.pos);
if (ch === quote) {
base_1.state.pos++;
break;
}
return out;
base_1.state.pos++;
}
jsxReadString(quote) {
let out = "";
let chunkStart = ++this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
this.raise(this.state.start, "Unterminated string constant");
}
const ch = this.input.charCodeAt(this.state.pos);
if (ch === quote)
break;
if (ch === charCodes.ampersand) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.jsxReadEntity();
chunkStart = this.state.pos;
}
else if (whitespace_1.isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
out += this.jsxReadNewLine(false);
chunkStart = this.state.pos;
}
else {
++this.state.pos;
}
}
out += this.input.slice(chunkStart, this.state.pos++);
this.finishToken(types_1.types.string, out);
tokenizer_1.finishToken(1536 /* string */);
}
// Read a JSX identifier (valid tag or attribute name).
//
// Optimized version since JSX identifiers can't contain
// escape characters and so can be read as single slice.
// Also assumes that first character was already checked
// by isIdentifierStart in readToken.
function jsxReadWord() {
let ch;
do {
ch = base_1.input.charCodeAt(++base_1.state.pos);
} while (identifier_1.isIdentifierChar(ch) || ch === 45 /* dash */);
tokenizer_1.finishToken(26112 /* jsxName */);
}
// Parse next token as JSX identifier
function jsxParseIdentifier() {
nextJSXTagToken();
}
// Parse namespaced identifier.
function jsxParseNamespacedName() {
jsxParseIdentifier();
if (!tokenizer_1.eat(8192 /* colon */)) {
// Plain identifier, so this is an access.
base_1.state.tokens[base_1.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.Access;
return;
}
jsxReadEntity() {
let str = "";
let count = 0;
let entity;
let ch = this.input[this.state.pos];
const startPos = ++this.state.pos;
while (this.state.pos < this.input.length && count++ < 10) {
ch = this.input[this.state.pos++];
if (ch === ";") {
if (str[0] === "#") {
if (str[1] === "x") {
str = str.substr(2);
if (HEX_NUMBER.test(str)) {
entity = String.fromCodePoint(parseInt(str, 16));
}
}
else {
str = str.substr(1);
if (DECIMAL_NUMBER.test(str)) {
entity = String.fromCodePoint(parseInt(str, 10));
}
}
}
else {
entity = xhtml_1.default[str];
}
break;
}
str += ch;
}
if (!entity) {
this.state.pos = startPos;
return "&";
}
return entity;
// Process the second half of the namespaced name.
jsxParseIdentifier();
}
// Parses element name in any form - namespaced, member
// or single identifier.
function jsxParseElementName() {
jsxParseNamespacedName();
while (tokenizer_1.match(9216 /* dot */)) {
nextJSXTagToken();
jsxParseIdentifier();
}
// Read a JSX identifier (valid tag or attribute name).
//
// Optimized version since JSX identifiers can't contain
// escape characters and so can be read as single slice.
// Also assumes that first character was already checked
// by isIdentifierStart in readToken.
jsxReadWord() {
let ch;
const start = this.state.pos;
do {
ch = this.input.charCodeAt(++this.state.pos);
} while (identifier_1.isIdentifierChar(ch) || ch === charCodes.dash);
this.finishToken(types_1.types.jsxName, this.input.slice(start, this.state.pos));
}
// Parse next token as JSX identifier
jsxParseIdentifier() {
this.nextJSXTagToken();
}
// Parse namespaced identifier.
jsxParseNamespacedName() {
this.jsxParseIdentifier();
if (!this.eat(types_1.types.colon)) {
// Plain identifier, so this is an access.
this.state.tokens[this.state.tokens.length - 1].identifierRole = tokenizer_1.IdentifierRole.Access;
}
// Parses any type of JSX attribute value.
function jsxParseAttributeValue() {
switch (base_1.state.type) {
case 4096 /* braceL */:
jsxParseExpressionContainer();
nextJSXTagToken();
return;
}
// Process the second half of the namespaced name.
this.jsxParseIdentifier();
case 27136 /* jsxTagStart */:
jsxParseElement();
nextJSXTagToken();
return;
case 1536 /* string */:
nextJSXTagToken();
return;
default:
throw base_1.raise(base_1.state.start, "JSX value should be either an expression or a quoted JSX text");
}
// Parses element name in any form - namespaced, member
// or single identifier.
jsxParseElementName() {
this.jsxParseNamespacedName();
while (this.match(types_1.types.dot)) {
this.nextJSXTagToken();
this.jsxParseIdentifier();
}
}
function jsxParseEmptyExpression() {
// Do nothing.
}
// Parse JSX spread child
function jsxParseSpreadChild() {
util_1.expect(4096 /* braceL */);
util_1.expect(11776 /* ellipsis */);
expression_1.parseExpression();
util_1.expect(5120 /* braceR */);
}
// Parses JSX expression enclosed into curly brackets.
// Does not parse the last token.
function jsxParseExpressionContainer() {
tokenizer_1.next();
if (tokenizer_1.match(5120 /* braceR */)) {
jsxParseEmptyExpression();
}
// Parses any type of JSX attribute value.
jsxParseAttributeValue() {
switch (this.state.type) {
case types_1.types.braceL:
this.jsxParseExpressionContainer();
this.nextJSXTagToken();
return;
case types_1.types.jsxTagStart:
this.jsxParseElement();
this.nextJSXTagToken();
return;
case types_1.types.string:
this.nextJSXTagToken();
return;
default:
throw this.raise(this.state.start, "JSX value should be either an expression or a quoted JSX text");
}
else {
expression_1.parseExpression();
}
jsxParseEmptyExpression() {
// Do nothing.
}
// Parses following JSX attribute name-value pair.
function jsxParseAttribute() {
if (tokenizer_1.eat(4096 /* braceL */)) {
util_1.expect(11776 /* ellipsis */);
expression_1.parseMaybeAssign();
// }
nextJSXTagToken();
return;
}
// Parse JSX spread child
jsxParseSpreadChild() {
this.expect(types_1.types.braceL);
this.expect(types_1.types.ellipsis);
this.parseExpression();
this.expect(types_1.types.braceR);
jsxParseNamespacedName();
if (tokenizer_1.match(14368 /* eq */)) {
nextJSXTagToken();
jsxParseAttributeValue();
}
// Parses JSX expression enclosed into curly brackets.
// Does not parse the last token.
jsxParseExpressionContainer() {
this.next();
if (this.match(types_1.types.braceR)) {
this.jsxParseEmptyExpression();
}
else {
this.parseExpression();
}
}
// Parses JSX opening tag starting after "<".
// Returns true if the tag was self-closing.
// Does not parse the last token.
function jsxParseOpeningElement() {
if (tokenizer_1.match(27648 /* jsxTagEnd */)) {
nextJSXExprToken();
// This is an open-fragment.
return false;
}
// Parses following JSX attribute name-value pair.
jsxParseAttribute() {
if (this.eat(types_1.types.braceL)) {
this.expect(types_1.types.ellipsis);
this.parseMaybeAssign();
// }
this.nextJSXTagToken();
return;
}
this.jsxParseNamespacedName();
if (this.match(types_1.types.eq)) {
this.nextJSXTagToken();
this.jsxParseAttributeValue();
}
jsxParseElementName();
while (!tokenizer_1.match(25099 /* slash */) && !tokenizer_1.match(27648 /* jsxTagEnd */)) {
jsxParseAttribute();
}
// Parses JSX opening tag starting after "<".
// Returns true if the tag was self-closing.
// Does not parse the last token.
jsxParseOpeningElement() {
if (this.match(types_1.types.jsxTagEnd)) {
this.nextJSXExprToken();
// This is an open-fragment.
return false;
}
this.jsxParseElementName();
while (!this.match(types_1.types.slash) && !this.match(types_1.types.jsxTagEnd)) {
this.jsxParseAttribute();
}
const isSelfClosing = this.match(types_1.types.slash);
if (isSelfClosing) {
// /
this.nextJSXTagToken();
}
return isSelfClosing;
const isSelfClosing = tokenizer_1.match(25099 /* slash */);
if (isSelfClosing) {
// /
nextJSXTagToken();
}
// Parses JSX closing tag starting after "</".
// Does not parse the last token.
jsxParseClosingElement() {
if (this.eat(types_1.types.jsxTagEnd)) {
return;
}
this.jsxParseElementName();
return isSelfClosing;
}
// Parses JSX closing tag starting after "</".
// Does not parse the last token.
function jsxParseClosingElement() {
if (tokenizer_1.eat(27648 /* jsxTagEnd */)) {
return;
}
// Parses entire JSX element, including its opening tag
// (starting after "<"), attributes, contents and closing tag.
// Does not parse the last token.
jsxParseElementAt() {
const isSelfClosing = this.jsxParseOpeningElement();
if (!isSelfClosing) {
this.nextJSXExprToken();
contents: while (true) {
switch (this.state.type) {
case types_1.types.jsxTagStart:
this.nextJSXTagToken();
if (this.match(types_1.types.slash)) {
this.nextJSXTagToken();
this.jsxParseClosingElement();
break contents;
}
this.jsxParseElementAt();
this.nextJSXExprToken();
break;
case types_1.types.jsxText:
this.nextJSXExprToken();
break;
case types_1.types.braceL:
if (this.lookaheadType() === types_1.types.ellipsis) {
this.jsxParseSpreadChild();
}
else {
this.jsxParseExpressionContainer();
this.nextJSXExprToken();
}
break;
// istanbul ignore next - should never happen
default:
throw this.unexpected();
}
}
}
}
// Parses entire JSX element from current position.
// Does not parse the last token.
jsxParseElement() {
this.nextJSXTagToken();
this.jsxParseElementAt();
}
// ==================================
// Overrides
// ==================================
// Returns true if this was an arrow function.
parseExprAtom() {
if (this.match(types_1.types.jsxText)) {
this.parseLiteral();
return false;
}
else if (this.match(types_1.types.lessThan) && this.hasPlugin("jsx")) {
this.state.type = types_1.types.jsxTagStart;
this.jsxParseElement();
this.next();
return false;
}
else {
return super.parseExprAtom();
}
}
nextJSXTagToken() {
this.state.tokens.push(new tokenizer_1.Token(this.state));
this.skipSpace();
this.state.start = this.state.pos;
const code = this.fullCharCodeAtPos();
if (identifier_1.isIdentifierStart(code)) {
this.jsxReadWord();
}
else if (code === charCodes.quotationMark || code === charCodes.apostrophe) {
this.jsxReadString(code);
}
else {
// The following tokens are just one character each.
++this.state.pos;
switch (code) {
case charCodes.greaterThan:
this.finishToken(types_1.types.jsxTagEnd);
jsxParseElementName();
}
// Parses entire JSX element, including its opening tag
// (starting after "<"), attributes, contents and closing tag.
// Does not parse the last token.
function jsxParseElementAt() {
const isSelfClosing = jsxParseOpeningElement();
if (!isSelfClosing) {
nextJSXExprToken();
contents: while (true) {
switch (base_1.state.type) {
case 27136 /* jsxTagStart */:
nextJSXTagToken();
if (tokenizer_1.match(25099 /* slash */)) {
nextJSXTagToken();
jsxParseClosingElement();
break contents;
}
jsxParseElementAt();
nextJSXExprToken();
break;
case charCodes.slash:
this.finishToken(types_1.types.slash);
case 26624 /* jsxText */:
nextJSXExprToken();
break;
case charCodes.equalsTo:
this.finishToken(types_1.types.eq);
case 4096 /* braceL */:
if (tokenizer_1.lookaheadType() === 11776 /* ellipsis */) {
jsxParseSpreadChild();
}
else {
jsxParseExpressionContainer();
nextJSXExprToken();
}
break;
case charCodes.leftCurlyBrace:
this.finishToken(types_1.types.braceL);
break;
case charCodes.dot:
this.finishToken(types_1.types.dot);
break;
case charCodes.colon:
this.finishToken(types_1.types.colon);
break;
// istanbul ignore next - should never happen
default:
this.unexpected();
throw util_1.unexpected();
}
}
}
nextJSXExprToken() {
this.state.tokens.push(new tokenizer_1.Token(this.state));
this.state.start = this.state.pos;
this.jsxReadToken();
}
// Parses entire JSX element from current position.
// Does not parse the last token.
function jsxParseElement() {
nextJSXTagToken();
jsxParseElementAt();
}
exports.jsxParseElement = jsxParseElement;
// ==================================
// Overrides
// ==================================
function nextJSXTagToken() {
base_1.state.tokens.push(new tokenizer_1.Token());
tokenizer_1.skipSpace();
base_1.state.start = base_1.state.pos;
const code = base_1.input.charCodeAt(base_1.state.pos);
if (identifier_1.isIdentifierStart(code)) {
jsxReadWord();
}
else if (code === 34 /* quotationMark */ || code === 39 /* apostrophe */) {
jsxReadString(code);
}
else {
// The following tokens are just one character each.
++base_1.state.pos;
switch (code) {
case 62 /* greaterThan */:
tokenizer_1.finishToken(27648 /* jsxTagEnd */);
break;
case 47 /* slash */:
tokenizer_1.finishToken(25099 /* slash */);
break;
case 61 /* equalsTo */:
tokenizer_1.finishToken(14368 /* eq */);
break;
case 123 /* leftCurlyBrace */:
tokenizer_1.finishToken(4096 /* braceL */);
break;
case 46 /* dot */:
tokenizer_1.finishToken(9216 /* dot */);
break;
case 58 /* colon */:
tokenizer_1.finishToken(8192 /* colon */);
break;
default:
util_1.unexpected();
}
}
}
exports.default = JSXParser;
function nextJSXExprToken() {
base_1.state.tokens.push(new tokenizer_1.Token());
base_1.state.start = base_1.state.pos;
jsxReadToken();
}

@@ -1,13 +0,5 @@

import JSXParser from "./jsx";
/**
* Common parser code for TypeScript and Flow.
*/
export default abstract class TypeParser extends JSXParser {
abstract parseTypeAnnotation(): void;
parseConditional(noIn: boolean | null, startPos: number): void;
parseParenItem(): void;
isClassMethod(): boolean;
isClassProperty(): boolean;
shouldParseArrow(): boolean;
shouldParseAsyncArrow(): boolean;
}
export declare function typedParseConditional(noIn: boolean | null, startPos: number): void;
export declare function typedParseParenItem(): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../tokenizer/types");
const jsx_1 = require("./jsx");
const base_1 = require("../parser/base");
const expression_1 = require("../parser/expression");
const tokenizer_1 = require("../tokenizer");
const flow_1 = require("./flow");
const typescript_1 = require("./typescript");
/**
* Common parser code for TypeScript and Flow.
*/
class TypeParser extends jsx_1.default {
// An apparent conditional expression could actually be an optional parameter in an arrow function.
parseConditional(noIn, startPos) {
// only do the expensive clone if there is a question mark
// and if we come from inside parens
if (!this.match(types_1.types.question)) {
super.parseConditional(noIn, startPos);
return;
// An apparent conditional expression could actually be an optional parameter in an arrow function.
function typedParseConditional(noIn, startPos) {
// only do the expensive clone if there is a question mark
// and if we come from inside parens
if (!tokenizer_1.match(9728 /* question */)) {
expression_1.baseParseConditional(noIn, startPos);
return;
}
const snapshot = base_1.state.snapshot();
try {
expression_1.baseParseConditional(noIn, startPos);
return;
}
catch (err) {
if (!(err instanceof SyntaxError)) {
// istanbul ignore next: no such error is expected
throw err;
}
const snapshot = this.state.snapshot();
try {
super.parseConditional(noIn, startPos);
return;
}
catch (err) {
if (!(err instanceof SyntaxError)) {
// istanbul ignore next: no such error is expected
throw err;
}
this.state.restoreFromSnapshot(snapshot);
}
base_1.state.restoreFromSnapshot(snapshot);
}
// Note: These "type casts" are *not* valid TS expressions.
// But we parse them here and change them when completing the arrow function.
parseParenItem() {
super.parseParenItem();
if (this.eat(types_1.types.question)) {
this.state.tokens[this.state.tokens.length - 1].isType = true;
}
exports.typedParseConditional = typedParseConditional;
// Note: These "type casts" are *not* valid TS expressions.
// But we parse them here and change them when completing the arrow function.
function typedParseParenItem() {
if (tokenizer_1.eat(9728 /* question */)) {
base_1.state.tokens[base_1.state.tokens.length - 1].isType = true;
}
if (tokenizer_1.match(8192 /* colon */)) {
if (base_1.hasPlugin("typescript")) {
typescript_1.tsParseTypeAnnotation();
}
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
else if (base_1.hasPlugin("flow")) {
flow_1.flowParseTypeAnnotation();
}
}
isClassMethod() {
return this.match(types_1.types.lessThan) || super.isClassMethod();
}
isClassProperty() {
return this.match(types_1.types.colon) || super.isClassProperty();
}
shouldParseArrow() {
return this.match(types_1.types.colon) || super.shouldParseArrow();
}
shouldParseAsyncArrow() {
return this.match(types_1.types.colon) || super.shouldParseAsyncArrow();
}
}
exports.default = TypeParser;
exports.typedParseParenItem = typedParseParenItem;

@@ -1,119 +0,32 @@

import { TokenType } from "../tokenizer/types";
import TypeParser from "./types";
export declare type TsModifier = "readonly" | "abstract" | "static" | "public" | "private" | "protected";
import { ContextualKeyword } from "../tokenizer";
export declare type TsModifier = ContextualKeyword._readonly | ContextualKeyword._abstract | ContextualKeyword._static | ContextualKeyword._public | ContextualKeyword._private | ContextualKeyword._protected;
export declare type ParsingContext = "EnumMembers" | "HeritageClauseElement" | "TupleElementTypes" | "TypeMembers" | "TypeParametersOrArguments";
export default class TypeScriptParser extends TypeParser {
tsIsIdentifier(): boolean;
tsNextTokenCanFollowModifier(): boolean;
/** Parses a modifier matching one the given modifier names. */
tsParseModifier<T extends TsModifier>(allowedModifiers: Array<T>): T | null;
tsIsListTerminator(kind: ParsingContext): boolean;
tsParseList(kind: ParsingContext, parseElement: () => void): void;
tsParseDelimitedList(kind: ParsingContext, parseElement: () => void): void;
/**
* If !expectSuccess, returns undefined instead of failing to parse.
* If expectSuccess, parseElement should always return a defined value.
*/
tsParseDelimitedListWorker(kind: ParsingContext, parseElement: () => void): void;
tsParseBracketedList(kind: ParsingContext, parseElement: () => void, bracket: boolean, skipFirstToken: boolean): void;
tsParseEntityName(): void;
tsParseTypeReference(): void;
tsParseThisTypePredicate(): void;
tsParseThisTypeNode(): void;
tsParseTypeQuery(): void;
tsParseTypeParameter(): void;
tsTryParseTypeParameters(): void;
tsParseTypeParameters(): void;
tsFillSignature(returnToken: TokenType): void;
tsParseBindingListForSignature(isBlockScope: boolean): void;
tsParseTypeMemberSemicolon(): void;
tsParseSignatureMember(kind: "TSCallSignatureDeclaration" | "TSConstructSignatureDeclaration"): void;
tsIsUnambiguouslyIndexSignature(): boolean;
tsTryParseIndexSignature(): boolean;
tsParsePropertyOrMethodSignature(readonly: boolean): void;
tsParseTypeMember(): void;
tsIsStartOfConstructSignature(): boolean;
tsParseTypeLiteral(): void;
tsParseObjectTypeMembers(): void;
tsIsStartOfMappedType(): boolean;
tsParseMappedTypeParameter(): void;
tsParseMappedType(): void;
tsParseTupleType(): void;
tsParseParenthesizedType(): void;
tsParseFunctionOrConstructorType(type: "TSFunctionType" | "TSConstructorType"): void;
tsParseNonArrayType(): void;
tsParseArrayTypeOrHigher(): void;
tsParseTypeOperator(operator: "keyof"): void;
tsParseTypeOperatorOrHigher(): void;
tsParseUnionOrIntersectionType(kind: "TSUnionType" | "TSIntersectionType", parseConstituentType: () => void, operator: TokenType): void;
tsParseIntersectionTypeOrHigher(): void;
tsParseUnionTypeOrHigher(): void;
tsIsStartOfFunctionType(): boolean;
tsSkipParameterStart(): boolean;
tsIsUnambiguouslyStartOfFunctionType(): boolean;
tsParseTypeOrTypePredicateAnnotation(returnToken: TokenType): void;
tsTryParseTypeOrTypePredicateAnnotation(): void;
tsTryParseTypeAnnotation(): void;
tsTryParseType(): void;
tsParseTypePredicatePrefix(): boolean;
parseTypeAnnotation(): void;
tsParseType(): void;
tsParseTypeAssertion(): void;
tsTryParseTypeArgumentsInExpression(): boolean;
tsParseHeritageClause(): void;
tsParseExpressionWithTypeArguments(): void;
tsParseInterfaceDeclaration(): void;
tsParseTypeAliasDeclaration(): void;
tsParseEnumMember(): void;
tsParseEnumDeclaration(): void;
tsParseModuleBlock(): void;
tsParseModuleOrNamespaceDeclaration(): void;
tsParseAmbientExternalModuleDeclaration(): void;
tsParseImportEqualsDeclaration(): void;
tsIsExternalModuleReference(): boolean;
tsParseModuleReference(): void;
tsParseExternalModuleReference(): void;
tsLookAhead<T>(f: () => T): T;
tsTryParseAndCatch<T>(f: () => void): boolean;
tsTryParse<T>(f: () => boolean): boolean;
tsTryParseDeclare(): boolean;
tsTryParseExportDeclaration(): boolean;
tsParseExpressionStatement(name: string): boolean;
tsParseDeclaration(name: string, next: boolean): boolean;
tsTryParseGenericAsyncArrowFunction(): boolean;
tsParseTypeArguments(): void;
tsIsDeclarationStart(): boolean;
isExportDefaultSpecifier(): boolean;
parseAssignableListItem(allowModifiers: boolean | null, isBlockScope: boolean): void;
parseFunctionBodyAndFinish(functionStart: number, isGenerator: boolean, allowExpressionBody?: boolean, funcContextId?: number): void;
parseSubscript(startPos: number, noCalls: boolean | null, state: {
stop: boolean;
}): void;
parseNewArguments(): void;
parseExprOp(minPrec: number, noIn: boolean | null): void;
checkDuplicateExports(): void;
parseImport(): void;
parseExport(): void;
parseExportDefaultExpression(): void;
parseStatementContent(declaration: boolean, topLevel?: boolean): void;
parseAccessModifier(): void;
parseClassMember(memberStart: number, classContextId: number): void;
parseClassMemberWithIsStatic(memberStart: number, isStatic: boolean, classContextId: number): void;
parsePostMemberNameModifiers(): void;
parseIdentifierStatement(name: string): void;
shouldParseExportDeclaration(): boolean;
parseExportDeclaration(): void;
parseClassId(isStatement: boolean, optionalId?: boolean): void;
parseClassProperty(): void;
parseClassMethod(functionStart: number, isGenerator: boolean, isConstructor: boolean): void;
parseClassSuper(): boolean;
parseObjPropValue(isGenerator: boolean, isPattern: boolean, isBlockScope: boolean, objectContextId: number): void;
parseFunctionParams(allowModifiers?: boolean, contextId?: number): void;
parseVarHead(isBlockScope: boolean): void;
parseAsyncArrowFromCallExpression(functionStart: number, startTokenIndex: number): void;
parseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): boolean;
parseMaybeUnary(): boolean;
parseArrow(): boolean;
parseAssignableListItemTypes(): void;
parseBindingAtom(isBlockScope: boolean): void;
}
/** Parses a modifier matching one the given modifier names. */
export declare function tsParseModifier<T extends TsModifier>(allowedModifiers: Array<T>): T | null;
export declare function tsTryParseTypeParameters(): void;
export declare function tsTryParseTypeAnnotation(): void;
export declare function tsParseTypeAnnotation(): void;
export declare function tsParseType(): void;
export declare function tsParseTypeAssertion(): void;
export declare function tsParseImportEqualsDeclaration(): void;
export declare function tsIsDeclarationStart(): boolean;
export declare function tsParseFunctionBodyAndFinish(functionStart: number, isGenerator: boolean, allowExpressionBody?: boolean | null, funcContextId?: number): void;
export declare function tsParseSubscript(startPos: number, noCalls: boolean | null, stopState: {
stop: boolean;
}): void;
export declare function tsStartParseNewArguments(): void;
export declare function tsTryParseExport(): boolean;
export declare function tsTryParseExportDefaultExpression(): boolean;
export declare function tsTryParseStatementContent(): boolean;
export declare function tsParseAccessModifier(): void;
export declare function tsTryParseClassMemberWithIsStatic(isStatic: boolean, classContextId: number): boolean;
export declare function tsParseIdentifierStatement(contextualKeyword: ContextualKeyword): void;
export declare function tsParseExportDeclaration(): void;
export declare function tsAfterParseClassSuper(hasSuper: boolean): void;
export declare function tsStartParseObjPropValue(): void;
export declare function tsStartParseFunctionParams(): void;
export declare function tsAfterParseVarHead(): void;
export declare function tsStartParseAsyncArrowFromCallExpression(): void;
export declare function tsParseMaybeAssign(noIn?: boolean | null, afterLeftParse?: Function): boolean;
export declare function tsParseArrow(): boolean;
export declare function tsParseAssignableListItemTypes(): void;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("../tokenizer/types");
const types_2 = require("./types");
function nonNull(x) {
if (x == null) {
// $FlowIgnore
throw new Error(`Unexpected ${x} value.`);
}
return x;
}
const base_1 = require("../parser/base");
const expression_1 = require("../parser/expression");
const lval_1 = require("../parser/lval");
const statement_1 = require("../parser/statement");
const util_1 = require("../parser/util");
const tokenizer_1 = require("../tokenizer");
function assert(x) {

@@ -17,1173 +14,1064 @@ if (!x) {

}
// Doesn't handle "void" or "null" because those are keywords, not identifiers.
function isTypeKeyword(value) {
switch (value) {
case "any":
case "boolean":
case "never":
case "number":
case "object":
case "string":
case "symbol":
case "undefined":
return true;
default:
return false;
}
function tsIsIdentifier() {
// TODO: actually a bit more complex in TypeScript, but shouldn't matter.
// See https://github.com/Microsoft/TypeScript/issues/15008
return tokenizer_1.match(2048 /* name */);
}
class TypeScriptParser extends types_2.default {
tsIsIdentifier() {
// TODO: actually a bit more complex in TypeScript, but shouldn't matter.
// See https://github.com/Microsoft/TypeScript/issues/15008
return this.match(types_1.types.name);
}
tsNextTokenCanFollowModifier() {
// Note: TypeScript's implementation is much more complicated because
// more things are considered modifiers there.
// This implementation only handles modifiers not handled by babylon itself. And "static".
// TODO: Would be nice to avoid lookahead. Want a hasLineBreakUpNext() method...
this.next();
return (!this.hasPrecedingLineBreak() &&
!this.match(types_1.types.parenL) &&
!this.match(types_1.types.colon) &&
!this.match(types_1.types.eq) &&
!this.match(types_1.types.question));
}
/** Parses a modifier matching one the given modifier names. */
tsParseModifier(allowedModifiers) {
if (!this.match(types_1.types.name)) {
return null;
}
const modifier = this.state.value;
if (allowedModifiers.indexOf(modifier) !== -1 &&
this.tsTryParse(() => this.tsNextTokenCanFollowModifier())) {
switch (modifier) {
case "readonly":
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._readonly;
break;
case "abstract":
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._abstract;
break;
case "static":
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._static;
break;
case "public":
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._public;
break;
case "private":
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._private;
break;
case "protected":
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._protected;
break;
default:
break;
}
return modifier;
}
function tsNextTokenCanFollowModifier() {
// Note: TypeScript's implementation is much more complicated because
// more things are considered modifiers there.
// This implementation only handles modifiers not handled by babylon itself. And "static".
// TODO: Would be nice to avoid lookahead. Want a hasLineBreakUpNext() method...
tokenizer_1.next();
return (!util_1.hasPrecedingLineBreak() &&
!tokenizer_1.match(6144 /* parenL */) &&
!tokenizer_1.match(8192 /* colon */) &&
!tokenizer_1.match(14368 /* eq */) &&
!tokenizer_1.match(9728 /* question */));
}
/** Parses a modifier matching one the given modifier names. */
function tsParseModifier(allowedModifiers) {
if (!tokenizer_1.match(2048 /* name */)) {
return null;
}
tsIsListTerminator(kind) {
switch (kind) {
case "EnumMembers":
case "TypeMembers":
return this.match(types_1.types.braceR);
case "HeritageClauseElement":
return this.match(types_1.types.braceL);
case "TupleElementTypes":
return this.match(types_1.types.bracketR);
case "TypeParametersOrArguments":
return this.match(types_1.types.greaterThan);
const modifier = base_1.state.contextualKeyword;
if (allowedModifiers.indexOf(modifier) !== -1 &&
tsTryParse(() => tsNextTokenCanFollowModifier())) {
switch (modifier) {
case 25 /* _readonly */:
base_1.state.tokens[base_1.state.tokens.length - 1].type = 50192 /* _readonly */;
break;
case 1 /* _abstract */:
base_1.state.tokens[base_1.state.tokens.length - 1].type = 50704 /* _abstract */;
break;
case 27 /* _static */:
base_1.state.tokens[base_1.state.tokens.length - 1].type = 51216 /* _static */;
break;
case 24 /* _public */:
base_1.state.tokens[base_1.state.tokens.length - 1].type = 51728 /* _public */;
break;
case 22 /* _private */:
base_1.state.tokens[base_1.state.tokens.length - 1].type = 52240 /* _private */;
break;
case 23 /* _protected */:
base_1.state.tokens[base_1.state.tokens.length - 1].type = 52752 /* _protected */;
break;
default:
break;
}
throw new Error("Unreachable");
return modifier;
}
tsParseList(kind, parseElement) {
while (!this.tsIsListTerminator(kind)) {
// Skipping "parseListElement" from the TS source since that's just for error handling.
parseElement();
}
return null;
}
exports.tsParseModifier = tsParseModifier;
function tsIsListTerminator(kind) {
switch (kind) {
case "EnumMembers":
case "TypeMembers":
return tokenizer_1.match(5120 /* braceR */);
case "HeritageClauseElement":
return tokenizer_1.match(4096 /* braceL */);
case "TupleElementTypes":
return tokenizer_1.match(3584 /* bracketR */);
case "TypeParametersOrArguments":
return tokenizer_1.match(21512 /* greaterThan */);
default:
break;
}
tsParseDelimitedList(kind, parseElement) {
this.tsParseDelimitedListWorker(kind, parseElement);
throw new Error("Unreachable");
}
function tsParseList(kind, parseElement) {
while (!tsIsListTerminator(kind)) {
// Skipping "parseListElement" from the TS source since that's just for error handling.
parseElement();
}
/**
* If !expectSuccess, returns undefined instead of failing to parse.
* If expectSuccess, parseElement should always return a defined value.
*/
tsParseDelimitedListWorker(kind, parseElement) {
while (true) {
if (this.tsIsListTerminator(kind)) {
break;
}
parseElement();
if (this.eat(types_1.types.comma)) {
continue;
}
if (this.tsIsListTerminator(kind)) {
break;
}
}
function tsParseDelimitedList(kind, parseElement) {
tsParseDelimitedListWorker(kind, parseElement);
}
/**
* If !expectSuccess, returns undefined instead of failing to parse.
* If expectSuccess, parseElement should always return a defined value.
*/
function tsParseDelimitedListWorker(kind, parseElement) {
while (true) {
if (tsIsListTerminator(kind)) {
break;
}
parseElement();
if (tokenizer_1.eat(7168 /* comma */)) {
continue;
}
if (tsIsListTerminator(kind)) {
break;
}
}
tsParseBracketedList(kind, parseElement, bracket, skipFirstToken) {
if (!skipFirstToken) {
if (bracket) {
this.expect(types_1.types.bracketL);
}
else {
this.expect(types_1.types.lessThan);
}
}
this.tsParseDelimitedList(kind, parseElement);
}
function tsParseBracketedList(kind, parseElement, bracket, skipFirstToken) {
if (!skipFirstToken) {
if (bracket) {
this.expect(types_1.types.bracketR);
util_1.expect(3072 /* bracketL */);
}
else {
this.expect(types_1.types.greaterThan);
util_1.expect(21000 /* lessThan */);
}
}
tsParseEntityName() {
this.parseIdentifier();
while (this.eat(types_1.types.dot)) {
this.parseIdentifier();
}
tsParseDelimitedList(kind, parseElement);
if (bracket) {
util_1.expect(3584 /* bracketR */);
}
tsParseTypeReference() {
this.tsParseEntityName();
if (!this.hasPrecedingLineBreak() && this.match(types_1.types.lessThan)) {
this.tsParseTypeArguments();
}
else {
util_1.expect(21512 /* greaterThan */);
}
tsParseThisTypePredicate() {
this.next();
this.parseTypeAnnotation();
}
function tsParseEntityName() {
expression_1.parseIdentifier();
while (tokenizer_1.eat(9216 /* dot */)) {
expression_1.parseIdentifier();
}
tsParseThisTypeNode() {
this.next();
}
function tsParseTypeReference() {
tsParseEntityName();
if (!util_1.hasPrecedingLineBreak() && tokenizer_1.match(21000 /* lessThan */)) {
tsParseTypeArguments();
}
tsParseTypeQuery() {
this.expect(types_1.types._typeof);
this.tsParseEntityName();
}
function tsParseThisTypePredicate() {
tokenizer_1.next();
tsParseTypeAnnotation();
}
function tsParseThisTypeNode() {
tokenizer_1.next();
}
function tsParseTypeQuery() {
util_1.expect(46736 /* _typeof */);
tsParseEntityName();
}
function tsParseTypeParameter() {
expression_1.parseIdentifier();
if (tokenizer_1.eat(42000 /* _extends */)) {
tsParseType();
}
tsParseTypeParameter() {
this.parseIdentifier();
if (this.eat(types_1.types._extends)) {
this.tsParseType();
}
if (this.eat(types_1.types.eq)) {
this.tsParseType();
}
if (tokenizer_1.eat(14368 /* eq */)) {
tsParseType();
}
tsTryParseTypeParameters() {
if (this.match(types_1.types.lessThan)) {
this.tsParseTypeParameters();
}
}
function tsTryParseTypeParameters() {
if (tokenizer_1.match(21000 /* lessThan */)) {
tsParseTypeParameters();
}
tsParseTypeParameters() {
this.runInTypeContext(0, () => {
if (this.match(types_1.types.lessThan) || this.match(types_1.types.typeParameterStart)) {
this.next();
}
else {
this.unexpected();
}
this.tsParseBracketedList("TypeParametersOrArguments", this.tsParseTypeParameter.bind(this),
/* bracket */ false,
/* skipFirstToken */ true);
});
}
// Note: In TypeScript implementation we must provide `yieldContext` and `awaitContext`,
// but here it's always false, because this is only used for types.
tsFillSignature(returnToken) {
// Arrow fns *must* have return token (`=>`). Normal functions can omit it.
const returnTokenRequired = returnToken === types_1.types.arrow;
this.tsTryParseTypeParameters();
this.expect(types_1.types.parenL);
this.tsParseBindingListForSignature(false /* isBlockScope */);
if (returnTokenRequired) {
this.tsParseTypeOrTypePredicateAnnotation(returnToken);
}
exports.tsTryParseTypeParameters = tsTryParseTypeParameters;
function tsParseTypeParameters() {
tokenizer_1.runInTypeContext(0, () => {
if (tokenizer_1.match(21000 /* lessThan */) || tokenizer_1.match(28160 /* typeParameterStart */)) {
tokenizer_1.next();
}
else if (this.match(returnToken)) {
this.tsParseTypeOrTypePredicateAnnotation(returnToken);
else {
util_1.unexpected();
}
tsParseBracketedList("TypeParametersOrArguments", tsParseTypeParameter,
/* bracket */ false,
/* skipFirstToken */ true);
});
}
// Note: In TypeScript implementation we must provide `yieldContext` and `awaitContext`,
// but here it's always false, because this is only used for types.
function tsFillSignature(returnToken) {
// Arrow fns *must* have return token (`=>`). Normal functions can omit it.
const returnTokenRequired = returnToken === 10752 /* arrow */;
tsTryParseTypeParameters();
util_1.expect(6144 /* parenL */);
tsParseBindingListForSignature(false /* isBlockScope */);
if (returnTokenRequired) {
tsParseTypeOrTypePredicateAnnotation(returnToken);
}
tsParseBindingListForSignature(isBlockScope) {
this.parseBindingList(types_1.types.parenR, isBlockScope);
else if (tokenizer_1.match(returnToken)) {
tsParseTypeOrTypePredicateAnnotation(returnToken);
}
tsParseTypeMemberSemicolon() {
if (!this.eat(types_1.types.comma)) {
this.semicolon();
}
}
function tsParseBindingListForSignature(isBlockScope) {
lval_1.parseBindingList(6656 /* parenR */, isBlockScope);
}
function tsParseTypeMemberSemicolon() {
if (!tokenizer_1.eat(7168 /* comma */)) {
util_1.semicolon();
}
tsParseSignatureMember(kind) {
if (kind === "TSConstructSignatureDeclaration") {
this.expect(types_1.types._new);
}
this.tsFillSignature(types_1.types.colon);
this.tsParseTypeMemberSemicolon();
}
function tsParseSignatureMember(kind) {
if (kind === "TSConstructSignatureDeclaration") {
util_1.expect(39952 /* _new */);
}
tsIsUnambiguouslyIndexSignature() {
this.next(); // Skip '{'
return this.eat(types_1.types.name) && this.match(types_1.types.colon);
tsFillSignature(8192 /* colon */);
tsParseTypeMemberSemicolon();
}
function tsIsUnambiguouslyIndexSignature() {
tokenizer_1.next(); // Skip '{'
return tokenizer_1.eat(2048 /* name */) && tokenizer_1.match(8192 /* colon */);
}
function tsTryParseIndexSignature() {
if (!(tokenizer_1.match(3072 /* bracketL */) && tsLookAhead(tsIsUnambiguouslyIndexSignature))) {
return false;
}
tsTryParseIndexSignature() {
if (!(this.match(types_1.types.bracketL) && this.tsLookAhead(this.tsIsUnambiguouslyIndexSignature.bind(this)))) {
return false;
}
this.expect(types_1.types.bracketL);
this.parseIdentifier();
this.parseTypeAnnotation();
this.expect(types_1.types.bracketR);
this.tsTryParseTypeAnnotation();
this.tsParseTypeMemberSemicolon();
return true;
util_1.expect(3072 /* bracketL */);
expression_1.parseIdentifier();
tsParseTypeAnnotation();
util_1.expect(3584 /* bracketR */);
tsTryParseTypeAnnotation();
tsParseTypeMemberSemicolon();
return true;
}
function tsParsePropertyOrMethodSignature(readonly) {
expression_1.parsePropertyName(-1 /* Types don't need context IDs. */);
tokenizer_1.eat(9728 /* question */);
if (!readonly && (tokenizer_1.match(6144 /* parenL */) || tokenizer_1.match(21000 /* lessThan */))) {
tsFillSignature(8192 /* colon */);
tsParseTypeMemberSemicolon();
}
tsParsePropertyOrMethodSignature(readonly) {
this.parsePropertyName(-1 /* Types don't need context IDs. */);
this.eat(types_1.types.question);
if (!readonly && (this.match(types_1.types.parenL) || this.match(types_1.types.lessThan))) {
this.tsFillSignature(types_1.types.colon);
this.tsParseTypeMemberSemicolon();
}
else {
this.tsTryParseTypeAnnotation();
this.tsParseTypeMemberSemicolon();
}
else {
tsTryParseTypeAnnotation();
tsParseTypeMemberSemicolon();
}
tsParseTypeMember() {
if (this.match(types_1.types.parenL) || this.match(types_1.types.lessThan)) {
this.tsParseSignatureMember("TSCallSignatureDeclaration");
return;
}
if (this.match(types_1.types._new) && this.tsLookAhead(this.tsIsStartOfConstructSignature.bind(this))) {
this.tsParseSignatureMember("TSConstructSignatureDeclaration");
return;
}
const readonly = !!this.tsParseModifier(["readonly"]);
const found = this.tsTryParseIndexSignature();
if (found) {
return;
}
this.tsParsePropertyOrMethodSignature(readonly);
}
function tsParseTypeMember() {
if (tokenizer_1.match(6144 /* parenL */) || tokenizer_1.match(21000 /* lessThan */)) {
tsParseSignatureMember("TSCallSignatureDeclaration");
return;
}
tsIsStartOfConstructSignature() {
this.next();
return this.match(types_1.types.parenL) || this.match(types_1.types.lessThan);
if (tokenizer_1.match(39952 /* _new */) && tsLookAhead(tsIsStartOfConstructSignature)) {
tsParseSignatureMember("TSConstructSignatureDeclaration");
return;
}
tsParseTypeLiteral() {
this.tsParseObjectTypeMembers();
const readonly = !!tsParseModifier([25 /* _readonly */]);
const found = tsTryParseIndexSignature();
if (found) {
return;
}
tsParseObjectTypeMembers() {
this.expect(types_1.types.braceL);
this.tsParseList("TypeMembers", this.tsParseTypeMember.bind(this));
this.expect(types_1.types.braceR);
tsParsePropertyOrMethodSignature(readonly);
}
function tsIsStartOfConstructSignature() {
tokenizer_1.next();
return tokenizer_1.match(6144 /* parenL */) || tokenizer_1.match(21000 /* lessThan */);
}
function tsParseTypeLiteral() {
tsParseObjectTypeMembers();
}
function tsParseObjectTypeMembers() {
util_1.expect(4096 /* braceL */);
tsParseList("TypeMembers", tsParseTypeMember);
util_1.expect(5120 /* braceR */);
}
function tsIsStartOfMappedType() {
tokenizer_1.next();
if (util_1.isContextual(25 /* _readonly */)) {
tokenizer_1.next();
}
tsIsStartOfMappedType() {
this.next();
if (this.isContextual("readonly")) {
this.next();
}
if (!this.match(types_1.types.bracketL)) {
return false;
}
this.next();
if (!this.tsIsIdentifier()) {
return false;
}
this.next();
return this.match(types_1.types._in);
if (!tokenizer_1.match(3072 /* bracketL */)) {
return false;
}
tsParseMappedTypeParameter() {
this.parseIdentifier();
this.expect(types_1.types._in);
this.tsParseType();
tokenizer_1.next();
if (!tsIsIdentifier()) {
return false;
}
tsParseMappedType() {
this.expect(types_1.types.braceL);
this.eatContextual("readonly");
this.expect(types_1.types.bracketL);
this.tsParseMappedTypeParameter();
this.expect(types_1.types.bracketR);
this.eat(types_1.types.question);
this.tsTryParseType();
this.semicolon();
this.expect(types_1.types.braceR);
tokenizer_1.next();
return tokenizer_1.match(45592 /* _in */);
}
function tsParseMappedTypeParameter() {
expression_1.parseIdentifier();
util_1.expect(45592 /* _in */);
tsParseType();
}
function tsParseMappedType() {
util_1.expect(4096 /* braceL */);
util_1.eatContextual(25 /* _readonly */);
util_1.expect(3072 /* bracketL */);
tsParseMappedTypeParameter();
util_1.expect(3584 /* bracketR */);
tokenizer_1.eat(9728 /* question */);
tsTryParseType();
util_1.semicolon();
util_1.expect(5120 /* braceR */);
}
function tsParseTupleType() {
tsParseBracketedList("TupleElementTypes", tsParseType,
/* bracket */ true,
/* skipFirstToken */ false);
}
function tsParseParenthesizedType() {
util_1.expect(6144 /* parenL */);
tsParseType();
util_1.expect(6656 /* parenR */);
}
function tsParseFunctionOrConstructorType(type) {
if (type === "TSConstructorType") {
util_1.expect(39952 /* _new */);
}
tsParseTupleType() {
this.tsParseBracketedList("TupleElementTypes", this.tsParseType.bind(this),
/* bracket */ true,
/* skipFirstToken */ false);
}
tsParseParenthesizedType() {
this.expect(types_1.types.parenL);
this.tsParseType();
this.expect(types_1.types.parenR);
}
tsParseFunctionOrConstructorType(type) {
if (type === "TSConstructorType") {
this.expect(types_1.types._new);
tsFillSignature(10752 /* arrow */);
}
function tsParseNonArrayType() {
switch (base_1.state.type) {
case 2048 /* name */:
tsParseTypeReference();
return;
case 47248 /* _void */:
case 44048 /* _null */:
tokenizer_1.next();
return;
case 1536 /* string */:
case 0 /* num */:
case 44560 /* _true */:
case 45072 /* _false */:
expression_1.parseLiteral();
return;
case 23690 /* minus */:
tokenizer_1.next();
expression_1.parseLiteral();
return;
case 40464 /* _this */: {
tsParseThisTypeNode();
if (util_1.isContextual(15 /* _is */) && !util_1.hasPrecedingLineBreak()) {
tsParseThisTypePredicate();
}
return;
}
this.tsFillSignature(types_1.types.arrow);
}
tsParseNonArrayType() {
switch (this.state.type) {
case types_1.types.name:
case types_1.types._void:
case types_1.types._null: {
if (this.match(types_1.types._void) || this.match(types_1.types._null) || isTypeKeyword(this.state.value)) {
this.next();
return;
}
this.tsParseTypeReference();
return;
case 46736 /* _typeof */:
tsParseTypeQuery();
return;
case 4096 /* braceL */:
if (tsLookAhead(tsIsStartOfMappedType)) {
tsParseMappedType();
}
case types_1.types.string:
case types_1.types.num:
case types_1.types._true:
case types_1.types._false:
this.parseLiteral();
return;
case types_1.types.plusMin:
// Allow negative signs but not plus signs before numbers.
if (this.state.value === "-") {
this.next();
this.parseLiteral();
return;
}
break;
case types_1.types._this: {
this.tsParseThisTypeNode();
if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
this.tsParseThisTypePredicate();
}
return;
else {
tsParseTypeLiteral();
}
case types_1.types._typeof:
this.tsParseTypeQuery();
return;
case types_1.types.braceL:
if (this.tsLookAhead(this.tsIsStartOfMappedType.bind(this))) {
this.tsParseMappedType();
}
else {
this.tsParseTypeLiteral();
}
return;
case types_1.types.bracketL:
this.tsParseTupleType();
return;
case types_1.types.parenL:
this.tsParseParenthesizedType();
return;
default:
break;
}
throw this.unexpected();
return;
case 3072 /* bracketL */:
tsParseTupleType();
return;
case 6144 /* parenL */:
tsParseParenthesizedType();
return;
default:
break;
}
tsParseArrayTypeOrHigher() {
this.tsParseNonArrayType();
while (!this.hasPrecedingLineBreak() && this.eat(types_1.types.bracketL)) {
if (!this.eat(types_1.types.bracketR)) {
// If we hit ] immediately, this is an array type, otherwise it's an indexed access type.
this.tsParseType();
this.expect(types_1.types.bracketR);
}
throw util_1.unexpected();
}
function tsParseArrayTypeOrHigher() {
tsParseNonArrayType();
while (!util_1.hasPrecedingLineBreak() && tokenizer_1.eat(3072 /* bracketL */)) {
if (!tokenizer_1.eat(3584 /* bracketR */)) {
// If we hit ] immediately, this is an array type, otherwise it's an indexed access type.
tsParseType();
util_1.expect(3584 /* bracketR */);
}
}
tsParseTypeOperator(operator) {
this.expectContextual(operator);
this.tsParseTypeOperatorOrHigher();
}
function tsParseTypeOperatorOrHigher() {
if (util_1.eatContextual(16 /* _keyof */)) {
tsParseTypeOperatorOrHigher();
}
tsParseTypeOperatorOrHigher() {
if (this.isContextual("keyof")) {
this.tsParseTypeOperator("keyof");
}
else {
this.tsParseArrayTypeOrHigher();
}
else {
tsParseArrayTypeOrHigher();
}
tsParseUnionOrIntersectionType(kind, parseConstituentType, operator) {
this.eat(operator);
parseConstituentType();
if (this.match(operator)) {
while (this.eat(operator)) {
parseConstituentType();
}
}
function tsParseUnionOrIntersectionType(kind, parseConstituentType, operator) {
tokenizer_1.eat(operator);
parseConstituentType();
if (tokenizer_1.match(operator)) {
while (tokenizer_1.eat(operator)) {
parseConstituentType();
}
}
tsParseIntersectionTypeOrHigher() {
this.tsParseUnionOrIntersectionType("TSIntersectionType", this.tsParseTypeOperatorOrHigher.bind(this), types_1.types.bitwiseAND);
}
function tsParseIntersectionTypeOrHigher() {
tsParseUnionOrIntersectionType("TSIntersectionType", tsParseTypeOperatorOrHigher, 19974 /* bitwiseAND */);
}
function tsParseUnionTypeOrHigher() {
tsParseUnionOrIntersectionType("TSUnionType", tsParseIntersectionTypeOrHigher, 18948 /* bitwiseOR */);
}
function tsIsStartOfFunctionType() {
if (tokenizer_1.match(21000 /* lessThan */)) {
return true;
}
tsParseUnionTypeOrHigher() {
this.tsParseUnionOrIntersectionType("TSUnionType", this.tsParseIntersectionTypeOrHigher.bind(this), types_1.types.bitwiseOR);
return tokenizer_1.match(6144 /* parenL */) && tsLookAhead(tsIsUnambiguouslyStartOfFunctionType);
}
function tsSkipParameterStart() {
if (tokenizer_1.match(2048 /* name */) || tokenizer_1.match(40464 /* _this */)) {
tokenizer_1.next();
return true;
}
tsIsStartOfFunctionType() {
if (this.match(types_1.types.lessThan)) {
return true;
}
return (this.match(types_1.types.parenL) &&
this.tsLookAhead(this.tsIsUnambiguouslyStartOfFunctionType.bind(this)));
return false;
}
function tsIsUnambiguouslyStartOfFunctionType() {
tokenizer_1.next();
if (tokenizer_1.match(6656 /* parenR */) || tokenizer_1.match(11776 /* ellipsis */)) {
// ( )
// ( ...
return true;
}
tsSkipParameterStart() {
if (this.match(types_1.types.name) || this.match(types_1.types._this)) {
this.next();
if (tsSkipParameterStart()) {
if (tokenizer_1.match(8192 /* colon */) || tokenizer_1.match(7168 /* comma */) || tokenizer_1.match(9728 /* question */) || tokenizer_1.match(14368 /* eq */)) {
// ( xxx :
// ( xxx ,
// ( xxx ?
// ( xxx =
return true;
}
return false;
}
tsIsUnambiguouslyStartOfFunctionType() {
this.next();
if (this.match(types_1.types.parenR) || this.match(types_1.types.ellipsis)) {
// ( )
// ( ...
return true;
}
if (this.tsSkipParameterStart()) {
if (this.match(types_1.types.colon) ||
this.match(types_1.types.comma) ||
this.match(types_1.types.question) ||
this.match(types_1.types.eq)) {
// ( xxx :
// ( xxx ,
// ( xxx ?
// ( xxx =
if (tokenizer_1.match(6656 /* parenR */)) {
tokenizer_1.next();
if (tokenizer_1.match(10752 /* arrow */)) {
// ( xxx ) =>
return true;
}
if (this.match(types_1.types.parenR)) {
this.next();
if (this.match(types_1.types.arrow)) {
// ( xxx ) =>
return true;
}
}
}
return false;
}
tsParseTypeOrTypePredicateAnnotation(returnToken) {
this.runInTypeContext(0, () => {
this.expect(returnToken);
this.tsTryParse(() => this.tsParseTypePredicatePrefix());
// Regardless of whether we found an "is" token, there's now just a regular type in front of
// us.
this.tsParseType();
});
return false;
}
function tsParseTypeOrTypePredicateAnnotation(returnToken) {
tokenizer_1.runInTypeContext(0, () => {
util_1.expect(returnToken);
tsTryParse(() => tsParseTypePredicatePrefix());
// Regardless of whether we found an "is" token, there's now just a regular type in front of
// us.
tsParseType();
});
}
function tsTryParseTypeOrTypePredicateAnnotation() {
if (tokenizer_1.match(8192 /* colon */)) {
tsParseTypeOrTypePredicateAnnotation(8192 /* colon */);
}
tsTryParseTypeOrTypePredicateAnnotation() {
if (this.match(types_1.types.colon)) {
this.tsParseTypeOrTypePredicateAnnotation(types_1.types.colon);
}
}
function tsTryParseTypeAnnotation() {
if (tokenizer_1.match(8192 /* colon */)) {
tsParseTypeAnnotation();
}
tsTryParseTypeAnnotation() {
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
}
}
exports.tsTryParseTypeAnnotation = tsTryParseTypeAnnotation;
function tsTryParseType() {
if (tokenizer_1.eat(8192 /* colon */)) {
tsParseType();
}
tsTryParseType() {
if (this.eat(types_1.types.colon)) {
this.tsParseType();
}
}
function tsParseTypePredicatePrefix() {
expression_1.parseIdentifier();
if (util_1.isContextual(15 /* _is */) && !util_1.hasPrecedingLineBreak()) {
tokenizer_1.next();
return true;
}
tsParseTypePredicatePrefix() {
this.parseIdentifier();
if (this.isContextual("is") && !this.hasPrecedingLineBreak()) {
this.next();
return true;
}
return false;
return false;
}
function tsParseTypeAnnotation() {
tokenizer_1.runInTypeContext(0, () => {
util_1.expect(8192 /* colon */);
tsParseType();
});
}
exports.tsParseTypeAnnotation = tsParseTypeAnnotation;
function tsParseType() {
if (tsIsStartOfFunctionType()) {
tsParseFunctionOrConstructorType("TSFunctionType");
return;
}
parseTypeAnnotation() {
this.runInTypeContext(0, () => {
this.expect(types_1.types.colon);
this.tsParseType();
if (tokenizer_1.match(39952 /* _new */)) {
// As in `new () => Date`
tsParseFunctionOrConstructorType("TSConstructorType");
return;
}
tsParseUnionTypeOrHigher();
}
exports.tsParseType = tsParseType;
function tsParseTypeAssertion() {
tokenizer_1.runInTypeContext(1, () => {
tsParseType();
util_1.expect(21512 /* greaterThan */);
});
expression_1.parseMaybeUnary();
}
exports.tsParseTypeAssertion = tsParseTypeAssertion;
// Returns true if parsing was successful.
function tsTryParseTypeArgumentsInExpression() {
return tsTryParseAndCatch(() => {
tokenizer_1.runInTypeContext(0, () => {
util_1.expect(21000 /* lessThan */);
base_1.state.tokens[base_1.state.tokens.length - 1].type = 28160 /* typeParameterStart */;
tsParseDelimitedList("TypeParametersOrArguments", tsParseType);
util_1.expect(21512 /* greaterThan */);
});
util_1.expect(6144 /* parenL */);
});
}
function tsParseHeritageClause() {
tsParseDelimitedList("HeritageClauseElement", tsParseExpressionWithTypeArguments);
}
function tsParseExpressionWithTypeArguments() {
// Note: TS uses parseLeftHandSideExpressionOrHigher,
// then has grammar errors later if it's not an EntityName.
tsParseEntityName();
if (tokenizer_1.match(21000 /* lessThan */)) {
tsParseTypeArguments();
}
tsParseType() {
if (this.tsIsStartOfFunctionType()) {
this.tsParseFunctionOrConstructorType("TSFunctionType");
return;
}
if (this.match(types_1.types._new)) {
// As in `new () => Date`
this.tsParseFunctionOrConstructorType("TSConstructorType");
return;
}
this.tsParseUnionTypeOrHigher();
}
function tsParseInterfaceDeclaration() {
expression_1.parseIdentifier();
tsTryParseTypeParameters();
if (tokenizer_1.eat(42000 /* _extends */)) {
tsParseHeritageClause();
}
tsParseTypeAssertion() {
this.runInTypeContext(1, () => {
this.tsParseType();
this.expect(types_1.types.greaterThan);
});
this.parseMaybeUnary();
tsParseObjectTypeMembers();
}
function tsParseTypeAliasDeclaration() {
expression_1.parseIdentifier();
tsTryParseTypeParameters();
util_1.expect(14368 /* eq */);
tsParseType();
util_1.semicolon();
}
function tsParseEnumMember() {
// Computed property names are grammar errors in an enum, so accept just string literal or identifier.
if (tokenizer_1.match(1536 /* string */)) {
expression_1.parseLiteral();
}
// Returns true if parsing was successful.
tsTryParseTypeArgumentsInExpression() {
return this.tsTryParseAndCatch(() => {
this.runInTypeContext(0, () => {
this.expect(types_1.types.lessThan);
this.state.tokens[this.state.tokens.length - 1].type = types_1.types.typeParameterStart;
this.tsParseDelimitedList("TypeParametersOrArguments", this.tsParseType.bind(this));
this.expect(types_1.types.greaterThan);
});
this.expect(types_1.types.parenL);
});
else {
expression_1.parseIdentifier();
}
tsParseHeritageClause() {
this.tsParseDelimitedList("HeritageClauseElement", this.tsParseExpressionWithTypeArguments.bind(this));
if (tokenizer_1.eat(14368 /* eq */)) {
const eqIndex = base_1.state.tokens.length - 1;
expression_1.parseMaybeAssign();
base_1.state.tokens[eqIndex].rhsEndIndex = base_1.state.tokens.length;
}
tsParseExpressionWithTypeArguments() {
// Note: TS uses parseLeftHandSideExpressionOrHigher,
// then has grammar errors later if it's not an EntityName.
this.tsParseEntityName();
if (this.match(types_1.types.lessThan)) {
this.tsParseTypeArguments();
}
}
function tsParseEnumDeclaration() {
expression_1.parseIdentifier();
util_1.expect(4096 /* braceL */);
tsParseDelimitedList("EnumMembers", tsParseEnumMember);
util_1.expect(5120 /* braceR */);
}
function tsParseModuleBlock() {
util_1.expect(4096 /* braceL */);
// Inside of a module block is considered "top-level", meaning it can have imports and exports.
statement_1.parseBlockBody(/* topLevel */ true, /* end */ 5120 /* braceR */);
}
function tsParseModuleOrNamespaceDeclaration() {
expression_1.parseIdentifier();
if (tokenizer_1.eat(9216 /* dot */)) {
tsParseModuleOrNamespaceDeclaration();
}
tsParseInterfaceDeclaration() {
this.parseIdentifier();
this.tsTryParseTypeParameters();
if (this.eat(types_1.types._extends)) {
this.tsParseHeritageClause();
}
this.tsParseObjectTypeMembers();
else {
tsParseModuleBlock();
}
tsParseTypeAliasDeclaration() {
this.parseIdentifier();
this.tsTryParseTypeParameters();
this.expect(types_1.types.eq);
this.tsParseType();
this.semicolon();
}
function tsParseAmbientExternalModuleDeclaration() {
if (util_1.isContextual(12 /* _global */)) {
expression_1.parseIdentifier();
}
tsParseEnumMember() {
// Computed property names are grammar errors in an enum, so accept just string literal or identifier.
if (this.match(types_1.types.string)) {
this.parseLiteral();
}
else {
this.parseIdentifier();
}
if (this.eat(types_1.types.eq)) {
const eqIndex = this.state.tokens.length - 1;
this.parseMaybeAssign();
this.state.tokens[eqIndex].rhsEndIndex = this.state.tokens.length;
}
else if (tokenizer_1.match(1536 /* string */)) {
expression_1.parseExprAtom();
}
tsParseEnumDeclaration() {
this.parseIdentifier();
this.expect(types_1.types.braceL);
this.tsParseDelimitedList("EnumMembers", this.tsParseEnumMember.bind(this));
this.expect(types_1.types.braceR);
else {
util_1.unexpected();
}
tsParseModuleBlock() {
this.expect(types_1.types.braceL);
// Inside of a module block is considered "top-level", meaning it can have imports and exports.
this.parseBlockBody(/* topLevel */ true, /* end */ types_1.types.braceR);
if (tokenizer_1.match(4096 /* braceL */)) {
tsParseModuleBlock();
}
tsParseModuleOrNamespaceDeclaration() {
this.parseIdentifier();
if (this.eat(types_1.types.dot)) {
this.tsParseModuleOrNamespaceDeclaration();
}
else {
this.tsParseModuleBlock();
}
else {
util_1.semicolon();
}
tsParseAmbientExternalModuleDeclaration() {
if (this.isContextual("global")) {
this.parseIdentifier();
}
else if (this.match(types_1.types.string)) {
this.parseExprAtom();
}
else {
this.unexpected();
}
if (this.match(types_1.types.braceL)) {
this.tsParseModuleBlock();
}
else {
this.semicolon();
}
}
function tsParseImportEqualsDeclaration() {
expression_1.parseIdentifier();
util_1.expect(14368 /* eq */);
tsParseModuleReference();
util_1.semicolon();
}
exports.tsParseImportEqualsDeclaration = tsParseImportEqualsDeclaration;
function tsIsExternalModuleReference() {
return util_1.isContextual(26 /* _require */) && tokenizer_1.lookaheadType() === 6144 /* parenL */;
}
function tsParseModuleReference() {
if (tsIsExternalModuleReference()) {
tsParseExternalModuleReference();
}
tsParseImportEqualsDeclaration() {
this.parseIdentifier();
this.expect(types_1.types.eq);
this.tsParseModuleReference();
this.semicolon();
else {
tsParseEntityName();
}
tsIsExternalModuleReference() {
return this.isContextual("require") && this.lookaheadType() === types_1.types.parenL;
}
function tsParseExternalModuleReference() {
util_1.expectContextual(26 /* _require */);
util_1.expect(6144 /* parenL */);
if (!tokenizer_1.match(1536 /* string */)) {
throw util_1.unexpected();
}
tsParseModuleReference() {
if (this.tsIsExternalModuleReference()) {
this.tsParseExternalModuleReference();
}
else {
this.tsParseEntityName();
}
expression_1.parseLiteral();
util_1.expect(6656 /* parenR */);
}
// Utilities
function tsLookAhead(f) {
const snapshot = base_1.state.snapshot();
const res = f();
base_1.state.restoreFromSnapshot(snapshot);
return res;
}
// Returns true if parsing was successful.
function tsTryParseAndCatch(f) {
const snapshot = base_1.state.snapshot();
try {
f();
return true;
}
tsParseExternalModuleReference() {
this.expectContextual("require");
this.expect(types_1.types.parenL);
if (!this.match(types_1.types.string)) {
throw this.unexpected();
catch (e) {
if (e instanceof SyntaxError) {
base_1.state.restoreFromSnapshot(snapshot);
return false;
}
this.parseLiteral();
this.expect(types_1.types.parenR);
throw e;
}
// Utilities
tsLookAhead(f) {
const snapshot = this.state.snapshot();
const res = f();
this.state.restoreFromSnapshot(snapshot);
return res;
}
// The function should return true if the parse was successful. If not, we revert the state to
// before we started parsing.
function tsTryParse(f) {
const snapshot = base_1.state.snapshot();
const wasSuccessful = f();
if (wasSuccessful) {
return true;
}
// Returns true if parsing was successful.
tsTryParseAndCatch(f) {
const snapshot = this.state.snapshot();
try {
f();
else {
base_1.state.restoreFromSnapshot(snapshot);
return false;
}
}
// Returns true if a statement matched.
function tsTryParseDeclare() {
switch (base_1.state.type) {
case 34320 /* _function */:
tokenizer_1.runInTypeContext(1, () => {
tokenizer_1.next();
// We don't need to precisely get the function start here, since it's only used to mark
// the function as a type if it's bodiless, and it's already a type here.
const functionStart = base_1.state.start;
statement_1.parseFunction(functionStart, /* isStatement */ true);
});
return true;
}
catch (e) {
if (e instanceof SyntaxError) {
this.state.restoreFromSnapshot(snapshot);
return false;
case 41488 /* _class */:
tokenizer_1.runInTypeContext(1, () => {
statement_1.parseClass(/* isStatement */ true, /* optionalId */ false);
});
return true;
case 38416 /* _const */:
if (tokenizer_1.match(38416 /* _const */) && util_1.isLookaheadContextual(8 /* _enum */)) {
tokenizer_1.runInTypeContext(1, () => {
// `const enum = 0;` not allowed because "enum" is a strict mode reserved word.
util_1.expect(38416 /* _const */);
util_1.expectContextual(8 /* _enum */);
base_1.state.tokens[base_1.state.tokens.length - 1].type = 53776 /* _enum */;
tsParseEnumDeclaration();
});
return true;
}
throw e;
}
}
// The function should return true if the parse was successful. If not, we revert the state to
// before we started parsing.
tsTryParse(f) {
const snapshot = this.state.snapshot();
const wasSuccessful = f();
if (wasSuccessful) {
// falls through
case 37392 /* _var */:
case 37904 /* _let */:
tokenizer_1.runInTypeContext(1, () => {
statement_1.parseVarStatement(base_1.state.type);
});
return true;
case 2048 /* name */: {
return tokenizer_1.runInTypeContext(1, () => {
const contextualKeyword = base_1.state.contextualKeyword;
if (contextualKeyword === 12 /* _global */) {
tsParseAmbientExternalModuleDeclaration();
return true;
}
else {
return tsParseDeclaration(contextualKeyword, /* isBeforeToken */ true);
}
});
}
else {
this.state.restoreFromSnapshot(snapshot);
default:
return false;
}
}
// Note: this won't be called unless the keyword is allowed in `shouldParseExportDeclaration`.
// Returns true if it matched a declaration.
function tsTryParseExportDeclaration() {
return tsParseDeclaration(base_1.state.contextualKeyword, /* isBeforeToken */ true);
}
// Returns true if it matched a statement.
function tsParseExpressionStatement(contextualKeyword) {
switch (contextualKeyword) {
case 7 /* _declare */: {
const declareTokenIndex = base_1.state.tokens.length - 1;
const matched = tsTryParseDeclare();
if (matched) {
base_1.state.tokens[declareTokenIndex].type = 49680 /* _declare */;
return true;
}
break;
}
case 12 /* _global */:
// `global { }` (with no `declare`) may appear inside an ambient module declaration.
// Would like to use tsParseAmbientExternalModuleDeclaration here, but already ran past "global".
if (tokenizer_1.match(4096 /* braceL */)) {
tsParseModuleBlock();
return true;
}
break;
default:
return tsParseDeclaration(contextualKeyword, /* isBeforeToken */ false);
}
// Returns true if a statement matched.
tsTryParseDeclare() {
switch (this.state.type) {
case types_1.types._function:
this.runInTypeContext(1, () => {
this.next();
// We don't need to precisely get the function start here, since it's only used to mark
// the function as a type if it's bodiless, and it's already a type here.
const functionStart = this.state.start;
this.parseFunction(functionStart, /* isStatement */ true);
return false;
}
// Common to tsTryParseDeclare, tsTryParseExportDeclaration, and tsParseExpressionStatement.
// Returns true if it matched a declaration.
function tsParseDeclaration(contextualKeyword, isBeforeToken) {
switch (contextualKeyword) {
case 1 /* _abstract */:
if (isBeforeToken || tokenizer_1.match(41488 /* _class */)) {
if (isBeforeToken)
tokenizer_1.next();
base_1.state.tokens[base_1.state.tokens.length - 1].type = 50704 /* _abstract */;
statement_1.parseClass(/* isStatement */ true, /* optionalId */ false);
return true;
}
break;
case 8 /* _enum */:
if (isBeforeToken || tokenizer_1.match(2048 /* name */)) {
if (isBeforeToken)
tokenizer_1.next();
base_1.state.tokens[base_1.state.tokens.length - 1].type = 53776 /* _enum */;
tsParseEnumDeclaration();
return true;
}
break;
case 14 /* _interface */:
if (isBeforeToken || tokenizer_1.match(2048 /* name */)) {
// `next` is true in "export" and "declare" contexts, so we want to remove that token
// as well.
tokenizer_1.runInTypeContext(1, () => {
if (isBeforeToken)
tokenizer_1.next();
tsParseInterfaceDeclaration();
});
return true;
case types_1.types._class:
this.runInTypeContext(1, () => {
this.parseClass(/* isStatement */ true, /* optionalId */ false);
}
break;
case 18 /* _module */:
if (isBeforeToken)
tokenizer_1.next();
if (tokenizer_1.match(1536 /* string */)) {
tokenizer_1.runInTypeContext(isBeforeToken ? 2 : 1, () => {
tsParseAmbientExternalModuleDeclaration();
});
return true;
case types_1.types._const:
if (this.match(types_1.types._const) && this.isLookaheadContextual("enum")) {
this.runInTypeContext(1, () => {
// `const enum = 0;` not allowed because "enum" is a strict mode reserved word.
this.expect(types_1.types._const);
this.expectContextual("enum");
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._enum;
this.tsParseEnumDeclaration();
});
return true;
}
// falls through
case types_1.types._var:
case types_1.types._let:
this.runInTypeContext(1, () => {
this.parseVarStatement(this.state.type);
}
else if (tokenizer_1.next || tokenizer_1.match(2048 /* name */)) {
tokenizer_1.runInTypeContext(isBeforeToken ? 2 : 1, () => {
tsParseModuleOrNamespaceDeclaration();
});
return true;
case types_1.types.name: {
return this.runInTypeContext(1, () => {
const value = this.state.value;
if (value === "global") {
this.tsParseAmbientExternalModuleDeclaration();
return true;
}
else {
return this.tsParseDeclaration(value, /* next */ true);
}
}
break;
case 19 /* _namespace */:
if (isBeforeToken || tokenizer_1.match(2048 /* name */)) {
tokenizer_1.runInTypeContext(1, () => {
if (isBeforeToken)
tokenizer_1.next();
tsParseModuleOrNamespaceDeclaration();
});
return true;
}
default:
return false;
}
break;
case 28 /* _type */:
if (isBeforeToken || tokenizer_1.match(2048 /* name */)) {
tokenizer_1.runInTypeContext(1, () => {
if (isBeforeToken)
tokenizer_1.next();
tsParseTypeAliasDeclaration();
});
return true;
}
break;
default:
break;
}
// Note: this won't be called unless the keyword is allowed in `shouldParseExportDeclaration`.
// Returns true if it matched a declaration.
tsTryParseExportDeclaration() {
return this.tsParseDeclaration(this.state.value, /* next */ true);
}
// Returns true if it matched a statement.
tsParseExpressionStatement(name) {
switch (name) {
case "declare": {
const declareTokenIndex = this.state.tokens.length - 1;
const matched = this.tsTryParseDeclare();
if (matched) {
this.state.tokens[declareTokenIndex].type = types_1.types._declare;
return true;
}
break;
}
case "global":
// `global { }` (with no `declare`) may appear inside an ambient module declaration.
// Would like to use tsParseAmbientExternalModuleDeclaration here, but already ran past "global".
if (this.match(types_1.types.braceL)) {
this.tsParseModuleBlock();
return true;
}
break;
default:
return this.tsParseDeclaration(name, /* next */ false);
}
return false;
}
// Returns true if there was a generic async arrow function.
function tsTryParseGenericAsyncArrowFunction() {
const matched = tsTryParseAndCatch(() => {
tsParseTypeParameters();
statement_1.parseFunctionParams();
tsTryParseTypeOrTypePredicateAnnotation();
util_1.expect(10752 /* arrow */);
});
if (!matched) {
return false;
}
// Common to tsTryParseDeclare, tsTryParseExportDeclaration, and tsParseExpressionStatement.
// Returns true if it matched a declaration.
tsParseDeclaration(name, next) {
switch (name) {
case "abstract":
if (next || this.match(types_1.types._class)) {
if (next)
this.next();
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._abstract;
this.parseClass(/* isStatement */ true, /* optionalId */ false);
return true;
}
break;
case "enum":
if (next || this.match(types_1.types.name)) {
if (next)
this.next();
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._enum;
this.tsParseEnumDeclaration();
return true;
}
break;
case "interface":
if (next || this.match(types_1.types.name)) {
// `next` is true in "export" and "declare" contexts, so we want to remove that token
// as well.
this.runInTypeContext(1, () => {
if (next)
this.next();
this.tsParseInterfaceDeclaration();
});
return true;
}
break;
case "module":
if (next)
this.next();
if (this.match(types_1.types.string)) {
this.runInTypeContext(next ? 2 : 1, () => {
this.tsParseAmbientExternalModuleDeclaration();
});
return true;
}
else if (next || this.match(types_1.types.name)) {
this.runInTypeContext(next ? 2 : 1, () => {
this.tsParseModuleOrNamespaceDeclaration();
});
return true;
}
break;
case "namespace":
if (next || this.match(types_1.types.name)) {
this.runInTypeContext(1, () => {
if (next)
this.next();
this.tsParseModuleOrNamespaceDeclaration();
});
return true;
}
break;
case "type":
if (next || this.match(types_1.types.name)) {
this.runInTypeContext(1, () => {
if (next)
this.next();
this.tsParseTypeAliasDeclaration();
});
return true;
}
break;
// We don't need to be precise about the function start since it's only used if this is a
// bodiless function, which isn't valid here.
const functionStart = base_1.state.start;
expression_1.parseFunctionBody(functionStart, false /* isGenerator */, true);
return true;
}
function tsParseTypeArguments() {
tokenizer_1.runInTypeContext(0, () => {
util_1.expect(21000 /* lessThan */);
tsParseDelimitedList("TypeParametersOrArguments", tsParseType);
util_1.expect(21512 /* greaterThan */);
});
}
function tsIsDeclarationStart() {
if (tokenizer_1.match(2048 /* name */)) {
switch (base_1.state.contextualKeyword) {
case 1 /* _abstract */:
case 7 /* _declare */:
case 8 /* _enum */:
case 14 /* _interface */:
case 18 /* _module */:
case 19 /* _namespace */:
case 28 /* _type */:
return true;
default:
break;
}
return false;
}
// Returns true if there was a generic async arrow function.
tsTryParseGenericAsyncArrowFunction() {
const matched = this.tsTryParseAndCatch(() => {
this.tsParseTypeParameters();
// Don't use overloaded parseFunctionParams which would look for "<" again.
super.parseFunctionParams();
this.tsTryParseTypeOrTypePredicateAnnotation();
this.expect(types_1.types.arrow);
});
if (!matched) {
return false;
return false;
}
exports.tsIsDeclarationStart = tsIsDeclarationStart;
// ======================================================
// OVERRIDES
// ======================================================
function tsParseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody = null, funcContextId) {
// For arrow functions, `parseArrow` handles the return type itself.
if (!allowExpressionBody && tokenizer_1.match(8192 /* colon */)) {
tsParseTypeOrTypePredicateAnnotation(8192 /* colon */);
}
// The original code checked the node type to make sure this function type allows a missing
// body, but we skip that to avoid sending around the node type. We instead just use the
// allowExpressionBody boolean to make sure it's not an arrow function.
if (!allowExpressionBody && !tokenizer_1.match(4096 /* braceL */) && util_1.isLineTerminator()) {
// Retroactively mark the function declaration as a type.
let i = base_1.state.tokens.length - 1;
while (i >= 0 &&
(base_1.state.tokens[i].start >= functionStart ||
base_1.state.tokens[i].type === 31760 /* _default */ ||
base_1.state.tokens[i].type === 42512 /* _export */)) {
base_1.state.tokens[i].isType = true;
i--;
}
// We don't need to be precise about the function start since it's only used if this is a
// bodiless function, which isn't valid here.
const functionStart = this.state.start;
this.parseFunctionBody(functionStart, false /* isGenerator */, true);
return true;
return;
}
tsParseTypeArguments() {
this.runInTypeContext(0, () => {
this.expect(types_1.types.lessThan);
this.tsParseDelimitedList("TypeParametersOrArguments", this.tsParseType.bind(this));
this.expect(types_1.types.greaterThan);
});
expression_1.parseFunctionBody(functionStart, isGenerator, allowExpressionBody, funcContextId);
}
exports.tsParseFunctionBodyAndFinish = tsParseFunctionBodyAndFinish;
function tsParseSubscript(startPos, noCalls, stopState) {
if (!util_1.hasPrecedingLineBreak() && tokenizer_1.eat(16000 /* bang */)) {
base_1.state.tokens[base_1.state.tokens.length - 1].type = 28672 /* nonNullAssertion */;
return;
}
tsIsDeclarationStart() {
if (this.match(types_1.types.name)) {
switch (this.state.value) {
case "abstract":
case "declare":
case "enum":
case "interface":
case "module":
case "namespace":
case "type":
return true;
default:
break;
if (!noCalls && tokenizer_1.match(21000 /* lessThan */)) {
if (expression_1.atPossibleAsync()) {
// Almost certainly this is a generic async function `async <T>() => ...
// But it might be a call with a type argument `async<T>();`
const asyncArrowFn = tsTryParseGenericAsyncArrowFunction();
if (asyncArrowFn) {
return;
}
}
return false;
}
// ======================================================
// OVERRIDES
// ======================================================
isExportDefaultSpecifier() {
if (this.tsIsDeclarationStart())
return false;
return super.isExportDefaultSpecifier();
}
parseAssignableListItem(allowModifiers, isBlockScope) {
if (allowModifiers) {
this.parseAccessModifier();
this.tsParseModifier(["readonly"]);
// May be passing type arguments. But may just be the `<` operator.
const typeArguments = tsTryParseTypeArgumentsInExpression(); // Also eats the "("
if (typeArguments) {
// possibleAsync always false here, because we would have handled it above.
expression_1.parseCallExpressionArguments(6656 /* parenR */);
}
this.parseMaybeDefault(isBlockScope);
this.parseAssignableListItemTypes();
this.parseMaybeDefault(isBlockScope, true);
}
parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody, funcContextId) {
// For arrow functions, `parseArrow` handles the return type itself.
if (!allowExpressionBody && this.match(types_1.types.colon)) {
this.tsParseTypeOrTypePredicateAnnotation(types_1.types.colon);
}
// The original code checked the node type to make sure this function type allows a missing
// body, but we skip that to avoid sending around the node type. We instead just use the
// allowExpressionBody boolean to make sure it's not an arrow function.
if (!allowExpressionBody && !this.match(types_1.types.braceL) && this.isLineTerminator()) {
// Retroactively mark the function declaration as a type.
let i = this.state.tokens.length - 1;
while (i >= 0 &&
(this.state.tokens[i].start >= functionStart ||
this.state.tokens[i].type === types_1.types._default ||
this.state.tokens[i].type === types_1.types._export)) {
this.state.tokens[i].isType = true;
i--;
expression_1.baseParseSubscript(startPos, noCalls, stopState);
}
exports.tsParseSubscript = tsParseSubscript;
function tsStartParseNewArguments() {
if (tokenizer_1.match(21000 /* lessThan */)) {
// tsTryParseAndCatch is expensive, so avoid if not necessary.
// 99% certain this is `new C<T>();`. But may be `new C < T;`, which is also legal.
tsTryParseAndCatch(() => {
base_1.state.type = 28160 /* typeParameterStart */;
tsParseTypeArguments();
if (!tokenizer_1.match(6144 /* parenL */)) {
util_1.unexpected();
}
return;
}
super.parseFunctionBodyAndFinish(functionStart, isGenerator, allowExpressionBody, funcContextId);
});
}
parseSubscript(startPos, noCalls, state) {
if (!this.hasPrecedingLineBreak() && this.eat(types_1.types.bang)) {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types.nonNullAssertion;
return;
}
if (!noCalls && this.match(types_1.types.lessThan)) {
if (this.atPossibleAsync()) {
// Almost certainly this is a generic async function `async <T>() => ...
// But it might be a call with a type argument `async<T>();`
const asyncArrowFn = this.tsTryParseGenericAsyncArrowFunction();
if (asyncArrowFn) {
return;
}
}
// May be passing type arguments. But may just be the `<` operator.
const typeArguments = this.tsTryParseTypeArgumentsInExpression(); // Also eats the "("
if (typeArguments) {
// possibleAsync always false here, because we would have handled it above.
this.parseCallExpressionArguments(types_1.types.parenR);
}
}
super.parseSubscript(startPos, noCalls, state);
}
exports.tsStartParseNewArguments = tsStartParseNewArguments;
function tsTryParseExport() {
if (tokenizer_1.match(43024 /* _import */)) {
// `export import A = B;`
util_1.expect(43024 /* _import */);
tsParseImportEqualsDeclaration();
return true;
}
parseNewArguments() {
if (this.match(types_1.types.lessThan)) {
// tsTryParseAndCatch is expensive, so avoid if not necessary.
// 99% certain this is `new C<T>();`. But may be `new C < T;`, which is also legal.
this.tsTryParseAndCatch(() => {
this.state.type = types_1.types.typeParameterStart;
this.tsParseTypeArguments();
if (!this.match(types_1.types.parenL)) {
this.unexpected();
}
});
}
super.parseNewArguments();
else if (tokenizer_1.eat(14368 /* eq */)) {
// `export = x;`
expression_1.parseExpression();
util_1.semicolon();
return true;
}
parseExprOp(minPrec, noIn) {
if (nonNull(types_1.types._in.binop) > minPrec &&
!this.hasPrecedingLineBreak() &&
this.eatContextual("as")) {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._as;
this.runInTypeContext(1, () => {
this.tsParseType();
});
this.parseExprOp(minPrec, noIn);
return;
}
super.parseExprOp(minPrec, noIn);
else if (util_1.eatContextual(2 /* _as */)) {
// `export as namespace A;`
// See `parseNamespaceExportDeclaration` in TypeScript's own parser
util_1.expectContextual(19 /* _namespace */);
expression_1.parseIdentifier();
util_1.semicolon();
return true;
}
/*
Don't bother doing this check in TypeScript code because:
1. We may have a nested export statement with the same name:
export const x = 0;
export namespace N {
export const x = 1;
}
2. We have a type checker to warn us about this sort of thing.
*/
checkDuplicateExports() { }
parseImport() {
if (this.match(types_1.types.name) && this.lookaheadType() === types_1.types.eq) {
this.tsParseImportEqualsDeclaration();
return;
}
super.parseImport();
else {
return false;
}
parseExport() {
if (this.match(types_1.types._import)) {
// `export import A = B;`
this.expect(types_1.types._import);
this.tsParseImportEqualsDeclaration();
}
else if (this.eat(types_1.types.eq)) {
// `export = x;`
this.parseExpression();
this.semicolon();
}
else if (this.eatContextual("as")) {
// `export as namespace A;`
// See `parseNamespaceExportDeclaration` in TypeScript's own parser
this.expectContextual("namespace");
this.parseIdentifier();
this.semicolon();
}
else {
super.parseExport();
}
}
exports.tsTryParseExport = tsTryParseExport;
function tsTryParseExportDefaultExpression() {
if (util_1.isContextual(1 /* _abstract */) && tokenizer_1.lookaheadType() === 41488 /* _class */) {
base_1.state.type = 50704 /* _abstract */;
tokenizer_1.next(); // Skip "abstract"
statement_1.parseClass(true, true);
return true;
}
parseExportDefaultExpression() {
if (this.isContextual("abstract") && this.lookaheadType() === types_1.types._class) {
this.state.type = types_1.types._abstract;
this.next(); // Skip "abstract"
this.parseClass(true, true);
return;
return false;
}
exports.tsTryParseExportDefaultExpression = tsTryParseExportDefaultExpression;
function tsTryParseStatementContent() {
if (base_1.state.type === 38416 /* _const */) {
const ahead = tokenizer_1.lookaheadTypeAndKeyword();
if (ahead.type === 2048 /* name */ && ahead.contextualKeyword === 8 /* _enum */) {
util_1.expect(38416 /* _const */);
util_1.expectContextual(8 /* _enum */);
base_1.state.tokens[base_1.state.tokens.length - 1].type = 53776 /* _enum */;
tsParseEnumDeclaration();
return true;
}
super.parseExportDefaultExpression();
}
parseStatementContent(declaration, topLevel = false) {
if (this.state.type === types_1.types._const) {
const ahead = this.lookaheadTypeAndValue();
if (ahead.type === types_1.types.name && ahead.value === "enum") {
this.expect(types_1.types._const);
this.expectContextual("enum");
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._enum;
this.tsParseEnumDeclaration();
return;
}
}
super.parseStatementContent(declaration, topLevel);
return false;
}
exports.tsTryParseStatementContent = tsTryParseStatementContent;
function tsParseAccessModifier() {
tsParseModifier([
24 /* _public */,
23 /* _protected */,
22 /* _private */,
]);
}
exports.tsParseAccessModifier = tsParseAccessModifier;
function tsTryParseClassMemberWithIsStatic(isStatic, classContextId) {
let isAbstract = false;
let isReadonly = false;
const mod = tsParseModifier([1 /* _abstract */, 25 /* _readonly */]);
switch (mod) {
case 25 /* _readonly */:
isReadonly = true;
isAbstract = !!tsParseModifier([1 /* _abstract */]);
break;
case 1 /* _abstract */:
isAbstract = true;
isReadonly = !!tsParseModifier([25 /* _readonly */]);
break;
default:
break;
}
parseAccessModifier() {
this.tsParseModifier(["public", "protected", "private"]);
}
parseClassMember(memberStart, classContextId) {
this.parseAccessModifier();
super.parseClassMember(memberStart, classContextId);
}
parseClassMemberWithIsStatic(memberStart, isStatic, classContextId) {
let isAbstract = false;
let isReadonly = false;
const mod = this.tsParseModifier(["abstract", "readonly"]);
switch (mod) {
case "readonly":
isReadonly = true;
isAbstract = !!this.tsParseModifier(["abstract"]);
break;
case "abstract":
isAbstract = true;
isReadonly = !!this.tsParseModifier(["readonly"]);
break;
default:
break;
// We no longer check for public/private/etc, but tsTryParseIndexSignature should just return
// false in that case for valid code.
if (!isAbstract && !isStatic) {
const found = tsTryParseIndexSignature();
if (found) {
return true;
}
// We no longer check for public/private/etc, but tsTryParseIndexSignature should just return
// false in that case for valid code.
if (!isAbstract && !isStatic) {
const found = this.tsTryParseIndexSignature();
if (found) {
return;
}
}
if (isReadonly) {
// Must be a property (if not an index signature).
this.parseClassPropertyName(classContextId);
this.parsePostMemberNameModifiers();
this.parseClassProperty();
return;
}
super.parseClassMemberWithIsStatic(memberStart, isStatic, classContextId);
}
parsePostMemberNameModifiers() {
this.eat(types_1.types.question);
if (isReadonly) {
// Must be a property (if not an index signature).
statement_1.parseClassPropertyName(classContextId);
statement_1.parsePostMemberNameModifiers();
statement_1.parseClassProperty();
return true;
}
// Note: The reason we do this in `parseIdentifierStatement` and not `parseStatement`
// is that e.g. `type()` is valid JS, so we must try parsing that first.
// If it's really a type, we will parse `type` as the statement, and can correct it here
// by parsing the rest.
parseIdentifierStatement(name) {
const matched = this.tsParseExpressionStatement(name);
if (!matched) {
super.parseIdentifierStatement(name);
}
return false;
}
exports.tsTryParseClassMemberWithIsStatic = tsTryParseClassMemberWithIsStatic;
// Note: The reason we do this in `parseIdentifierStatement` and not `parseStatement`
// is that e.g. `type()` is valid JS, so we must try parsing that first.
// If it's really a type, we will parse `type` as the statement, and can correct it here
// by parsing the rest.
function tsParseIdentifierStatement(contextualKeyword) {
const matched = tsParseExpressionStatement(contextualKeyword);
if (!matched) {
util_1.semicolon();
}
// export type
// Should be true for anything parsed by `tsTryParseExportDeclaration`.
shouldParseExportDeclaration() {
if (this.tsIsDeclarationStart())
return true;
return super.shouldParseExportDeclaration();
}
exports.tsParseIdentifierStatement = tsParseIdentifierStatement;
function tsParseExportDeclaration() {
// "export declare" is equivalent to just "export".
const isDeclare = util_1.eatContextual(7 /* _declare */);
if (isDeclare) {
base_1.state.tokens[base_1.state.tokens.length - 1].type = 49680 /* _declare */;
}
parseExportDeclaration() {
// "export declare" is equivalent to just "export".
const isDeclare = this.eatContextual("declare");
let matchedDeclaration = false;
if (tokenizer_1.match(2048 /* name */)) {
if (isDeclare) {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._declare;
matchedDeclaration = tokenizer_1.runInTypeContext(2, () => tsTryParseExportDeclaration());
}
let matchedDeclaration = false;
if (this.match(types_1.types.name)) {
if (isDeclare) {
matchedDeclaration = this.runInTypeContext(2, () => this.tsTryParseExportDeclaration());
}
else {
matchedDeclaration = this.tsTryParseExportDeclaration();
}
else {
matchedDeclaration = tsTryParseExportDeclaration();
}
if (!matchedDeclaration) {
if (isDeclare) {
this.runInTypeContext(2, () => {
super.parseExportDeclaration();
});
}
else {
super.parseExportDeclaration();
}
}
}
parseClassId(isStatement, optionalId = false) {
if ((!isStatement || optionalId) && this.isContextual("implements")) {
return;
}
super.parseClassId(isStatement, optionalId);
this.tsTryParseTypeParameters();
}
parseClassProperty() {
this.tsTryParseTypeAnnotation();
super.parseClassProperty();
}
parseClassMethod(functionStart, isGenerator, isConstructor) {
this.tsTryParseTypeParameters();
super.parseClassMethod(functionStart, isGenerator, isConstructor);
}
parseClassSuper() {
const hasSuper = super.parseClassSuper();
if (hasSuper && this.match(types_1.types.lessThan)) {
this.tsParseTypeArguments();
}
if (this.eatContextual("implements")) {
this.state.tokens[this.state.tokens.length - 1].type = types_1.types._implements;
this.runInTypeContext(1, () => {
this.tsParseHeritageClause();
if (!matchedDeclaration) {
if (isDeclare) {
tokenizer_1.runInTypeContext(2, () => {
statement_1.parseStatement(true);
});
}
return hasSuper;
}
parseObjPropValue(isGenerator, isPattern, isBlockScope, objectContextId) {
if (this.match(types_1.types.lessThan)) {
throw new Error("TODO");
else {
statement_1.parseStatement(true);
}
super.parseObjPropValue(isGenerator, isPattern, isBlockScope, objectContextId);
}
parseFunctionParams(allowModifiers, contextId) {
this.tsTryParseTypeParameters();
super.parseFunctionParams(allowModifiers, contextId);
}
exports.tsParseExportDeclaration = tsParseExportDeclaration;
function tsAfterParseClassSuper(hasSuper) {
if (hasSuper && tokenizer_1.match(21000 /* lessThan */)) {
tsParseTypeArguments();
}
// `let x: number;`
parseVarHead(isBlockScope) {
super.parseVarHead(isBlockScope);
this.tsTryParseTypeAnnotation();
if (util_1.eatContextual(13 /* _implements */)) {
base_1.state.tokens[base_1.state.tokens.length - 1].type = 54800 /* _implements */;
tokenizer_1.runInTypeContext(1, () => {
tsParseHeritageClause();
});
}
// parse the return type of an async arrow function - let foo = (async (): number => {});
parseAsyncArrowFromCallExpression(functionStart, startTokenIndex) {
if (this.match(types_1.types.colon)) {
this.parseTypeAnnotation();
}
super.parseAsyncArrowFromCallExpression(functionStart, startTokenIndex);
}
exports.tsAfterParseClassSuper = tsAfterParseClassSuper;
function tsStartParseObjPropValue() {
if (tokenizer_1.match(21000 /* lessThan */)) {
throw new Error("TODO");
}
// Returns true if the expression was an arrow function.
parseMaybeAssign(noIn = null, afterLeftParse) {
// Note: When the JSX plugin is on, type assertions (`<T> x`) aren't valid syntax.
let jsxError = null;
if (this.match(types_1.types.lessThan) && this.hasPlugin("jsx")) {
// Prefer to parse JSX if possible. But may be an arrow fn.
const snapshot = this.state.snapshot();
try {
return super.parseMaybeAssign(noIn, afterLeftParse);
}
catch (err) {
if (!(err instanceof SyntaxError)) {
// istanbul ignore next: no such error is expected
throw err;
}
this.state.restoreFromSnapshot(snapshot);
this.state.type = types_1.types.typeParameterStart;
jsxError = err;
}
}
if (jsxError === null && !this.match(types_1.types.lessThan)) {
return super.parseMaybeAssign(noIn, afterLeftParse);
}
// Either way, we're looking at a '<': tt.typeParameterStart or relational.
let wasArrow = false;
const snapshot = this.state.snapshot();
}
exports.tsStartParseObjPropValue = tsStartParseObjPropValue;
function tsStartParseFunctionParams() {
tsTryParseTypeParameters();
}
exports.tsStartParseFunctionParams = tsStartParseFunctionParams;
// `let x: number;`
function tsAfterParseVarHead() {
tsTryParseTypeAnnotation();
}
exports.tsAfterParseVarHead = tsAfterParseVarHead;
// parse the return type of an async arrow function - let foo = (async (): number => {});
function tsStartParseAsyncArrowFromCallExpression() {
if (tokenizer_1.match(8192 /* colon */)) {
tsParseTypeAnnotation();
}
}
exports.tsStartParseAsyncArrowFromCallExpression = tsStartParseAsyncArrowFromCallExpression;
// Returns true if the expression was an arrow function.
function tsParseMaybeAssign(noIn = null, afterLeftParse) {
// Note: When the JSX plugin is on, type assertions (`<T> x`) aren't valid syntax.
let jsxError = null;
if (tokenizer_1.match(21000 /* lessThan */) && base_1.hasPlugin("jsx")) {
// Prefer to parse JSX if possible. But may be an arrow fn.
const snapshot = base_1.state.snapshot();
try {
// This is similar to TypeScript's `tryParseParenthesizedArrowFunctionExpression`.
this.runInTypeContext(0, () => {
this.tsParseTypeParameters();
});
wasArrow = super.parseMaybeAssign(noIn, afterLeftParse);
if (!wasArrow) {
this.unexpected(); // Go to the catch block (needs a SyntaxError).
}
return expression_1.baseParseMaybeAssign(noIn, afterLeftParse);
}

@@ -1195,71 +1083,76 @@ catch (err) {

}
if (jsxError) {
throw jsxError;
}
// Try parsing a type cast instead of an arrow function.
// This will never happen outside of JSX.
// (Because in JSX the '<' should be a jsxTagStart and not a relational.
assert(!this.hasPlugin("jsx"));
// Parsing an arrow function failed, so try a type cast.
this.state.restoreFromSnapshot(snapshot);
// This will start with a type assertion (via parseMaybeUnary).
// But don't directly call `this.tsParseTypeAssertion` because we want to handle any binary after it.
return super.parseMaybeAssign(noIn, afterLeftParse);
base_1.state.restoreFromSnapshot(snapshot);
base_1.state.type = 28160 /* typeParameterStart */;
jsxError = err;
}
return wasArrow;
}
// Handle type assertions
parseMaybeUnary() {
if (!this.hasPlugin("jsx") && this.eat(types_1.types.lessThan)) {
this.tsParseTypeAssertion();
return false;
if (jsxError === null && !tokenizer_1.match(21000 /* lessThan */)) {
return expression_1.baseParseMaybeAssign(noIn, afterLeftParse);
}
// Either way, we're looking at a '<': tt.typeParameterStart or relational.
let wasArrow = false;
const snapshot = base_1.state.snapshot();
try {
// This is similar to TypeScript's `tryParseParenthesizedArrowFunctionExpression`.
tokenizer_1.runInTypeContext(0, () => {
tsParseTypeParameters();
});
wasArrow = expression_1.baseParseMaybeAssign(noIn, afterLeftParse);
if (!wasArrow) {
util_1.unexpected(); // Go to the catch block (needs a SyntaxError).
}
else {
return super.parseMaybeUnary();
}
catch (err) {
if (!(err instanceof SyntaxError)) {
// istanbul ignore next: no such error is expected
throw err;
}
if (jsxError) {
throw jsxError;
}
// Try parsing a type cast instead of an arrow function.
// This will never happen outside of JSX.
// (Because in JSX the '<' should be a jsxTagStart and not a relational.
assert(!base_1.hasPlugin("jsx"));
// Parsing an arrow function failed, so try a type cast.
base_1.state.restoreFromSnapshot(snapshot);
// This will start with a type assertion (via parseMaybeUnary).
// But don't directly call `tsParseTypeAssertion` because we want to handle any binary after it.
return expression_1.baseParseMaybeAssign(noIn, afterLeftParse);
}
parseArrow() {
if (this.match(types_1.types.colon)) {
// This is different from how the TS parser does it.
// TS uses lookahead. Babylon parses it as a parenthesized expression and converts.
const snapshot = this.state.snapshot();
try {
this.tsParseTypeOrTypePredicateAnnotation(types_1.types.colon);
if (this.canInsertSemicolon())
this.unexpected();
if (!this.match(types_1.types.arrow))
this.unexpected();
return wasArrow;
}
exports.tsParseMaybeAssign = tsParseMaybeAssign;
function tsParseArrow() {
if (tokenizer_1.match(8192 /* colon */)) {
// This is different from how the TS parser does it.
// TS uses lookahead. Babylon parses it as a parenthesized expression and converts.
const snapshot = base_1.state.snapshot();
try {
tsParseTypeOrTypePredicateAnnotation(8192 /* colon */);
if (util_1.canInsertSemicolon())
util_1.unexpected();
if (!tokenizer_1.match(10752 /* arrow */))
util_1.unexpected();
}
catch (err) {
if (err instanceof SyntaxError) {
base_1.state.restoreFromSnapshot(snapshot);
}
catch (err) {
if (err instanceof SyntaxError) {
this.state.restoreFromSnapshot(snapshot);
}
else {
// istanbul ignore next: no such error is expected
throw err;
}
else {
// istanbul ignore next: no such error is expected
throw err;
}
}
return super.parseArrow();
}
// Allow type annotations inside of a parameter list.
parseAssignableListItemTypes() {
this.runInTypeContext(0, () => {
this.eat(types_1.types.question);
this.tsTryParseTypeAnnotation();
});
}
parseBindingAtom(isBlockScope) {
switch (this.state.type) {
case types_1.types._this:
// "this" may be the name of a parameter, so allow it.
this.runInTypeContext(0, () => {
this.parseIdentifier();
});
return;
default:
super.parseBindingAtom(isBlockScope);
}
}
return tokenizer_1.eat(10752 /* arrow */);
}
exports.default = TypeScriptParser;
exports.tsParseArrow = tsParseArrow;
// Allow type annotations inside of a parameter list.
function tsParseAssignableListItemTypes() {
tokenizer_1.runInTypeContext(0, () => {
tokenizer_1.eat(9728 /* question */);
tsTryParseTypeAnnotation();
});
}
exports.tsParseAssignableListItemTypes = tsParseAssignableListItemTypes;

@@ -1,3 +0,1 @@

import BaseParser from "../parser/base";
import State from "./state";
import { TokenType } from "./types";

@@ -12,6 +10,42 @@ export declare enum IdentifierRole {

}
export declare const enum ContextualKeyword {
NONE = 0,
_abstract = 1,
_as = 2,
_async = 3,
_await = 4,
_checks = 5,
_constructor = 6,
_declare = 7,
_enum = 8,
_exports = 9,
_from = 10,
_get = 11,
_global = 12,
_implements = 13,
_interface = 14,
_is = 15,
_keyof = 16,
_mixins = 17,
_module = 18,
_namespace = 19,
_of = 20,
_opaque = 21,
_private = 22,
_protected = 23,
_public = 24,
_readonly = 25,
_require = 26,
_static = 27,
_type = 28,
_set = 29,
_React = 30,
_createClass = 31,
_createReactClass = 32,
_displayName = 33,
}
export declare class Token {
constructor(state: State);
constructor();
type: TokenType;
value: any;
contextualKeyword: ContextualKeyword;
start: number;

@@ -26,49 +60,18 @@ end: number;

}
export default abstract class Tokenizer extends BaseParser {
abstract unexpected(pos?: number | null, messageOrType?: string | TokenType): never;
state: State;
input: string;
nextContextId: number;
constructor(input: string);
next(): void;
nextTemplateToken(): void;
retokenizeSlashAsRegex(): void;
runInTypeContext<T>(existingTokensInType: number, func: () => T): T;
eat(type: TokenType): boolean;
match(type: TokenType): boolean;
isKeyword(word: string): boolean;
lookaheadType(): TokenType;
lookaheadTypeAndValue(): {
type: TokenType;
value: any;
};
nextToken(): void;
readToken(code: number): void;
fullCharCodeAtPos(): number;
skipBlockComment(): void;
skipLineComment(startSkip: number): void;
skipSpace(): void;
finishToken(type: TokenType, val?: any): void;
readToken_dot(): void;
readToken_slash(): void;
readToken_mult_modulo(code: number): void;
readToken_pipe_amp(code: number): void;
readToken_caret(): void;
readToken_plus_min(code: number): void;
readToken_lt_gt(code: number): void;
readToken_eq_excl(code: number): void;
readToken_question(): void;
getTokenFromCode(code: number): void;
finishOp(type: TokenType, size: number): void;
readRegexp(): void;
readInt(radix: number, len?: number): number | null;
readRadixNumber(radix: number): void;
readNumber(startsWithDot: boolean): void;
readCodePoint(throwOnInvalid: boolean): number | null;
readString(quote: number): void;
readTmplToken(): void;
readEscapedChar(inTemplate: boolean): string | null;
readHexChar(len: number, throwOnInvalid: boolean): number | null;
readWord1(): string;
readWord(): void;
}
export declare function next(): void;
export declare function nextTemplateToken(): void;
export declare function retokenizeSlashAsRegex(): void;
export declare function runInTypeContext<T>(existingTokensInType: number, func: () => T): T;
export declare function eat(type: TokenType): boolean;
export declare function match(type: TokenType): boolean;
export declare function lookaheadType(): TokenType;
export declare function lookaheadTypeAndKeyword(): {
type: TokenType;
contextualKeyword: ContextualKeyword;
};
export declare function nextToken(): void;
export declare function skipLineComment(startSkip: number): void;
export declare function skipSpace(): void;
export declare function finishToken(type: TokenType, contextualKeyword?: ContextualKeyword): void;
export declare function getTokenFromCode(code: number): void;
export declare function skipWord(): void;

@@ -5,66 +5,6 @@ "use strict";

const base_1 = require("../parser/base");
const charCodes = require("../util/charcodes");
const util_1 = require("../parser/util");
const identifier_1 = require("../util/identifier");
const whitespace_1 = require("../util/whitespace");
const state_1 = require("./state");
const types_1 = require("./types");
// The following character codes are forbidden from being
// an immediate sibling of NumericLiteralSeparator _
const forbiddenNumericSeparatorSiblings = {
decBinOct: [
charCodes.dot,
charCodes.uppercaseB,
charCodes.uppercaseE,
charCodes.uppercaseO,
charCodes.underscore,
charCodes.lowercaseB,
charCodes.lowercaseE,
charCodes.lowercaseO,
],
hex: [
charCodes.dot,
charCodes.uppercaseX,
charCodes.underscore,
charCodes.lowercaseX,
],
};
// tslint:disable-next-line no-any
const allowedNumericSeparatorSiblings = {};
allowedNumericSeparatorSiblings.bin = [
// 0 - 1
charCodes.digit0,
charCodes.digit1,
];
allowedNumericSeparatorSiblings.oct = [
// 0 - 7
...allowedNumericSeparatorSiblings.bin,
charCodes.digit2,
charCodes.digit3,
charCodes.digit4,
charCodes.digit5,
charCodes.digit6,
charCodes.digit7,
];
allowedNumericSeparatorSiblings.dec = [
// 0 - 9
...allowedNumericSeparatorSiblings.oct,
charCodes.digit8,
charCodes.digit9,
];
allowedNumericSeparatorSiblings.hex = [
// 0 - 9, A - F, a - f,
...allowedNumericSeparatorSiblings.dec,
charCodes.uppercaseA,
charCodes.uppercaseB,
charCodes.uppercaseC,
charCodes.uppercaseD,
charCodes.uppercaseE,
charCodes.uppercaseF,
charCodes.lowercaseA,
charCodes.lowercaseB,
charCodes.lowercaseC,
charCodes.lowercaseD,
charCodes.lowercaseE,
charCodes.lowercaseF,
];
const readWord_1 = require("./readWord");
var IdentifierRole;

@@ -83,8 +23,8 @@ (function (IdentifierRole) {

class Token {
constructor(state) {
this.type = state.type;
this.value = state.value;
this.start = state.start;
this.end = state.end;
this.isType = state.isType;
constructor() {
this.type = base_1.state.type;
this.contextualKeyword = base_1.state.contextualKeyword;
this.start = base_1.state.start;
this.end = base_1.state.end;
this.isType = base_1.state.isType;
this.identifierRole = null;

@@ -99,911 +39,640 @@ this.shadowsGlobal = null;

// ## Tokenizer
function codePointToString(code) {
// UTF-16 Decoding
if (code <= 0xffff) {
return String.fromCharCode(code);
// Move to the next token
function next() {
base_1.state.tokens.push(new Token());
nextToken();
}
exports.next = next;
// Call instead of next when inside a template, since that needs to be handled differently.
function nextTemplateToken() {
base_1.state.tokens.push(new Token());
base_1.state.start = base_1.state.pos;
readTmplToken();
}
exports.nextTemplateToken = nextTemplateToken;
// The tokenizer never parses regexes by default. Instead, the parser is responsible for
// instructing it to parse a regex when we see a slash at the start of an expression.
function retokenizeSlashAsRegex() {
if (base_1.state.type === 14880 /* assign */) {
--base_1.state.pos;
}
readRegexp();
}
exports.retokenizeSlashAsRegex = retokenizeSlashAsRegex;
function runInTypeContext(existingTokensInType, func) {
for (let i = base_1.state.tokens.length - existingTokensInType; i < base_1.state.tokens.length; i++) {
base_1.state.tokens[i].isType = true;
}
const oldIsType = base_1.state.isType;
base_1.state.isType = true;
const result = func();
base_1.state.isType = oldIsType;
return result;
}
exports.runInTypeContext = runInTypeContext;
function eat(type) {
if (match(type)) {
next();
return true;
}
else {
return String.fromCharCode(((code - 0x10000) >> 10) + 0xd800, ((code - 0x10000) & 1023) + 0xdc00);
return false;
}
}
class Tokenizer extends base_1.default {
constructor(input) {
super();
this.state = new state_1.default();
this.state.init(input);
this.nextContextId = 1;
exports.eat = eat;
function match(type) {
return base_1.state.type === type;
}
exports.match = match;
function lookaheadType() {
const snapshot = base_1.state.snapshot();
next();
const type = base_1.state.type;
base_1.state.restoreFromSnapshot(snapshot);
return type;
}
exports.lookaheadType = lookaheadType;
function lookaheadTypeAndKeyword() {
const snapshot = base_1.state.snapshot();
next();
const type = base_1.state.type;
const contextualKeyword = base_1.state.contextualKeyword;
base_1.state.restoreFromSnapshot(snapshot);
return { type, contextualKeyword };
}
exports.lookaheadTypeAndKeyword = lookaheadTypeAndKeyword;
// Read a single token, updating the parser object's token-related
// properties.
function nextToken() {
skipSpace();
base_1.state.start = base_1.state.pos;
if (base_1.state.pos >= base_1.input.length) {
const tokens = base_1.state.tokens;
// We normally run past the end a bit, but if we're way past the end, avoid an infinite loop.
// Also check the token positions rather than the types since sometimes we rewrite the token
// type to something else.
if (tokens.length >= 2 &&
tokens[tokens.length - 1].start >= base_1.input.length &&
tokens[tokens.length - 2].start >= base_1.input.length) {
util_1.unexpected(null, "Unexpectedly reached the end of input.");
}
finishToken(2560 /* eof */);
return;
}
// Move to the next token
next() {
this.state.tokens.push(new Token(this.state));
this.nextToken();
readToken(base_1.input.charCodeAt(base_1.state.pos));
}
exports.nextToken = nextToken;
function readToken(code) {
// Identifier or keyword. '\uXXXX' sequences are allowed in
// identifiers, so '\' also dispatches to that.
if (identifier_1.isIdentifierStart(code) || code === 92 /* backslash */) {
readWord_1.default();
}
// Call instead of next when inside a template, since that needs to be handled differently.
nextTemplateToken() {
this.state.tokens.push(new Token(this.state));
this.state.start = this.state.pos;
this.readTmplToken();
else {
getTokenFromCode(code);
}
// The tokenizer never parses regexes by default. Instead, the parser is responsible for
// instructing it to parse a regex when we see a slash at the start of an expression.
retokenizeSlashAsRegex() {
if (this.state.type === types_1.types.assign) {
--this.state.pos;
}
function skipBlockComment() {
const end = base_1.input.indexOf("*/", (base_1.state.pos += 2));
if (end === -1)
base_1.raise(base_1.state.pos - 2, "Unterminated comment");
base_1.state.pos = end + 2;
}
function skipLineComment(startSkip) {
let ch = base_1.input.charCodeAt((base_1.state.pos += startSkip));
if (base_1.state.pos < base_1.input.length) {
while (ch !== 10 /* lineFeed */ &&
ch !== 13 /* carriageReturn */ &&
ch !== 8232 /* lineSeparator */ &&
ch !== 8233 /* paragraphSeparator */ &&
++base_1.state.pos < base_1.input.length) {
ch = base_1.input.charCodeAt(base_1.state.pos);
}
this.readRegexp();
}
runInTypeContext(existingTokensInType, func) {
for (let i = this.state.tokens.length - existingTokensInType; i < this.state.tokens.length; i++) {
this.state.tokens[i].isType = true;
}
exports.skipLineComment = skipLineComment;
// Called at the start of the parse and after every token. Skips
// whitespace and comments.
function skipSpace() {
loop: while (base_1.state.pos < base_1.input.length) {
const ch = base_1.input.charCodeAt(base_1.state.pos);
switch (ch) {
case 32 /* space */:
case 160 /* nonBreakingSpace */:
++base_1.state.pos;
break;
case 13 /* carriageReturn */:
if (base_1.input.charCodeAt(base_1.state.pos + 1) === 10 /* lineFeed */) {
++base_1.state.pos;
}
case 10 /* lineFeed */:
case 8232 /* lineSeparator */:
case 8233 /* paragraphSeparator */:
++base_1.state.pos;
break;
case 47 /* slash */:
switch (base_1.input.charCodeAt(base_1.state.pos + 1)) {
case 42 /* asterisk */:
skipBlockComment();
break;
case 47 /* slash */:
skipLineComment(2);
break;
default:
break loop;
}
break;
default:
if ((ch > 8 /* backSpace */ && ch < 14 /* shiftOut */) ||
(ch >= 5760 /* oghamSpaceMark */ && whitespace_1.nonASCIIwhitespace.test(String.fromCharCode(ch)))) {
++base_1.state.pos;
}
else {
break loop;
}
}
const oldIsType = this.state.isType;
this.state.isType = true;
const result = func();
this.state.isType = oldIsType;
return result;
}
eat(type) {
if (this.match(type)) {
this.next();
return true;
}
else {
return false;
}
}
exports.skipSpace = skipSpace;
// Called at the end of every token. Sets various fields, and skips the space after the token, so
// that the next one's `start` will point at the right position.
function finishToken(type, contextualKeyword = 0 /* NONE */) {
base_1.state.end = base_1.state.pos;
base_1.state.type = type;
base_1.state.contextualKeyword = contextualKeyword;
}
exports.finishToken = finishToken;
// ### Token reading
// This is the function that is called to fetch the next token. It
// is somewhat obscure, because it works in character codes rather
// than characters, and because operator parsing has been inlined
// into it.
//
// All in the name of speed.
function readToken_dot() {
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
if (nextChar >= 48 /* digit0 */ && nextChar <= 57 /* digit9 */) {
readNumber(true);
return;
}
match(type) {
return this.state.type === type;
const next2 = base_1.input.charCodeAt(base_1.state.pos + 2);
if (nextChar === 46 /* dot */ && next2 === 46 /* dot */) {
base_1.state.pos += 3;
finishToken(11776 /* ellipsis */);
}
isKeyword(word) {
return identifier_1.isKeyword(word);
else {
++base_1.state.pos;
finishToken(9216 /* dot */);
}
lookaheadType() {
const snapshot = this.state.snapshot();
this.next();
const type = this.state.type;
this.state.restoreFromSnapshot(snapshot);
return type;
}
function readToken_slash() {
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
if (nextChar === 61 /* equalsTo */) {
finishOp(14880 /* assign */, 2);
}
// tslint:disable-next-line no-any
lookaheadTypeAndValue() {
const snapshot = this.state.snapshot();
this.next();
const type = this.state.type;
const value = this.state.value;
this.state.restoreFromSnapshot(snapshot);
return { type, value };
else {
finishOp(25099 /* slash */, 1);
}
// Read a single token, updating the parser object's token-related
// properties.
nextToken() {
this.skipSpace();
this.state.start = this.state.pos;
if (this.state.pos >= this.input.length) {
const tokens = this.state.tokens;
// We normally run past the end a bit, but if we're way past the end, avoid an infinite loop.
// Also check the token positions rather than the types since sometimes we rewrite the token
// type to something else.
if (tokens.length >= 2 &&
tokens[tokens.length - 1].start >= this.input.length &&
tokens[tokens.length - 2].start >= this.input.length) {
this.unexpected(null, "Unexpectedly reached the end of input.");
}
this.finishToken(types_1.types.eof);
}
function readToken_mult_modulo(code) {
// '%*'
let type = code === 42 /* asterisk */ ? 24587 /* star */ : 24075 /* modulo */;
let width = 1;
let nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
// Exponentiation operator **
if (code === 42 /* asterisk */ && nextChar === 42 /* asterisk */) {
width++;
nextChar = base_1.input.charCodeAt(base_1.state.pos + 2);
type = 25676 /* exponent */;
}
// Match *= or %=, disallowing *=> which can be valid in flow.
if (nextChar === 61 /* equalsTo */ &&
base_1.input.charCodeAt(base_1.state.pos + 2) !== 62 /* greaterThan */) {
width++;
type = 14880 /* assign */;
}
finishOp(type, width);
}
function readToken_pipe_amp(code) {
// '|&'
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
if (nextChar === code) {
finishOp(code === 124 /* verticalBar */ ? 17922 /* logicalOR */ : 18435 /* logicalAND */, 2);
return;
}
if (code === 124 /* verticalBar */) {
// '|>'
if (nextChar === 62 /* greaterThan */) {
finishOp(16897 /* pipeline */, 2);
return;
}
this.readToken(this.fullCharCodeAtPos());
}
readToken(code) {
// Identifier or keyword. '\uXXXX' sequences are allowed in
// identifiers, so '\' also dispatches to that.
if (identifier_1.isIdentifierStart(code) || code === charCodes.backslash) {
this.readWord();
else if (nextChar === 125 /* rightCurlyBrace */ && base_1.hasPlugin("flow")) {
// '|}'
finishOp(5632 /* braceBarR */, 2);
return;
}
else {
this.getTokenFromCode(code);
}
}
fullCharCodeAtPos() {
const code = this.input.charCodeAt(this.state.pos);
if (code <= 0xd7ff || code >= 0xe000)
return code;
const next = this.input.charCodeAt(this.state.pos + 1);
return (code << 10) + next - 0x35fdc00;
if (nextChar === 61 /* equalsTo */) {
finishOp(14880 /* assign */, 2);
return;
}
skipBlockComment() {
const end = this.input.indexOf("*/", (this.state.pos += 2));
if (end === -1)
this.raise(this.state.pos - 2, "Unterminated comment");
this.state.pos = end + 2;
finishOp(code === 124 /* verticalBar */ ? 18948 /* bitwiseOR */ : 19974 /* bitwiseAND */, 1);
}
function readToken_caret() {
// '^'
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
if (nextChar === 61 /* equalsTo */) {
finishOp(14880 /* assign */, 2);
}
skipLineComment(startSkip) {
let ch = this.input.charCodeAt((this.state.pos += startSkip));
if (this.state.pos < this.input.length) {
while (ch !== charCodes.lineFeed &&
ch !== charCodes.carriageReturn &&
ch !== charCodes.lineSeparator &&
ch !== charCodes.paragraphSeparator &&
++this.state.pos < this.input.length) {
ch = this.input.charCodeAt(this.state.pos);
}
}
else {
finishOp(19461 /* bitwiseXOR */, 1);
}
// Called at the start of the parse and after every token. Skips
// whitespace and comments.
skipSpace() {
loop: while (this.state.pos < this.input.length) {
const ch = this.input.charCodeAt(this.state.pos);
switch (ch) {
case charCodes.space:
case charCodes.nonBreakingSpace:
++this.state.pos;
break;
case charCodes.carriageReturn:
if (this.input.charCodeAt(this.state.pos + 1) === charCodes.lineFeed) {
++this.state.pos;
}
case charCodes.lineFeed:
case charCodes.lineSeparator:
case charCodes.paragraphSeparator:
++this.state.pos;
break;
case charCodes.slash:
switch (this.input.charCodeAt(this.state.pos + 1)) {
case charCodes.asterisk:
this.skipBlockComment();
break;
case charCodes.slash:
this.skipLineComment(2);
break;
default:
break loop;
}
break;
default:
if ((ch > charCodes.backSpace && ch < charCodes.shiftOut) ||
(ch >= charCodes.oghamSpaceMark && whitespace_1.nonASCIIwhitespace.test(String.fromCharCode(ch)))) {
++this.state.pos;
}
else {
break loop;
}
}
}
}
function readToken_plus_min(code) {
// '+-'
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
if (nextChar === code) {
finishOp(15744 /* incDec */, 2);
return;
}
// Called at the end of every token. Sets `end`, `val`, and
// maintains `context` and `exprAllowed`, and skips the space after
// the token, so that the next one's `start` will point at the
// right position.
// tslint:disable-next-line no-any
finishToken(type, val) {
this.state.end = this.state.pos;
const prevType = this.state.type;
this.state.type = type;
this.state.value = val;
if (nextChar === 61 /* equalsTo */) {
finishOp(14880 /* assign */, 2);
}
// ### Token reading
// This is the function that is called to fetch the next token. It
// is somewhat obscure, because it works in character codes rather
// than characters, and because operator parsing has been inlined
// into it.
//
// All in the name of speed.
//
readToken_dot() {
const next = this.input.charCodeAt(this.state.pos + 1);
if (next >= charCodes.digit0 && next <= charCodes.digit9) {
this.readNumber(true);
else if (code === 43 /* plusSign */) {
finishOp(23178 /* plus */, 1);
}
else {
finishOp(23690 /* minus */, 1);
}
}
// '<>'
function readToken_lt_gt(code) {
// Avoid right-shift for things like Array<Array<string>>.
if (code === 62 /* greaterThan */ && base_1.state.isType) {
finishOp(21512 /* greaterThan */, 1);
return;
}
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
if (nextChar === code) {
const size = code === 62 /* greaterThan */ && base_1.input.charCodeAt(base_1.state.pos + 2) === 62 /* greaterThan */
? 3
: 2;
if (base_1.input.charCodeAt(base_1.state.pos + size) === 61 /* equalsTo */) {
finishOp(14880 /* assign */, size + 1);
return;
}
const next2 = this.input.charCodeAt(this.state.pos + 2);
if (next === charCodes.dot && next2 === charCodes.dot) {
this.state.pos += 3;
this.finishToken(types_1.types.ellipsis);
}
else {
++this.state.pos;
this.finishToken(types_1.types.dot);
}
finishOp(22537 /* bitShift */, size);
return;
}
readToken_slash() {
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(types_1.types.assign, 2);
}
else {
this.finishOp(types_1.types.slash, 1);
}
if (nextChar === 61 /* equalsTo */) {
// <= | >=
finishOp(22024 /* relationalOrEqual */, 2);
}
readToken_mult_modulo(code) {
// '%*'
let type = code === charCodes.asterisk ? types_1.types.star : types_1.types.modulo;
let width = 1;
let next = this.input.charCodeAt(this.state.pos + 1);
// Exponentiation operator **
if (code === charCodes.asterisk && next === charCodes.asterisk) {
width++;
next = this.input.charCodeAt(this.state.pos + 2);
type = types_1.types.exponent;
}
// Match *= or %=, disallowing *=> which can be valid in flow.
if (next === charCodes.equalsTo &&
this.input.charCodeAt(this.state.pos + 2) !== charCodes.greaterThan) {
width++;
type = types_1.types.assign;
}
this.finishOp(type, width);
else if (code === 60 /* lessThan */) {
finishOp(21000 /* lessThan */, 1);
}
readToken_pipe_amp(code) {
// '|&'
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === code) {
this.finishOp(code === charCodes.verticalBar ? types_1.types.logicalOR : types_1.types.logicalAND, 2);
else {
finishOp(21512 /* greaterThan */, 1);
}
}
function readToken_eq_excl(code) {
// '=!'
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
if (nextChar === 61 /* equalsTo */) {
finishOp(20487 /* equality */, base_1.input.charCodeAt(base_1.state.pos + 2) === 61 /* equalsTo */ ? 3 : 2);
return;
}
if (code === 61 /* equalsTo */ && nextChar === 62 /* greaterThan */) {
// '=>'
base_1.state.pos += 2;
finishToken(10752 /* arrow */);
return;
}
finishOp(code === 61 /* equalsTo */ ? 14368 /* eq */ : 16000 /* bang */, 1);
}
function readToken_question() {
// '?'
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
const nextChar2 = base_1.input.charCodeAt(base_1.state.pos + 2);
if (nextChar === 63 /* questionMark */) {
// '??'
finishOp(17410 /* nullishCoalescing */, 2);
}
else if (nextChar === 46 /* dot */ &&
!(nextChar2 >= 48 /* digit0 */ && nextChar2 <= 57 /* digit9 */)) {
// '.' not followed by a number
base_1.state.pos += 2;
finishToken(10240 /* questionDot */);
}
else {
++base_1.state.pos;
finishToken(9728 /* question */);
}
}
function getTokenFromCode(code) {
switch (code) {
case 35 /* numberSign */:
++base_1.state.pos;
finishToken(13824 /* hash */);
return;
}
if (code === charCodes.verticalBar) {
// '|>'
if (next === charCodes.greaterThan) {
this.finishOp(types_1.types.pipeline, 2);
return;
// The interpretation of a dot depends on whether it is followed
// by a digit or another two dots.
case 46 /* dot */:
readToken_dot();
return;
// Punctuation tokens.
case 40 /* leftParenthesis */:
++base_1.state.pos;
finishToken(6144 /* parenL */);
return;
case 41 /* rightParenthesis */:
++base_1.state.pos;
finishToken(6656 /* parenR */);
return;
case 59 /* semicolon */:
++base_1.state.pos;
finishToken(7680 /* semi */);
return;
case 44 /* comma */:
++base_1.state.pos;
finishToken(7168 /* comma */);
return;
case 91 /* leftSquareBracket */:
++base_1.state.pos;
finishToken(3072 /* bracketL */);
return;
case 93 /* rightSquareBracket */:
++base_1.state.pos;
finishToken(3584 /* bracketR */);
return;
case 123 /* leftCurlyBrace */:
if (base_1.hasPlugin("flow") && base_1.input.charCodeAt(base_1.state.pos + 1) === 124 /* verticalBar */) {
finishOp(4608 /* braceBarL */, 2);
}
else if (next === charCodes.rightCurlyBrace && this.hasPlugin("flow")) {
// '|}'
this.finishOp(types_1.types.braceBarR, 2);
return;
else {
++base_1.state.pos;
finishToken(4096 /* braceL */);
}
}
if (next === charCodes.equalsTo) {
this.finishOp(types_1.types.assign, 2);
return;
}
this.finishOp(code === charCodes.verticalBar ? types_1.types.bitwiseOR : types_1.types.bitwiseAND, 1);
}
readToken_caret() {
// '^'
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(types_1.types.assign, 2);
}
else {
this.finishOp(types_1.types.bitwiseXOR, 1);
}
}
readToken_plus_min(code) {
// '+-'
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === code) {
this.finishOp(types_1.types.incDec, 2);
case 125 /* rightCurlyBrace */:
++base_1.state.pos;
finishToken(5120 /* braceR */);
return;
}
if (next === charCodes.equalsTo) {
this.finishOp(types_1.types.assign, 2);
}
else {
this.finishOp(types_1.types.plusMin, 1);
}
}
// '<>'
readToken_lt_gt(code) {
// Avoid right-shift for things like Array<Array<string>>.
if (code === charCodes.greaterThan && this.state.isType) {
this.finishOp(types_1.types.greaterThan, 1);
case 58 /* colon */:
if (base_1.input.charCodeAt(base_1.state.pos + 1) === 58 /* colon */) {
finishOp(8704 /* doubleColon */, 2);
}
else {
++base_1.state.pos;
finishToken(8192 /* colon */);
}
return;
}
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === code) {
const size = code === charCodes.greaterThan &&
this.input.charCodeAt(this.state.pos + 2) === charCodes.greaterThan
? 3
: 2;
if (this.input.charCodeAt(this.state.pos + size) === charCodes.equalsTo) {
this.finishOp(types_1.types.assign, size + 1);
case 63 /* questionMark */:
readToken_question();
return;
case 64 /* atSign */:
++base_1.state.pos;
finishToken(13312 /* at */);
return;
case 96 /* graveAccent */:
++base_1.state.pos;
finishToken(12288 /* backQuote */);
return;
case 48 /* digit0 */: {
const nextChar = base_1.input.charCodeAt(base_1.state.pos + 1);
// '0x', '0X', '0o', '0O', '0b', '0B'
if (nextChar === 120 /* lowercaseX */ ||
nextChar === 88 /* uppercaseX */ ||
nextChar === 111 /* lowercaseO */ ||
nextChar === 79 /* uppercaseO */ ||
nextChar === 98 /* lowercaseB */ ||
nextChar === 66 /* uppercaseB */) {
readRadixNumber();
return;
}
this.finishOp(types_1.types.bitShift, size);
return;
}
if (next === charCodes.equalsTo) {
// <= | >=
this.finishOp(types_1.types.relationalOrEqual, 2);
}
else if (code === charCodes.lessThan) {
this.finishOp(types_1.types.lessThan, 1);
}
else {
this.finishOp(types_1.types.greaterThan, 1);
}
}
readToken_eq_excl(code) {
// '=!'
const next = this.input.charCodeAt(this.state.pos + 1);
if (next === charCodes.equalsTo) {
this.finishOp(types_1.types.equality, this.input.charCodeAt(this.state.pos + 2) === charCodes.equalsTo ? 3 : 2);
// Anything else beginning with a digit is an integer, octal
// number, or float.
case 49 /* digit1 */:
case 50 /* digit2 */:
case 51 /* digit3 */:
case 52 /* digit4 */:
case 53 /* digit5 */:
case 54 /* digit6 */:
case 55 /* digit7 */:
case 56 /* digit8 */:
case 57 /* digit9 */:
readNumber(false);
return;
}
if (code === charCodes.equalsTo && next === charCodes.greaterThan) {
// '=>'
this.state.pos += 2;
this.finishToken(types_1.types.arrow);
// Quotes produce strings.
case 34 /* quotationMark */:
case 39 /* apostrophe */:
readString(code);
return;
}
this.finishOp(code === charCodes.equalsTo ? types_1.types.eq : types_1.types.bang, 1);
// Operators are parsed inline in tiny state machines. '=' (charCodes.equalsTo) is
// often referred to. `finishOp` simply skips the amount of
// characters it is given as second argument, and returns a token
// of the type given by its first argument.
case 47 /* slash */:
readToken_slash();
return;
case 37 /* percentSign */:
case 42 /* asterisk */:
readToken_mult_modulo(code);
return;
case 124 /* verticalBar */:
case 38 /* ampersand */:
readToken_pipe_amp(code);
return;
case 94 /* caret */:
readToken_caret();
return;
case 43 /* plusSign */:
case 45 /* dash */:
readToken_plus_min(code);
return;
case 60 /* lessThan */:
case 62 /* greaterThan */:
readToken_lt_gt(code);
return;
case 61 /* equalsTo */:
case 33 /* exclamationMark */:
readToken_eq_excl(code);
return;
case 126 /* tilde */:
finishOp(16512 /* tilde */, 1);
return;
default:
break;
}
readToken_question() {
// '?'
const next = this.input.charCodeAt(this.state.pos + 1);
const next2 = this.input.charCodeAt(this.state.pos + 2);
if (next === charCodes.questionMark) {
// '??'
this.finishOp(types_1.types.nullishCoalescing, 2);
base_1.raise(base_1.state.pos, `Unexpected character '${String.fromCharCode(code)}'`);
}
exports.getTokenFromCode = getTokenFromCode;
function finishOp(type, size) {
base_1.state.pos += size;
finishToken(type);
}
function readRegexp() {
const start = base_1.state.pos;
let escaped;
let inClass;
for (;;) {
if (base_1.state.pos >= base_1.input.length) {
base_1.raise(start, "Unterminated regular expression");
}
else if (next === charCodes.dot &&
!(next2 >= charCodes.digit0 && next2 <= charCodes.digit9)) {
// '.' not followed by a number
this.state.pos += 2;
this.finishToken(types_1.types.questionDot);
const ch = base_1.input.charAt(base_1.state.pos);
if (escaped) {
escaped = false;
}
else {
++this.state.pos;
this.finishToken(types_1.types.question);
}
}
getTokenFromCode(code) {
switch (code) {
case charCodes.numberSign:
++this.state.pos;
this.finishToken(types_1.types.hash);
return;
// The interpretation of a dot depends on whether it is followed
// by a digit or another two dots.
case charCodes.dot:
this.readToken_dot();
return;
// Punctuation tokens.
case charCodes.leftParenthesis:
++this.state.pos;
this.finishToken(types_1.types.parenL);
return;
case charCodes.rightParenthesis:
++this.state.pos;
this.finishToken(types_1.types.parenR);
return;
case charCodes.semicolon:
++this.state.pos;
this.finishToken(types_1.types.semi);
return;
case charCodes.comma:
++this.state.pos;
this.finishToken(types_1.types.comma);
return;
case charCodes.leftSquareBracket:
++this.state.pos;
this.finishToken(types_1.types.bracketL);
return;
case charCodes.rightSquareBracket:
++this.state.pos;
this.finishToken(types_1.types.bracketR);
return;
case charCodes.leftCurlyBrace:
if (this.hasPlugin("flow") &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.verticalBar) {
this.finishOp(types_1.types.braceBarL, 2);
}
else {
++this.state.pos;
this.finishToken(types_1.types.braceL);
}
return;
case charCodes.rightCurlyBrace:
++this.state.pos;
this.finishToken(types_1.types.braceR);
return;
case charCodes.colon:
if (this.input.charCodeAt(this.state.pos + 1) === charCodes.colon) {
this.finishOp(types_1.types.doubleColon, 2);
}
else {
++this.state.pos;
this.finishToken(types_1.types.colon);
}
return;
case charCodes.questionMark:
this.readToken_question();
return;
case charCodes.atSign:
++this.state.pos;
this.finishToken(types_1.types.at);
return;
case charCodes.graveAccent:
++this.state.pos;
this.finishToken(types_1.types.backQuote);
return;
case charCodes.digit0: {
const next = this.input.charCodeAt(this.state.pos + 1);
// '0x', '0X' - hex number
if (next === charCodes.lowercaseX || next === charCodes.uppercaseX) {
this.readRadixNumber(16);
return;
}
// '0o', '0O' - octal number
if (next === charCodes.lowercaseO || next === charCodes.uppercaseO) {
this.readRadixNumber(8);
return;
}
// '0b', '0B' - binary number
if (next === charCodes.lowercaseB || next === charCodes.uppercaseB) {
this.readRadixNumber(2);
return;
}
if (ch === "[") {
inClass = true;
}
// Anything else beginning with a digit is an integer, octal
// number, or float.
case charCodes.digit1:
case charCodes.digit2:
case charCodes.digit3:
case charCodes.digit4:
case charCodes.digit5:
case charCodes.digit6:
case charCodes.digit7:
case charCodes.digit8:
case charCodes.digit9:
this.readNumber(false);
return;
// Quotes produce strings.
case charCodes.quotationMark:
case charCodes.apostrophe:
this.readString(code);
return;
// Operators are parsed inline in tiny state machines. '=' (charCodes.equalsTo) is
// often referred to. `finishOp` simply skips the amount of
// characters it is given as second argument, and returns a token
// of the type given by its first argument.
case charCodes.slash:
this.readToken_slash();
return;
case charCodes.percentSign:
case charCodes.asterisk:
this.readToken_mult_modulo(code);
return;
case charCodes.verticalBar:
case charCodes.ampersand:
this.readToken_pipe_amp(code);
return;
case charCodes.caret:
this.readToken_caret();
return;
case charCodes.plusSign:
case charCodes.dash:
this.readToken_plus_min(code);
return;
case charCodes.lessThan:
case charCodes.greaterThan:
this.readToken_lt_gt(code);
return;
case charCodes.equalsTo:
case charCodes.exclamationMark:
this.readToken_eq_excl(code);
return;
case charCodes.tilde:
this.finishOp(types_1.types.tilde, 1);
return;
default:
else if (ch === "]" && inClass) {
inClass = false;
}
else if (ch === "/" && !inClass) {
break;
}
this.raise(this.state.pos, `Unexpected character '${codePointToString(code)}'`);
}
finishOp(type, size) {
const str = this.input.slice(this.state.pos, this.state.pos + size);
this.state.pos += size;
this.finishToken(type, str);
}
readRegexp() {
const start = this.state.pos;
let escaped;
let inClass;
for (;;) {
if (this.state.pos >= this.input.length) {
this.raise(start, "Unterminated regular expression");
}
const ch = this.input.charAt(this.state.pos);
if (whitespace_1.lineBreak.test(ch)) {
this.raise(start, "Unterminated regular expression");
}
if (escaped) {
escaped = false;
}
else {
if (ch === "[") {
inClass = true;
}
else if (ch === "]" && inClass) {
inClass = false;
}
else if (ch === "/" && !inClass) {
break;
}
escaped = ch === "\\";
}
++this.state.pos;
escaped = ch === "\\";
}
const content = this.input.slice(start, this.state.pos);
++this.state.pos;
// Need to use `readWord1` because '\uXXXX' sequences are allowed
// here (don't ask).
const mods = this.readWord1();
if (mods) {
const validFlags = /^[gmsiyu]*$/;
if (!validFlags.test(mods)) {
this.raise(start, "Invalid regular expression flag");
}
}
this.finishToken(types_1.types.regexp, {
pattern: content,
flags: mods,
});
++base_1.state.pos;
}
// Read an integer in the given radix. Return null if zero digits
// were read, the integer value otherwise. When `len` is given, this
// will return `null` unless the integer has exactly `len` digits.
readInt(radix, len) {
const start = this.state.pos;
const forbiddenSiblings = radix === 16
? forbiddenNumericSeparatorSiblings.hex
: forbiddenNumericSeparatorSiblings.decBinOct;
/* eslint-disable no-nested-ternary */
const allowedSiblings = radix === 16
? allowedNumericSeparatorSiblings.hex
: radix === 10
? allowedNumericSeparatorSiblings.dec
: radix === 8 ? allowedNumericSeparatorSiblings.oct : allowedNumericSeparatorSiblings.bin;
/* eslint-enable no-nested-ternary */
let total = 0;
for (let i = 0, e = len == null ? Infinity : len; i < e; ++i) {
const code = this.input.charCodeAt(this.state.pos);
let val;
// Handle numeric separators.
const prev = this.input.charCodeAt(this.state.pos - 1);
const next = this.input.charCodeAt(this.state.pos + 1);
if (code === charCodes.underscore) {
if (allowedSiblings.indexOf(next) === -1) {
this.raise(this.state.pos, "Invalid or unexpected token");
}
if (forbiddenSiblings.indexOf(prev) > -1 ||
forbiddenSiblings.indexOf(next) > -1 ||
Number.isNaN(next)) {
this.raise(this.state.pos, "Invalid or unexpected token");
}
// Ignore this _ character
++this.state.pos;
continue;
}
if (code >= charCodes.lowercaseA) {
val = code - charCodes.lowercaseA + charCodes.lineFeed;
}
else if (code >= charCodes.uppercaseA) {
val = code - charCodes.uppercaseA + charCodes.lineFeed;
}
else if (charCodes.isDigit(code)) {
val = code - charCodes.digit0; // 0-9
}
else {
val = Infinity;
}
if (val >= radix)
break;
++this.state.pos;
total = total * radix + val;
++base_1.state.pos;
// Need to use `skipWord` because '\uXXXX' sequences are allowed here (don't ask).
skipWord();
finishToken(1024 /* regexp */);
}
// Read an integer. We allow any valid digit, including hex digits, plus numeric separators, and
// stop at any other character.
function readInt() {
while (true) {
const code = base_1.input.charCodeAt(base_1.state.pos);
if ((code >= 48 /* digit0 */ && code <= 57 /* digit9 */) ||
(code >= 97 /* lowercaseA */ && code <= 102 /* lowercaseF */) ||
(code >= 65 /* uppercaseA */ && code <= 70 /* uppercaseF */) ||
code === 95 /* underscore */) {
base_1.state.pos++;
}
if (this.state.pos === start || (len != null && this.state.pos - start !== len)) {
return null;
else {
break;
}
return total;
}
readRadixNumber(radix) {
const start = this.state.pos;
let isBigInt = false;
this.state.pos += 2; // 0x
const val = this.readInt(radix);
if (val == null) {
this.raise(this.state.start + 2, `Expected number in radix ${radix}`);
}
function readRadixNumber() {
let isBigInt = false;
base_1.state.pos += 2; // 0x
readInt();
if (base_1.input.charCodeAt(base_1.state.pos) === 110 /* lowercaseN */) {
++base_1.state.pos;
isBigInt = true;
}
if (isBigInt) {
finishToken(512 /* bigint */);
return;
}
finishToken(0 /* num */);
}
// Read an integer, octal integer, or floating-point number.
function readNumber(startsWithDot) {
let isBigInt = false;
if (!startsWithDot) {
readInt();
}
let nextChar = base_1.input.charCodeAt(base_1.state.pos);
if (nextChar === 46 /* dot */) {
++base_1.state.pos;
readInt();
nextChar = base_1.input.charCodeAt(base_1.state.pos);
}
if (nextChar === 69 /* uppercaseE */ || nextChar === 101 /* lowercaseE */) {
nextChar = base_1.input.charCodeAt(++base_1.state.pos);
if (nextChar === 43 /* plusSign */ || nextChar === 45 /* dash */) {
++base_1.state.pos;
}
if (this.input.charCodeAt(this.state.pos) === charCodes.lowercaseN) {
++this.state.pos;
isBigInt = true;
}
if (identifier_1.isIdentifierStart(this.fullCharCodeAtPos())) {
this.raise(this.state.pos, "Identifier directly after number");
}
if (isBigInt) {
const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");
this.finishToken(types_1.types.bigint, str);
return;
}
this.finishToken(types_1.types.num, val);
readInt();
nextChar = base_1.input.charCodeAt(base_1.state.pos);
}
// Read an integer, octal integer, or floating-point number.
readNumber(startsWithDot) {
const start = this.state.pos;
let octal = this.input.charCodeAt(start) === charCodes.digit0;
let isFloat = false;
let isBigInt = false;
if (!startsWithDot && this.readInt(10) === null) {
this.raise(start, "Invalid number");
if (nextChar === 110 /* lowercaseN */) {
++base_1.state.pos;
isBigInt = true;
}
if (isBigInt) {
finishToken(512 /* bigint */);
return;
}
finishToken(0 /* num */);
}
function readString(quote) {
base_1.state.pos++;
for (;;) {
if (base_1.state.pos >= base_1.input.length) {
base_1.raise(base_1.state.start, "Unterminated string constant");
}
if (octal && this.state.pos === start + 1)
octal = false; // number === 0
let next = this.input.charCodeAt(this.state.pos);
if (next === charCodes.dot && !octal) {
++this.state.pos;
this.readInt(10);
isFloat = true;
next = this.input.charCodeAt(this.state.pos);
const ch = base_1.input.charCodeAt(base_1.state.pos);
if (ch === 92 /* backslash */) {
base_1.state.pos++;
}
if ((next === charCodes.uppercaseE || next === charCodes.lowercaseE) && !octal) {
next = this.input.charCodeAt(++this.state.pos);
if (next === charCodes.plusSign || next === charCodes.dash) {
++this.state.pos;
}
if (this.readInt(10) === null)
this.raise(start, "Invalid number");
isFloat = true;
next = this.input.charCodeAt(this.state.pos);
else if (ch === quote) {
break;
}
if (next === charCodes.lowercaseN) {
// disallow floats and legacy octal syntax, new style octal ("0o") is handled in this.readRadixNumber
if (isFloat || octal)
this.raise(start, "Invalid BigIntLiteral");
++this.state.pos;
isBigInt = true;
}
if (identifier_1.isIdentifierStart(this.fullCharCodeAtPos())) {
this.raise(this.state.pos, "Identifier directly after number");
}
// remove "_" for numeric literal separator, and "n" for BigInts
const str = this.input.slice(start, this.state.pos).replace(/[_n]/g, "");
if (isBigInt) {
this.finishToken(types_1.types.bigint, str);
return;
}
let val;
if (isFloat) {
val = parseFloat(str);
}
else if (!octal || str.length === 1) {
val = parseInt(str, 10);
}
else {
this.raise(start, "Invalid number");
}
this.finishToken(types_1.types.num, val);
base_1.state.pos++;
}
// Read a string value, interpreting backslash-escapes.
readCodePoint(throwOnInvalid) {
const ch = this.input.charCodeAt(this.state.pos);
let code;
if (ch === charCodes.leftCurlyBrace) {
const codePos = ++this.state.pos;
code = this.readHexChar(this.input.indexOf("}", this.state.pos) - this.state.pos, throwOnInvalid);
++this.state.pos;
if (code !== null && code > 0x10ffff) {
if (throwOnInvalid) {
this.raise(codePos, "Code point out of bounds");
}
else {
return null;
}
}
base_1.state.pos++;
finishToken(1536 /* string */);
}
// Reads template string tokens.
function readTmplToken() {
for (;;) {
if (base_1.state.pos >= base_1.input.length) {
base_1.raise(base_1.state.start, "Unterminated template");
}
else {
code = this.readHexChar(4, throwOnInvalid);
}
return code;
}
readString(quote) {
let out = "";
let chunkStart = ++this.state.pos;
for (;;) {
if (this.state.pos >= this.input.length) {
this.raise(this.state.start, "Unterminated string constant");
}
const ch = this.input.charCodeAt(this.state.pos);
if (ch === quote)
break;
if (ch === charCodes.backslash) {
out += this.input.slice(chunkStart, this.state.pos);
// $FlowFixMe
out += this.readEscapedChar(false);
chunkStart = this.state.pos;
}
else {
if (whitespace_1.isNewLine(ch)) {
this.raise(this.state.start, "Unterminated string constant");
const ch = base_1.input.charCodeAt(base_1.state.pos);
if (ch === 96 /* graveAccent */ ||
(ch === 36 /* dollarSign */ && base_1.input.charCodeAt(base_1.state.pos + 1) === 123 /* leftCurlyBrace */)) {
if (base_1.state.pos === base_1.state.start && match(11264 /* template */)) {
if (ch === 36 /* dollarSign */) {
base_1.state.pos += 2;
finishToken(12800 /* dollarBraceL */);
return;
}
++this.state.pos;
}
}
out += this.input.slice(chunkStart, this.state.pos++);
this.finishToken(types_1.types.string, out);
}
// Reads template string tokens.
readTmplToken() {
let out = "";
let chunkStart = this.state.pos;
let containsInvalid = false;
for (;;) {
if (this.state.pos >= this.input.length) {
this.raise(this.state.start, "Unterminated template");
}
const ch = this.input.charCodeAt(this.state.pos);
if (ch === charCodes.graveAccent ||
(ch === charCodes.dollarSign &&
this.input.charCodeAt(this.state.pos + 1) === charCodes.leftCurlyBrace)) {
if (this.state.pos === this.state.start && this.match(types_1.types.template)) {
if (ch === charCodes.dollarSign) {
this.state.pos += 2;
this.finishToken(types_1.types.dollarBraceL);
return;
}
else {
++this.state.pos;
this.finishToken(types_1.types.backQuote);
return;
}
}
out += this.input.slice(chunkStart, this.state.pos);
this.finishToken(types_1.types.template, containsInvalid ? null : out);
return;
}
if (ch === charCodes.backslash) {
out += this.input.slice(chunkStart, this.state.pos);
const escaped = this.readEscapedChar(true);
if (escaped === null) {
containsInvalid = true;
}
else {
out += escaped;
++base_1.state.pos;
finishToken(12288 /* backQuote */);
return;
}
chunkStart = this.state.pos;
}
else if (whitespace_1.isNewLine(ch)) {
out += this.input.slice(chunkStart, this.state.pos);
++this.state.pos;
switch (ch) {
case charCodes.carriageReturn:
if (this.input.charCodeAt(this.state.pos) === charCodes.lineFeed) {
++this.state.pos;
}
case charCodes.lineFeed:
out += "\n";
break;
default:
out += String.fromCharCode(ch);
break;
}
chunkStart = this.state.pos;
}
else {
++this.state.pos;
}
finishToken(11264 /* template */);
return;
}
}
// Used to read escaped characters
readEscapedChar(inTemplate) {
const throwOnInvalid = !inTemplate;
const ch = this.input.charCodeAt(++this.state.pos);
++this.state.pos;
switch (ch) {
case charCodes.lowercaseN:
return "\n";
case charCodes.lowercaseR:
return "\r";
case charCodes.lowercaseX: {
const code = this.readHexChar(2, throwOnInvalid);
return code === null ? null : String.fromCharCode(code);
}
case charCodes.lowercaseU: {
const code = this.readCodePoint(throwOnInvalid);
return code === null ? null : codePointToString(code);
}
case charCodes.lowercaseT:
return "\t";
case charCodes.lowercaseB:
return "\b";
case charCodes.lowercaseV:
return "\u000b";
case charCodes.lowercaseF:
return "\f";
case charCodes.carriageReturn:
if (this.input.charCodeAt(this.state.pos) === charCodes.lineFeed) {
++this.state.pos;
}
case charCodes.lineFeed:
return "";
default:
// TODO(sucrase): Consider removing all octal parsing.
if (ch >= charCodes.digit0 && ch <= charCodes.digit7) {
const codePos = this.state.pos - 1;
// $FlowFixMe
// @ts-ignore
let octalStr = this.input.substr(this.state.pos - 1, 3).match(/^[0-7]+/)[0];
let octal = parseInt(octalStr, 8);
if (octal > 255) {
octalStr = octalStr.slice(0, -1);
octal = parseInt(octalStr, 8);
}
if (octal > 0) {
if (inTemplate) {
return null;
}
else {
this.raise(codePos, "Octal literal in strict mode");
}
}
this.state.pos += octalStr.length - 1;
return String.fromCharCode(octal);
}
return String.fromCharCode(ch);
if (ch === 92 /* backslash */) {
base_1.state.pos++;
}
base_1.state.pos++;
}
// Used to read character escape sequences ('\x', '\u').
readHexChar(len, throwOnInvalid) {
const codePos = this.state.pos;
const n = this.readInt(16, len);
if (n === null) {
if (throwOnInvalid) {
this.raise(codePos, "Bad character escape sequence");
}
else {
this.state.pos = codePos - 1;
}
}
// Skip to the end of the current word. Note that this is the same as the snippet at the end of
// readWord, but calling skipWord from readWord seems to slightly hurt performance from some rough
// measurements.
function skipWord() {
while (base_1.state.pos < base_1.input.length) {
const ch = base_1.input.charCodeAt(base_1.state.pos);
if (identifier_1.isIdentifierChar(ch)) {
base_1.state.pos++;
}
return n;
}
// Read an identifier, and return it as a string. Sets `this.state.containsEsc`
// to whether the word contained a '\u' escape.
//
// Incrementally adds only escaped chars, adding other chunks as-is
// as a micro-optimization.
readWord1() {
let word = "";
let first = true;
let chunkStart = this.state.pos;
while (this.state.pos < this.input.length) {
const ch = this.fullCharCodeAtPos();
if (identifier_1.isIdentifierChar(ch)) {
this.state.pos += ch <= 0xffff ? 1 : 2;
}
else if (ch === charCodes.backslash) {
word += this.input.slice(chunkStart, this.state.pos);
const escStart = this.state.pos;
if (this.input.charCodeAt(++this.state.pos) !== charCodes.lowercaseU) {
this.raise(this.state.pos, "Expecting Unicode escape sequence \\uXXXX");
else if (ch === 92 /* backslash */) {
// \u
base_1.state.pos += 2;
if (base_1.input.charCodeAt(base_1.state.pos) === 123 /* leftCurlyBrace */) {
while (base_1.input.charCodeAt(base_1.state.pos) !== 123 /* leftCurlyBrace */) {
base_1.state.pos++;
}
++this.state.pos;
const esc = this.readCodePoint(true);
// $FlowFixMe (thinks esc may be null, but throwOnInvalid is true)
if (!(first ? identifier_1.isIdentifierStart : identifier_1.isIdentifierChar)(esc)) {
this.raise(escStart, "Invalid Unicode escape");
}
// $FlowFixMe
word += codePointToString(esc);
chunkStart = this.state.pos;
base_1.state.pos++;
}
else {
break;
}
first = false;
}
return word + this.input.slice(chunkStart, this.state.pos);
}
// Read an identifier or keyword token. Will check for reserved
// words when necessary.
readWord() {
const word = this.readWord1();
let type = types_1.types.name;
if (this.isKeyword(word)) {
type = types_1.keywords[word];
else {
break;
}
this.finishToken(type, word);
}
}
exports.default = Tokenizer;
exports.skipWord = skipWord;

@@ -1,2 +0,2 @@

import { Token } from "./index";
import { ContextualKeyword, Token } from "./index";
import { TokenType } from "./types";

@@ -15,3 +15,3 @@ export declare type Scope = {

type: TokenType;
value: any;
contextualKeyword: ContextualKeyword;
start: number;

@@ -22,4 +22,3 @@ end: number;

export default class State {
init(input: string): void;
input: string;
init(): void;
potentialArrowAt: number;

@@ -31,3 +30,3 @@ noAnonFunctionType: boolean;

type: TokenType;
value: any;
contextualKeyword: ContextualKeyword;
start: number;

@@ -34,0 +33,0 @@ end: number;

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("./types");
class State {
init(input) {
this.input = input;
init() {
this.potentialArrowAt = -1;

@@ -12,4 +10,3 @@ this.noAnonFunctionType = false;

this.pos = 0;
this.type = types_1.types.eof;
this.value = null;
this.type = 2560 /* eof */;
this.start = this.pos;

@@ -27,4 +24,3 @@ this.end = this.pos;

type: this.type,
// tslint:disable-next-line: no-any
value: this.value,
contextualKeyword: this.contextualKeyword,
start: this.start,

@@ -42,3 +38,3 @@ end: this.end,

this.type = snapshot.type;
this.value = snapshot.value;
this.contextualKeyword = snapshot.contextualKeyword;
this.start = snapshot.start;

@@ -45,0 +41,0 @@ this.end = snapshot.end;

@@ -1,186 +0,120 @@

export declare type TokenOptions = {
keyword?: string;
rightAssociative?: boolean;
isAssign?: boolean;
prefix?: boolean;
postfix?: boolean;
binop?: number;
};
export declare class TokenType {
label: string;
keyword?: string;
rightAssociative: boolean;
isAssign: boolean;
prefix: boolean;
postfix: boolean;
binop: number | null;
constructor(label: string, conf?: TokenOptions);
/**
* Enum of all token types, with bit fields to signify meaningful properties.
*/
export declare const enum TokenType {
PRECEDENCE_MASK = 15,
IS_KEYWORD = 16,
IS_ASSIGN = 32,
IS_RIGHT_ASSOCIATIVE = 64,
IS_PREFIX = 128,
IS_POSTFIX = 256,
num = 0,
bigint = 512,
regexp = 1024,
string = 1536,
name = 2048,
eof = 2560,
bracketL = 3072,
bracketR = 3584,
braceL = 4096,
braceBarL = 4608,
braceR = 5120,
braceBarR = 5632,
parenL = 6144,
parenR = 6656,
comma = 7168,
semi = 7680,
colon = 8192,
doubleColon = 8704,
dot = 9216,
question = 9728,
questionDot = 10240,
arrow = 10752,
template = 11264,
ellipsis = 11776,
backQuote = 12288,
dollarBraceL = 12800,
at = 13312,
hash = 13824,
eq = 14368,
assign = 14880,
incDec = 15744,
bang = 16000,
tilde = 16512,
pipeline = 16897,
nullishCoalescing = 17410,
logicalOR = 17922,
logicalAND = 18435,
bitwiseOR = 18948,
bitwiseXOR = 19461,
bitwiseAND = 19974,
equality = 20487,
lessThan = 21000,
greaterThan = 21512,
relationalOrEqual = 22024,
bitShift = 22537,
plus = 23178,
minus = 23690,
modulo = 24075,
star = 24587,
slash = 25099,
exponent = 25676,
jsxName = 26112,
jsxText = 26624,
jsxTagStart = 27136,
jsxTagEnd = 27648,
typeParameterStart = 28160,
nonNullAssertion = 28672,
_break = 29200,
_case = 29712,
_catch = 30224,
_continue = 30736,
_debugger = 31248,
_default = 31760,
_do = 32272,
_else = 32784,
_finally = 33296,
_for = 33808,
_function = 34320,
_if = 34832,
_return = 35344,
_switch = 35856,
_throw = 36496,
_try = 36880,
_var = 37392,
_let = 37904,
_const = 38416,
_while = 38928,
_with = 39440,
_new = 39952,
_this = 40464,
_super = 40976,
_class = 41488,
_extends = 42000,
_export = 42512,
_import = 43024,
_yield = 43536,
_null = 44048,
_true = 44560,
_false = 45072,
_in = 45592,
_instanceof = 46104,
_typeof = 46736,
_void = 47248,
_delete = 47760,
_async = 48144,
_get = 48656,
_set = 49168,
_declare = 49680,
_readonly = 50192,
_abstract = 50704,
_static = 51216,
_public = 51728,
_private = 52240,
_protected = 52752,
_as = 53264,
_enum = 53776,
_type = 54288,
_implements = 54800,
}
export declare class KeywordTokenType extends TokenType {
constructor(name: string, options?: TokenOptions);
}
export declare class BinopTokenType extends TokenType {
constructor(name: string, prec: number);
}
export declare const types: {
num: TokenType;
bigint: TokenType;
regexp: TokenType;
string: TokenType;
name: TokenType;
eof: TokenType;
bracketL: TokenType;
bracketR: TokenType;
braceL: TokenType;
braceBarL: TokenType;
braceR: TokenType;
braceBarR: TokenType;
parenL: TokenType;
parenR: TokenType;
comma: TokenType;
semi: TokenType;
colon: TokenType;
doubleColon: TokenType;
dot: TokenType;
question: TokenType;
questionDot: TokenType;
arrow: TokenType;
template: TokenType;
ellipsis: TokenType;
backQuote: TokenType;
dollarBraceL: TokenType;
at: TokenType;
hash: TokenType;
eq: TokenType;
assign: TokenType;
incDec: TokenType;
bang: TokenType;
tilde: TokenType;
pipeline: BinopTokenType;
nullishCoalescing: BinopTokenType;
logicalOR: BinopTokenType;
logicalAND: BinopTokenType;
bitwiseOR: BinopTokenType;
bitwiseXOR: BinopTokenType;
bitwiseAND: BinopTokenType;
equality: BinopTokenType;
lessThan: BinopTokenType;
greaterThan: BinopTokenType;
relationalOrEqual: BinopTokenType;
bitShift: BinopTokenType;
plusMin: TokenType;
modulo: BinopTokenType;
star: BinopTokenType;
slash: BinopTokenType;
exponent: TokenType;
jsxName: TokenType;
jsxText: TokenType;
jsxTagStart: TokenType;
jsxTagEnd: TokenType;
typeParameterStart: TokenType;
nonNullAssertion: TokenType;
_break: KeywordTokenType;
_case: KeywordTokenType;
_catch: KeywordTokenType;
_continue: KeywordTokenType;
_debugger: KeywordTokenType;
_default: KeywordTokenType;
_do: KeywordTokenType;
_else: KeywordTokenType;
_finally: KeywordTokenType;
_for: KeywordTokenType;
_function: KeywordTokenType;
_if: KeywordTokenType;
_return: KeywordTokenType;
_switch: KeywordTokenType;
_throw: KeywordTokenType;
_try: KeywordTokenType;
_var: KeywordTokenType;
_let: KeywordTokenType;
_const: KeywordTokenType;
_while: KeywordTokenType;
_with: KeywordTokenType;
_new: KeywordTokenType;
_this: KeywordTokenType;
_super: KeywordTokenType;
_class: KeywordTokenType;
_extends: KeywordTokenType;
_export: KeywordTokenType;
_import: KeywordTokenType;
_yield: KeywordTokenType;
_null: KeywordTokenType;
_true: KeywordTokenType;
_false: KeywordTokenType;
_in: KeywordTokenType;
_instanceof: KeywordTokenType;
_typeof: KeywordTokenType;
_void: KeywordTokenType;
_delete: KeywordTokenType;
_async: KeywordTokenType;
_get: KeywordTokenType;
_set: KeywordTokenType;
_declare: KeywordTokenType;
_readonly: KeywordTokenType;
_abstract: KeywordTokenType;
_static: KeywordTokenType;
_public: KeywordTokenType;
_private: KeywordTokenType;
_protected: KeywordTokenType;
_as: KeywordTokenType;
_enum: KeywordTokenType;
_type: KeywordTokenType;
_implements: KeywordTokenType;
};
export declare const keywords: {
break: KeywordTokenType;
case: KeywordTokenType;
catch: KeywordTokenType;
continue: KeywordTokenType;
debugger: KeywordTokenType;
default: KeywordTokenType;
do: KeywordTokenType;
else: KeywordTokenType;
finally: KeywordTokenType;
for: KeywordTokenType;
function: KeywordTokenType;
if: KeywordTokenType;
return: KeywordTokenType;
switch: KeywordTokenType;
throw: KeywordTokenType;
try: KeywordTokenType;
var: KeywordTokenType;
let: KeywordTokenType;
const: KeywordTokenType;
while: KeywordTokenType;
with: KeywordTokenType;
new: KeywordTokenType;
this: KeywordTokenType;
super: KeywordTokenType;
class: KeywordTokenType;
extends: KeywordTokenType;
export: KeywordTokenType;
import: KeywordTokenType;
yield: KeywordTokenType;
null: KeywordTokenType;
true: KeywordTokenType;
false: KeywordTokenType;
in: KeywordTokenType;
instanceof: KeywordTokenType;
typeof: KeywordTokenType;
void: KeywordTokenType;
delete: KeywordTokenType;
async: KeywordTokenType;
get: KeywordTokenType;
set: KeywordTokenType;
declare: KeywordTokenType;
readonly: KeywordTokenType;
abstract: KeywordTokenType;
static: KeywordTokenType;
public: KeywordTokenType;
private: KeywordTokenType;
protected: KeywordTokenType;
as: KeywordTokenType;
enum: KeywordTokenType;
type: KeywordTokenType;
implements: KeywordTokenType;
};
export declare function formatTokenType(tokenType: TokenType): string;
"use strict";
// ## Token types
Object.defineProperty(exports, "__esModule", { value: true });
// The assignment of fine-grained, information-carrying type objects
// allows the tokenizer to store the information it has about a
// token in a way that is very cheap for the parser to look up.
// All token type variables start with an underscore, to make them
// easy to recognize.
const isAssign = true;
const prefix = true;
const postfix = true;
class TokenType {
constructor(label, conf = {}) {
this.label = label;
this.keyword = conf.keyword;
this.rightAssociative = !!conf.rightAssociative;
this.isAssign = !!conf.isAssign;
this.prefix = !!conf.prefix;
this.postfix = !!conf.postfix;
this.binop = conf.binop === 0 ? 0 : conf.binop || null;
function formatTokenType(tokenType) {
switch (tokenType) {
case 0 /* num */:
return "num";
case 512 /* bigint */:
return "bigint";
case 1024 /* regexp */:
return "regexp";
case 1536 /* string */:
return "string";
case 2048 /* name */:
return "name";
case 2560 /* eof */:
return "eof";
case 3072 /* bracketL */:
return "[";
case 3584 /* bracketR */:
return "]";
case 4096 /* braceL */:
return "{";
case 4608 /* braceBarL */:
return "{|";
case 5120 /* braceR */:
return "}";
case 5632 /* braceBarR */:
return "|}";
case 6144 /* parenL */:
return "(";
case 6656 /* parenR */:
return ")";
case 7168 /* comma */:
return ",";
case 7680 /* semi */:
return ";";
case 8192 /* colon */:
return ":";
case 8704 /* doubleColon */:
return "::";
case 9216 /* dot */:
return ".";
case 9728 /* question */:
return "?";
case 10240 /* questionDot */:
return "?.";
case 10752 /* arrow */:
return "=>";
case 11264 /* template */:
return "template";
case 11776 /* ellipsis */:
return "...";
case 12288 /* backQuote */:
return "`";
case 12800 /* dollarBraceL */:
return "${";
case 13312 /* at */:
return "@";
case 13824 /* hash */:
return "#";
case 14368 /* eq */:
return "=";
case 14880 /* assign */:
return "_=";
case 15744 /* incDec */:
return "++/--";
case 16000 /* bang */:
return "!";
case 16512 /* tilde */:
return "~";
case 16897 /* pipeline */:
return "|>";
case 17410 /* nullishCoalescing */:
return "??";
case 17922 /* logicalOR */:
return "||";
case 18435 /* logicalAND */:
return "&&";
case 18948 /* bitwiseOR */:
return "|";
case 19461 /* bitwiseXOR */:
return "^";
case 19974 /* bitwiseAND */:
return "&";
case 20487 /* equality */:
return "==/!=";
case 21000 /* lessThan */:
return "<";
case 21512 /* greaterThan */:
return ">";
case 22024 /* relationalOrEqual */:
return "<=/>=";
case 22537 /* bitShift */:
return "<</>>";
case 23178 /* plus */:
return "+";
case 23690 /* minus */:
return "-";
case 24075 /* modulo */:
return "%";
case 24587 /* star */:
return "*";
case 25099 /* slash */:
return "/";
case 25676 /* exponent */:
return "**";
case 26112 /* jsxName */:
return "jsxName";
case 26624 /* jsxText */:
return "jsxText";
case 27136 /* jsxTagStart */:
return "jsxTagStart";
case 27648 /* jsxTagEnd */:
return "jsxTagEnd";
case 28160 /* typeParameterStart */:
return "typeParameterStart";
case 28672 /* nonNullAssertion */:
return "nonNullAssertion";
case 29200 /* _break */:
return "break";
case 29712 /* _case */:
return "case";
case 30224 /* _catch */:
return "catch";
case 30736 /* _continue */:
return "continue";
case 31248 /* _debugger */:
return "debugger";
case 31760 /* _default */:
return "default";
case 32272 /* _do */:
return "do";
case 32784 /* _else */:
return "else";
case 33296 /* _finally */:
return "finally";
case 33808 /* _for */:
return "for";
case 34320 /* _function */:
return "function";
case 34832 /* _if */:
return "if";
case 35344 /* _return */:
return "return";
case 35856 /* _switch */:
return "switch";
case 36496 /* _throw */:
return "throw";
case 36880 /* _try */:
return "try";
case 37392 /* _var */:
return "var";
case 37904 /* _let */:
return "let";
case 38416 /* _const */:
return "const";
case 38928 /* _while */:
return "while";
case 39440 /* _with */:
return "with";
case 39952 /* _new */:
return "new";
case 40464 /* _this */:
return "this";
case 40976 /* _super */:
return "super";
case 41488 /* _class */:
return "class";
case 42000 /* _extends */:
return "extends";
case 42512 /* _export */:
return "export";
case 43024 /* _import */:
return "import";
case 43536 /* _yield */:
return "yield";
case 44048 /* _null */:
return "null";
case 44560 /* _true */:
return "true";
case 45072 /* _false */:
return "false";
case 45592 /* _in */:
return "in";
case 46104 /* _instanceof */:
return "instanceof";
case 46736 /* _typeof */:
return "typeof";
case 47248 /* _void */:
return "void";
case 47760 /* _delete */:
return "delete";
case 48144 /* _async */:
return "async";
case 48656 /* _get */:
return "get";
case 49168 /* _set */:
return "set";
case 49680 /* _declare */:
return "declare";
case 50192 /* _readonly */:
return "readonly";
case 50704 /* _abstract */:
return "abstract";
case 51216 /* _static */:
return "static";
case 51728 /* _public */:
return "public";
case 52240 /* _private */:
return "private";
case 52752 /* _protected */:
return "protected";
case 53264 /* _as */:
return "as";
case 53776 /* _enum */:
return "enum";
case 54288 /* _type */:
return "type";
case 54800 /* _implements */:
return "implements";
default:
return "";
}
}
exports.TokenType = TokenType;
class KeywordTokenType extends TokenType {
constructor(name, options = {}) {
options.keyword = name;
super(name, options);
}
}
exports.KeywordTokenType = KeywordTokenType;
class BinopTokenType extends TokenType {
constructor(name, prec) {
super(name, { binop: prec });
}
}
exports.BinopTokenType = BinopTokenType;
exports.types = {
num: new TokenType("num"),
bigint: new TokenType("bigint"),
regexp: new TokenType("regexp"),
string: new TokenType("string"),
name: new TokenType("name"),
eof: new TokenType("eof"),
// Punctuation token types.
bracketL: new TokenType("["),
bracketR: new TokenType("]"),
braceL: new TokenType("{"),
braceBarL: new TokenType("{|"),
braceR: new TokenType("}"),
braceBarR: new TokenType("|}"),
parenL: new TokenType("("),
parenR: new TokenType(")"),
comma: new TokenType(","),
semi: new TokenType(";"),
colon: new TokenType(":"),
doubleColon: new TokenType("::"),
dot: new TokenType("."),
question: new TokenType("?"),
questionDot: new TokenType("?."),
arrow: new TokenType("=>"),
template: new TokenType("template"),
ellipsis: new TokenType("..."),
backQuote: new TokenType("`"),
dollarBraceL: new TokenType("${"),
at: new TokenType("@"),
hash: new TokenType("#"),
// Operators. These carry several kinds of properties to help the
// parser use them properly (the presence of these properties is
// what categorizes them as operators).
//
// `binop`, when present, specifies that this operator is a binary
// operator, and will refer to its precedence.
//
// `prefix` and `postfix` mark the operator as a prefix or postfix
// unary operator.
//
// `isAssign` marks all of `=`, `+=`, `-=` etcetera, which act as
// binary operators with a very low precedence, that should result
// in AssignmentExpression nodes.
eq: new TokenType("=", { isAssign }),
assign: new TokenType("_=", { isAssign }),
incDec: new TokenType("++/--", { prefix, postfix }),
bang: new TokenType("!", { prefix }),
tilde: new TokenType("~", { prefix }),
pipeline: new BinopTokenType("|>", 0),
nullishCoalescing: new BinopTokenType("??", 1),
logicalOR: new BinopTokenType("||", 1),
logicalAND: new BinopTokenType("&&", 2),
bitwiseOR: new BinopTokenType("|", 3),
bitwiseXOR: new BinopTokenType("^", 4),
bitwiseAND: new BinopTokenType("&", 5),
equality: new BinopTokenType("==/!=", 6),
lessThan: new BinopTokenType("<", 7),
greaterThan: new BinopTokenType(">", 7),
relationalOrEqual: new BinopTokenType("<=/>=", 7),
bitShift: new BinopTokenType("<</>>", 8),
plusMin: new TokenType("+/-", { binop: 9, prefix }),
modulo: new BinopTokenType("%", 10),
star: new BinopTokenType("*", 10),
slash: new BinopTokenType("/", 10),
exponent: new TokenType("**", { binop: 11, rightAssociative: true }),
jsxName: new TokenType("jsxName"),
jsxText: new TokenType("jsxText"),
jsxTagStart: new TokenType("jsxTagStart"),
jsxTagEnd: new TokenType("jsxTagEnd"),
typeParameterStart: new TokenType("typeParameterStart"),
nonNullAssertion: new TokenType("nonNullAssertion"),
// keywords
_break: new KeywordTokenType("break"),
_case: new KeywordTokenType("case"),
_catch: new KeywordTokenType("catch"),
_continue: new KeywordTokenType("continue"),
_debugger: new KeywordTokenType("debugger"),
_default: new KeywordTokenType("default"),
_do: new KeywordTokenType("do"),
_else: new KeywordTokenType("else"),
_finally: new KeywordTokenType("finally"),
_for: new KeywordTokenType("for"),
_function: new KeywordTokenType("function"),
_if: new KeywordTokenType("if"),
_return: new KeywordTokenType("return"),
_switch: new KeywordTokenType("switch"),
_throw: new KeywordTokenType("throw", { prefix }),
_try: new KeywordTokenType("try"),
_var: new KeywordTokenType("var"),
_let: new KeywordTokenType("let"),
_const: new KeywordTokenType("const"),
_while: new KeywordTokenType("while"),
_with: new KeywordTokenType("with"),
_new: new KeywordTokenType("new"),
_this: new KeywordTokenType("this"),
_super: new KeywordTokenType("super"),
_class: new KeywordTokenType("class"),
_extends: new KeywordTokenType("extends"),
_export: new KeywordTokenType("export"),
_import: new KeywordTokenType("import"),
_yield: new KeywordTokenType("yield"),
_null: new KeywordTokenType("null"),
_true: new KeywordTokenType("true"),
_false: new KeywordTokenType("false"),
_in: new KeywordTokenType("in", { binop: 7 }),
_instanceof: new KeywordTokenType("instanceof", { binop: 7 }),
_typeof: new KeywordTokenType("typeof", { prefix }),
_void: new KeywordTokenType("void", { prefix }),
_delete: new KeywordTokenType("delete", { prefix }),
// Other keywords
_async: new KeywordTokenType("async"),
_get: new KeywordTokenType("get"),
_set: new KeywordTokenType("set"),
// TypeScript keywords
_declare: new KeywordTokenType("declare"),
_readonly: new KeywordTokenType("readonly"),
_abstract: new KeywordTokenType("abstract"),
_static: new KeywordTokenType("static"),
_public: new KeywordTokenType("public"),
_private: new KeywordTokenType("private"),
_protected: new KeywordTokenType("protected"),
_as: new KeywordTokenType("as"),
_enum: new KeywordTokenType("enum"),
_type: new KeywordTokenType("type"),
_implements: new KeywordTokenType("implements"),
};
exports.keywords = {
break: exports.types._break,
case: exports.types._case,
catch: exports.types._catch,
continue: exports.types._continue,
debugger: exports.types._debugger,
default: exports.types._default,
do: exports.types._do,
else: exports.types._else,
finally: exports.types._finally,
for: exports.types._for,
function: exports.types._function,
if: exports.types._if,
return: exports.types._return,
switch: exports.types._switch,
throw: exports.types._throw,
try: exports.types._try,
var: exports.types._var,
let: exports.types._let,
const: exports.types._const,
while: exports.types._while,
with: exports.types._with,
new: exports.types._new,
this: exports.types._this,
super: exports.types._super,
class: exports.types._class,
extends: exports.types._extends,
export: exports.types._export,
import: exports.types._import,
yield: exports.types._yield,
null: exports.types._null,
true: exports.types._true,
false: exports.types._false,
in: exports.types._in,
instanceof: exports.types._instanceof,
typeof: exports.types._typeof,
void: exports.types._void,
delete: exports.types._delete,
// Other keywords
async: exports.types._async,
get: exports.types._get,
set: exports.types._set,
// TypeScript keywords
declare: exports.types._declare,
readonly: exports.types._readonly,
abstract: exports.types._abstract,
static: exports.types._static,
public: exports.types._public,
private: exports.types._private,
protected: exports.types._protected,
as: exports.types._as,
enum: exports.types._enum,
type: exports.types._type,
implements: exports.types._implements,
};
exports.formatTokenType = formatTokenType;

@@ -1,104 +0,106 @@

export declare const backSpace = 8;
export declare const lineFeed = 10;
export declare const carriageReturn = 13;
export declare const shiftOut = 14;
export declare const space = 32;
export declare const exclamationMark = 33;
export declare const quotationMark = 34;
export declare const numberSign = 35;
export declare const dollarSign = 36;
export declare const percentSign = 37;
export declare const ampersand = 38;
export declare const apostrophe = 39;
export declare const leftParenthesis = 40;
export declare const rightParenthesis = 41;
export declare const asterisk = 42;
export declare const plusSign = 43;
export declare const comma = 44;
export declare const dash = 45;
export declare const dot = 46;
export declare const slash = 47;
export declare const digit0 = 48;
export declare const digit1 = 49;
export declare const digit2 = 50;
export declare const digit3 = 51;
export declare const digit4 = 52;
export declare const digit5 = 53;
export declare const digit6 = 54;
export declare const digit7 = 55;
export declare const digit8 = 56;
export declare const digit9 = 57;
export declare const colon = 58;
export declare const semicolon = 59;
export declare const lessThan = 60;
export declare const equalsTo = 61;
export declare const greaterThan = 62;
export declare const questionMark = 63;
export declare const atSign = 64;
export declare const uppercaseA = 65;
export declare const uppercaseB = 66;
export declare const uppercaseC = 67;
export declare const uppercaseD = 68;
export declare const uppercaseE = 69;
export declare const uppercaseF = 70;
export declare const uppercaseG = 71;
export declare const uppercaseH = 72;
export declare const uppercaseI = 73;
export declare const uppercaseJ = 74;
export declare const uppercaseK = 75;
export declare const uppercaseL = 76;
export declare const uppercaseM = 77;
export declare const uppercaseN = 78;
export declare const uppercaseO = 79;
export declare const uppercaseP = 80;
export declare const uppercaseQ = 81;
export declare const uppercaseR = 82;
export declare const uppercaseS = 83;
export declare const uppercaseT = 84;
export declare const uppercaseU = 85;
export declare const uppercaseV = 86;
export declare const uppercaseW = 87;
export declare const uppercaseX = 88;
export declare const uppercaseY = 89;
export declare const uppercaseZ = 90;
export declare const leftSquareBracket = 91;
export declare const backslash = 92;
export declare const rightSquareBracket = 93;
export declare const caret = 94;
export declare const underscore = 95;
export declare const graveAccent = 96;
export declare const lowercaseA = 97;
export declare const lowercaseB = 98;
export declare const lowercaseC = 99;
export declare const lowercaseD = 100;
export declare const lowercaseE = 101;
export declare const lowercaseF = 102;
export declare const lowercaseG = 103;
export declare const lowercaseH = 104;
export declare const lowercaseI = 105;
export declare const lowercaseJ = 106;
export declare const lowercaseK = 107;
export declare const lowercaseL = 108;
export declare const lowercaseM = 109;
export declare const lowercaseN = 110;
export declare const lowercaseO = 111;
export declare const lowercaseP = 112;
export declare const lowercaseQ = 113;
export declare const lowercaseR = 114;
export declare const lowercaseS = 115;
export declare const lowercaseT = 116;
export declare const lowercaseU = 117;
export declare const lowercaseV = 118;
export declare const lowercaseW = 119;
export declare const lowercaseX = 120;
export declare const lowercaseY = 121;
export declare const lowercaseZ = 122;
export declare const leftCurlyBrace = 123;
export declare const verticalBar = 124;
export declare const rightCurlyBrace = 125;
export declare const tilde = 126;
export declare const nonBreakingSpace = 160;
export declare const oghamSpaceMark = 5760;
export declare const lineSeparator = 8232;
export declare const paragraphSeparator = 8233;
export declare const enum charCodes {
backSpace = 8,
lineFeed = 10,
carriageReturn = 13,
shiftOut = 14,
space = 32,
exclamationMark = 33,
quotationMark = 34,
numberSign = 35,
dollarSign = 36,
percentSign = 37,
ampersand = 38,
apostrophe = 39,
leftParenthesis = 40,
rightParenthesis = 41,
asterisk = 42,
plusSign = 43,
comma = 44,
dash = 45,
dot = 46,
slash = 47,
digit0 = 48,
digit1 = 49,
digit2 = 50,
digit3 = 51,
digit4 = 52,
digit5 = 53,
digit6 = 54,
digit7 = 55,
digit8 = 56,
digit9 = 57,
colon = 58,
semicolon = 59,
lessThan = 60,
equalsTo = 61,
greaterThan = 62,
questionMark = 63,
atSign = 64,
uppercaseA = 65,
uppercaseB = 66,
uppercaseC = 67,
uppercaseD = 68,
uppercaseE = 69,
uppercaseF = 70,
uppercaseG = 71,
uppercaseH = 72,
uppercaseI = 73,
uppercaseJ = 74,
uppercaseK = 75,
uppercaseL = 76,
uppercaseM = 77,
uppercaseN = 78,
uppercaseO = 79,
uppercaseP = 80,
uppercaseQ = 81,
uppercaseR = 82,
uppercaseS = 83,
uppercaseT = 84,
uppercaseU = 85,
uppercaseV = 86,
uppercaseW = 87,
uppercaseX = 88,
uppercaseY = 89,
uppercaseZ = 90,
leftSquareBracket = 91,
backslash = 92,
rightSquareBracket = 93,
caret = 94,
underscore = 95,
graveAccent = 96,
lowercaseA = 97,
lowercaseB = 98,
lowercaseC = 99,
lowercaseD = 100,
lowercaseE = 101,
lowercaseF = 102,
lowercaseG = 103,
lowercaseH = 104,
lowercaseI = 105,
lowercaseJ = 106,
lowercaseK = 107,
lowercaseL = 108,
lowercaseM = 109,
lowercaseN = 110,
lowercaseO = 111,
lowercaseP = 112,
lowercaseQ = 113,
lowercaseR = 114,
lowercaseS = 115,
lowercaseT = 116,
lowercaseU = 117,
lowercaseV = 118,
lowercaseW = 119,
lowercaseX = 120,
lowercaseY = 121,
lowercaseZ = 122,
leftCurlyBrace = 123,
verticalBar = 124,
rightCurlyBrace = 125,
tilde = 126,
nonBreakingSpace = 160,
oghamSpaceMark = 5760,
lineSeparator = 8232,
paragraphSeparator = 8233,
}
export declare function isDigit(code: number): boolean;
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.backSpace = 8;
exports.lineFeed = 10; // '\n'
exports.carriageReturn = 13; // '\r'
exports.shiftOut = 14;
exports.space = 32;
exports.exclamationMark = 33; // '!'
exports.quotationMark = 34; // '"'
exports.numberSign = 35; // '#'
exports.dollarSign = 36; // '$'
exports.percentSign = 37; // '%'
exports.ampersand = 38; // '&'
exports.apostrophe = 39; // '''
exports.leftParenthesis = 40; // '('
exports.rightParenthesis = 41; // ')'
exports.asterisk = 42; // '*'
exports.plusSign = 43; // '+'
exports.comma = 44; // ','
exports.dash = 45; // '-'
exports.dot = 46; // '.'
exports.slash = 47; // '/'
exports.digit0 = 48; // '0'
exports.digit1 = 49; // '1'
exports.digit2 = 50; // '2'
exports.digit3 = 51; // '3'
exports.digit4 = 52; // '4'
exports.digit5 = 53; // '5'
exports.digit6 = 54; // '6'
exports.digit7 = 55; // '7'
exports.digit8 = 56; // '8'
exports.digit9 = 57; // '9'
exports.colon = 58; // ':'
exports.semicolon = 59; // ';'
exports.lessThan = 60; // '<'
exports.equalsTo = 61; // '='
exports.greaterThan = 62; // '>'
exports.questionMark = 63; // '?'
exports.atSign = 64; // '@'
exports.uppercaseA = 65; // 'A'
exports.uppercaseB = 66; // 'B'
exports.uppercaseC = 67; // 'C'
exports.uppercaseD = 68; // 'D'
exports.uppercaseE = 69; // 'E'
exports.uppercaseF = 70; // 'F'
exports.uppercaseG = 71; // 'G'
exports.uppercaseH = 72; // 'H'
exports.uppercaseI = 73; // 'I'
exports.uppercaseJ = 74; // 'J'
exports.uppercaseK = 75; // 'K'
exports.uppercaseL = 76; // 'L'
exports.uppercaseM = 77; // 'M'
exports.uppercaseN = 78; // 'N'
exports.uppercaseO = 79; // 'O'
exports.uppercaseP = 80; // 'P'
exports.uppercaseQ = 81; // 'Q'
exports.uppercaseR = 82; // 'R'
exports.uppercaseS = 83; // 'S'
exports.uppercaseT = 84; // 'T'
exports.uppercaseU = 85; // 'U'
exports.uppercaseV = 86; // 'V'
exports.uppercaseW = 87; // 'W'
exports.uppercaseX = 88; // 'X'
exports.uppercaseY = 89; // 'Y'
exports.uppercaseZ = 90; // 'Z'
exports.leftSquareBracket = 91; // '['
exports.backslash = 92; // '\ '
exports.rightSquareBracket = 93; // ']'
exports.caret = 94; // '^'
exports.underscore = 95; // '_'
exports.graveAccent = 96; // '`'
exports.lowercaseA = 97; // 'a'
exports.lowercaseB = 98; // 'b'
exports.lowercaseC = 99; // 'c'
exports.lowercaseD = 100; // 'd'
exports.lowercaseE = 101; // 'e'
exports.lowercaseF = 102; // 'f'
exports.lowercaseG = 103; // 'g'
exports.lowercaseH = 104; // 'h'
exports.lowercaseI = 105; // 'i'
exports.lowercaseJ = 106; // 'j'
exports.lowercaseK = 107; // 'k'
exports.lowercaseL = 108; // 'l'
exports.lowercaseM = 109; // 'm'
exports.lowercaseN = 110; // 'n'
exports.lowercaseO = 111; // 'o'
exports.lowercaseP = 112; // 'p'
exports.lowercaseQ = 113; // 'q'
exports.lowercaseR = 114; // 'r'
exports.lowercaseS = 115; // 's'
exports.lowercaseT = 116; // 't'
exports.lowercaseU = 117; // 'u'
exports.lowercaseV = 118; // 'v'
exports.lowercaseW = 119; // 'w'
exports.lowercaseX = 120; // 'x'
exports.lowercaseY = 121; // 'y'
exports.lowercaseZ = 122; // 'z'
exports.leftCurlyBrace = 123; // '{'
exports.verticalBar = 124; // '|'
exports.rightCurlyBrace = 125; // '}'
exports.tilde = 126; // '~'
exports.nonBreakingSpace = 160;
// eslint-disable-next-line no-irregular-whitespace
exports.oghamSpaceMark = 5760; // ' '
exports.lineSeparator = 8232;
exports.paragraphSeparator = 8233;
function isDigit(code) {
return code >= exports.digit0 && code <= exports.digit9;
return ((code >= 48 /* digit0 */ && code <= 57 /* digit9 */) ||
(code >= 97 /* lowercaseA */ && code <= 102 /* lowercaseF */) ||
(code >= 65 /* uppercaseA */ && code <= 70 /* uppercaseF */));
}
exports.isDigit = isDigit;

@@ -1,3 +0,2 @@

export declare const isKeyword: (str: string) => boolean;
export declare function isIdentifierStart(code: number): boolean;
export declare function isIdentifierChar(code: number): boolean;
"use strict";
/* eslint max-len: 0 */
Object.defineProperty(exports, "__esModule", { value: true });
function makePredicate(words) {
const wordsArr = words.split(" ");
return (str) => wordsArr.indexOf(str) >= 0;
}
// And the keywords
exports.isKeyword = makePredicate("break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this let const class extends export import yield super");
// ## Character categories

@@ -24,26 +18,2 @@ // Big ugly regular expressions that match characters in the

nonASCIIidentifierChars = null;
// These are a run-length and offset encoded representation of the
// >0xffff code points that are a valid part of identifiers. The
// offset starts at 0x10000, and each pair of numbers represents an
// offset to the next range, and then a size of the range. They were
// generated by `bin/generate-identifier-regex.js`.
/* prettier-ignore */
const astralIdentifierStartCodes = [0, 11, 2, 25, 2, 18, 2, 1, 2, 14, 3, 13, 35, 122, 70, 52, 268, 28, 4, 48, 48, 31, 14, 29, 6, 37, 11, 29, 3, 35, 5, 7, 2, 4, 43, 157, 19, 35, 5, 35, 5, 39, 9, 51, 157, 310, 10, 21, 11, 7, 153, 5, 3, 0, 2, 43, 2, 1, 4, 0, 3, 22, 11, 22, 10, 30, 66, 18, 2, 1, 11, 21, 11, 25, 71, 55, 7, 1, 65, 0, 16, 3, 2, 2, 2, 26, 45, 28, 4, 28, 36, 7, 2, 27, 28, 53, 11, 21, 11, 18, 14, 17, 111, 72, 56, 50, 14, 50, 785, 52, 76, 44, 33, 24, 27, 35, 42, 34, 4, 0, 13, 47, 15, 3, 22, 0, 2, 0, 36, 17, 2, 24, 85, 6, 2, 0, 2, 3, 2, 14, 2, 9, 8, 46, 39, 7, 3, 1, 3, 21, 2, 6, 2, 1, 2, 4, 4, 0, 19, 0, 13, 4, 159, 52, 19, 3, 54, 47, 21, 1, 2, 0, 185, 46, 42, 3, 37, 47, 21, 0, 60, 42, 86, 25, 391, 63, 32, 0, 257, 0, 11, 39, 8, 0, 22, 0, 12, 39, 3, 3, 55, 56, 264, 8, 2, 36, 18, 0, 50, 29, 113, 6, 2, 1, 2, 37, 22, 0, 698, 921, 103, 110, 18, 195, 2749, 1070, 4050, 582, 8634, 568, 8, 30, 114, 29, 19, 47, 17, 3, 32, 20, 6, 18, 881, 68, 12, 0, 67, 12, 65, 1, 31, 6124, 20, 754, 9486, 286, 82, 395, 2309, 106, 6, 12, 4, 8, 8, 9, 5991, 84, 2, 70, 2, 1, 3, 0, 3, 1, 3, 3, 2, 11, 2, 0, 2, 6, 2, 64, 2, 3, 3, 7, 2, 6, 2, 27, 2, 3, 2, 4, 2, 0, 4, 6, 2, 339, 3, 24, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 30, 2, 24, 2, 7, 4149, 196, 60, 67, 1213, 3, 2, 26, 2, 1, 2, 0, 3, 0, 2, 9, 2, 3, 2, 0, 2, 0, 7, 0, 5, 0, 2, 0, 2, 0, 2, 2, 2, 1, 2, 0, 3, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 1, 2, 0, 3, 3, 2, 6, 2, 3, 2, 3, 2, 0, 2, 9, 2, 16, 6, 2, 2, 4, 2, 16, 4421, 42710, 42, 4148, 12, 221, 3, 5761, 15, 7472, 3104, 541];
/* prettier-ignore */
const astralIdentifierCodes = [509, 0, 227, 0, 150, 4, 294, 9, 1368, 2, 2, 1, 6, 3, 41, 2, 5, 0, 166, 1, 1306, 2, 54, 14, 32, 9, 16, 3, 46, 10, 54, 9, 7, 2, 37, 13, 2, 9, 52, 0, 13, 2, 49, 13, 10, 2, 4, 9, 83, 11, 7, 0, 161, 11, 6, 9, 7, 3, 57, 0, 2, 6, 3, 1, 3, 2, 10, 0, 11, 1, 3, 6, 4, 4, 193, 17, 10, 9, 87, 19, 13, 9, 214, 6, 3, 8, 28, 1, 83, 16, 16, 9, 82, 12, 9, 9, 84, 14, 5, 9, 423, 9, 280, 9, 41, 6, 2, 3, 9, 0, 10, 10, 47, 15, 406, 7, 2, 7, 17, 9, 57, 21, 2, 13, 123, 5, 4, 0, 2, 1, 2, 6, 2, 0, 9, 9, 19719, 9, 135, 4, 60, 6, 26, 9, 1016, 45, 17, 3, 19723, 1, 5319, 4, 4, 5, 9, 7, 3, 6, 31, 3, 149, 2, 1418, 49, 513, 54, 5, 49, 9, 0, 15, 0, 23, 4, 2, 14, 1361, 6, 2, 16, 3, 6, 2, 1, 2, 4, 2214, 6, 110, 6, 6, 9, 792487, 239];
// This has a complexity linear to the value of the code. The
// assumption is that looking up astral identifier characters is
// rare.
function isInAstralSet(code, set) {
let pos = 0x10000;
for (let i = 0; i < set.length; i += 2) {
pos += set[i];
if (pos > code)
return false;
pos += set[i + 1];
if (pos >= code)
return true;
}
return false;
}
// Test whether a given character code starts an identifier.

@@ -59,6 +29,7 @@ function isIdentifierStart(code) {

return true;
if (code <= 0xffff) {
if (code < 0xd800) {
return code >= 0xaa && nonASCIIidentifierStart.test(String.fromCharCode(code));
}
return isInAstralSet(code, astralIdentifierStartCodes);
// Anything outside of BMP we call an identifier char.
return true;
}

@@ -80,7 +51,8 @@ exports.isIdentifierStart = isIdentifierStart;

return true;
if (code <= 0xffff) {
if (code < 0xd800) {
return code >= 0xaa && nonASCIIidentifier.test(String.fromCharCode(code));
}
return (isInAstralSet(code, astralIdentifierStartCodes) || isInAstralSet(code, astralIdentifierCodes));
// Anything outside of BMP we call an identifier char.
return true;
}
exports.isIdentifierChar = isIdentifierChar;
{
"name": "sucrase",
"version": "1.12.1",
"version": "1.13.0",
"description": "Super-fast alternative to Babel for when you can target modern JS runtimes",

@@ -21,2 +21,3 @@ "author": "Alan Pierce <alangpierce@gmail.com>",

"clean": "rm -rf ./build ./dist",
"generate": "ts-node ./generator/generate.ts",
"self-build": "script/self-build",

@@ -23,0 +24,0 @@ "self-test": "mocha test/**/*.ts --opts test/mocha-self-test.opts",

@@ -17,7 +17,6 @@ # Sucrase

**Current state:** The project is in active development. It is about 13x faster
than Babel and about 5x faster than TypeScript, and it has been tested on
hundreds of thousands of lines of code. You may still find bugs when running on
your code, though. You probably shouldn't use it in production, but you may find
it useful in development. Feel free to file issues!
**Current state:** The project is in active development. It is about 20x faster
than Babel and about 8x faster than TypeScript, and it has been tested on
hundreds of thousands of lines of code. Still, you may find correctness issues
when running on a large codebase. Feel free to file issues!

@@ -29,2 +28,4 @@ Sucrase can convert the following codebases with all tests passing:

* [Babel](https://github.com/babel/babel) (63K lines of code, flow, imports).
* [React](https://github.com/facebook/react) (86K lines of code, JSX, flow,
imports).
* [TSLint](https://github.com/palantir/tslint) (20K lines of code, typescript,

@@ -143,4 +144,4 @@ imports).

Currently, Sucrase runs about 13x faster than Babel (even when Babel only runs
the relevant transforms) and 5x faster than TypeScript. Here's the output of
Currently, Sucrase runs about 20x faster than Babel (even when Babel only runs
the relevant transforms) and 8x faster than TypeScript. Here's the output of
one run of `npm run benchmark`:

@@ -150,5 +151,5 @@

Simulating transpilation of 100,000 lines of code:
Sucrase: 777.638ms
TypeScript: 3820.914ms
Babel: 10041.368ms
Sucrase: 469.672ms
TypeScript: 3782.414ms
Babel: 9591.515ms
```

@@ -168,3 +169,3 @@

* Implement more integrations, like for Webpack and Rollup.
* Implement more integrations, like a Rollup plugin.
* Emit proper source maps. (The line numbers already match up, but this would

@@ -189,5 +190,4 @@ help with debuggers and other tools.)

information from Babel.
* Fix some known correctness loose ends, like import hoisting, export assignment
detection for complex assignments, and fully replicating the small differences
between Babel and the TypeScript compiler.
* Fix some known correctness loose ends, like import hoisting and fully
replicating the small differences between Babel and the TypeScript compiler.

@@ -194,0 +194,0 @@ ## License and attribution

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc