diff options
| author | Philipp Tanlak <philipp.tanlak@gmail.com> | 2025-11-24 20:54:57 +0100 |
|---|---|---|
| committer | Philipp Tanlak <philipp.tanlak@gmail.com> | 2025-11-24 20:57:48 +0100 |
| commit | b1e2c8fd5cb5dfa46bc440a12eafaf56cd844b1c (patch) | |
| tree | 49d360fd6cbc6a2754efe93524ac47ff0fbe0f7d /node_modules/sucrase/dist/esm/parser/traverser/lval.js | |
Docs
Diffstat (limited to 'node_modules/sucrase/dist/esm/parser/traverser/lval.js')
| -rw-r--r-- | node_modules/sucrase/dist/esm/parser/traverser/lval.js | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/node_modules/sucrase/dist/esm/parser/traverser/lval.js b/node_modules/sucrase/dist/esm/parser/traverser/lval.js new file mode 100644 index 0000000..f5c4855 --- /dev/null +++ b/node_modules/sucrase/dist/esm/parser/traverser/lval.js @@ -0,0 +1,159 @@ +import {flowParseAssignableListItemTypes} from "../plugins/flow"; +import {tsParseAssignableListItemTypes, tsParseModifiers} from "../plugins/typescript"; +import { + eat, + IdentifierRole, + match, + next, + popTypeContext, + pushTypeContext, +} from "../tokenizer/index"; +import {ContextualKeyword} from "../tokenizer/keywords"; +import {TokenType, TokenType as tt} from "../tokenizer/types"; +import {isFlowEnabled, isTypeScriptEnabled, state} from "./base"; +import {parseIdentifier, parseMaybeAssign, parseObj} from "./expression"; +import {expect, unexpected} from "./util"; + +export function parseSpread() { + next(); + parseMaybeAssign(false); +} + +export function parseRest(isBlockScope) { + next(); + parseBindingAtom(isBlockScope); +} + +export function parseBindingIdentifier(isBlockScope) { + parseIdentifier(); + markPriorBindingIdentifier(isBlockScope); +} + +export function parseImportedIdentifier() { + parseIdentifier(); + state.tokens[state.tokens.length - 1].identifierRole = IdentifierRole.ImportDeclaration; +} + +export function markPriorBindingIdentifier(isBlockScope) { + let identifierRole; + if (state.scopeDepth === 0) { + identifierRole = IdentifierRole.TopLevelDeclaration; + } else if (isBlockScope) { + identifierRole = IdentifierRole.BlockScopedDeclaration; + } else { + identifierRole = IdentifierRole.FunctionScopedDeclaration; + } + state.tokens[state.tokens.length - 1].identifierRole = identifierRole; +} + +// Parses lvalue (assignable) atom. +export function parseBindingAtom(isBlockScope) { + switch (state.type) { + case tt._this: { + // In TypeScript, "this" may be the name of a parameter, so allow it. + const oldIsType = pushTypeContext(0); + next(); + popTypeContext(oldIsType); + return; + } + + case tt._yield: + case tt.name: { + state.type = tt.name; + parseBindingIdentifier(isBlockScope); + return; + } + + case tt.bracketL: { + next(); + parseBindingList(tt.bracketR, isBlockScope, true /* allowEmpty */); + return; + } + + case tt.braceL: + parseObj(true, isBlockScope); + return; + + default: + unexpected(); + } +} + +export function parseBindingList( + close, + isBlockScope, + allowEmpty = false, + allowModifiers = false, + contextId = 0, +) { + let first = true; + + let hasRemovedComma = false; + const firstItemTokenIndex = state.tokens.length; + + while (!eat(close) && !state.error) { + if (first) { + first = false; + } else { + expect(tt.comma); + state.tokens[state.tokens.length - 1].contextId = contextId; + // 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 && state.tokens[firstItemTokenIndex].isType) { + state.tokens[state.tokens.length - 1].isType = true; + hasRemovedComma = true; + } + } + if (allowEmpty && match(tt.comma)) { + // Empty item; nothing further to parse for this item. + } else if (eat(close)) { + break; + } else if (match(tt.ellipsis)) { + parseRest(isBlockScope); + parseAssignableListItemTypes(); + // Support rest element trailing commas allowed by TypeScript <2.9. + eat(TokenType.comma); + expect(close); + break; + } else { + parseAssignableListItem(allowModifiers, isBlockScope); + } + } +} + +function parseAssignableListItem(allowModifiers, isBlockScope) { + if (allowModifiers) { + tsParseModifiers([ + ContextualKeyword._public, + ContextualKeyword._protected, + ContextualKeyword._private, + ContextualKeyword._readonly, + ContextualKeyword._override, + ]); + } + + parseMaybeDefault(isBlockScope); + parseAssignableListItemTypes(); + parseMaybeDefault(isBlockScope, true /* leftAlreadyParsed */); +} + +function parseAssignableListItemTypes() { + if (isFlowEnabled) { + flowParseAssignableListItemTypes(); + } else if (isTypeScriptEnabled) { + tsParseAssignableListItemTypes(); + } +} + +// Parses assignment pattern around given atom if possible. +export function parseMaybeDefault(isBlockScope, leftAlreadyParsed = false) { + if (!leftAlreadyParsed) { + parseBindingAtom(isBlockScope); + } + if (!eat(tt.eq)) { + return; + } + const eqIndex = state.tokens.length - 1; + parseMaybeAssign(); + state.tokens[eqIndex].rhsEndIndex = state.tokens.length; +} |