js-slang
Version:
Javascript-based implementations of Source, written in Typescript
975 lines • 41.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// Code taken from https://github.com/patternfly/patternfly-org/blob/main/packages/ast-helpers/acorn-typescript.js
// Some cases such as arrow function expressions are not properly handled
const acorn_1 = require("acorn");
// Taken from https://github.com/acornjs/acorn/blob/6770c2ecbf8e01470f6c9a2f59c786f014045baf/acorn/src/whitespace.js#L4C1-L5C1
const lineBreak = /\r\n?|\n|\u2028|\u2029/;
class DestructuringErrors {
constructor() {
this.shorthandAssign =
this.trailingComma =
this.parenthesizedAssign =
this.parenthesizedBind =
this.doubleProto =
-1;
}
}
const tsPredefinedType = {
any: 'TSAnyKeyword',
bigint: 'TSBigIntKeyword',
boolean: 'TSBooleanKeyword',
never: 'TSNeverKeyword',
null: 'TSNullKeyword',
number: 'TSNumberKeyword',
object: 'TSObjectKeyword',
string: 'TSStringKeyword',
symbol: 'TSSymbolKeyword',
undefined: 'TSUndefinedKeyword',
unknown: 'TSUnknownKeyword',
void: 'TSVoidKeyword'
};
const tsDeclaration = {
interface: 1,
type: 2,
enum: 4,
declare: 8
};
const tsTypeOperator = {
typeof: 1,
keyof: 2,
infer: 4
};
const tsExprMarkup = {
as: 1,
'!': 2
};
const tsPlugin = (BaseParser) => {
return class extends BaseParser {
constructor(...args) {
super(...args);
// Allow 'interface'
this.reservedWords = /^(?:enum)$/;
this.reservedWordsStrict = this.reservedWords;
}
finishNode(node, type) {
if (type.startsWith('TS')) {
// Hack to not need acorn-walk to detect TS
this.options.sourceType = 'ts';
}
return this.finishNodeAt.call(this, node, type, this.lastTokEnd, this.lastTokEndLoc);
}
computeLocByOffset(offset) {
// If `locations` option is off, do nothing for saving performance.
if (this.options.locations) {
return (0, acorn_1.getLineInfo)(this.input, offset);
}
else {
return;
}
}
startNodeAtNode(node) {
return this.startNodeAt(node.start, this.computeLocByOffset(node.start));
}
tsPreparePreview() {
const { pos, curLine, type, value, end, start, endLoc, startLoc, scopeStack, lastTokStartLoc, lastTokEndLoc, lastTokEnd, lastTokStart, context } = this;
return () => {
this.pos = pos;
this.curLine = curLine;
this.type = type;
this.value = value;
this.end = end;
this.start = start;
this.endLoc = endLoc;
this.startLoc = startLoc;
this.scopeStack = scopeStack;
this.lastTokStartLoc = lastTokStartLoc;
this.lastTokEndLoc = lastTokEndLoc;
this.lastTokEnd = lastTokEnd;
this.lastTokStart = lastTokStart;
this.context = context;
};
}
_isStartOfTypeParameters() {
return this.value && this.value.charCodeAt(0) === 60; // <
}
_isEndOfTypeParameters() {
return this.value && this.value.charCodeAt(0) === 62; // >
}
_hasPrecedingLineBreak() {
return lineBreak.test(this.input.slice(this.lastTokEnd, this.start));
}
// Studied from Babel
parseExpressionStatement(node, expr) {
return expr.type === 'Identifier'
? this._parseTSDeclaration(node, expr)
: super.parseExpressionStatement(node, expr);
}
parseBindingAtom() {
const node = super.parseBindingAtom();
if (this.eat(acorn_1.tokTypes.colon)) {
node.typeAnnotation = this.parseTSTypeAnnotation(false);
node.end = node.typeAnnotation.end;
if (this.options.locations) {
node.loc.end = node.typeAnnotation.loc.end;
}
}
return node;
}
parseMaybeDefault(startPos, startLoc, left) {
if (!left) {
left = this.parseBindingAtom();
if (this.eat(acorn_1.tokTypes.question)) {
left.optional = true;
}
// `parseBindingAtom` is executed,
// so we need to check type annotation again.
if (this.eat(acorn_1.tokTypes.colon)) {
left.typeAnnotation = this.parseTSTypeAnnotation(false);
left.end = left.typeAnnotation.end;
if (this.options.locations) {
left.loc.end = left.typeAnnotation.loc.end;
}
}
}
return super.parseMaybeDefault(startPos, startLoc, left);
}
parseMaybeAssign(noIn, refDestructuringErrors, afterLeftParse) {
let node = super.parseMaybeAssign(noIn, refDestructuringErrors, afterLeftParse);
node = this._parseMaybeTSExpression(node);
return node;
}
parseFunctionParams(node) {
node.typeParameters = this.parseMaybeTSTypeParameterDeclaration();
return super.parseFunctionParams(node);
}
parseFunctionBody(node, isArrowFunction) {
// I know, return type doesn't belong to function body,
// but this will be less hacky.
if (this.eat(acorn_1.tokTypes.colon)) {
node.returnType = this.parseTSTypeAnnotation(false);
}
super.parseFunctionBody(node, isArrowFunction);
}
parseParenAndDistinguishExpression(canBeArrow) {
const startPos = this.start;
const startLoc = this.startLoc;
const allowTrailingComma = this.options.ecmaVersion >= 8;
let val;
if (this.options.ecmaVersion >= 6) {
this.next();
const innerStartPos = this.start, innerStartLoc = this.startLoc;
const exprList = [];
let first = true, lastIsComma = false;
const refDestructuringErrors = new DestructuringErrors(), oldYieldPos = this.yieldPos, oldAwaitPos = this.awaitPos;
let spreadStart;
this.yieldPos = 0;
this.awaitPos = 0;
// Do not save awaitIdentPos to allow checking awaits nested in parameters
while (this.type !== acorn_1.tokTypes.parenR) {
if (first) {
first = false;
}
else {
this.expect(acorn_1.tokTypes.comma);
}
if (allowTrailingComma && this.afterTrailingComma(acorn_1.tokTypes.parenR, true)) {
lastIsComma = true;
break;
}
else if (this.type === acorn_1.tokTypes.ellipsis) {
spreadStart = this.start;
exprList.push(this.parseParenItem(this.parseRestBinding()));
if (this.type === acorn_1.tokTypes.comma)
this.raise(this.start, 'Comma is not permitted after the rest element');
break;
}
else {
exprList.push(this.parseMaybeAssign(false, refDestructuringErrors, this.parseParenItem));
}
if (this.type === acorn_1.tokTypes.colon) {
this.parseTSTypeAnnotation(); // Part I added
}
}
const innerEndPos = this.start;
const innerEndLoc = this.startLoc;
this.expect(acorn_1.tokTypes.parenR);
if (canBeArrow && !this.canInsertSemicolon()) {
const branch = this._branch();
try {
if (branch.parseTSTypeAnnotation() && branch.eat(acorn_1.tokTypes.arrow)) {
this.parseTSTypeAnnotation(); // throw away type
}
}
catch { }
if (this.eat(acorn_1.tokTypes.arrow)) {
this.checkPatternErrors(refDestructuringErrors, false);
this.checkYieldAwaitInDefaultParams();
this.yieldPos = oldYieldPos;
this.awaitPos = oldAwaitPos;
return this.parseParenArrowList(startPos, startLoc, exprList);
}
}
if (!exprList.length || lastIsComma)
this.unexpected(this.lastTokStart);
if (spreadStart)
this.unexpected(spreadStart);
this.checkExpressionErrors(refDestructuringErrors, true);
this.yieldPos = oldYieldPos || this.yieldPos;
this.awaitPos = oldAwaitPos || this.awaitPos;
if (exprList.length > 1) {
val = this.startNodeAt(innerStartPos, innerStartLoc);
val.expressions = exprList;
this.finishNodeAt(val, 'SequenceExpression', innerEndPos, innerEndLoc);
}
else {
val = exprList[0];
}
}
else {
val = this.parseParenExpression();
}
if (this.options.preserveParens) {
const par = this.startNodeAt(startPos, startLoc);
par.expression = val;
return this.finishNode(par, 'ParenthesizedExpression');
}
else {
return val;
}
}
// Fix ambiguity between BinaryExpressions and TSCallExpressions
parseSubscript(base) {
const branch = this._branch();
if (this._isStartOfTypeParameters()) {
// <
try {
// will throw if no matching >
const typeParameters = branch.parseTSTypeParameterInstantiation();
if (typeParameters && branch.eat(acorn_1.tokTypes.parenL)) {
// Update parser to match branch
base.typeParameters = this.parseTSTypeParameterInstantiation();
}
}
catch { }
}
return super.parseSubscript.apply(this, arguments);
}
parseExpression() {
const parenthesized = this.type === acorn_1.tokTypes.parenL, parenStart = parenthesized ? this.start : -1;
let expr = super.parseExpression();
if (parenthesized) {
expr.extra = { parenthesized, parenStart };
return expr;
}
expr = this._parseMaybeTSExpression(expr);
return expr;
}
parseParenItem(item) {
item = super.parseParenItem(item);
item = this._parseMaybeTSExpression(item);
return item;
}
parseTSTypeAnnotation(eatColon = true) {
if (eatColon) {
this.expect(acorn_1.tokTypes.colon);
}
const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc);
this._parseTSTypeAnnotation(node);
return this.finishNode(node, 'TSTypeAnnotation');
}
_parseTSType() {
const node = this._parseNonConditionalType();
if (this.type === acorn_1.tokTypes._extends && !this._hasPrecedingLineBreak()) {
return this.parseTSConditionalType(node);
}
return node;
}
_parseTSTypeAnnotation(node) {
node.typeAnnotation = this._parseTSType();
}
_parsePrimaryType() {
let node;
switch (this.type) {
case acorn_1.tokTypes.name:
node =
this.value in tsPredefinedType
? this.parseTSPredefinedType()
: this.parseTSTypeReference();
break;
case acorn_1.tokTypes.braceL:
node = this.parseTSTypeLiteral();
break;
case acorn_1.tokTypes._void:
case acorn_1.tokTypes._null:
node = this.parseTSPredefinedType();
break;
case acorn_1.tokTypes.parenL:
node = this.parseTSParenthesizedType();
break;
case acorn_1.tokTypes.bracketL:
node = this.parseTSTupleType();
break;
case acorn_1.tokTypes.num:
case acorn_1.tokTypes.string:
case acorn_1.tokTypes._true:
case acorn_1.tokTypes._false:
node = this.parseTSLiteralType(this.type);
break;
case acorn_1.tokTypes._import:
node = this.parseTSImportType(false);
break;
default:
return;
}
while (this.type === acorn_1.tokTypes.bracketL) {
node = this._parseMaybeTSArrayType(node);
}
return node;
}
_parseNonConditionalType() {
let node;
switch (this.type) {
case acorn_1.tokTypes.name:
switch (tsTypeOperator[this.value]) {
case tsTypeOperator.infer:
node = this.parseTSInferType();
break;
case tsTypeOperator.keyof:
node = this.parseTSKeyofType();
break;
default:
node = this._parseTSUnionTypeOrIntersectionType();
}
break;
case acorn_1.tokTypes._new:
node = this.parseTSConstructorType();
break;
case acorn_1.tokTypes.parenL:
const recover = this.tsPreparePreview();
const isStartOfTSFunctionType = this._isStartOfTSFunctionType();
recover();
node = isStartOfTSFunctionType
? this.parseTSFunctionType()
: this.parseTSParenthesizedType();
break;
case acorn_1.tokTypes.relational:
node = this._isStartOfTypeParameters() ? this.parseTSFunctionType() : this.unexpected();
break;
case acorn_1.tokTypes._typeof:
node = this.parseTSTypeofType();
break;
default:
node = this._parseTSUnionTypeOrIntersectionType();
break;
}
return node || this.unexpected();
}
_parseTSDeclaration(node, expr) {
const val = tsDeclaration[expr.name];
switch (val) {
case tsDeclaration.interface:
if (this.type === acorn_1.tokTypes.name) {
return this.parseTSInterfaceDeclaration();
}
break;
case tsDeclaration.type:
if (this.type === acorn_1.tokTypes.name) {
return this.parseTSTypeAliasDeclaration();
}
break;
default:
break;
}
return super.parseExpressionStatement(node, expr);
}
parseTSTypeReference() {
const node = this.startNode();
let typeName = this.parseIdent();
if (this.type === acorn_1.tokTypes.dot) {
typeName = this.parseTSQualifiedName(typeName);
}
node.typeName = typeName;
if (this._isStartOfTypeParameters()) {
node.typeParameters = this.parseTSTypeParameterInstantiation();
}
this.finishNode(node, 'TSTypeReference');
return node;
}
parseTSPredefinedType() {
const node = this.startNode();
const keyword = this.value;
this.next();
this.finishNode(node, tsPredefinedType[keyword]);
return node;
}
parseTSLiteralType(tokType) {
const node = this.startNode();
const literal = this.parseLiteral(this.value);
if (tokType === acorn_1.tokTypes._true || tokType === acorn_1.tokTypes._false) {
literal.value = tokType === acorn_1.tokTypes._true;
}
node.literal = literal;
return this.finishNode(node, 'TSLiteralType');
}
parseTSTupleType() {
const node = this.startNode();
const elementTypes = [];
this.eat(acorn_1.tokTypes.bracketL);
let first = true;
while (!this.eat(acorn_1.tokTypes.bracketR)) {
if (first) {
first = false;
}
else {
this.expect(acorn_1.tokTypes.comma);
}
switch (this.type) {
case acorn_1.tokTypes.name:
const elem = this.parseTSTypeReference();
if (this.type === acorn_1.tokTypes.question) {
elementTypes.push(this.parseTSOptionalType(elem));
}
else {
elementTypes.push(elem);
}
break;
case acorn_1.tokTypes.ellipsis:
elementTypes.push(this.parseTSRestType());
break;
case acorn_1.tokTypes.bracketR:
break;
default:
this.unexpected();
}
}
node.elementTypes = elementTypes;
return this.finishNode(node, 'TSTupleType');
}
parseTSOptionalType(typeRef) {
const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc);
this.expect(acorn_1.tokTypes.question);
node.typeAnnotation = typeRef;
return this.finishNode(node, 'TSOptionalType');
}
parseTSRestType() {
const node = this.startNode();
this.expect(acorn_1.tokTypes.ellipsis);
this._parseTSTypeAnnotation(node);
return this.finishNode(node, 'TSRestType');
}
_parseMaybeTSArrayType(prev) {
const node = this.startNodeAtNode(prev);
this.expect(acorn_1.tokTypes.bracketL);
if (this.eat(acorn_1.tokTypes.bracketR)) {
return this.parseTSArrayType(node, prev);
}
return this.parseTSIndexedAccessType(node, prev);
}
parseTSArrayType(node, elementType) {
node.elementType = elementType;
return this.finishNode(node, 'TSArrayType');
}
parseTSIndexedAccessType(node, objectType) {
node.objectType = objectType;
node.indexType = this._parseTSType();
this.expect(acorn_1.tokTypes.bracketR);
if (this.type === acorn_1.tokTypes.bracketL) {
return this._parseMaybeTSArrayType(node);
}
return this.finishNode(node, 'TSIndexedAccessType');
}
_isStartOfTSFunctionType() {
this.nextToken();
switch (this.type) {
case acorn_1.tokTypes.parenR:
case acorn_1.tokTypes.ellipsis:
return true;
case acorn_1.tokTypes.name:
case acorn_1.tokTypes._this:
this.nextToken();
switch (this.type) {
case acorn_1.tokTypes.colon:
case acorn_1.tokTypes.comma:
case acorn_1.tokTypes.question:
return true;
case acorn_1.tokTypes.parenR:
this.nextToken();
return this.type === acorn_1.tokTypes.arrow;
default:
return false;
}
case acorn_1.tokTypes.braceL:
case acorn_1.tokTypes.bracketL: {
if (this.type === acorn_1.tokTypes.braceL) {
this.parseObj(/* isPattern */ true);
}
else {
this.parseBindingAtom();
}
switch (this.type) {
case acorn_1.tokTypes.colon:
case acorn_1.tokTypes.comma:
case acorn_1.tokTypes.question:
return true;
case acorn_1.tokTypes.parenR:
this.nextToken();
return this.type === acorn_1.tokTypes.arrow;
default:
return false;
}
}
default:
return false;
}
}
parseTSFunctionType() {
const node = this.startNode();
const temp = Object.create(null);
node.typeParameters = this.parseMaybeTSTypeParameterDeclaration();
this.parseFunctionParams(temp);
node.parameters = temp.params;
this.expect(acorn_1.tokTypes.arrow);
node.typeAnnotation = this.parseTSTypeAnnotation(false);
return this.finishNode(node, 'TSFunctionType');
}
parseTSParenthesizedType() {
const node = this.startNode();
this.expect(acorn_1.tokTypes.parenL);
this._parseTSTypeAnnotation(node);
this.expect(acorn_1.tokTypes.parenR);
while (this.eat(acorn_1.tokTypes.bracketL)) {
this.expect(acorn_1.tokTypes.bracketR);
}
return this.finishNode(node, 'TSParenthesizedType');
}
parseTSUnionType(first) {
const node = first ? this.startNodeAtNode(first) : this.startNode();
const types = [];
if (first)
types.push(first);
while (this.eat(acorn_1.tokTypes.bitwiseOR)) {
types.push(this._parseTSIntersectionTypeOrPrimaryType());
}
if (types.length === 1) {
return first;
}
node.types = types;
return this.finishNode(node, 'TSUnionType');
}
parseTSIntersectionType(first) {
const node = first ? this.startNodeAtNode(first) : this.startNode();
const types = [];
if (first)
types.push(first);
while (this.eat(acorn_1.tokTypes.bitwiseAND)) {
types.push(this._parsePrimaryType());
}
if (types.length === 1) {
return first;
}
node.types = types;
return this.finishNode(node, 'TSIntersectionType');
}
_parseTSIntersectionTypeOrPrimaryType() {
this.eat(acorn_1.tokTypes.bitwiseAND);
const node = this._parsePrimaryType();
if (this.type === acorn_1.tokTypes.bitwiseAND) {
return this.parseTSIntersectionType(node);
}
return node;
}
_parseTSUnionTypeOrIntersectionType() {
this.eat(acorn_1.tokTypes.bitwiseOR);
const node = this._parseTSIntersectionTypeOrPrimaryType();
if (this.type === acorn_1.tokTypes.bitwiseOR) {
return this.parseTSUnionType(node);
}
return node;
}
parseTSConditionalType(checkType) {
const node = this.startNodeAtNode(checkType);
node.checkType = checkType;
this.expect(acorn_1.tokTypes._extends);
node.extendsType = this._parseNonConditionalType();
this.expect(acorn_1.tokTypes.question);
node.trueType = this._parseNonConditionalType();
this.expect(acorn_1.tokTypes.colon);
node.falseType = this._parseNonConditionalType();
return this.finishNode(node, 'TSConditionalType');
}
parseTSInferType() {
const node = this.startNode();
this.next();
node.typeParameter = this.parseTSTypeParameter();
return this.finishNode(node, 'TSInferType');
}
parseTSKeyofType() {
const node = this.startNode();
this.next();
node.typeAnnotation = this.parseTSTypeAnnotation(false);
return this.finishNode(node, 'TSTypeOperator');
}
parseTSTypeQuery() {
const node = this.startNode();
this.next();
node.exprName = this.parseIdent();
return this.finishNode(node, 'TSTypeQuery');
}
parseTSTypeofType() {
const typeQuery = this.parseTSTypeQuery();
if (this.eat(acorn_1.tokTypes.bracketL)) {
const node = this.startNode();
return this.parseTSIndexedAccessType(node, typeQuery);
}
return typeQuery;
}
parseTSImportType(isTypeOf) {
const node = this.startNode();
node.isTypeOf = isTypeOf;
this.expect(acorn_1.tokTypes._import);
this.expect(acorn_1.tokTypes.parenL);
node.parameter = this.parseTSLiteralType(this.type);
this.expect(acorn_1.tokTypes.parenR);
if (this.eat(acorn_1.tokTypes.dot)) {
let qualifier = this.parseIdent();
if (this.type === acorn_1.tokTypes.dot) {
qualifier = this.parseTSQualifiedName(qualifier);
}
node.qualifier = qualifier;
}
return this.finishNode(node, 'TSImportType');
}
parseTSQualifiedName(left) {
let node = this.startNodeAtNode(left);
node.left = left;
this.expect(acorn_1.tokTypes.dot);
node.right = this.parseIdent();
node = this.finishNode(node, 'TSQualifiedName');
if (this.type === acorn_1.tokTypes.dot) {
node = this.parseTSQualifiedName(node);
}
return node;
}
parseTSConstructorType() {
const node = this.startNode();
this.expect(acorn_1.tokTypes._new);
node.typeParameters = this.parseMaybeTSTypeParameterDeclaration();
this.expect(acorn_1.tokTypes.parenL);
node.parameters = this.parseBindingList(acorn_1.tokTypes.parenR, false, this.options.ecmaVersion >= 8);
this.expect(acorn_1.tokTypes.arrow);
node.typeAnnotation = this.parseTSTypeAnnotation(false);
return this.finishNode(node, 'TSConstructorType');
}
parseTSConstructSignatureDeclaration() {
const node = this.startNode();
this.expect(acorn_1.tokTypes._new);
node.typeParameters = this.parseMaybeTSTypeParameterDeclaration();
this.expect(acorn_1.tokTypes.parenL);
node.parameters = this.parseBindingList(acorn_1.tokTypes.parenR, false, this.options.ecmaVersion >= 8);
if (this.eat(acorn_1.tokTypes.colon)) {
node.typeAnnotation = this.parseTSTypeAnnotation(false);
}
return this.finishNode(node, 'TSConstructSignatureDeclaration');
}
parseTSTypeLiteral() {
return this._parseObjectLikeType('TSTypeLiteral', 'members');
}
parseTSTypeAliasDeclaration() {
const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc);
node.id = this.parseIdent();
node.typeParameters = this.parseMaybeTSTypeParameterDeclaration();
this.expect(acorn_1.tokTypes.eq);
this._parseTSTypeAnnotation(node);
this.semicolon();
return this.finishNode(node, 'TSTypeAliasDeclaration');
}
parseTSInterfaceDeclaration() {
const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc);
node.id = this.parseIdent();
node.typeParameters = this.parseMaybeTSTypeParameterDeclaration();
if (this.eat(acorn_1.tokTypes._extends)) {
const heritage = [];
do {
heritage.push(this.parseTSExpressionWithTypeArguments());
} while (this.eat(acorn_1.tokTypes.comma));
node.heritage = heritage;
}
node.body = this._parseObjectLikeType('TSInterfaceBody', 'body');
this.semicolon();
return this.finishNode(node, 'TSInterfaceDeclaration');
}
parseTSExpressionWithTypeArguments() {
const node = this.startNode();
let expr = this.parseIdent();
if (this.eat(acorn_1.tokTypes.dot)) {
expr = this.parseTSQualifiedName(expr);
}
node.expr = expr;
if (this._isStartOfTypeParameters()) {
const typeParameters = this.parseTSTypeParameterInstantiation();
node.typeParameters = typeParameters;
node.end = typeParameters.end;
if (this.options.locations) {
node.loc.end = typeParameters.loc.end;
}
}
return this.finishNode(node, 'TSExpressionWithTypeArguments');
}
parseTSTypeParameter() {
const node = this.startNode();
if (this.type === acorn_1.tokTypes.name) {
node.name = this.value;
this.next();
}
else {
this.unexpected();
}
if (this.eat(acorn_1.tokTypes._extends)) {
node.constraint = this._parseTSType();
}
if (this.eat(acorn_1.tokTypes.eq)) {
node.default = this._parseTSType();
}
return this.finishNode(node, 'TSTypeParameter');
}
parseMaybeTSTypeParameterDeclaration() {
if (this._isStartOfTypeParameters()) {
const node = this.startNode();
const params = [];
let first = true;
this.next();
while (!this.eat(acorn_1.tokTypes.relational)) {
if (first) {
first = false;
}
else {
this.expect(acorn_1.tokTypes.comma);
}
if (this._isEndOfTypeParameters()) {
break;
}
params.push(this.parseTSTypeParameter());
}
node.params = params;
return this.finishNode(node, 'TSTypeParameterDeclaration');
}
}
parseTSTypeParameterInstantiation() {
const node = this.startNode();
const params = [];
this.next(); // <
let first = true;
while ((this.value && !this._isEndOfTypeParameters()) || this.type === acorn_1.tokTypes.comma) {
if (first) {
first = false;
}
else {
this.expect(acorn_1.tokTypes.comma);
}
params.push(this._parseTSType());
}
if (this._isEndOfTypeParameters()) {
if (this.value.length > 1) {
this.value = this.value.slice(1); // Fix to allow chaining of type parameters
}
else {
this.next(); // >
}
}
node.params = params;
return this.finishNode(node, 'TSTypeParameterInstantiation');
}
parseMaybeTSTypeParameterInstantiation() {
if (this._isStartOfTypeParameters()) {
return this.parseTSTypeParameterInstantiation();
}
}
_parseObjectLikeType(kind, prop) {
const node = this.startNode();
this.expect(acorn_1.tokTypes.braceL);
const list = [];
while (!this.eat(acorn_1.tokTypes.braceR)) {
switch (this.type) {
case acorn_1.tokTypes.name:
const key = this.parseIdent();
switch (this.type) {
case acorn_1.tokTypes.parenL:
case acorn_1.tokTypes.relational:
list.push(this.parseTSMethodSignature(key));
break;
case acorn_1.tokTypes.colon:
case acorn_1.tokTypes.semi:
case acorn_1.tokTypes.comma:
case acorn_1.tokTypes.braceR:
case acorn_1.tokTypes.question:
list.push(this.parseTSPropertySignature(key));
break;
default:
if (this._hasPrecedingLineBreak()) {
list.push(this.parseTSPropertySignature(key));
continue;
}
this.unexpected();
}
break;
case acorn_1.tokTypes.bracketL:
const recover = this.tsPreparePreview();
this.nextToken();
if (this.type === acorn_1.tokTypes.name) {
this.nextToken();
switch (this.type) {
case acorn_1.tokTypes.colon:
recover();
list.push(this.parseTSIndexSignature());
break;
case acorn_1.tokTypes._in:
if (list.length === 0) {
recover();
return this.parseTSMappedType();
}
else {
recover();
list.push(this.parseTSPropertySignature(null, true));
}
break;
default:
recover();
list.push(this.parseTSPropertySignature(null, true));
}
}
else {
recover();
list.push(this.parseTSPropertySignature(null, true));
}
break;
case acorn_1.tokTypes._new:
list.push(this.parseTSConstructSignatureDeclaration());
break;
default:
this.unexpected();
}
}
node[prop] = list;
return this.finishNode(node, kind);
}
parseTSMethodSignature(key) {
const node = this.startNodeAtNode(key);
node.key = key;
if (this.eat(acorn_1.tokTypes.question)) {
node.optional = true;
}
node.typeParameters = this.parseMaybeTSTypeParameterDeclaration();
this.expect(acorn_1.tokTypes.parenL);
node.parameters = this.parseBindingList(acorn_1.tokTypes.parenR, false, this.options.ecmaVersion >= 8);
if (this.type === acorn_1.tokTypes.colon) {
node.typeAnnotation = this.parseTSTypeAnnotation(true);
}
if (!this.eat(acorn_1.tokTypes.comma))
this.eat(acorn_1.tokTypes.semi);
return this.finishNode(node, 'TSMethodSignature');
}
parseTSPropertySignature(key, computed = false) {
let node;
if (computed) {
node = this.startNode();
this.expect(acorn_1.tokTypes.bracketL);
node.key = this.parseExpression();
this.expect(acorn_1.tokTypes.bracketR);
}
else {
node = this.startNodeAtNode(key);
node.key = key;
}
node.computed = computed;
if (this.eat(acorn_1.tokTypes.question)) {
node.optional = true;
}
if (this.type === acorn_1.tokTypes.colon) {
node.typeAnnotation = this.parseTSTypeAnnotation(true);
}
if (!this.eat(acorn_1.tokTypes.comma))
this.eat(acorn_1.tokTypes.semi);
return this.finishNode(node, 'TSPropertySignature');
}
parseTSIndexSignature() {
const node = this.startNode();
this.expect(acorn_1.tokTypes.bracketL);
const index = this.parseIdent();
index.typeAnnotation = this.parseTSTypeAnnotation(true);
index.end = index.typeAnnotation.end;
if (this.options.locations) {
index.loc.end = index.typeAnnotation.loc.end;
}
node.index = index;
this.expect(acorn_1.tokTypes.bracketR);
node.typeAnnotation = this.parseTSTypeAnnotation(true);
if (!this.eat(acorn_1.tokTypes.comma))
this.eat(acorn_1.tokTypes.semi);
return this.finishNode(node, 'TSIndexSignature');
}
parseTSMappedType() {
const node = this.startNodeAt(this.lastTokStart, this.lastTokStartLoc);
this.expect(acorn_1.tokTypes.bracketL);
node.typeParameter = this._parseTSTypeParameterInTSMappedType();
this.expect(acorn_1.tokTypes.bracketR);
if (this.eat(acorn_1.tokTypes.question)) {
node.optional = true;
}
if (this.type === acorn_1.tokTypes.colon) {
node.typeAnnotation = this.parseTSTypeAnnotation(true);
}
this.semicolon();
this.expect(acorn_1.tokTypes.braceR);
return this.finishNode(node, 'TSMappedType');
}
_parseTSTypeParameterInTSMappedType() {
const node = this.startNode();
if (this.type === acorn_1.tokTypes.name) {
node.name = this.value;
this.next();
}
else {
this.unexpected();
}
this.expect(acorn_1.tokTypes._in);
node.constraint = this._parseNonConditionalType();
return this.finishNode(node, 'TSTypeParameter');
}
_parseMaybeTSExpression(node) {
if (this.type === acorn_1.tokTypes.prefix && tsExprMarkup[this.value] === tsExprMarkup['!']) {
node = this.parseTSNonNullExpression(node);
}
if (this.type === acorn_1.tokTypes.name && tsExprMarkup[this.value] === tsExprMarkup.as) {
node = this.parseTSAsExpression(node);
}
return node;
}
parseTSAsExpression(expression) {
let node = expression;
while (this.type === acorn_1.tokTypes.name && tsExprMarkup[this.value] === tsExprMarkup.as) {
const _node = this.startNodeAtNode(node);
this.next();
_node.expression = node;
this._parseTSTypeAnnotation(_node);
node = this.finishNode(_node, 'TSAsExpression');
}
return expression;
}
parseTSNonNullExpression(expression) {
let node = expression;
while (this.type === acorn_1.tokTypes.prefix && tsExprMarkup[this.value] === tsExprMarkup['!']) {
const _node = this.startNodeAtNode(node);
_node.expression = node;
this.next();
node = this.finishNode(_node, 'TSNonNullExpression');
}
return node;
}
};
};
// acorn-class-fields plugin is needed, else parsing of some function types will not work
// eslint-disable-next-line @typescript-eslint/no-require-imports
const TypeParser = acorn_1.Parser.extend(tsPlugin, require('acorn-class-fields'));
exports.default = TypeParser;
//# sourceMappingURL=typeParser.js.map