diff --git a/packages/eslint-plugin/src/rules/await-thenable.ts b/packages/eslint-plugin/src/rules/await-thenable.ts index f5b06b683f4..78b7ad12939 100644 --- a/packages/eslint-plugin/src/rules/await-thenable.ts +++ b/packages/eslint-plugin/src/rules/await-thenable.ts @@ -26,9 +26,7 @@ export default util.createRule({ return { AwaitExpression(node): void { - const originalNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.AwaitExpression - >(node); + const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); const type = checker.getTypeAtLocation(originalNode.expression); if ( diff --git a/packages/eslint-plugin/src/rules/no-floating-promises.ts b/packages/eslint-plugin/src/rules/no-floating-promises.ts index 0cf9542e88a..fdc93cbed3f 100644 --- a/packages/eslint-plugin/src/rules/no-floating-promises.ts +++ b/packages/eslint-plugin/src/rules/no-floating-promises.ts @@ -44,9 +44,7 @@ export default util.createRule({ return { ExpressionStatement(node): void { - const { expression } = parserServices.esTreeNodeToTSNodeMap.get< - ts.ExpressionStatement - >(node); + const { expression } = parserServices.esTreeNodeToTSNodeMap.get(node); if (isUnhandledPromise(checker, expression)) { context.report({ diff --git a/packages/eslint-plugin/src/rules/no-for-in-array.ts b/packages/eslint-plugin/src/rules/no-for-in-array.ts index b93665069c7..511b744ee4c 100644 --- a/packages/eslint-plugin/src/rules/no-for-in-array.ts +++ b/packages/eslint-plugin/src/rules/no-for-in-array.ts @@ -23,9 +23,7 @@ export default util.createRule({ ForInStatement(node): void { const parserServices = util.getParserServices(context); const checker = parserServices.program.getTypeChecker(); - const originalNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.ForInStatement - >(node); + const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); const type = checker.getTypeAtLocation(originalNode.expression); diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index 5326129780c..bd74721c7a2 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -99,9 +99,7 @@ export default util.createRule({ | TSESTree.OptionalCallExpression | TSESTree.NewExpression, ): void { - const tsNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.CallExpression | ts.NewExpression - >(node); + const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); const voidParams = voidFunctionParams(checker, tsNode); if (voidParams.size === 0) { return; diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts index 043a52304c6..22a9fed5ba6 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-condition.ts @@ -136,12 +136,12 @@ export default createRule({ const checker = service.program.getTypeChecker(); const sourceCode = context.getSourceCode(); - function getNodeType(node: TSESTree.Node): ts.Type { + function getNodeType(node: TSESTree.Expression): ts.Type { const tsNode = service.esTreeNodeToTSNodeMap.get(node); return getConstrainedTypeAtLocation(checker, tsNode); } - function nodeIsArrayType(node: TSESTree.Node): boolean { + function nodeIsArrayType(node: TSESTree.Expression): boolean { const nodeType = getNodeType(node); return checker.isArrayType(nodeType) || checker.isTupleType(nodeType); } @@ -150,7 +150,7 @@ export default createRule({ * Checks if a conditional node is necessary: * if the type of the node is always true or always false, it's not necessary. */ - function checkNode(node: TSESTree.Node): void { + function checkNode(node: TSESTree.Expression): void { const type = getNodeType(node); // Conditional is always necessary if it involves: @@ -180,7 +180,7 @@ export default createRule({ } } - function checkNodeForNullish(node: TSESTree.Node): void { + function checkNodeForNullish(node: TSESTree.Expression): void { const type = getNodeType(node); // Conditional is always necessary if it involves `any` or `unknown` if (isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) { diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts b/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts index f489fd3c331..a34533d2fc2 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-qualifier.ts @@ -74,7 +74,7 @@ export default util.createRule({ } function qualifierIsUnnecessary( - qualifier: TSESTree.Node, + qualifier: TSESTree.EntityName | TSESTree.MemberExpression, name: TSESTree.Identifier, ): boolean { const tsQualifier = esTreeNodeToTSNodeMap.get(qualifier); @@ -110,7 +110,7 @@ export default util.createRule({ function visitNamespaceAccess( node: TSESTree.Node, - qualifier: TSESTree.Node, + qualifier: TSESTree.EntityName | TSESTree.MemberExpression, name: TSESTree.Identifier, ): void { // Only look for nested qualifier errors if we didn't already fail on the outer qualifier. @@ -132,7 +132,12 @@ export default util.createRule({ } } - function enterDeclaration(node: TSESTree.Node): void { + function enterDeclaration( + node: + | TSESTree.TSModuleDeclaration + | TSESTree.TSEnumDeclaration + | TSESTree.ExportNamedDeclaration, + ): void { namespacesInScope.push(esTreeNodeToTSNodeMap.get(node)); } @@ -152,7 +157,9 @@ export default util.createRule({ return node.type === AST_NODE_TYPES.MemberExpression && !node.computed; } - function isEntityNameExpression(node: TSESTree.Node): boolean { + function isEntityNameExpression( + node: TSESTree.Node, + ): node is TSESTree.Identifier | TSESTree.MemberExpression { return ( node.type === AST_NODE_TYPES.Identifier || (isPropertyAccessExpression(node) && diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts index a32cb94728c..e900a0b0707 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-arguments.ts @@ -5,10 +5,14 @@ import * as util from '../util'; import { findFirstResult } from '../util'; type ParameterCapableTSNode = + | ts.TaggedTemplateExpression + | ts.ImportTypeNode | ts.CallExpression | ts.NewExpression | ts.TypeReferenceNode - | ts.ExpressionWithTypeArguments; + | ts.ExpressionWithTypeArguments + | ts.JsxOpeningElement + | ts.JsxSelfClosingElement; type MessageIds = 'unnecessaryTypeParameter'; @@ -67,9 +71,7 @@ export default util.createRule<[], MessageIds>({ return { TSTypeParameterInstantiation(node): void { - const expression = parserServices.esTreeNodeToTSNodeMap.get< - ParameterCapableTSNode - >(node); + const expression = parserServices.esTreeNodeToTSNodeMap.get(node); const typeParameters = getTypeParametersFromNode(expression, checker); if (typeParameters) { diff --git a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts index 6696b127c10..f0ed2502bb8 100644 --- a/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts +++ b/packages/eslint-plugin/src/rules/no-unnecessary-type-assertion.ts @@ -168,9 +168,7 @@ export default util.createRule({ return { TSNonNullExpression(node): void { - const originalNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.NonNullExpression - >(node); + const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); const type = util.getConstrainedTypeAtLocation( checker, originalNode.expression, @@ -252,9 +250,7 @@ export default util.createRule({ return; } - const originalNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.AssertionExpression - >(node); + const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); const castType = checker.getTypeAtLocation(originalNode); if ( diff --git a/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts b/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts index db21c42570c..0c1ac212380 100644 --- a/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts +++ b/packages/eslint-plugin/src/rules/no-unused-vars-experimental.ts @@ -290,7 +290,7 @@ export default util.createRule({ } return { - 'Program:exit'(program: TSESTree.Node): void { + 'Program:exit'(program: TSESTree.Program): void { const tsNode = parserServices.esTreeNodeToTSNodeMap.get(program); const sourceFile = util.getSourceFileOfNode(tsNode); const diagnostics = tsProgram.getSemanticDiagnostics(sourceFile); diff --git a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts index 805f17d4f60..d5b35e8dd13 100644 --- a/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts +++ b/packages/eslint-plugin/src/rules/prefer-nullish-coalescing.ts @@ -4,7 +4,6 @@ import { TSESLint, TSESTree, } from '@typescript-eslint/experimental-utils'; -import * as ts from 'typescript'; import * as util from '../util'; export type Options = [ @@ -75,9 +74,7 @@ export default util.createRule({ 'LogicalExpression[operator = "||"]'( node: TSESTree.LogicalExpression, ): void { - const tsNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.BinaryExpression - >(node); + const tsNode = parserServices.esTreeNodeToTSNodeMap.get(node); const type = checker.getTypeAtLocation(tsNode.left); const isNullish = util.isNullableType(type, { allowUndefined: true }); if (!isNullish) { diff --git a/packages/eslint-plugin/src/rules/prefer-readonly.ts b/packages/eslint-plugin/src/rules/prefer-readonly.ts index d2aa135b99f..d51b8c0f954 100644 --- a/packages/eslint-plugin/src/rules/prefer-readonly.ts +++ b/packages/eslint-plugin/src/rules/prefer-readonly.ts @@ -135,7 +135,9 @@ export default util.createRule({ return false; } - function isConstructor(node: TSESTree.Node): boolean { + function isConstructor( + node: TSESTree.Node, + ): node is TSESTree.MethodDefinition { return ( node.type === AST_NODE_TYPES.MethodDefinition && node.kind === 'constructor' @@ -143,7 +145,11 @@ export default util.createRule({ } function isFunctionScopeBoundaryInStack( - node: TSESTree.Node, + node: + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionDeclaration + | TSESTree.FunctionExpression + | TSESTree.MethodDefinition, ): boolean | tsutils.ScopeBoundary { if (classScopeStack.length === 0) { return false; @@ -208,10 +214,10 @@ export default util.createRule({ } }, MemberExpression(node): void { - const tsNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.PropertyAccessExpression - >(node); if (classScopeStack.length !== 0 && !node.computed) { + const tsNode = parserServices.esTreeNodeToTSNodeMap.get( + node, + ) as ts.PropertyAccessExpression; handlePropertyAccessExpression( tsNode, tsNode.parent, @@ -228,9 +234,7 @@ export default util.createRule({ ): void { if (isConstructor(node)) { classScopeStack[classScopeStack.length - 1].enterConstructor( - parserServices.esTreeNodeToTSNodeMap.get( - node, - ), + parserServices.esTreeNodeToTSNodeMap.get(node), ); } else if (isFunctionScopeBoundaryInStack(node)) { classScopeStack[classScopeStack.length - 1].enterNonConstructor(); @@ -339,7 +343,13 @@ class ClassScope { ).add(node.name.text); } - public enterConstructor(node: ts.ConstructorDeclaration): void { + public enterConstructor( + node: + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration + | ts.MethodDeclaration + | ts.ConstructorDeclaration, + ): void { this.constructorScopeDepth = DIRECTLY_INSIDE_CONSTRUCTOR; for (const parameter of node.parameters) { diff --git a/packages/eslint-plugin/src/rules/prefer-regexp-exec.ts b/packages/eslint-plugin/src/rules/prefer-regexp-exec.ts index e62033603b5..599e0f2a6da 100644 --- a/packages/eslint-plugin/src/rules/prefer-regexp-exec.ts +++ b/packages/eslint-plugin/src/rules/prefer-regexp-exec.ts @@ -30,7 +30,7 @@ export default createRule({ * Check if a given node is a string. * @param node The node to check. */ - function isStringType(node: TSESTree.Node): boolean { + function isStringType(node: TSESTree.LeftHandSideExpression): boolean { const objectType = typeChecker.getTypeAtLocation( service.esTreeNodeToTSNodeMap.get(node), ); diff --git a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts index d8872bdfa25..2b4946b2a14 100644 --- a/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts +++ b/packages/eslint-plugin/src/rules/prefer-string-starts-ends-with.ts @@ -45,7 +45,7 @@ export default createRule({ * Check if a given node is a string. * @param node The node to check. */ - function isStringType(node: TSESTree.Node): boolean { + function isStringType(node: TSESTree.LeftHandSideExpression): boolean { const objectType = typeChecker.getTypeAtLocation( service.esTreeNodeToTSNodeMap.get(node), ); diff --git a/packages/eslint-plugin/src/rules/promise-function-async.ts b/packages/eslint-plugin/src/rules/promise-function-async.ts index e736f5a9201..16134675d57 100644 --- a/packages/eslint-plugin/src/rules/promise-function-async.ts +++ b/packages/eslint-plugin/src/rules/promise-function-async.ts @@ -90,7 +90,14 @@ export default util.createRule({ const parserServices = util.getParserServices(context); const checker = parserServices.program.getTypeChecker(); - function validateNode(node: TSESTree.Node): void { + function validateNode( + node: + | TSESTree.ArrowFunctionExpression + | TSESTree.FunctionDeclaration + | TSESTree.FunctionExpression + | TSESTree.MethodDefinition + | TSESTree.TSAbstractMethodDefinition, + ): void { const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); const signatures = checker .getTypeAtLocation(originalNode) diff --git a/packages/eslint-plugin/src/rules/require-await.ts b/packages/eslint-plugin/src/rules/require-await.ts index ed28a105430..b9949659daa 100644 --- a/packages/eslint-plugin/src/rules/require-await.ts +++ b/packages/eslint-plugin/src/rules/require-await.ts @@ -66,9 +66,7 @@ export default util.createRule({ ForOfStatement: rules.ForOfStatement, ReturnStatement(node): void { - const { expression } = parserServices.esTreeNodeToTSNodeMap.get< - ts.ReturnStatement - >(node); + const { expression } = parserServices.esTreeNodeToTSNodeMap.get(node); if (expression && isThenableType(expression)) { // tell the base rule to mark the scope as having an await so it ignores it rules.AwaitExpression(); diff --git a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts index f07e624eeb2..a833825a207 100644 --- a/packages/eslint-plugin/src/rules/restrict-plus-operands.ts +++ b/packages/eslint-plugin/src/rules/restrict-plus-operands.ts @@ -96,7 +96,7 @@ export default util.createRule({ * Helper function to get base type of node * @param node the node to be evaluated. */ - function getNodeType(node: TSESTree.Node): BaseLiteral { + function getNodeType(node: TSESTree.Expression): BaseLiteral { const tsNode = service.esTreeNodeToTSNodeMap.get(node); const type = typeChecker.getTypeAtLocation(tsNode); diff --git a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts index efedc786b51..6ff1627daf5 100644 --- a/packages/eslint-plugin/src/rules/restrict-template-expressions.ts +++ b/packages/eslint-plugin/src/rules/restrict-template-expressions.ts @@ -92,7 +92,7 @@ export default util.createRule({ * Helper function to get base type of node * @param node the node to be evaluated. */ - function getNodeType(node: TSESTree.Node): BaseType[] { + function getNodeType(node: TSESTree.Expression): BaseType[] { const tsNode = service.esTreeNodeToTSNodeMap.get(node); const type = typeChecker.getTypeAtLocation(tsNode); diff --git a/packages/eslint-plugin/src/rules/return-await.ts b/packages/eslint-plugin/src/rules/return-await.ts index 43d9b3e0f55..52ffb052c7e 100644 --- a/packages/eslint-plugin/src/rules/return-await.ts +++ b/packages/eslint-plugin/src/rules/return-await.ts @@ -135,9 +135,7 @@ export default util.createRule({ } }, ReturnStatement(node): void { - const originalNode = parserServices.esTreeNodeToTSNodeMap.get< - ts.ReturnStatement - >(node); + const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node); const { expression } = originalNode; diff --git a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts index 0d4235e2d7d..c924045ba02 100644 --- a/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts +++ b/packages/eslint-plugin/src/rules/strict-boolean-expressions.ts @@ -66,10 +66,8 @@ export default util.createRule({ /** * Determines if the node is safe for boolean type */ - function isValidBooleanNode(node: TSESTree.Node): boolean { - const tsNode = service.esTreeNodeToTSNodeMap.get( - node, - ); + function isValidBooleanNode(node: TSESTree.Expression): boolean { + const tsNode = service.esTreeNodeToTSNodeMap.get(node); const type = util.getConstrainedTypeAtLocation(checker, tsNode); if (tsutils.isTypeFlagSet(type, ts.TypeFlags.BooleanLike)) { diff --git a/packages/experimental-utils/package.json b/packages/experimental-utils/package.json index 34b7f5e91b7..8299d36ceee 100644 --- a/packages/experimental-utils/package.json +++ b/packages/experimental-utils/package.json @@ -26,6 +26,7 @@ }, "license": "MIT", "main": "dist/index.js", + "types": "dist/index.d.ts", "scripts": { "build": "tsc -b tsconfig.build.json", "clean": "tsc -b tsconfig.build.json --clean", diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 4a5d4accb40..1f079b71055 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -21,8 +21,13 @@ import { unescapeStringLiteralText, TSError, } from './node-utils'; -import { AST_NODE_TYPES, TSESTree, TSNode } from './ts-estree'; -import { ParserWeakMap } from './parser-options'; +import { + AST_NODE_TYPES, + TSESTree, + TSNode, + TSESTreeToTSNode, +} from './ts-estree'; +import { ParserWeakMap, ParserWeakMapESTreeToTSNode } from './parser-options'; const SyntaxKind = ts.SyntaxKind; @@ -46,7 +51,7 @@ export function convertError(error: any): TSError { } export interface ASTMaps { - esTreeNodeToTSNodeMap: ParserWeakMap; + esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode; tsNodeToESTreeNodeMap: ParserWeakMap; } @@ -125,12 +130,20 @@ export class Converter { /** * Fixes the exports of the given ts.Node - * @param node the ts.Node + * @param node the ts.Node * @param result result * @returns the ESTreeNode with fixed exports */ private fixExports( - node: ts.Node, + node: + | ts.FunctionDeclaration + | ts.VariableStatement + | ts.ClassDeclaration + | ts.ClassExpression + | ts.TypeAliasDeclaration + | ts.InterfaceDeclaration + | ts.EnumDeclaration + | ts.ModuleDeclaration, result: T, ): TSESTree.ExportDefaultDeclaration | TSESTree.ExportNamedDeclaration | T { // check for exports @@ -216,8 +229,8 @@ export class Converter { return this.converter(child, parent, true, false); } - private createNode( - node: ts.Node, + private createNode( + node: TSESTreeToTSNode, data: TSESTree.OptionalRangeAndLoc, ): T { const result = data; @@ -306,7 +319,7 @@ export class Converter { */ private convertTypeArgumentsToTypeParameters( typeArguments: ts.NodeArray, - node: ts.Node, + node: TSESTreeToTSNode, ): TSESTree.TSTypeParameterInstantiation { const greaterThanToken = findNextToken(typeArguments, this.ast, this.ast)!; @@ -1821,10 +1834,14 @@ export class Converter { 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), - }), + meta: this.createNode( + // TODO: do we really want to convert it to Token? + node.getFirstToken()! as ts.Token, + { + type: AST_NODE_TYPES.Identifier, + name: getTextForTokenKind(node.keywordToken), + }, + ), property: this.convertChild(node.name), }); } @@ -1914,7 +1931,7 @@ export class Converter { type: AST_NODE_TYPES.TSNullKeyword, }); } else { - return this.createNode(node, { + return this.createNode(node as ts.NullLiteral, { type: AST_NODE_TYPES.Literal, value: null, raw: 'null', @@ -2114,6 +2131,10 @@ export class Converter { } case SyntaxKind.ThisType: + return this.createNode(node, { + type: AST_NODE_TYPES.TSThisType, + }); + case SyntaxKind.AnyKeyword: case SyntaxKind.BigIntKeyword: case SyntaxKind.BooleanKeyword: diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index 63e14a2fffb..4a4bc3eb415 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -1,5 +1,5 @@ import { Program } from 'typescript'; -import { TSESTree, TSNode } from './ts-estree'; +import { TSESTree, TSNode, TSESTreeToTSNode, TSToken } from './ts-estree'; export interface Extra { code: string; @@ -47,8 +47,17 @@ export interface ParserWeakMap { has(key: unknown): boolean; } +export interface ParserWeakMapESTreeToTSNode< + TKey extends TSESTree.Node = TSESTree.Node +> { + get(key: TKeyBase): TSESTreeToTSNode; + has(key: unknown): boolean; +} + export interface ParserServices { program: Program | undefined; - esTreeNodeToTSNodeMap: ParserWeakMap | undefined; - tsNodeToESTreeNodeMap: ParserWeakMap | undefined; + esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode | undefined; + tsNodeToESTreeNodeMap: + | ParserWeakMap + | undefined; } diff --git a/packages/typescript-estree/src/ts-estree/estree-to-ts-node-types.ts b/packages/typescript-estree/src/ts-estree/estree-to-ts-node-types.ts new file mode 100644 index 00000000000..bb00046c334 --- /dev/null +++ b/packages/typescript-estree/src/ts-estree/estree-to-ts-node-types.ts @@ -0,0 +1,279 @@ +import { TSNode } from './ts-nodes'; +import { AST_NODE_TYPES } from './ast-node-types'; +import { Node } from './ts-estree'; +import * as ts from 'typescript'; + +export interface EstreeToTsNodeTypes { + [AST_NODE_TYPES.ArrayExpression]: ts.ArrayLiteralExpression; + [AST_NODE_TYPES.ArrayPattern]: + | ts.ArrayLiteralExpression + | ts.ArrayBindingPattern; + [AST_NODE_TYPES.ArrowFunctionExpression]: ts.ArrowFunction; + [AST_NODE_TYPES.AssignmentExpression]: ts.BinaryExpression; + [AST_NODE_TYPES.AssignmentPattern]: + | ts.ShorthandPropertyAssignment + | ts.BindingElement + | ts.BinaryExpression + | ts.ParameterDeclaration; + [AST_NODE_TYPES.AwaitExpression]: ts.AwaitExpression; + [AST_NODE_TYPES.BigIntLiteral]: ts.BigIntLiteral; + [AST_NODE_TYPES.BinaryExpression]: ts.BinaryExpression; + [AST_NODE_TYPES.BlockStatement]: ts.Block; + [AST_NODE_TYPES.BreakStatement]: ts.BreakStatement; + [AST_NODE_TYPES.CallExpression]: ts.CallExpression; + [AST_NODE_TYPES.CatchClause]: ts.CatchClause; + [AST_NODE_TYPES.ClassBody]: ts.ClassDeclaration | ts.ClassExpression; + [AST_NODE_TYPES.ClassDeclaration]: ts.ClassDeclaration; + [AST_NODE_TYPES.ClassExpression]: ts.ClassExpression; + [AST_NODE_TYPES.ClassProperty]: ts.PropertyDeclaration; + [AST_NODE_TYPES.ConditionalExpression]: ts.ConditionalExpression; + [AST_NODE_TYPES.ContinueStatement]: ts.ContinueStatement; + [AST_NODE_TYPES.DebuggerStatement]: ts.DebuggerStatement; + [AST_NODE_TYPES.Decorator]: ts.Decorator; + [AST_NODE_TYPES.DoWhileStatement]: ts.DoStatement; + [AST_NODE_TYPES.EmptyStatement]: ts.EmptyStatement; + [AST_NODE_TYPES.ExportAllDeclaration]: ts.ExportDeclaration; + [AST_NODE_TYPES.ExportDefaultDeclaration]: + | ts.ExportAssignment + | ts.FunctionDeclaration + | ts.VariableStatement + | ts.ClassDeclaration + | ts.ClassExpression + | ts.TypeAliasDeclaration + | ts.InterfaceDeclaration + | ts.EnumDeclaration + | ts.ModuleDeclaration; + [AST_NODE_TYPES.ExportNamedDeclaration]: + | ts.ExportDeclaration + | ts.FunctionDeclaration + | ts.VariableStatement + | ts.ClassDeclaration + | ts.ClassExpression + | ts.TypeAliasDeclaration + | ts.InterfaceDeclaration + | ts.EnumDeclaration + | ts.ModuleDeclaration; + [AST_NODE_TYPES.ExportSpecifier]: ts.ExportSpecifier; + [AST_NODE_TYPES.ExpressionStatement]: ts.ExpressionStatement; + [AST_NODE_TYPES.ForInStatement]: ts.ForInStatement; + [AST_NODE_TYPES.ForOfStatement]: ts.ForOfStatement; + [AST_NODE_TYPES.ForStatement]: ts.ForStatement; + [AST_NODE_TYPES.FunctionDeclaration]: ts.FunctionDeclaration; + [AST_NODE_TYPES.FunctionExpression]: + | ts.FunctionExpression + | ts.ConstructorDeclaration + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration + | ts.MethodDeclaration; + [AST_NODE_TYPES.Identifier]: + | ts.Identifier + | ts.ConstructorDeclaration + | ts.Token; + [AST_NODE_TYPES.IfStatement]: ts.IfStatement; + [AST_NODE_TYPES.Import]: ts.ImportExpression; + [AST_NODE_TYPES.ImportDeclaration]: ts.ImportDeclaration; + [AST_NODE_TYPES.ImportDefaultSpecifier]: ts.ImportClause; + [AST_NODE_TYPES.ImportNamespaceSpecifier]: ts.NamespaceImport; + [AST_NODE_TYPES.ImportSpecifier]: ts.ImportSpecifier; + [AST_NODE_TYPES.JSXAttribute]: ts.JsxAttribute; + [AST_NODE_TYPES.JSXClosingElement]: ts.JsxClosingElement; + [AST_NODE_TYPES.JSXClosingFragment]: ts.JsxClosingFragment; + [AST_NODE_TYPES.JSXElement]: ts.JsxElement | ts.JsxSelfClosingElement; + [AST_NODE_TYPES.JSXEmptyExpression]: ts.JsxExpression; + [AST_NODE_TYPES.JSXExpressionContainer]: ts.JsxExpression; + [AST_NODE_TYPES.JSXFragment]: ts.JsxFragment; + [AST_NODE_TYPES.JSXIdentifier]: ts.Identifier | ts.ThisExpression; + [AST_NODE_TYPES.JSXOpeningElement]: + | ts.JsxOpeningElement + | ts.JsxSelfClosingElement; + [AST_NODE_TYPES.JSXOpeningFragment]: ts.JsxOpeningFragment; + [AST_NODE_TYPES.JSXSpreadAttribute]: ts.JsxSpreadAttribute; + [AST_NODE_TYPES.JSXSpreadChild]: ts.JsxExpression; + [AST_NODE_TYPES.JSXMemberExpression]: ts.PropertyAccessExpression; + [AST_NODE_TYPES.JSXText]: ts.JsxText; + [AST_NODE_TYPES.LabeledStatement]: ts.LabeledStatement; + [AST_NODE_TYPES.Literal]: + | ts.StringLiteral + | ts.NumericLiteral + | ts.RegularExpressionLiteral + | ts.JsxText + | ts.NullLiteral + | ts.BooleanLiteral; + [AST_NODE_TYPES.LogicalExpression]: ts.BinaryExpression; + [AST_NODE_TYPES.MemberExpression]: + | ts.PropertyAccessExpression + | ts.ElementAccessExpression; + [AST_NODE_TYPES.MetaProperty]: ts.MetaProperty; + [AST_NODE_TYPES.MethodDefinition]: + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration + | ts.MethodDeclaration + | ts.ConstructorDeclaration; + [AST_NODE_TYPES.NewExpression]: ts.NewExpression; + [AST_NODE_TYPES.ObjectExpression]: ts.ObjectLiteralExpression; + [AST_NODE_TYPES.ObjectPattern]: + | ts.ObjectLiteralExpression + | ts.ObjectBindingPattern; + [AST_NODE_TYPES.OptionalCallExpression]: ts.CallExpression; + [AST_NODE_TYPES.OptionalMemberExpression]: + | ts.PropertyAccessExpression + | ts.ElementAccessExpression; + [AST_NODE_TYPES.Program]: ts.SourceFile; + [AST_NODE_TYPES.Property]: + | ts.PropertyAssignment + | ts.ShorthandPropertyAssignment + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration + | ts.MethodDeclaration + | ts.BindingElement; + [AST_NODE_TYPES.RestElement]: + | ts.BindingElement + | ts.SpreadAssignment + | ts.SpreadElement + | ts.ParameterDeclaration; + [AST_NODE_TYPES.ReturnStatement]: ts.ReturnStatement; + [AST_NODE_TYPES.SequenceExpression]: ts.BinaryExpression; + [AST_NODE_TYPES.SpreadElement]: ts.SpreadElement | ts.SpreadAssignment; + [AST_NODE_TYPES.Super]: ts.SuperExpression; + [AST_NODE_TYPES.SwitchCase]: ts.CaseClause | ts.DefaultClause; + [AST_NODE_TYPES.SwitchStatement]: ts.SwitchStatement; + [AST_NODE_TYPES.TaggedTemplateExpression]: ts.TaggedTemplateExpression; + [AST_NODE_TYPES.TemplateElement]: + | ts.NoSubstitutionTemplateLiteral + | ts.TemplateHead + | ts.TemplateMiddle + | ts.TemplateTail; + [AST_NODE_TYPES.TemplateLiteral]: + | ts.NoSubstitutionTemplateLiteral + | ts.TemplateExpression; + [AST_NODE_TYPES.ThisExpression]: ts.ThisExpression | ts.KeywordTypeNode; + [AST_NODE_TYPES.ThrowStatement]: ts.ThrowStatement; + [AST_NODE_TYPES.TryStatement]: ts.TryStatement; + [AST_NODE_TYPES.TSAbstractClassProperty]: ts.PropertyDeclaration; + [AST_NODE_TYPES.TSAbstractMethodDefinition]: + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration + | ts.MethodDeclaration + | ts.ConstructorDeclaration; + [AST_NODE_TYPES.TSArrayType]: ts.ArrayTypeNode; + [AST_NODE_TYPES.TSAsExpression]: ts.AsExpression; + [AST_NODE_TYPES.TSCallSignatureDeclaration]: ts.PropertySignature; + [AST_NODE_TYPES.TSClassImplements]: ts.ExpressionWithTypeArguments; + [AST_NODE_TYPES.TSConditionalType]: ts.ConditionalTypeNode; + [AST_NODE_TYPES.TSConstructorType]: ts.ConstructorTypeNode; + [AST_NODE_TYPES.TSConstructSignatureDeclaration]: + | ts.ConstructorTypeNode + | ts.FunctionTypeNode + | ts.ConstructSignatureDeclaration + | ts.CallSignatureDeclaration; + [AST_NODE_TYPES.TSDeclareFunction]: ts.FunctionDeclaration; + [AST_NODE_TYPES.TSEnumDeclaration]: ts.EnumDeclaration; + [AST_NODE_TYPES.TSEnumMember]: ts.EnumMember; + [AST_NODE_TYPES.TSExportAssignment]: ts.ExportAssignment; + [AST_NODE_TYPES.TSExternalModuleReference]: ts.ExternalModuleReference; + [AST_NODE_TYPES.TSFunctionType]: ts.FunctionTypeNode; + [AST_NODE_TYPES.TSImportEqualsDeclaration]: ts.ImportEqualsDeclaration; + [AST_NODE_TYPES.TSImportType]: ts.ImportTypeNode; + [AST_NODE_TYPES.TSIndexedAccessType]: ts.IndexedAccessTypeNode; + [AST_NODE_TYPES.TSIndexSignature]: ts.IndexSignatureDeclaration; + [AST_NODE_TYPES.TSInferType]: ts.InferTypeNode; + [AST_NODE_TYPES.TSInterfaceDeclaration]: ts.InterfaceDeclaration; + [AST_NODE_TYPES.TSInterfaceBody]: ts.InterfaceDeclaration; + [AST_NODE_TYPES.TSInterfaceHeritage]: ts.ExpressionWithTypeArguments; + [AST_NODE_TYPES.TSIntersectionType]: ts.IntersectionTypeNode; + [AST_NODE_TYPES.TSLiteralType]: ts.LiteralTypeNode; + [AST_NODE_TYPES.TSMappedType]: ts.MappedTypeNode; + [AST_NODE_TYPES.TSMethodSignature]: ts.MethodSignature; + [AST_NODE_TYPES.TSModuleBlock]: ts.ModuleBlock; + [AST_NODE_TYPES.TSModuleDeclaration]: ts.ModuleDeclaration; + [AST_NODE_TYPES.TSNamespaceExportDeclaration]: ts.NamespaceExportDeclaration; + [AST_NODE_TYPES.TSNonNullExpression]: ts.NonNullExpression; + [AST_NODE_TYPES.TSOptionalType]: ts.OptionalTypeNode; + [AST_NODE_TYPES.TSParameterProperty]: ts.ParameterDeclaration; + [AST_NODE_TYPES.TSParenthesizedType]: ts.ParenthesizedTypeNode; + [AST_NODE_TYPES.TSPropertySignature]: ts.PropertySignature; + [AST_NODE_TYPES.TSQualifiedName]: ts.QualifiedName; + [AST_NODE_TYPES.TSRestType]: ts.RestTypeNode; + [AST_NODE_TYPES.TSThisType]: ts.ThisTypeNode; + [AST_NODE_TYPES.TSTupleType]: ts.TupleTypeNode; + [AST_NODE_TYPES.TSTypeAliasDeclaration]: ts.TypeAliasDeclaration; + [AST_NODE_TYPES.TSTypeAnnotation]: undefined; + [AST_NODE_TYPES.TSTypeAssertion]: ts.TypeAssertion; + [AST_NODE_TYPES.TSTypeLiteral]: ts.TypeLiteralNode; + [AST_NODE_TYPES.TSTypeOperator]: ts.TypeOperatorNode; + [AST_NODE_TYPES.TSTypeParameter]: ts.TypeParameterDeclaration; + [AST_NODE_TYPES.TSTypeParameterDeclaration]: undefined; + [AST_NODE_TYPES.TSTypeParameterInstantiation]: + | ts.TaggedTemplateExpression + | ts.ImportTypeNode + | ts.ExpressionWithTypeArguments + | ts.TypeReferenceNode + | ts.JsxOpeningElement + | ts.JsxSelfClosingElement + | ts.NewExpression + | ts.CallExpression; + [AST_NODE_TYPES.TSTypePredicate]: ts.TypePredicateNode; + [AST_NODE_TYPES.TSTypeQuery]: ts.TypeQueryNode; + [AST_NODE_TYPES.TSTypeReference]: ts.TypeReferenceNode; + [AST_NODE_TYPES.TSUnionType]: ts.UnionTypeNode; + [AST_NODE_TYPES.UpdateExpression]: + | ts.PrefixUnaryExpression + | ts.PostfixUnaryExpression; + [AST_NODE_TYPES.UnaryExpression]: + | ts.PrefixUnaryExpression + | ts.PostfixUnaryExpression + | ts.DeleteExpression + | ts.VoidExpression + | ts.TypeOfExpression; + [AST_NODE_TYPES.VariableDeclaration]: + | ts.VariableDeclarationList + | ts.VariableStatement; + [AST_NODE_TYPES.VariableDeclarator]: ts.VariableDeclaration; + [AST_NODE_TYPES.WhileStatement]: ts.WhileStatement; + [AST_NODE_TYPES.WithStatement]: ts.WithStatement; + [AST_NODE_TYPES.YieldExpression]: ts.YieldExpression; + + // Added by parser + // Should be same as AST_NODE_TYPES.FunctionExpression + [AST_NODE_TYPES.TSEmptyBodyFunctionExpression]: + | ts.FunctionExpression + | ts.ConstructorDeclaration + | ts.GetAccessorDeclaration + | ts.SetAccessorDeclaration + | ts.MethodDeclaration; + + // Keywords + [AST_NODE_TYPES.TSAbstractKeyword]: ts.Token; + [AST_NODE_TYPES.TSNullKeyword]: ts.NullLiteral | ts.KeywordTypeNode; + + [AST_NODE_TYPES.TSAnyKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSBigIntKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSBooleanKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSNeverKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSNumberKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSObjectKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSStringKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSSymbolKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSUnknownKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSVoidKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSUndefinedKeyword]: ts.KeywordTypeNode; + + // Unused + [AST_NODE_TYPES.TSAsyncKeyword]: ts.Token; + [AST_NODE_TYPES.TSDeclareKeyword]: ts.Token; + [AST_NODE_TYPES.TSExportKeyword]: ts.Token; + [AST_NODE_TYPES.TSStaticKeyword]: ts.Token; + [AST_NODE_TYPES.TSPublicKeyword]: ts.Token; + [AST_NODE_TYPES.TSPrivateKeyword]: ts.Token; + [AST_NODE_TYPES.TSProtectedKeyword]: ts.Token; + [AST_NODE_TYPES.TSReadonlyKeyword]: ts.Token; +} + +/** + * Maps TSESTree AST Node type to the expected TypeScript AST Node type(s). + * This mapping is based on the internal logic of the parser. + */ +export type TSESTreeToTSNode = Extract< + TSNode | ts.Token, + EstreeToTsNodeTypes[T['type']] +>; diff --git a/packages/typescript-estree/src/ts-estree/index.ts b/packages/typescript-estree/src/ts-estree/index.ts index 5bed681f209..459edb57877 100644 --- a/packages/typescript-estree/src/ts-estree/index.ts +++ b/packages/typescript-estree/src/ts-estree/index.ts @@ -3,3 +3,4 @@ import * as TSESTree from './ts-estree'; export { TSESTree }; export * from './ast-node-types'; export * from './ts-nodes'; +export * from './estree-to-ts-node-types'; diff --git a/packages/typescript-estree/src/ts-estree/ts-nodes.ts b/packages/typescript-estree/src/ts-estree/ts-nodes.ts index eb99af20780..825aceab97d 100644 --- a/packages/typescript-estree/src/ts-estree/ts-nodes.ts +++ b/packages/typescript-estree/src/ts-estree/ts-nodes.ts @@ -1,5 +1,7 @@ import * as ts from 'typescript'; +export type TSToken = ts.Token; + export type TSNode = ts.Node & ( | ts.Modifier @@ -30,7 +32,7 @@ export type TSNode = ts.Node & | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration | ts.IndexSignatureDeclaration - | ts.KeywordTypeNode + | ts.KeywordTypeNode // TODO: This node is bad, maybe we should report this | ts.ImportTypeNode | ts.ThisTypeNode // | ts.FunctionOrConstructorTypeNodeBase -> FunctionTypeNode, ConstructorTypeNode