Packages
moon
2.90.1
2.90.5
retired
2.90.4
2.90.3
2.90.2
2.90.1
2.90.0
2.89.4
2.89.1
2.89.0
2.88.0
2.87.11
2.87.10
2.87.9
2.87.8
2.87.7
2.87.6
2.87.5
2.87.4
2.87.3
2.87.2
2.87.1
2.87.0
2.86.1
2.86.0
2.85.1
2.85.0
2.84.0
2.83.0
2.82.0
2.81.4
2.81.3
2.81.2
2.81.1
2.81.0
2.80.2
2.80.1
2.80.0
2.79.13
2.79.12
2.79.11
2.79.10
2.79.9
2.79.8
2.79.7
2.79.6
2.79.5
2.79.4
2.79.3
2.79.2
2.79.1
2.79.0
2.78.4
2.78.3
2.78.2
2.78.1
2.78.0
2.77.0
2.76.5
2.76.4
2.76.3
2.76.2
2.76.1
2.76.0
2.75.0
2.74.1
2.74.0
2.73.8
2.73.7
2.73.6
2.73.5
2.73.4
2.73.3
2.73.2
2.73.1
2.73.0
2.72.5
2.72.4
2.72.3
2.72.2
2.72.1
2.72.0
2.71.1
2.71.0
2.70.0
2.69.2
2.69.1
2.69.0
2.68.11
2.68.10
Components-based design system written in elixir
Current section
Files
Jump to
Current section
Files
assets/node_modules/sucrase/dist/esm/parser/traverser/statement.js
/* eslint max-len: 0 */
import {File} from "../index";
import {
flowAfterParseClassSuper,
flowAfterParseVarHead,
flowParseExportDeclaration,
flowParseExportStar,
flowParseIdentifierStatement,
flowParseImportSpecifier,
flowParseTypeAnnotation,
flowParseTypeParameterDeclaration,
flowShouldDisallowExportDefaultSpecifier,
flowShouldParseExportDeclaration,
flowShouldParseExportStar,
flowStartParseFunctionParams,
flowStartParseImportSpecifiers,
flowTryParseExportDefaultExpression,
flowTryParseStatement,
} from "../plugins/flow";
import {
tsAfterParseClassSuper,
tsAfterParseVarHead,
tsIsDeclarationStart,
tsParseExportDeclaration,
tsParseExportSpecifier,
tsParseIdentifierStatement,
tsParseImportEqualsDeclaration,
tsParseImportSpecifier,
tsParseMaybeDecoratorArguments,
tsParseModifiers,
tsStartParseFunctionParams,
tsTryParseClassMemberWithIsStatic,
tsTryParseExport,
tsTryParseExportDefaultExpression,
tsTryParseStatementContent,
tsTryParseTypeAnnotation,
tsTryParseTypeParameters,
} from "../plugins/typescript";
import {
eat,
eatTypeToken,
IdentifierRole,
lookaheadType,
lookaheadTypeAndKeyword,
match,
next,
nextTokenStart,
nextTokenStartSince,
popTypeContext,
pushTypeContext,
} from "../tokenizer";
import {ContextualKeyword} from "../tokenizer/keywords";
import {Scope} from "../tokenizer/state";
import { TokenType as tt} from "../tokenizer/types";
import {charCodes} from "../util/charcodes";
import {getNextContextId, input, isFlowEnabled, isTypeScriptEnabled, state} from "./base";
import {
parseCallExpressionArguments,
parseExprAtom,
parseExpression,
parseExprSubscripts,
parseFunctionBodyAndFinish,
parseIdentifier,
parseMaybeAssign,
parseMethod,
parseObj,
parseParenExpression,
parsePropertyName,
} from "./expression";
import {
parseBindingAtom,
parseBindingIdentifier,
parseBindingList,
parseImportedIdentifier,
} from "./lval";
import {
canInsertSemicolon,
eatContextual,
expect,
expectContextual,
hasFollowingLineBreak,
hasPrecedingLineBreak,
isContextual,
isLineTerminator,
isLookaheadContextual,
semicolon,
unexpected,
} from "./util";
export function parseTopLevel() {
parseBlockBody(tt.eof);
state.scopes.push(new Scope(0, state.tokens.length, true));
if (state.scopeDepth !== 0) {
throw new Error(`Invalid scope depth at end of file: ${state.scopeDepth}`);
}
return new File(state.tokens, state.scopes);
}
// 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.
export function parseStatement(declaration) {
if (isFlowEnabled) {
if (flowTryParseStatement()) {
return;
}
}
if (match(tt.at)) {
parseDecorators();
}
parseStatementContent(declaration);
}
function parseStatementContent(declaration) {
if (isTypeScriptEnabled) {
if (tsTryParseStatementContent()) {
return;
}
}
const starttype = 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 tt._break:
case tt._continue:
parseBreakContinueStatement();
return;
case tt._debugger:
parseDebuggerStatement();
return;
case tt._do:
parseDoStatement();
return;
case tt._for:
parseForStatement();
return;
case tt._function:
if (lookaheadType() === tt.dot) break;
if (!declaration) unexpected();
parseFunctionStatement();
return;
case tt._class:
if (!declaration) unexpected();
parseClass(true);
return;
case tt._if:
parseIfStatement();
return;
case tt._return:
parseReturnStatement();
return;
case tt._switch:
parseSwitchStatement();
return;
case tt._throw:
parseThrowStatement();
return;
case tt._try:
parseTryStatement();
return;
case tt._let:
case tt._const:
if (!declaration) unexpected(); // NOTE: falls through to _var
case tt._var:
parseVarStatement(starttype !== tt._var);
return;
case tt._while:
parseWhileStatement();
return;
case tt.braceL:
parseBlock();
return;
case tt.semi:
parseEmptyStatement();
return;
case tt._export:
case tt._import: {
const nextType = lookaheadType();
if (nextType === tt.parenL || nextType === tt.dot) {
break;
}
next();
if (starttype === tt._import) {
parseImport();
} else {
parseExport();
}
return;
}
case tt.name:
if (state.contextualKeyword === ContextualKeyword._async) {
const functionStart = state.start;
// peek ahead and see if next token is a function
const snapshot = state.snapshot();
next();
if (match(tt._function) && !canInsertSemicolon()) {
expect(tt._function);
parseFunction(functionStart, true);
return;
} else {
state.restoreFromSnapshot(snapshot);
}
} else if (
state.contextualKeyword === ContextualKeyword._using &&
!hasFollowingLineBreak() &&
// Statements like `using[0]` and `using in foo` aren't actual using
// declarations.
lookaheadType() === tt.name
) {
parseVarStatement(true);
return;
}
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 = state.tokens.length;
parseExpression();
let simpleName = null;
if (state.tokens.length === initialTokensLength + 1) {
const token = state.tokens[state.tokens.length - 1];
if (token.type === tt.name) {
simpleName = token.contextualKeyword;
}
}
if (simpleName == null) {
semicolon();
return;
}
if (eat(tt.colon)) {
parseLabeledStatement();
} else {
// This was an identifier, so we might want to handle flow/typescript-specific cases.
parseIdentifierStatement(simpleName);
}
}
export function parseDecorators() {
while (match(tt.at)) {
parseDecorator();
}
}
function parseDecorator() {
next();
if (eat(tt.parenL)) {
parseExpression();
expect(tt.parenR);
} else {
parseIdentifier();
while (eat(tt.dot)) {
parseIdentifier();
}
parseMaybeDecoratorArguments();
}
}
function parseMaybeDecoratorArguments() {
if (isTypeScriptEnabled) {
tsParseMaybeDecoratorArguments();
} else {
baseParseMaybeDecoratorArguments();
}
}
export function baseParseMaybeDecoratorArguments() {
if (eat(tt.parenL)) {
parseCallExpressionArguments();
}
}
function parseBreakContinueStatement() {
next();
if (!isLineTerminator()) {
parseIdentifier();
semicolon();
}
}
function parseDebuggerStatement() {
next();
semicolon();
}
function parseDoStatement() {
next();
parseStatement(false);
expect(tt._while);
parseParenExpression();
eat(tt.semi);
}
function parseForStatement() {
state.scopeDepth++;
const startTokenIndex = state.tokens.length;
parseAmbiguousForStatement();
const endTokenIndex = state.tokens.length;
state.scopes.push(new Scope(startTokenIndex, endTokenIndex, false));
state.scopeDepth--;
}
/**
* Determine if this token is a `using` declaration (explicit resource
* management) as part of a loop.
* https://github.com/tc39/proposal-explicit-resource-management
*/
function isUsingInLoop() {
if (!isContextual(ContextualKeyword._using)) {
return false;
}
// This must be `for (using of`, where `using` is the name of the loop
// variable.
if (isLookaheadContextual(ContextualKeyword._of)) {
return false;
}
return true;
}
// 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() {
next();
let forAwait = false;
if (isContextual(ContextualKeyword._await)) {
forAwait = true;
next();
}
expect(tt.parenL);
if (match(tt.semi)) {
if (forAwait) {
unexpected();
}
parseFor();
return;
}
if (match(tt._var) || match(tt._let) || match(tt._const) || isUsingInLoop()) {
next();
parseVar(true, state.type !== tt._var);
if (match(tt._in) || isContextual(ContextualKeyword._of)) {
parseForIn(forAwait);
return;
}
parseFor();
return;
}
parseExpression(true);
if (match(tt._in) || isContextual(ContextualKeyword._of)) {
parseForIn(forAwait);
return;
}
if (forAwait) {
unexpected();
}
parseFor();
}
function parseFunctionStatement() {
const functionStart = state.start;
next();
parseFunction(functionStart, true);
}
function parseIfStatement() {
next();
parseParenExpression();
parseStatement(false);
if (eat(tt._else)) {
parseStatement(false);
}
}
function parseReturnStatement() {
next();
// In `return` (and `break`/`continue`), the keywords with
// optional arguments, we eagerly look for a semicolon or the
// possibility to insert one.
if (!isLineTerminator()) {
parseExpression();
semicolon();
}
}
function parseSwitchStatement() {
next();
parseParenExpression();
state.scopeDepth++;
const startTokenIndex = state.tokens.length;
expect(tt.braceL);
// Don't bother validation; just go through any sequence of cases, defaults, and statements.
while (!match(tt.braceR) && !state.error) {
if (match(tt._case) || match(tt._default)) {
const isCase = match(tt._case);
next();
if (isCase) {
parseExpression();
}
expect(tt.colon);
} else {
parseStatement(true);
}
}
next(); // Closing brace
const endTokenIndex = state.tokens.length;
state.scopes.push(new Scope(startTokenIndex, endTokenIndex, false));
state.scopeDepth--;
}
function parseThrowStatement() {
next();
parseExpression();
semicolon();
}
function parseCatchClauseParam() {
parseBindingAtom(true /* isBlockScope */);
if (isTypeScriptEnabled) {
tsTryParseTypeAnnotation();
}
}
function parseTryStatement() {
next();
parseBlock();
if (match(tt._catch)) {
next();
let catchBindingStartTokenIndex = null;
if (match(tt.parenL)) {
state.scopeDepth++;
catchBindingStartTokenIndex = state.tokens.length;
expect(tt.parenL);
parseCatchClauseParam();
expect(tt.parenR);
}
parseBlock();
if (catchBindingStartTokenIndex != null) {
// We need a special scope for the catch binding which includes the binding itself and the
// catch block.
const endTokenIndex = state.tokens.length;
state.scopes.push(new Scope(catchBindingStartTokenIndex, endTokenIndex, false));
state.scopeDepth--;
}
}
if (eat(tt._finally)) {
parseBlock();
}
}
export function parseVarStatement(isBlockScope) {
next();
parseVar(false, isBlockScope);
semicolon();
}
function parseWhileStatement() {
next();
parseParenExpression();
parseStatement(false);
}
function parseEmptyStatement() {
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 (isTypeScriptEnabled) {
tsParseIdentifierStatement(contextualKeyword);
} else if (isFlowEnabled) {
flowParseIdentifierStatement(contextualKeyword);
} else {
semicolon();
}
}
// Parse a semicolon-enclosed block of statements.
export function parseBlock(isFunctionScope = false, contextId = 0) {
const startTokenIndex = state.tokens.length;
state.scopeDepth++;
expect(tt.braceL);
if (contextId) {
state.tokens[state.tokens.length - 1].contextId = contextId;
}
parseBlockBody(tt.braceR);
if (contextId) {
state.tokens[state.tokens.length - 1].contextId = contextId;
}
const endTokenIndex = state.tokens.length;
state.scopes.push(new Scope(startTokenIndex, endTokenIndex, isFunctionScope));
state.scopeDepth--;
}
export function parseBlockBody(end) {
while (!eat(end) && !state.error) {
parseStatement(true);
}
}
// Parse a regular `for` loop. The disambiguation code in
// `parseStatement` will already have parsed the init statement or
// expression.
function parseFor() {
expect(tt.semi);
if (!match(tt.semi)) {
parseExpression();
}
expect(tt.semi);
if (!match(tt.parenR)) {
parseExpression();
}
expect(tt.parenR);
parseStatement(false);
}
// Parse a `for`/`in` and `for`/`of` loop, which are almost
// same from parser's perspective.
function parseForIn(forAwait) {
if (forAwait) {
eatContextual(ContextualKeyword._of);
} else {
next();
}
parseExpression();
expect(tt.parenR);
parseStatement(false);
}
// Parse a list of variable declarations.
function parseVar(isFor, isBlockScope) {
while (true) {
parseVarHead(isBlockScope);
if (eat(tt.eq)) {
const eqIndex = state.tokens.length - 1;
parseMaybeAssign(isFor);
state.tokens[eqIndex].rhsEndIndex = state.tokens.length;
}
if (!eat(tt.comma)) {
break;
}
}
}
function parseVarHead(isBlockScope) {
parseBindingAtom(isBlockScope);
if (isTypeScriptEnabled) {
tsAfterParseVarHead();
} else if (isFlowEnabled) {
flowAfterParseVarHead();
}
}
// Parse a function declaration or literal (depending on the
// `isStatement` parameter).
export function parseFunction(
functionStart,
isStatement,
optionalId = false,
) {
if (match(tt.star)) {
next();
}
if (isStatement && !optionalId && !match(tt.name) && !match(tt._yield)) {
unexpected();
}
let nameScopeStartTokenIndex = null;
if (match(tt.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 = state.tokens.length;
state.scopeDepth++;
}
parseBindingIdentifier(false);
}
const startTokenIndex = state.tokens.length;
state.scopeDepth++;
parseFunctionParams();
parseFunctionBodyAndFinish(functionStart);
const endTokenIndex = state.tokens.length;
// In addition to the block scope of the function body, we need a separate function-style scope
// that includes the params.
state.scopes.push(new Scope(startTokenIndex, endTokenIndex, true));
state.scopeDepth--;
if (nameScopeStartTokenIndex !== null) {
state.scopes.push(new Scope(nameScopeStartTokenIndex, endTokenIndex, true));
state.scopeDepth--;
}
}
export function parseFunctionParams(
allowModifiers = false,
funcContextId = 0,
) {
if (isTypeScriptEnabled) {
tsStartParseFunctionParams();
} else if (isFlowEnabled) {
flowStartParseFunctionParams();
}
expect(tt.parenL);
if (funcContextId) {
state.tokens[state.tokens.length - 1].contextId = funcContextId;
}
parseBindingList(
tt.parenR,
false /* isBlockScope */,
false /* allowEmpty */,
allowModifiers,
funcContextId,
);
if (funcContextId) {
state.tokens[state.tokens.length - 1].contextId = funcContextId;
}
}
// Parse a class declaration or literal (depending on the
// `isStatement` parameter).
export 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 = getNextContextId();
next();
state.tokens[state.tokens.length - 1].contextId = contextId;
state.tokens[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 = state.tokens.length;
state.scopeDepth++;
}
parseClassId(isStatement, optionalId);
parseClassSuper();
const openBraceIndex = state.tokens.length;
parseClassBody(contextId);
if (state.error) {
return;
}
state.tokens[openBraceIndex].contextId = contextId;
state.tokens[state.tokens.length - 1].contextId = contextId;
if (nameScopeStartTokenIndex !== null) {
const endTokenIndex = state.tokens.length;
state.scopes.push(new Scope(nameScopeStartTokenIndex, endTokenIndex, false));
state.scopeDepth--;
}
}
function isClassProperty() {
return match(tt.eq) || match(tt.semi) || match(tt.braceR) || match(tt.bang) || match(tt.colon);
}
function isClassMethod() {
return match(tt.parenL) || match(tt.lessThan);
}
function parseClassBody(classContextId) {
expect(tt.braceL);
while (!eat(tt.braceR) && !state.error) {
if (eat(tt.semi)) {
continue;
}
if (match(tt.at)) {
parseDecorator();
continue;
}
const memberStart = state.start;
parseClassMember(memberStart, classContextId);
}
}
function parseClassMember(memberStart, classContextId) {
if (isTypeScriptEnabled) {
tsParseModifiers([
ContextualKeyword._declare,
ContextualKeyword._public,
ContextualKeyword._protected,
ContextualKeyword._private,
ContextualKeyword._override,
]);
}
let isStatic = false;
if (match(tt.name) && state.contextualKeyword === ContextualKeyword._static) {
parseIdentifier(); // eats 'static'
if (isClassMethod()) {
parseClassMethod(memberStart, /* isConstructor */ false);
return;
} else if (isClassProperty()) {
parseClassProperty();
return;
}
// otherwise something static
state.tokens[state.tokens.length - 1].type = tt._static;
isStatic = true;
if (match(tt.braceL)) {
// This is a static block. Mark the word "static" with the class context ID for class element
// detection and parse as a regular block.
state.tokens[state.tokens.length - 1].contextId = classContextId;
parseBlock();
return;
}
}
parseClassMemberWithIsStatic(memberStart, isStatic, classContextId);
}
function parseClassMemberWithIsStatic(
memberStart,
isStatic,
classContextId,
) {
if (isTypeScriptEnabled) {
if (tsTryParseClassMemberWithIsStatic(isStatic)) {
return;
}
}
if (eat(tt.star)) {
// a generator
parseClassPropertyName(classContextId);
parseClassMethod(memberStart, /* isConstructor */ false);
return;
}
// 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 = state.tokens[state.tokens.length - 1];
// We allow "constructor" as either an identifier or a string.
if (token.contextualKeyword === ContextualKeyword._constructor) {
isConstructor = true;
}
parsePostMemberNameModifiers();
if (isClassMethod()) {
parseClassMethod(memberStart, isConstructor);
} else if (isClassProperty()) {
parseClassProperty();
} else if (token.contextualKeyword === ContextualKeyword._async && !isLineTerminator()) {
state.tokens[state.tokens.length - 1].type = tt._async;
// an async method
const isGenerator = match(tt.star);
if (isGenerator) {
next();
}
// The so-called parsed name would have been "async": get the real name.
parseClassPropertyName(classContextId);
parsePostMemberNameModifiers();
parseClassMethod(memberStart, false /* isConstructor */);
} else if (
(token.contextualKeyword === ContextualKeyword._get ||
token.contextualKeyword === ContextualKeyword._set) &&
!(isLineTerminator() && match(tt.star))
) {
if (token.contextualKeyword === ContextualKeyword._get) {
state.tokens[state.tokens.length - 1].type = tt._get;
} else {
state.tokens[state.tokens.length - 1].type = tt._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, /* isConstructor */ false);
} else if (token.contextualKeyword === ContextualKeyword._accessor && !isLineTerminator()) {
parseClassPropertyName(classContextId);
parseClassProperty();
} else if (isLineTerminator()) {
// an uninitialized class property (due to ASI, since we don't otherwise recognize the next token)
parseClassProperty();
} else {
unexpected();
}
}
function parseClassMethod(functionStart, isConstructor) {
if (isTypeScriptEnabled) {
tsTryParseTypeParameters();
} else if (isFlowEnabled) {
if (match(tt.lessThan)) {
flowParseTypeParameterDeclaration();
}
}
parseMethod(functionStart, isConstructor);
}
// Return the name of the class property, if it is a simple identifier.
export function parseClassPropertyName(classContextId) {
parsePropertyName(classContextId);
}
export function parsePostMemberNameModifiers() {
if (isTypeScriptEnabled) {
const oldIsType = pushTypeContext(0);
eat(tt.question);
popTypeContext(oldIsType);
}
}
export function parseClassProperty() {
if (isTypeScriptEnabled) {
eatTypeToken(tt.bang);
tsTryParseTypeAnnotation();
} else if (isFlowEnabled) {
if (match(tt.colon)) {
flowParseTypeAnnotation();
}
}
if (match(tt.eq)) {
const equalsTokenIndex = state.tokens.length;
next();
parseMaybeAssign();
state.tokens[equalsTokenIndex].rhsEndIndex = state.tokens.length;
}
semicolon();
}
function parseClassId(isStatement, optionalId = false) {
if (
isTypeScriptEnabled &&
(!isStatement || optionalId) &&
isContextual(ContextualKeyword._implements)
) {
return;
}
if (match(tt.name)) {
parseBindingIdentifier(true);
}
if (isTypeScriptEnabled) {
tsTryParseTypeParameters();
} else if (isFlowEnabled) {
if (match(tt.lessThan)) {
flowParseTypeParameterDeclaration();
}
}
}
// Returns true if there was a superclass.
function parseClassSuper() {
let hasSuper = false;
if (eat(tt._extends)) {
parseExprSubscripts();
hasSuper = true;
} else {
hasSuper = false;
}
if (isTypeScriptEnabled) {
tsAfterParseClassSuper(hasSuper);
} else if (isFlowEnabled) {
flowAfterParseClassSuper(hasSuper);
}
}
// Parses module export declaration.
export function parseExport() {
const exportIndex = state.tokens.length - 1;
if (isTypeScriptEnabled) {
if (tsTryParseExport()) {
return;
}
}
// export * from '...'
if (shouldParseExportStar()) {
parseExportStar();
} else if (isExportDefaultSpecifier()) {
// export default from
parseIdentifier();
if (match(tt.comma) && lookaheadType() === tt.star) {
expect(tt.comma);
expect(tt.star);
expectContextual(ContextualKeyword._as);
parseIdentifier();
} else {
parseExportSpecifiersMaybe();
}
parseExportFrom();
} else if (eat(tt._default)) {
// export default ...
parseExportDefaultExpression();
} else if (shouldParseExportDeclaration()) {
parseExportDeclaration();
} else {
// export { x, y as z } [from '...']
parseExportSpecifiers();
parseExportFrom();
}
state.tokens[exportIndex].rhsEndIndex = state.tokens.length;
}
function parseExportDefaultExpression() {
if (isTypeScriptEnabled) {
if (tsTryParseExportDefaultExpression()) {
return;
}
}
if (isFlowEnabled) {
if (flowTryParseExportDefaultExpression()) {
return;
}
}
const functionStart = state.start;
if (eat(tt._function)) {
parseFunction(functionStart, true, true);
} else if (isContextual(ContextualKeyword._async) && lookaheadType() === tt._function) {
// async function declaration
eatContextual(ContextualKeyword._async);
eat(tt._function);
parseFunction(functionStart, true, true);
} else if (match(tt._class)) {
parseClass(true, true);
} else if (match(tt.at)) {
parseDecorators();
parseClass(true, true);
} else {
parseMaybeAssign();
semicolon();
}
}
function parseExportDeclaration() {
if (isTypeScriptEnabled) {
tsParseExportDeclaration();
} else if (isFlowEnabled) {
flowParseExportDeclaration();
} else {
parseStatement(true);
}
}
function isExportDefaultSpecifier() {
if (isTypeScriptEnabled && tsIsDeclarationStart()) {
return false;
} else if (isFlowEnabled && flowShouldDisallowExportDefaultSpecifier()) {
return false;
}
if (match(tt.name)) {
return state.contextualKeyword !== ContextualKeyword._async;
}
if (!match(tt._default)) {
return false;
}
const _next = nextTokenStart();
const lookahead = lookaheadTypeAndKeyword();
const hasFrom =
lookahead.type === tt.name && lookahead.contextualKeyword === ContextualKeyword._from;
if (lookahead.type === tt.comma) {
return true;
}
// lookahead again when `export default from` is seen
if (hasFrom) {
const nextAfterFrom = input.charCodeAt(nextTokenStartSince(_next + 4));
return nextAfterFrom === charCodes.quotationMark || nextAfterFrom === charCodes.apostrophe;
}
return false;
}
function parseExportSpecifiersMaybe() {
if (eat(tt.comma)) {
parseExportSpecifiers();
}
}
export function parseExportFrom() {
if (eatContextual(ContextualKeyword._from)) {
parseExprAtom();
maybeParseImportAssertions();
}
semicolon();
}
function shouldParseExportStar() {
if (isFlowEnabled) {
return flowShouldParseExportStar();
} else {
return match(tt.star);
}
}
function parseExportStar() {
if (isFlowEnabled) {
flowParseExportStar();
} else {
baseParseExportStar();
}
}
export function baseParseExportStar() {
expect(tt.star);
if (isContextual(ContextualKeyword._as)) {
parseExportNamespace();
} else {
parseExportFrom();
}
}
function parseExportNamespace() {
next();
state.tokens[state.tokens.length - 1].type = tt._as;
parseIdentifier();
parseExportSpecifiersMaybe();
parseExportFrom();
}
function shouldParseExportDeclaration() {
return (
(isTypeScriptEnabled && tsIsDeclarationStart()) ||
(isFlowEnabled && flowShouldParseExportDeclaration()) ||
state.type === tt._var ||
state.type === tt._const ||
state.type === tt._let ||
state.type === tt._function ||
state.type === tt._class ||
isContextual(ContextualKeyword._async) ||
match(tt.at)
);
}
// Parses a comma-separated list of module exports.
export function parseExportSpecifiers() {
let first = true;
// export { x, y as z } [from '...']
expect(tt.braceL);
while (!eat(tt.braceR) && !state.error) {
if (first) {
first = false;
} else {
expect(tt.comma);
if (eat(tt.braceR)) {
break;
}
}
parseExportSpecifier();
}
}
function parseExportSpecifier() {
if (isTypeScriptEnabled) {
tsParseExportSpecifier();
return;
}
parseIdentifier();
state.tokens[state.tokens.length - 1].identifierRole = IdentifierRole.ExportAccess;
if (eatContextual(ContextualKeyword._as)) {
parseIdentifier();
}
}
/**
* Starting at the `module` token in an import, determine if it was truly an
* import reflection token or just looks like one.
*
* Returns true for:
* import module foo from "foo";
* import module from from "foo";
*
* Returns false for:
* import module from "foo";
* import module, {bar} from "foo";
*/
function isImportReflection() {
const snapshot = state.snapshot();
expectContextual(ContextualKeyword._module);
if (eatContextual(ContextualKeyword._from)) {
if (isContextual(ContextualKeyword._from)) {
state.restoreFromSnapshot(snapshot);
return true;
} else {
state.restoreFromSnapshot(snapshot);
return false;
}
} else if (match(tt.comma)) {
state.restoreFromSnapshot(snapshot);
return false;
} else {
state.restoreFromSnapshot(snapshot);
return true;
}
}
/**
* Eat the "module" token from the import reflection proposal.
* https://github.com/tc39/proposal-import-reflection
*/
function parseMaybeImportReflection() {
// isImportReflection does snapshot/restore, so only run it if we see the word
// "module".
if (isContextual(ContextualKeyword._module) && isImportReflection()) {
next();
}
}
// Parses import declaration.
export function parseImport() {
if (isTypeScriptEnabled && match(tt.name) && lookaheadType() === tt.eq) {
tsParseImportEqualsDeclaration();
return;
}
if (isTypeScriptEnabled && isContextual(ContextualKeyword._type)) {
const lookahead = lookaheadTypeAndKeyword();
if (lookahead.type === tt.name && lookahead.contextualKeyword !== ContextualKeyword._from) {
// One of these `import type` cases:
// import type T = require('T');
// import type A from 'A';
expectContextual(ContextualKeyword._type);
if (lookaheadType() === tt.eq) {
tsParseImportEqualsDeclaration();
return;
}
// If this is an `import type...from` statement, then we already ate the
// type token, so proceed to the regular import parser.
} else if (lookahead.type === tt.star || lookahead.type === tt.braceL) {
// One of these `import type` cases, in which case we can eat the type token
// and proceed as normal:
// import type * as A from 'A';
// import type {a} from 'A';
expectContextual(ContextualKeyword._type);
}
// Otherwise, we are importing the name "type".
}
// import '...'
if (match(tt.string)) {
parseExprAtom();
} else {
parseMaybeImportReflection();
parseImportSpecifiers();
expectContextual(ContextualKeyword._from);
parseExprAtom();
}
maybeParseImportAssertions();
semicolon();
}
// eslint-disable-next-line no-unused-vars
function shouldParseDefaultImport() {
return match(tt.name);
}
function parseImportSpecifierLocal() {
parseImportedIdentifier();
}
// Parses a comma-separated list of module imports.
function parseImportSpecifiers() {
if (isFlowEnabled) {
flowStartParseImportSpecifiers();
}
let first = true;
if (shouldParseDefaultImport()) {
// import defaultObj, { x, y as z } from '...'
parseImportSpecifierLocal();
if (!eat(tt.comma)) return;
}
if (match(tt.star)) {
next();
expectContextual(ContextualKeyword._as);
parseImportSpecifierLocal();
return;
}
expect(tt.braceL);
while (!eat(tt.braceR) && !state.error) {
if (first) {
first = false;
} else {
// Detect an attempt to deep destructure
if (eat(tt.colon)) {
unexpected(
"ES2015 named imports do not destructure. Use another statement for destructuring after the import.",
);
}
expect(tt.comma);
if (eat(tt.braceR)) {
break;
}
}
parseImportSpecifier();
}
}
function parseImportSpecifier() {
if (isTypeScriptEnabled) {
tsParseImportSpecifier();
return;
}
if (isFlowEnabled) {
flowParseImportSpecifier();
return;
}
parseImportedIdentifier();
if (isContextual(ContextualKeyword._as)) {
state.tokens[state.tokens.length - 1].identifierRole = IdentifierRole.ImportAccess;
next();
parseImportedIdentifier();
}
}
/**
* Parse import assertions like `assert {type: "json"}`.
*
* Import assertions technically have their own syntax, but are always parseable
* as a plain JS object, so just do that for simplicity.
*/
function maybeParseImportAssertions() {
if (isContextual(ContextualKeyword._assert) && !hasPrecedingLineBreak()) {
next();
parseObj(false, false);
}
}