diff --git a/packages/typescript-estree/src/ast-converter.ts b/packages/typescript-estree/src/ast-converter.ts index 13d2212c5c4f..131539a981b8 100644 --- a/packages/typescript-estree/src/ast-converter.ts +++ b/packages/typescript-estree/src/ast-converter.ts @@ -5,11 +5,11 @@ * @copyright jQuery Foundation and other contributors, https://jquery.org/ * MIT License */ -import convert, { getASTMaps, resetASTMaps, convertError } from './convert'; +import { convertError, Converter } from './convert'; import { convertComments } from './convert-comments'; import { convertTokens } from './node-utils'; import ts from 'typescript'; -import { Extra } from './temp-types-based-on-js-source'; +import { Extra } from './parser-options'; export default function astConverter( ast: ts.SourceFile, @@ -27,17 +27,14 @@ export default function astConverter( /** * Recursively convert the TypeScript AST into an ESTree-compatible AST */ - const estree: any = convert({ - node: ast, - parent: null, - ast, - additionalOptions: { - errorOnUnknownASTType: extra.errorOnUnknownASTType || false, - useJSXTextNode: extra.useJSXTextNode || false, - shouldProvideParserServices - } + const instance = new Converter(ast, { + errorOnUnknownASTType: extra.errorOnUnknownASTType || false, + useJSXTextNode: extra.useJSXTextNode || false, + shouldProvideParserServices }); + const estree = instance.convertProgram(); + /** * Optionally convert and include all tokens in the AST */ @@ -52,11 +49,9 @@ export default function astConverter( estree.comments = convertComments(ast, extra.code); } - let astMaps = undefined; - if (shouldProvideParserServices) { - astMaps = getASTMaps(); - resetASTMaps(); - } + const astMaps = shouldProvideParserServices + ? instance.getASTMaps() + : undefined; return { estree, astMaps }; } diff --git a/packages/typescript-estree/src/convert-comments.ts b/packages/typescript-estree/src/convert-comments.ts index ac7f8504d8aa..59a2326122c8 100644 --- a/packages/typescript-estree/src/convert-comments.ts +++ b/packages/typescript-estree/src/convert-comments.ts @@ -7,31 +7,28 @@ import ts from 'typescript'; import { getLocFor, getNodeContainer } from './node-utils'; -import { - ESTreeComment, - LineAndColumnData -} from './temp-types-based-on-js-source'; +import * as es from './typedefs'; /** * Converts a TypeScript comment to an Esprima comment. - * @param {boolean} block True if it's a block comment, false if not. - * @param {string} text The text of the comment. - * @param {number} start The index at which the comment starts. - * @param {number} end The index at which the comment ends. - * @param {LineAndColumnData} startLoc The location at which the comment starts. - * @param {LineAndColumnData} endLoc The location at which the comment ends. - * @returns {Object} The comment object. - * @private + * @param block True if it's a block comment, false if not. + * @param text The text of the comment. + * @param start The index at which the comment starts. + * @param end The index at which the comment ends. + * @param startLoc The location at which the comment starts. + * @param endLoc The location at which the comment ends. + * @returns The comment object. + * @internal */ function convertTypeScriptCommentToEsprimaComment( block: boolean, text: string, start: number, end: number, - startLoc: LineAndColumnData, - endLoc: LineAndColumnData -): ESTreeComment { - const comment: ESTreeComment = { + startLoc: es.LineAndColumnData, + endLoc: es.LineAndColumnData +): es.Comment { + const comment: es.OptionalRangeAndLoc = { type: block ? 'Block' : 'Line', value: text }; @@ -47,22 +44,22 @@ function convertTypeScriptCommentToEsprimaComment( }; } - return comment; + return comment as es.Comment; } /** * Convert comment from TypeScript Triva Scanner. - * @param {ts.Scanner} triviaScanner TS Scanner - * @param {ts.SourceFile} ast the AST object - * @param {string} code TypeScript code - * @returns {ESTreeComment} the converted ESTreeComment + * @param triviaScanner TS Scanner + * @param ast the AST object + * @param code TypeScript code + * @returns the converted Comment * @private */ function getCommentFromTriviaScanner( triviaScanner: ts.Scanner, ast: ts.SourceFile, code: string -): ESTreeComment { +): es.Comment { const kind = triviaScanner.getToken(); const isBlock = kind === ts.SyntaxKind.MultiLineCommentTrivia; const range = { @@ -77,7 +74,7 @@ function getCommentFromTriviaScanner( : comment.replace(/^\/\//, ''); const loc = getLocFor(range.pos, range.end, ast); - const esprimaComment = convertTypeScriptCommentToEsprimaComment( + return convertTypeScriptCommentToEsprimaComment( isBlock, text, range.pos, @@ -85,22 +82,20 @@ function getCommentFromTriviaScanner( loc.start, loc.end ); - - return esprimaComment; } /** * Convert all comments for the given AST. - * @param {ts.SourceFile} ast the AST object - * @param {string} code the TypeScript code - * @returns {ESTreeComment[]} the converted ESTreeComment + * @param ast the AST object + * @param code the TypeScript code + * @returns the converted ESTreeComment * @private */ export function convertComments( ast: ts.SourceFile, code: string -): ESTreeComment[] { - const comments: ESTreeComment[] = []; +): es.Comment[] { + const comments: es.Comment[] = []; /** * Create a TypeScript Scanner, with skipTrivia set to false so that diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 9a7adebc8e2e..8e2d6a876a15 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -6,65 +6,44 @@ * MIT License */ import ts from 'typescript'; +import * as es from './typedefs'; import { canContainDirective, + convertToken, createError, - getLoc, - getLocFor, findNextToken, - convertToken, - hasModifier, fixExports, - getTSNodeAccessibility, + getBinaryExpressionType, + getDeclarationKind, + getLastModifier, + getLineAndCharacterFor, + getLocFor, + getRange, getTextForTokenKind, - isJSXToken, + getTSNodeAccessibility, + hasModifier, + isComma, isComputedProperty, isESTreeClassMember, - isComma, - getBinaryExpressionType, + isJSXToken, isOptional, - unescapeStringLiteralText, - getDeclarationKind, - getLastModifier, - getLineAndCharacterFor + unescapeStringLiteralText } from './node-utils'; import { AST_NODE_TYPES } from './ast-node-types'; -import { ESTreeNode } from './temp-types-based-on-js-source'; import { TSNode } from './ts-nodes'; const SyntaxKind = ts.SyntaxKind; -let esTreeNodeToTSNodeMap = new WeakMap(); -let tsNodeToESTreeNodeMap = new WeakMap(); - -export function resetASTMaps() { - esTreeNodeToTSNodeMap = new WeakMap(); - tsNodeToESTreeNodeMap = new WeakMap(); -} - -export function getASTMaps() { - return { esTreeNodeToTSNodeMap, tsNodeToESTreeNodeMap }; -} - -interface ConvertAdditionalOptions { +interface ConverterOptions { errorOnUnknownASTType: boolean; useJSXTextNode: boolean; shouldProvideParserServices: boolean; } -interface ConvertConfig { - node: ts.Node; - parent?: ts.Node | null; - inTypeMode?: boolean; - allowPattern?: boolean; - ast: ts.SourceFile; - additionalOptions: ConvertAdditionalOptions; -} - /** * Extends and formats a given error object - * @param {Object} error the error object - * @returns {Object} converted error object + * @param error the error object + * @returns converted error object */ export function convertError(error: any) { return createError( @@ -74,121 +53,171 @@ export function convertError(error: any) { ); } -/** - * Converts a TypeScript node into an ESTree node - * @param {Object} config configuration options for the conversion - * @param {TSNode} config.node the ts.Node - * @param {ts.Node} config.parent the parent ts.Node - * @param {ts.SourceFile} config.ast the full TypeScript AST - * @param {Object} config.additionalOptions additional options for the conversion - * @returns {ESTreeNode|null} the converted ESTreeNode - */ -export default function convert(config: ConvertConfig): ESTreeNode | null { - const node: TSNode = config.node as TSNode; - const parent = config.parent; - const ast = config.ast; - const additionalOptions = config.additionalOptions || {}; +export class Converter { + private readonly ast: ts.SourceFile; + private options: ConverterOptions; + private esTreeNodeToTSNodeMap = new WeakMap(); + private tsNodeToESTreeNodeMap = new WeakMap(); + + private allowPattern: boolean = false; + private inTypeMode: boolean = false; /** - * Exit early for null and undefined + * Converts a TypeScript node into an ESTree node + * @param ast the full TypeScript AST + * @param options additional options for the conversion + * @returns the converted ESTreeNode */ - if (!node) { - return null; + constructor(ast: ts.SourceFile, options: ConverterOptions) { + this.ast = ast; + this.options = options; + } + + getASTMaps() { + return { + esTreeNodeToTSNodeMap: this.esTreeNodeToTSNodeMap, + tsNodeToESTreeNodeMap: this.tsNodeToESTreeNodeMap + }; + } + + convertProgram(): es.Program { + return this.converter(this.ast) as es.Program; } /** - * Create a new ESTree node + * Converts a TypeScript node into an ESTree node. + * @param node the child ts.Node + * @param parent parentNode + * @param inTypeMode flag to determine if we are in typeMode + * @param allowPattern flag to determine if patterns are allowed + * @returns the converted ESTree node */ - let result: ESTreeNode = { - type: '' as AST_NODE_TYPES, - range: [node.getStart(ast), node.end], - loc: getLoc(node, ast) - }; - - function converter( - child?: ts.Node, + private converter( + node?: ts.Node, + parent?: ts.Node, inTypeMode?: boolean, allowPattern?: boolean - ): ESTreeNode | null { - if (!child) { + ): any { + /** + * Exit early for null and undefined + */ + if (!node) { return null; } - return convert({ - node: child, - parent: node, - inTypeMode, - allowPattern, - ast, - additionalOptions - }); + + const typeMode = this.inTypeMode; + const pattern = this.allowPattern; + if (inTypeMode !== undefined) { + this.inTypeMode = inTypeMode; + } + if (allowPattern !== undefined) { + this.allowPattern = allowPattern; + } + + let result: es.BaseNode | null = this.convertNode( + node as TSNode, + parent || node.parent + ); + + if (result && this.options.shouldProvideParserServices) { + this.tsNodeToESTreeNodeMap.set(node, result); + this.esTreeNodeToTSNodeMap.set(result, node); + } + + this.inTypeMode = typeMode; + this.allowPattern = pattern; + return result; } /** * Converts a TypeScript node into an ESTree node. - * @param {ts.Node} child the child ts.Node - * @returns {ESTreeNode|null} the converted ESTree node + * @param child the child ts.Node + * @param parent parentNode + * @returns the converted ESTree node */ - function convertPattern(child?: ts.Node): ESTreeNode | null { - return converter(child, config.inTypeMode, true); + private convertPattern(child?: ts.Node, parent?: ts.Node): any | null { + return this.converter(child, parent, this.inTypeMode, true); } /** * Converts a TypeScript node into an ESTree node. - * @param {ts.Node} child the child ts.Node - * @returns {ESTreeNode|null} the converted ESTree node + * @param child the child ts.Node + * @param parent parentNode + * @returns the converted ESTree node */ - function convertChild(child?: ts.Node): ESTreeNode | null { - return converter(child, config.inTypeMode, false); + private convertChild(child?: ts.Node, parent?: ts.Node): any | null { + return this.converter(child, parent, this.inTypeMode, false); } /** * Converts a TypeScript node into an ESTree node. - * @param {ts.Node} child the child ts.Node - * @returns {ESTreeNode|null} the converted ESTree node + * @param child the child ts.Node + * @param parent parentNode + * @returns the converted ESTree node */ - function convertChildType(child?: ts.Node): ESTreeNode | null { - return converter(child, true, false); + private convertType(child?: ts.Node, parent?: ts.Node): any | null { + return this.converter(child, parent, true, false); + } + + private createNode( + node: ts.Node, + data: es.OptionalRangeAndLoc + ): T { + const result = data; + if (!result.range) { + result.range = getRange(node, this.ast); + } + if (!result.loc) { + result.loc = getLocFor(result.range[0], result.range[1], this.ast); + } + + return result as T; } /** * Converts a child into a type annotation. This creates an intermediary * TypeAnnotation node to match what Flow does. - * @param {ts.TypeNode} child The TypeScript AST node to convert. - * @returns {ESTreeNode} The type annotation node. + * @param child The TypeScript AST node to convert. + * @param parent parentNode + * @returns The type annotation node. */ - function convertTypeAnnotation(child: ts.TypeNode): ESTreeNode { - const annotation = convertChildType(child); + private convertTypeAnnotation( + child: ts.TypeNode, + parent: ts.Node + ): es.TSTypeAnnotation { // in FunctionType and ConstructorType typeAnnotation has 2 characters `=>` and in other places is just colon const offset = - node.kind === SyntaxKind.FunctionType || - node.kind === SyntaxKind.ConstructorType + parent.kind === SyntaxKind.FunctionType || + parent.kind === SyntaxKind.ConstructorType ? 2 : 1; const annotationStartCol = child.getFullStart() - offset; - const loc = getLocFor(annotationStartCol, child.end, ast); + const loc = getLocFor(annotationStartCol, child.end, this.ast); return { type: AST_NODE_TYPES.TSTypeAnnotation, loc, range: [annotationStartCol, child.end], - typeAnnotation: annotation + typeAnnotation: this.convertType(child) }; } /** * Coverts body Nodes and add directive field to StringLiterals - * @param {ts.NodeArray} nodes of ts.Node - * @returns {ESTreeNode[]} Array of body statements + * @param nodes of ts.Node + * @param parent parentNode + * @returns Array of body statements */ - function convertBodyExpressions( - nodes: ts.NodeArray - ): ESTreeNode[] { - let allowDirectives = canContainDirective(node); + private convertBodyExpressions( + nodes: ts.NodeArray, + parent: ts.Node + ): any[] { + let allowDirectives = canContainDirective(parent); return ( nodes .map(statement => { - const child = convertChild(statement); + const child = this.convertChild(statement); if (allowDirectives) { if ( child && @@ -196,14 +225,14 @@ export default function convert(config: ConvertConfig): ESTreeNode | null { ts.isExpressionStatement(statement) && ts.isStringLiteral(statement.expression) ) { - const raw = child.expression.raw!; + const raw = child.expression.raw; child.directive = raw.slice(1, -1); - return child!; // child can be null but it's filtered below + return child; // child can be null but it's filtered below } else { allowDirectives = false; } } - return child!; // child can be null but it's filtered below + return child; // child can be null but it's filtered below }) // filter out unknown nodes for now .filter(statement => statement) @@ -212,58 +241,60 @@ export default function convert(config: ConvertConfig): ESTreeNode | null { /** * Converts a ts.Node's typeArguments to TSTypeParameterInstantiation node - * @param {ts.NodeArray} typeArguments ts.Node typeArguments - * @returns {ESTreeNode} TypeParameterInstantiation node + * @param typeArguments ts.Node typeArguments + * @returns TypeParameterInstantiation node */ - function convertTypeArgumentsToTypeParameters( - typeArguments: ts.NodeArray - ): ESTreeNode { - const greaterThanToken = findNextToken(typeArguments, ast, ast)!; + private convertTypeArgumentsToTypeParameters( + typeArguments: ts.NodeArray + ): es.TSTypeParameterInstantiation { + const greaterThanToken = findNextToken(typeArguments, this.ast, this.ast)!; return { type: AST_NODE_TYPES.TSTypeParameterInstantiation, range: [typeArguments.pos - 1, greaterThanToken.end], - loc: getLocFor(typeArguments.pos - 1, greaterThanToken.end, ast), - params: typeArguments.map(typeArgument => convertChildType(typeArgument)) + loc: getLocFor(typeArguments.pos - 1, greaterThanToken.end, this.ast), + params: typeArguments.map(typeArgument => this.convertType(typeArgument)) }; } /** * Converts a ts.Node's typeParameters to TSTypeParameterDeclaration node - * @param {ts.NodeArray} typeParameters ts.Node typeParameters - * @returns {ESTreeNode} TypeParameterDeclaration node + * @param typeParameters ts.Node typeParameters + * @returns TypeParameterDeclaration node */ - function convertTSTypeParametersToTypeParametersDeclaration( - typeParameters: ts.NodeArray - ): ESTreeNode { - const greaterThanToken = findNextToken(typeParameters, ast, ast)!; + private convertTSTypeParametersToTypeParametersDeclaration( + typeParameters: ts.NodeArray + ): es.TSTypeParameterDeclaration { + const greaterThanToken = findNextToken(typeParameters, this.ast, this.ast)!; return { type: AST_NODE_TYPES.TSTypeParameterDeclaration, range: [typeParameters.pos - 1, greaterThanToken.end], - loc: getLocFor(typeParameters.pos - 1, greaterThanToken.end, ast), + loc: getLocFor(typeParameters.pos - 1, greaterThanToken.end, this.ast), params: typeParameters.map(typeParameter => - convertChildType(typeParameter) + this.convertType(typeParameter) ) }; } /** * Converts an array of ts.Node parameters into an array of ESTreeNode params - * @param {ts.Node[]} parameters An array of ts.Node params to be converted - * @returns {ESTreeNode[]} an array of converted ESTreeNode params + * @param parameters An array of ts.Node params to be converted + * @returns an array of converted ESTreeNode params */ - function convertParameters(parameters: ts.NodeArray): ESTreeNode[] { + private convertParameters( + parameters: ts.NodeArray + ): (es.TSParameterProperty | es.RestElement | es.AssignmentPattern)[] { if (!parameters || !parameters.length) { return []; } return parameters.map(param => { - const convertedParam = convertChild(param)!; + const convertedParam = this.convertChild(param); if (!param.decorators || !param.decorators.length) { return convertedParam; } return Object.assign(convertedParam, { - decorators: param.decorators.map(convertChild) + decorators: param.decorators.map(el => this.convertChild(el)) }); }); } @@ -272,21 +303,20 @@ export default function convert(config: ConvertConfig): ESTreeNode | null { * For nodes that are copied directly from the TypeScript AST into * ESTree mostly as-is. The only difference is the addition of a type * property instead of a kind property. Recursively copies all children. - * @returns {void} */ - function deeplyCopy(): void { + private deeplyCopy(node: ts.Node): any { const customType = `TS${SyntaxKind[node.kind]}` as AST_NODE_TYPES; /** * If the "errorOnUnknownASTType" option is set to true, throw an error, * otherwise fallback to just including the unknown type as-is. */ - if ( - additionalOptions.errorOnUnknownASTType && - !AST_NODE_TYPES[customType] - ) { + if (this.options.errorOnUnknownASTType && !AST_NODE_TYPES[customType]) { throw new Error(`Unknown AST_NODE_TYPE: "${customType}"`); } - result.type = customType; + const result = this.createNode(node, { + type: customType + }); + Object.keys(node) .filter( key => @@ -297,83 +327,105 @@ export default function convert(config: ConvertConfig): ESTreeNode | null { .forEach(key => { if (key === 'type') { result.typeAnnotation = (node as any).type - ? convertTypeAnnotation((node as any).type) + ? this.convertTypeAnnotation((node as any).type, node) : null; } else if (key === 'typeArguments') { result.typeParameters = (node as any).typeArguments - ? convertTypeArgumentsToTypeParameters((node as any).typeArguments) + ? this.convertTypeArgumentsToTypeParameters( + (node as any).typeArguments + ) : null; } else if (key === 'typeParameters') { result.typeParameters = (node as any).typeParameters - ? convertTSTypeParametersToTypeParametersDeclaration( + ? this.convertTSTypeParametersToTypeParametersDeclaration( (node as any).typeParameters ) : null; } else if (key === 'decorators') { if (node.decorators && node.decorators.length) { - result.decorators = node.decorators.map(convertChild); + result.decorators = node.decorators.map((el: any) => + this.convertChild(el) + ); } } else { if (Array.isArray((node as any)[key])) { - (result as any)[key] = (node as any)[key].map(convertChild); + result[key] = (node as any)[key].map((el: any) => + this.convertChild(el) + ); } else if ( (node as any)[key] && typeof (node as any)[key] === 'object' && (node as any)[key].kind ) { // need to check node[key].kind to ensure we don't try to convert a symbol - (result as any)[key] = convertChild((node as any)[key]); + result[key] = this.convertChild((node as any)[key]); } else { - (result as any)[key] = (node as any)[key]; + result[key] = (node as any)[key]; } } }); + return result; } /** * Converts a TypeScript JSX node.tagName into an ESTree node.name - * @param {ts.JsxTagNameExpression} tagName the tagName object from a JSX ts.Node - * @returns {Object} the converted ESTree name object + * @param tagName the tagName object from a JSX ts.Node + * @param parent + * @returns the converted ESTree name object */ - function convertTypeScriptJSXTagNameToESTreeName( - tagName: ts.JsxTagNameExpression - ): ESTreeNode { - const tagNameToken = convertToken(tagName, ast); - - if (tagNameToken.type === AST_NODE_TYPES.JSXMemberExpression) { + private convertTypeScriptJSXTagNameToESTreeName( + tagName: ts.JsxTagNameExpression, + parent: ts.Node + ): es.JSXMemberExpression | es.JSXIdentifier { + // TODO: remove convertToken call + const tagNameToken = convertToken(tagName, this.ast); + + if (tagName.kind === SyntaxKind.PropertyAccessExpression) { const isNestedMemberExpression = - (node as any).tagName.expression.kind === - SyntaxKind.PropertyAccessExpression; + tagName.expression.kind === SyntaxKind.PropertyAccessExpression; // Convert TSNode left and right objects into ESTreeNode object // and property objects - tagNameToken.object = convertChild((node as any).tagName.expression); - tagNameToken.property = convertChild((node as any).tagName.name); + const object = this.convertChild(tagName.expression, parent); + const property = this.convertChild(tagName.name, parent); // Assign the appropriate types - tagNameToken.object.type = isNestedMemberExpression + object.type = isNestedMemberExpression ? AST_NODE_TYPES.JSXMemberExpression : AST_NODE_TYPES.JSXIdentifier; - tagNameToken.property.type = AST_NODE_TYPES.JSXIdentifier; + property.type = AST_NODE_TYPES.JSXIdentifier; if ((tagName as any).expression.kind === SyntaxKind.ThisKeyword) { - tagNameToken.object.name = 'this'; + object.name = 'this'; } + + return this.createNode(tagName, { + type: AST_NODE_TYPES.JSXMemberExpression, + range: tagNameToken.range, + loc: tagNameToken.loc, + object: object, + property: property + }); } else { - tagNameToken.type = AST_NODE_TYPES.JSXIdentifier; - tagNameToken.name = tagNameToken.value; + return this.createNode(tagName, { + type: AST_NODE_TYPES.JSXIdentifier, + range: tagNameToken.range, + loc: tagNameToken.loc, + name: tagNameToken.value + }); } - - delete tagNameToken.value; - - return tagNameToken; } /** * Applies the given TS modifiers to the given result object. - * @param {ts.ModifiersArray} modifiers original ts.Nodes from the node.modifiers array - * @returns {void} (the current result object will be mutated) + * @param result + * @param modifiers original ts.Nodes from the node.modifiers array + * @returns the current result object will be mutated + * @deprecated This method adds not standardized `modifiers` property in nodes */ - function applyModifiersToResult(modifiers?: ts.ModifiersArray): void { + private applyModifiersToResult( + result: es.TSEnumDeclaration | es.TSModuleDeclaration, + modifiers?: ts.ModifiersArray + ): void { if (!modifiers || !modifiers.length) { return; } @@ -396,7 +448,7 @@ export default function convert(config: ConvertConfig): ESTreeNode | null { handledModifierIndices[i] = true; break; case SyntaxKind.ConstKeyword: - result.const = true; + (result as any).const = true; handledModifierIndices[i] = true; break; case SyntaxKind.DeclareKeyword: @@ -417,2091 +469,2022 @@ export default function convert(config: ConvertConfig): ESTreeNode | null { if (!remainingModifiers || !remainingModifiers.length) { return; } - result.modifiers = remainingModifiers.map(convertChild); + result.modifiers = remainingModifiers.map(el => this.convertChild(el)); } /** * Uses the current TSNode's end location for its `type` to adjust the location data of the given * ESTreeNode, which should be the parent of the final typeAnnotation node - * @param {ESTreeNode} typeAnnotationParent The node that will have its location data mutated - * @returns {void} + * @param typeAnnotationParent The node that will have its location data mutated + * @param node */ - function fixTypeAnnotationParentLocation( - typeAnnotationParent: ESTreeNode + private fixTypeAnnotationParentLocation( + typeAnnotationParent: es.BaseNode, + node: ts.TypeNode ): void { - typeAnnotationParent.range[1] = (node as any).type.getEnd(); - typeAnnotationParent.loc = getLocFor( - typeAnnotationParent.range[0], + typeAnnotationParent.range[1] = node.getEnd(); + typeAnnotationParent.loc.end = getLineAndCharacterFor( typeAnnotationParent.range[1], - ast + this.ast ); } /** + * Converts a TypeScript node into an ESTree node. * The core of the conversion logic: * Identify and convert each relevant TypeScript SyntaxKind + * @param node the child ts.Node + * @param parent parentNode + * @returns the converted ESTree node */ - switch (node.kind) { - case SyntaxKind.SourceFile: - Object.assign(result, { - type: AST_NODE_TYPES.Program, - body: convertBodyExpressions(node.statements), - // externalModuleIndicator is internal field in TSC - sourceType: (node as any).externalModuleIndicator ? 'module' : 'script' - }); + private convertNode(node: TSNode, parent: ts.Node): es.Node | null { + switch (node.kind) { + case SyntaxKind.SourceFile: { + return this.createNode(node, { + type: AST_NODE_TYPES.Program, + body: this.convertBodyExpressions(node.statements, node), + // externalModuleIndicator is internal field in TSC + sourceType: (node as any).externalModuleIndicator + ? 'module' + : 'script', + range: [node.getStart(this.ast), node.endOfFileToken.end] + }); + } - result.range[1] = node.endOfFileToken.end; - result.loc = getLocFor(node.getStart(ast), result.range[1], ast); - break; + case SyntaxKind.Block: { + return this.createNode(node, { + type: AST_NODE_TYPES.BlockStatement, + body: this.convertBodyExpressions(node.statements, node) + }); + } - case SyntaxKind.Block: - Object.assign(result, { - type: AST_NODE_TYPES.BlockStatement, - body: convertBodyExpressions(node.statements) - }); - break; + case SyntaxKind.Identifier: { + return this.createNode(node, { + type: AST_NODE_TYPES.Identifier, + name: node.text + }); + } - case SyntaxKind.Identifier: - Object.assign(result, { - type: AST_NODE_TYPES.Identifier, - name: node.text - }); - break; + case SyntaxKind.WithStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.WithStatement, + object: this.convertChild(node.expression), + body: this.convertChild(node.statement) + }); - case SyntaxKind.WithStatement: - Object.assign(result, { - type: AST_NODE_TYPES.WithStatement, - object: convertChild(node.expression), - body: convertChild(node.statement) - }); - break; + // Control Flow - // Control Flow + case SyntaxKind.ReturnStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.ReturnStatement, + argument: this.convertChild(node.expression) + }); - case SyntaxKind.ReturnStatement: - Object.assign(result, { - type: AST_NODE_TYPES.ReturnStatement, - argument: convertChild(node.expression) - }); - break; + case SyntaxKind.LabeledStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.LabeledStatement, + label: this.convertChild(node.label), + body: this.convertChild(node.statement) + }); - case SyntaxKind.LabeledStatement: - Object.assign(result, { - type: AST_NODE_TYPES.LabeledStatement, - label: convertChild(node.label), - body: convertChild(node.statement) - }); - break; + case SyntaxKind.ContinueStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.ContinueStatement, + label: this.convertChild(node.label) + }); - case SyntaxKind.BreakStatement: - case SyntaxKind.ContinueStatement: - Object.assign(result, { - type: SyntaxKind[node.kind], - label: convertChild(node.label) - }); - break; + case SyntaxKind.BreakStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.BreakStatement, + label: this.convertChild(node.label) + }); - // Choice + // Choice - case SyntaxKind.IfStatement: - Object.assign(result, { - type: AST_NODE_TYPES.IfStatement, - test: convertChild(node.expression), - consequent: convertChild(node.thenStatement), - alternate: convertChild(node.elseStatement) - }); - break; + case SyntaxKind.IfStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.IfStatement, + test: this.convertChild(node.expression), + consequent: this.convertChild(node.thenStatement), + alternate: this.convertChild(node.elseStatement) + }); - case SyntaxKind.SwitchStatement: - Object.assign(result, { - type: AST_NODE_TYPES.SwitchStatement, - discriminant: convertChild(node.expression), - cases: node.caseBlock.clauses.map(convertChild) - }); - break; - - case SyntaxKind.CaseClause: - case SyntaxKind.DefaultClause: - Object.assign(result, { - type: AST_NODE_TYPES.SwitchCase, - // expression is present in case only - test: - node.kind === SyntaxKind.CaseClause - ? convertChild(node.expression) - : null, - consequent: node.statements.map(convertChild) - }); - break; + case SyntaxKind.SwitchStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.SwitchStatement, + discriminant: this.convertChild(node.expression), + cases: node.caseBlock.clauses.map(el => this.convertChild(el)) + }); - // Exceptions + case SyntaxKind.CaseClause: + case SyntaxKind.DefaultClause: + return this.createNode(node, { + type: AST_NODE_TYPES.SwitchCase, + // expression is present in case only + test: + node.kind === SyntaxKind.CaseClause + ? this.convertChild(node.expression) + : null, + consequent: node.statements.map(el => this.convertChild(el)) + }); - case SyntaxKind.ThrowStatement: - Object.assign(result, { - type: AST_NODE_TYPES.ThrowStatement, - argument: convertChild(node.expression) - }); - break; - - case SyntaxKind.TryStatement: - Object.assign(result, { - type: AST_NODE_TYPES.TryStatement, - block: convert({ - node: node.tryBlock, - parent: null, - ast, - additionalOptions - }), - handler: convertChild(node.catchClause), - finalizer: convertChild(node.finallyBlock) - }); - break; - - case SyntaxKind.CatchClause: - Object.assign(result, { - type: AST_NODE_TYPES.CatchClause, - param: node.variableDeclaration - ? convertChild(node.variableDeclaration.name) - : null, - body: convertChild(node.block) - }); - break; + // Exceptions - // Loops + case SyntaxKind.ThrowStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.ThrowStatement, + argument: this.convertChild(node.expression) + }); - case SyntaxKind.WhileStatement: - Object.assign(result, { - type: AST_NODE_TYPES.WhileStatement, - test: convertChild(node.expression), - body: convertChild(node.statement) - }); - break; + case SyntaxKind.TryStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.TryStatement, + block: this.convertChild(node.tryBlock), + handler: this.convertChild(node.catchClause), + finalizer: this.convertChild(node.finallyBlock) + }); - /** - * Unlike other parsers, TypeScript calls a "DoWhileStatement" - * a "DoStatement" - */ - case SyntaxKind.DoStatement: - Object.assign(result, { - type: AST_NODE_TYPES.DoWhileStatement, - test: convertChild(node.expression), - body: convertChild(node.statement) - }); - break; - - case SyntaxKind.ForStatement: - Object.assign(result, { - type: AST_NODE_TYPES.ForStatement, - init: convertChild(node.initializer), - test: convertChild(node.condition), - update: convertChild(node.incrementor), - body: convertChild(node.statement) - }); - break; - - case SyntaxKind.ForInStatement: - case SyntaxKind.ForOfStatement: { - Object.assign(result, { - type: SyntaxKind[node.kind], - left: convertPattern(node.initializer), - right: convertChild(node.expression), - body: convertChild(node.statement) - }); + case SyntaxKind.CatchClause: + return this.createNode(node, { + type: AST_NODE_TYPES.CatchClause, + param: node.variableDeclaration + ? this.convertChild(node.variableDeclaration.name) + : null, + body: this.convertChild(node.block) + }); - // await is only available in for of statement - if (node.kind === SyntaxKind.ForOfStatement) { - (result as any).await = Boolean( - node.awaitModifier && - node.awaitModifier.kind === SyntaxKind.AwaitKeyword - ); - } - break; - } + // Loops - // Declarations + case SyntaxKind.WhileStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.WhileStatement, + test: this.convertChild(node.expression), + body: this.convertChild(node.statement) + }); - case SyntaxKind.FunctionDeclaration: { - const isDeclare = hasModifier(SyntaxKind.DeclareKeyword, node); - let functionDeclarationType = AST_NODE_TYPES.FunctionDeclaration; - if (isDeclare || !node.body) { - functionDeclarationType = AST_NODE_TYPES.TSDeclareFunction; - } + /** + * Unlike other parsers, TypeScript calls a "DoWhileStatement" + * a "DoStatement" + */ + case SyntaxKind.DoStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.DoWhileStatement, + test: this.convertChild(node.expression), + body: this.convertChild(node.statement) + }); - Object.assign(result, { - type: functionDeclarationType, - id: convertChild(node.name), - generator: !!node.asteriskToken, - expression: false, - async: hasModifier(SyntaxKind.AsyncKeyword, node), - params: convertParameters(node.parameters), - body: convertChild(node.body) || undefined - }); + case SyntaxKind.ForStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.ForStatement, + init: this.convertChild(node.initializer), + test: this.convertChild(node.condition), + update: this.convertChild(node.incrementor), + body: this.convertChild(node.statement) + }); - // Process returnType - if (node.type) { - result.returnType = convertTypeAnnotation(node.type); - } + case SyntaxKind.ForInStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.ForInStatement, + left: this.convertPattern(node.initializer), + right: this.convertChild(node.expression), + body: this.convertChild(node.statement) + }); - if (isDeclare) { - result.declare = true; - } + case SyntaxKind.ForOfStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.ForOfStatement, + left: this.convertPattern(node.initializer), + right: this.convertChild(node.expression), + body: this.convertChild(node.statement), + await: Boolean( + node.awaitModifier && + node.awaitModifier.kind === SyntaxKind.AwaitKeyword + ) + }); - // Process typeParameters - if (node.typeParameters && node.typeParameters.length) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } + // Declarations + + case SyntaxKind.FunctionDeclaration: { + const isDeclare = hasModifier(SyntaxKind.DeclareKeyword, node); + + const result = this.createNode< + es.TSDeclareFunction | es.FunctionDeclaration + >(node, { + type: + isDeclare || !node.body + ? AST_NODE_TYPES.TSDeclareFunction + : AST_NODE_TYPES.FunctionDeclaration, + id: this.convertChild(node.name), + generator: !!node.asteriskToken, + expression: false, + async: hasModifier(SyntaxKind.AsyncKeyword, node), + params: this.convertParameters(node.parameters), + body: this.convertChild(node.body) || undefined + }); - // check for exports - result = fixExports(node, result, ast); + // Process returnType + if (node.type) { + result.returnType = this.convertTypeAnnotation(node.type, node); + } - break; - } + if (isDeclare) { + result.declare = true; + } - case SyntaxKind.VariableDeclaration: { - Object.assign(result, { - type: AST_NODE_TYPES.VariableDeclarator, - id: convertPattern(node.name), - init: convertChild(node.initializer) - }); + // Process typeParameters + if (node.typeParameters && node.typeParameters.length) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } - if (node.exclamationToken) { - (result as any).definite = true; + // check for exports + return fixExports(node, result, this.ast); } - if (node.type) { - result.id!.typeAnnotation = convertTypeAnnotation(node.type); - fixTypeAnnotationParentLocation(result.id!); - } - break; - } + case SyntaxKind.VariableDeclaration: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.VariableDeclarator, + id: this.convertPattern(node.name), + init: this.convertChild(node.initializer) + }); - case SyntaxKind.VariableStatement: - Object.assign(result, { - type: AST_NODE_TYPES.VariableDeclaration, - declarations: node.declarationList.declarations.map(convertChild), - kind: getDeclarationKind(node.declarationList) - }); + if (node.exclamationToken) { + result.definite = true; + } - if (hasModifier(SyntaxKind.DeclareKeyword, node)) { - result.declare = true; + if (node.type) { + result.id.typeAnnotation = this.convertTypeAnnotation( + node.type, + node + ); + this.fixTypeAnnotationParentLocation(result.id, node.type); + } + return result; } - // check for exports - result = fixExports(node, result, ast); - break; - - // mostly for for-of, for-in - case SyntaxKind.VariableDeclarationList: - Object.assign(result, { - type: AST_NODE_TYPES.VariableDeclaration, - declarations: node.declarations.map(convertChild), - kind: getDeclarationKind(node) - }); - break; - - // Expressions - - case SyntaxKind.ExpressionStatement: - Object.assign(result, { - type: AST_NODE_TYPES.ExpressionStatement, - expression: convertChild(node.expression) - }); - break; + case SyntaxKind.VariableStatement: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.VariableDeclaration, + declarations: node.declarationList.declarations.map(el => + this.convertChild(el) + ), + kind: getDeclarationKind(node.declarationList) + }); - case SyntaxKind.ThisKeyword: - Object.assign(result, { - type: AST_NODE_TYPES.ThisExpression - }); - break; + if (hasModifier(SyntaxKind.DeclareKeyword, node)) { + result.declare = true; + } - case SyntaxKind.ArrayLiteralExpression: { - // TypeScript uses ArrayLiteralExpression in destructuring assignment, too - if (config.allowPattern) { - Object.assign(result, { - type: AST_NODE_TYPES.ArrayPattern, - elements: node.elements.map(convertPattern) - }); - } else { - Object.assign(result, { - type: AST_NODE_TYPES.ArrayExpression, - elements: node.elements.map(convertChild) - }); + // check for exports + return fixExports(node, result, this.ast); } - break; - } - case SyntaxKind.ObjectLiteralExpression: { - // TypeScript uses ObjectLiteralExpression in destructuring assignment, too - if (config.allowPattern) { - Object.assign(result, { - type: AST_NODE_TYPES.ObjectPattern, - properties: node.properties.map(convertPattern) - }); - } else { - Object.assign(result, { - type: AST_NODE_TYPES.ObjectExpression, - properties: node.properties.map(convertChild) + // mostly for for-of, for-in + case SyntaxKind.VariableDeclarationList: + return this.createNode(node, { + type: AST_NODE_TYPES.VariableDeclaration, + declarations: node.declarations.map(el => this.convertChild(el)), + kind: getDeclarationKind(node) }); - } - break; - } - case SyntaxKind.PropertyAssignment: - Object.assign(result, { - type: AST_NODE_TYPES.Property, - key: convertChild(node.name), - value: converter( - node.initializer, - config.inTypeMode, - config.allowPattern - ), - computed: isComputedProperty(node.name), - method: false, - shorthand: false, - kind: 'init' - }); - break; + // Expressions - case SyntaxKind.ShorthandPropertyAssignment: { - if (node.objectAssignmentInitializer) { - Object.assign(result, { - type: AST_NODE_TYPES.Property, - key: convertChild(node.name), - value: { - type: AST_NODE_TYPES.AssignmentPattern, - left: convertPattern(node.name), - right: convertChild(node.objectAssignmentInitializer), - loc: result.loc, - range: result.range - }, - computed: false, - method: false, - shorthand: true, - kind: 'init' + case SyntaxKind.ExpressionStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.ExpressionStatement, + expression: this.convertChild(node.expression) }); - } else { - // TODO: this node has no initializer field - Object.assign(result, { - type: AST_NODE_TYPES.Property, - key: convertChild(node.name), - value: convertChild((node as any).initializer || node.name), - computed: false, - method: false, - shorthand: true, - kind: 'init' - }); - } - break; - } - - case SyntaxKind.ComputedPropertyName: - return convertChild(node.expression); - - case SyntaxKind.PropertyDeclaration: { - const isAbstract = hasModifier(SyntaxKind.AbstractKeyword, node); - Object.assign(result, { - type: isAbstract - ? AST_NODE_TYPES.TSAbstractClassProperty - : AST_NODE_TYPES.ClassProperty, - key: convertChild(node.name), - value: convertChild(node.initializer), - computed: isComputedProperty(node.name), - static: hasModifier(SyntaxKind.StaticKeyword, node), - readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined - }); - - if (node.type) { - result.typeAnnotation = convertTypeAnnotation(node.type); - } - - if (node.decorators) { - result.decorators = node.decorators.map(convertChild); - } - - const accessibility = getTSNodeAccessibility(node); - if (accessibility) { - result.accessibility = accessibility; - } - - if (node.name.kind === SyntaxKind.Identifier && node.questionToken) { - result.optional = true; - } - if (node.exclamationToken) { - (result as any).definite = true; - } + case SyntaxKind.ThisKeyword: + return this.createNode(node, { + type: AST_NODE_TYPES.ThisExpression + }); - if ( - (result as any).key.type === AST_NODE_TYPES.Literal && - node.questionToken - ) { - result.optional = true; + case SyntaxKind.ArrayLiteralExpression: { + // TypeScript uses ArrayLiteralExpression in destructuring assignment, too + if (this.allowPattern) { + return this.createNode(node, { + type: AST_NODE_TYPES.ArrayPattern, + elements: node.elements.map(el => this.convertPattern(el)) + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.ArrayExpression, + elements: node.elements.map(el => this.convertChild(el)) + }); + } } - break; - } - case SyntaxKind.GetAccessor: - case SyntaxKind.SetAccessor: - case SyntaxKind.MethodDeclaration: { - const method: ESTreeNode = { - type: AST_NODE_TYPES.FunctionExpression, - id: null, - generator: !!node.asteriskToken, - expression: false, // ESTreeNode as ESTreeNode here - async: hasModifier(SyntaxKind.AsyncKeyword, node), - body: convertChild(node.body), - range: [node.parameters.pos - 1, result.range[1]], - loc: { - start: getLineAndCharacterFor(node.parameters.pos - 1, ast), - end: result.loc.end + case SyntaxKind.ObjectLiteralExpression: { + // TypeScript uses ObjectLiteralExpression in destructuring assignment, too + if (this.allowPattern) { + return this.createNode(node, { + type: AST_NODE_TYPES.ObjectPattern, + properties: node.properties.map(el => this.convertPattern(el)) + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.ObjectExpression, + properties: node.properties.map(el => this.convertChild(el)) + }); } - } as any; - - if (node.type) { - (method as any).returnType = convertTypeAnnotation(node.type); } - if (parent!.kind === SyntaxKind.ObjectLiteralExpression) { - (method as any).params = node.parameters.map(convertChild); - - Object.assign(result, { + case SyntaxKind.PropertyAssignment: + return this.createNode(node, { type: AST_NODE_TYPES.Property, - key: convertChild(node.name), - value: method, + key: this.convertChild(node.name), + value: this.converter( + node.initializer, + node, + this.inTypeMode, + this.allowPattern + ), computed: isComputedProperty(node.name), - method: node.kind === SyntaxKind.MethodDeclaration, + method: false, shorthand: false, kind: 'init' }); - } else { - // class - /** - * Unlike in object literal methods, class method params can have decorators - */ - (method as any).params = convertParameters(node.parameters); + case SyntaxKind.ShorthandPropertyAssignment: { + if (node.objectAssignmentInitializer) { + return this.createNode(node, { + type: AST_NODE_TYPES.Property, + key: this.convertChild(node.name), + value: this.createNode(node, { + type: AST_NODE_TYPES.AssignmentPattern, + left: this.convertPattern(node.name), + right: this.convertChild(node.objectAssignmentInitializer) + }), + computed: false, + method: false, + shorthand: true, + kind: 'init' + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.Property, + key: this.convertChild(node.name), + value: this.convertChild(node.name), + computed: false, + method: false, + shorthand: true, + kind: 'init' + }); + } + } - /** - * TypeScript class methods can be defined as "abstract" - */ - const methodDefinitionType = hasModifier( - SyntaxKind.AbstractKeyword, - node - ) - ? AST_NODE_TYPES.TSAbstractMethodDefinition - : AST_NODE_TYPES.MethodDefinition; - - Object.assign(result, { - type: methodDefinitionType, - key: convertChild(node.name), - value: method, + case SyntaxKind.ComputedPropertyName: + return this.convertChild(node.expression); + + case SyntaxKind.PropertyDeclaration: { + const isAbstract = hasModifier(SyntaxKind.AbstractKeyword, node); + const result = this.createNode< + es.TSAbstractClassProperty | es.ClassProperty + >(node, { + type: isAbstract + ? AST_NODE_TYPES.TSAbstractClassProperty + : AST_NODE_TYPES.ClassProperty, + key: this.convertChild(node.name), + value: this.convertChild(node.initializer), computed: isComputedProperty(node.name), static: hasModifier(SyntaxKind.StaticKeyword, node), - kind: 'method' + readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined }); + if (node.type) { + result.typeAnnotation = this.convertTypeAnnotation(node.type, node); + } + if (node.decorators) { - result.decorators = node.decorators.map(convertChild); + result.decorators = node.decorators.map(el => this.convertChild(el)); } const accessibility = getTSNodeAccessibility(node); if (accessibility) { result.accessibility = accessibility; } - } - - if ( - (result as any).key.type === AST_NODE_TYPES.Identifier && - node.questionToken - ) { - (result as any).key.optional = true; - } - if (node.kind === SyntaxKind.GetAccessor) { - (result as any).kind = 'get'; - } else if (node.kind === SyntaxKind.SetAccessor) { - (result as any).kind = 'set'; - } else if ( - !(result as any).static && - node.name.kind === SyntaxKind.StringLiteral && - node.name.text === 'constructor' && - result.type !== AST_NODE_TYPES.Property - ) { - (result as any).kind = 'constructor'; - } + if (node.name.kind === SyntaxKind.Identifier && node.questionToken) { + result.optional = true; + } - // Process typeParameters - if (node.typeParameters && node.typeParameters.length) { - if (result.type !== AST_NODE_TYPES.Property) { - method.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } else { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); + if (node.exclamationToken) { + result.definite = true; } - } - break; - } + if (result.key.type === AST_NODE_TYPES.Literal && node.questionToken) { + result.optional = true; + } + return result; + } + + case SyntaxKind.GetAccessor: + case SyntaxKind.SetAccessor: + case SyntaxKind.MethodDeclaration: { + const method = this.createNode(node, { + type: AST_NODE_TYPES.FunctionExpression, + id: null, + generator: !!node.asteriskToken, + expression: false, // ESTreeNode as ESTreeNode here + async: hasModifier(SyntaxKind.AsyncKeyword, node), + body: this.convertChild(node.body), + range: [node.parameters.pos - 1, node.end], + params: [] + }); - // TypeScript uses this even for static methods named "constructor" - case SyntaxKind.Constructor: { - const lastModifier = getLastModifier(node); - const constructorToken = - (lastModifier && findNextToken(lastModifier, node, ast)) || - node.getFirstToken()!; - - const constructorTokenRange = [ - constructorToken.getStart(ast), - constructorToken.end - ]; - - const constructor: ESTreeNode = { - type: AST_NODE_TYPES.FunctionExpression, - id: null, - params: convertParameters(node.parameters), - generator: false, - expression: false, // is not present in ESTreeNode - async: false, - body: convertChild(node.body), - range: [node.parameters.pos - 1, result.range[1]], - loc: { - start: getLineAndCharacterFor(node.parameters.pos - 1, ast), - end: result.loc.end - } - } as any; - - // Process typeParameters - if (node.typeParameters && node.typeParameters.length) { - constructor.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } + if (node.type) { + method.returnType = this.convertTypeAnnotation(node.type, node); + } - // Process returnType - if (node.type) { - constructor.returnType = convertTypeAnnotation(node.type); - } + let result: + | es.Property + | es.TSAbstractMethodDefinition + | es.MethodDefinition; - const constructorKey = { - type: AST_NODE_TYPES.Identifier, - name: 'constructor', - range: constructorTokenRange, - loc: getLocFor(constructorTokenRange[0], constructorTokenRange[1], ast) - }; + if (parent.kind === SyntaxKind.ObjectLiteralExpression) { + method.params = node.parameters.map(el => this.convertChild(el)); - const isStatic = hasModifier(SyntaxKind.StaticKeyword, node); + result = this.createNode(node, { + type: AST_NODE_TYPES.Property, + key: this.convertChild(node.name), + value: method, + computed: isComputedProperty(node.name), + method: node.kind === SyntaxKind.MethodDeclaration, + shorthand: false, + kind: 'init' + }); + } else { + // class + + /** + * Unlike in object literal methods, class method params can have decorators + */ + method.params = this.convertParameters(node.parameters); + + /** + * TypeScript class methods can be defined as "abstract" + */ + const methodDefinitionType = hasModifier( + SyntaxKind.AbstractKeyword, + node + ) + ? AST_NODE_TYPES.TSAbstractMethodDefinition + : AST_NODE_TYPES.MethodDefinition; + + result = this.createNode< + es.TSAbstractMethodDefinition | es.MethodDefinition + >(node, { + type: methodDefinitionType, + key: this.convertChild(node.name), + value: method, + computed: isComputedProperty(node.name), + static: hasModifier(SyntaxKind.StaticKeyword, node), + kind: 'method' + }); - Object.assign(result, { - type: hasModifier(SyntaxKind.AbstractKeyword, node) - ? AST_NODE_TYPES.TSAbstractMethodDefinition - : AST_NODE_TYPES.MethodDefinition, - key: constructorKey, - value: constructor, - computed: false, - static: isStatic, - kind: isStatic ? 'method' : 'constructor' - }); + if (node.decorators) { + result.decorators = node.decorators.map(el => + this.convertChild(el) + ); + } - const accessibility = getTSNodeAccessibility(node); - if (accessibility) { - result.accessibility = accessibility; - } + const accessibility = getTSNodeAccessibility(node); + if (accessibility) { + result.accessibility = accessibility; + } + } - break; - } + if ( + result.key.type === AST_NODE_TYPES.Identifier && + node.questionToken + ) { + result.key.optional = true; + } - case SyntaxKind.FunctionExpression: - Object.assign(result, { - type: AST_NODE_TYPES.FunctionExpression, - id: convertChild(node.name), - generator: !!node.asteriskToken, - params: convertParameters(node.parameters), - body: convertChild(node.body), - async: hasModifier(SyntaxKind.AsyncKeyword, node), - expression: false - }); + if (node.kind === SyntaxKind.GetAccessor) { + result.kind = 'get'; + } else if (node.kind === SyntaxKind.SetAccessor) { + result.kind = 'set'; + } else if ( + !(result as es.MethodDefinition).static && + node.name.kind === SyntaxKind.StringLiteral && + node.name.text === 'constructor' && + result.type !== AST_NODE_TYPES.Property + ) { + result.kind = 'constructor'; + } - // Process returnType - if (node.type) { - result.returnType = convertTypeAnnotation(node.type); - } + // Process typeParameters + if (node.typeParameters && node.typeParameters.length) { + if (result.type !== AST_NODE_TYPES.Property) { + method.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } else { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } + } + return result; + } + + // TypeScript uses this even for static methods named "constructor" + case SyntaxKind.Constructor: { + const lastModifier = getLastModifier(node); + const constructorToken = + (lastModifier && findNextToken(lastModifier, node, this.ast)) || + node.getFirstToken()!; + + const constructor = this.createNode(node, { + type: AST_NODE_TYPES.FunctionExpression, + id: null, + params: this.convertParameters(node.parameters), + generator: false, + expression: false, // is not present in ESTreeNode + async: false, + body: this.convertChild(node.body), + range: [node.parameters.pos - 1, node.end] + }); - // Process typeParameters - if (node.typeParameters && node.typeParameters.length) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } - break; + // Process typeParameters + if (node.typeParameters && node.typeParameters.length) { + constructor.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } - case SyntaxKind.SuperKeyword: - Object.assign(result, { - type: AST_NODE_TYPES.Super - }); - break; + // Process returnType + if (node.type) { + constructor.returnType = this.convertTypeAnnotation(node.type, node); + } - case SyntaxKind.ArrayBindingPattern: - Object.assign(result, { - type: AST_NODE_TYPES.ArrayPattern, - elements: node.elements.map(convertPattern) - }); - break; + const constructorKey = this.createNode(node, { + type: AST_NODE_TYPES.Identifier, + name: 'constructor', + range: [constructorToken.getStart(this.ast), constructorToken.end] + }); - // occurs with missing array elements like [,] - case SyntaxKind.OmittedExpression: - return null; + const isStatic = hasModifier(SyntaxKind.StaticKeyword, node); + const result = this.createNode< + es.TSAbstractMethodDefinition | es.MethodDefinition + >(node, { + type: hasModifier(SyntaxKind.AbstractKeyword, node) + ? AST_NODE_TYPES.TSAbstractMethodDefinition + : AST_NODE_TYPES.MethodDefinition, + key: constructorKey, + value: constructor, + computed: false, + static: isStatic, + kind: isStatic ? 'method' : 'constructor' + }); - case SyntaxKind.ObjectBindingPattern: - Object.assign(result, { - type: AST_NODE_TYPES.ObjectPattern, - properties: node.elements.map(convertPattern) - }); - break; + const accessibility = getTSNodeAccessibility(node); + if (accessibility) { + result.accessibility = accessibility; + } + + return result; + } - case SyntaxKind.BindingElement: - if (parent!.kind === SyntaxKind.ArrayBindingPattern) { - const arrayItem = convert({ - node: node.name, - parent, - ast, - additionalOptions + case SyntaxKind.FunctionExpression: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.FunctionExpression, + id: this.convertChild(node.name), + generator: !!node.asteriskToken, + params: this.convertParameters(node.parameters), + body: this.convertChild(node.body), + async: hasModifier(SyntaxKind.AsyncKeyword, node), + expression: false }); - if (node.initializer) { - Object.assign(result, { - type: AST_NODE_TYPES.AssignmentPattern, - left: arrayItem, - right: convertChild(node.initializer) - }); - } else if (node.dotDotDotToken) { - Object.assign(result, { - type: AST_NODE_TYPES.RestElement, - argument: arrayItem - }); - } else { - return arrayItem; + // Process returnType + if (node.type) { + result.returnType = this.convertTypeAnnotation(node.type, node); } - } else if (parent!.kind === SyntaxKind.ObjectBindingPattern) { - if (node.dotDotDotToken) { - Object.assign(result, { - type: AST_NODE_TYPES.RestElement, - argument: convertChild(node.propertyName || node.name) - }); - } else { - Object.assign(result, { - type: AST_NODE_TYPES.Property, - key: convertChild(node.propertyName || node.name), - value: convertChild(node.name), - computed: Boolean( - node.propertyName && - node.propertyName.kind === SyntaxKind.ComputedPropertyName - ), - method: false, - shorthand: !node.propertyName, - kind: 'init' - }); + + // Process typeParameters + if (node.typeParameters && node.typeParameters.length) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); } + return result; + } - if (node.initializer) { - (result as any).value = { - type: AST_NODE_TYPES.AssignmentPattern, - left: convertChild(node.name), - right: convertChild(node.initializer), - range: [node.name.getStart(ast), node.initializer.end], - loc: getLocFor(node.name.getStart(ast), node.initializer.end, ast) - }; - } - } - break; - - case SyntaxKind.ArrowFunction: - Object.assign(result, { - type: AST_NODE_TYPES.ArrowFunctionExpression, - generator: false, - id: null, - params: convertParameters(node.parameters), - body: convertChild(node.body), - async: hasModifier(SyntaxKind.AsyncKeyword, node), - expression: node.body.kind !== SyntaxKind.Block - }); + case SyntaxKind.SuperKeyword: + return this.createNode(node, { + type: AST_NODE_TYPES.Super + }); - // Process returnType - if (node.type) { - result.returnType = convertTypeAnnotation(node.type); - } + case SyntaxKind.ArrayBindingPattern: + return this.createNode(node, { + type: AST_NODE_TYPES.ArrayPattern, + elements: node.elements.map(el => this.convertPattern(el)) + }); - // Process typeParameters - if (node.typeParameters && node.typeParameters.length) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } - break; + // occurs with missing array elements like [,] + case SyntaxKind.OmittedExpression: + return null; - case SyntaxKind.YieldExpression: - Object.assign(result, { - type: AST_NODE_TYPES.YieldExpression, - delegate: !!node.asteriskToken, - argument: convertChild(node.expression) - }); - break; + case SyntaxKind.ObjectBindingPattern: + return this.createNode(node, { + type: AST_NODE_TYPES.ObjectPattern, + properties: node.elements.map(el => this.convertPattern(el)) + }); - case SyntaxKind.AwaitExpression: - Object.assign(result, { - type: AST_NODE_TYPES.AwaitExpression, - argument: convertChild(node.expression) - }); - break; - - // Template Literals - - case SyntaxKind.NoSubstitutionTemplateLiteral: - Object.assign(result, { - type: AST_NODE_TYPES.TemplateLiteral, - quasis: [ - { - type: AST_NODE_TYPES.TemplateElement, - value: { - raw: ast.text.slice(node.getStart(ast) + 1, node.end - 1), - cooked: node.text - }, - tail: true, - range: result.range, - loc: result.loc + case SyntaxKind.BindingElement: { + if (parent.kind === SyntaxKind.ArrayBindingPattern) { + const arrayItem = this.convertChild(node.name, parent); + + if (node.initializer) { + return this.createNode(node, { + type: AST_NODE_TYPES.AssignmentPattern, + left: arrayItem, + right: this.convertChild(node.initializer) + }); + } else if (node.dotDotDotToken) { + return this.createNode(node, { + type: AST_NODE_TYPES.RestElement, + argument: arrayItem + }); + } else { + return arrayItem; + } + } else if (parent.kind === SyntaxKind.ObjectBindingPattern) { + let result: es.RestElement | es.Property; + if (node.dotDotDotToken) { + result = this.createNode(node, { + type: AST_NODE_TYPES.RestElement, + argument: this.convertChild(node.propertyName || node.name) + }); + } else { + result = this.createNode(node, { + type: AST_NODE_TYPES.Property, + key: this.convertChild(node.propertyName || node.name), + value: this.convertChild(node.name), + computed: Boolean( + node.propertyName && + node.propertyName.kind === SyntaxKind.ComputedPropertyName + ), + method: false, + shorthand: !node.propertyName, + kind: 'init' + }); } - ], - expressions: [] - }); - break; - case SyntaxKind.TemplateExpression: - Object.assign(result, { - type: AST_NODE_TYPES.TemplateLiteral, - quasis: [convertChild(node.head)], - expressions: [] - }); + if (node.initializer) { + result.value = this.createNode(node, { + type: AST_NODE_TYPES.AssignmentPattern, + left: this.convertChild(node.name), + right: this.convertChild(node.initializer), + range: [node.name.getStart(this.ast), node.initializer.end] + }); + } + return result; + } + return null; + } + + case SyntaxKind.ArrowFunction: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.ArrowFunctionExpression, + generator: false, + id: null, + params: this.convertParameters(node.parameters), + body: this.convertChild(node.body), + async: hasModifier(SyntaxKind.AsyncKeyword, node), + expression: node.body.kind !== SyntaxKind.Block + }); - node.templateSpans.forEach(templateSpan => { - (result as any).expressions.push(convertChild(templateSpan.expression)); - (result as any).quasis.push(convertChild(templateSpan.literal)); - }); - break; - - case SyntaxKind.TaggedTemplateExpression: - Object.assign(result, { - type: AST_NODE_TYPES.TaggedTemplateExpression, - typeParameters: node.typeArguments - ? convertTypeArgumentsToTypeParameters(node.typeArguments) - : undefined, - tag: convertChild(node.tag), - quasi: convertChild(node.template) - }); - break; - - case SyntaxKind.TemplateHead: - case SyntaxKind.TemplateMiddle: - case SyntaxKind.TemplateTail: { - const tail = node.kind === SyntaxKind.TemplateTail; - Object.assign(result, { - type: AST_NODE_TYPES.TemplateElement, - value: { - raw: ast.text.slice( - node.getStart(ast) + 1, - node.end - (tail ? 1 : 2) - ), - cooked: node.text - }, - tail - }); - break; - } + // Process returnType + if (node.type) { + result.returnType = this.convertTypeAnnotation(node.type, node); + } - // Patterns + // Process typeParameters + if (node.typeParameters && node.typeParameters.length) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } + return result; + } - case SyntaxKind.SpreadAssignment: - case SyntaxKind.SpreadElement: { - if (config.allowPattern) { - Object.assign(result, { - type: AST_NODE_TYPES.RestElement, - argument: convertPattern(node.expression) - }); - } else { - Object.assign(result, { - type: AST_NODE_TYPES.SpreadElement, - argument: convertChild(node.expression) + case SyntaxKind.YieldExpression: + return this.createNode(node, { + type: AST_NODE_TYPES.YieldExpression, + delegate: !!node.asteriskToken, + argument: this.convertChild(node.expression) }); - } - break; - } - case SyntaxKind.Parameter: { - let parameter: ESTreeNode; + case SyntaxKind.AwaitExpression: + return this.createNode(node, { + type: AST_NODE_TYPES.AwaitExpression, + argument: this.convertChild(node.expression) + }); - if (node.dotDotDotToken) { - Object.assign(result, { - type: AST_NODE_TYPES.RestElement, - argument: convertChild(node.name) + // Template Literals + + case SyntaxKind.NoSubstitutionTemplateLiteral: + return this.createNode(node, { + type: AST_NODE_TYPES.TemplateLiteral, + quasis: [ + this.createNode(node, { + type: AST_NODE_TYPES.TemplateElement, + value: { + raw: this.ast.text.slice( + node.getStart(this.ast) + 1, + node.end - 1 + ), + cooked: node.text + }, + tail: true + }) + ], + expressions: [] }); - parameter = result; - } else if (node.initializer) { - parameter = convertChild(node.name)!; - Object.assign(result, { - type: AST_NODE_TYPES.AssignmentPattern, - left: parameter, - right: convertChild(node.initializer) + + case SyntaxKind.TemplateExpression: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TemplateLiteral, + quasis: [this.convertChild(node.head)], + expressions: [] }); - if (node.modifiers) { - // AssignmentPattern should not contain modifiers in range - result.range[0] = parameter.range[0]; - result.loc = getLocFor(result.range[0], result.range[1], ast); - } - } else { - parameter = result = convert({ - node: node.name, - parent, - ast, - additionalOptions - })!; - } - - if (node.type) { - parameter.typeAnnotation = convertTypeAnnotation(node.type); - fixTypeAnnotationParentLocation(parameter); - } - - if (node.questionToken) { - if (node.questionToken.end > parameter.range[1]) { - parameter.range[1] = node.questionToken.end; - parameter.loc = getLocFor( - parameter.range[0], - parameter.range[1], - ast - ); - } - parameter.optional = true; + node.templateSpans.forEach(templateSpan => { + result.expressions.push(this.convertChild(templateSpan.expression)); + result.quasis.push(this.convertChild(templateSpan.literal)); + }); + return result; } - if (node.modifiers) { - return { - type: AST_NODE_TYPES.TSParameterProperty, - range: [node.getStart(ast), node.end], - loc: getLoc(node, ast), - accessibility: getTSNodeAccessibility(node) || undefined, - readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined, - static: hasModifier(SyntaxKind.StaticKeyword, node) || undefined, - export: hasModifier(SyntaxKind.ExportKeyword, node) || undefined, - parameter: result - }; + case SyntaxKind.TaggedTemplateExpression: + return this.createNode(node, { + type: AST_NODE_TYPES.TaggedTemplateExpression, + typeParameters: node.typeArguments + ? this.convertTypeArgumentsToTypeParameters(node.typeArguments) + : undefined, + tag: this.convertChild(node.tag), + quasi: this.convertChild(node.template) + }); + + case SyntaxKind.TemplateHead: + case SyntaxKind.TemplateMiddle: + case SyntaxKind.TemplateTail: { + const tail = node.kind === SyntaxKind.TemplateTail; + return this.createNode(node, { + type: AST_NODE_TYPES.TemplateElement, + value: { + raw: this.ast.text.slice( + node.getStart(this.ast) + 1, + node.end - (tail ? 1 : 2) + ), + cooked: node.text + }, + tail + }); } - break; - } + // Patterns - // Classes + case SyntaxKind.SpreadAssignment: + case SyntaxKind.SpreadElement: { + if (this.allowPattern) { + return this.createNode(node, { + type: AST_NODE_TYPES.RestElement, + argument: this.convertPattern(node.expression) + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.SpreadElement, + argument: this.convertChild(node.expression) + }); + } + } - case SyntaxKind.ClassDeclaration: - case SyntaxKind.ClassExpression: { - const heritageClauses = node.heritageClauses || []; - let classNodeType = SyntaxKind[node.kind]; + case SyntaxKind.Parameter: { + let parameter: any; + let result: es.RestElement | es.AssignmentPattern; - if (node.typeParameters && node.typeParameters.length) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } + if (node.dotDotDotToken) { + parameter = result = this.createNode(node, { + type: AST_NODE_TYPES.RestElement, + argument: this.convertChild(node.name) + }); + } else if (node.initializer) { + parameter = this.convertChild(node.name); + result = this.createNode(node, { + type: AST_NODE_TYPES.AssignmentPattern, + left: parameter, + right: this.convertChild(node.initializer) + }); - const superClass = heritageClauses.find( - clause => clause.token === SyntaxKind.ExtendsKeyword - ); + if (node.modifiers) { + // AssignmentPattern should not contain modifiers in range + result.range[0] = parameter.range[0]; + result.loc = getLocFor(result.range[0], result.range[1], this.ast); + } + } else { + parameter = result = this.convertChild(node.name, parent); + } - if (superClass) { - if (superClass.types.length > 1) { - throw createError( - ast, - superClass.types[1].pos, - 'Classes can only extend a single class.' + if (node.type) { + parameter.typeAnnotation = this.convertTypeAnnotation( + node.type, + node ); + this.fixTypeAnnotationParentLocation(parameter, node.type); } - if (superClass.types[0] && superClass.types[0].typeArguments) { - (result as any).superTypeParameters = convertTypeArgumentsToTypeParameters( - superClass.types[0].typeArguments - ); + if (node.questionToken) { + if (node.questionToken.end > parameter.range[1]) { + parameter.range[1] = node.questionToken.end; + parameter.loc.end = getLineAndCharacterFor( + parameter.range[1], + this.ast + ); + } + parameter.optional = true; + } + + if (node.modifiers) { + return this.createNode(node, { + type: AST_NODE_TYPES.TSParameterProperty, + accessibility: getTSNodeAccessibility(node) || undefined, + readonly: + hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined, + static: hasModifier(SyntaxKind.StaticKeyword, node) || undefined, + export: hasModifier(SyntaxKind.ExportKeyword, node) || undefined, + parameter: result + }); } + return result; } - const implementsClause = heritageClauses.find( - clause => clause.token === SyntaxKind.ImplementsKeyword - ); + // Classes - const classBodyRange = [node.members.pos - 1, node.end]; + case SyntaxKind.ClassDeclaration: + case SyntaxKind.ClassExpression: { + const heritageClauses = node.heritageClauses || []; + let classNodeType = + node.kind === SyntaxKind.ClassDeclaration + ? AST_NODE_TYPES.ClassDeclaration + : AST_NODE_TYPES.ClassExpression; - Object.assign(result, { - type: classNodeType, - id: convertChild(node.name), - body: { - type: AST_NODE_TYPES.ClassBody, - body: [], - range: classBodyRange, - loc: getLocFor(classBodyRange[0], classBodyRange[1], ast) - }, - superClass: - superClass && superClass.types[0] - ? convertChild(superClass.types[0].expression) - : null - }); + const superClass = heritageClauses.find( + clause => clause.token === SyntaxKind.ExtendsKeyword + ); - if (implementsClause) { - result.implements = implementsClause.types.map(convertChild); - } + const implementsClause = heritageClauses.find( + clause => clause.token === SyntaxKind.ImplementsKeyword + ); - /** - * TypeScript class declarations can be defined as "abstract" - */ - if (hasModifier(SyntaxKind.AbstractKeyword, node)) { - result.abstract = true; - } + const result = this.createNode< + es.ClassDeclaration | es.ClassExpression + >(node, { + type: classNodeType, + id: this.convertChild(node.name), + body: this.createNode(node, { + type: AST_NODE_TYPES.ClassBody, + body: [], + range: [node.members.pos - 1, node.end] + }), + superClass: + superClass && superClass.types[0] + ? this.convertChild(superClass.types[0].expression) + : null + }); - if (hasModifier(SyntaxKind.DeclareKeyword, node)) { - result.declare = true; - } + if (superClass) { + if (superClass.types.length > 1) { + throw createError( + this.ast, + superClass.types[1].pos, + 'Classes can only extend a single class.' + ); + } - if (node.decorators) { - result.decorators = node.decorators.map(convertChild); - } + if (superClass.types[0] && superClass.types[0].typeArguments) { + result.superTypeParameters = this.convertTypeArgumentsToTypeParameters( + superClass.types[0].typeArguments + ); + } + } - const filteredMembers = node.members.filter(isESTreeClassMember); + if (node.typeParameters && node.typeParameters.length) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } - if (filteredMembers.length) { - result.body.body = filteredMembers.map(convertChild); - } + if (implementsClause) { + result.implements = implementsClause.types.map(el => + this.convertChild(el) + ); + } - // check for exports - result = fixExports(node, result, ast); + /** + * TypeScript class declarations can be defined as "abstract" + */ + if (hasModifier(SyntaxKind.AbstractKeyword, node)) { + result.abstract = true; + } - break; - } + if (hasModifier(SyntaxKind.DeclareKeyword, node)) { + result.declare = true; + } - // Modules - case SyntaxKind.ModuleBlock: - Object.assign(result, { - type: AST_NODE_TYPES.TSModuleBlock, - body: convertBodyExpressions(node.statements) - }); - break; + if (node.decorators) { + result.decorators = node.decorators.map(el => this.convertChild(el)); + } - case SyntaxKind.ImportDeclaration: - Object.assign(result, { - type: AST_NODE_TYPES.ImportDeclaration, - source: convertChild(node.moduleSpecifier), - specifiers: [] - }); + const filteredMembers = node.members.filter(isESTreeClassMember); - if (node.importClause) { - if (node.importClause.name) { - result.specifiers!.push(convertChild(node.importClause)); - } - - if (node.importClause.namedBindings) { - switch (node.importClause.namedBindings.kind) { - case SyntaxKind.NamespaceImport: - result.specifiers!.push( - convertChild(node.importClause.namedBindings) - ); - break; - case SyntaxKind.NamedImports: - result.specifiers = result.specifiers!.concat( - node.importClause.namedBindings.elements.map(convertChild) - ); - break; - } + if (filteredMembers.length) { + result.body.body = filteredMembers.map(el => this.convertChild(el)); } + + // check for exports + return fixExports(node, result, this.ast); } - break; - case SyntaxKind.NamespaceImport: - Object.assign(result, { - type: AST_NODE_TYPES.ImportNamespaceSpecifier, - local: convertChild(node.name) - }); - break; + // Modules + case SyntaxKind.ModuleBlock: + return this.createNode(node, { + type: AST_NODE_TYPES.TSModuleBlock, + body: this.convertBodyExpressions(node.statements, node) + }); - case SyntaxKind.ImportSpecifier: - Object.assign(result, { - type: AST_NODE_TYPES.ImportSpecifier, - local: convertChild(node.name), - imported: convertChild(node.propertyName || node.name) - }); - break; + case SyntaxKind.ImportDeclaration: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.ImportDeclaration, + source: this.convertChild(node.moduleSpecifier), + specifiers: [] + }); - case SyntaxKind.ImportClause: - Object.assign(result, { - type: AST_NODE_TYPES.ImportDefaultSpecifier, - local: convertChild(node.name) - }); + if (node.importClause) { + if (node.importClause.name) { + result.specifiers.push(this.convertChild(node.importClause)); + } - // have to adjust location information due to tree differences - result.range[1] = node.name!.end; - result.loc = getLocFor(result.range[0], result.range[1], ast); - break; + if (node.importClause.namedBindings) { + switch (node.importClause.namedBindings.kind) { + case SyntaxKind.NamespaceImport: + result.specifiers.push( + this.convertChild(node.importClause.namedBindings) + ); + break; + case SyntaxKind.NamedImports: + result.specifiers = result.specifiers.concat( + node.importClause.namedBindings.elements.map(el => + this.convertChild(el) + ) + ); + break; + } + } + } + return result; + } - case SyntaxKind.ExportDeclaration: - if (node.exportClause) { - Object.assign(result, { - type: AST_NODE_TYPES.ExportNamedDeclaration, - source: convertChild(node.moduleSpecifier), - specifiers: node.exportClause.elements.map(convertChild), - declaration: null - }); - } else { - Object.assign(result, { - type: AST_NODE_TYPES.ExportAllDeclaration, - source: convertChild(node.moduleSpecifier) + case SyntaxKind.NamespaceImport: + return this.createNode(node, { + type: AST_NODE_TYPES.ImportNamespaceSpecifier, + local: this.convertChild(node.name) }); - } - break; - case SyntaxKind.ExportSpecifier: - Object.assign(result, { - type: AST_NODE_TYPES.ExportSpecifier, - local: convertChild(node.propertyName || node.name), - exported: convertChild(node.name) - }); - break; + case SyntaxKind.ImportSpecifier: + return this.createNode(node, { + type: AST_NODE_TYPES.ImportSpecifier, + local: this.convertChild(node.name), + imported: this.convertChild(node.propertyName || node.name) + }); - case SyntaxKind.ExportAssignment: - if (node.isExportEquals) { - Object.assign(result, { - type: AST_NODE_TYPES.TSExportAssignment, - expression: convertChild(node.expression) + case SyntaxKind.ImportClause: + return this.createNode(node, { + type: AST_NODE_TYPES.ImportDefaultSpecifier, + local: this.convertChild(node.name), + range: [node.getStart(this.ast), node.name!.end] }); - } else { - Object.assign(result, { - type: AST_NODE_TYPES.ExportDefaultDeclaration, - declaration: convertChild(node.expression) + + case SyntaxKind.ExportDeclaration: + if (node.exportClause) { + return this.createNode(node, { + type: AST_NODE_TYPES.ExportNamedDeclaration, + source: this.convertChild(node.moduleSpecifier), + specifiers: node.exportClause.elements.map(el => + this.convertChild(el) + ), + declaration: null + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.ExportAllDeclaration, + source: this.convertChild(node.moduleSpecifier) + }); + } + + case SyntaxKind.ExportSpecifier: + return this.createNode(node, { + type: AST_NODE_TYPES.ExportSpecifier, + local: this.convertChild(node.propertyName || node.name), + exported: this.convertChild(node.name) }); - } - break; - // Unary Operations + case SyntaxKind.ExportAssignment: + if (node.isExportEquals) { + return this.createNode(node, { + type: AST_NODE_TYPES.TSExportAssignment, + expression: this.convertChild(node.expression) + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.ExportDefaultDeclaration, + declaration: this.convertChild(node.expression) + }); + } + + // Unary Operations - case SyntaxKind.PrefixUnaryExpression: - case SyntaxKind.PostfixUnaryExpression: { - const operator = getTextForTokenKind(node.operator) || ''; - Object.assign(result, { + case SyntaxKind.PrefixUnaryExpression: + case SyntaxKind.PostfixUnaryExpression: { + const operator = (getTextForTokenKind(node.operator) || '') as any; /** * ESTree uses UpdateExpression for ++/-- */ - type: /^(?:\+\+|--)$/.test(operator) - ? AST_NODE_TYPES.UpdateExpression - : AST_NODE_TYPES.UnaryExpression, - operator, - prefix: node.kind === SyntaxKind.PrefixUnaryExpression, - argument: convertChild(node.operand) - }); - break; - } + if (/^(?:\+\+|--)$/.test(operator)) { + return this.createNode(node, { + type: AST_NODE_TYPES.UpdateExpression, + operator, + prefix: node.kind === SyntaxKind.PrefixUnaryExpression, + argument: this.convertChild(node.operand) + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.UnaryExpression, + operator, + prefix: node.kind === SyntaxKind.PrefixUnaryExpression, + argument: this.convertChild(node.operand) + }); + } + } - case SyntaxKind.DeleteExpression: - Object.assign(result, { - type: AST_NODE_TYPES.UnaryExpression, - operator: 'delete', - prefix: true, - argument: convertChild(node.expression) - }); - break; - - case SyntaxKind.VoidExpression: - Object.assign(result, { - type: AST_NODE_TYPES.UnaryExpression, - operator: 'void', - prefix: true, - argument: convertChild(node.expression) - }); - break; - - case SyntaxKind.TypeOfExpression: - Object.assign(result, { - type: AST_NODE_TYPES.UnaryExpression, - operator: 'typeof', - prefix: true, - argument: convertChild(node.expression) - }); - break; + case SyntaxKind.DeleteExpression: + return this.createNode(node, { + type: AST_NODE_TYPES.UnaryExpression, + operator: 'delete', + prefix: true, + argument: this.convertChild(node.expression) + }); - case SyntaxKind.TypeOperator: - Object.assign(result, { - type: AST_NODE_TYPES.TSTypeOperator, - operator: getTextForTokenKind(node.operator), - typeAnnotation: convertChild(node.type) - }); - break; + case SyntaxKind.VoidExpression: + return this.createNode(node, { + type: AST_NODE_TYPES.UnaryExpression, + operator: 'void', + prefix: true, + argument: this.convertChild(node.expression) + }); - // Binary Operations + case SyntaxKind.TypeOfExpression: + return this.createNode(node, { + type: AST_NODE_TYPES.UnaryExpression, + operator: 'typeof', + prefix: true, + argument: this.convertChild(node.expression) + }); - case SyntaxKind.BinaryExpression: - // TypeScript uses BinaryExpression for sequences as well - if (isComma(node.operatorToken)) { - Object.assign(result, { - type: AST_NODE_TYPES.SequenceExpression, - expressions: [] + case SyntaxKind.TypeOperator: + return this.createNode(node, { + type: AST_NODE_TYPES.TSTypeOperator, + operator: getTextForTokenKind(node.operator) as any, + typeAnnotation: this.convertChild(node.type) }); - const left = convertChild(node.left)!, - right = convertChild(node.right)!; + // Binary Operations - if (left.type === AST_NODE_TYPES.SequenceExpression) { - (result as any).expressions = (result as any).expressions.concat( - (left as any).expressions - ); - } else { - (result as any).expressions.push(left); - } + case SyntaxKind.BinaryExpression: { + // TypeScript uses BinaryExpression for sequences as well + if (isComma(node.operatorToken)) { + const result = this.createNode(node, { + type: AST_NODE_TYPES.SequenceExpression, + expressions: [] + }); - if (right.type === AST_NODE_TYPES.SequenceExpression) { - (result as any).expressions = (result as any).expressions.concat( - (right as any).expressions - ); + const left = this.convertChild(node.left), + right = this.convertChild(node.right); + + if (left.type === AST_NODE_TYPES.SequenceExpression) { + result.expressions = result.expressions.concat(left.expressions); + } else { + result.expressions.push(left); + } + + if (right.type === AST_NODE_TYPES.SequenceExpression) { + result.expressions = result.expressions.concat(right.expressions); + } else { + result.expressions.push(right); + } + return result; } else { - (result as any).expressions.push(right); - } - } else { - const type = getBinaryExpressionType(node.operatorToken); - Object.assign(result, { - type, - operator: getTextForTokenKind(node.operatorToken.kind), - left: converter( - node.left, - config.inTypeMode, + const type = getBinaryExpressionType(node.operatorToken); + if ( + this.allowPattern && type === AST_NODE_TYPES.AssignmentExpression - ), - right: convertChild(node.right) - }); - - // if the binary expression is in a destructured array, switch it - if (result.type === AST_NODE_TYPES.AssignmentExpression) { - if (config.allowPattern) { - delete (result as any).operator; - result.type = AST_NODE_TYPES.AssignmentPattern; + ) { + return this.createNode(node, { + type: AST_NODE_TYPES.AssignmentPattern, + left: this.convertPattern(node.left, node), + right: this.convertChild(node.right) + }); } + return this.createNode< + es.AssignmentExpression | es.LogicalExpression | es.BinaryExpression + >(node, { + type: type, + operator: getTextForTokenKind(node.operatorToken.kind)!, + left: this.converter( + node.left, + node, + this.inTypeMode, + type === AST_NODE_TYPES.AssignmentExpression + ), + right: this.convertChild(node.right) + }); } } - break; - case SyntaxKind.PropertyAccessExpression: - if (isJSXToken(parent!)) { - const jsxMemberExpression = { - type: AST_NODE_TYPES.MemberExpression, - object: convertChild(node.expression), - property: convertChild(node.name) - }; - const isNestedMemberExpression = - node.expression.kind === SyntaxKind.PropertyAccessExpression; - if (node.expression.kind === SyntaxKind.ThisKeyword) { - (jsxMemberExpression as any).object.name = 'this'; - } - - (jsxMemberExpression as any).object.type = isNestedMemberExpression - ? AST_NODE_TYPES.MemberExpression - : AST_NODE_TYPES.JSXIdentifier; - (jsxMemberExpression as any).property.type = - AST_NODE_TYPES.JSXIdentifier; - Object.assign(result, jsxMemberExpression); - } else { - Object.assign(result, { + case SyntaxKind.PropertyAccessExpression: + if (isJSXToken(parent)) { + const jsxMemberExpression = this.createNode( + node, + { + type: AST_NODE_TYPES.MemberExpression, + object: this.convertChild(node.expression), + property: this.convertChild(node.name) + } + ); + // TODO: refactor this + const isNestedMemberExpression = + node.expression.kind === SyntaxKind.PropertyAccessExpression; + if (node.expression.kind === SyntaxKind.ThisKeyword) { + (jsxMemberExpression.object as any).name = 'this'; + } + + (jsxMemberExpression.object as any).type = isNestedMemberExpression + ? AST_NODE_TYPES.MemberExpression + : AST_NODE_TYPES.JSXIdentifier; + (jsxMemberExpression as any).property.type = + AST_NODE_TYPES.JSXIdentifier; + return jsxMemberExpression; + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.MemberExpression, + object: this.convertChild(node.expression), + property: this.convertChild(node.name), + computed: false + }); + } + + case SyntaxKind.ElementAccessExpression: + return this.createNode(node, { type: AST_NODE_TYPES.MemberExpression, - object: convertChild(node.expression), - property: convertChild(node.name), - computed: false + object: this.convertChild(node.expression), + property: this.convertChild(node.argumentExpression), + computed: true }); - } - break; - case SyntaxKind.ElementAccessExpression: - Object.assign(result, { - type: AST_NODE_TYPES.MemberExpression, - object: convertChild(node.expression), - property: convertChild(node.argumentExpression), - computed: true - }); - break; - - case SyntaxKind.ConditionalExpression: - Object.assign(result, { - type: AST_NODE_TYPES.ConditionalExpression, - test: convertChild(node.condition), - consequent: convertChild(node.whenTrue), - alternate: convertChild(node.whenFalse) - }); - break; + case SyntaxKind.ConditionalExpression: + return this.createNode(node, { + type: AST_NODE_TYPES.ConditionalExpression, + test: this.convertChild(node.condition), + consequent: this.convertChild(node.whenTrue), + alternate: this.convertChild(node.whenFalse) + }); - case SyntaxKind.CallExpression: - Object.assign(result, { - type: AST_NODE_TYPES.CallExpression, - callee: convertChild(node.expression), - arguments: node.arguments.map(convertChild) - }); - if (node.typeArguments && node.typeArguments.length) { - result.typeParameters = convertTypeArgumentsToTypeParameters( - node.typeArguments - ); + case SyntaxKind.CallExpression: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.CallExpression, + callee: this.convertChild(node.expression), + arguments: node.arguments.map(el => this.convertChild(el)) + }); + if (node.typeArguments && node.typeArguments.length) { + result.typeParameters = this.convertTypeArgumentsToTypeParameters( + node.typeArguments + ); + } + return result; } - break; - case SyntaxKind.NewExpression: - Object.assign(result, { - type: AST_NODE_TYPES.NewExpression, - callee: convertChild(node.expression), - arguments: node.arguments ? node.arguments.map(convertChild) : [] - }); - if (node.typeArguments && node.typeArguments.length) { - result.typeParameters = convertTypeArgumentsToTypeParameters( - node.typeArguments - ); + case SyntaxKind.NewExpression: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.NewExpression, + callee: this.convertChild(node.expression), + arguments: node.arguments + ? node.arguments.map(el => this.convertChild(el)) + : [] + }); + if (node.typeArguments && node.typeArguments.length) { + result.typeParameters = this.convertTypeArgumentsToTypeParameters( + node.typeArguments + ); + } + return result; } - break; - - case SyntaxKind.MetaProperty: { - const newToken = convertToken(node.getFirstToken()!, ast); - Object.assign(result, { - type: AST_NODE_TYPES.MetaProperty, - meta: { - type: AST_NODE_TYPES.Identifier, - range: newToken.range, - loc: newToken.loc, - name: getTextForTokenKind(node.keywordToken) - }, - property: convertChild(node.name) - }); - break; - } - - case SyntaxKind.Decorator: { - Object.assign(result, { - type: AST_NODE_TYPES.Decorator, - expression: convertChild(node.expression) - }); - break; - } - // Literals + case SyntaxKind.MetaProperty: { + return this.createNode(node, { + type: AST_NODE_TYPES.MetaProperty, + meta: this.createNode(node.getFirstToken()!, { + type: AST_NODE_TYPES.Identifier, + name: getTextForTokenKind(node.keywordToken)! + }), + property: this.convertChild(node.name) + }); + } - case SyntaxKind.StringLiteral: - Object.assign(result, { - type: AST_NODE_TYPES.Literal, - raw: ast.text.slice(result.range[0], result.range[1]) - }); - if ((parent as any).name && (parent as any).name === node) { - (result as any).value = node.text; - } else { - (result as any).value = unescapeStringLiteralText(node.text); - } - break; - - case SyntaxKind.NumericLiteral: { - Object.assign(result, { - type: AST_NODE_TYPES.Literal, - value: Number(node.text), - raw: node.getText() - }); - break; - } + case SyntaxKind.Decorator: { + return this.createNode(node, { + type: AST_NODE_TYPES.Decorator, + expression: this.convertChild(node.expression) + }); + } - case SyntaxKind.BigIntLiteral: { - const raw = ast.text.slice(result.range[0], result.range[1]); - const value = raw.slice(0, -1); // remove suffix `n` - Object.assign(result, { - type: AST_NODE_TYPES.BigIntLiteral, - raw, - value - }); - break; - } + // Literals - case SyntaxKind.RegularExpressionLiteral: { - const pattern = node.text.slice(1, node.text.lastIndexOf('/')); - const flags = node.text.slice(node.text.lastIndexOf('/') + 1); + case SyntaxKind.StringLiteral: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.Literal, + raw: '', + value: '' + }); + result.raw = this.ast.text.slice(result.range[0], result.range[1]); + if ((parent as any).name && (parent as any).name === node) { + result.value = node.text; + } else { + result.value = unescapeStringLiteralText(node.text); + } + return result; + } - let regex = null; - try { - regex = new RegExp(pattern, flags); - } catch (exception) { - regex = null; + case SyntaxKind.NumericLiteral: { + return this.createNode(node, { + type: AST_NODE_TYPES.Literal, + value: Number(node.text), + raw: node.getText() + }); } - Object.assign(result, { - type: AST_NODE_TYPES.Literal, - value: regex, - raw: node.text, - regex: { - pattern, - flags - } - }); - break; - } + case SyntaxKind.BigIntLiteral: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.BigIntLiteral, + raw: '', + value: '' + }); + result.raw = this.ast.text.slice(result.range[0], result.range[1]); + result.value = result.raw.slice(0, -1); // remove suffix `n` + return result; + } - case SyntaxKind.TrueKeyword: - Object.assign(result, { - type: AST_NODE_TYPES.Literal, - value: true, - raw: 'true' - }); - break; + case SyntaxKind.RegularExpressionLiteral: { + const pattern = node.text.slice(1, node.text.lastIndexOf('/')); + const flags = node.text.slice(node.text.lastIndexOf('/') + 1); - case SyntaxKind.FalseKeyword: - Object.assign(result, { - type: AST_NODE_TYPES.Literal, - value: false, - raw: 'false' - }); - break; + let regex = null; + try { + regex = new RegExp(pattern, flags); + } catch (exception) { + regex = null; + } - case SyntaxKind.NullKeyword: { - if (config.inTypeMode) { - Object.assign(result, { - type: AST_NODE_TYPES.TSNullKeyword - }); - } else { - Object.assign(result, { + return this.createNode(node, { type: AST_NODE_TYPES.Literal, - value: null, - raw: 'null' + value: regex, + raw: node.text, + regex: { + pattern, + flags + } }); } - break; - } - case SyntaxKind.ImportKeyword: - Object.assign(result, { - type: AST_NODE_TYPES.Import - }); - break; + case SyntaxKind.TrueKeyword: + return this.createNode(node, { + type: AST_NODE_TYPES.Literal, + value: true, + raw: 'true' + }); - case SyntaxKind.EmptyStatement: - case SyntaxKind.DebuggerStatement: - Object.assign(result, { - type: SyntaxKind[node.kind] - }); - break; + case SyntaxKind.FalseKeyword: + return this.createNode(node, { + type: AST_NODE_TYPES.Literal, + value: false, + raw: 'false' + }); - // JSX + case SyntaxKind.NullKeyword: { + if (this.inTypeMode) { + return this.createNode(node, { + type: AST_NODE_TYPES.TSNullKeyword + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.Literal, + value: null, + raw: 'null' + }); + } + } - case SyntaxKind.JsxElement: - Object.assign(result, { - type: AST_NODE_TYPES.JSXElement, - openingElement: convertChild(node.openingElement), - closingElement: convertChild(node.closingElement), - children: node.children.map(convertChild) - }); + case SyntaxKind.ImportKeyword: + return this.createNode(node, { + type: AST_NODE_TYPES.Import + }); - break; + case SyntaxKind.EmptyStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.EmptyStatement + }); - case SyntaxKind.JsxFragment: - Object.assign(result, { - type: AST_NODE_TYPES.JSXFragment, - openingFragment: convertChild(node.openingFragment), - closingFragment: convertChild(node.closingFragment), - children: node.children.map(convertChild) - }); - break; + case SyntaxKind.DebuggerStatement: + return this.createNode(node, { + type: AST_NODE_TYPES.DebuggerStatement + }); - case SyntaxKind.JsxSelfClosingElement: { - Object.assign(result, { - type: AST_NODE_TYPES.JSXElement, - /** - * Convert SyntaxKind.JsxSelfClosingElement to SyntaxKind.JsxOpeningElement, - * TypeScript does not seem to have the idea of openingElement when tag is self-closing - */ - openingElement: { + // JSX + + case SyntaxKind.JsxElement: + return this.createNode(node, { + type: AST_NODE_TYPES.JSXElement, + openingElement: this.convertChild(node.openingElement), + closingElement: this.convertChild(node.closingElement), + children: node.children.map(el => this.convertChild(el)) + }); + + case SyntaxKind.JsxFragment: + return this.createNode(node, { + type: AST_NODE_TYPES.JSXFragment, + openingFragment: this.convertChild(node.openingFragment), + closingFragment: this.convertChild(node.closingFragment), + children: node.children.map(el => this.convertChild(el)) + }); + + case SyntaxKind.JsxSelfClosingElement: { + return this.createNode(node, { + type: AST_NODE_TYPES.JSXElement, + /** + * Convert SyntaxKind.JsxSelfClosingElement to SyntaxKind.JsxOpeningElement, + * TypeScript does not seem to have the idea of openingElement when tag is self-closing + */ + openingElement: this.createNode(node, { + type: AST_NODE_TYPES.JSXOpeningElement, + typeParameters: node.typeArguments + ? this.convertTypeArgumentsToTypeParameters(node.typeArguments) + : undefined, + selfClosing: true, + name: this.convertTypeScriptJSXTagNameToESTreeName( + node.tagName, + node + ), + attributes: node.attributes.properties.map(el => + this.convertChild(el) + ), + range: getRange(node, this.ast) + }), + closingElement: null, + children: [] + }); + } + + case SyntaxKind.JsxOpeningElement: + return this.createNode(node, { type: AST_NODE_TYPES.JSXOpeningElement, typeParameters: node.typeArguments - ? convertTypeArgumentsToTypeParameters(node.typeArguments) + ? this.convertTypeArgumentsToTypeParameters(node.typeArguments) : undefined, - selfClosing: true, - name: convertTypeScriptJSXTagNameToESTreeName(node.tagName), - attributes: node.attributes.properties.map(convertChild), - range: result.range, - loc: result.loc - }, - closingElement: null, - children: [] - }); - break; - } - - case SyntaxKind.JsxOpeningElement: - Object.assign(result, { - type: AST_NODE_TYPES.JSXOpeningElement, - typeParameters: node.typeArguments - ? convertTypeArgumentsToTypeParameters(node.typeArguments) - : undefined, - selfClosing: false, - name: convertTypeScriptJSXTagNameToESTreeName(node.tagName), - attributes: node.attributes.properties.map(convertChild) - }); - break; + selfClosing: false, + name: this.convertTypeScriptJSXTagNameToESTreeName( + node.tagName, + node + ), + attributes: node.attributes.properties.map(el => + this.convertChild(el) + ) + }); - case SyntaxKind.JsxClosingElement: - Object.assign(result, { - type: AST_NODE_TYPES.JSXClosingElement, - name: convertTypeScriptJSXTagNameToESTreeName(node.tagName) - }); - break; + case SyntaxKind.JsxClosingElement: + return this.createNode(node, { + type: AST_NODE_TYPES.JSXClosingElement, + name: this.convertTypeScriptJSXTagNameToESTreeName(node.tagName, node) + }); - case SyntaxKind.JsxOpeningFragment: - Object.assign(result, { - type: AST_NODE_TYPES.JSXOpeningFragment - }); - break; - case SyntaxKind.JsxClosingFragment: - Object.assign(result, { - type: AST_NODE_TYPES.JSXClosingFragment - }); - break; - - case SyntaxKind.JsxExpression: { - const expression = node.expression - ? convertChild(node.expression) - : { - type: AST_NODE_TYPES.JSXEmptyExpression, - loc: { - start: getLineAndCharacterFor(result.range[0] + 1, ast), - end: { - line: result.loc.end.line, - column: result.loc.end.column - 1 - } - }, - range: [result.range[0] + 1, result.range[1] - 1] - }; - - Object.assign(result, { - type: node.dotDotDotToken - ? AST_NODE_TYPES.JSXSpreadChild - : AST_NODE_TYPES.JSXExpressionContainer, - expression - }); + case SyntaxKind.JsxOpeningFragment: + return this.createNode(node, { + type: AST_NODE_TYPES.JSXOpeningFragment + }); - break; - } + case SyntaxKind.JsxClosingFragment: + return this.createNode(node, { + type: AST_NODE_TYPES.JSXClosingFragment + }); - case SyntaxKind.JsxAttribute: { - const attributeName = convertToken(node.name, ast); - attributeName.type = AST_NODE_TYPES.JSXIdentifier; - attributeName.name = attributeName.value; - delete attributeName.value; + case SyntaxKind.JsxExpression: { + const expression = node.expression + ? this.convertChild(node.expression) + : this.createNode(node, { + type: AST_NODE_TYPES.JSXEmptyExpression, + range: [node.getStart(this.ast) + 1, node.getEnd() - 1] + }); - Object.assign(result, { - type: AST_NODE_TYPES.JSXAttribute, - name: attributeName, - value: convertChild(node.initializer) - }); + if (node.dotDotDotToken) { + return this.createNode(node, { + type: AST_NODE_TYPES.JSXSpreadChild, + expression + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.JSXExpressionContainer, + expression + }); + } + } - break; - } + case SyntaxKind.JsxAttribute: { + const attributeName = this.convertChild(node.name); + attributeName.type = AST_NODE_TYPES.JSXIdentifier; - /** - * The JSX AST changed the node type for string literals - * inside a JSX Element from `Literal` to `JSXText`. We - * provide a flag to support both types until `Literal` - * node type is deprecated in ESLint v5. - */ - case SyntaxKind.JsxText: { - const start = node.getFullStart(); - const end = node.getEnd(); - - const type = additionalOptions.useJSXTextNode - ? AST_NODE_TYPES.JSXText - : AST_NODE_TYPES.Literal; - - Object.assign(result, { - type, - value: ast.text.slice(start, end), - raw: ast.text.slice(start, end) - }); + return this.createNode(node, { + type: AST_NODE_TYPES.JSXAttribute, + name: attributeName, + value: this.convertChild(node.initializer) + }); + } - result.loc = getLocFor(start, end, ast); - result.range = [start, end]; + /** + * The JSX AST changed the node type for string literals + * inside a JSX Element from `Literal` to `JSXText`. We + * provide a flag to support both types until `Literal` + * node type is deprecated in ESLint v5. + */ + case SyntaxKind.JsxText: { + const start = node.getFullStart(); + const end = node.getEnd(); + + if (this.options.useJSXTextNode) { + return this.createNode(node, { + type: AST_NODE_TYPES.JSXText, + value: this.ast.text.slice(start, end), + raw: this.ast.text.slice(start, end), + range: [start, end] + }); + } else { + return this.createNode(node, { + type: AST_NODE_TYPES.Literal, + value: this.ast.text.slice(start, end), + raw: this.ast.text.slice(start, end), + range: [start, end] + }); + } + } - break; - } + case SyntaxKind.JsxSpreadAttribute: + return this.createNode(node, { + type: AST_NODE_TYPES.JSXSpreadAttribute, + argument: this.convertChild(node.expression) + }); - case SyntaxKind.JsxSpreadAttribute: - Object.assign(result, { - type: AST_NODE_TYPES.JSXSpreadAttribute, - argument: convertChild(node.expression) - }); - break; + case SyntaxKind.QualifiedName: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSQualifiedName, + left: this.convertChild(node.left), + right: this.convertChild(node.right) + }); + } - case SyntaxKind.QualifiedName: { - Object.assign(result, { - type: AST_NODE_TYPES.TSQualifiedName, - left: convertChild(node.left), - right: convertChild(node.right) - }); - break; - } + // TypeScript specific - // TypeScript specific + case SyntaxKind.TypeReference: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSTypeReference, + typeName: this.convertType(node.typeName), + typeParameters: node.typeArguments + ? this.convertTypeArgumentsToTypeParameters(node.typeArguments) + : undefined + }); + } - case SyntaxKind.TypeReference: { - Object.assign(result, { - type: AST_NODE_TYPES.TSTypeReference, - typeName: convertChildType(node.typeName), - typeParameters: node.typeArguments - ? convertTypeArgumentsToTypeParameters(node.typeArguments) - : undefined - }); - break; - } + case SyntaxKind.TypeParameter: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSTypeParameter, + name: this.convertType(node.name), + constraint: node.constraint + ? this.convertType(node.constraint) + : undefined, + default: node.default ? this.convertType(node.default) : undefined + }); + } - case SyntaxKind.TypeParameter: { - Object.assign(result, { - type: AST_NODE_TYPES.TSTypeParameter, - name: convertChildType(node.name), - constraint: node.constraint - ? convertChildType(node.constraint) - : undefined, - default: node.default ? convertChildType(node.default) : undefined - }); - break; - } + case SyntaxKind.ThisType: + case SyntaxKind.AnyKeyword: + case SyntaxKind.BigIntKeyword: + case SyntaxKind.BooleanKeyword: + case SyntaxKind.NeverKeyword: + case SyntaxKind.NumberKeyword: + case SyntaxKind.ObjectKeyword: + case SyntaxKind.StringKeyword: + case SyntaxKind.SymbolKeyword: + case SyntaxKind.UnknownKeyword: + case SyntaxKind.VoidKeyword: + case SyntaxKind.UndefinedKeyword: { + return this.createNode(node, { + type: AST_NODE_TYPES[`TS${SyntaxKind[node.kind]}` as AST_NODE_TYPES] + }); + } - case SyntaxKind.ThisType: - case SyntaxKind.AnyKeyword: - case SyntaxKind.BigIntKeyword: - case SyntaxKind.BooleanKeyword: - case SyntaxKind.NeverKeyword: - case SyntaxKind.NumberKeyword: - case SyntaxKind.ObjectKeyword: - case SyntaxKind.StringKeyword: - case SyntaxKind.SymbolKeyword: - case SyntaxKind.UnknownKeyword: - case SyntaxKind.VoidKeyword: - case SyntaxKind.UndefinedKeyword: { - Object.assign(result, { - type: AST_NODE_TYPES[`TS${SyntaxKind[node.kind]}` as AST_NODE_TYPES] - }); - break; - } + case SyntaxKind.NonNullExpression: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSNonNullExpression, + expression: this.convertChild(node.expression) + }); + } - case SyntaxKind.NonNullExpression: { - Object.assign(result, { - type: AST_NODE_TYPES.TSNonNullExpression, - expression: convertChild(node.expression) - }); - break; - } + case SyntaxKind.TypeLiteral: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSTypeLiteral, + members: node.members.map(el => this.convertChild(el)) + }); + } - case SyntaxKind.TypeLiteral: { - Object.assign(result, { - type: AST_NODE_TYPES.TSTypeLiteral, - members: node.members.map(convertChild) - }); - break; - } + case SyntaxKind.ArrayType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSArrayType, + elementType: this.convertType(node.elementType) + }); + } - case SyntaxKind.ArrayType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSArrayType, - elementType: convertChildType(node.elementType) - }); - break; - } + case SyntaxKind.IndexedAccessType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSIndexedAccessType, + objectType: this.convertType(node.objectType), + indexType: this.convertType(node.indexType) + }); + } - case SyntaxKind.IndexedAccessType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSIndexedAccessType, - objectType: convertChildType(node.objectType), - indexType: convertChildType(node.indexType) - }); - break; - } + case SyntaxKind.ConditionalType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSConditionalType, + checkType: this.convertType(node.checkType), + extendsType: this.convertType(node.extendsType), + trueType: this.convertType(node.trueType), + falseType: this.convertType(node.falseType) + }); + } - case SyntaxKind.ConditionalType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSConditionalType, - checkType: convertChildType(node.checkType), - extendsType: convertChildType(node.extendsType), - trueType: convertChildType(node.trueType), - falseType: convertChildType(node.falseType) - }); - break; - } + case SyntaxKind.TypeQuery: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSTypeQuery, + exprName: this.convertType(node.exprName) + }); + } - case SyntaxKind.TypeQuery: { - Object.assign(result, { - type: AST_NODE_TYPES.TSTypeQuery, - exprName: convertChildType(node.exprName) - }); - break; - } + case SyntaxKind.MappedType: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSMappedType, + typeParameter: this.convertType(node.typeParameter) + }); - case SyntaxKind.MappedType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSMappedType, - typeParameter: convertChildType(node.typeParameter) - }); + if (node.readonlyToken) { + if (node.readonlyToken.kind === SyntaxKind.ReadonlyKeyword) { + result.readonly = true; + } else { + result.readonly = getTextForTokenKind(node.readonlyToken.kind) as + | '+' + | '-'; + } + } - if (node.readonlyToken) { - if (node.readonlyToken.kind === SyntaxKind.ReadonlyKeyword) { - result.readonly = true; - } else { - result.readonly = getTextForTokenKind(node.readonlyToken.kind); + if (node.questionToken) { + if (node.questionToken.kind === SyntaxKind.QuestionToken) { + result.optional = true; + } else { + result.optional = getTextForTokenKind(node.questionToken.kind) as + | '+' + | '-'; + } } - } - if (node.questionToken) { - if (node.questionToken.kind === SyntaxKind.QuestionToken) { - result.optional = true; - } else { - result.optional = getTextForTokenKind(node.questionToken.kind); + if (node.type) { + result.typeAnnotation = this.convertType(node.type); } + return result; } - if (node.type) { - result.typeAnnotation = convertChildType(node.type); - } - break; - } + case SyntaxKind.ParenthesizedExpression: + return this.convertChild(node.expression, parent); - case SyntaxKind.ParenthesizedExpression: - return convert({ - node: node.expression, - parent, - ast, - additionalOptions - }); + case SyntaxKind.TypeAliasDeclaration: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSTypeAliasDeclaration, + id: this.convertChild(node.name), + typeAnnotation: this.convertType(node.type) + }); - case SyntaxKind.TypeAliasDeclaration: { - Object.assign(result, { - type: AST_NODE_TYPES.TSTypeAliasDeclaration, - id: convertChild(node.name), - typeAnnotation: convertChildType(node.type) - }); + if (hasModifier(SyntaxKind.DeclareKeyword, node)) { + result.declare = true; + } - if (hasModifier(SyntaxKind.DeclareKeyword, node)) { - result.declare = true; - } + // Process typeParameters + if (node.typeParameters && node.typeParameters.length) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } - // Process typeParameters - if (node.typeParameters && node.typeParameters.length) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); + // check for exports + return fixExports(node, result, this.ast); } - // check for exports - result = fixExports(node, result, ast); - break; - } + case SyntaxKind.MethodSignature: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSMethodSignature, + computed: isComputedProperty(node.name), + key: this.convertChild(node.name), + params: this.convertParameters(node.parameters) + }); - case SyntaxKind.MethodSignature: { - Object.assign(result, { - type: AST_NODE_TYPES.TSMethodSignature, - computed: isComputedProperty(node.name), - key: convertChild(node.name), - params: convertParameters(node.parameters) - }); + if (isOptional(node)) { + result.optional = true; + } - if (isOptional(node)) { - result.optional = true; - } + if (node.type) { + result.returnType = this.convertTypeAnnotation(node.type, node); + } - if (node.type) { - result.returnType = convertTypeAnnotation(node.type); - } + if (hasModifier(SyntaxKind.ReadonlyKeyword, node)) { + result.readonly = true; + } - if (hasModifier(SyntaxKind.ReadonlyKeyword, node)) { - result.readonly = true; - } + if (node.typeParameters) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } - if (node.typeParameters) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } + const accessibility = getTSNodeAccessibility(node); + if (accessibility) { + result.accessibility = accessibility; + } - const accessibility = getTSNodeAccessibility(node); - if (accessibility) { - result.accessibility = accessibility; - } + if (hasModifier(SyntaxKind.ExportKeyword, node)) { + result.export = true; + } - if (hasModifier(SyntaxKind.ExportKeyword, node)) { - result.export = true; + if (hasModifier(SyntaxKind.StaticKeyword, node)) { + result.static = true; + } + return result; } - if (hasModifier(SyntaxKind.StaticKeyword, node)) { - result.static = true; - } - break; - } + case SyntaxKind.PropertySignature: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSPropertySignature, + optional: isOptional(node) || undefined, + computed: isComputedProperty(node.name), + key: this.convertChild(node.name), + typeAnnotation: node.type + ? this.convertTypeAnnotation(node.type, node) + : undefined, + initializer: this.convertChild(node.initializer) || undefined, + readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined, + static: hasModifier(SyntaxKind.StaticKeyword, node) || undefined, + export: hasModifier(SyntaxKind.ExportKeyword, node) || undefined + }); - case SyntaxKind.PropertySignature: { - Object.assign(result, { - type: AST_NODE_TYPES.TSPropertySignature, - optional: isOptional(node) || undefined, - computed: isComputedProperty(node.name), - key: convertChild(node.name), - typeAnnotation: node.type - ? convertTypeAnnotation(node.type) - : undefined, - initializer: convertChild(node.initializer) || undefined, - readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node) || undefined, - static: hasModifier(SyntaxKind.StaticKeyword, node) || undefined, - export: hasModifier(SyntaxKind.ExportKeyword, node) || undefined - }); + const accessibility = getTSNodeAccessibility(node); + if (accessibility) { + result.accessibility = accessibility; + } - const accessibility = getTSNodeAccessibility(node); - if (accessibility) { - result.accessibility = accessibility; + return result; } - break; - } + case SyntaxKind.IndexSignature: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSIndexSignature, + parameters: node.parameters.map(el => this.convertChild(el)) + }); - case SyntaxKind.IndexSignature: { - Object.assign(result, { - type: AST_NODE_TYPES.TSIndexSignature, - parameters: node.parameters.map(convertChild) - }); + if (node.type) { + result.typeAnnotation = this.convertTypeAnnotation(node.type, node); + } - if (node.type) { - result.typeAnnotation = convertTypeAnnotation(node.type); - } + if (hasModifier(SyntaxKind.ReadonlyKeyword, node)) { + result.readonly = true; + } - if (hasModifier(SyntaxKind.ReadonlyKeyword, node)) { - result.readonly = true; - } + const accessibility = getTSNodeAccessibility(node); + if (accessibility) { + result.accessibility = accessibility; + } - const accessibility = getTSNodeAccessibility(node); - if (accessibility) { - result.accessibility = accessibility; - } + if (hasModifier(SyntaxKind.ExportKeyword, node)) { + result.export = true; + } - if (hasModifier(SyntaxKind.ExportKeyword, node)) { - result.export = true; - } + if (hasModifier(SyntaxKind.StaticKeyword, node)) { + result.static = true; + } + return result; + } + case SyntaxKind.ConstructorType: + case SyntaxKind.FunctionType: + case SyntaxKind.ConstructSignature: + case SyntaxKind.CallSignature: { + let type: AST_NODE_TYPES; + switch (node.kind) { + case SyntaxKind.ConstructSignature: + type = AST_NODE_TYPES.TSConstructSignatureDeclaration; + break; + case SyntaxKind.CallSignature: + type = AST_NODE_TYPES.TSCallSignatureDeclaration; + break; + case SyntaxKind.FunctionType: + type = AST_NODE_TYPES.TSFunctionType; + break; + case SyntaxKind.ConstructorType: + default: + type = AST_NODE_TYPES.TSConstructorType; + break; + } + const result = this.createNode< + | es.TSConstructSignatureDeclaration + | es.TSCallSignatureDeclaration + | es.TSFunctionType + | es.TSConstructorType + >(node, { + type: type, + params: this.convertParameters(node.parameters) + }); - if (hasModifier(SyntaxKind.StaticKeyword, node)) { - result.static = true; - } - break; - } - case SyntaxKind.ConstructorType: - case SyntaxKind.FunctionType: - case SyntaxKind.ConstructSignature: - case SyntaxKind.CallSignature: { - let type: AST_NODE_TYPES; - switch (node.kind) { - case SyntaxKind.ConstructSignature: - type = AST_NODE_TYPES.TSConstructSignatureDeclaration; - break; - case SyntaxKind.CallSignature: - type = AST_NODE_TYPES.TSCallSignatureDeclaration; - break; - case SyntaxKind.FunctionType: - type = AST_NODE_TYPES.TSFunctionType; - break; - case SyntaxKind.ConstructorType: - default: - type = AST_NODE_TYPES.TSConstructorType; - break; - } - Object.assign(result, { - type: type, - params: convertParameters(node.parameters) - }); + if (node.type) { + result.returnType = this.convertTypeAnnotation(node.type, node); + } - if (node.type) { - result.returnType = convertTypeAnnotation(node.type); - } + if (node.typeParameters) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } - if (node.typeParameters) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); + return result; } - break; - } + case SyntaxKind.ExpressionWithTypeArguments: { + const result = this.createNode< + es.TSInterfaceHeritage | es.TSClassImplements + >(node, { + type: + parent && parent.kind === SyntaxKind.InterfaceDeclaration + ? AST_NODE_TYPES.TSInterfaceHeritage + : AST_NODE_TYPES.TSClassImplements, + expression: this.convertChild(node.expression) + }); - case SyntaxKind.ExpressionWithTypeArguments: { - Object.assign(result, { - type: - parent && parent.kind === SyntaxKind.InterfaceDeclaration - ? AST_NODE_TYPES.TSInterfaceHeritage - : AST_NODE_TYPES.TSClassImplements, - expression: convertChild(node.expression) - }); + if (node.typeArguments && node.typeArguments.length) { + result.typeParameters = this.convertTypeArgumentsToTypeParameters( + node.typeArguments + ); + } + return result; + } + + case SyntaxKind.InterfaceDeclaration: { + const interfaceHeritageClauses = node.heritageClauses || []; + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSInterfaceDeclaration, + body: this.createNode(node, { + type: AST_NODE_TYPES.TSInterfaceBody, + body: node.members.map(member => this.convertChild(member)), + range: [node.members.pos - 1, node.end] + }), + id: this.convertChild(node.name) + }); - if (node.typeArguments && node.typeArguments.length) { - result.typeParameters = convertTypeArgumentsToTypeParameters( - node.typeArguments - ); - } - break; - } + if (node.typeParameters && node.typeParameters.length) { + result.typeParameters = this.convertTSTypeParametersToTypeParametersDeclaration( + node.typeParameters + ); + } - case SyntaxKind.InterfaceDeclaration: { - const interfaceHeritageClauses = node.heritageClauses || []; + if (interfaceHeritageClauses.length > 0) { + const interfaceExtends = []; + const interfaceImplements = []; - if (node.typeParameters && node.typeParameters.length) { - result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration( - node.typeParameters - ); - } + for (const heritageClause of interfaceHeritageClauses) { + if (heritageClause.token === SyntaxKind.ExtendsKeyword) { + for (const n of heritageClause.types) { + interfaceExtends.push(this.convertChild(n, node)); + } + } else if (heritageClause.token === SyntaxKind.ImplementsKeyword) { + for (const n of heritageClause.types) { + interfaceImplements.push(this.convertChild(n, node)); + } + } + } - const interfaceBodyRange = [node.members.pos - 1, node.end]; + if (interfaceExtends.length) { + result.extends = interfaceExtends; + } - Object.assign(result, { - type: AST_NODE_TYPES.TSInterfaceDeclaration, - body: { - type: AST_NODE_TYPES.TSInterfaceBody, - body: node.members.map(member => convertChild(member)), - range: interfaceBodyRange, - loc: getLocFor(interfaceBodyRange[0], interfaceBodyRange[1], ast) - }, - id: convertChild(node.name) - }); + if (interfaceImplements.length) { + result.implements = interfaceImplements; + } + } + + /** + * Semantically, decorators are not allowed on interface declarations, + * but the TypeScript compiler will parse them and produce a valid AST, + * so we handle them here too. + */ + if (node.decorators) { + result.decorators = node.decorators.map(el => this.convertChild(el)); + } + if (hasModifier(SyntaxKind.AbstractKeyword, node)) { + result.abstract = true; + } + if (hasModifier(SyntaxKind.DeclareKeyword, node)) { + result.declare = true; + } + // check for exports + return fixExports(node, result, this.ast); + } - if (interfaceHeritageClauses.length > 0) { - const interfaceExtends = []; - const interfaceImplements = []; + case SyntaxKind.FirstTypeNode: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSTypePredicate, + parameterName: this.convertChild(node.parameterName), + typeAnnotation: this.convertTypeAnnotation(node.type, node) + }); + /** + * Specific fix for type-guard location data + */ + result.typeAnnotation.loc = result.typeAnnotation.typeAnnotation.loc; + result.typeAnnotation.range = + result.typeAnnotation.typeAnnotation.range; + return result; + } + + case SyntaxKind.ImportType: + return this.createNode(node, { + type: AST_NODE_TYPES.TSImportType, + isTypeOf: !!node.isTypeOf, + parameter: this.convertChild(node.argument), + qualifier: this.convertChild(node.qualifier), + typeParameters: node.typeArguments + ? this.convertTypeArgumentsToTypeParameters(node.typeArguments) + : null + }); - for (const heritageClause of interfaceHeritageClauses) { - if (heritageClause.token === SyntaxKind.ExtendsKeyword) { - for (const n of heritageClause.types) { - interfaceExtends.push(convertChild(n)); - } - } else if (heritageClause.token === SyntaxKind.ImplementsKeyword) { - for (const n of heritageClause.types) { - interfaceImplements.push(convertChild(n)); - } - } + case SyntaxKind.EnumDeclaration: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSEnumDeclaration, + id: this.convertChild(node.name), + members: node.members.map(el => this.convertChild(el)) + }); + // apply modifiers first... + this.applyModifiersToResult(result, node.modifiers); + /** + * Semantically, decorators are not allowed on enum declarations, + * but the TypeScript compiler will parse them and produce a valid AST, + * so we handle them here too. + */ + if (node.decorators) { + result.decorators = node.decorators.map(el => this.convertChild(el)); } + // ...then check for exports + return fixExports(node, result, this.ast); + } - if (interfaceExtends.length) { - result.extends = interfaceExtends; + case SyntaxKind.EnumMember: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSEnumMember, + id: this.convertChild(node.name) + }); + if (node.initializer) { + result.initializer = this.convertChild(node.initializer); } + return result; + } - if (interfaceImplements.length) { - result.implements = interfaceImplements; + case SyntaxKind.ModuleDeclaration: { + const result = this.createNode(node, { + type: AST_NODE_TYPES.TSModuleDeclaration, + id: this.convertChild(node.name) + }); + if (node.body) { + result.body = this.convertChild(node.body); } + // apply modifiers first... + this.applyModifiersToResult(result, node.modifiers); + if (node.flags & ts.NodeFlags.GlobalAugmentation) { + result.global = true; + } + // ...then check for exports + return fixExports(node, result, this.ast); } - /** - * Semantically, decorators are not allowed on interface declarations, - * but the TypeScript compiler will parse them and produce a valid AST, - * so we handle them here too. - */ - if (node.decorators) { - result.decorators = node.decorators.map(convertChild); + // TypeScript specific types + case SyntaxKind.OptionalType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSOptionalType, + typeAnnotation: this.convertType(node.type) + }); } - if (hasModifier(SyntaxKind.AbstractKeyword, node)) { - result.abstract = true; + case SyntaxKind.ParenthesizedType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSParenthesizedType, + typeAnnotation: this.convertType(node.type) + }); } - if (hasModifier(SyntaxKind.DeclareKeyword, node)) { - result.declare = true; + case SyntaxKind.TupleType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSTupleType, + elementTypes: node.elementTypes.map(el => this.convertType(el)) + }); } - // check for exports - result = fixExports(node, result, ast); - - break; - } - - case SyntaxKind.FirstTypeNode: - Object.assign(result, { - type: AST_NODE_TYPES.TSTypePredicate, - parameterName: convertChild(node.parameterName), - typeAnnotation: convertTypeAnnotation(node.type) - }); - /** - * Specific fix for type-guard location data - */ - result.typeAnnotation!.loc = result.typeAnnotation!.typeAnnotation!.loc; - result.typeAnnotation!.range = result.typeAnnotation!.typeAnnotation!.range; - break; - - case SyntaxKind.ImportType: - Object.assign(result, { - type: AST_NODE_TYPES.TSImportType, - isTypeOf: !!node.isTypeOf, - parameter: convertChild(node.argument), - qualifier: convertChild(node.qualifier), - typeParameters: node.typeArguments - ? convertTypeArgumentsToTypeParameters(node.typeArguments) - : null - }); - break; - - case SyntaxKind.EnumDeclaration: { - Object.assign(result, { - type: AST_NODE_TYPES.TSEnumDeclaration, - id: convertChild(node.name), - members: node.members.map(convertChild) - }); - // apply modifiers first... - applyModifiersToResult(node.modifiers); - // ...then check for exports - result = fixExports(node, result, ast); - /** - * Semantically, decorators are not allowed on enum declarations, - * but the TypeScript compiler will parse them and produce a valid AST, - * so we handle them here too. - */ - if (node.decorators) { - result.decorators = node.decorators.map(convertChild); + case SyntaxKind.UnionType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSUnionType, + types: node.types.map(el => this.convertType(el)) + }); } - break; - } - - case SyntaxKind.EnumMember: { - Object.assign(result, { - type: AST_NODE_TYPES.TSEnumMember, - id: convertChild(node.name) - }); - if (node.initializer) { - (result as any).initializer = convertChild(node.initializer); + case SyntaxKind.IntersectionType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSIntersectionType, + types: node.types.map(el => this.convertType(el)) + }); } - break; - } - - case SyntaxKind.AbstractKeyword: { - Object.assign(result, { - type: AST_NODE_TYPES.TSAbstractKeyword - }); - break; - } - - case SyntaxKind.ModuleDeclaration: { - Object.assign(result, { - type: AST_NODE_TYPES.TSModuleDeclaration, - id: convertChild(node.name) - }); - if (node.body) { - result.body = convertChild(node.body); + case SyntaxKind.RestType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSRestType, + typeAnnotation: this.convertType(node.type) + }); } - // apply modifiers first... - applyModifiersToResult(node.modifiers); - if (node.flags & ts.NodeFlags.GlobalAugmentation) { - result.global = true; + case SyntaxKind.AsExpression: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSAsExpression, + expression: this.convertChild(node.expression), + typeAnnotation: this.convertType(node.type) + }); } - // ...then check for exports - result = fixExports(node, result, ast); - break; - } - - // TypeScript specific types - case SyntaxKind.OptionalType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSOptionalType, - typeAnnotation: convertChildType(node.type) - }); - break; - } - case SyntaxKind.ParenthesizedType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSParenthesizedType, - typeAnnotation: convertChildType(node.type) - }); - break; - } - case SyntaxKind.TupleType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSTupleType, - elementTypes: node.elementTypes.map(convertChildType) - }); - break; - } - case SyntaxKind.UnionType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSUnionType, - types: node.types.map(convertChildType) - }); - break; - } - case SyntaxKind.IntersectionType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSIntersectionType, - types: node.types.map(convertChildType) - }); - break; - } - case SyntaxKind.RestType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSRestType, - typeAnnotation: convertChildType(node.type) - }); - break; - } - case SyntaxKind.AsExpression: { - Object.assign(result, { - type: AST_NODE_TYPES.TSAsExpression, - expression: convertChild(node.expression), - typeAnnotation: convertChildType(node.type) - }); - break; - } - case SyntaxKind.InferType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSInferType, - typeParameter: convertChildType(node.typeParameter) - }); - break; - } - case SyntaxKind.LiteralType: { - Object.assign(result, { - type: AST_NODE_TYPES.TSLiteralType, - literal: convertChildType(node.literal) - }); - break; - } - case SyntaxKind.TypeAssertionExpression: { - Object.assign(result, { - type: AST_NODE_TYPES.TSTypeAssertion, - typeAnnotation: convertChildType(node.type), - expression: convertChild(node.expression) - }); - break; - } - case SyntaxKind.ImportEqualsDeclaration: { - Object.assign(result, { - type: AST_NODE_TYPES.TSImportEqualsDeclaration, - id: convertChild(node.name), - moduleReference: convertChild(node.moduleReference), - isExport: hasModifier(SyntaxKind.ExportKeyword, node) - }); - break; - } - case SyntaxKind.ExternalModuleReference: { - Object.assign(result, { - type: AST_NODE_TYPES.TSExternalModuleReference, - expression: convertChild(node.expression) - }); - break; - } - case SyntaxKind.NamespaceExportDeclaration: { - Object.assign(result, { - type: AST_NODE_TYPES.TSNamespaceExportDeclaration, - id: convertChild(node.name) - }); - break; + case SyntaxKind.InferType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSInferType, + typeParameter: this.convertType(node.typeParameter) + }); + } + case SyntaxKind.LiteralType: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSLiteralType, + literal: this.convertType(node.literal) + }); + } + case SyntaxKind.TypeAssertionExpression: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSTypeAssertion, + typeAnnotation: this.convertType(node.type), + expression: this.convertChild(node.expression) + }); + } + case SyntaxKind.ImportEqualsDeclaration: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSImportEqualsDeclaration, + id: this.convertChild(node.name), + moduleReference: this.convertChild(node.moduleReference), + isExport: hasModifier(SyntaxKind.ExportKeyword, node) + }); + } + case SyntaxKind.ExternalModuleReference: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSExternalModuleReference, + expression: this.convertChild(node.expression) + }); + } + case SyntaxKind.NamespaceExportDeclaration: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSNamespaceExportDeclaration, + id: this.convertChild(node.name) + }); + } + case SyntaxKind.AbstractKeyword: { + return this.createNode(node, { + type: AST_NODE_TYPES.TSAbstractKeyword + }); + } + default: + return this.deeplyCopy(node); } - - default: - deeplyCopy(); } - - if (additionalOptions.shouldProvideParserServices) { - tsNodeToESTreeNodeMap.set(node, result); - esTreeNodeToTSNodeMap.set(result, node); - } - - return result; } diff --git a/packages/typescript-estree/src/estree/experimental.ts b/packages/typescript-estree/src/estree/experimental.ts deleted file mode 100644 index 103d9ffd53a5..000000000000 --- a/packages/typescript-estree/src/estree/experimental.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Node, Expression, MethodDefinition, Property, Class } from './spec'; - -/** - * Decorator - */ -export interface Decorator extends Node { - type: 'Decorator'; - expression: Expression; -} - -/** - * MethodDefinition - */ -export interface ExtendedMethodDefinition extends MethodDefinition { - decorators: Decorator[]; -} - -/** - * Property - */ -export interface ExtendedProperty extends Property { - decorators: Decorator[]; -} - -/** - * Class - */ -export interface ExtendedClass extends Class { - decorators: Decorator[]; -} diff --git a/packages/typescript-estree/src/estree/extensions.ts b/packages/typescript-estree/src/estree/extensions.ts deleted file mode 100644 index 5e036917a3b3..000000000000 --- a/packages/typescript-estree/src/estree/extensions.ts +++ /dev/null @@ -1,63 +0,0 @@ -/** - * Based on https://github.com/estree/estree/blob/master/extensions/type-annotations.md - */ - -import { - Identifier, - Function, - ObjectPattern, - ArrayPattern, - RestElement -} from './spec'; - -/** - * Type Annotations - */ - -/** - * Any type annotation. - */ -export interface TypeAnnotation extends Node {} - -/** - * Identifier - * - * The `typeAnnotation` property is used only in the case of variable declarations with type annotations or function arguments with type annotations. - */ -export interface ExtendedIdentifier extends Identifier { - typeAnnotation: TypeAnnotation | null; -} - -/** - * Functions - * - * The `returnType` property is used to specify the type annotation for the return value of the function. - */ -export interface ExtendedFunction extends Function { - returnType: TypeAnnotation | null; -} - -/** - * Patterns - */ - -/** - * ObjectPattern - */ -export interface ExtendedObjectPattern extends ObjectPattern { - typeAnnotation: TypeAnnotation | null; -} - -/** - * ArrayPattern - */ -export interface ExtendedArrayPattern extends ArrayPattern { - typeAnnotation: TypeAnnotation | null; -} - -/** - * RestElement - */ -export interface ExtendedRestElement extends RestElement { - typeAnnotation: TypeAnnotation | null; -} diff --git a/packages/typescript-estree/src/estree/spec.ts b/packages/typescript-estree/src/estree/spec.ts deleted file mode 100644 index 1d2a0a765ee6..000000000000 --- a/packages/typescript-estree/src/estree/spec.ts +++ /dev/null @@ -1,985 +0,0 @@ -/** - * This document specifies the core ESTree AST node types based on: - * - ES5: https://github.com/estree/estree/blob/master/es5.md - * - ES2015: https://github.com/estree/estree/blob/master/es2015.md - * - ES2016: https://github.com/estree/estree/blob/master/es2016.md - * - ES2017: https://github.com/estree/estree/blob/master/es2017.md - * - ES2018: https://github.com/estree/estree/blob/master/es2018.md - */ - -/** - * Node objects - * - * ESTree AST nodes are represented as `Node` objects, which may have any prototype inheritance but which implement the following interface: - */ - -export interface Node { - type: string; - loc: SourceLocation | null; -} - -/** - * The `type` field is a string representing the AST variant type. Each subtype of `Node` is documented below with the specific string of its `type` field. You can use this field to determine which interface a node implements. - * - * The `loc` field represents the source location information of the node. If the node contains no information about the source location, the field is `null`; otherwise it is an object consisting of a start position (the position of the first character of the parsed source region) and an end position (the position of the first character after the parsed source region): - */ -export interface SourceLocation { - source: string | null; - start: Position; - end: Position; -} - -/** - * Each `Position` object consists of a `line` number (1-indexed) and a `column` number (0-indexed): - */ -export interface Position { - line: number; // >= 1 - column: number; // >= 0 -} - -/** - * Identifier - * - * An identifier. Note that an identifier may be an expression or a destructuring pattern. - */ -export interface Identifier extends Expression, Pattern { - type: 'Identifier'; - name: string; -} - -/** - * Literal - * - * A literal token. Note that a literal can be an expression. - */ -export interface Literal extends Expression { - type: 'Literal'; - value: string | boolean | null | number | RegExp; -} - -/** - * RegExpLiteral - * - * The `regex` property allows regexes to be represented in environments that don’t - * support certain flags such as `y` or `u`. In environments that don't support - * these flags `value` will be `null` as the regex can't be represented natively. - */ -export interface RegExpLiteral extends Literal { - regex: { - pattern: string; - flags: string; - }; -} - -/** - * Programs - * - * A complete program source tree. - * - * ES2015+ Parsers must specify sourceType as "module" if the source has been parsed as an ES6 module. Otherwise, sourceType must be "script". - */ -export interface Program extends Node { - type: 'Program'; - body: Array; - sourceType: 'script' | 'module'; -} - -/** - * Functions - * - * A function declaration or expression. - */ -export interface Function extends Node { - id: Identifier | null; - params: Pattern[]; - body: FunctionBody; - generator: boolean; - async: boolean; -} - -/** - * Statements - * - * Any statement. - */ -export interface Statement extends Node {} - -/** - * ExpressionStatement - * - * An expression statement, i.e., a statement consisting of a single expression. - */ -export interface ExpressionStatement extends Statement { - type: 'ExpressionStatement'; - expression: Expression; -} - -/** - * Directive - * - * A directive from the directive prologue of a script or function. - * The `directive` property is the raw string source of the directive without quotes. - */ -export interface Directive extends Node { - type: 'ExpressionStatement'; - expression: Literal; - directive: string; -} - -/** - * BlockStatement - * - * A block statement, i.e., a sequence of statements surrounded by braces. - */ -export interface BlockStatement extends Statement { - type: 'BlockStatement'; - body: Statement[]; -} - -/** - * FunctionBody - * - * The body of a function, which is a block statement that may begin with directives. - */ -export interface FunctionBody extends BlockStatement { - body: Array; -} - -/** - * EmptyStatement - * - * An empty statement, i.e., a solitary semicolon. - */ -export interface EmptyStatement extends Statement { - type: 'EmptyStatement'; -} - -/** - * DebuggerStatement - * - * A `debugger` statement. - */ -export interface DebuggerStatement extends Statement { - type: 'DebuggerStatement'; -} - -/** - * WithStatement - * - * A `with` statement. - */ -export interface WithStatement extends Statement { - type: 'WithStatement'; - object: Expression; - body: Statement; -} - -/** - * Control flow - */ - -/** - * ReturnStatement - * - * A `return` statement. - */ -export interface ReturnStatement extends Statement { - type: 'ReturnStatement'; - argument: Expression | null; -} - -/** - * LabeledStatement - * - * A labeled statement, i.e., a statement prefixed by a `break`/`continue` label. - */ -export interface LabeledStatement extends Statement { - type: 'LabeledStatement'; - label: Identifier; - body: Statement; -} - -/** - * BreakStatement - * - * A `break` statement. - */ -export interface BreakStatement extends Statement { - type: 'BreakStatement'; - label: Identifier | null; -} - -/** - * ContinueStatement - * - * A `continue` statement. - */ -export interface ContinueStatement extends Statement { - type: 'ContinueStatement'; - label: Identifier | null; -} - -/** - * Choice - */ - -/** - * IfStatement - * - * An `if` statement. - */ -export interface IfStatement extends Statement { - type: 'IfStatement'; - test: Expression; - consequent: Statement; - alternate: Statement | null; -} - -/** - * SwitchStatement - * - * A `switch` statement. - */ -export interface SwitchStatement extends Statement { - type: 'SwitchStatement'; - discriminant: Expression; - cases: SwitchCase[]; -} - -/** - * SwitchCase - * - * A `case` (if `test` is an `Expression`) or `default` (if `test === null`) clause in the body of a `switch` statement. - */ -export interface SwitchCase extends Node { - type: 'SwitchCase'; - test: Expression | null; - consequent: Statement[]; -} - -/** - * Exceptions - */ - -/** - * ThrowStatement - * - * A `throw` statement. - */ -export interface ThrowStatement extends Statement { - type: 'ThrowStatement'; - argument: Expression; -} - -/** - * TryStatement - * - * A `try` statement. If `handler` is `null` then `finalizer` must be a `BlockStatement`. - */ -export interface TryStatement extends Statement { - type: 'TryStatement'; - block: BlockStatement; - handler: CatchClause | null; - finalizer: BlockStatement | null; -} - -/** - * CatchClause - * - * A `catch` clause following a `try` block. - * - * The param is null if the catch binding is omitted. E.g., try { foo() } catch { bar() } - */ -export interface CatchClause extends Node { - type: 'CatchClause'; - param: Pattern | null; - body: BlockStatement; -} - -/** - * Loops - */ - -/** - * WhileStatement - * - * A `while` statement. - */ -export interface WhileStatement extends Statement { - type: 'WhileStatement'; - test: Expression; - body: Statement; -} - -/** - * DoWhileStatement - * - * A `do`/`while` statement. - */ -export interface DoWhileStatement extends Statement { - type: 'DoWhileStatement'; - body: Statement; - test: Expression; -} - -/** - * ForStatement - * - * A `for` statement. - */ -export interface ForStatement extends Statement { - type: 'ForStatement'; - init: VariableDeclaration | Expression | null; - test: Expression | null; - update: Expression | null; - body: Statement; -} - -/** - * ForInStatement - * - * A `for`/`in` statement. - */ -export interface ForInStatement extends Statement { - type: 'ForInStatement'; - left: VariableDeclaration | Pattern; - right: Expression; - body: Statement; -} - -/** - * ForOfStatement - * - * A `for`/`of` statement and for-await-of statements, e.g., for await (const x of xs) { - */ -export interface ForOfStatement { - type: 'ForOfStatement'; - left: VariableDeclaration | Pattern; - right: Expression; - body: Statement; - await: boolean; -} - -/** - * Declarations - * - * Any declaration node. Note that declarations are considered statements; this is because declarations can appear in any statement context. - */ -export interface Declaration extends Statement {} - -/** - * FunctionDeclaration - * - * A function declaration. Note that unlike in the parent interface `Function`, the `id` cannot be `null`. - */ -export interface FunctionDeclaration extends Function, Declaration { - type: 'FunctionDeclaration'; - id: Identifier; -} - -/** - * VariableDeclaration - * - * A variable declaration. - */ -export interface VariableDeclaration extends Declaration { - type: 'VariableDeclaration'; - declarations: VariableDeclarator[]; - kind: 'var' | 'let' | 'const'; -} - -/** - * VariableDeclarator - * - * A variable declarator. - */ -export interface VariableDeclarator extends Node { - type: 'VariableDeclarator'; - id: Pattern; - init: Expression | null; -} - -/** - * Expressions - * - * Any expression node. Since the left-hand side of an assignment may be any expression in general, an expression can also be a pattern. - */ -export interface Expression extends Node {} - -/** - * Super - * - * A super pseudo-expression. - */ -export interface Super extends Node { - type: 'Super'; -} - -/** - * ThisExpression - * - * A `this` expression. - */ -export interface ThisExpression extends Expression { - type: 'ThisExpression'; -} - -/** - * SpreadElement - * - * Spread expression, e.g., [head, ...iter, tail], f(head, ...iter, ...tail). - */ -export interface SpreadElement extends Node { - type: 'SpreadElement'; - argument: Expression; -} - -/** - * ArrayExpression - * - * An array expression. - */ -export interface ArrayExpression extends Expression { - type: 'ArrayExpression'; - elements: Array; -} - -/** - * ObjectExpression - * - * An object expression. - * - * Spread properties, e.g., {a: 1, ...obj, b: 2}. - */ -export interface ObjectExpression extends Expression { - type: 'ObjectExpression'; - properties: Array; -} - -/** - * Property - * - * A literal property in an object expression can have either a string or number as its `value`. Ordinary property initializers have a `kind` value `"init"`; getters and setters have the kind values `"get"` and `"set"`, respectively. - */ -export interface Property extends Node { - type: 'Property'; - key: Literal | Identifier | Expression; - value: Expression; - kind: 'init' | 'get' | 'set'; - method: boolean; - shorthand: boolean; - computed: boolean; -} - -/** - * FunctionExpression - * - * A `function` expression. - */ -export interface FunctionExpression extends Function, Expression { - type: 'FunctionExpression'; -} - -/** - * ArrowFunctionExpression - * - * A fat arrow function expression, e.g., let foo = (bar) => { / body / }. - */ -export interface ArrowFunctionExpression extends Expression { - id: Identifier | null; - params: Pattern[]; - type: 'ArrowFunctionExpression'; - body: FunctionBody | Expression; - generator: boolean; - expression: boolean; -} - -/** - * Unary operations - */ - -/** - * UnaryExpression - * - * A unary operator expression. - */ -export interface UnaryExpression extends Expression { - type: 'UnaryExpression'; - operator: UnaryOperator; - prefix: boolean; - argument: Expression; -} - -/** - * UnaryOperator - * - * A unary operator token. - */ -export type UnaryOperator = - | '-' - | '+' - | '!' - | '~' - | 'typeof' - | 'void' - | 'delete'; - -/** - * UpdateExpression - * - * An update (increment or decrement) operator expression. - */ -export interface UpdateExpression extends Expression { - type: 'UpdateExpression'; - operator: UpdateOperator; - argument: Expression; - prefix: boolean; -} - -/** - * UpdateOperator - * - * An update (increment or decrement) operator token. - */ -export type UpdateOperator = '++' | '--'; - -/** - * Binary operations - */ - -/** - * BinaryExpression - * - * A binary operator expression. - */ -export interface BinaryExpression extends Expression { - type: 'BinaryExpression'; - operator: BinaryOperator; - left: Expression; - right: Expression; -} - -/** - * BinaryOperator - * - * A binary operator token. - */ -export type BinaryOperator = - | '==' - | '!=' - | '===' - | '!==' - | '<' - | '<=' - | '>' - | '>=' - | '<<' - | '>>' - | '>>>' - | '+' - | '-' - | '*' - | '/' - | '%' - | '|' - | '^' - | '&' - | 'in' - | 'instanceof' - | '**'; - -/** - * AssignmentExpression - * - * An assignment operator expression. - * - * FROM ESTREE DOCS: - * - * ``` - * FIXME: This describes the Esprima and Acorn behaviors, which is not currently aligned with the SpiderMonkey behavior. - * - * extend interface AssignmentExpression { - * left: Pattern; - * } - * - * Note that pre-ES6 code was allowed to pass references around and so left was much more liberal; an implementation might choose to continue using old definition if it needs to support such legacy code. - * ``` - */ -export interface AssignmentExpression extends Expression { - type: 'AssignmentExpression'; - operator: AssignmentOperator; - left: Pattern | Expression; - right: Expression; -} - -/** - * AssignmentOperator - * - * An assignment operator token. - */ -export type AssignmentOperator = - | '=' - | '+=' - | '-=' - | '*=' - | '/=' - | '%=' - | '<<=' - | '>>=' - | '>>>=' - | '|=' - | '^=' - | '&=' - | '**='; - -/** - * LogicalExpression - * - * A logical operator expression. - */ -export interface LogicalExpression extends Expression { - type: 'LogicalExpression'; - operator: LogicalOperator; - left: Expression; - right: Expression; -} - -/** - * LogicalOperator - * - * A logical operator token. - */ -export type LogicalOperator = '||' | '&&'; - -/** - * MemberExpression - * - * A member expression. If `computed` is `true`, the node corresponds to a computed (`a[b]`) member expression and `property` is an `Expression`. If `computed` is `false`, the node corresponds to a static (`a.b`) member expression and `property` is an `Identifier`. - */ -export interface MemberExpression extends Expression, Pattern { - type: 'MemberExpression'; - object: Expression | Super; - property: Expression; - computed: boolean; -} - -/** - * ConditionalExpression - * - * A conditional expression, i.e., a ternary `?`/`:` expression. - */ -export interface ConditionalExpression extends Expression { - type: 'ConditionalExpression'; - test: Expression; - alternate: Expression; - consequent: Expression; -} - -/** - * CallExpression - * - * A function or method call expression. - */ -export interface CallExpression extends Expression { - type: 'CallExpression'; - callee: Expression | Super; - arguments: Array; -} - -/** - * NewExpression - * - * A `new` expression. - */ -export interface NewExpression extends Expression { - type: 'NewExpression'; - callee: Expression; - arguments: Array; -} - -/** - * SequenceExpression - * - * A sequence expression, i.e., a comma-separated sequence of expressions. - */ -export interface SequenceExpression extends Expression { - type: 'SequenceExpression'; - expressions: Expression[]; -} - -/** - * YieldExpression - * - * A yield expression. - */ -export interface YieldExpression extends Expression { - type: 'YieldExpression'; - argument: Expression | null; - delegate: boolean; -} - -/** - * AwaitExpression - */ -export interface AwaitExpression extends Expression { - type: 'AwaitExpression'; - argument: Expression; -} - -/** - * Template Literals - */ - -/** - * TemplateLiteral - */ -export interface TemplateLiteral extends Expression { - type: 'TemplateLiteral'; - quasis: TemplateElement[]; - expressions: Expression[]; -} - -/** - * TaggedTemplateExpression - */ -export interface TaggedTemplateExpression extends Expression { - type: 'TaggedTemplateExpression'; - tag: Expression; - quasi: TemplateLiteral; -} - -/** - * TemplateElement - * - * If the template literal is tagged and the text has an invalid escape, cooked will be null, e.g., tag`\unicode and \u{55}` - */ -export interface TemplateElement extends Node { - type: 'TemplateElement'; - tail: boolean; - value: { - cooked: string | null; - raw: string; - }; -} - -/** - * Patterns - * - * Destructuring binding and assignment are not part of ES5, but all binding positions accept Pattern to allow for destructuring in ES6. Nevertheless, for ES5, the only Pattern subtype is Identifier. - */ -export interface Pattern extends Node {} - -/** - * AssignmentProperty - */ -export interface AssignmentProperty extends Property { - type: 'Property'; // inherited - value: Pattern; - kind: 'init'; - method: false; -} - -/** - * ObjectPattern - * - * Rest properties, e.g., {a, ...rest} = obj. - */ -export interface ObjectPattern extends Pattern { - type: 'ObjectPattern'; - properties: Array; -} - -/** - * ArrayPattern - */ -export interface ArrayPattern extends Pattern { - type: 'ArrayPattern'; - elements: Array; -} - -/** - * RestElement - */ -export interface RestElement extends Pattern { - type: 'RestElement'; - argument: Pattern; -} - -/** - * AssignmentPattern - */ -export interface AssignmentPattern extends Pattern { - type: 'AssignmentPattern'; - left: Pattern; - right: Expression; -} - -/** - * Classes - */ - -/** - * Class - */ -export interface Class extends Node { - id: Identifier | null; - superClass: Expression | null; - body: ClassBody; -} - -/** - * ClassBody - */ -export interface ClassBody extends Node { - type: 'ClassBody'; - body: MethodDefinition[]; -} - -/** - * MethodDefinition - */ -export interface MethodDefinition extends Node { - type: 'MethodDefinition'; - key: Expression; - value: FunctionExpression; - kind: 'constructor' | 'method' | 'get' | 'set'; - computed: boolean; - static: boolean; -} - -/** - * ClassDeclaration - */ -export interface ClassDeclaration extends Class, Declaration { - type: 'ClassDeclaration'; - id: Identifier; -} - -/** - * ClassExpression - */ -export interface ClassExpression extends Class, Expression { - type: 'ClassExpression'; -} - -/** - * MetaProperty - */ -export interface MetaProperty extends Expression { - type: 'MetaProperty'; - meta: Identifier; - property: Identifier; -} - -/** - * Modules - */ - -/** - * ModuleDeclaration - * - * A module `import` or `export` declaration. - */ -export interface ModuleDeclaration extends Node {} - -/** - * ModuleSpecifier - * - * A specifier in an import or export declaration. - */ -export interface ModuleSpecifier extends Node { - local: Identifier; -} - -/** - * Imports - */ - -/** - * ImportDeclaration - * - * An import declaration, e.g., `import foo from "mod";`. - */ -export interface ImportDeclaration extends ModuleDeclaration { - type: 'ImportDeclaration'; - specifiers: Array< - ImportSpecifier | ImportDefaultSpecifier | ImportNamespaceSpecifier - >; - source: Literal; -} - -/** - * ImportSpecifier - * - * An imported variable binding, e.g., `{foo}` in `import {foo} from "mod"` or `{foo as bar}` in `import {foo as bar} from "mod"`. The `imported` field refers to the name of the export imported from the module. The `local` field refers to the binding imported into the local module scope. If it is a basic named import, such as in `import {foo} from "mod"`, both `imported` and `local` are equivalent `Identifier` nodes; in this case an `Identifier` node representing `foo`. If it is an aliased import, such as in `import {foo as bar} from "mod"`, the `imported` field is an `Identifier` node representing `foo`, and the `local` field is an `Identifier` node representing `bar`. - */ -export interface ImportSpecifier extends ModuleSpecifier { - type: 'ImportSpecifier'; - imported: Identifier; -} - -/** - * ImportDefaultSpecifier - * - * A default import specifier, e.g., `foo` in `import foo from "mod.js"`. - */ -export interface ImportDefaultSpecifier extends ModuleSpecifier { - type: 'ImportDefaultSpecifier'; -} - -/** - * ImportNamespaceSpecifier - * - * A namespace import specifier, e.g., `* as foo` in `import * as foo from "mod.js"`. - */ -export interface ImportNamespaceSpecifier extends ModuleSpecifier { - type: 'ImportNamespaceSpecifier'; -} - -/** - * Exports - */ - -/** - * ExportNamedDeclaration - * - * An export named declaration, e.g., `export {foo, bar};`, `export {foo} from "mod";` or `export var foo = 1;`. - * - * _Note: Having `declaration` populated with non-empty `specifiers` or non-null `source` results in an invalid state._ - */ -export interface ExportNamedDeclaration extends ModuleDeclaration { - type: 'ExportNamedDeclaration'; - declaration: Declaration | null; - specifiers: [ExportSpecifier]; - source: Literal | null; -} - -/** - * ExportSpecifier - * - * An exported variable binding, e.g., `{foo}` in `export {foo}` or `{bar as foo}` in `export {bar as foo}`. The `exported` field refers to the name exported in the module. The `local` field refers to the binding into the local module scope. If it is a basic named export, such as in `export {foo}`, both `exported` and `local` are equivalent `Identifier` nodes; in this case an `Identifier` node representing `foo`. If it is an aliased export, such as in `export {bar as foo}`, the `exported` field is an `Identifier` node representing `foo`, and the `local` field is an `Identifier` node representing `bar`. - */ -export interface ExportSpecifier extends ModuleSpecifier { - type: 'ExportSpecifier'; - exported: Identifier; -} - -/** - * ExportDefaultDeclaration - * - * An export default declaration, e.g., `export default function () {};` or `export default 1;`. - */ -export interface ExportDefaultDeclaration extends ModuleDeclaration { - type: 'ExportDefaultDeclaration'; - declaration: Declaration | Expression; -} - -/** - * ExportAllDeclaration - * - * An export batch declaration, e.g., `export * from "mod";`. - */ -export interface ExportAllDeclaration extends ModuleDeclaration { - type: 'ExportAllDeclaration'; - source: Literal; -} diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index d79353f755e6..aa5a10418c76 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -6,12 +6,7 @@ */ import ts from 'typescript'; import unescape from 'lodash.unescape'; -import { - ESTreeNodeLoc, - ESTreeNode, - ESTreeToken, - LineAndColumnData -} from './temp-types-based-on-js-source'; +import * as es from './typedefs'; import { AST_NODE_TYPES } from './ast-node-types'; const SyntaxKind = ts.SyntaxKind; @@ -102,8 +97,8 @@ const TOKEN_TO_TEXT: { readonly [P in ts.SyntaxKind]?: string } = { /** * Returns true if the given ts.Token is the assignment operator - * @param {ts.Token} operator the operator token - * @returns {boolean} is assignment + * @param operator the operator token + * @returns is assignment */ export function isAssignmentOperator( operator: ts.Token @@ -113,8 +108,8 @@ export function isAssignmentOperator( /** * Returns true if the given ts.Token is a logical operator - * @param {ts.Token} operator the operator token - * @returns {boolean} is a logical operator + * @param operator the operator token + * @returns is a logical operator */ export function isLogicalOperator( operator: ts.Token @@ -124,8 +119,8 @@ export function isLogicalOperator( /** * Returns the string form of the given TSToken SyntaxKind - * @param {number} kind the token's SyntaxKind - * @returns {string} the token applicable token as a string + * @param kind the token's SyntaxKind + * @returns the token applicable token as a string */ export function getTextForTokenKind(kind: ts.SyntaxKind): string | undefined { return TOKEN_TO_TEXT[kind]; @@ -133,8 +128,8 @@ export function getTextForTokenKind(kind: ts.SyntaxKind): string | undefined { /** * Returns true if the given ts.Node is a valid ESTree class member - * @param {ts.Node} node TypeScript AST node - * @returns {boolean} is valid ESTree class member + * @param node TypeScript AST node + * @returns is valid ESTree class member */ export function isESTreeClassMember(node: ts.Node): boolean { return node.kind !== SyntaxKind.SemicolonClassElement; @@ -142,9 +137,9 @@ export function isESTreeClassMember(node: ts.Node): boolean { /** * Checks if a ts.Node has a modifier - * @param {ts.KeywordSyntaxKind} modifierKind TypeScript SyntaxKind modifier - * @param {ts.Node} node TypeScript AST node - * @returns {boolean} has the modifier specified + * @param modifierKind TypeScript SyntaxKind modifier + * @param node TypeScript AST node + * @returns has the modifier specified */ export function hasModifier( modifierKind: ts.KeywordSyntaxKind, @@ -173,8 +168,8 @@ export function getLastModifier(node: ts.Node): ts.Modifier | null { /** * Returns true if the given ts.Token is a comma - * @param {ts.Node} token the TypeScript token - * @returns {boolean} is comma + * @param token the TypeScript token + * @returns is comma */ export function isComma(token: ts.Node): boolean { return token.kind === SyntaxKind.CommaToken; @@ -182,8 +177,8 @@ export function isComma(token: ts.Node): boolean { /** * Returns true if the given ts.Node is a comment - * @param {ts.Node} node the TypeScript node - * @returns {boolean} is comment + * @param node the TypeScript node + * @returns is comment */ export function isComment(node: ts.Node): boolean { return ( @@ -194,8 +189,8 @@ export function isComment(node: ts.Node): boolean { /** * Returns true if the given ts.Node is a JSDoc comment - * @param {ts.Node} node the TypeScript node - * @returns {boolean} is JSDoc comment + * @param node the TypeScript node + * @returns is JSDoc comment */ export function isJSDocComment(node: ts.Node): boolean { return node.kind === SyntaxKind.JSDocComment; @@ -203,8 +198,8 @@ export function isJSDocComment(node: ts.Node): boolean { /** * Returns the binary expression type of the given ts.Token - * @param {ts.Token} operator the operator token - * @returns {string} the binary expression type + * @param operator the operator token + * @returns the binary expression type */ export function getBinaryExpressionType( operator: ts.Token @@ -229,7 +224,7 @@ export function getBinaryExpressionType( export function getLineAndCharacterFor( pos: number, ast: ts.SourceFile -): LineAndColumnData { +): es.LineAndColumnData { const loc = ast.getLineAndCharacterOfPosition(pos); return { line: loc.line + 1, @@ -240,16 +235,16 @@ export function getLineAndCharacterFor( /** * Returns line and column data for the given start and end positions, * for the given AST - * @param {number} start start data - * @param {number} end end data - * @param {ts.SourceFile} ast the AST object - * @returns {ESTreeNodeLoc} the loc data + * @param start start data + * @param end end data + * @param ast the AST object + * @returns the loc data */ export function getLocFor( start: number, end: number, ast: ts.SourceFile -): ESTreeNodeLoc { +): es.SourceLocation { return { start: getLineAndCharacterFor(start, ast), end: getLineAndCharacterFor(end, ast) @@ -258,8 +253,8 @@ export function getLocFor( /** * Check whatever node can contain directive - * @param {ts.Node} node - * @returns {boolean} returns true if node can contain directive + * @param node + * @returns returns true if node can contain directive */ export function canContainDirective(node: ts.Node): boolean { switch (node.kind) { @@ -285,23 +280,19 @@ export function canContainDirective(node: ts.Node): boolean { } /** - * Returns line and column data for the given ts.Node or ts.Token, - * for the given AST - * @param {ts.Node} nodeOrToken the ts.Node or ts.Token - * @param {ts.SourceFile} ast the AST object - * @returns {ESTreeLoc} the loc data + * Returns range for the given ts.Node + * @param node the ts.Node or ts.Token + * @param ast the AST object + * @returns the range data */ -export function getLoc( - nodeOrToken: ts.Node, - ast: ts.SourceFile -): ESTreeNodeLoc { - return getLocFor(nodeOrToken.getStart(ast), nodeOrToken.end, ast); +export function getRange(node: ts.Node, ast: ts.SourceFile): [number, number] { + return [node.getStart(ast), node.getEnd()]; } /** * Returns true if a given ts.Node is a token - * @param {ts.Node} node the ts.Node - * @returns {boolean} is a token + * @param node the ts.Node + * @returns is a token */ export function isToken(node: ts.Node): boolean { return ( @@ -311,8 +302,8 @@ export function isToken(node: ts.Node): boolean { /** * Returns true if a given ts.Node is a JSX token - * @param {ts.Node} node ts.Node to be checked - * @returns {boolean} is a JSX token + * @param node ts.Node to be checked + * @returns is a JSX token */ export function isJSXToken(node: ts.Node): boolean { return ( @@ -322,8 +313,8 @@ export function isJSXToken(node: ts.Node): boolean { /** * Returns the declaration kind of the given ts.Node - * @param {ts.VariableDeclarationList} node TypeScript AST node - * @returns {string} declaration kind + * @param node TypeScript AST node + * @returns declaration kind */ export function getDeclarationKind( node: ts.VariableDeclarationList @@ -339,8 +330,8 @@ export function getDeclarationKind( /** * Gets a ts.Node's accessibility level - * @param {ts.Node} node The ts.Node - * @returns {string | null} accessibility "public", "protected", "private", or null + * @param node The ts.Node + * @returns accessibility "public", "protected", "private", or null */ export function getTSNodeAccessibility( node: ts.Node @@ -368,10 +359,10 @@ export function getTSNodeAccessibility( /** * Finds the next token based on the previous one and its parent * Had to copy this from TS instead of using TS's version because theirs doesn't pass the ast to getChildren - * @param {ts.TextRange} previousToken The previous TSToken - * @param {ts.Node} parent The parent TSNode - * @param {ts.SourceFile} ast The TS AST - * @returns {ts.Node|undefined} the next TSToken + * @param previousToken The previous TSToken + * @param parent The parent TSNode + * @param ast The TS AST + * @returns the next TSToken */ export function findNextToken( previousToken: ts.TextRange, @@ -400,9 +391,9 @@ export function findNextToken( /** * Find the first matching ancestor based on the given predicate function. - * @param {ts.Node} node The current ts.Node - * @param {Function} predicate The predicate function to apply to each checked ancestor - * @returns {ts.Node|undefined} a matching parent ts.Node + * @param node The current ts.Node + * @param predicate The predicate function to apply to each checked ancestor + * @returns a matching parent ts.Node */ export function findFirstMatchingAncestor( node: ts.Node, @@ -419,8 +410,8 @@ export function findFirstMatchingAncestor( /** * Returns true if a given ts.Node has a JSX token within its hierarchy - * @param {ts.Node} node ts.Node to be checked - * @returns {boolean} has JSX ancestor + * @param node ts.Node to be checked + * @returns has JSX ancestor */ export function hasJSXAncestor(node: ts.Node): boolean { return !!findFirstMatchingAncestor(node, isJSXToken); @@ -428,8 +419,8 @@ export function hasJSXAncestor(node: ts.Node): boolean { /** * Unescape the text content of string literals, e.g. & -> & - * @param {string} text The escaped string literal text. - * @returns {string} The unescaped string literal text. + * @param text The escaped string literal text. + * @returns The unescaped string literal text. */ export function unescapeStringLiteralText(text: string): string { return unescape(text); @@ -437,8 +428,8 @@ export function unescapeStringLiteralText(text: string): string { /** * Returns true if a given ts.Node is a computed property - * @param {ts.Node} node ts.Node to be checked - * @returns {boolean} is Computed Property + * @param node ts.Node to be checked + * @returns is Computed Property */ export function isComputedProperty(node: ts.Node): boolean { return node.kind === SyntaxKind.ComputedPropertyName; @@ -446,8 +437,8 @@ export function isComputedProperty(node: ts.Node): boolean { /** * Returns true if a given ts.Node is optional (has QuestionToken) - * @param {ts.Node} node ts.Node to be checked - * @returns {boolean} is Optional + * @param node ts.Node to be checked + * @returns is Optional */ export function isOptional(node: { questionToken?: ts.QuestionToken; @@ -459,16 +450,16 @@ export function isOptional(node: { /** * Fixes the exports of the given ts.Node - * @param {ts.Node} node the ts.Node - * @param {ESTreeNode} result result - * @param {ts.SourceFile} ast the AST - * @returns {ESTreeNode} the ESTreeNode with fixed exports + * @param node the ts.Node + * @param result result + * @param ast the AST + * @returns the ESTreeNode with fixed exports */ -export function fixExports( +export function fixExports( node: ts.Node, - result: ESTreeNode, + result: T, ast: ts.SourceFile -): ESTreeNode { +): es.ExportDefaultDeclaration | es.ExportNamedDeclaration | T { // check for exports if (node.modifiers && node.modifiers[0].kind === SyntaxKind.ExportKeyword) { const exportKeyword = node.modifiers[0]; @@ -480,26 +471,26 @@ export function fixExports( ? findNextToken(nextModifier, ast, ast) : findNextToken(exportKeyword, ast, ast); - result.range[0] = varToken!.getStart(ast); - result.loc = getLocFor(result.range[0], result.range[1], ast); - - const declarationType = declarationIsDefault - ? AST_NODE_TYPES.ExportDefaultDeclaration - : AST_NODE_TYPES.ExportNamedDeclaration; + result.range![0] = varToken!.getStart(ast); + result.loc = getLocFor(result.range![0], result.range![1], ast); - const newResult: any = { - type: declarationType, - declaration: result, - range: [exportKeyword.getStart(ast), result.range[1]], - loc: getLocFor(exportKeyword.getStart(ast), result.range[1], ast) - }; - - if (!declarationIsDefault) { - newResult.specifiers = []; - newResult.source = null; + if (declarationIsDefault) { + return { + type: AST_NODE_TYPES.ExportDefaultDeclaration, + declaration: result as any, + range: [exportKeyword.getStart(ast), result.range![1]], + loc: getLocFor(exportKeyword.getStart(ast), result.range![1], ast) + }; + } else { + return { + type: AST_NODE_TYPES.ExportNamedDeclaration, + declaration: result as any, + range: [exportKeyword.getStart(ast), result.range![1]], + loc: getLocFor(exportKeyword.getStart(ast), result.range![1], ast), + specifiers: [], + source: null + }; } - - return newResult; } return result; @@ -507,10 +498,10 @@ export function fixExports( /** * Returns the type of a given ts.Token - * @param {ts.Token} token the ts.Token - * @returns {string} the token type + * @param token the ts.Token + * @returns the token type */ -export function getTokenType(token: any): string { +export function getTokenType(token: any): es.TokenType { // Need two checks for keywords since some are also identifiers if (token.originalKeywordKind) { switch (token.originalKeywordKind) { @@ -614,18 +605,18 @@ export function getTokenType(token: any): string { /** * Extends and formats a given ts.Token, for a given AST - * @param {ts.Node} token the ts.Token - * @param {ts.SourceFile} ast the AST object - * @returns {ESTreeToken} the converted ESTreeToken + * @param token the ts.Token + * @param ast the AST object + * @returns the converted es.Token */ -export function convertToken(token: ts.Node, ast: ts.SourceFile): ESTreeToken { +export function convertToken(token: ts.Node, ast: ts.SourceFile): es.Token { const start = token.kind === SyntaxKind.JsxText ? token.getFullStart() : token.getStart(ast), end = token.getEnd(), value = ast.text.slice(start, end), - newToken: any = { + newToken: es.Token = { type: getTokenType(token), value, range: [start, end], @@ -644,14 +635,13 @@ export function convertToken(token: ts.Node, ast: ts.SourceFile): ESTreeToken { /** * Converts all tokens for the given AST - * @param {ts.SourceFile} ast the AST object - * @returns {ESTreeToken[]} the converted ESTreeTokens + * @param ast the AST object + * @returns the converted Tokens */ -export function convertTokens(ast: ts.SourceFile): ESTreeToken[] { - const result: ESTreeToken[] = []; +export function convertTokens(ast: ts.SourceFile): es.Token[] { + const result: es.Token[] = []; /** - * @param {ts.Node} node the ts.Node - * @returns {void} + * @param node the ts.Node */ function walk(node: ts.Node): void { // TypeScript generates tokens for types in JSDoc blocks. Comment tokens @@ -676,10 +666,10 @@ export function convertTokens(ast: ts.SourceFile): ESTreeToken[] { /** * Get container token node between range - * @param {ts.SourceFile} ast the AST object - * @param {number} start The index at which the comment starts. - * @param {number} end The index at which the comment ends. - * @returns {ts.Node} typescript container token + * @param ast the AST object + * @param start The index at which the comment starts. + * @param end The index at which the comment ends. + * @returns typescript container token * @private */ export function getNodeContainer( @@ -690,8 +680,7 @@ export function getNodeContainer( let container: ts.Node | null = null; /** - * @param {ts.Node} node the ts.Node - * @returns {void} + * @param node the ts.Node */ function walk(node: ts.Node): void { const nodeStart = node.pos; @@ -711,10 +700,10 @@ export function getNodeContainer( } /** - * @param {ts.SourceFile} ast the AST object - * @param {number} start the index at which the error starts - * @param {string} message the error message - * @returns {Object} converted error object + * @param ast the AST object + * @param start the index at which the error starts + * @param message the error message + * @returns converted error object */ export function createError( ast: ts.SourceFile, @@ -731,8 +720,8 @@ export function createError( } /** - * @param {ts.Node} n the TSNode - * @param {ts.SourceFile} ast the TS AST + * @param n the TSNode + * @param ast the TS AST */ export function nodeHasTokens(n: ts.Node, ast: ts.SourceFile) { // If we have a token or node that has a non-zero width, it must have tokens. @@ -746,9 +735,8 @@ export function nodeHasTokens(n: ts.Node, ast: ts.SourceFile) { * Like `forEach`, but suitable for use with numbers and strings (which may be falsy). * @template T * @template U - * @param {ReadonlyArray|undefined} array - * @param {(element: T, index: number) => (U|undefined)} callback - * @returns {U|undefined} + * @param array + * @param callback */ export function firstDefined( array: ReadonlyArray | undefined, diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts new file mode 100644 index 000000000000..a838db4af139 --- /dev/null +++ b/packages/typescript-estree/src/parser-options.ts @@ -0,0 +1,35 @@ +import { Token, Comment } from './typedefs'; + +export interface Extra { + errorOnUnknownASTType: boolean; + errorOnTypeScriptSyntacticAndSemanticIssues: boolean; + useJSXTextNode: boolean; + tokens: null | Token[]; + comment: boolean; + code: string; + range: boolean; + loc: boolean; + comments: Comment[]; + strict: boolean; + jsx: boolean; + log: Function; + projects: string[]; + tsconfigRootDir: string; + extraFileExtensions: string[]; +} + +export interface ParserOptions { + range?: boolean; + loc?: boolean; + tokens?: boolean; + comment?: boolean; + jsx?: boolean; + errorOnUnknownASTType?: boolean; + errorOnTypeScriptSyntacticAndSemanticIssues?: boolean; + useJSXTextNode?: boolean; + loggerFn?: Function | false; + project?: string | string[]; + filePath?: string; + tsconfigRootDir?: string; + extraFileExtensions?: string[]; +} diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index 225899a106f9..3c9680df06d4 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -13,14 +13,9 @@ import semver from 'semver'; import ts from 'typescript'; import convert from './ast-converter'; import { convertError } from './convert'; -import { Program } from './estree/spec'; import { firstDefined } from './node-utils'; -import { - ESTreeComment, - ESTreeToken, - Extra, - ParserOptions -} from './temp-types-based-on-js-source'; +import * as es from './typedefs'; +import { Extra, ParserOptions } from './parser-options'; import { getFirstSemanticOrSyntacticError } from './semantic-errors'; const packageJSON = require('../package.json'); @@ -49,7 +44,6 @@ function getFileName({ jsx }: { jsx?: boolean }) { /** * Resets the extra config object - * @returns {void} */ function resetExtra(): void { extra = { @@ -72,9 +66,9 @@ function resetExtra(): void { } /** - * @param {string} code The code of the file being linted - * @param {Object} options The config object - * @returns {{ast: ts.SourceFile, program: ts.Program} | undefined} If found, returns the source file corresponding to the code and the containing program + * @param code The code of the file being linted + * @param options The config object + * @returns If found, returns the source file corresponding to the code and the containing program */ function getASTFromProject(code: string, options: ParserOptions) { return firstDefined( @@ -93,9 +87,9 @@ function getASTFromProject(code: string, options: ParserOptions) { } /** - * @param {string} code The code of the file being linted - * @param {Object} options The config object - * @returns {{ast: ts.SourceFile, program: ts.Program} | undefined} If found, returns the source file corresponding to the code and the containing program + * @param code The code of the file being linted + * @param options The config object + * @returns If found, returns the source file corresponding to the code and the containing program */ function getASTAndDefaultProject(code: string, options: ParserOptions) { const fileName = options.filePath || getFileName(options); @@ -105,8 +99,8 @@ function getASTAndDefaultProject(code: string, options: ParserOptions) { } /** - * @param {string} code The code of the file being linted - * @returns {{ast: ts.SourceFile, program: ts.Program}} Returns a new source file and program corresponding to the linted code + * @param code The code of the file being linted + * @returns Returns a new source file and program corresponding to the linted code */ function createNewProgram(code: string) { const FILENAME = getFileName(extra); @@ -162,10 +156,10 @@ function createNewProgram(code: string) { } /** - * @param {string} code The code of the file being linted - * @param {Object} options The config object - * @param {boolean} shouldProvideParserServices True iff the program should be attempted to be calculated from provided tsconfig files - * @returns {{ast: ts.SourceFile, program: ts.Program}} Returns a source file and program corresponding to the linted code + * @param code The code of the file being linted + * @param options The config object + * @param shouldProvideParserServices True iff the program should be attempted to be calculated from provided tsconfig files + * @returns Returns a source file and program corresponding to the linted code */ function getProgramAndAST( code: string, @@ -275,10 +269,10 @@ function warnAboutTSVersion(): void { // Parser //------------------------------------------------------------------------------ -type AST = Program & +type AST = es.Program & (T['range'] extends true ? { range: [number, number] } : {}) & - (T['tokens'] extends true ? { tokens: ESTreeToken[] } : {}) & - (T['comment'] extends true ? { comments: ESTreeComment[] } : {}); + (T['tokens'] extends true ? { tokens: es.Token[] } : {}) & + (T['comment'] extends true ? { comments: es.Comment[] } : {}); interface ParseAndGenerateServicesResult { ast: AST; @@ -342,7 +336,7 @@ export function parse( * Convert the TypeScript AST to an ESTree-compatible one */ const { estree } = convert(ast, extra, false); - return estree; + return estree as AST; } export function parseAndGenerateServices< @@ -406,7 +400,7 @@ export function parseAndGenerateServices< * Return the converted AST and additional parser services */ return { - ast: estree, + ast: estree as AST, services: { program: shouldProvideParserServices ? program : undefined, esTreeNodeToTSNodeMap: diff --git a/packages/typescript-estree/src/temp-types-based-on-js-source.ts b/packages/typescript-estree/src/temp-types-based-on-js-source.ts deleted file mode 100644 index a2234fc1308a..000000000000 --- a/packages/typescript-estree/src/temp-types-based-on-js-source.ts +++ /dev/null @@ -1,106 +0,0 @@ -/** - * NOTE: The following types are inferred from usage within the original JavaScript source. - * - * They will be gradually replaced with the more accurate types derived from the ESTree spec, and its - * applicable extensions - */ -import { AST_NODE_TYPES } from './ast-node-types'; - -export interface ESTreeToken { - type: AST_NODE_TYPES; - range: [number, number]; - loc: ESTreeNodeLoc; - value: string; - regex?: { - pattern: string; - flags: string; - }; - object?: any; - property?: any; - name?: any; -} - -export interface ESTreeNode { - type: AST_NODE_TYPES; - range: [number, number]; - loc: ESTreeNodeLoc; - declaration?: ESTreeNode; - specifiers?: (ESTreeNode | null)[]; - source?: any; - typeAnnotation?: ESTreeNode | null; - typeParameters?: ESTreeNode | null; - id?: ESTreeNode | null; - raw?: string; - value?: string; - expression?: ESTreeNode | null; - decorators?: (ESTreeNode | null)[]; - implements?: (ESTreeNode | null)[]; - extends?: (ESTreeNode | null)[]; - const?: boolean; - declare?: boolean; - global?: boolean; - modifiers?: any; - body?: any; - params?: any; - accessibility?: 'public' | 'protected' | 'private'; - readonly?: boolean | string; - static?: boolean; - export?: boolean; - parameter?: any; - abstract?: boolean; - typeName?: ESTreeNode | null; - directive?: string; - returnType?: ESTreeNode; - optional?: boolean | string; -} - -export interface ESTreeComment { - type: 'Block' | 'Line'; - range?: [number, number]; - loc?: ESTreeNodeLoc; - value: string; -} - -export interface LineAndColumnData { - line: number; - column: number; -} - -export interface ESTreeNodeLoc { - start: LineAndColumnData; - end: LineAndColumnData; -} - -export interface Extra { - errorOnUnknownASTType: boolean; - errorOnTypeScriptSyntacticAndSemanticIssues: boolean; - useJSXTextNode: boolean; - tokens: null | ESTreeToken[]; - comment: boolean; - code: string; - range: boolean; - loc: boolean; - comments: ESTreeComment[]; - strict: boolean; - jsx: boolean; - log: Function; - projects: string[]; - tsconfigRootDir: string; - extraFileExtensions: string[]; -} - -export interface ParserOptions { - range?: boolean; - loc?: boolean; - tokens?: boolean; - comment?: boolean; - jsx?: boolean; - errorOnUnknownASTType?: boolean; - errorOnTypeScriptSyntacticAndSemanticIssues?: boolean; - useJSXTextNode?: boolean; - loggerFn?: Function | false; - project?: string | string[]; - filePath?: string; - tsconfigRootDir?: string; - extraFileExtensions?: string[]; -} diff --git a/packages/typescript-estree/src/tsconfig-parser.ts b/packages/typescript-estree/src/tsconfig-parser.ts index 2212c4d0b1d0..3d68a034c16e 100644 --- a/packages/typescript-estree/src/tsconfig-parser.ts +++ b/packages/typescript-estree/src/tsconfig-parser.ts @@ -2,7 +2,7 @@ import path from 'path'; import ts from 'typescript'; -import { Extra } from './temp-types-based-on-js-source'; +import { Extra } from './parser-options'; //------------------------------------------------------------------------------ // Environment calculation @@ -10,7 +10,6 @@ import { Extra } from './temp-types-based-on-js-source'; /** * Default compiler options for program generation from single root file - * @type {ts.CompilerOptions} */ const defaultCompilerOptions: ts.CompilerOptions = { allowNonTsExtensions: true, @@ -19,7 +18,6 @@ const defaultCompilerOptions: ts.CompilerOptions = { /** * Maps tsconfig paths to their corresponding file contents and resulting watches - * @type {Map>} */ const knownWatchProgramMap = new Map< string, @@ -29,13 +27,11 @@ const knownWatchProgramMap = new Map< /** * Maps file paths to their set of corresponding watch callbacks * There may be more than one per file if a file is shared between projects - * @type {Map} */ const watchCallbackTrackingMap = new Map(); /** * Holds information about the file currently being linted - * @type {{code: string, filePath: string}} */ const currentLintOperationState = { code: '', @@ -44,8 +40,7 @@ const currentLintOperationState = { /** * Appropriately report issues found when reading a config file - * @param {ts.Diagnostic} diagnostic The diagnostic raised when creating a program - * @returns {void} + * @param diagnostic The diagnostic raised when creating a program */ function diagnosticReporter(diagnostic: ts.Diagnostic): void { throw new Error( @@ -57,11 +52,11 @@ const noopFileWatcher = { close: () => {} }; /** * Calculate project environments using options provided by consumer and paths from config - * @param {string} code The code being linted - * @param {string} filePath The path of the file being parsed - * @param {string} extra.tsconfigRootDir The root directory for relative tsconfig paths - * @param {string[]} extra.project Provided tsconfig paths - * @returns {ts.Program[]} The programs corresponding to the supplied tsconfig paths + * @param code The code being linted + * @param filePath The path of the file being parsed + * @param extra.tsconfigRootDir The root directory for relative tsconfig paths + * @param extra.project Provided tsconfig paths + * @returns The programs corresponding to the supplied tsconfig paths */ export function calculateProjectParserOptions( code: string, @@ -187,9 +182,9 @@ export function calculateProjectParserOptions( * Create program from single root file. Requires a single tsconfig to be specified. * @param code The code being linted * @param filePath The file being linted - * @param {string} extra.tsconfigRootDir The root directory for relative tsconfig paths - * @param {string[]} extra.project Provided tsconfig paths - * @returns {ts.Program} The program containing just the file being linted and associated library files + * @param extra.tsconfigRootDir The root directory for relative tsconfig paths + * @param extra.project Provided tsconfig paths + * @returns The program containing just the file being linted and associated library files */ export function createProgram(code: string, filePath: string, extra: Extra) { if (!extra.projects || extra.projects.length !== 1) { diff --git a/packages/typescript-estree/src/typedefs.ts b/packages/typescript-estree/src/typedefs.ts new file mode 100644 index 000000000000..140ed6e09a49 --- /dev/null +++ b/packages/typescript-estree/src/typedefs.ts @@ -0,0 +1,1409 @@ +import { AST_NODE_TYPES } from './ast-node-types'; + +export interface LineAndColumnData { + /** + * Line number (1-indexed) + */ + line: number; + /** + * Column number on the line (0-indexed) + */ + column: number; +} +export interface SourceLocation { + /** + * The position of the first character of the parsed source region + */ + start: LineAndColumnData; + /** + * The position of the first character after the parsed source region + */ + end: LineAndColumnData; +} + +export interface BaseNode { + /** + * The source location information of the node. + */ + loc: SourceLocation; + /** + * An array of two numbers. + * Both numbers are a 0-based index which is the position in the array of source code characters. + * The first is the start position of the node, the second is the end position of the node. + */ + range: [number, number]; + /** + * The parent node of the current node + */ + parent?: Node; + + // every node *will* have a type, but let the nodes define their own exact string + // type: string; + + // we don't ever set this from within ts-estree + // source?: string | null; +} + +/* + * Token and Comment are pseudo-nodes to represent pieces of source code + * + * NOTE: + * They are not included in the `Node` union below on purpose because they + * are not ever included as part of the standard AST tree. + */ + +export type TokenType = + | 'Boolean' + | 'Identifier' + | 'JSXIdentifier' + | 'JSXMemberExpression' + | 'JSXText' + | 'Keyword' + | 'Null' + | 'Numeric' + | 'Punctuator' + | 'RegularExpression' + | 'String' + | 'Template'; + +export interface Token extends BaseNode { + type: TokenType; + value: string; + regex?: { + pattern: string; + flags: string; + }; +} +export interface Comment extends BaseNode { + type: 'Line' | 'Block'; + value: string; +} + +export type OptionalRangeAndLoc = Pick< + T, + Exclude +> & { + range?: [number, number]; + loc?: SourceLocation; +}; + +// Every single valid AST Node +// Please keep it sorted alphabetically. +export type Node = + | ArrayExpression + | ArrayPattern + | ArrowFunctionExpression + | AssignmentExpression + | AssignmentPattern + | AwaitExpression + | BigIntLiteral + | BinaryExpression + | BlockStatement + | BreakStatement + | CallExpression + | CatchClause + | ClassBody + | ClassDeclaration + | ClassExpression + | ClassProperty + | ConditionalExpression + | ContinueStatement + | DebuggerStatement + | Decorator + | DoWhileStatement + | EmptyStatement + | ExportAllDeclaration + | ExportDefaultDeclaration + | ExportNamedDeclaration + | ExportSpecifier + | ExpressionStatement + | ForInStatement + | ForOfStatement + | ForStatement + | FunctionDeclaration + | FunctionExpression + | Identifier + | IfStatement + | Import + | ImportDeclaration + | ImportDefaultSpecifier + | ImportNamespaceSpecifier + | ImportSpecifier + | JSXAttribute + | JSXClosingElement + | JSXClosingFragment + | JSXElement + | JSXEmptyExpression + | JSXExpressionContainer + | JSXFragment + | JSXIdentifier + | JSXOpeningElement + | JSXOpeningFragment + | JSXSpreadAttribute + | JSXSpreadChild + | JSXText + | LabeledStatement + | Literal + | LogicalExpression + | MemberExpression + | MetaProperty + | MethodDefinition + | NewExpression + | ObjectExpression + | ObjectPattern + | Program + | Property + | RestElement + | ReturnStatement + | SequenceExpression + | SpreadElement + | Super + | SwitchCase + | SwitchStatement + | TaggedTemplateExpression + | TemplateElement + | TemplateLiteral + | ThisExpression + | ThrowStatement + | TryStatement + | TSAbstractClassProperty + | TSAbstractKeyword + | TSAbstractMethodDefinition + | TSAnyKeyword + | TSArrayType + | TSAsExpression + | TSAsyncKeyword + | TSBigIntKeyword + | TSBooleanKeyword + | TSCallSignatureDeclaration + | TSClassImplements + | TSConditionalType + | TSConstructorType + | TSConstructSignatureDeclaration + | TSDeclareFunction + | TSDeclareKeyword + | TSEnumDeclaration + | TSEnumMember + | TSExportAssignment + | TSExportKeyword + | TSExternalModuleReference + | TSFunctionType + | TSImportEqualsDeclaration + | TSImportType + | TSIndexedAccessType + | TSIndexSignature + | TSInferType + | TSInterfaceDeclaration + | TSInterfaceBody + | TSInterfaceHeritage + | TSIntersectionType + | TSLiteralType + | TSMappedType + | TSMethodSignature + | TSModuleBlock + | TSModuleDeclaration + | TSNamespaceExportDeclaration + | TSNeverKeyword + | TSNonNullExpression + | TSNullKeyword + | TSNumberKeyword + | TSObjectKeyword + | TSOptionalType + | TSParameterProperty + | TSParenthesizedType + | TSPropertySignature + | TSPublicKeyword + | TSPrivateKeyword + | TSProtectedKeyword + | TSQualifiedName + | TSReadonlyKeyword + | TSRestType + | TSStaticKeyword + | TSStringKeyword + | TSSymbolKeyword + | TSThisType + | TSTupleType + | TSTypeAliasDeclaration + | TSTypeAnnotation + | TSTypeAssertion + | TSTypeLiteral + | TSTypeOperator + | TSTypeParameter + | TSTypeParameterDeclaration + | TSTypeParameterInstantiation + | TSTypePredicate + | TSTypeQuery + | TSTypeReference + | TSUndefinedKeyword + | TSUnionType + | TSUnknownKeyword + | TSVoidKeyword + | UpdateExpression + | UnaryExpression + | VariableDeclaration + | VariableDeclarator + | WhileStatement + | WithStatement + | YieldExpression; + +////////// +// Reusable Unions +// These are based off of types used in the Typescript AST definitions +// **Ensure you sort the union members alphabetically** +////////// + +export type Accessibility = 'public' | 'protected' | 'private'; +export type BindingPattern = ArrayPattern | ObjectPattern; +export type BindingName = BindingPattern | Identifier; +export type ClassElement = + | ClassProperty + | FunctionExpression + | MethodDefinition + | TSAbstractClassProperty + | TSAbstractMethodDefinition + | TSIndexSignature; +export type DeclarationStatement = + | ClassDeclaration + | ClassExpression + | ExportAllDeclaration + | ExportNamedDeclaration + | FunctionDeclaration + | TSDeclareFunction + | TSImportEqualsDeclaration + | TSInterfaceDeclaration + | TSModuleDeclaration + | TSNamespaceExportDeclaration + | TSTypeAliasDeclaration + | TSEnumDeclaration; +export type EntityName = Identifier | TSQualifiedName; +export type ExportDeclaration = + | ClassDeclaration + | ClassExpression + | FunctionDeclaration + | TSDeclareFunction + | TSEnumDeclaration + | TSInterfaceDeclaration + | TSModuleDeclaration + | TSTypeAliasDeclaration + | VariableDeclarator; +export type Expression = + | ArrowFunctionExpression + | AssignmentExpression + | BinaryExpression + | ConditionalExpression + | JSXClosingElement + | JSXClosingFragment + | JSXExpressionContainer + | JSXOpeningElement + | JSXOpeningFragment + | JSXSpreadChild + | LogicalExpression + | RestElement + | SequenceExpression + | SpreadElement + | TSAsExpression + | TSUnaryExpression + | YieldExpression; +export type ExpressionWithTypeArguments = + | TSClassImplements + | TSInterfaceHeritage; +export type ForInitialiser = Expression | VariableDeclaration; +export type ImportClause = + | ImportDefaultSpecifier + | ImportNamespaceSpecifier + | ImportSpecifier; +export type IterationStatement = + | DoWhileStatement + | ForInStatement + | ForOfStatement + | ForStatement + | WhileStatement; +export type JSXChild = JSXElement | JSXExpression | JSXFragment | JSXText; +export type JSXExpression = + | JSXEmptyExpression + | JSXSpreadChild + | JSXExpressionContainer; +export type JSXTagNameExpression = JSXIdentifier | JSXMemberExpression; +export type LeftHandSideExpression = + | CallExpression + | ClassExpression + | ClassDeclaration + | FunctionExpression + | LiteralExpression + | MemberExpression + | PrimaryExpression + | TaggedTemplateExpression + | TSNonNullExpression; +export type LiteralExpression = BigIntLiteral | Literal | TemplateLiteral; +export type Modifier = + | TSAbstractKeyword + | TSAsyncKeyword + | TSDeclareKeyword + | TSExportKeyword + | TSPublicKeyword + | TSPrivateKeyword + | TSProtectedKeyword + | TSReadonlyKeyword + | TSStaticKeyword; +export type ObjectLiteralElementLike = + | MethodDefinition + | Property + | RestElement + | SpreadElement + | TSAbstractMethodDefinition; +export type Parameter = AssignmentPattern | RestElement | TSParameterProperty; +export type PrimaryExpression = + | ArrayExpression + | ArrayPattern + | ClassExpression + | FunctionExpression + | Identifier + | Import + | JSXElement + | JSXFragment + | JSXOpeningElement + | Literal + | LiteralExpression + | MetaProperty + | ObjectExpression + | ObjectPattern + | Super + | TemplateLiteral + | ThisExpression + | TSNullKeyword; +export type PropertyName = Identifier | Literal; +export type Statement = + | BlockStatement + | BreakStatement + | ContinueStatement + | DebuggerStatement + | DeclarationStatement + | EmptyStatement + | ExpressionStatement + | IfStatement + | IterationStatement + | ImportDeclaration + | LabeledStatement + | TSModuleBlock + | ReturnStatement + | SwitchStatement + | ThrowStatement + | TryStatement + | VariableDeclaration + | WithStatement; +export type TypeElement = + | TSCallSignatureDeclaration + | TSConstructSignatureDeclaration + | TSIndexSignature + | TSMethodSignature + | TSPropertySignature; +export type TypeNode = + | ThisExpression + | TSAnyKeyword + | TSArrayType + | TSBigIntKeyword + | TSBooleanKeyword + | TSClassImplements + | TSConditionalType + | TSConstructorType + | TSFunctionType + | TSImportType + | TSIndexedAccessType + | TSInferType + | TSInterfaceHeritage + | TSIntersectionType + | TSLiteralType + | TSMappedType + | TSNeverKeyword + | TSNullKeyword + | TSNumberKeyword + | TSObjectKeyword + | TSOptionalType + | TSParenthesizedType + | TSRestType + | TSStringKeyword + | TSSymbolKeyword + | TSThisType + | TSTupleType + | TSTypeLiteral + | TSTypeOperator + | TSTypeReference + | TSTypePredicate + | TSTypeQuery + | TSUndefinedKeyword + | TSUnionType + | TSUnknownKeyword + | TSVoidKeyword; +export type TSUnaryExpression = + | AwaitExpression + | LeftHandSideExpression + | TSTypeAssertion + | UnaryExpression + | UpdateExpression; + +/////////////// +// Base, common types +// **Ensure you sort the interfaces alphabetically** +/////////////// + +interface BinaryExpressionBase extends BaseNode { + operator: string; + left: Expression; + right: Expression; +} + +interface ClassDeclarationBase extends BaseNode { + typeParameters?: TSTypeParameterDeclaration; + superTypeParameters?: TSTypeParameterInstantiation; + id?: Identifier; + body: ClassBody; + superClass?: LeftHandSideExpression; + implements?: ExpressionWithTypeArguments[]; + abstract?: boolean; + declare?: boolean; + decorators?: Decorator[]; +} + +interface ClassPropertyBase extends BaseNode { + key: PropertyName; + value: Expression; + computed: boolean; + static: boolean; + readonly?: boolean; + decorators?: Decorator[]; + accessibility?: Accessibility; + optional?: boolean; + definite?: boolean; + typeAnnotation?: TSTypeAnnotation; +} + +interface FunctionDeclarationBase extends BaseNode { + id: Identifier | null; + generator: boolean; + expression: boolean; + async: boolean; + params: Parameter[]; + body?: BlockStatement | null; + returnType?: TSTypeAnnotation; + typeParameters?: TSTypeParameterDeclaration; + declare?: boolean; +} + +interface FunctionSignatureBase extends BaseNode { + params: Parameter[]; + returnType?: TSTypeAnnotation; + typeParameters?: TSTypeParameterDeclaration; +} + +interface LiteralBase extends BaseNode { + raw: string; + value: boolean | number | RegExp | string | null; + regex?: { + pattern: string; + flags: string; + }; +} + +interface MethodDefinitionBase extends BaseNode { + key: PropertyName; + value: FunctionExpression; + computed: boolean; + static: boolean; + kind: 'method' | 'get' | 'set' | 'constructor'; + decorators?: Decorator[]; + accessibility?: Accessibility; + typeParameters?: TSTypeParameterDeclaration; +} + +interface TSHeritageBase extends BaseNode { + expression: Expression; + typeParameters?: TSTypeParameterInstantiation; +} + +interface UnaryExpressionBase extends BaseNode { + operator: string; + prefix: boolean; + argument: LeftHandSideExpression | Literal | UnaryExpression; +} + +/////////////// +// Typescript ESTree Nodes +// **Ensure you sort the interfaces alphabetically** +/////////////// + +export interface ArrayExpression extends BaseNode { + type: AST_NODE_TYPES.ArrayExpression; + elements: Expression[]; +} + +export interface ArrayPattern extends BaseNode { + type: AST_NODE_TYPES.ArrayPattern; + elements: Expression[]; + typeAnnotation?: TSTypeAnnotation; + optional?: boolean; +} + +export interface ArrowFunctionExpression extends BaseNode { + type: AST_NODE_TYPES.ArrowFunctionExpression; + generator: boolean; + id: null; + params: Parameter[]; + body: Expression | BlockStatement; + async: boolean; + expression: boolean; + returnType?: TSTypeAnnotation; + typeParameters?: TSTypeParameterDeclaration; +} + +export interface AssignmentExpression extends BinaryExpressionBase { + type: AST_NODE_TYPES.AssignmentExpression; +} + +export interface AssignmentPattern extends BaseNode { + type: AST_NODE_TYPES.AssignmentPattern; + left: BindingName; + right?: Expression; + typeAnnotation?: TSTypeAnnotation; + optional?: boolean; +} + +export interface AwaitExpression extends BaseNode { + type: AST_NODE_TYPES.AwaitExpression; + argument: TSUnaryExpression; +} + +export interface BigIntLiteral extends LiteralBase { + type: AST_NODE_TYPES.BigIntLiteral; +} + +export interface BinaryExpression extends BinaryExpressionBase { + type: AST_NODE_TYPES.BinaryExpression; +} + +export interface BlockStatement extends BaseNode { + type: AST_NODE_TYPES.BlockStatement; + body: Statement[]; +} + +export interface BreakStatement extends BaseNode { + type: AST_NODE_TYPES.BreakStatement; + label: Identifier | null; +} + +export interface CallExpression extends BaseNode { + type: AST_NODE_TYPES.CallExpression; + callee: LeftHandSideExpression; + arguments: Expression[]; + typeParameters?: TSTypeParameterInstantiation; +} + +export interface CatchClause extends BaseNode { + type: AST_NODE_TYPES.CatchClause; + param: BindingName | null; + body: BlockStatement; +} + +export interface ClassBody extends BaseNode { + type: AST_NODE_TYPES.ClassBody; + body: ClassElement[]; +} + +export interface ClassDeclaration extends ClassDeclarationBase { + type: AST_NODE_TYPES.ClassDeclaration; +} + +export interface ClassExpression extends ClassDeclarationBase { + type: AST_NODE_TYPES.ClassExpression; +} + +export interface ClassProperty extends ClassPropertyBase { + type: AST_NODE_TYPES.ClassProperty; +} + +export interface ConditionalExpression extends BaseNode { + type: AST_NODE_TYPES.ConditionalExpression; + test: Expression; + consequent: Expression; + alternate: Expression; +} + +export interface ContinueStatement extends BaseNode { + type: AST_NODE_TYPES.ContinueStatement; + label: Identifier | null; +} + +export interface DebuggerStatement extends BaseNode { + type: AST_NODE_TYPES.DebuggerStatement; +} + +export interface Decorator extends BaseNode { + type: AST_NODE_TYPES.Decorator; + expression: LeftHandSideExpression; +} + +export interface DoWhileStatement extends BaseNode { + type: AST_NODE_TYPES.DoWhileStatement; + test: Expression; + body: Statement; +} + +export interface EmptyStatement extends BaseNode { + type: AST_NODE_TYPES.EmptyStatement; +} + +export interface ExportAllDeclaration extends BaseNode { + type: AST_NODE_TYPES.ExportAllDeclaration; + source: Expression | null; +} + +export interface ExportDefaultDeclaration extends BaseNode { + type: AST_NODE_TYPES.ExportDefaultDeclaration; + declaration: ExportDeclaration; +} + +export interface ExportNamedDeclaration extends BaseNode { + type: AST_NODE_TYPES.ExportNamedDeclaration; + declaration: ExportDeclaration | null; + specifiers: ExportSpecifier[]; + source: Expression | null; +} + +export interface ExportSpecifier extends BaseNode { + type: AST_NODE_TYPES.ExportSpecifier; + local: Identifier; + exported: Identifier; +} + +export interface ExpressionStatement extends BaseNode { + type: AST_NODE_TYPES.ExpressionStatement; + expression: Expression; +} + +export interface ForInStatement extends BaseNode { + type: AST_NODE_TYPES.ForInStatement; + left: ForInitialiser; + right: Expression; + body: Statement; +} + +export interface ForOfStatement extends BaseNode { + type: AST_NODE_TYPES.ForOfStatement; + left: ForInitialiser; + right: Expression; + body: Statement; + await: boolean; +} + +export interface ForStatement extends BaseNode { + type: AST_NODE_TYPES.ForStatement; + init: Expression | ForInitialiser | null; + test: Expression | null; + update: Expression | null; + body: Statement; +} + +export interface FunctionDeclaration extends FunctionDeclarationBase { + type: AST_NODE_TYPES.FunctionDeclaration; +} + +export interface FunctionExpression extends FunctionDeclarationBase { + type: AST_NODE_TYPES.FunctionExpression; +} + +export interface Identifier extends BaseNode { + type: AST_NODE_TYPES.Identifier; + name: string; + typeAnnotation?: TSTypeAnnotation; + optional?: boolean; +} + +export interface IfStatement extends BaseNode { + type: AST_NODE_TYPES.IfStatement; + test: Expression; + consequent: Statement; + alternate: Statement | null; +} + +export interface Import extends BaseNode { + type: AST_NODE_TYPES.Import; +} + +export interface ImportDeclaration extends BaseNode { + type: AST_NODE_TYPES.ImportDeclaration; + source: Expression; + specifiers: ImportClause[]; +} + +export interface ImportDefaultSpecifier extends BaseNode { + type: AST_NODE_TYPES.ImportDefaultSpecifier; + local: Identifier; +} + +export interface ImportNamespaceSpecifier extends BaseNode { + type: AST_NODE_TYPES.ImportNamespaceSpecifier; + local: Identifier; +} + +export interface ImportSpecifier extends BaseNode { + type: AST_NODE_TYPES.ImportSpecifier; + local: Identifier; + imported: Identifier; +} + +export interface JSXAttribute extends BaseNode { + type: AST_NODE_TYPES.JSXAttribute; + name: JSXIdentifier; + value: Literal | JSXExpression | null; +} + +export interface JSXClosingElement extends BaseNode { + type: AST_NODE_TYPES.JSXClosingElement; + name: JSXTagNameExpression; +} + +export interface JSXClosingFragment extends BaseNode { + type: AST_NODE_TYPES.JSXClosingFragment; +} + +export interface JSXElement extends BaseNode { + type: AST_NODE_TYPES.JSXElement; + openingElement: JSXOpeningElement; + closingElement: JSXClosingElement | null; + children: JSXChild[]; +} + +export interface JSXEmptyExpression extends BaseNode { + type: AST_NODE_TYPES.JSXEmptyExpression; +} + +export interface JSXExpressionContainer extends BaseNode { + type: AST_NODE_TYPES.JSXExpressionContainer; + expression: Expression | JSXEmptyExpression; +} + +export interface JSXFragment extends BaseNode { + type: AST_NODE_TYPES.JSXFragment; + openingFragment: JSXOpeningFragment; + closingFragment: JSXClosingFragment; + children: JSXChild[]; +} + +export interface JSXIdentifier extends BaseNode { + type: AST_NODE_TYPES.JSXIdentifier; + name: string; +} + +export interface JSXMemberExpression extends BaseNode { + type: AST_NODE_TYPES.JSXMemberExpression; + object: JSXTagNameExpression; + property: JSXIdentifier; +} + +export interface JSXOpeningElement extends BaseNode { + type: AST_NODE_TYPES.JSXOpeningElement; + typeParameters?: TSTypeParameterInstantiation; + selfClosing: boolean; + name: JSXTagNameExpression; + attributes: JSXAttribute[]; +} + +export interface JSXOpeningFragment extends BaseNode { + type: AST_NODE_TYPES.JSXOpeningFragment; +} + +export interface JSXSpreadAttribute extends BaseNode { + type: AST_NODE_TYPES.JSXSpreadAttribute; + argument: Expression; +} + +export interface JSXSpreadChild extends BaseNode { + type: AST_NODE_TYPES.JSXSpreadChild; + expression: Expression | JSXEmptyExpression; +} + +export interface JSXText extends BaseNode { + type: AST_NODE_TYPES.JSXText; + value: string; + raw: string; +} + +export interface LabeledStatement extends BaseNode { + type: AST_NODE_TYPES.LabeledStatement; + label: Identifier; + body: Statement; +} + +export interface Literal extends LiteralBase { + type: AST_NODE_TYPES.Literal; +} + +export interface LogicalExpression extends BinaryExpressionBase { + type: AST_NODE_TYPES.LogicalExpression; +} + +export interface MemberExpression extends BaseNode { + type: AST_NODE_TYPES.MemberExpression; + object: LeftHandSideExpression; + property: Expression | Identifier; + computed?: boolean; +} + +export interface MetaProperty extends BaseNode { + type: AST_NODE_TYPES.MetaProperty; + meta: Identifier; + property: Identifier; +} + +export interface MethodDefinition extends MethodDefinitionBase { + type: AST_NODE_TYPES.MethodDefinition; +} + +export interface NewExpression extends BaseNode { + type: AST_NODE_TYPES.NewExpression; + callee: LeftHandSideExpression; + arguments: Expression[]; + typeParameters?: TSTypeParameterInstantiation; +} + +export interface ObjectExpression extends BaseNode { + type: AST_NODE_TYPES.ObjectExpression; + properties: ObjectLiteralElementLike[]; +} + +export interface ObjectPattern extends BaseNode { + type: AST_NODE_TYPES.ObjectPattern; + properties: ObjectLiteralElementLike[]; + typeAnnotation?: TSTypeAnnotation; + optional?: boolean; +} + +export interface Program extends BaseNode { + type: AST_NODE_TYPES.Program; + body: Statement[]; + sourceType: 'module' | 'script'; + comments?: Comment[]; + tokens?: Token[]; +} + +export interface Property extends BaseNode { + type: AST_NODE_TYPES.Property; + key: PropertyName; + value: Expression | AssignmentPattern | BindingName; + computed: boolean; + method: boolean; + shorthand: boolean; + kind: 'init'; + typeParameters?: TSTypeParameterDeclaration; +} + +export interface RestElement extends BaseNode { + type: AST_NODE_TYPES.RestElement; + argument: BindingName | Expression | PropertyName; + typeAnnotation?: TSTypeAnnotation; + optional?: boolean; + value?: AssignmentPattern; +} + +export interface ReturnStatement extends BaseNode { + type: AST_NODE_TYPES.ReturnStatement; + argument: Expression | null; +} + +export interface SequenceExpression extends BaseNode { + type: AST_NODE_TYPES.SequenceExpression; + expressions: Expression[]; +} + +export interface SpreadElement extends BaseNode { + type: AST_NODE_TYPES.SpreadElement; + argument: BindingName | Expression | PropertyName; +} + +export interface Super extends BaseNode { + type: AST_NODE_TYPES.Super; +} + +export interface SwitchCase extends BaseNode { + type: AST_NODE_TYPES.SwitchCase; + test: Expression; + consequent: Statement[]; +} + +export interface SwitchStatement extends BaseNode { + type: AST_NODE_TYPES.SwitchStatement; + discriminant: Expression; + cases: SwitchCase[]; +} + +export interface TaggedTemplateExpression extends BaseNode { + type: AST_NODE_TYPES.TaggedTemplateExpression; + typeParameters?: TSTypeParameterInstantiation; + tag: LeftHandSideExpression; + quasi: TemplateLiteral; +} + +export interface TemplateElement extends BaseNode { + type: AST_NODE_TYPES.TemplateElement; + value: { + raw: string; + cooked: string; + }; + tail: boolean; +} + +export interface TemplateLiteral extends BaseNode { + type: AST_NODE_TYPES.TemplateLiteral; + quasis: TemplateElement[]; + expressions: Expression[]; +} + +export interface ThisExpression extends BaseNode { + type: AST_NODE_TYPES.ThisExpression; +} + +export interface ThrowStatement extends BaseNode { + type: AST_NODE_TYPES.ThrowStatement; + argument: Statement | null; +} + +export interface TryStatement extends BaseNode { + type: AST_NODE_TYPES.TryStatement; + block: BlockStatement; + handler: CatchClause | null; + finalizer: BlockStatement; +} + +export interface TSAbstractClassProperty extends ClassPropertyBase { + type: AST_NODE_TYPES.TSAbstractClassProperty; +} + +export interface TSAbstractKeyword extends BaseNode { + type: AST_NODE_TYPES.TSAbstractKeyword; +} + +export interface TSAbstractMethodDefinition extends MethodDefinitionBase { + type: AST_NODE_TYPES.TSAbstractMethodDefinition; +} + +export interface TSAnyKeyword extends BaseNode { + type: AST_NODE_TYPES.TSAnyKeyword; +} + +export interface TSArrayType extends BaseNode { + type: AST_NODE_TYPES.TSArrayType; + elementType: TypeNode; +} + +export interface TSAsExpression extends BaseNode { + type: AST_NODE_TYPES.TSAsExpression; + expression: Expression; + typeAnnotation: TypeNode; +} + +export interface TSAsyncKeyword extends BaseNode { + type: AST_NODE_TYPES.TSAsyncKeyword; +} + +export interface TSBigIntKeyword extends BaseNode { + type: AST_NODE_TYPES.TSBigIntKeyword; +} + +export interface TSBooleanKeyword extends BaseNode { + type: AST_NODE_TYPES.TSBooleanKeyword; +} + +export interface TSCallSignatureDeclaration extends FunctionSignatureBase { + type: AST_NODE_TYPES.TSCallSignatureDeclaration; +} + +export interface TSClassImplements extends TSHeritageBase { + type: AST_NODE_TYPES.TSClassImplements; +} + +export interface TSConditionalType extends BaseNode { + type: AST_NODE_TYPES.TSConditionalType; + checkType: TypeNode; + extendsType: TypeNode; + trueType: TypeNode; + falseType: TypeNode; +} + +export interface TSConstructorType extends FunctionSignatureBase { + type: AST_NODE_TYPES.TSConstructorType; +} + +export interface TSConstructSignatureDeclaration extends FunctionSignatureBase { + type: AST_NODE_TYPES.TSConstructSignatureDeclaration; +} + +export interface TSDeclareFunction extends FunctionDeclarationBase { + type: AST_NODE_TYPES.TSDeclareFunction; +} + +export interface TSDeclareKeyword extends BaseNode { + type: AST_NODE_TYPES.TSDeclareKeyword; +} + +export interface TSEnumDeclaration extends BaseNode { + type: AST_NODE_TYPES.TSEnumDeclaration; + id: Identifier; + members: TSEnumMember[]; + const?: boolean; + declare?: boolean; + modifiers?: Modifier[]; + decorators?: Decorator[]; +} + +export interface TSEnumMember extends BaseNode { + type: AST_NODE_TYPES.TSEnumMember; + id: PropertyName; + initializer?: Expression; +} + +export interface TSExportAssignment extends BaseNode { + type: AST_NODE_TYPES.TSExportAssignment; + expression: Expression; +} + +export interface TSExportKeyword extends BaseNode { + type: AST_NODE_TYPES.TSExportKeyword; +} + +export interface TSExternalModuleReference extends BaseNode { + type: AST_NODE_TYPES.TSExternalModuleReference; + expression: Expression; +} + +export interface TSFunctionType extends FunctionSignatureBase { + type: AST_NODE_TYPES.TSFunctionType; +} + +export interface TSImportEqualsDeclaration extends BaseNode { + type: AST_NODE_TYPES.TSImportEqualsDeclaration; + id: Identifier; + moduleReference: EntityName | TSExternalModuleReference; + isExport: boolean; +} + +export interface TSImportType extends BaseNode { + type: AST_NODE_TYPES.TSImportType; + isTypeOf: boolean; + parameter: TypeNode; + qualifier: EntityName | null; + typeParameters: TSTypeParameterInstantiation | null; +} + +export interface TSIndexedAccessType extends BaseNode { + type: AST_NODE_TYPES.TSIndexedAccessType; + objectType: TypeNode; + indexType: TypeNode; +} + +export interface TSIndexSignature extends BaseNode { + type: AST_NODE_TYPES.TSIndexSignature; + parameters: Parameter[]; + typeAnnotation?: TSTypeAnnotation; + readonly?: boolean; + accessibility?: Accessibility; + export?: boolean; + static?: boolean; +} + +export interface TSInferType extends BaseNode { + type: AST_NODE_TYPES.TSInferType; + typeParameter: TSTypeParameterDeclaration; +} + +export interface TSInterfaceDeclaration extends BaseNode { + type: AST_NODE_TYPES.TSInterfaceDeclaration; + body: TSInterfaceBody; + id: Identifier; + typeParameters?: TSTypeParameterDeclaration; + extends?: ExpressionWithTypeArguments[]; + implements?: ExpressionWithTypeArguments[]; + decorators?: Decorator[]; + abstract?: boolean; + declare?: boolean; +} + +export interface TSInterfaceBody extends BaseNode { + type: AST_NODE_TYPES.TSInterfaceBody; + body: TypeElement[]; +} + +export interface TSInterfaceHeritage extends TSHeritageBase { + type: AST_NODE_TYPES.TSInterfaceHeritage; +} + +export interface TSIntersectionType extends BaseNode { + type: AST_NODE_TYPES.TSIntersectionType; + types: TypeNode[]; +} + +export interface TSLiteralType extends BaseNode { + type: AST_NODE_TYPES.TSLiteralType; + literal: LiteralExpression | UnaryExpression | UpdateExpression; +} + +export interface TSMappedType extends BaseNode { + type: AST_NODE_TYPES.TSMappedType; + typeParameter: TSTypeParameterDeclaration; + readonly?: boolean | '-' | '+'; + optional?: boolean | '-' | '+'; + typeAnnotation?: TypeNode; +} + +export interface TSMethodSignature extends BaseNode { + type: AST_NODE_TYPES.TSMethodSignature; + computed: boolean; + key: PropertyName; + params: Parameter[]; + optional?: boolean; + returnType?: TSTypeAnnotation; + readonly?: boolean; + typeParameters?: TSTypeParameterDeclaration; + accessibility?: Accessibility; + export?: boolean; + static?: boolean; +} + +export interface TSModuleBlock extends BaseNode { + type: AST_NODE_TYPES.TSModuleBlock; + body: Statement[]; +} + +export interface TSModuleDeclaration extends BaseNode { + type: AST_NODE_TYPES.TSModuleDeclaration; + id: Identifier | Literal; + body?: TSModuleBlock | Identifier; + global?: boolean; + declare?: boolean; + modifiers?: Modifier[]; +} + +export interface TSNamespaceExportDeclaration extends BaseNode { + type: AST_NODE_TYPES.TSNamespaceExportDeclaration; + id: Identifier; +} + +export interface TSNeverKeyword extends BaseNode { + type: AST_NODE_TYPES.TSNeverKeyword; +} + +export interface TSNonNullExpression extends BaseNode { + type: AST_NODE_TYPES.TSNonNullExpression; + expression: Expression; +} + +export interface TSNullKeyword extends BaseNode { + type: AST_NODE_TYPES.TSNullKeyword; +} + +export interface TSNumberKeyword extends BaseNode { + type: AST_NODE_TYPES.TSNumberKeyword; +} + +export interface TSObjectKeyword extends BaseNode { + type: AST_NODE_TYPES.TSObjectKeyword; +} + +export interface TSOptionalType extends BaseNode { + type: AST_NODE_TYPES.TSOptionalType; + typeAnnotation: TypeNode; +} + +export interface TSParameterProperty extends BaseNode { + type: AST_NODE_TYPES.TSParameterProperty; + accessibility?: Accessibility; + readonly?: boolean; + static?: boolean; + export?: boolean; + parameter: AssignmentPattern | BindingName | RestElement; +} + +export interface TSParenthesizedType extends BaseNode { + type: AST_NODE_TYPES.TSParenthesizedType; + typeAnnotation: TypeNode; +} + +export interface TSPropertySignature extends BaseNode { + type: AST_NODE_TYPES.TSPropertySignature; + optional?: boolean; + computed: boolean; + key: PropertyName; + typeAnnotation?: TSTypeAnnotation; + initializer?: Expression; + readonly?: boolean; + static?: boolean; + export?: boolean; + accessibility?: Accessibility; +} + +export interface TSPublicKeyword extends BaseNode { + type: AST_NODE_TYPES.TSPublicKeyword; +} + +export interface TSPrivateKeyword extends BaseNode { + type: AST_NODE_TYPES.TSPrivateKeyword; +} + +export interface TSProtectedKeyword extends BaseNode { + type: AST_NODE_TYPES.TSProtectedKeyword; +} + +export interface TSQualifiedName extends BaseNode { + type: AST_NODE_TYPES.TSQualifiedName; + left: EntityName; + right: Identifier; +} + +export interface TSReadonlyKeyword extends BaseNode { + type: AST_NODE_TYPES.TSReadonlyKeyword; +} + +export interface TSRestType extends BaseNode { + type: AST_NODE_TYPES.TSRestType; + typeAnnotation: TypeNode; +} + +export interface TSStaticKeyword extends BaseNode { + type: AST_NODE_TYPES.TSStaticKeyword; +} + +export interface TSStringKeyword extends BaseNode { + type: AST_NODE_TYPES.TSStringKeyword; +} + +export interface TSSymbolKeyword extends BaseNode { + type: AST_NODE_TYPES.TSSymbolKeyword; +} + +export interface TSThisType extends BaseNode { + type: AST_NODE_TYPES.TSThisType; +} + +export interface TSTupleType extends BaseNode { + type: AST_NODE_TYPES.TSTupleType; + elementTypes: TypeNode[]; +} + +export interface TSTypeAliasDeclaration extends BaseNode { + type: AST_NODE_TYPES.TSTypeAliasDeclaration; + id: Identifier; + typeAnnotation: TypeNode; + declare?: boolean; + typeParameters?: TSTypeParameterDeclaration; +} + +export interface TSTypeAnnotation extends BaseNode { + type: AST_NODE_TYPES.TSTypeAnnotation; + typeAnnotation: TypeNode; +} + +export interface TSTypeAssertion extends BaseNode { + type: AST_NODE_TYPES.TSTypeAssertion; + typeAnnotation: TypeNode; + expression: UnaryExpression; +} + +export interface TSTypeLiteral extends BaseNode { + type: AST_NODE_TYPES.TSTypeLiteral; + members: TypeElement[]; +} + +export interface TSTypeOperator extends BaseNode { + type: AST_NODE_TYPES.TSTypeOperator; + operator: 'keyof' | 'unique'; + typeAnnotation?: TSTypeAnnotation; +} + +export interface TSTypeParameter extends BaseNode { + type: AST_NODE_TYPES.TSTypeParameter; + name: Identifier; + constraint?: TypeNode; + default?: TypeNode; +} + +export interface TSTypeParameterDeclaration extends BaseNode { + type: AST_NODE_TYPES.TSTypeParameterDeclaration; + params: TSTypeParameter[]; +} + +export interface TSTypeParameterInstantiation extends BaseNode { + type: AST_NODE_TYPES.TSTypeParameterInstantiation; + params: TypeNode[]; +} + +export interface TSTypePredicate extends BaseNode { + type: AST_NODE_TYPES.TSTypePredicate; + parameterName: Identifier | TSThisType; + typeAnnotation: TSTypeAnnotation; +} + +export interface TSTypeQuery extends BaseNode { + type: AST_NODE_TYPES.TSTypeQuery; + exprName: EntityName; +} + +export interface TSTypeReference extends BaseNode { + type: AST_NODE_TYPES.TSTypeReference; + typeName: EntityName; + typeParameters?: TSTypeParameterInstantiation; +} + +export interface TSUndefinedKeyword extends BaseNode { + type: AST_NODE_TYPES.TSUndefinedKeyword; +} + +export interface TSUnionType extends BaseNode { + type: AST_NODE_TYPES.TSUnionType; + types: TypeNode[]; +} + +export interface TSUnknownKeyword extends BaseNode { + type: AST_NODE_TYPES.TSUnknownKeyword; +} + +export interface TSVoidKeyword extends BaseNode { + type: AST_NODE_TYPES.TSVoidKeyword; +} + +export interface UpdateExpression extends UnaryExpressionBase { + type: AST_NODE_TYPES.UpdateExpression; +} + +export interface UnaryExpression extends UnaryExpressionBase { + type: AST_NODE_TYPES.UnaryExpression; +} + +export interface VariableDeclaration extends BaseNode { + type: AST_NODE_TYPES.VariableDeclaration; + declarations: VariableDeclarator[]; + kind: 'let' | 'const' | 'var'; + declare?: boolean; +} + +export interface VariableDeclarator extends BaseNode { + type: AST_NODE_TYPES.VariableDeclarator; + id: BindingName; + init: Expression | null; + definite?: boolean; +} + +export interface WhileStatement extends BaseNode { + type: AST_NODE_TYPES.WhileStatement; + test: Expression; + body: Statement; +} + +export interface WithStatement extends BaseNode { + type: AST_NODE_TYPES.WithStatement; + object: Expression; + body: Statement; +} + +export interface YieldExpression extends BaseNode { + type: AST_NODE_TYPES.YieldExpression; + delegate: boolean; + argument?: Expression; +} diff --git a/packages/typescript-estree/tests/lib/comments.ts b/packages/typescript-estree/tests/lib/comments.ts index e469c39f00ef..1d02e2fa6715 100644 --- a/packages/typescript-estree/tests/lib/comments.ts +++ b/packages/typescript-estree/tests/lib/comments.ts @@ -8,7 +8,7 @@ import { readFileSync } from 'fs'; import glob from 'glob'; import { extname } from 'path'; -import { ParserOptions } from '../../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock, formatSnapshotName diff --git a/packages/typescript-estree/tests/lib/javascript.ts b/packages/typescript-estree/tests/lib/javascript.ts index aca646998b3b..d254f8fd612c 100644 --- a/packages/typescript-estree/tests/lib/javascript.ts +++ b/packages/typescript-estree/tests/lib/javascript.ts @@ -7,7 +7,7 @@ */ import { readFileSync } from 'fs'; import glob from 'glob'; -import { ParserOptions } from '../../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock, formatSnapshotName diff --git a/packages/typescript-estree/tests/lib/jsx.ts b/packages/typescript-estree/tests/lib/jsx.ts index 8b2f9f2c19de..b887911ab008 100644 --- a/packages/typescript-estree/tests/lib/jsx.ts +++ b/packages/typescript-estree/tests/lib/jsx.ts @@ -7,7 +7,7 @@ */ import { readFileSync } from 'fs'; import glob from 'glob'; -import { ParserOptions } from '../../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock, formatSnapshotName diff --git a/packages/typescript-estree/tests/lib/parse.ts b/packages/typescript-estree/tests/lib/parse.ts index 6bed7ce8bcef..2f8463cc0a2b 100644 --- a/packages/typescript-estree/tests/lib/parse.ts +++ b/packages/typescript-estree/tests/lib/parse.ts @@ -7,7 +7,7 @@ */ import * as parser from '../../src/parser'; import * as astConverter from '../../src/ast-converter'; -import { ParserOptions } from '../../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock } from '../../tools/test-utils'; //------------------------------------------------------------------------------ diff --git a/packages/typescript-estree/tests/lib/semanticInfo.ts b/packages/typescript-estree/tests/lib/semanticInfo.ts index f5612f191cc5..a164288ceb0f 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.ts @@ -11,7 +11,7 @@ import { readFileSync } from 'fs'; import glob from 'glob'; import { extname, join, resolve } from 'path'; import ts from 'typescript'; -import { ParserOptions } from '../../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock, formatSnapshotName, diff --git a/packages/typescript-estree/tests/lib/tsx.ts b/packages/typescript-estree/tests/lib/tsx.ts index 8d4230a2c91f..21dbbd57efe0 100644 --- a/packages/typescript-estree/tests/lib/tsx.ts +++ b/packages/typescript-estree/tests/lib/tsx.ts @@ -7,7 +7,7 @@ import { readFileSync } from 'fs'; import glob from 'glob'; import { extname } from 'path'; -import { ParserOptions } from '../../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock, formatSnapshotName diff --git a/packages/typescript-estree/tests/lib/typescript.ts b/packages/typescript-estree/tests/lib/typescript.ts index dabfac14def4..9740c4570e74 100644 --- a/packages/typescript-estree/tests/lib/typescript.ts +++ b/packages/typescript-estree/tests/lib/typescript.ts @@ -8,7 +8,7 @@ import { readFileSync } from 'fs'; import glob from 'glob'; import { extname } from 'path'; -import { ParserOptions } from '../../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../../src/parser-options'; import { createSnapshotTestBlock, formatSnapshotName diff --git a/packages/typescript-estree/tools/test-utils.ts b/packages/typescript-estree/tools/test-utils.ts index 9191ae5e518a..c2d57246ca09 100644 --- a/packages/typescript-estree/tools/test-utils.ts +++ b/packages/typescript-estree/tools/test-utils.ts @@ -6,7 +6,7 @@ * MIT License */ import * as parser from '../src/parser'; -import { ParserOptions } from '../src/temp-types-based-on-js-source'; +import { ParserOptions } from '../src/parser-options'; /** * Returns a raw copy of the given AST