From 2e82fbd3ee6e75409a8cf719f8f758190726090c Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 20 Aug 2024 16:02:26 -0400 Subject: [PATCH 1/3] chore: enable eslint-plugin-perfectionist on typescript-estree package --- eslint.config.mjs | 5 +- .../typescript-estree/src/ast-converter.ts | 9 +- .../typescript-estree/src/convert-comments.ts | 7 +- packages/typescript-estree/src/convert.ts | 1447 +++++++++-------- .../WatchCompilerHostOfConfigFile.ts | 2 +- .../create-program/createIsolatedProgram.ts | 11 +- .../create-program/createProjectProgram.ts | 8 +- .../createProjectProgramError.ts | 2 +- .../create-program/createProjectService.ts | 16 +- .../src/create-program/createSourceFile.ts | 7 +- .../src/create-program/getParsedConfigFile.ts | 8 +- .../src/create-program/getScriptKind.ts | 23 +- .../getWatchProgramsForProjects.ts | 8 +- .../src/create-program/shared.ts | 12 +- .../src/create-program/useProvidedPrograms.ts | 8 +- .../src/createParserServices.ts | 2 +- packages/typescript-estree/src/index.ts | 14 +- .../src/jsx/xhtml-entities.ts | 446 ++--- packages/typescript-estree/src/node-utils.ts | 57 +- .../src/parseSettings/ExpiringCache.ts | 26 +- .../src/parseSettings/createParseSettings.ts | 7 +- .../parseSettings/getProjectConfigFiles.ts | 3 +- .../src/parseSettings/index.ts | 2 +- .../src/parseSettings/resolveProjectList.ts | 3 +- .../typescript-estree/src/parser-options.ts | 30 +- packages/typescript-estree/src/parser.ts | 38 +- .../src/semantic-or-syntactic-errors.ts | 1 + .../typescript-estree/src/simple-traverse.ts | 3 +- .../src/ts-estree/estree-to-ts-node-types.ts | 96 +- .../typescript-estree/src/ts-estree/index.ts | 4 +- .../src/ts-estree/ts-nodes.ts | 336 ++-- .../src/use-at-your-own-risk.ts | 10 +- .../src/useProgramFromProjectService.ts | 12 +- .../tests/lib/convert.test.ts | 30 +- .../tests/lib/createParseSettings.test.ts | 4 +- .../tests/lib/createProjectService.test.ts | 8 +- .../tests/lib/getParsedConfigFile.test.ts | 9 +- .../tests/lib/getProjectConfigFiles.test.ts | 8 +- .../tests/lib/parse.project-true.test.ts | 2 +- .../typescript-estree/tests/lib/parse.test.ts | 39 +- .../tests/lib/persistentParse.test.ts | 19 +- .../tests/lib/semanticInfo-singleRun.test.ts | 15 +- .../tests/lib/semanticInfo.test.ts | 28 +- .../lib/useProgramFromProjectService.test.ts | 6 +- .../lib/withoutProjectParserOptions.test.ts | 1 + .../tests/test-utils/test-utils.ts | 3 +- .../typescript-estree/typings/typescript.d.ts | 8 +- 47 files changed, 1432 insertions(+), 1411 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 60b302d8cb50..ade8f0cb00b3 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -578,7 +578,10 @@ export default tseslint.config( }, { extends: [perfectionistPlugin.configs['recommended-alphabetical']], - files: ['packages/utils/src/**/*.ts'], + files: [ + 'packages/typescript-estree/{src,tests,typings}/**/*.ts', + 'packages/utils/src/**/*.ts', + ], rules: { 'perfectionist/sort-classes': [ 'error', diff --git a/packages/typescript-estree/src/ast-converter.ts b/packages/typescript-estree/src/ast-converter.ts index a4cb0a4b7ddb..65b993cbefa9 100644 --- a/packages/typescript-estree/src/ast-converter.ts +++ b/packages/typescript-estree/src/ast-converter.ts @@ -1,18 +1,19 @@ import type { SourceFile } from 'typescript'; import type { ASTMaps } from './convert'; +import type { ParseSettings } from './parseSettings'; +import type { TSESTree } from './ts-estree'; + import { Converter, convertError } from './convert'; import { convertComments } from './convert-comments'; import { convertTokens } from './node-utils'; -import type { ParseSettings } from './parseSettings'; import { simpleTraverse } from './simple-traverse'; -import type { TSESTree } from './ts-estree'; export function astConverter( ast: SourceFile, parseSettings: ParseSettings, shouldPreserveNodeMaps: boolean, -): { estree: TSESTree.Program; astMaps: ASTMaps } { +): { astMaps: ASTMaps; estree: TSESTree.Program } { /** * The TypeScript compiler produced fundamental parse errors when parsing the * source. @@ -71,5 +72,5 @@ export function astConverter( const astMaps = instance.getASTMaps(); - return { estree, astMaps }; + return { astMaps, estree }; } diff --git a/packages/typescript-estree/src/convert-comments.ts b/packages/typescript-estree/src/convert-comments.ts index db1278baa4cb..aedc93ad2d50 100644 --- a/packages/typescript-estree/src/convert-comments.ts +++ b/packages/typescript-estree/src/convert-comments.ts @@ -1,8 +1,9 @@ import * as tsutils from 'ts-api-utils'; import * as ts from 'typescript'; -import { getLocFor } from './node-utils'; import type { TSESTree } from './ts-estree'; + +import { getLocFor } from './node-utils'; import { AST_TOKEN_TYPES } from './ts-estree'; /** @@ -37,10 +38,10 @@ export function convertComments( : // multiline comments end 2 characters early range[1] - textStart - 2; comments.push({ + loc, + range, type, value: code.slice(textStart, textStart + textEnd), - range, - loc, }); }, ast, diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 7fab3f5eaac4..e1e09078c03d 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -2,8 +2,15 @@ /* eslint-disable @typescript-eslint/no-non-null-assertion, @typescript-eslint/no-unnecessary-condition, @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-member-access */ import * as ts from 'typescript'; -import { getDecorators, getModifiers } from './getModifiers'; import type { TSError } from './node-utils'; +import type { + ParserWeakMap, + ParserWeakMapESTreeToTSNode, +} from './parser-options'; +import type { SemanticOrSyntacticError } from './semantic-or-syntactic-errors'; +import type { TSESTree, TSESTreeToTSNode, TSNode } from './ts-estree'; + +import { getDecorators, getModifiers } from './getModifiers'; import { canContainDirective, createError, @@ -32,12 +39,6 @@ import { nodeIsPresent, unescapeStringLiteralText, } from './node-utils'; -import type { - ParserWeakMap, - ParserWeakMapESTreeToTSNode, -} from './parser-options'; -import type { SemanticOrSyntacticError } from './semantic-or-syntactic-errors'; -import type { TSESTree, TSESTreeToTSNode, TSNode } from './ts-estree'; import { AST_NODE_TYPES } from './ts-estree'; const SyntaxKind = ts.SyntaxKind; @@ -70,12 +71,12 @@ export interface ASTMaps { } export class Converter { + private allowPattern = false; private readonly ast: ts.SourceFile; - private readonly options: ConverterOptions; private readonly esTreeNodeToTSNodeMap = new WeakMap(); - private readonly tsNodeToESTreeNodeMap = new WeakMap(); + private readonly options: ConverterOptions; - private allowPattern = false; + private readonly tsNodeToESTreeNodeMap = new WeakMap(); /** * Converts a TypeScript node into an ESTree node @@ -88,6 +89,10 @@ export class Converter { this.options = { ...options }; } + convertProgram(): TSESTree.Program { + return this.converter(this.ast) as TSESTree.Program; + } + getASTMaps(): ASTMaps { return { esTreeNodeToTSNodeMap: this.esTreeNodeToTSNodeMap, @@ -95,10 +100,6 @@ export class Converter { }; } - convertProgram(): TSESTree.Program { - return this.converter(this.ast) as TSESTree.Program; - } - /** * Converts a TypeScript node into an ESTree node. * @param node the child ts.Node @@ -187,10 +188,10 @@ export class Converter { return this.createNode( node as Exclude, { - type: AST_NODE_TYPES.ExportDefaultDeclaration, declaration: result as TSESTree.DefaultExportDeclarations, - range: [exportKeyword.getStart(this.ast), result.range[1]], exportKind: 'value', + range: [exportKeyword.getStart(this.ast), result.range[1]], + type: AST_NODE_TYPES.ExportDefaultDeclaration, }, ); } @@ -203,13 +204,13 @@ export class Converter { // @ts-expect-error - TODO, narrow the types here this.#withDeprecatedAliasGetter( { - type: AST_NODE_TYPES.ExportNamedDeclaration, + attributes: [], declaration: result, - specifiers: [], - source: null, exportKind: isType || isDeclare ? 'type' : 'value', range: [exportKeyword.getStart(this.ast), result.range[1]], - attributes: [], + source: null, + specifiers: [], + type: AST_NODE_TYPES.ExportNamedDeclaration, }, 'assertions', 'attributes', @@ -251,6 +252,21 @@ export class Converter { * @param parent parentNode * @returns the converted ESTree node */ + private convertBindingNameWithTypeAnnotation( + name: ts.BindingName, + tsType: ts.TypeNode | undefined, + parent?: ts.Node, + ): TSESTree.BindingName { + const id = this.convertPattern(name) as TSESTree.BindingName; + + if (tsType) { + id.typeAnnotation = this.convertTypeAnnotation(tsType, parent); + this.fixParentLocation(id, id.typeAnnotation.range); + } + + return id; + } + private convertChild(child?: ts.Node, parent?: ts.Node): any { return this.converter(child, parent, false); } @@ -270,21 +286,6 @@ export class Converter { return result as T; } - private convertBindingNameWithTypeAnnotation( - name: ts.BindingName, - tsType: ts.TypeNode | undefined, - parent?: ts.Node, - ): TSESTree.BindingName { - const id = this.convertPattern(name) as TSESTree.BindingName; - - if (tsType) { - id.typeAnnotation = this.convertTypeAnnotation(tsType, parent); - this.fixParentLocation(id, id.typeAnnotation.range); - } - - return id; - } - /** * Converts a child into a type annotation. This creates an intermediary * TypeAnnotation node to match what Flow does. @@ -307,9 +308,9 @@ export class Converter { const loc = getLocFor(range, this.ast); return { - type: AST_NODE_TYPES.TSTypeAnnotation, loc, range, + type: AST_NODE_TYPES.TSTypeAnnotation, typeAnnotation: this.convertChild(child), } as TSESTree.TSTypeAnnotation; } @@ -366,11 +367,11 @@ export class Converter { const greaterThanToken = findNextToken(typeArguments, this.ast, this.ast)!; return this.createNode(node, { - type: AST_NODE_TYPES.TSTypeParameterInstantiation, - range: [typeArguments.pos - 1, greaterThanToken.end], params: typeArguments.map(typeArgument => this.convertChild(typeArgument), ), + range: [typeArguments.pos - 1, greaterThanToken.end], + type: AST_NODE_TYPES.TSTypeParameterInstantiation, }); } @@ -389,12 +390,12 @@ export class Converter { ]; return { - type: AST_NODE_TYPES.TSTypeParameterDeclaration, - range, loc: getLocFor(range, this.ast), params: typeParameters.map(typeParameter => this.convertChild(typeParameter), ), + range, + type: AST_NODE_TYPES.TSTypeParameterDeclaration, } as TSESTree.TSTypeParameterDeclaration; } @@ -403,22 +404,6 @@ export class Converter { * @param parameters An array of ts.Node params to be converted * @returns an array of converted ESTreeNode params */ - private convertParameters( - parameters: ts.NodeArray, - ): TSESTree.Parameter[] { - if (!parameters?.length) { - return []; - } - return parameters.map(param => { - const convertedParam = this.convertChild(param) as TSESTree.Parameter; - - convertedParam.decorators = - getDecorators(param)?.map(el => this.convertChild(el)) ?? []; - - return convertedParam; - }); - } - private convertChainExpression( node: TSESTree.ChainElement, tsNode: @@ -458,8 +443,24 @@ export class Converter { } return this.createNode(tsNode, { - type: AST_NODE_TYPES.ChainExpression, expression: node, + type: AST_NODE_TYPES.ChainExpression, + }); + } + + private convertParameters( + parameters: ts.NodeArray, + ): TSESTree.Parameter[] { + if (!parameters?.length) { + return []; + } + return parameters.map(param => { + const convertedParam = this.convertChild(param) as TSESTree.Parameter; + + convertedParam.decorators = + getDecorators(param)?.map(el => this.convertChild(el)) ?? []; + + return convertedParam; }); } @@ -468,6 +469,66 @@ export class Converter { * ESTree mostly as-is. The only difference is the addition of a type * property instead of a kind property. Recursively copies all children. */ + private convertJSXIdentifier( + node: ts.Identifier | ts.ThisExpression, + ): TSESTree.JSXIdentifier { + const result = this.createNode(node, { + name: node.getText(), + type: AST_NODE_TYPES.JSXIdentifier, + }); + this.registerTSNodeInNodeMap(node, result); + return result; + } + + private convertJSXNamespaceOrIdentifier( + node: ts.Identifier | ts.JsxNamespacedName | ts.ThisExpression, + ): TSESTree.JSXIdentifier | TSESTree.JSXNamespacedName { + // TypeScript@5.1 added in ts.JsxNamespacedName directly + // We prefer using that if it's relevant for this node type + if (node.kind === ts.SyntaxKind.JsxNamespacedName) { + const result = this.createNode(node, { + name: this.createNode(node.name, { + name: node.name.text, + type: AST_NODE_TYPES.JSXIdentifier, + }), + namespace: this.createNode(node.namespace, { + name: node.namespace.text, + type: AST_NODE_TYPES.JSXIdentifier, + }), + type: AST_NODE_TYPES.JSXNamespacedName, + }); + this.registerTSNodeInNodeMap(node, result); + return result; + } + + // TypeScript@<5.1 has to manually parse the JSX attributes + const text = node.getText(); + const colonIndex = text.indexOf(':'); + // this is intentional we can ignore conversion if `:` is in first character + if (colonIndex > 0) { + const range = getRange(node, this.ast); + // @ts-expect-error -- TypeScript@<5.1 doesn't have ts.JsxNamespacedName + const result = this.createNode(node, { + name: this.createNode(node, { + name: text.slice(colonIndex + 1), + range: [range[0] + colonIndex + 1, range[1]], + type: AST_NODE_TYPES.JSXIdentifier, + }), + namespace: this.createNode(node, { + name: text.slice(0, colonIndex), + range: [range[0], range[0] + colonIndex], + type: AST_NODE_TYPES.JSXIdentifier, + }), + range, + type: AST_NODE_TYPES.JSXNamespacedName, + }); + this.registerTSNodeInNodeMap(node, result); + return result; + } + + return this.convertJSXIdentifier(node); + } + private deeplyCopy(node: TSNode): any { if (node.kind === ts.SyntaxKind.JSDocFunctionType) { this.#throwError( @@ -558,71 +619,19 @@ export class Converter { return result; } - private convertJSXIdentifier( - node: ts.Identifier | ts.ThisExpression, - ): TSESTree.JSXIdentifier { - const result = this.createNode(node, { - type: AST_NODE_TYPES.JSXIdentifier, - name: node.getText(), - }); - this.registerTSNodeInNodeMap(node, result); - return result; - } - - private convertJSXNamespaceOrIdentifier( - node: ts.JsxNamespacedName | ts.Identifier | ts.ThisExpression, - ): TSESTree.JSXIdentifier | TSESTree.JSXNamespacedName { - // TypeScript@5.1 added in ts.JsxNamespacedName directly - // We prefer using that if it's relevant for this node type - if (node.kind === ts.SyntaxKind.JsxNamespacedName) { - const result = this.createNode(node, { - type: AST_NODE_TYPES.JSXNamespacedName, - namespace: this.createNode(node.namespace, { - type: AST_NODE_TYPES.JSXIdentifier, - name: node.namespace.text, - }), - name: this.createNode(node.name, { - type: AST_NODE_TYPES.JSXIdentifier, - name: node.name.text, - }), - }); - this.registerTSNodeInNodeMap(node, result); - return result; - } - - // TypeScript@<5.1 has to manually parse the JSX attributes - const text = node.getText(); - const colonIndex = text.indexOf(':'); - // this is intentional we can ignore conversion if `:` is in first character - if (colonIndex > 0) { - const range = getRange(node, this.ast); - // @ts-expect-error -- TypeScript@<5.1 doesn't have ts.JsxNamespacedName - const result = this.createNode(node, { - type: AST_NODE_TYPES.JSXNamespacedName, - namespace: this.createNode(node, { - type: AST_NODE_TYPES.JSXIdentifier, - name: text.slice(0, colonIndex), - range: [range[0], range[0] + colonIndex], - }), - name: this.createNode(node, { - type: AST_NODE_TYPES.JSXIdentifier, - name: text.slice(colonIndex + 1), - range: [range[0] + colonIndex + 1, range[1]], - }), - range, - }); - this.registerTSNodeInNodeMap(node, result); - return result; - } - - return this.convertJSXIdentifier(node); - } - /** * Converts a TypeScript JSX node.tagName into an ESTree node.name * @param node the tagName object from a JSX ts.Node * @returns the converted ESTree name object */ + private convertImportAttributes( + node: ts.ImportAttributes | undefined, + ): TSESTree.ImportAttribute[] { + return node === undefined + ? [] + : node.elements.map(element => this.convertChild(element)); + } + private convertJSXTagName( node: ts.JsxTagNameExpression, parent: ts.Node, @@ -637,9 +646,9 @@ export class Converter { } result = this.createNode(node, { - type: AST_NODE_TYPES.JSXMemberExpression, object: this.convertJSXTagName(node.expression, parent), property: this.convertJSXIdentifier(node.name), + type: AST_NODE_TYPES.JSXMemberExpression, }); break; @@ -660,7 +669,6 @@ export class Converter { | ts.SetAccessorDeclaration, ): TSESTree.TSMethodSignature { return this.createNode(node, { - type: AST_NODE_TYPES.TSMethodSignature, accessibility: getTSNodeAccessibility(node), computed: isComputedProperty(node.name), key: this.convertChild(node.name), @@ -678,9 +686,10 @@ export class Converter { })(), optional: isOptional(node), params: this.convertParameters(node.parameters), - returnType: node.type && this.convertTypeAnnotation(node.type, node), readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node), + returnType: node.type && this.convertTypeAnnotation(node.type, node), static: hasModifier(SyntaxKind.StaticKeyword, node), + type: AST_NODE_TYPES.TSMethodSignature, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -689,33 +698,11 @@ export class Converter { }); } - private convertImportAttributes( - node: ts.ImportAttributes | undefined, - ): TSESTree.ImportAttribute[] { - return node === undefined - ? [] - : node.elements.map(element => this.convertChild(element)); - } - /** * Uses the provided range location to adjust the location data of the given Node * @param result The node that will have its location data mutated * @param childRange The child node range used to expand location */ - private fixParentLocation( - result: TSESTree.BaseNode, - childRange: [number, number], - ): void { - if (childRange[0] < result.range[0]) { - result.range[0] = childRange[0]; - result.loc.start = getLineAndCharacterFor(result.range[0], this.ast); - } - if (childRange[1] > result.range[1]) { - result.range[1] = childRange[1]; - result.loc.end = getLineAndCharacterFor(result.range[1], this.ast); - } - } - private assertModuleSpecifier( node: ts.ExportDeclaration | ts.ImportDeclaration, allowNull: boolean, @@ -738,29 +725,300 @@ export class Converter { } } + private fixParentLocation( + result: TSESTree.BaseNode, + childRange: [number, number], + ): void { + if (childRange[0] < result.range[0]) { + result.range[0] = childRange[0]; + result.loc.start = getLineAndCharacterFor(result.range[0], this.ast); + } + if (childRange[1] > result.range[1]) { + result.range[1] = childRange[1]; + result.loc.end = getLineAndCharacterFor(result.range[1], this.ast); + } + } + /** * Converts a TypeScript node into an ESTree node. * The core of the conversion logic: * Identify and convert each relevant TypeScript SyntaxKind * @returns the converted ESTree node */ + #checkModifiers(node: ts.Node): void { + if (this.options.allowInvalidAST) { + return; + } + + // typescript<5.0.0 + if (nodeHasIllegalDecorators(node)) { + this.#throwError( + node.illegalDecorators[0], + 'Decorators are not valid here.', + ); + } + + for (const decorator of getDecorators( + node, + /* includeIllegalDecorators */ true, + ) ?? []) { + // `checkGrammarModifiers` function in typescript + if (!nodeCanBeDecorated(node as TSNode)) { + if (ts.isMethodDeclaration(node) && !nodeIsPresent(node.body)) { + this.#throwError( + decorator, + 'A decorator can only decorate a method implementation, not an overload.', + ); + } else { + this.#throwError(decorator, 'Decorators are not valid here.'); + } + } + } + + for (const modifier of getModifiers( + node, + /* includeIllegalModifiers */ true, + ) ?? []) { + if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { + if ( + node.kind === SyntaxKind.PropertySignature || + node.kind === SyntaxKind.MethodSignature + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier cannot appear on a type member`, + ); + } + + if ( + node.kind === SyntaxKind.IndexSignature && + (modifier.kind !== SyntaxKind.StaticKeyword || + !ts.isClassLike(node.parent)) + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier cannot appear on an index signature`, + ); + } + } + + if ( + modifier.kind !== SyntaxKind.InKeyword && + modifier.kind !== SyntaxKind.OutKeyword && + modifier.kind !== SyntaxKind.ConstKeyword && + node.kind === SyntaxKind.TypeParameter + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier cannot appear on a type parameter`, + ); + } + + if ( + (modifier.kind === SyntaxKind.InKeyword || + modifier.kind === SyntaxKind.OutKeyword) && + (node.kind !== SyntaxKind.TypeParameter || + !( + ts.isInterfaceDeclaration(node.parent) || + ts.isClassLike(node.parent) || + ts.isTypeAliasDeclaration(node.parent) + )) + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier can only appear on a type parameter of a class, interface or type alias`, + ); + } + + if ( + modifier.kind === SyntaxKind.ReadonlyKeyword && + node.kind !== SyntaxKind.PropertyDeclaration && + node.kind !== SyntaxKind.PropertySignature && + node.kind !== SyntaxKind.IndexSignature && + node.kind !== SyntaxKind.Parameter + ) { + this.#throwError( + modifier, + "'readonly' modifier can only appear on a property declaration or index signature.", + ); + } + + if ( + modifier.kind === SyntaxKind.DeclareKeyword && + ts.isClassLike(node.parent) && + !ts.isPropertyDeclaration(node) + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier cannot appear on class elements of this kind.`, + ); + } + + if ( + modifier.kind === SyntaxKind.DeclareKeyword && + ts.isVariableStatement(node) + ) { + const declarationKind = getDeclarationKind(node.declarationList); + if (declarationKind === 'using' || declarationKind === 'await using') { + this.#throwError( + modifier, + `'declare' modifier cannot appear on a '${declarationKind}' declaration.`, + ); + } + } + + if ( + modifier.kind === SyntaxKind.AbstractKeyword && + node.kind !== SyntaxKind.ClassDeclaration && + node.kind !== SyntaxKind.ConstructorType && + node.kind !== SyntaxKind.MethodDeclaration && + node.kind !== SyntaxKind.PropertyDeclaration && + node.kind !== SyntaxKind.GetAccessor && + node.kind !== SyntaxKind.SetAccessor + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier can only appear on a class, method, or property declaration.`, + ); + } + + if ( + (modifier.kind === SyntaxKind.StaticKeyword || + modifier.kind === SyntaxKind.PublicKeyword || + modifier.kind === SyntaxKind.ProtectedKeyword || + modifier.kind === SyntaxKind.PrivateKeyword) && + (node.parent.kind === SyntaxKind.ModuleBlock || + node.parent.kind === SyntaxKind.SourceFile) + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier cannot appear on a module or namespace element.`, + ); + } + + if ( + modifier.kind === SyntaxKind.AccessorKeyword && + node.kind !== SyntaxKind.PropertyDeclaration + ) { + this.#throwError( + modifier, + "'accessor' modifier can only appear on a property declaration.", + ); + } + + // `checkGrammarAsyncModifier` function in `typescript` + if ( + modifier.kind === SyntaxKind.AsyncKeyword && + node.kind !== SyntaxKind.MethodDeclaration && + node.kind !== SyntaxKind.FunctionDeclaration && + node.kind !== SyntaxKind.FunctionExpression && + node.kind !== SyntaxKind.ArrowFunction + ) { + this.#throwError(modifier, "'async' modifier cannot be used here."); + } + + // `checkGrammarModifiers` function in `typescript` + if ( + node.kind === SyntaxKind.Parameter && + (modifier.kind === SyntaxKind.StaticKeyword || + modifier.kind === SyntaxKind.ExportKeyword || + modifier.kind === SyntaxKind.DeclareKeyword || + modifier.kind === SyntaxKind.AsyncKeyword) + ) { + this.#throwError( + modifier, + `'${ts.tokenToString( + modifier.kind, + )}' modifier cannot appear on a parameter.`, + ); + } + + // `checkGrammarModifiers` function in `typescript` + if ( + modifier.kind === SyntaxKind.PublicKeyword || + modifier.kind === SyntaxKind.ProtectedKeyword || + modifier.kind === SyntaxKind.PrivateKeyword + ) { + for (const anotherModifier of getModifiers(node) ?? []) { + if ( + anotherModifier !== modifier && + (anotherModifier.kind === SyntaxKind.PublicKeyword || + anotherModifier.kind === SyntaxKind.ProtectedKeyword || + anotherModifier.kind === SyntaxKind.PrivateKeyword) + ) { + this.#throwError( + anotherModifier, + `Accessibility modifier already seen.`, + ); + } + } + } + + // `checkParameter` function in `typescript` + if ( + node.kind === SyntaxKind.Parameter && + // In `typescript` package, it's `ts.hasSyntacticModifier(node, ts.ModifierFlags.ParameterPropertyModifier)` + // https://github.com/typescript-eslint/typescript-eslint/pull/6615#discussion_r1136489935 + (modifier.kind === SyntaxKind.PublicKeyword || + modifier.kind === SyntaxKind.PrivateKeyword || + modifier.kind === SyntaxKind.ProtectedKeyword || + modifier.kind === SyntaxKind.ReadonlyKeyword || + modifier.kind === SyntaxKind.OverrideKeyword) + ) { + const func = getContainingFunction(node)!; + + if ( + !(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body)) + ) { + this.#throwError( + modifier, + 'A parameter property is only allowed in a constructor implementation.', + ); + } + } + } + } + + #throwUnlessAllowInvalidAST( + node: ts.Node | number, + message: string, + ): asserts node is never { + if (!this.options.allowInvalidAST) { + this.#throwError(node, message); + } + } + private convertNode(node: TSNode, parent: TSNode): TSESTree.Node | null { switch (node.kind) { case SyntaxKind.SourceFile: { return this.createNode(node, { - type: AST_NODE_TYPES.Program, body: this.convertBodyExpressions(node.statements, node), comments: undefined, range: [node.getStart(this.ast), node.endOfFileToken.end], sourceType: node.externalModuleIndicator ? 'module' : 'script', tokens: undefined, + type: AST_NODE_TYPES.Program, }); } case SyntaxKind.Block: { return this.createNode(node, { - type: AST_NODE_TYPES.BlockStatement, body: this.convertBodyExpressions(node.statements, node), + type: AST_NODE_TYPES.BlockStatement, }); } @@ -773,10 +1031,10 @@ export class Converter { }); } return this.createNode(node, { - type: AST_NODE_TYPES.Identifier, decorators: [], name: node.text, optional: false, + type: AST_NODE_TYPES.Identifier, typeAnnotation: undefined, }); } @@ -791,46 +1049,46 @@ export class Converter { case SyntaxKind.WithStatement: return this.createNode(node, { - type: AST_NODE_TYPES.WithStatement, - object: this.convertChild(node.expression), body: this.convertChild(node.statement), + object: this.convertChild(node.expression), + type: AST_NODE_TYPES.WithStatement, }); // Control Flow case SyntaxKind.ReturnStatement: return this.createNode(node, { - type: AST_NODE_TYPES.ReturnStatement, argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.ReturnStatement, }); case SyntaxKind.LabeledStatement: return this.createNode(node, { - type: AST_NODE_TYPES.LabeledStatement, - label: this.convertChild(node.label), body: this.convertChild(node.statement), + label: this.convertChild(node.label), + type: AST_NODE_TYPES.LabeledStatement, }); case SyntaxKind.ContinueStatement: return this.createNode(node, { - type: AST_NODE_TYPES.ContinueStatement, label: this.convertChild(node.label), + type: AST_NODE_TYPES.ContinueStatement, }); case SyntaxKind.BreakStatement: return this.createNode(node, { - type: AST_NODE_TYPES.BreakStatement, label: this.convertChild(node.label), + type: AST_NODE_TYPES.BreakStatement, }); // Choice 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), + consequent: this.convertChild(node.thenStatement), + test: this.convertChild(node.expression), + type: AST_NODE_TYPES.IfStatement, }); case SyntaxKind.SwitchStatement: @@ -846,9 +1104,9 @@ export class Converter { } return this.createNode(node, { - type: AST_NODE_TYPES.SwitchStatement, - discriminant: this.convertChild(node.expression), cases: node.caseBlock.clauses.map(el => this.convertChild(el)), + discriminant: this.convertChild(node.expression), + type: AST_NODE_TYPES.SwitchStatement, }); case SyntaxKind.CaseClause: @@ -856,11 +1114,11 @@ export class Converter { return this.createNode(node, { type: AST_NODE_TYPES.SwitchCase, // expression is present in case only + consequent: node.statements.map(el => this.convertChild(el)), test: node.kind === SyntaxKind.CaseClause ? this.convertChild(node.expression) : null, - consequent: node.statements.map(el => this.convertChild(el)), }); // Exceptions @@ -874,16 +1132,16 @@ export class Converter { } return this.createNode(node, { - type: AST_NODE_TYPES.ThrowStatement, argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.ThrowStatement, }); 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), + handler: this.convertChild(node.catchClause), + type: AST_NODE_TYPES.TryStatement, }); case SyntaxKind.CatchClause: @@ -894,23 +1152,23 @@ export class Converter { ); } return this.createNode(node, { - type: AST_NODE_TYPES.CatchClause, + body: this.convertChild(node.block), param: node.variableDeclaration ? this.convertBindingNameWithTypeAnnotation( node.variableDeclaration.name, node.variableDeclaration.type, ) : null, - body: this.convertChild(node.block), + type: AST_NODE_TYPES.CatchClause, }); // Loops case SyntaxKind.WhileStatement: return this.createNode(node, { - type: AST_NODE_TYPES.WhileStatement, - test: this.convertChild(node.expression), body: this.convertChild(node.statement), + test: this.convertChild(node.expression), + type: AST_NODE_TYPES.WhileStatement, }); /** @@ -919,40 +1177,40 @@ export class Converter { */ case SyntaxKind.DoStatement: return this.createNode(node, { - type: AST_NODE_TYPES.DoWhileStatement, - test: this.convertChild(node.expression), body: this.convertChild(node.statement), + test: this.convertChild(node.expression), + type: AST_NODE_TYPES.DoWhileStatement, }); case SyntaxKind.ForStatement: return this.createNode(node, { - type: AST_NODE_TYPES.ForStatement, + body: this.convertChild(node.statement), init: this.convertChild(node.initializer), test: this.convertChild(node.condition), + type: AST_NODE_TYPES.ForStatement, update: this.convertChild(node.incrementor), - body: this.convertChild(node.statement), }); case SyntaxKind.ForInStatement: this.#checkForStatementDeclaration(node.initializer, node.kind); return this.createNode(node, { - type: AST_NODE_TYPES.ForInStatement, + body: this.convertChild(node.statement), left: this.convertPattern(node.initializer), right: this.convertChild(node.expression), - body: this.convertChild(node.statement), + type: AST_NODE_TYPES.ForInStatement, }); case SyntaxKind.ForOfStatement: { this.#checkForStatementDeclaration(node.initializer, node.kind); 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, ), + body: this.convertChild(node.statement), + left: this.convertPattern(node.initializer), + right: this.convertChild(node.expression), + type: AST_NODE_TYPES.ForOfStatement, }); } @@ -990,9 +1248,6 @@ export class Converter { TSESTree.FunctionDeclaration | TSESTree.TSDeclareFunction >(node, { // declare implies no body due to the invariant above - type: !node.body - ? AST_NODE_TYPES.TSDeclareFunction - : AST_NODE_TYPES.FunctionDeclaration, async: isAsync, body: this.convertChild(node.body) || undefined, declare: isDeclare, @@ -1001,6 +1256,9 @@ export class Converter { id: this.convertChild(node.name), params: this.convertParameters(node.parameters), returnType: node.type && this.convertTypeAnnotation(node.type, node), + type: !node.body + ? AST_NODE_TYPES.TSDeclareFunction + : AST_NODE_TYPES.FunctionDeclaration, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -1036,21 +1294,21 @@ export class Converter { } } return this.createNode(node, { - type: AST_NODE_TYPES.VariableDeclarator, definite, id, init, + type: AST_NODE_TYPES.VariableDeclarator, }); } case SyntaxKind.VariableStatement: { const result = this.createNode(node, { - type: AST_NODE_TYPES.VariableDeclaration, declarations: node.declarationList.declarations.map(el => this.convertChild(el), ), declare: hasModifier(SyntaxKind.DeclareKeyword, node), kind: getDeclarationKind(node.declarationList), + type: AST_NODE_TYPES.VariableDeclaration, }); if (!result.declarations.length) { @@ -1078,7 +1336,7 @@ export class Converter { // Definite assignment only allowed for non-declare let and var if ( result.declare || - ['using', 'await using', 'const'].includes(result.kind) + ['await using', 'const', 'using'].includes(result.kind) ) { node.declarationList.declarations.forEach((declaration, i) => { if (result.declarations[i].definite) { @@ -1124,10 +1382,10 @@ export class Converter { // mostly for for-of, for-in case SyntaxKind.VariableDeclarationList: { const result = this.createNode(node, { - type: AST_NODE_TYPES.VariableDeclaration, declarations: node.declarations.map(el => this.convertChild(el)), declare: false, kind: getDeclarationKind(node), + type: AST_NODE_TYPES.VariableDeclaration, }); if (result.kind === 'using' || result.kind === 'await using') { @@ -1153,9 +1411,9 @@ export class Converter { case SyntaxKind.ExpressionStatement: return this.createNode(node, { - type: AST_NODE_TYPES.ExpressionStatement, directive: undefined, expression: this.convertChild(node.expression), + type: AST_NODE_TYPES.ExpressionStatement, }); case SyntaxKind.ThisKeyword: @@ -1167,16 +1425,16 @@ export class Converter { // TypeScript uses ArrayLiteralExpression in destructuring assignment, too if (this.allowPattern) { return this.createNode(node, { - type: AST_NODE_TYPES.ArrayPattern, decorators: [], elements: node.elements.map(el => this.convertPattern(el)), optional: false, + type: AST_NODE_TYPES.ArrayPattern, typeAnnotation: undefined, }); } return this.createNode(node, { - type: AST_NODE_TYPES.ArrayExpression, elements: node.elements.map(el => this.convertChild(el)), + type: AST_NODE_TYPES.ArrayExpression, }); } @@ -1184,10 +1442,10 @@ export class Converter { // TypeScript uses ObjectLiteralExpression in destructuring assignment, too if (this.allowPattern) { return this.createNode(node, { - type: AST_NODE_TYPES.ObjectPattern, decorators: [], optional: false, properties: node.properties.map(el => this.convertPattern(el)), + type: AST_NODE_TYPES.ObjectPattern, typeAnnotation: undefined, }); } @@ -1207,14 +1465,14 @@ export class Converter { } return this.createNode(node, { - type: AST_NODE_TYPES.ObjectExpression, properties, + type: AST_NODE_TYPES.ObjectExpression, }); } case SyntaxKind.PropertyAssignment: { // eslint-disable-next-line deprecation/deprecation - const { questionToken, exclamationToken } = node; + const { exclamationToken, questionToken } = node; if (questionToken) { this.#throwError( @@ -1231,20 +1489,20 @@ export class Converter { } return this.createNode(node, { - type: AST_NODE_TYPES.Property, - key: this.convertChild(node.name), - value: this.converter(node.initializer, node, this.allowPattern), computed: isComputedProperty(node.name), + key: this.convertChild(node.name), + kind: 'init', method: false, optional: false, shorthand: false, - kind: 'init', + type: AST_NODE_TYPES.Property, + value: this.converter(node.initializer, node, this.allowPattern), }); } case SyntaxKind.ShorthandPropertyAssignment: { // eslint-disable-next-line deprecation/deprecation - const { modifiers, questionToken, exclamationToken } = node; + const { exclamationToken, modifiers, questionToken } = node; if (modifiers) { this.#throwError( @@ -1269,31 +1527,31 @@ export class Converter { if (node.objectAssignmentInitializer) { return this.createNode(node, { - type: AST_NODE_TYPES.Property, + computed: false, key: this.convertChild(node.name), + kind: 'init', + method: false, + optional: false, + shorthand: true, + type: AST_NODE_TYPES.Property, value: this.createNode(node, { - type: AST_NODE_TYPES.AssignmentPattern, decorators: [], left: this.convertPattern(node.name), optional: false, right: this.convertChild(node.objectAssignmentInitializer), + type: AST_NODE_TYPES.AssignmentPattern, typeAnnotation: undefined, }), - computed: false, - method: false, - optional: false, - shorthand: true, - kind: 'init', }); } return this.createNode(node, { - type: AST_NODE_TYPES.Property, computed: false, key: this.convertChild(node.name), kind: 'init', method: false, optional: false, shorthand: true, + type: AST_NODE_TYPES.Property, value: this.convertChild(node.name), }); } @@ -1334,27 +1592,27 @@ export class Converter { | TSESTree.TSAbstractAccessorProperty | TSESTree.TSAbstractPropertyDefinition >(node, { - type, - key, accessibility: getTSNodeAccessibility(node), - value: isAbstract ? null : this.convertChild(node.initializer), computed: isComputedProperty(node.name), - static: hasModifier(SyntaxKind.StaticKeyword, node), - readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node), + declare: hasModifier(SyntaxKind.DeclareKeyword, node), decorators: getDecorators(node)?.map(el => this.convertChild(el)) ?? [], - - declare: hasModifier(SyntaxKind.DeclareKeyword, node), - override: hasModifier(SyntaxKind.OverrideKeyword, node), - typeAnnotation: - node.type && this.convertTypeAnnotation(node.type, node), + definite: !!node.exclamationToken, + key, optional: (key.type === AST_NODE_TYPES.Literal || node.name.kind === SyntaxKind.Identifier || node.name.kind === SyntaxKind.ComputedPropertyName || node.name.kind === SyntaxKind.PrivateIdentifier) && !!node.questionToken, - definite: !!node.exclamationToken, + override: hasModifier(SyntaxKind.OverrideKeyword, node), + + readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node), + static: hasModifier(SyntaxKind.StaticKeyword, node), + type, + typeAnnotation: + node.type && this.convertTypeAnnotation(node.type, node), + value: isAbstract ? null : this.convertChild(node.initializer), }); } @@ -1372,18 +1630,18 @@ export class Converter { const method = this.createNode< TSESTree.FunctionExpression | TSESTree.TSEmptyBodyFunctionExpression >(node, { - type: !node.body - ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression - : 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), declare: false, - range: [node.parameters.pos - 1, node.end], + expression: false, // ESTreeNode as ESTreeNode here + generator: !!node.asteriskToken, + id: null, params: [], + range: [node.parameters.pos - 1, node.end], returnType: node.type && this.convertTypeAnnotation(node.type, node), + type: !node.body + ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression + : AST_NODE_TYPES.FunctionExpression, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -1404,14 +1662,14 @@ export class Converter { method.params = node.parameters.map(el => this.convertChild(el)); result = this.createNode(node, { - type: AST_NODE_TYPES.Property, - key: this.convertChild(node.name), - value: method, computed: isComputedProperty(node.name), - optional: !!node.questionToken, + key: this.convertChild(node.name), + kind: 'init', method: node.kind === SyntaxKind.MethodDeclaration, + optional: !!node.questionToken, shorthand: false, - kind: 'init', + type: AST_NODE_TYPES.Property, + value: method, }); } else { // class @@ -1434,7 +1692,6 @@ export class Converter { result = this.createNode< TSESTree.MethodDefinition | TSESTree.TSAbstractMethodDefinition >(node, { - type: methodDefinitionType, accessibility: getTSNodeAccessibility(node), computed: isComputedProperty(node.name), decorators: @@ -1444,6 +1701,7 @@ export class Converter { optional: !!node.questionToken, override: hasModifier(SyntaxKind.OverrideKeyword, node), static: hasModifier(SyntaxKind.StaticKeyword, node), + type: methodDefinitionType, value: method, }); } @@ -1473,9 +1731,6 @@ export class Converter { const constructor = this.createNode< TSESTree.FunctionExpression | TSESTree.TSEmptyBodyFunctionExpression >(node, { - type: !node.body - ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression - : AST_NODE_TYPES.FunctionExpression, async: false, body: this.convertChild(node.body), declare: false, @@ -1485,6 +1740,9 @@ export class Converter { params: this.convertParameters(node.parameters), range: [node.parameters.pos - 1, node.end], returnType: node.type && this.convertTypeAnnotation(node.type, node), + type: !node.body + ? AST_NODE_TYPES.TSEmptyBodyFunctionExpression + : AST_NODE_TYPES.FunctionExpression, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -1497,11 +1755,11 @@ export class Converter { } const constructorKey = this.createNode(node, { - type: AST_NODE_TYPES.Identifier, decorators: [], name: 'constructor', optional: false, range: [constructorToken.getStart(this.ast), constructorToken.end], + type: AST_NODE_TYPES.Identifier, typeAnnotation: undefined, }); @@ -1510,24 +1768,23 @@ export class Converter { return this.createNode< TSESTree.MethodDefinition | TSESTree.TSAbstractMethodDefinition >(node, { - type: hasModifier(SyntaxKind.AbstractKeyword, node) - ? AST_NODE_TYPES.TSAbstractMethodDefinition - : AST_NODE_TYPES.MethodDefinition, accessibility: getTSNodeAccessibility(node), computed: false, decorators: [], - optional: false, key: constructorKey, kind: isStatic ? 'method' : 'constructor', + optional: false, override: false, static: isStatic, + type: hasModifier(SyntaxKind.AbstractKeyword, node) + ? AST_NODE_TYPES.TSAbstractMethodDefinition + : AST_NODE_TYPES.MethodDefinition, value: constructor, }); } case SyntaxKind.FunctionExpression: { return this.createNode(node, { - type: AST_NODE_TYPES.FunctionExpression, async: hasModifier(SyntaxKind.AsyncKeyword, node), body: this.convertChild(node.body), declare: false, @@ -1536,6 +1793,7 @@ export class Converter { id: this.convertChild(node.name), params: this.convertParameters(node.parameters), returnType: node.type && this.convertTypeAnnotation(node.type, node), + type: AST_NODE_TYPES.FunctionExpression, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -1551,10 +1809,10 @@ export class Converter { case SyntaxKind.ArrayBindingPattern: return this.createNode(node, { - type: AST_NODE_TYPES.ArrayPattern, decorators: [], elements: node.elements.map(el => this.convertPattern(el)), optional: false, + type: AST_NODE_TYPES.ArrayPattern, typeAnnotation: undefined, }); @@ -1564,10 +1822,10 @@ export class Converter { case SyntaxKind.ObjectBindingPattern: return this.createNode(node, { - type: AST_NODE_TYPES.ObjectPattern, decorators: [], optional: false, properties: node.elements.map(el => this.convertPattern(el)), + type: AST_NODE_TYPES.ObjectPattern, typeAnnotation: undefined, }); @@ -1577,19 +1835,19 @@ export class Converter { if (node.initializer) { return this.createNode(node, { - type: AST_NODE_TYPES.AssignmentPattern, decorators: [], left: arrayItem, optional: false, right: this.convertChild(node.initializer), + type: AST_NODE_TYPES.AssignmentPattern, typeAnnotation: undefined, }); } else if (node.dotDotDotToken) { return this.createNode(node, { - type: AST_NODE_TYPES.RestElement, argument: arrayItem, decorators: [], optional: false, + type: AST_NODE_TYPES.RestElement, typeAnnotation: undefined, value: undefined, }); @@ -1599,37 +1857,37 @@ export class Converter { let result: TSESTree.Property | TSESTree.RestElement; if (node.dotDotDotToken) { result = this.createNode(node, { - type: AST_NODE_TYPES.RestElement, argument: this.convertChild(node.propertyName ?? node.name), decorators: [], optional: false, + type: AST_NODE_TYPES.RestElement, typeAnnotation: undefined, value: undefined, }); } 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, ), + key: this.convertChild(node.propertyName ?? node.name), + kind: 'init', method: false, optional: false, shorthand: !node.propertyName, - kind: 'init', + type: AST_NODE_TYPES.Property, + value: this.convertChild(node.name), }); } if (node.initializer) { result.value = this.createNode(node, { - type: AST_NODE_TYPES.AssignmentPattern, decorators: [], left: this.convertChild(node.name), optional: false, range: [node.name.getStart(this.ast), node.initializer.end], right: this.convertChild(node.initializer), + type: AST_NODE_TYPES.AssignmentPattern, typeAnnotation: undefined, }); } @@ -1638,14 +1896,14 @@ export class Converter { case SyntaxKind.ArrowFunction: { return this.createNode(node, { - type: AST_NODE_TYPES.ArrowFunctionExpression, + async: hasModifier(SyntaxKind.AsyncKeyword, node), + body: this.convertChild(node.body), + expression: node.body.kind !== SyntaxKind.Block, 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, returnType: node.type && this.convertTypeAnnotation(node.type, node), + type: AST_NODE_TYPES.ArrowFunctionExpression, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -1656,43 +1914,43 @@ export class Converter { case SyntaxKind.YieldExpression: return this.createNode(node, { - type: AST_NODE_TYPES.YieldExpression, - delegate: !!node.asteriskToken, argument: this.convertChild(node.expression), + delegate: !!node.asteriskToken, + type: AST_NODE_TYPES.YieldExpression, }); case SyntaxKind.AwaitExpression: return this.createNode(node, { - type: AST_NODE_TYPES.AwaitExpression, argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.AwaitExpression, }); // Template Literals case SyntaxKind.NoSubstitutionTemplateLiteral: return this.createNode(node, { - type: AST_NODE_TYPES.TemplateLiteral, + expressions: [], quasis: [ this.createNode(node, { + tail: true, type: AST_NODE_TYPES.TemplateElement, value: { + cooked: node.text, raw: this.ast.text.slice( node.getStart(this.ast) + 1, node.end - 1, ), - cooked: node.text, }, - tail: true, }), ], - expressions: [], + type: AST_NODE_TYPES.TemplateLiteral, }); case SyntaxKind.TemplateExpression: { const result = this.createNode(node, { - type: AST_NODE_TYPES.TemplateLiteral, - quasis: [this.convertChild(node.head)], expressions: [], + quasis: [this.convertChild(node.head)], + type: AST_NODE_TYPES.TemplateLiteral, }); node.templateSpans.forEach(templateSpan => { @@ -1708,6 +1966,8 @@ export class Converter { case SyntaxKind.TaggedTemplateExpression: return this.createNode(node, { + quasi: this.convertChild(node.template), + tag: this.convertChild(node.tag), type: AST_NODE_TYPES.TaggedTemplateExpression, typeArguments: node.typeArguments && @@ -1715,8 +1975,6 @@ export class Converter { node.typeArguments, node, ), - tag: this.convertChild(node.tag), - quasi: this.convertChild(node.template), }); case SyntaxKind.TemplateHead: @@ -1724,15 +1982,15 @@ export class Converter { case SyntaxKind.TemplateTail: { const tail = node.kind === SyntaxKind.TemplateTail; return this.createNode(node, { + tail, type: AST_NODE_TYPES.TemplateElement, value: { + cooked: node.text, raw: this.ast.text.slice( node.getStart(this.ast) + 1, node.end - (tail ? 1 : 2), ), - cooked: node.text, }, - tail, }); } @@ -1742,17 +2000,17 @@ export class Converter { case SyntaxKind.SpreadElement: { if (this.allowPattern) { return this.createNode(node, { - type: AST_NODE_TYPES.RestElement, argument: this.convertPattern(node.expression), decorators: [], optional: false, + type: AST_NODE_TYPES.RestElement, typeAnnotation: undefined, value: undefined, }); } return this.createNode(node, { - type: AST_NODE_TYPES.SpreadElement, argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.SpreadElement, }); } @@ -1762,21 +2020,21 @@ export class Converter { if (node.dotDotDotToken) { parameter = result = this.createNode(node, { - type: AST_NODE_TYPES.RestElement, argument: this.convertChild(node.name), decorators: [], optional: false, + type: AST_NODE_TYPES.RestElement, typeAnnotation: undefined, value: undefined, }); } else if (node.initializer) { parameter = this.convertChild(node.name) as TSESTree.BindingName; result = this.createNode(node, { - type: AST_NODE_TYPES.AssignmentPattern, decorators: [], left: parameter, optional: false, right: this.convertChild(node.initializer), + type: AST_NODE_TYPES.AssignmentPattern, typeAnnotation: undefined, }); @@ -1812,13 +2070,13 @@ export class Converter { const modifiers = getModifiers(node); if (modifiers) { return this.createNode(node, { - type: AST_NODE_TYPES.TSParameterProperty, accessibility: getTSNodeAccessibility(node), decorators: [], override: hasModifier(SyntaxKind.OverrideKeyword, node), parameter: result, readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node), static: hasModifier(SyntaxKind.StaticKeyword, node), + type: AST_NODE_TYPES.TSParameterProperty, }); } return result; @@ -1895,14 +2153,13 @@ export class Converter { const result = this.createNode< TSESTree.ClassDeclaration | TSESTree.ClassExpression >(node, { - type: classNodeType, abstract: hasModifier(SyntaxKind.AbstractKeyword, node), body: this.createNode(node, { - type: AST_NODE_TYPES.ClassBody, body: node.members .filter(isESTreeClassMember) .map(el => this.convertChild(el)), range: [node.members.pos - 1, node.end], + type: AST_NODE_TYPES.ClassBody, }), declare: hasModifier(SyntaxKind.DeclareKeyword, node), decorators: @@ -1914,6 +2171,7 @@ export class Converter { ? this.convertChild(extendsClause.types[0].expression) : null, superTypeArguments: undefined, + type: classNodeType, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -1935,8 +2193,8 @@ export class Converter { // Modules case SyntaxKind.ModuleBlock: return this.createNode(node, { - type: AST_NODE_TYPES.TSModuleBlock, body: this.convertBodyExpressions(node.statements, node), + type: AST_NODE_TYPES.TSModuleBlock, }); case SyntaxKind.ImportDeclaration: { @@ -1946,14 +2204,14 @@ export class Converter { node, this.#withDeprecatedAliasGetter( { - type: AST_NODE_TYPES.ImportDeclaration, - source: this.convertChild(node.moduleSpecifier), - specifiers: [], - importKind: 'value', attributes: this.convertImportAttributes( // eslint-disable-next-line deprecation/deprecation -- TS <5.3 node.attributes ?? node.assertClause, ), + importKind: 'value', + source: this.convertChild(node.moduleSpecifier), + specifiers: [], + type: AST_NODE_TYPES.ImportDeclaration, }, 'assertions', 'attributes', @@ -1996,24 +2254,24 @@ export class Converter { case SyntaxKind.NamespaceImport: return this.createNode(node, { - type: AST_NODE_TYPES.ImportNamespaceSpecifier, local: this.convertChild(node.name), + type: AST_NODE_TYPES.ImportNamespaceSpecifier, }); case SyntaxKind.ImportSpecifier: return this.createNode(node, { - type: AST_NODE_TYPES.ImportSpecifier, - local: this.convertChild(node.name), imported: this.convertChild(node.propertyName ?? node.name), importKind: node.isTypeOnly ? 'type' : 'value', + local: this.convertChild(node.name), + type: AST_NODE_TYPES.ImportSpecifier, }); case SyntaxKind.ImportClause: { const local = this.convertChild(node.name); return this.createNode(node, { - type: AST_NODE_TYPES.ImportDefaultSpecifier, local, range: local.range, + type: AST_NODE_TYPES.ImportDefaultSpecifier, }); } @@ -2024,17 +2282,17 @@ export class Converter { node, this.#withDeprecatedAliasGetter( { - type: AST_NODE_TYPES.ExportNamedDeclaration, - source: this.convertChild(node.moduleSpecifier), - specifiers: node.exportClause.elements.map(el => - this.convertChild(el), - ), - exportKind: node.isTypeOnly ? 'type' : 'value', - declaration: null, attributes: this.convertImportAttributes( // eslint-disable-next-line deprecation/deprecation -- TS <5.3 node.attributes ?? node.assertClause, ), + declaration: null, + exportKind: node.isTypeOnly ? 'type' : 'value', + source: this.convertChild(node.moduleSpecifier), + specifiers: node.exportClause.elements.map(el => + this.convertChild(el), + ), + type: AST_NODE_TYPES.ExportNamedDeclaration, }, 'assertions', 'attributes', @@ -2047,17 +2305,17 @@ export class Converter { node, this.#withDeprecatedAliasGetter( { - type: AST_NODE_TYPES.ExportAllDeclaration, - source: this.convertChild(node.moduleSpecifier), - exportKind: node.isTypeOnly ? 'type' : 'value', - exported: - node.exportClause?.kind === SyntaxKind.NamespaceExport - ? this.convertChild(node.exportClause.name) - : null, attributes: this.convertImportAttributes( // eslint-disable-next-line deprecation/deprecation -- TS <5.3 node.attributes ?? node.assertClause, ), + exported: + node.exportClause?.kind === SyntaxKind.NamespaceExport + ? this.convertChild(node.exportClause.name) + : null, + exportKind: node.isTypeOnly ? 'type' : 'value', + source: this.convertChild(node.moduleSpecifier), + type: AST_NODE_TYPES.ExportAllDeclaration, }, 'assertions', 'attributes', @@ -2068,23 +2326,23 @@ export class Converter { case SyntaxKind.ExportSpecifier: return this.createNode(node, { - type: AST_NODE_TYPES.ExportSpecifier, - local: this.convertChild(node.propertyName ?? node.name), exported: this.convertChild(node.name), exportKind: node.isTypeOnly ? 'type' : 'value', + local: this.convertChild(node.propertyName ?? node.name), + type: AST_NODE_TYPES.ExportSpecifier, }); case SyntaxKind.ExportAssignment: if (node.isExportEquals) { return this.createNode(node, { - type: AST_NODE_TYPES.TSExportAssignment, expression: this.convertChild(node.expression), + type: AST_NODE_TYPES.TSExportAssignment, }); } return this.createNode(node, { - type: AST_NODE_TYPES.ExportDefaultDeclaration, declaration: this.convertChild(node.expression), exportKind: 'value', + type: AST_NODE_TYPES.ExportDefaultDeclaration, }); // Unary Operations @@ -2103,48 +2361,48 @@ export class Converter { ); } return this.createNode(node, { - type: AST_NODE_TYPES.UpdateExpression, + argument: this.convertChild(node.operand), operator, prefix: node.kind === SyntaxKind.PrefixUnaryExpression, - argument: this.convertChild(node.operand), + type: AST_NODE_TYPES.UpdateExpression, }); } return this.createNode(node, { - type: AST_NODE_TYPES.UnaryExpression, + argument: this.convertChild(node.operand), operator, prefix: node.kind === SyntaxKind.PrefixUnaryExpression, - argument: this.convertChild(node.operand), + type: AST_NODE_TYPES.UnaryExpression, }); } case SyntaxKind.DeleteExpression: return this.createNode(node, { - type: AST_NODE_TYPES.UnaryExpression, + argument: this.convertChild(node.expression), operator: 'delete', prefix: true, - argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.UnaryExpression, }); case SyntaxKind.VoidExpression: return this.createNode(node, { - type: AST_NODE_TYPES.UnaryExpression, + argument: this.convertChild(node.expression), operator: 'void', prefix: true, - argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.UnaryExpression, }); case SyntaxKind.TypeOfExpression: return this.createNode(node, { - type: AST_NODE_TYPES.UnaryExpression, + argument: this.convertChild(node.expression), operator: 'typeof', prefix: true, - argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.UnaryExpression, }); case SyntaxKind.TypeOperator: return this.createNode(node, { - type: AST_NODE_TYPES.TSTypeOperator, operator: getTextForTokenKind(node.operator), + type: AST_NODE_TYPES.TSTypeOperator, typeAnnotation: this.convertChild(node.type), }); @@ -2154,8 +2412,8 @@ export class Converter { // TypeScript uses BinaryExpression for sequences as well if (isComma(node.operatorToken)) { const result = this.createNode(node, { - type: AST_NODE_TYPES.SequenceExpression, expressions: [], + type: AST_NODE_TYPES.SequenceExpression, }); const left = this.convertChild(node.left) as TSESTree.Expression; @@ -2179,11 +2437,11 @@ export class Converter { expressionType.type === AST_NODE_TYPES.AssignmentExpression ) { return this.createNode(node, { - type: AST_NODE_TYPES.AssignmentPattern, decorators: [], left: this.convertPattern(node.left, node), optional: false, right: this.convertChild(node.right), + type: AST_NODE_TYPES.AssignmentPattern, typeAnnotation: undefined, }); } @@ -2208,11 +2466,11 @@ export class Converter { const computed = false; const result = this.createNode(node, { - type: AST_NODE_TYPES.MemberExpression, - object, - property, computed, + object, optional: node.questionDotToken !== undefined, + property, + type: AST_NODE_TYPES.MemberExpression, }); return this.convertChainExpression(result, node); @@ -2224,11 +2482,11 @@ export class Converter { const computed = true; const result = this.createNode(node, { - type: AST_NODE_TYPES.MemberExpression, - object, - property, computed, + object, optional: node.questionDotToken !== undefined, + property, + type: AST_NODE_TYPES.MemberExpression, }); return this.convertChainExpression(result, node); @@ -2243,11 +2501,11 @@ export class Converter { ); } return this.createNode(node, { - type: AST_NODE_TYPES.ImportExpression, - source: this.convertChild(node.arguments[0]), attributes: node.arguments[1] ? this.convertChild(node.arguments[1]) : null, + source: this.convertChild(node.arguments[0]), + type: AST_NODE_TYPES.ImportExpression, }); } @@ -2261,10 +2519,10 @@ export class Converter { ); const result = this.createNode(node, { - type: AST_NODE_TYPES.CallExpression, - callee, arguments: args, + callee, optional: node.questionDotToken !== undefined, + type: AST_NODE_TYPES.CallExpression, typeArguments, }); @@ -2281,45 +2539,45 @@ export class Converter { // NOTE - NewExpression cannot have an optional chain in it return this.createNode(node, { - type: AST_NODE_TYPES.NewExpression, arguments: node.arguments ? node.arguments.map(el => this.convertChild(el)) : [], callee: this.convertChild(node.expression), + type: AST_NODE_TYPES.NewExpression, typeArguments, }); } 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), + consequent: this.convertChild(node.whenTrue), + test: this.convertChild(node.condition), + type: AST_NODE_TYPES.ConditionalExpression, }); case SyntaxKind.MetaProperty: { return this.createNode(node, { - type: AST_NODE_TYPES.MetaProperty, meta: this.createNode( // TODO: do we really want to convert it to Token? node.getFirstToken()! as ts.Token, { - type: AST_NODE_TYPES.Identifier, decorators: [], name: getTextForTokenKind(node.keywordToken), optional: false, + type: AST_NODE_TYPES.Identifier, typeAnnotation: undefined, }, ), property: this.convertChild(node.name), + type: AST_NODE_TYPES.MetaProperty, }); } case SyntaxKind.Decorator: { return this.createNode(node, { - type: AST_NODE_TYPES.Decorator, expression: this.convertChild(node.expression), + type: AST_NODE_TYPES.Decorator, }); } @@ -2327,20 +2585,20 @@ export class Converter { case SyntaxKind.StringLiteral: { return this.createNode(node, { + raw: node.getText(), type: AST_NODE_TYPES.Literal, value: parent.kind === SyntaxKind.JsxAttribute ? unescapeStringLiteralText(node.text) : node.text, - raw: node.getText(), }); } case SyntaxKind.NumericLiteral: { return this.createNode(node, { + raw: node.getText(), type: AST_NODE_TYPES.Literal, value: Number(node.text), - raw: node.getText(), }); } @@ -2355,11 +2613,11 @@ export class Converter { .replaceAll('_', ''); const value = typeof BigInt !== 'undefined' ? BigInt(bigint) : null; return this.createNode(node, { - type: AST_NODE_TYPES.Literal, - raw: rawValue, - value, bigint: value == null ? bigint : String(value), range, + raw: rawValue, + type: AST_NODE_TYPES.Literal, + value, }); } @@ -2375,35 +2633,35 @@ export class Converter { } return this.createNode(node, { - type: AST_NODE_TYPES.Literal, - value: regex, raw: node.text, regex: { - pattern, flags, + pattern, }, + type: AST_NODE_TYPES.Literal, + value: regex, }); } case SyntaxKind.TrueKeyword: return this.createNode(node, { + raw: 'true', type: AST_NODE_TYPES.Literal, value: true, - raw: 'true', }); case SyntaxKind.FalseKeyword: return this.createNode(node, { + raw: 'false', type: AST_NODE_TYPES.Literal, value: false, - raw: 'false', }); case SyntaxKind.NullKeyword: { return this.createNode(node, { + raw: 'null', type: AST_NODE_TYPES.Literal, value: null, - raw: 'null', }); } @@ -2421,18 +2679,18 @@ export class Converter { 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)), + closingElement: this.convertChild(node.closingElement), + openingElement: this.convertChild(node.openingElement), + type: AST_NODE_TYPES.JSXElement, }); 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)), + closingFragment: this.convertChild(node.closingFragment), + openingFragment: this.convertChild(node.openingFragment), + type: AST_NODE_TYPES.JSXFragment, }); case SyntaxKind.JsxSelfClosingElement: { @@ -2442,7 +2700,15 @@ export class Converter { * Convert SyntaxKind.JsxSelfClosingElement to SyntaxKind.JsxOpeningElement, * TypeScript does not seem to have the idea of openingElement when tag is self-closing */ + children: [], + closingElement: null, openingElement: this.createNode(node, { + attributes: node.attributes.properties.map(el => + this.convertChild(el), + ), + name: this.convertJSXTagName(node.tagName, node), + range: getRange(node, this.ast), + selfClosing: true, type: AST_NODE_TYPES.JSXOpeningElement, typeArguments: node.typeArguments ? this.convertTypeArgumentsToTypeParameterInstantiation( @@ -2450,20 +2716,17 @@ export class Converter { node, ) : undefined, - selfClosing: true, - name: this.convertJSXTagName(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, { + attributes: node.attributes.properties.map(el => + this.convertChild(el), + ), + name: this.convertJSXTagName(node.tagName, node), + selfClosing: false, type: AST_NODE_TYPES.JSXOpeningElement, typeArguments: node.typeArguments && @@ -2471,18 +2734,13 @@ export class Converter { node.typeArguments, node, ), - selfClosing: false, - name: this.convertJSXTagName(node.tagName, node), - attributes: node.attributes.properties.map(el => - this.convertChild(el), - ), }); } case SyntaxKind.JsxClosingElement: return this.createNode(node, { - type: AST_NODE_TYPES.JSXClosingElement, name: this.convertJSXTagName(node.tagName, node), + type: AST_NODE_TYPES.JSXClosingElement, }); case SyntaxKind.JsxOpeningFragment: @@ -2499,26 +2757,26 @@ export class Converter { 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], + type: AST_NODE_TYPES.JSXEmptyExpression, }); if (node.dotDotDotToken) { return this.createNode(node, { - type: AST_NODE_TYPES.JSXSpreadChild, expression, + type: AST_NODE_TYPES.JSXSpreadChild, }); } return this.createNode(node, { - type: AST_NODE_TYPES.JSXExpressionContainer, expression, + type: AST_NODE_TYPES.JSXExpressionContainer, }); } case SyntaxKind.JsxAttribute: { return this.createNode(node, { - type: AST_NODE_TYPES.JSXAttribute, name: this.convertJSXNamespaceOrIdentifier(node.name), + type: AST_NODE_TYPES.JSXAttribute, value: this.convertChild(node.initializer), }); } @@ -2529,24 +2787,24 @@ export class Converter { const text = this.ast.text.slice(start, end); return this.createNode(node, { + range: [start, end], + raw: text, type: AST_NODE_TYPES.JSXText, value: unescapeStringLiteralText(text), - raw: text, - range: [start, end], }); } case SyntaxKind.JsxSpreadAttribute: return this.createNode(node, { - type: AST_NODE_TYPES.JSXSpreadAttribute, argument: this.convertChild(node.expression), + type: AST_NODE_TYPES.JSXSpreadAttribute, }); case SyntaxKind.QualifiedName: { return this.createNode(node, { - type: AST_NODE_TYPES.TSQualifiedName, left: this.convertChild(node.left), right: this.convertChild(node.right), + type: AST_NODE_TYPES.TSQualifiedName, }); } @@ -2555,24 +2813,24 @@ export class Converter { case SyntaxKind.TypeReference: return this.createNode(node, { type: AST_NODE_TYPES.TSTypeReference, - typeName: this.convertChild(node.typeName), typeArguments: node.typeArguments && this.convertTypeArgumentsToTypeParameterInstantiation( node.typeArguments, node, ), + typeName: this.convertChild(node.typeName), }); case SyntaxKind.TypeParameter: { return this.createNode(node, { - type: AST_NODE_TYPES.TSTypeParameter, - name: this.convertChild(node.name), + const: hasModifier(SyntaxKind.ConstKeyword, node), constraint: node.constraint && this.convertChild(node.constraint), default: node.default ? this.convertChild(node.default) : undefined, in: hasModifier(SyntaxKind.InKeyword, node), + name: this.convertChild(node.name), out: hasModifier(SyntaxKind.OutKeyword, node), - const: hasModifier(SyntaxKind.ConstKeyword, node), + type: AST_NODE_TYPES.TSTypeParameter, }); } @@ -2600,8 +2858,8 @@ export class Converter { case SyntaxKind.NonNullExpression: { const nnExpr = this.createNode(node, { - type: AST_NODE_TYPES.TSNonNullExpression, expression: this.convertChild(node.expression), + type: AST_NODE_TYPES.TSNonNullExpression, }); return this.convertChainExpression(nnExpr, node); @@ -2609,40 +2867,40 @@ export class Converter { case SyntaxKind.TypeLiteral: { return this.createNode(node, { - type: AST_NODE_TYPES.TSTypeLiteral, members: node.members.map(el => this.convertChild(el)), + type: AST_NODE_TYPES.TSTypeLiteral, }); } case SyntaxKind.ArrayType: { return this.createNode(node, { - type: AST_NODE_TYPES.TSArrayType, elementType: this.convertChild(node.elementType), + type: AST_NODE_TYPES.TSArrayType, }); } case SyntaxKind.IndexedAccessType: { return this.createNode(node, { - type: AST_NODE_TYPES.TSIndexedAccessType, - objectType: this.convertChild(node.objectType), indexType: this.convertChild(node.indexType), + objectType: this.convertChild(node.objectType), + type: AST_NODE_TYPES.TSIndexedAccessType, }); } case SyntaxKind.ConditionalType: { return this.createNode(node, { - type: AST_NODE_TYPES.TSConditionalType, checkType: this.convertChild(node.checkType), extendsType: this.convertChild(node.extendsType), - trueType: this.convertChild(node.trueType), falseType: this.convertChild(node.falseType), + trueType: this.convertChild(node.trueType), + type: AST_NODE_TYPES.TSConditionalType, }); } case SyntaxKind.TypeQuery: return this.createNode(node, { - type: AST_NODE_TYPES.TSTypeQuery, exprName: this.convertChild(node.exprName), + type: AST_NODE_TYPES.TSTypeQuery, typeArguments: node.typeArguments && this.convertTypeArgumentsToTypeParameterInstantiation( @@ -2663,7 +2921,6 @@ export class Converter { node, this.#withDeprecatedGetter( { - type: AST_NODE_TYPES.TSMappedType, constraint: this.convertChild(node.typeParameter.constraint), key: this.convertChild(node.typeParameter.name), nameType: this.convertChild(node.nameType) ?? null, @@ -2675,6 +2932,7 @@ export class Converter { node.readonlyToken && (node.readonlyToken.kind === SyntaxKind.ReadonlyKeyword || getTextForTokenKind(node.readonlyToken.kind)), + type: AST_NODE_TYPES.TSMappedType, typeAnnotation: node.type && this.convertChild(node.type), }, 'typeParameter', @@ -2689,9 +2947,9 @@ export class Converter { case SyntaxKind.TypeAliasDeclaration: { const result = this.createNode(node, { - type: AST_NODE_TYPES.TSTypeAliasDeclaration, declare: hasModifier(SyntaxKind.DeclareKeyword, node), id: this.convertChild(node.name), + type: AST_NODE_TYPES.TSTypeAliasDeclaration, typeAnnotation: this.convertChild(node.type), typeParameters: node.typeParameters && @@ -2718,13 +2976,13 @@ export class Converter { } return this.createNode(node, { - type: AST_NODE_TYPES.TSPropertySignature, accessibility: getTSNodeAccessibility(node), computed: isComputedProperty(node.name), key: this.convertChild(node.name), optional: isOptional(node), readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node), static: hasModifier(SyntaxKind.StaticKeyword, node), + type: AST_NODE_TYPES.TSPropertySignature, typeAnnotation: node.type && this.convertTypeAnnotation(node.type, node), }); @@ -2732,11 +2990,11 @@ export class Converter { case SyntaxKind.IndexSignature: { return this.createNode(node, { - type: AST_NODE_TYPES.TSIndexSignature, accessibility: getTSNodeAccessibility(node), parameters: node.parameters.map(el => this.convertChild(el)), readonly: hasModifier(SyntaxKind.ReadonlyKeyword, node), static: hasModifier(SyntaxKind.StaticKeyword, node), + type: AST_NODE_TYPES.TSIndexSignature, typeAnnotation: node.type && this.convertTypeAnnotation(node.type, node), }); @@ -2744,10 +3002,10 @@ export class Converter { case SyntaxKind.ConstructorType: { return this.createNode(node, { - type: AST_NODE_TYPES.TSConstructorType, abstract: hasModifier(SyntaxKind.AbstractKeyword, node), params: this.convertParameters(node.parameters), returnType: node.type && this.convertTypeAnnotation(node.type, node), + type: AST_NODE_TYPES.TSConstructorType, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -2781,9 +3039,9 @@ export class Converter { | TSESTree.TSConstructSignatureDeclaration | TSESTree.TSFunctionType >(node, { - type, params: this.convertParameters(node.parameters), returnType: node.type && this.convertTypeAnnotation(node.type, node), + type, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -2806,8 +3064,8 @@ export class Converter { | TSESTree.TSInstantiationExpression | TSESTree.TSInterfaceHeritage >(node, { - type, expression: this.convertChild(node.expression), + type, typeArguments: node.typeArguments && this.convertTypeArgumentsToTypeParameterInstantiation( @@ -2842,15 +3100,15 @@ export class Converter { } 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], + type: AST_NODE_TYPES.TSInterfaceBody, }), declare: hasModifier(SyntaxKind.DeclareKeyword, node), extends: interfaceExtends, id: this.convertChild(node.name), + type: AST_NODE_TYPES.TSInterfaceDeclaration, typeParameters: node.typeParameters && this.convertTSTypeParametersToTypeParametersDeclaration( @@ -2863,9 +3121,9 @@ export class Converter { case SyntaxKind.TypePredicate: { const result = this.createNode(node, { - type: AST_NODE_TYPES.TSTypePredicate, asserts: node.assertsModifier !== undefined, parameterName: this.convertChild(node.parameterName), + type: AST_NODE_TYPES.TSTypePredicate, typeAnnotation: null, }); /** @@ -2887,22 +3145,22 @@ export class Converter { range[0] = token.getStart(this.ast); } const result = this.createNode(node, { - type: AST_NODE_TYPES.TSImportType, argument: this.convertChild(node.argument), qualifier: this.convertChild(node.qualifier), + range, + type: AST_NODE_TYPES.TSImportType, typeArguments: node.typeArguments ? this.convertTypeArgumentsToTypeParameterInstantiation( node.typeArguments, node, ) : null, - range, }); if (node.isTypeOf) { return this.createNode(node, { - type: AST_NODE_TYPES.TSTypeQuery, exprName: result, + type: AST_NODE_TYPES.TSTypeQuery, typeArguments: undefined, }); } @@ -2915,15 +3173,15 @@ export class Converter { node, this.#withDeprecatedGetter( { - type: AST_NODE_TYPES.TSEnumDeclaration, body: this.createNode(node, { - type: AST_NODE_TYPES.TSEnumBody, members, range: [node.members.pos - 1, node.end], + type: AST_NODE_TYPES.TSEnumBody, }), const: hasModifier(SyntaxKind.ConstKeyword, node), declare: hasModifier(SyntaxKind.DeclareKeyword, node), id: this.convertChild(node.name), + type: AST_NODE_TYPES.TSEnumDeclaration, }, 'members', `'body.members'`, @@ -2936,10 +3194,10 @@ export class Converter { case SyntaxKind.EnumMember: { return this.createNode(node, { - type: AST_NODE_TYPES.TSEnumMember, computed: node.name.kind === ts.SyntaxKind.ComputedPropertyName, id: this.convertChild(node.name), initializer: node.initializer && this.convertChild(node.initializer), + type: AST_NODE_TYPES.TSEnumMember, }); } @@ -2978,11 +3236,11 @@ export class Converter { ); } return { - kind: 'global', body: body as TSESTree.TSModuleBlock, declare: false, global: false, id, + kind: 'global', }; } @@ -3044,18 +3302,18 @@ export class Converter { name = this.createNode(nextName, { left: name, - right, range: [name.range[0], right.range[1]], + right, type: AST_NODE_TYPES.TSQualifiedName, }); } return { - kind: 'namespace', body: this.convertChild(node.body), declare: false, global: false, id: name, + kind: 'namespace', }; })(), }); @@ -3088,8 +3346,8 @@ export class Converter { } case SyntaxKind.AsExpression: { return this.createNode(node, { - type: AST_NODE_TYPES.TSAsExpression, expression: this.convertChild(node.expression), + type: AST_NODE_TYPES.TSAsExpression, typeAnnotation: this.convertChild(node.type), }); } @@ -3112,25 +3370,25 @@ export class Converter { } return this.createNode(node, { - type: AST_NODE_TYPES.TSLiteralType, literal: this.convertChild(node.literal), + type: AST_NODE_TYPES.TSLiteralType, }); } case SyntaxKind.TypeAssertionExpression: { return this.createNode(node, { + expression: this.convertChild(node.expression), type: AST_NODE_TYPES.TSTypeAssertion, typeAnnotation: this.convertChild(node.type), - expression: this.convertChild(node.expression), }); } case SyntaxKind.ImportEqualsDeclaration: { return this.fixExports( node, this.createNode(node, { - type: AST_NODE_TYPES.TSImportEqualsDeclaration, id: this.convertChild(node.name), importKind: node.isTypeOnly ? 'type' : 'value', moduleReference: this.convertChild(node.moduleReference), + type: AST_NODE_TYPES.TSImportEqualsDeclaration, }), ); } @@ -3139,14 +3397,14 @@ export class Converter { this.#throwError(node.expression, 'String literal expected.'); } return this.createNode(node, { - type: AST_NODE_TYPES.TSExternalModuleReference, expression: this.convertChild(node.expression), + type: AST_NODE_TYPES.TSExternalModuleReference, }); } case SyntaxKind.NamespaceExportDeclaration: { return this.createNode(node, { - type: AST_NODE_TYPES.TSNamespaceExportDeclaration, id: this.convertChild(node.name), + type: AST_NODE_TYPES.TSNamespaceExportDeclaration, }); } case SyntaxKind.AbstractKeyword: { @@ -3160,16 +3418,16 @@ export class Converter { const elementTypes = node.elements.map(el => this.convertChild(el)); return this.createNode(node, { - type: AST_NODE_TYPES.TSTupleType, elementTypes, + type: AST_NODE_TYPES.TSTupleType, }); } case SyntaxKind.NamedTupleMember: { const member = this.createNode(node, { - type: AST_NODE_TYPES.TSNamedTupleMember, elementType: this.convertChild(node.type, node), label: this.convertChild(node.name, node), optional: node.questionToken != null, + type: AST_NODE_TYPES.TSNamedTupleMember, }); if (node.dotDotDotToken) { @@ -3200,8 +3458,8 @@ export class Converter { // Template Literal Types case SyntaxKind.TemplateLiteralType: { const result = this.createNode(node, { - type: AST_NODE_TYPES.TSTemplateLiteralType, quasis: [this.convertChild(node.head)], + type: AST_NODE_TYPES.TSTemplateLiteralType, types: [], }); @@ -3218,8 +3476,8 @@ export class Converter { case SyntaxKind.ClassStaticBlockDeclaration: { return this.createNode(node, { - type: AST_NODE_TYPES.StaticBlock, body: this.convertBodyExpressions(node.body.statements, node), + type: AST_NODE_TYPES.StaticBlock, }); } @@ -3227,293 +3485,95 @@ export class Converter { case SyntaxKind.AssertEntry: case SyntaxKind.ImportAttribute: { return this.createNode(node, { - type: AST_NODE_TYPES.ImportAttribute, key: this.convertChild(node.name), + type: AST_NODE_TYPES.ImportAttribute, value: this.convertChild(node.value), }); } - case SyntaxKind.SatisfiesExpression: { - return this.createNode(node, { - type: AST_NODE_TYPES.TSSatisfiesExpression, - expression: this.convertChild(node.expression), - typeAnnotation: this.convertChild(node.type), - }); - } - - default: - return this.deeplyCopy(node); - } - } - - #checkModifiers(node: ts.Node): void { - if (this.options.allowInvalidAST) { - return; - } - - // typescript<5.0.0 - if (nodeHasIllegalDecorators(node)) { - this.#throwError( - node.illegalDecorators[0], - 'Decorators are not valid here.', - ); - } - - for (const decorator of getDecorators( - node, - /* includeIllegalDecorators */ true, - ) ?? []) { - // `checkGrammarModifiers` function in typescript - if (!nodeCanBeDecorated(node as TSNode)) { - if (ts.isMethodDeclaration(node) && !nodeIsPresent(node.body)) { - this.#throwError( - decorator, - 'A decorator can only decorate a method implementation, not an overload.', - ); - } else { - this.#throwError(decorator, 'Decorators are not valid here.'); - } - } - } - - for (const modifier of getModifiers( - node, - /* includeIllegalModifiers */ true, - ) ?? []) { - if (modifier.kind !== SyntaxKind.ReadonlyKeyword) { - if ( - node.kind === SyntaxKind.PropertySignature || - node.kind === SyntaxKind.MethodSignature - ) { - this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier cannot appear on a type member`, - ); - } - - if ( - node.kind === SyntaxKind.IndexSignature && - (modifier.kind !== SyntaxKind.StaticKeyword || - !ts.isClassLike(node.parent)) - ) { - this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier cannot appear on an index signature`, - ); - } - } - - if ( - modifier.kind !== SyntaxKind.InKeyword && - modifier.kind !== SyntaxKind.OutKeyword && - modifier.kind !== SyntaxKind.ConstKeyword && - node.kind === SyntaxKind.TypeParameter - ) { - this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier cannot appear on a type parameter`, - ); - } - - if ( - (modifier.kind === SyntaxKind.InKeyword || - modifier.kind === SyntaxKind.OutKeyword) && - (node.kind !== SyntaxKind.TypeParameter || - !( - ts.isInterfaceDeclaration(node.parent) || - ts.isClassLike(node.parent) || - ts.isTypeAliasDeclaration(node.parent) - )) - ) { - this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier can only appear on a type parameter of a class, interface or type alias`, - ); - } - - if ( - modifier.kind === SyntaxKind.ReadonlyKeyword && - node.kind !== SyntaxKind.PropertyDeclaration && - node.kind !== SyntaxKind.PropertySignature && - node.kind !== SyntaxKind.IndexSignature && - node.kind !== SyntaxKind.Parameter - ) { - this.#throwError( - modifier, - "'readonly' modifier can only appear on a property declaration or index signature.", - ); - } - - if ( - modifier.kind === SyntaxKind.DeclareKeyword && - ts.isClassLike(node.parent) && - !ts.isPropertyDeclaration(node) - ) { - this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier cannot appear on class elements of this kind.`, - ); + case SyntaxKind.SatisfiesExpression: { + return this.createNode(node, { + expression: this.convertChild(node.expression), + type: AST_NODE_TYPES.TSSatisfiesExpression, + typeAnnotation: this.convertChild(node.type), + }); } - if ( - modifier.kind === SyntaxKind.DeclareKeyword && - ts.isVariableStatement(node) - ) { - const declarationKind = getDeclarationKind(node.declarationList); - if (declarationKind === 'using' || declarationKind === 'await using') { - this.#throwError( - modifier, - `'declare' modifier cannot appear on a '${declarationKind}' declaration.`, - ); - } - } + default: + return this.deeplyCopy(node); + } + } - if ( - modifier.kind === SyntaxKind.AbstractKeyword && - node.kind !== SyntaxKind.ClassDeclaration && - node.kind !== SyntaxKind.ConstructorType && - node.kind !== SyntaxKind.MethodDeclaration && - node.kind !== SyntaxKind.PropertyDeclaration && - node.kind !== SyntaxKind.GetAccessor && - node.kind !== SyntaxKind.SetAccessor - ) { + /** + * Creates a getter for a property under aliasKey that returns the value under + * valueKey. If suppressDeprecatedPropertyWarnings is not enabled, the + * getter also console warns about the deprecation. + * + * @see https://github.com/typescript-eslint/typescript-eslint/issues/6469 + */ + #checkForStatementDeclaration( + initializer: ts.ForInitializer, + kind: ts.SyntaxKind.ForInStatement | ts.SyntaxKind.ForOfStatement, + ): void { + const loop = + kind === ts.SyntaxKind.ForInStatement ? 'for...in' : 'for...of'; + if (ts.isVariableDeclarationList(initializer)) { + if (initializer.declarations.length !== 1) { this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier can only appear on a class, method, or property declaration.`, + initializer, + `Only a single variable declaration is allowed in a '${loop}' statement.`, ); } - - if ( - (modifier.kind === SyntaxKind.StaticKeyword || - modifier.kind === SyntaxKind.PublicKeyword || - modifier.kind === SyntaxKind.ProtectedKeyword || - modifier.kind === SyntaxKind.PrivateKeyword) && - (node.parent.kind === SyntaxKind.ModuleBlock || - node.parent.kind === SyntaxKind.SourceFile) - ) { + const declaration = initializer.declarations[0]; + if (declaration.initializer) { this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier cannot appear on a module or namespace element.`, + declaration, + `The variable declaration of a '${loop}' statement cannot have an initializer.`, ); - } - - if ( - modifier.kind === SyntaxKind.AccessorKeyword && - node.kind !== SyntaxKind.PropertyDeclaration - ) { + } else if (declaration.type) { this.#throwError( - modifier, - "'accessor' modifier can only appear on a property declaration.", + declaration, + `The variable declaration of a '${loop}' statement cannot have a type annotation.`, ); } - - // `checkGrammarAsyncModifier` function in `typescript` - if ( - modifier.kind === SyntaxKind.AsyncKeyword && - node.kind !== SyntaxKind.MethodDeclaration && - node.kind !== SyntaxKind.FunctionDeclaration && - node.kind !== SyntaxKind.FunctionExpression && - node.kind !== SyntaxKind.ArrowFunction - ) { - this.#throwError(modifier, "'async' modifier cannot be used here."); - } - - // `checkGrammarModifiers` function in `typescript` if ( - node.kind === SyntaxKind.Parameter && - (modifier.kind === SyntaxKind.StaticKeyword || - modifier.kind === SyntaxKind.ExportKeyword || - modifier.kind === SyntaxKind.DeclareKeyword || - modifier.kind === SyntaxKind.AsyncKeyword) + kind === ts.SyntaxKind.ForInStatement && + initializer.flags & ts.NodeFlags.Using ) { this.#throwError( - modifier, - `'${ts.tokenToString( - modifier.kind, - )}' modifier cannot appear on a parameter.`, + initializer, + "The left-hand side of a 'for...in' statement cannot be a 'using' declaration.", ); } - - // `checkGrammarModifiers` function in `typescript` - if ( - modifier.kind === SyntaxKind.PublicKeyword || - modifier.kind === SyntaxKind.ProtectedKeyword || - modifier.kind === SyntaxKind.PrivateKeyword - ) { - for (const anotherModifier of getModifiers(node) ?? []) { - if ( - anotherModifier !== modifier && - (anotherModifier.kind === SyntaxKind.PublicKeyword || - anotherModifier.kind === SyntaxKind.ProtectedKeyword || - anotherModifier.kind === SyntaxKind.PrivateKeyword) - ) { - this.#throwError( - anotherModifier, - `Accessibility modifier already seen.`, - ); - } - } - } - - // `checkParameter` function in `typescript` - if ( - node.kind === SyntaxKind.Parameter && - // In `typescript` package, it's `ts.hasSyntacticModifier(node, ts.ModifierFlags.ParameterPropertyModifier)` - // https://github.com/typescript-eslint/typescript-eslint/pull/6615#discussion_r1136489935 - (modifier.kind === SyntaxKind.PublicKeyword || - modifier.kind === SyntaxKind.PrivateKeyword || - modifier.kind === SyntaxKind.ProtectedKeyword || - modifier.kind === SyntaxKind.ReadonlyKeyword || - modifier.kind === SyntaxKind.OverrideKeyword) - ) { - const func = getContainingFunction(node)!; - - if ( - !(func.kind === SyntaxKind.Constructor && nodeIsPresent(func.body)) - ) { - this.#throwError( - modifier, - 'A parameter property is only allowed in a constructor implementation.', - ); - } - } + } else if ( + !isValidAssignmentTarget(initializer) && + initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression && + initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression + ) { + this.#throwError( + initializer, + `The left-hand side of a '${loop}' statement must be a variable or a property access.`, + ); } } - #throwUnlessAllowInvalidAST( - node: ts.Node | number, - message: string, - ): asserts node is never { - if (!this.options.allowInvalidAST) { - this.#throwError(node, message); + #throwError(node: ts.Node | number, message: string): asserts node is never { + let start; + let end; + if (typeof node === 'number') { + start = end = node; + } else { + start = node.getStart(this.ast); + end = node.getEnd(); } + + throw createError(message, this.ast, start, end); } - /** - * Creates a getter for a property under aliasKey that returns the value under - * valueKey. If suppressDeprecatedPropertyWarnings is not enabled, the - * getter also console warns about the deprecation. - * - * @see https://github.com/typescript-eslint/typescript-eslint/issues/6469 - */ #withDeprecatedAliasGetter< Properties extends { type: string }, AliasKey extends string, - ValueKey extends string & keyof Properties, + ValueKey extends keyof Properties & string, >( node: Properties, aliasKey: AliasKey, @@ -3540,15 +3600,14 @@ export class Converter { set(value): void { Object.defineProperty(node, aliasKey, { enumerable: true, - writable: true, value, + writable: true, }); }, }); return node as Properties & Record; } - #withDeprecatedGetter< Properties extends { type: string }, Key extends string, @@ -3579,70 +3638,12 @@ export class Converter { set(value): void { Object.defineProperty(node, deprecatedKey, { enumerable: true, - writable: true, value, + writable: true, }); }, }); return node as Properties & Record; } - - #throwError(node: ts.Node | number, message: string): asserts node is never { - let start; - let end; - if (typeof node === 'number') { - start = end = node; - } else { - start = node.getStart(this.ast); - end = node.getEnd(); - } - - throw createError(message, this.ast, start, end); - } - #checkForStatementDeclaration( - initializer: ts.ForInitializer, - kind: ts.SyntaxKind.ForInStatement | ts.SyntaxKind.ForOfStatement, - ): void { - const loop = - kind === ts.SyntaxKind.ForInStatement ? 'for...in' : 'for...of'; - if (ts.isVariableDeclarationList(initializer)) { - if (initializer.declarations.length !== 1) { - this.#throwError( - initializer, - `Only a single variable declaration is allowed in a '${loop}' statement.`, - ); - } - const declaration = initializer.declarations[0]; - if (declaration.initializer) { - this.#throwError( - declaration, - `The variable declaration of a '${loop}' statement cannot have an initializer.`, - ); - } else if (declaration.type) { - this.#throwError( - declaration, - `The variable declaration of a '${loop}' statement cannot have a type annotation.`, - ); - } - if ( - kind === ts.SyntaxKind.ForInStatement && - initializer.flags & ts.NodeFlags.Using - ) { - this.#throwError( - initializer, - "The left-hand side of a 'for...in' statement cannot be a 'using' declaration.", - ); - } - } else if ( - !isValidAssignmentTarget(initializer) && - initializer.kind !== ts.SyntaxKind.ObjectLiteralExpression && - initializer.kind !== ts.SyntaxKind.ArrayLiteralExpression - ) { - this.#throwError( - initializer, - `The left-hand side of a '${loop}' statement must be a variable or a property access.`, - ); - } - } } diff --git a/packages/typescript-estree/src/create-program/WatchCompilerHostOfConfigFile.ts b/packages/typescript-estree/src/create-program/WatchCompilerHostOfConfigFile.ts index 04799b89580c..5f39ea400463 100644 --- a/packages/typescript-estree/src/create-program/WatchCompilerHostOfConfigFile.ts +++ b/packages/typescript-estree/src/create-program/WatchCompilerHostOfConfigFile.ts @@ -29,10 +29,10 @@ interface CachedDirectoryStructureHost extends DirectoryStructureHost { // https://github.com/microsoft/TypeScript/blob/5d36aab06f12b0a3ba6197eb14e98204ec0195fb/src/compiler/watch.ts#L548-L554 interface WatchCompilerHostOfConfigFile extends ts.WatchCompilerHostOfConfigFile { + extraFileExtensions?: readonly ts.FileExtensionInfo[]; onCachedDirectoryStructureHostCreate( host: CachedDirectoryStructureHost, ): void; - extraFileExtensions?: readonly ts.FileExtensionInfo[]; } export { WatchCompilerHostOfConfigFile }; diff --git a/packages/typescript-estree/src/create-program/createIsolatedProgram.ts b/packages/typescript-estree/src/create-program/createIsolatedProgram.ts index 4c15f4a25bbf..ab9144326b2b 100644 --- a/packages/typescript-estree/src/create-program/createIsolatedProgram.ts +++ b/packages/typescript-estree/src/create-program/createIsolatedProgram.ts @@ -2,8 +2,9 @@ import debug from 'debug'; import * as ts from 'typescript'; import type { ParseSettings } from '../parseSettings'; -import { getScriptKind } from './getScriptKind'; import type { ASTAndDefiniteProgram } from './shared'; + +import { getScriptKind } from './getScriptKind'; import { createDefaultCompilerOptionsFromExtra } from './shared'; const log = debug('typescript-eslint:typescript-estree:createIsolatedProgram'); @@ -30,12 +31,12 @@ function createIsolatedProgram( getCurrentDirectory() { return ''; }, - getDirectories() { - return []; - }, getDefaultLibFileName() { return 'lib.d.ts'; }, + getDirectories() { + return []; + }, // TODO: Support Windows CRLF getNewLine() { @@ -65,9 +66,9 @@ function createIsolatedProgram( [parseSettings.filePath], { jsDocParsingMode: parseSettings.jsDocParsingMode, + jsx: parseSettings.jsx ? ts.JsxEmit.Preserve : undefined, noResolve: true, target: ts.ScriptTarget.Latest, - jsx: parseSettings.jsx ? ts.JsxEmit.Preserve : undefined, ...createDefaultCompilerOptionsFromExtra(parseSettings), }, compilerHost, diff --git a/packages/typescript-estree/src/create-program/createProjectProgram.ts b/packages/typescript-estree/src/create-program/createProjectProgram.ts index 0d678866da1b..e02c2c834385 100644 --- a/packages/typescript-estree/src/create-program/createProjectProgram.ts +++ b/packages/typescript-estree/src/create-program/createProjectProgram.ts @@ -1,10 +1,12 @@ -import debug from 'debug'; import type * as ts from 'typescript'; -import { firstDefined } from '../node-utils'; +import debug from 'debug'; + import type { ParseSettings } from '../parseSettings'; -import { createProjectProgramError } from './createProjectProgramError'; import type { ASTAndDefiniteProgram } from './shared'; + +import { firstDefined } from '../node-utils'; +import { createProjectProgramError } from './createProjectProgramError'; import { getAstFromProgram } from './shared'; const log = debug('typescript-eslint:typescript-estree:createProjectProgram'); diff --git a/packages/typescript-estree/src/create-program/createProjectProgramError.ts b/packages/typescript-estree/src/create-program/createProjectProgramError.ts index 2af659b217f6..16b4f8138c02 100644 --- a/packages/typescript-estree/src/create-program/createProjectProgramError.ts +++ b/packages/typescript-estree/src/create-program/createProjectProgramError.ts @@ -1,8 +1,8 @@ import path from 'node:path'; - import * as ts from 'typescript'; import type { ParseSettings } from '../parseSettings'; + import { describeFilePath } from './describeFilePath'; const DEFAULT_EXTRA_FILE_EXTENSIONS = new Set([ diff --git a/packages/typescript-estree/src/create-program/createProjectService.ts b/packages/typescript-estree/src/create-program/createProjectService.ts index e79e01b7b547..06d8df702915 100644 --- a/packages/typescript-estree/src/create-program/createProjectService.ts +++ b/packages/typescript-estree/src/create-program/createProjectService.ts @@ -1,8 +1,10 @@ /* eslint-disable @typescript-eslint/no-empty-function -- for TypeScript APIs*/ -import debug from 'debug'; import type * as ts from 'typescript/lib/tsserverlibrary'; +import debug from 'debug'; + import type { ProjectServiceOptions } from '../parser-options'; + import { getParsedConfigFile } from './getParsedConfigFile'; import { validateDefaultProjectForFilesGlob } from './validateDefaultProjectForFilesGlob'; @@ -37,7 +39,7 @@ export interface ProjectServiceSettings { } export function createProjectService( - optionsRaw: boolean | ProjectServiceOptions | undefined, + optionsRaw: ProjectServiceOptions | boolean | undefined, jsDocParsingMode: ts.JSDocParsingMode | undefined, tsconfigRootDir: string | undefined, ): ProjectServiceSettings { @@ -101,18 +103,18 @@ export function createProjectService( log('Creating project service with: %o', options); const service = new tsserver.server.ProjectService({ - host: system, cancellationToken: { isCancellationRequested: (): boolean => false }, - useSingleInferredProject: false, - useInferredProjectPerProjectRoot: false, - logger, eventHandler: logTsserverEvent.enabled ? (e): void => { logTsserverEvent(e); } : undefined, - session: undefined, + host: system, jsDocParsingMode, + logger, + session: undefined, + useInferredProjectPerProjectRoot: false, + useSingleInferredProject: false, }); service.setHostConfiguration({ diff --git a/packages/typescript-estree/src/create-program/createSourceFile.ts b/packages/typescript-estree/src/create-program/createSourceFile.ts index bb5bc9d7b8fc..129a132e1b84 100644 --- a/packages/typescript-estree/src/create-program/createSourceFile.ts +++ b/packages/typescript-estree/src/create-program/createSourceFile.ts @@ -2,9 +2,10 @@ import debug from 'debug'; import * as ts from 'typescript'; import type { ParseSettings } from '../parseSettings'; +import type { ASTAndNoProgram } from './shared'; + import { isSourceFile } from '../source-files'; import { getScriptKind } from './getScriptKind'; -import type { ASTAndNoProgram } from './shared'; const log = debug('typescript-eslint:typescript-estree:createSourceFile'); @@ -21,8 +22,8 @@ function createSourceFile(parseSettings: ParseSettings): ts.SourceFile { parseSettings.filePath, parseSettings.codeFullText, { - languageVersion: ts.ScriptTarget.Latest, jsDocParsingMode: parseSettings.jsDocParsingMode, + languageVersion: ts.ScriptTarget.Latest, }, /* setParentNodes */ true, getScriptKind(parseSettings.filePath, parseSettings.jsx), @@ -36,4 +37,4 @@ function createNoProgram(parseSettings: ParseSettings): ASTAndNoProgram { }; } -export { createSourceFile, createNoProgram }; +export { createNoProgram, createSourceFile }; diff --git a/packages/typescript-estree/src/create-program/getParsedConfigFile.ts b/packages/typescript-estree/src/create-program/getParsedConfigFile.ts index a48b02ea0fd2..53ca04e90835 100644 --- a/packages/typescript-estree/src/create-program/getParsedConfigFile.ts +++ b/packages/typescript-estree/src/create-program/getParsedConfigFile.ts @@ -1,8 +1,8 @@ +import type * as ts from 'typescript/lib/tsserverlibrary'; + import * as fs from 'node:fs'; import * as path from 'node:path'; -import type * as ts from 'typescript/lib/tsserverlibrary'; - import { CORE_COMPILER_OPTIONS } from './shared'; /** @@ -27,11 +27,11 @@ function getParsedConfigFile( configFile, CORE_COMPILER_OPTIONS, { + fileExists: fs.existsSync, + getCurrentDirectory, onUnRecoverableConfigFileDiagnostic: diag => { throw new Error(formatDiagnostics([diag])); // ensures that `parsed` is defined. }, - fileExists: fs.existsSync, - getCurrentDirectory, readDirectory: tsserver.sys.readDirectory, readFile: file => fs.readFileSync(file, 'utf-8'), useCaseSensitiveFileNames: tsserver.sys.useCaseSensitiveFileNames, diff --git a/packages/typescript-estree/src/create-program/getScriptKind.ts b/packages/typescript-estree/src/create-program/getScriptKind.ts index 619a34cf0a51..642501866133 100644 --- a/packages/typescript-estree/src/create-program/getScriptKind.ts +++ b/packages/typescript-estree/src/create-program/getScriptKind.ts @@ -1,5 +1,4 @@ import path from 'node:path'; - import * as ts from 'typescript'; function getScriptKind(filePath: string, jsx: boolean): ts.ScriptKind { @@ -9,25 +8,25 @@ function getScriptKind(filePath: string, jsx: boolean): ts.ScriptKind { // weird errors due to a mismatch. // https://github.com/microsoft/TypeScript/blob/da00ba67ed1182ad334f7c713b8254fba174aeba/src/compiler/utilities.ts#L6948-L6968 switch (extension) { - case ts.Extension.Js: case ts.Extension.Cjs: + case ts.Extension.Js: case ts.Extension.Mjs: return ts.ScriptKind.JS; - case ts.Extension.Jsx: - return ts.ScriptKind.JSX; - - case ts.Extension.Ts: case ts.Extension.Cts: case ts.Extension.Mts: + case ts.Extension.Ts: return ts.ScriptKind.TS; - case ts.Extension.Tsx: - return ts.ScriptKind.TSX; - case ts.Extension.Json: return ts.ScriptKind.JSON; + case ts.Extension.Jsx: + return ts.ScriptKind.JSX; + + case ts.Extension.Tsx: + return ts.ScriptKind.TSX; + default: // unknown extension, force typescript to ignore the file extension, and respect the user's setting return jsx ? ts.ScriptKind.TSX : ts.ScriptKind.TS; @@ -37,10 +36,10 @@ function getScriptKind(filePath: string, jsx: boolean): ts.ScriptKind { function getLanguageVariant(scriptKind: ts.ScriptKind): ts.LanguageVariant { // https://github.com/microsoft/TypeScript/blob/d6e483b8dabd8fd37c00954c3f2184bb7f1eb90c/src/compiler/utilities.ts#L6281-L6285 switch (scriptKind) { - case ts.ScriptKind.TSX: - case ts.ScriptKind.JSX: case ts.ScriptKind.JS: case ts.ScriptKind.JSON: + case ts.ScriptKind.JSX: + case ts.ScriptKind.TSX: return ts.LanguageVariant.JSX; default: @@ -48,4 +47,4 @@ function getLanguageVariant(scriptKind: ts.ScriptKind): ts.LanguageVariant { } } -export { getScriptKind, getLanguageVariant }; +export { getLanguageVariant, getScriptKind }; diff --git a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts index 16db33b6964e..7891757168a9 100644 --- a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts +++ b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts @@ -1,18 +1,18 @@ -import fs from 'node:fs'; - import debug from 'debug'; +import fs from 'node:fs'; import * as ts from 'typescript'; import type { ParseSettings } from '../parseSettings'; -import { getCodeText } from '../source-files'; import type { CanonicalPath } from './shared'; +import type { WatchCompilerHostOfConfigFile } from './WatchCompilerHostOfConfigFile'; + +import { getCodeText } from '../source-files'; import { canonicalDirname, createDefaultCompilerOptionsFromExtra, createHash, getCanonicalFileName, } from './shared'; -import type { WatchCompilerHostOfConfigFile } from './WatchCompilerHostOfConfigFile'; const log = debug('typescript-eslint:typescript-estree:createWatchProgram'); diff --git a/packages/typescript-estree/src/create-program/shared.ts b/packages/typescript-estree/src/create-program/shared.ts index 73f6e8e3588f..899f4d3cb2a7 100644 --- a/packages/typescript-estree/src/create-program/shared.ts +++ b/packages/typescript-estree/src/create-program/shared.ts @@ -1,6 +1,6 @@ -import path from 'node:path'; - import type { Program } from 'typescript'; + +import path from 'node:path'; import * as ts from 'typescript'; import type { ParseSettings } from '../parseSettings'; @@ -33,8 +33,8 @@ const CORE_COMPILER_OPTIONS: ts.CompilerOptions = { */ const DEFAULT_COMPILER_OPTIONS: ts.CompilerOptions = { ...CORE_COMPILER_OPTIONS, - allowNonTsExtensions: true, allowJs: true, + allowNonTsExtensions: true, checkJs: true, }; @@ -52,7 +52,7 @@ function createDefaultCompilerOptionsFromExtra( } // This narrows the type so we can be sure we're passing canonical names in the correct places -type CanonicalPath = string & { __brand: unknown }; +type CanonicalPath = { __brand: unknown } & string; // typescript doesn't provide a ts.sys implementation for browser environments const useCaseSensitiveFileNames = @@ -131,12 +131,12 @@ export { ASTAndDefiniteProgram, ASTAndNoProgram, ASTAndProgram, - CORE_COMPILER_OPTIONS, canonicalDirname, CanonicalPath, + CORE_COMPILER_OPTIONS, createDefaultCompilerOptionsFromExtra, createHash, ensureAbsolutePath, - getCanonicalFileName, getAstFromProgram, + getCanonicalFileName, }; diff --git a/packages/typescript-estree/src/create-program/useProvidedPrograms.ts b/packages/typescript-estree/src/create-program/useProvidedPrograms.ts index 9baa3bf7ba20..660e82ac4d76 100644 --- a/packages/typescript-estree/src/create-program/useProvidedPrograms.ts +++ b/packages/typescript-estree/src/create-program/useProvidedPrograms.ts @@ -1,11 +1,11 @@ -import * as path from 'node:path'; - import debug from 'debug'; +import * as path from 'node:path'; import * as ts from 'typescript'; import type { ParseSettings } from '../parseSettings'; -import { getParsedConfigFile } from './getParsedConfigFile'; import type { ASTAndDefiniteProgram } from './shared'; + +import { getParsedConfigFile } from './getParsedConfigFile'; import { getAstFromProgram } from './shared'; const log = debug('typescript-eslint:typescript-estree:useProvidedProgram'); @@ -66,4 +66,4 @@ function createProgramFromConfigFile( return ts.createProgram(parsed.fileNames, parsed.options, host); } -export { useProvidedPrograms, createProgramFromConfigFile }; +export { createProgramFromConfigFile, useProvidedPrograms }; diff --git a/packages/typescript-estree/src/createParserServices.ts b/packages/typescript-estree/src/createParserServices.ts index de3070c2fe73..b9a23477c23c 100644 --- a/packages/typescript-estree/src/createParserServices.ts +++ b/packages/typescript-estree/src/createParserServices.ts @@ -9,9 +9,9 @@ export function createParserServices( ): ParserServices { if (!program) { return { - program, emitDecoratorMetadata: undefined, experimentalDecorators: undefined, + program, // we always return the node maps because // (a) they don't require type info and // (b) they can be useful when using some of TS's internal non-type-aware AST utils diff --git a/packages/typescript-estree/src/index.ts b/packages/typescript-estree/src/index.ts index 5f6e8768d0c4..e8322c0c7266 100644 --- a/packages/typescript-estree/src/index.ts +++ b/packages/typescript-estree/src/index.ts @@ -1,3 +1,9 @@ +export * from './clear-caches'; +export * from './create-program/getScriptKind'; +export { getCanonicalFileName } from './create-program/shared'; +export { createProgramFromConfigFile as createProgram } from './create-program/useProvidedPrograms'; +export * from './getModifiers'; +export { TSError } from './node-utils'; export { AST, parse, @@ -6,19 +12,13 @@ export { } from './parser'; export { ParserServices, - ParserServicesWithTypeInformation, ParserServicesWithoutTypeInformation, + ParserServicesWithTypeInformation, TSESTreeOptions, } from './parser-options'; export { simpleTraverse } from './simple-traverse'; export * from './ts-estree'; -export { createProgramFromConfigFile as createProgram } from './create-program/useProvidedPrograms'; -export * from './create-program/getScriptKind'; -export { getCanonicalFileName } from './create-program/shared'; export { typescriptVersionIsAtLeast } from './version-check'; -export * from './getModifiers'; -export { TSError } from './node-utils'; -export * from './clear-caches'; export { withoutProjectParserOptions } from './withoutProjectParserOptions'; // note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder diff --git a/packages/typescript-estree/src/jsx/xhtml-entities.ts b/packages/typescript-estree/src/jsx/xhtml-entities.ts index 2c3e788f0edc..beb65f67cc95 100644 --- a/packages/typescript-estree/src/jsx/xhtml-entities.ts +++ b/packages/typescript-estree/src/jsx/xhtml-entities.ts @@ -1,255 +1,255 @@ export const xhtmlEntities: Record = { - quot: '\u0022', - amp: '&', - apos: '\u0027', - lt: '<', - gt: '>', - nbsp: '\u00A0', - iexcl: '\u00A1', - cent: '\u00A2', - pound: '\u00A3', - curren: '\u00A4', - yen: '\u00A5', - brvbar: '\u00A6', - sect: '\u00A7', - uml: '\u00A8', - copy: '\u00A9', - ordf: '\u00AA', - laquo: '\u00AB', - not: '\u00AC', - shy: '\u00AD', - reg: '\u00AE', - macr: '\u00AF', - deg: '\u00B0', - plusmn: '\u00B1', - sup2: '\u00B2', - sup3: '\u00B3', - acute: '\u00B4', - micro: '\u00B5', - para: '\u00B6', - middot: '\u00B7', - cedil: '\u00B8', - sup1: '\u00B9', - ordm: '\u00BA', - raquo: '\u00BB', - frac14: '\u00BC', - frac12: '\u00BD', - frac34: '\u00BE', - iquest: '\u00BF', - Agrave: '\u00C0', Aacute: '\u00C1', + aacute: '\u00E1', Acirc: '\u00C2', - Atilde: '\u00C3', - Auml: '\u00C4', - Aring: '\u00C5', + acirc: '\u00E2', + acute: '\u00B4', AElig: '\u00C6', - Ccedil: '\u00C7', - Egrave: '\u00C8', - Eacute: '\u00C9', - Ecirc: '\u00CA', - Euml: '\u00CB', - Igrave: '\u00CC', - Iacute: '\u00CD', - Icirc: '\u00CE', - Iuml: '\u00CF', - ETH: '\u00D0', - Ntilde: '\u00D1', - Ograve: '\u00D2', - Oacute: '\u00D3', - Ocirc: '\u00D4', - Otilde: '\u00D5', - Ouml: '\u00D6', - times: '\u00D7', - Oslash: '\u00D8', - Ugrave: '\u00D9', - Uacute: '\u00DA', - Ucirc: '\u00DB', - Uuml: '\u00DC', - Yacute: '\u00DD', - THORN: '\u00DE', - szlig: '\u00DF', + aelig: '\u00E6', + Agrave: '\u00C0', agrave: '\u00E0', - aacute: '\u00E1', - acirc: '\u00E2', + alefsym: '\u2135', + Alpha: '\u0391', + alpha: '\u03B1', + amp: '&', + and: '\u2227', + ang: '\u2220', + apos: '\u0027', + Aring: '\u00C5', + aring: '\u00E5', + asymp: '\u2248', + Atilde: '\u00C3', atilde: '\u00E3', + Auml: '\u00C4', auml: '\u00E4', - aring: '\u00E5', - aelig: '\u00E6', + bdquo: '\u201E', + Beta: '\u0392', + beta: '\u03B2', + brvbar: '\u00A6', + bull: '\u2022', + cap: '\u2229', + Ccedil: '\u00C7', ccedil: '\u00E7', - egrave: '\u00E8', + cedil: '\u00B8', + cent: '\u00A2', + Chi: '\u03A7', + chi: '\u03C7', + circ: '\u02C6', + clubs: '\u2663', + cong: '\u2245', + copy: '\u00A9', + crarr: '\u21B5', + cup: '\u222A', + curren: '\u00A4', + dagger: '\u2020', + Dagger: '\u2021', + darr: '\u2193', + dArr: '\u21D3', + deg: '\u00B0', + Delta: '\u0394', + delta: '\u03B4', + diams: '\u2666', + divide: '\u00F7', + Eacute: '\u00C9', eacute: '\u00E9', + Ecirc: '\u00CA', ecirc: '\u00EA', + Egrave: '\u00C8', + egrave: '\u00E8', + empty: '\u2205', + emsp: '\u2003', + ensp: '\u2002', + Epsilon: '\u0395', + epsilon: '\u03B5', + equiv: '\u2261', + Eta: '\u0397', + eta: '\u03B7', + ETH: '\u00D0', + eth: '\u00F0', + Euml: '\u00CB', euml: '\u00EB', - igrave: '\u00EC', + euro: '\u20AC', + exist: '\u2203', + fnof: '\u0192', + forall: '\u2200', + frac12: '\u00BD', + frac14: '\u00BC', + frac34: '\u00BE', + frasl: '\u2044', + Gamma: '\u0393', + gamma: '\u03B3', + ge: '\u2265', + gt: '>', + harr: '\u2194', + hArr: '\u21D4', + hearts: '\u2665', + hellip: '\u2026', + Iacute: '\u00CD', iacute: '\u00ED', + Icirc: '\u00CE', icirc: '\u00EE', + iexcl: '\u00A1', + Igrave: '\u00CC', + igrave: '\u00EC', + image: '\u2111', + infin: '\u221E', + int: '\u222B', + Iota: '\u0399', + iota: '\u03B9', + iquest: '\u00BF', + isin: '\u2208', + Iuml: '\u00CF', iuml: '\u00EF', - eth: '\u00F0', + Kappa: '\u039A', + kappa: '\u03BA', + Lambda: '\u039B', + lambda: '\u03BB', + lang: '\u2329', + laquo: '\u00AB', + larr: '\u2190', + lArr: '\u21D0', + lceil: '\u2308', + ldquo: '\u201C', + le: '\u2264', + lfloor: '\u230A', + lowast: '\u2217', + loz: '\u25CA', + lrm: '\u200E', + lsaquo: '\u2039', + lsquo: '\u2018', + lt: '<', + macr: '\u00AF', + mdash: '\u2014', + micro: '\u00B5', + middot: '\u00B7', + minus: '\u2212', + Mu: '\u039C', + mu: '\u03BC', + nabla: '\u2207', + nbsp: '\u00A0', + ndash: '\u2013', + ne: '\u2260', + ni: '\u220B', + not: '\u00AC', + notin: '\u2209', + nsub: '\u2284', + Ntilde: '\u00D1', ntilde: '\u00F1', - ograve: '\u00F2', + Nu: '\u039D', + nu: '\u03BD', + Oacute: '\u00D3', oacute: '\u00F3', + Ocirc: '\u00D4', ocirc: '\u00F4', - otilde: '\u00F5', - ouml: '\u00F6', - divide: '\u00F7', - oslash: '\u00F8', - ugrave: '\u00F9', - uacute: '\u00FA', - ucirc: '\u00FB', - uuml: '\u00FC', - yacute: '\u00FD', - thorn: '\u00FE', - yuml: '\u00FF', OElig: '\u0152', oelig: '\u0153', - Scaron: '\u0160', - scaron: '\u0161', - Yuml: '\u0178', - fnof: '\u0192', - circ: '\u02C6', - tilde: '\u02DC', - Alpha: '\u0391', - Beta: '\u0392', - Gamma: '\u0393', - Delta: '\u0394', - Epsilon: '\u0395', - Zeta: '\u0396', - Eta: '\u0397', - Theta: '\u0398', - Iota: '\u0399', - Kappa: '\u039A', - Lambda: '\u039B', - Mu: '\u039C', - Nu: '\u039D', - Xi: '\u039E', - Omicron: '\u039F', - Pi: '\u03A0', - Rho: '\u03A1', - Sigma: '\u03A3', - Tau: '\u03A4', - Upsilon: '\u03A5', - Phi: '\u03A6', - Chi: '\u03A7', - Psi: '\u03A8', + Ograve: '\u00D2', + ograve: '\u00F2', + oline: '\u203E', Omega: '\u03A9', - alpha: '\u03B1', - beta: '\u03B2', - gamma: '\u03B3', - delta: '\u03B4', - epsilon: '\u03B5', - zeta: '\u03B6', - eta: '\u03B7', - theta: '\u03B8', - iota: '\u03B9', - kappa: '\u03BA', - lambda: '\u03BB', - mu: '\u03BC', - nu: '\u03BD', - xi: '\u03BE', + omega: '\u03C9', + Omicron: '\u039F', omicron: '\u03BF', - pi: '\u03C0', - rho: '\u03C1', - sigmaf: '\u03C2', - sigma: '\u03C3', - tau: '\u03C4', - upsilon: '\u03C5', + oplus: '\u2295', + or: '\u2228', + ordf: '\u00AA', + ordm: '\u00BA', + Oslash: '\u00D8', + oslash: '\u00F8', + Otilde: '\u00D5', + otilde: '\u00F5', + otimes: '\u2297', + Ouml: '\u00D6', + ouml: '\u00F6', + para: '\u00B6', + part: '\u2202', + permil: '\u2030', + perp: '\u22A5', + Phi: '\u03A6', phi: '\u03C6', - chi: '\u03C7', - psi: '\u03C8', - omega: '\u03C9', - thetasym: '\u03D1', - upsih: '\u03D2', + Pi: '\u03A0', + pi: '\u03C0', piv: '\u03D6', - ensp: '\u2002', - emsp: '\u2003', - thinsp: '\u2009', - zwnj: '\u200C', - zwj: '\u200D', - lrm: '\u200E', - rlm: '\u200F', - ndash: '\u2013', - mdash: '\u2014', - lsquo: '\u2018', - rsquo: '\u2019', - sbquo: '\u201A', - ldquo: '\u201C', - rdquo: '\u201D', - bdquo: '\u201E', - dagger: '\u2020', - Dagger: '\u2021', - bull: '\u2022', - hellip: '\u2026', - permil: '\u2030', + plusmn: '\u00B1', + pound: '\u00A3', prime: '\u2032', Prime: '\u2033', - lsaquo: '\u2039', - rsaquo: '\u203A', - oline: '\u203E', - frasl: '\u2044', - euro: '\u20AC', - image: '\u2111', - weierp: '\u2118', - real: '\u211C', - trade: '\u2122', - alefsym: '\u2135', - larr: '\u2190', - uarr: '\u2191', - rarr: '\u2192', - darr: '\u2193', - harr: '\u2194', - crarr: '\u21B5', - lArr: '\u21D0', - uArr: '\u21D1', - rArr: '\u21D2', - dArr: '\u21D3', - hArr: '\u21D4', - forall: '\u2200', - part: '\u2202', - exist: '\u2203', - empty: '\u2205', - nabla: '\u2207', - isin: '\u2208', - notin: '\u2209', - ni: '\u220B', prod: '\u220F', - sum: '\u2211', - minus: '\u2212', - lowast: '\u2217', - radic: '\u221A', prop: '\u221D', - infin: '\u221E', - ang: '\u2220', - and: '\u2227', - or: '\u2228', - cap: '\u2229', - cup: '\u222A', - int: '\u222B', - there4: '\u2234', + Psi: '\u03A8', + psi: '\u03C8', + quot: '\u0022', + radic: '\u221A', + rang: '\u232A', + raquo: '\u00BB', + rarr: '\u2192', + rArr: '\u21D2', + rceil: '\u2309', + rdquo: '\u201D', + real: '\u211C', + reg: '\u00AE', + rfloor: '\u230B', + Rho: '\u03A1', + rho: '\u03C1', + rlm: '\u200F', + rsaquo: '\u203A', + rsquo: '\u2019', + sbquo: '\u201A', + Scaron: '\u0160', + scaron: '\u0161', + sdot: '\u22C5', + sect: '\u00A7', + shy: '\u00AD', + Sigma: '\u03A3', + sigma: '\u03C3', + sigmaf: '\u03C2', sim: '\u223C', - cong: '\u2245', - asymp: '\u2248', - ne: '\u2260', - equiv: '\u2261', - le: '\u2264', - ge: '\u2265', + spades: '\u2660', sub: '\u2282', - sup: '\u2283', - nsub: '\u2284', sube: '\u2286', + sum: '\u2211', + sup: '\u2283', + sup1: '\u00B9', + sup2: '\u00B2', + sup3: '\u00B3', supe: '\u2287', - oplus: '\u2295', - otimes: '\u2297', - perp: '\u22A5', - sdot: '\u22C5', - lceil: '\u2308', - rceil: '\u2309', - lfloor: '\u230A', - rfloor: '\u230B', - lang: '\u2329', - rang: '\u232A', - loz: '\u25CA', - spades: '\u2660', - clubs: '\u2663', - hearts: '\u2665', - diams: '\u2666', + szlig: '\u00DF', + Tau: '\u03A4', + tau: '\u03C4', + there4: '\u2234', + Theta: '\u0398', + theta: '\u03B8', + thetasym: '\u03D1', + thinsp: '\u2009', + THORN: '\u00DE', + thorn: '\u00FE', + tilde: '\u02DC', + times: '\u00D7', + trade: '\u2122', + Uacute: '\u00DA', + uacute: '\u00FA', + uarr: '\u2191', + uArr: '\u21D1', + Ucirc: '\u00DB', + ucirc: '\u00FB', + Ugrave: '\u00D9', + ugrave: '\u00F9', + uml: '\u00A8', + upsih: '\u03D2', + Upsilon: '\u03A5', + upsilon: '\u03C5', + Uuml: '\u00DC', + uuml: '\u00FC', + weierp: '\u2118', + Xi: '\u039E', + xi: '\u03BE', + Yacute: '\u00DD', + yacute: '\u00FD', + yen: '\u00A5', + yuml: '\u00FF', + Yuml: '\u0178', + Zeta: '\u0396', + zeta: '\u03B6', + zwj: '\u200D', + zwnj: '\u200C', }; diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index efd413beb57c..dcf2086278bf 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -1,8 +1,9 @@ import * as ts from 'typescript'; +import type { TSESTree, TSNode } from './ts-estree'; + import { getModifiers } from './getModifiers'; import { xhtmlEntities } from './jsx/xhtml-entities'; -import type { TSESTree, TSNode } from './ts-estree'; import { AST_NODE_TYPES, AST_TOKEN_TYPES } from './ts-estree'; import { typescriptVersionIsAtLeast } from './version-check'; @@ -24,8 +25,8 @@ interface TokenToText extends TSESTree.PunctuatorTokenToText, TSESTree.BinaryOperatorToText { [SyntaxKind.ImportKeyword]: 'import'; - [SyntaxKind.NewKeyword]: 'new'; [SyntaxKind.KeyOfKeyword]: 'keyof'; + [SyntaxKind.NewKeyword]: 'new'; [SyntaxKind.ReadonlyKeyword]: 'readonly'; [SyntaxKind.UniqueKeyword]: 'unique'; } @@ -200,31 +201,31 @@ function isJSDocComment(node: ts.Node): node is ts.JSDoc { */ export function getBinaryExpressionType(operator: ts.BinaryOperatorToken): | { - type: AST_NODE_TYPES.AssignmentExpression; operator: TokenForTokenKind; + type: AST_NODE_TYPES.AssignmentExpression; } | { - type: AST_NODE_TYPES.BinaryExpression; operator: TokenForTokenKind; + type: AST_NODE_TYPES.BinaryExpression; } | { - type: AST_NODE_TYPES.LogicalExpression; operator: TokenForTokenKind; + type: AST_NODE_TYPES.LogicalExpression; } { if (isAssignmentOperator(operator)) { return { - type: AST_NODE_TYPES.AssignmentExpression, operator: getTextForTokenKind(operator.kind), + type: AST_NODE_TYPES.AssignmentExpression, }; } else if (isLogicalOperator(operator)) { return { - type: AST_NODE_TYPES.LogicalExpression, operator: getTextForTokenKind(operator.kind), + type: AST_NODE_TYPES.LogicalExpression, }; } else if (isESTreeBinaryOperator(operator)) { return { - type: AST_NODE_TYPES.BinaryExpression, operator: getTextForTokenKind(operator.kind), + type: AST_NODE_TYPES.BinaryExpression, }; } @@ -245,8 +246,8 @@ export function getLineAndCharacterFor( ): TSESTree.Position { const loc = ast.getLineAndCharacterOfPosition(pos); return { - line: loc.line + 1, column: loc.character, + line: loc.line + 1, }; } @@ -262,7 +263,7 @@ export function getLocFor( ast: ts.SourceFile, ): TSESTree.SourceLocation { const [start, end] = range.map(pos => getLineAndCharacterFor(pos, ast)); - return { start, end }; + return { end, start }; } /** @@ -636,23 +637,23 @@ export function convertToken( if (tokenType === AST_TOKEN_TYPES.RegularExpression) { return { - type: tokenType, - value, - range, loc, + range, regex: { - pattern: value.slice(1, value.lastIndexOf('/')), flags: value.slice(value.lastIndexOf('/') + 1), + pattern: value.slice(1, value.lastIndexOf('/')), }, + type: tokenType, + value, }; } // @ts-expect-error TS is complaining about `value` not being the correct // type but it is return { + loc, + range, type: tokenType, value, - range, - loc, }; } @@ -688,23 +689,23 @@ export class TSError extends Error { message: string, public readonly fileName: string, public readonly location: { - start: { - line: number; + end: { column: number; + line: number; offset: number; }; - end: { - line: number; + start: { column: number; + line: number; offset: number; }; }, ) { super(message); Object.defineProperty(this, 'name', { - value: new.target.name, - enumerable: false, configurable: true, + enumerable: false, + value: new.target.name, }); } @@ -738,16 +739,16 @@ export function createError( endIndex: number = startIndex, ): TSError { const [start, end] = [startIndex, endIndex].map(offset => { - const { line, character: column } = + const { character: column, line } = ast.getLineAndCharacterOfPosition(offset); - return { line: line + 1, column, offset }; + return { column, line: line + 1, offset }; }); - return new TSError(message, ast.fileName, { start, end }); + return new TSError(message, ast.fileName, { end, start }); } export function nodeHasIllegalDecorators( node: ts.Node, -): node is ts.Node & { illegalDecorators: ts.Node[] } { +): node is { illegalDecorators: ts.Node[] } & ts.Node { return !!( 'illegalDecorators' in node && (node.illegalDecorators as unknown[] | undefined)?.length @@ -943,11 +944,11 @@ export function isValidAssignmentTarget(node: ts.Node): boolean { return isValidAssignmentTarget( ( node as - | ts.ParenthesizedExpression | ts.AssertionExpression - | ts.SatisfiesExpression | ts.ExpressionWithTypeArguments | ts.NonNullExpression + | ts.ParenthesizedExpression + | ts.SatisfiesExpression ).expression, ); default: diff --git a/packages/typescript-estree/src/parseSettings/ExpiringCache.ts b/packages/typescript-estree/src/parseSettings/ExpiringCache.ts index d02bdfb0b1f4..837612c026b9 100644 --- a/packages/typescript-estree/src/parseSettings/ExpiringCache.ts +++ b/packages/typescript-estree/src/parseSettings/ExpiringCache.ts @@ -17,8 +17,8 @@ export class ExpiringCache implements CacheLike { readonly #map = new Map< Key, Readonly<{ - value: Value; lastSeen: [number, number]; + value: Value; }> >(); @@ -26,16 +26,8 @@ export class ExpiringCache implements CacheLike { this.#cacheDurationSeconds = cacheDurationSeconds; } - set(key: Key, value: Value): this { - this.#map.set(key, { - value, - lastSeen: - this.#cacheDurationSeconds === 'Infinity' - ? // no need to waste time calculating the hrtime in infinity mode as there's no expiry - ZERO_HR_TIME - : process.hrtime(), - }); - return this; + clear(): void { + this.#map.clear(); } get(key: Key): Value | undefined { @@ -57,7 +49,15 @@ export class ExpiringCache implements CacheLike { return undefined; } - clear(): void { - this.#map.clear(); + set(key: Key, value: Value): this { + this.#map.set(key, { + lastSeen: + this.#cacheDurationSeconds === 'Infinity' + ? // no need to waste time calculating the hrtime in infinity mode as there's no expiry + ZERO_HR_TIME + : process.hrtime(), + value, + }); + return this; } } diff --git a/packages/typescript-estree/src/parseSettings/createParseSettings.ts b/packages/typescript-estree/src/parseSettings/createParseSettings.ts index 2bae667104fc..11dd689e9a7d 100644 --- a/packages/typescript-estree/src/parseSettings/createParseSettings.ts +++ b/packages/typescript-estree/src/parseSettings/createParseSettings.ts @@ -2,16 +2,17 @@ import debug from 'debug'; import * as ts from 'typescript'; import type { ProjectServiceSettings } from '../create-program/createProjectService'; +import type { TSESTreeOptions } from '../parser-options'; +import type { MutableParseSettings } from './index'; + import { createProjectService } from '../create-program/createProjectService'; import { ensureAbsolutePath } from '../create-program/shared'; -import type { TSESTreeOptions } from '../parser-options'; import { isSourceFile } from '../source-files'; import { DEFAULT_TSCONFIG_CACHE_DURATION_SECONDS, ExpiringCache, } from './ExpiringCache'; import { getProjectConfigFiles } from './getProjectConfigFiles'; -import type { MutableParseSettings } from './index'; import { inferSingleRun } from './inferSingleRun'; import { resolveProjectList } from './resolveProjectList'; import { warnAboutTSVersion } from './warnAboutTSVersion'; @@ -29,9 +30,9 @@ let TSSERVER_PROJECT_SERVICE: ProjectServiceSettings | null = null; /* eslint-disable @typescript-eslint/no-unnecessary-condition */ const JSDocParsingMode = { ParseAll: ts.JSDocParsingMode?.ParseAll, - ParseNone: ts.JSDocParsingMode?.ParseNone, ParseForTypeErrors: ts.JSDocParsingMode?.ParseForTypeErrors, ParseForTypeInfo: ts.JSDocParsingMode?.ParseForTypeInfo, + ParseNone: ts.JSDocParsingMode?.ParseNone, } as const; /* eslint-enable @typescript-eslint/no-unnecessary-condition */ diff --git a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts b/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts index 9744eec4146c..6c79d0619f86 100644 --- a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts +++ b/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts @@ -1,8 +1,7 @@ +import debug from 'debug'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import debug from 'debug'; - import type { TSESTreeOptions } from '../parser-options'; import type { ParseSettings } from './index'; diff --git a/packages/typescript-estree/src/parseSettings/index.ts b/packages/typescript-estree/src/parseSettings/index.ts index 41a21c044946..f8ee1870ec65 100644 --- a/packages/typescript-estree/src/parseSettings/index.ts +++ b/packages/typescript-estree/src/parseSettings/index.ts @@ -5,7 +5,7 @@ import type { CanonicalPath } from '../create-program/shared'; import type { TSESTree } from '../ts-estree'; import type { CacheLike } from './ExpiringCache'; -type DebugModule = 'eslint' | 'typescript-eslint' | 'typescript'; +type DebugModule = 'eslint' | 'typescript' | 'typescript-eslint'; // Workaround to support new TS version features for consumers on old TS versions declare module 'typescript' { diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts index 1e2155cd0103..4e94b30f27e5 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/typescript-estree/src/parseSettings/resolveProjectList.ts @@ -3,12 +3,13 @@ import { sync as globSync } from 'globby'; import isGlob from 'is-glob'; import type { CanonicalPath } from '../create-program/shared'; +import type { TSESTreeOptions } from '../parser-options'; + import { createHash, ensureAbsolutePath, getCanonicalFileName, } from '../create-program/shared'; -import type { TSESTreeOptions } from '../parser-options'; import { DEFAULT_TSCONFIG_CACHE_DURATION_SECONDS, ExpiringCache, diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index 8aeeaa8ff049..b2df4e95f14d 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -84,7 +84,7 @@ interface ParseOptions { * When value is `false`, no logging will occur. * When value is not provided, `console.log()` will be used. */ - loggerFn?: false | ((message: string) => void); + loggerFn?: ((message: string) => void) | false; /** * Controls whether the `range` property is included on AST nodes. @@ -94,14 +94,14 @@ interface ParseOptions { range?: boolean; /** - * Set to true to create a top-level array containing all tokens from the file. + * Whether deprecated AST properties should skip calling console.warn on accesses. */ - tokens?: boolean; + suppressDeprecatedPropertyWarnings?: boolean; /** - * Whether deprecated AST properties should skip calling console.warn on accesses. + * Set to true to create a top-level array containing all tokens from the file. */ - suppressDeprecatedPropertyWarnings?: boolean; + tokens?: boolean; } interface ParseAndGenerateServicesOptions extends ParseOptions { @@ -174,6 +174,13 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { */ preserveNodeMaps?: boolean; + /** + * An array of one or more instances of TypeScript Program objects to be used for type information. + * This overrides any program or programs that would have been computed from the `project` option. + * All linted files must be part of the provided program(s). + */ + programs?: ts.Program[] | null; + /** * Absolute (or relative to `tsconfigRootDir`) paths to the tsconfig(s), * or `true` to find the nearest tsconfig.json to the file. @@ -183,7 +190,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { * * Note that {@link projectService} is now preferred. */ - project?: string[] | string | boolean | null; + project?: string[] | boolean | string | null; /** * If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from @@ -197,19 +204,12 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { /** * Whether to create a shared TypeScript project service to power program creation. */ - projectService?: boolean | ProjectServiceOptions; + projectService?: ProjectServiceOptions | boolean; /** * The absolute path to the root directory for all provided `project`s. */ tsconfigRootDir?: string; - - /** - * An array of one or more instances of TypeScript Program objects to be used for type information. - * This overrides any program or programs that would have been computed from the `project` option. - * All linted files must be part of the provided program(s). - */ - programs?: ts.Program[] | null; } export type TSESTreeOptions = ParseAndGenerateServicesOptions; @@ -241,9 +241,9 @@ export interface ParserServicesNodeMaps { export interface ParserServicesWithTypeInformation extends ParserServicesNodeMaps, ParserServicesBase { - program: ts.Program; getSymbolAtLocation: (node: TSESTree.Node) => ts.Symbol | undefined; getTypeAtLocation: (node: TSESTree.Node) => ts.Type; + program: ts.Program; } export interface ParserServicesWithoutTypeInformation extends ParserServicesNodeMaps, diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index 45e5a0a92b87..10d928ef9bf5 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -1,6 +1,16 @@ -import debug from 'debug'; import type * as ts from 'typescript'; +import debug from 'debug'; + +import type { ASTAndProgram, CanonicalPath } from './create-program/shared'; +import type { + ParserServices, + ParserServicesNodeMaps, + TSESTreeOptions, +} from './parser-options'; +import type { ParseSettings } from './parseSettings'; +import type { TSESTree } from './ts-estree'; + import { astConverter } from './ast-converter'; import { convertError } from './convert'; import { createIsolatedProgram } from './create-program/createIsolatedProgram'; @@ -10,21 +20,13 @@ import { createSourceFile, } from './create-program/createSourceFile'; import { getWatchProgramsForProjects } from './create-program/getWatchProgramsForProjects'; -import type { ASTAndProgram, CanonicalPath } from './create-program/shared'; import { createProgramFromConfigFile, useProvidedPrograms, } from './create-program/useProvidedPrograms'; import { createParserServices } from './createParserServices'; -import type { - ParserServices, - ParserServicesNodeMaps, - TSESTreeOptions, -} from './parser-options'; -import type { ParseSettings } from './parseSettings'; import { createParseSettings } from './parseSettings/createParseSettings'; import { getFirstSemanticOrSyntacticError } from './semantic-or-syntactic-errors'; -import type { TSESTree } from './ts-estree'; import { useProgramFromProjectService } from './useProgramFromProjectService'; const log = debug('typescript-eslint:typescript-estree:parser'); @@ -88,9 +90,11 @@ function getProgramAndAST( } /* eslint-disable @typescript-eslint/no-empty-object-type */ -type AST = TSESTree.Program & - (T['comment'] extends true ? { comments: TSESTree.Comment[] } : {}) & - (T['tokens'] extends true ? { tokens: TSESTree.Token[] } : {}); +type AST = (T['comment'] extends true + ? { comments: TSESTree.Comment[] } + : {}) & + (T['tokens'] extends true ? { tokens: TSESTree.Token[] } : {}) & + TSESTree.Program; /* eslint-enable @typescript-eslint/no-empty-object-type */ interface ParseAndGenerateServicesResult { @@ -137,7 +141,7 @@ function parseWithNodeMapsInternal( /** * Convert the TypeScript AST to an ESTree-compatible one */ - const { estree, astMaps } = astConverter( + const { astMaps, estree } = astConverter( ast, parseSettings, shouldPreserveNodeMaps, @@ -246,7 +250,7 @@ function parseAndGenerateServices( ? parseSettings.preserveNodeMaps : true; - const { estree, astMaps } = astConverter( + const { astMaps, estree } = astConverter( ast, parseSettings, shouldPreserveNodeMaps, @@ -274,10 +278,10 @@ function parseAndGenerateServices( export { AST, + clearDefaultProjectMatchedFiles, + clearParseAndGenerateServicesCalls, + clearProgramCache, parse, parseAndGenerateServices, ParseAndGenerateServicesResult, - clearDefaultProjectMatchedFiles, - clearProgramCache, - clearParseAndGenerateServicesCalls, }; diff --git a/packages/typescript-estree/src/semantic-or-syntactic-errors.ts b/packages/typescript-estree/src/semantic-or-syntactic-errors.ts index 584e47cb51c9..a88a3615d9f8 100644 --- a/packages/typescript-estree/src/semantic-or-syntactic-errors.ts +++ b/packages/typescript-estree/src/semantic-or-syntactic-errors.ts @@ -4,6 +4,7 @@ import type { Program, SourceFile, } from 'typescript'; + import { flattenDiagnosticMessageText, sys } from 'typescript'; export interface SemanticOrSyntacticError extends Diagnostic { diff --git a/packages/typescript-estree/src/simple-traverse.ts b/packages/typescript-estree/src/simple-traverse.ts index b02189678a49..aa0d7ed4d070 100644 --- a/packages/typescript-estree/src/simple-traverse.ts +++ b/packages/typescript-estree/src/simple-traverse.ts @@ -1,4 +1,5 @@ import type { VisitorKeys } from '@typescript-eslint/visitor-keys'; + import { visitorKeys } from '@typescript-eslint/visitor-keys'; import type { TSESTree } from './ts-estree'; @@ -22,8 +23,8 @@ function getVisitorKeysForNode( type SimpleTraverseOptions = Readonly< | { - visitorKeys?: Readonly; enter: (node: TSESTree.Node, parent: TSESTree.Node | undefined) => void; + visitorKeys?: Readonly; } | { visitorKeys?: Readonly; 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 index 1797ffd62302..b42d78524245 100644 --- 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 @@ -30,7 +30,6 @@ export interface EstreeToTsNodeTypes { [AST_NODE_TYPES.ClassBody]: ts.ClassDeclaration | ts.ClassExpression; [AST_NODE_TYPES.ClassDeclaration]: ts.ClassDeclaration; [AST_NODE_TYPES.ClassExpression]: ts.ClassExpression; - [AST_NODE_TYPES.PropertyDefinition]: ts.PropertyDeclaration; [AST_NODE_TYPES.ConditionalExpression]: ts.ConditionalExpression; [AST_NODE_TYPES.ContinueStatement]: ts.ContinueStatement; [AST_NODE_TYPES.DebuggerStatement]: ts.DebuggerStatement; @@ -75,7 +74,6 @@ export interface EstreeToTsNodeTypes { | ts.ConstructorDeclaration | ts.Identifier | ts.Token; - [AST_NODE_TYPES.PrivateIdentifier]: ts.PrivateIdentifier; [AST_NODE_TYPES.IfStatement]: ts.IfStatement; // eslint-disable-next-line @typescript-eslint/internal/prefer-ast-types-enum [AST_NODE_TYPES.ImportAttribute]: 'ImportAttribute' extends keyof typeof ts @@ -95,14 +93,14 @@ export interface EstreeToTsNodeTypes { [AST_NODE_TYPES.JSXExpressionContainer]: ts.JsxExpression; [AST_NODE_TYPES.JSXFragment]: ts.JsxFragment; [AST_NODE_TYPES.JSXIdentifier]: ts.Identifier | ts.ThisExpression; + [AST_NODE_TYPES.JSXMemberExpression]: ts.PropertyAccessExpression; + [AST_NODE_TYPES.JSXNamespacedName]: ts.JsxNamespacedName; [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.JSXNamespacedName]: ts.JsxNamespacedName; [AST_NODE_TYPES.JSXText]: ts.JsxText; [AST_NODE_TYPES.LabeledStatement]: ts.LabeledStatement; [AST_NODE_TYPES.Literal]: @@ -127,6 +125,7 @@ export interface EstreeToTsNodeTypes { [AST_NODE_TYPES.ObjectPattern]: | ts.ObjectBindingPattern | ts.ObjectLiteralExpression; + [AST_NODE_TYPES.PrivateIdentifier]: ts.PrivateIdentifier; [AST_NODE_TYPES.Program]: ts.SourceFile; [AST_NODE_TYPES.Property]: | ts.BindingElement @@ -135,6 +134,7 @@ export interface EstreeToTsNodeTypes { | ts.PropertyAssignment | ts.SetAccessorDeclaration | ts.ShorthandPropertyAssignment; + [AST_NODE_TYPES.PropertyDefinition]: ts.PropertyDeclaration; [AST_NODE_TYPES.RestElement]: | ts.BindingElement | ts.ParameterDeclaration @@ -163,24 +163,40 @@ export interface EstreeToTsNodeTypes { [AST_NODE_TYPES.ThrowStatement]: ts.ThrowStatement; [AST_NODE_TYPES.TryStatement]: ts.TryStatement; [AST_NODE_TYPES.TSAbstractAccessorProperty]: ts.PropertyDeclaration; - [AST_NODE_TYPES.TSAbstractPropertyDefinition]: ts.PropertyDeclaration; + // Keywords + [AST_NODE_TYPES.TSAbstractKeyword]: ts.Token; [AST_NODE_TYPES.TSAbstractMethodDefinition]: | ts.ConstructorDeclaration | ts.GetAccessorDeclaration | ts.MethodDeclaration | ts.SetAccessorDeclaration; + [AST_NODE_TYPES.TSAbstractPropertyDefinition]: ts.PropertyDeclaration; + [AST_NODE_TYPES.TSAnyKeyword]: ts.KeywordTypeNode; [AST_NODE_TYPES.TSArrayType]: ts.ArrayTypeNode; [AST_NODE_TYPES.TSAsExpression]: ts.AsExpression; + // Unused + [AST_NODE_TYPES.TSAsyncKeyword]: ts.Token; + [AST_NODE_TYPES.TSBigIntKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSBooleanKeyword]: ts.KeywordTypeNode; [AST_NODE_TYPES.TSCallSignatureDeclaration]: ts.CallSignatureDeclaration; [AST_NODE_TYPES.TSClassImplements]: ts.ExpressionWithTypeArguments; [AST_NODE_TYPES.TSConditionalType]: ts.ConditionalTypeNode; [AST_NODE_TYPES.TSConstructorType]: ts.ConstructorTypeNode; [AST_NODE_TYPES.TSConstructSignatureDeclaration]: ts.ConstructSignatureDeclaration; [AST_NODE_TYPES.TSDeclareFunction]: ts.FunctionDeclaration; + [AST_NODE_TYPES.TSDeclareKeyword]: ts.Token; + // Should be same as AST_NODE_TYPES.FunctionExpression + [AST_NODE_TYPES.TSEmptyBodyFunctionExpression]: + | ts.ConstructorDeclaration + | ts.FunctionExpression + | ts.GetAccessorDeclaration + | ts.MethodDeclaration + | ts.SetAccessorDeclaration; [AST_NODE_TYPES.TSEnumBody]: ts.EnumDeclaration; [AST_NODE_TYPES.TSEnumDeclaration]: ts.EnumDeclaration; [AST_NODE_TYPES.TSEnumMember]: ts.EnumMember; [AST_NODE_TYPES.TSExportAssignment]: ts.ExportAssignment; + [AST_NODE_TYPES.TSExportKeyword]: ts.Token; [AST_NODE_TYPES.TSExternalModuleReference]: ts.ExternalModuleReference; [AST_NODE_TYPES.TSFunctionType]: ts.FunctionTypeNode; [AST_NODE_TYPES.TSImportEqualsDeclaration]: ts.ImportEqualsDeclaration; @@ -188,12 +204,12 @@ export interface EstreeToTsNodeTypes { [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.TSInstantiationExpression]: ts.ExpressionWithTypeArguments; [AST_NODE_TYPES.TSInterfaceBody]: ts.InterfaceDeclaration; + [AST_NODE_TYPES.TSInterfaceDeclaration]: ts.InterfaceDeclaration; [AST_NODE_TYPES.TSInterfaceHeritage]: ts.ExpressionWithTypeArguments; [AST_NODE_TYPES.TSIntersectionType]: ts.IntersectionTypeNode; - [AST_NODE_TYPES.TSInstantiationExpression]: ts.ExpressionWithTypeArguments; - [AST_NODE_TYPES.TSSatisfiesExpression]: ts.SatisfiesExpression; + [AST_NODE_TYPES.TSIntrinsicKeyword]: ts.KeywordTypeNode; [AST_NODE_TYPES.TSLiteralType]: ts.LiteralTypeNode; [AST_NODE_TYPES.TSMappedType]: ts.MappedTypeNode; [AST_NODE_TYPES.TSMethodSignature]: @@ -204,19 +220,35 @@ export interface EstreeToTsNodeTypes { [AST_NODE_TYPES.TSModuleDeclaration]: ts.ModuleDeclaration; [AST_NODE_TYPES.TSNamedTupleMember]: ts.NamedTupleMember; [AST_NODE_TYPES.TSNamespaceExportDeclaration]: ts.NamespaceExportDeclaration; + [AST_NODE_TYPES.TSNeverKeyword]: ts.KeywordTypeNode; [AST_NODE_TYPES.TSNonNullExpression]: ts.NonNullExpression; + [AST_NODE_TYPES.TSNullKeyword]: ts.KeywordTypeNode | ts.NullLiteral; + [AST_NODE_TYPES.TSNumberKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSObjectKeyword]: ts.KeywordTypeNode; [AST_NODE_TYPES.TSOptionalType]: ts.OptionalTypeNode; [AST_NODE_TYPES.TSParameterProperty]: ts.ParameterDeclaration; + [AST_NODE_TYPES.TSPrivateKeyword]: ts.Token; [AST_NODE_TYPES.TSPropertySignature]: ts.PropertySignature; + [AST_NODE_TYPES.TSProtectedKeyword]: ts.Token; + [AST_NODE_TYPES.TSPublicKeyword]: ts.Token; [AST_NODE_TYPES.TSQualifiedName]: ts.Identifier | ts.QualifiedName; + [AST_NODE_TYPES.TSReadonlyKeyword]: ts.Token; [AST_NODE_TYPES.TSRestType]: | ts.NamedTupleMember // for consistency and following babel's choices, a named tuple member with a rest gets converted to a TSRestType | ts.RestTypeNode; + [AST_NODE_TYPES.TSSatisfiesExpression]: ts.SatisfiesExpression; + [AST_NODE_TYPES.TSStaticKeyword]: ts.Token; + [AST_NODE_TYPES.TSStringKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSSymbolKeyword]: ts.KeywordTypeNode; + [AST_NODE_TYPES.TSTemplateLiteralType]: ts.TemplateLiteralTypeNode; [AST_NODE_TYPES.TSThisType]: ts.ThisTypeNode; + + // Added by parser [AST_NODE_TYPES.TSTupleType]: ts.TupleTypeNode; - [AST_NODE_TYPES.TSTemplateLiteralType]: ts.TemplateLiteralTypeNode; + [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; @@ -235,16 +267,20 @@ export interface EstreeToTsNodeTypes { [AST_NODE_TYPES.TSTypePredicate]: ts.TypePredicateNode; [AST_NODE_TYPES.TSTypeQuery]: ts.ImportTypeNode | ts.TypeQueryNode; [AST_NODE_TYPES.TSTypeReference]: ts.TypeReferenceNode; + [AST_NODE_TYPES.TSUndefinedKeyword]: ts.KeywordTypeNode; [AST_NODE_TYPES.TSUnionType]: ts.UnionTypeNode; - [AST_NODE_TYPES.UpdateExpression]: - | ts.PostfixUnaryExpression - | ts.PrefixUnaryExpression; + [AST_NODE_TYPES.TSUnknownKeyword]: ts.KeywordTypeNode; + + [AST_NODE_TYPES.TSVoidKeyword]: ts.KeywordTypeNode; [AST_NODE_TYPES.UnaryExpression]: | ts.DeleteExpression | ts.PostfixUnaryExpression | ts.PrefixUnaryExpression | ts.TypeOfExpression | ts.VoidExpression; + [AST_NODE_TYPES.UpdateExpression]: + | ts.PostfixUnaryExpression + | ts.PrefixUnaryExpression; [AST_NODE_TYPES.VariableDeclaration]: | ts.VariableDeclarationList | ts.VariableStatement; @@ -252,42 +288,6 @@ export interface EstreeToTsNodeTypes { [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.ConstructorDeclaration - | ts.FunctionExpression - | ts.GetAccessorDeclaration - | ts.MethodDeclaration - | ts.SetAccessorDeclaration; - - // Keywords - [AST_NODE_TYPES.TSAbstractKeyword]: ts.Token; - [AST_NODE_TYPES.TSNullKeyword]: ts.KeywordTypeNode | ts.NullLiteral; - - [AST_NODE_TYPES.TSAnyKeyword]: ts.KeywordTypeNode; - [AST_NODE_TYPES.TSBigIntKeyword]: ts.KeywordTypeNode; - [AST_NODE_TYPES.TSBooleanKeyword]: ts.KeywordTypeNode; - [AST_NODE_TYPES.TSIntrinsicKeyword]: 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; } /** diff --git a/packages/typescript-estree/src/ts-estree/index.ts b/packages/typescript-estree/src/ts-estree/index.ts index a7f64d91ce6b..833ec57508ba 100644 --- a/packages/typescript-estree/src/ts-estree/index.ts +++ b/packages/typescript-estree/src/ts-estree/index.ts @@ -1,8 +1,8 @@ // for simplicity and backwards-compatibility +export * from './estree-to-ts-node-types'; +export * from './ts-nodes'; export { AST_NODE_TYPES, AST_TOKEN_TYPES, TSESTree, } from '@typescript-eslint/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 5d268060d5d1..9c59af857815 100644 --- a/packages/typescript-estree/src/ts-estree/ts-nodes.ts +++ b/packages/typescript-estree/src/ts-estree/ts-nodes.ts @@ -20,197 +20,197 @@ declare module 'typescript' { export type TSToken = ts.Token; export type TSNode = - | ts.Modifier - | ts.Identifier - | ts.ImportAttribute - | ts.ImportAttributes + | ts.ArrayBindingPattern + | ts.ArrayLiteralExpression + | ts.ArrayTypeNode + | ts.ArrowFunction + | ts.AsExpression /* eslint-disable-next-line deprecation/deprecation -- intentional for old TS versions */ | ts.AssertClause /* eslint-disable-next-line deprecation/deprecation -- intentional for old TS versions */ | ts.AssertEntry - | ts.PrivateIdentifier - | ts.QualifiedName - | ts.ComputedPropertyName - | ts.Decorator - | ts.TypeParameterDeclaration - // | ts.SignatureDeclarationBase -> CallSignatureDeclaration, ConstructSignatureDeclaration - | ts.CallSignatureDeclaration - | ts.ConstructSignatureDeclaration - | ts.VariableDeclaration - | ts.VariableDeclarationList - | ts.ParameterDeclaration - | ts.BindingElement - | ts.PropertySignature - | ts.PropertyDeclaration - | ts.PropertyAssignment - | ts.ShorthandPropertyAssignment - | ts.SpreadAssignment - | ts.ObjectBindingPattern - | ts.ArrayBindingPattern - | ts.FunctionDeclaration - | ts.MethodSignature - | ts.MethodDeclaration - | ts.ConstructorDeclaration - | ts.SemicolonClassElement - | ts.GetAccessorDeclaration - | ts.SetAccessorDeclaration - | ts.IndexSignatureDeclaration - | ts.KeywordTypeNode // TODO: This node is bad, maybe we should report this - | ts.ImportTypeNode - | ts.ThisTypeNode - | ts.ClassStaticBlockDeclaration - // | ts.FunctionOrConstructorTypeNodeBase -> FunctionTypeNode, ConstructorTypeNode - | ts.ConstructorTypeNode - | ts.FunctionTypeNode - | ts.TypeReferenceNode - | ts.TypePredicateNode - | ts.TypeQueryNode - | ts.TypeLiteralNode - | ts.ArrayTypeNode - | ts.NamedTupleMember - | ts.TupleTypeNode - | ts.OptionalTypeNode - | ts.RestTypeNode - | ts.UnionTypeNode - | ts.IntersectionTypeNode - | ts.ConditionalTypeNode - | ts.InferTypeNode - | ts.ParenthesizedTypeNode - | ts.TypeOperatorNode - | ts.IndexedAccessTypeNode - | ts.MappedTypeNode - | ts.LiteralTypeNode - | ts.StringLiteral - | ts.OmittedExpression - | ts.PartiallyEmittedExpression - | ts.PrefixUnaryExpression - | ts.PostfixUnaryExpression - | ts.NullLiteral - | ts.BooleanLiteral - | ts.ThisExpression - | ts.SuperExpression - | ts.ImportExpression - | ts.DeleteExpression - | ts.TypeOfExpression - | ts.VoidExpression | ts.AwaitExpression - | ts.YieldExpression - | ts.SyntheticExpression - | ts.BinaryExpression - | ts.ConditionalExpression - | ts.FunctionExpression - | ts.ArrowFunction - | ts.RegularExpressionLiteral - | ts.NoSubstitutionTemplateLiteral - | ts.NumericLiteral | ts.BigIntLiteral - | ts.TemplateHead - | ts.TemplateMiddle - | ts.TemplateTail - | ts.TemplateExpression - | ts.TemplateSpan - | ts.ParenthesizedExpression - | ts.ArrayLiteralExpression - | ts.SpreadElement - | ts.ObjectLiteralExpression - | ts.PropertyAccessExpression - | ts.ElementAccessExpression - | ts.CallExpression - | ts.ExpressionWithTypeArguments - | ts.NewExpression - | ts.TaggedTemplateExpression - | ts.AsExpression - | ts.TypeAssertion - | ts.NonNullExpression - | ts.MetaProperty - | ts.JsxElement - | ts.JsxOpeningElement - | ts.JsxSelfClosingElement - | ts.JsxFragment - | ts.JsxOpeningFragment - | ts.JsxClosingFragment - | ts.JsxAttribute - | ts.JsxSpreadAttribute - | ts.JsxClosingElement - | ts.JsxExpression - | ts.JsxNamespacedName - | ts.JsxText - | ts.NotEmittedStatement - | ts.CommaListExpression - | ts.EmptyStatement - | ts.DebuggerStatement - | ts.MissingDeclaration + | ts.BinaryExpression + | ts.BindingElement + // | ts.SignatureDeclarationBase -> CallSignatureDeclaration, ConstructSignatureDeclaration | ts.Block - | ts.VariableStatement - | ts.ExpressionStatement - | ts.IfStatement - | ts.DoStatement - | ts.WhileStatement - | ts.ForStatement - | ts.ForInStatement - | ts.ForOfStatement + | ts.BooleanLiteral | ts.BreakStatement - | ts.ContinueStatement - | ts.ReturnStatement - | ts.WithStatement - | ts.SwitchStatement + | ts.Bundle + | ts.CallExpression + | ts.CallSignatureDeclaration | ts.CaseBlock | ts.CaseClause - | ts.DefaultClause - | ts.LabeledStatement - | ts.ThrowStatement - | ts.TryStatement | ts.CatchClause - // | ts.ClassLikeDeclarationBase -> ClassDeclaration | ClassExpression | ts.ClassDeclaration | ts.ClassExpression - | ts.InterfaceDeclaration - | ts.HeritageClause - | ts.TypeAliasDeclaration - | ts.EnumMember + | ts.ClassStaticBlockDeclaration + | ts.CommaListExpression + | ts.ComputedPropertyName + | ts.ConditionalExpression + | ts.ConditionalTypeNode + | ts.ConstructorDeclaration + | ts.ConstructorTypeNode + | ts.ConstructSignatureDeclaration + | ts.ContinueStatement + | ts.DebuggerStatement + | ts.Decorator + | ts.DefaultClause + | ts.DeleteExpression + | ts.DoStatement + // | ts.FunctionOrConstructorTypeNodeBase -> FunctionTypeNode, ConstructorTypeNode + | ts.ElementAccessExpression + | ts.EmptyStatement | ts.EnumDeclaration - | ts.ModuleDeclaration - | ts.ModuleBlock - | ts.ImportEqualsDeclaration + | ts.EnumMember + | ts.ExportAssignment + | ts.ExportDeclaration + | ts.ExportSpecifier + | ts.ExpressionStatement + | ts.ExpressionWithTypeArguments | ts.ExternalModuleReference - | ts.ImportDeclaration + | ts.ForInStatement + | ts.ForOfStatement + | ts.ForStatement + | ts.FunctionDeclaration + | ts.FunctionExpression + | ts.FunctionTypeNode + | ts.GetAccessorDeclaration + | ts.HeritageClause + | ts.Identifier + | ts.IfStatement + | ts.ImportAttribute + | ts.ImportAttributes | ts.ImportClause - | ts.NamespaceImport - | ts.NamespaceExportDeclaration - | ts.ExportDeclaration - | ts.NamedImports - | ts.NamedExports + | ts.ImportDeclaration + | ts.ImportEqualsDeclaration + | ts.ImportExpression | ts.ImportSpecifier - | ts.ExportSpecifier - | ts.ExportAssignment - | ts.SourceFile - | ts.Bundle - | ts.JsonMinusNumericLiteral - | ts.TemplateLiteralTypeNode - | ts.SatisfiesExpression - - // JSDoc: Unsupported + | ts.ImportTypeNode + | ts.IndexedAccessTypeNode + | ts.IndexSignatureDeclaration + | ts.InferTypeNode + | ts.InterfaceDeclaration + | ts.IntersectionTypeNode | ts.JSDoc - | ts.JSDocTypeExpression - | ts.JSDocUnknownTag + | ts.JSDocAllType | ts.JSDocAugmentsTag + | ts.JSDocAuthorTag + | ts.JSDocCallbackTag | ts.JSDocClassTag | ts.JSDocEnumTag - | ts.JSDocThisTag - | ts.JSDocTemplateTag + | ts.JSDocFunctionType + | ts.JSDocNonNullableType + | ts.JSDocNullableType + | ts.JSDocOptionalType + | ts.JSDocParameterTag + | ts.JSDocPropertyTag | ts.JSDocReturnTag - | ts.JSDocTypeTag - | ts.JSDocTypedefTag - | ts.JSDocCallbackTag | ts.JSDocSignature - | ts.JSDocPropertyTag - | ts.JSDocParameterTag + | ts.JSDocTemplateTag + | ts.JSDocThisTag + | ts.JSDocTypedefTag + | ts.JSDocTypeExpression | ts.JSDocTypeLiteral - | ts.JSDocFunctionType - | ts.JSDocAllType + | ts.JSDocTypeTag + | ts.JSDocUnknownTag | ts.JSDocUnknownType - | ts.JSDocNullableType - | ts.JSDocNonNullableType - | ts.JSDocOptionalType | ts.JSDocVariadicType - | ts.JSDocAuthorTag; + | ts.JsonMinusNumericLiteral + | ts.JsxAttribute + | ts.JsxClosingElement + | ts.JsxClosingFragment + | ts.JsxElement + | ts.JsxExpression + | ts.JsxFragment + | ts.JsxNamespacedName + | ts.JsxOpeningElement + | ts.JsxOpeningFragment + | ts.JsxSelfClosingElement + | ts.JsxSpreadAttribute + | ts.JsxText + | ts.KeywordTypeNode // TODO: This node is bad, maybe we should report this + | ts.LabeledStatement + | ts.LiteralTypeNode + | ts.MappedTypeNode + | ts.MetaProperty + | ts.MethodDeclaration + | ts.MethodSignature + | ts.MissingDeclaration + | ts.Modifier + | ts.ModuleBlock + | ts.ModuleDeclaration + | ts.NamedExports + | ts.NamedImports + | ts.NamedTupleMember + | ts.NamespaceExportDeclaration + | ts.NamespaceImport + | ts.NewExpression + | ts.NonNullExpression + | ts.NoSubstitutionTemplateLiteral + | ts.NotEmittedStatement + | ts.NullLiteral + | ts.NumericLiteral + | ts.ObjectBindingPattern + | ts.ObjectLiteralExpression + | ts.OmittedExpression + | ts.OptionalTypeNode + | ts.ParameterDeclaration + | ts.ParenthesizedExpression + | ts.ParenthesizedTypeNode + | ts.PartiallyEmittedExpression + | ts.PostfixUnaryExpression + // | ts.ClassLikeDeclarationBase -> ClassDeclaration | ClassExpression + | ts.PrefixUnaryExpression + | ts.PrivateIdentifier + | ts.PropertyAccessExpression + | ts.PropertyAssignment + | ts.PropertyDeclaration + | ts.PropertySignature + | ts.QualifiedName + | ts.RegularExpressionLiteral + | ts.RestTypeNode + | ts.ReturnStatement + | ts.SatisfiesExpression + | ts.SemicolonClassElement + | ts.SetAccessorDeclaration + | ts.ShorthandPropertyAssignment + | ts.SourceFile + | ts.SpreadAssignment + | ts.SpreadElement + | ts.StringLiteral + | ts.SuperExpression + | ts.SwitchStatement + | ts.SyntheticExpression + | ts.TaggedTemplateExpression + | ts.TemplateExpression + | ts.TemplateHead + | ts.TemplateLiteralTypeNode + | ts.TemplateMiddle + + // JSDoc: Unsupported + | ts.TemplateSpan + | ts.TemplateTail + | ts.ThisExpression + | ts.ThisTypeNode + | ts.ThrowStatement + | ts.TryStatement + | ts.TupleTypeNode + | ts.TypeAliasDeclaration + | ts.TypeAssertion + | ts.TypeLiteralNode + | ts.TypeOfExpression + | ts.TypeOperatorNode + | ts.TypeParameterDeclaration + | ts.TypePredicateNode + | ts.TypeQueryNode + | ts.TypeReferenceNode + | ts.UnionTypeNode + | ts.VariableDeclaration + | ts.VariableDeclarationList + | ts.VariableStatement + | ts.VoidExpression + | ts.WhileStatement + | ts.WithStatement + | ts.YieldExpression; diff --git a/packages/typescript-estree/src/use-at-your-own-risk.ts b/packages/typescript-estree/src/use-at-your-own-risk.ts index 951d68d649af..fdaa7035f219 100644 --- a/packages/typescript-estree/src/use-at-your-own-risk.ts +++ b/packages/typescript-estree/src/use-at-your-own-risk.ts @@ -1,11 +1,11 @@ // required by website -export * from './create-program/getScriptKind'; export * from './ast-converter'; -export type { ParseSettings } from './parseSettings'; +export * from './create-program/getScriptKind'; +// required by packages/type-utils +export { getCanonicalFileName } from './create-program/shared'; // required by packages/utils/src/ts-estree.ts export * from './getModifiers'; -export { typescriptVersionIsAtLeast } from './version-check'; +export type { ParseSettings } from './parseSettings'; -// required by packages/type-utils -export { getCanonicalFileName } from './create-program/shared'; +export { typescriptVersionIsAtLeast } from './version-check'; diff --git a/packages/typescript-estree/src/useProgramFromProjectService.ts b/packages/typescript-estree/src/useProgramFromProjectService.ts index e4c306b0ebee..e98cf5fccfc8 100644 --- a/packages/typescript-estree/src/useProgramFromProjectService.ts +++ b/packages/typescript-estree/src/useProgramFromProjectService.ts @@ -1,21 +1,21 @@ -import path from 'node:path'; -import util from 'node:util'; - import debug from 'debug'; import { minimatch } from 'minimatch'; +import path from 'node:path'; +import util from 'node:util'; import * as ts from 'typescript'; -import { createProjectProgram } from './create-program/createProjectProgram'; import type { ProjectServiceSettings } from './create-program/createProjectService'; -import { createNoProgram } from './create-program/createSourceFile'; import type { ASTAndDefiniteProgram, ASTAndNoProgram, ASTAndProgram, } from './create-program/shared'; -import { DEFAULT_PROJECT_FILES_ERROR_EXPLANATION } from './create-program/validateDefaultProjectForFilesGlob'; import type { MutableParseSettings } from './parseSettings'; +import { createProjectProgram } from './create-program/createProjectProgram'; +import { createNoProgram } from './create-program/createSourceFile'; +import { DEFAULT_PROJECT_FILES_ERROR_EXPLANATION } from './create-program/validateDefaultProjectForFilesGlob'; + const log = debug( 'typescript-eslint:typescript-estree:useProgramFromProjectService', ); diff --git a/packages/typescript-estree/tests/lib/convert.test.ts b/packages/typescript-estree/tests/lib/convert.test.ts index abbaa1c4b499..f626763df1a8 100644 --- a/packages/typescript-estree/tests/lib/convert.test.ts +++ b/packages/typescript-estree/tests/lib/convert.test.ts @@ -1,9 +1,11 @@ import type { TSESTree } from '@typescript-eslint/types'; + import { AST_NODE_TYPES } from '@typescript-eslint/types'; import * as ts from 'typescript'; import type { TSNode } from '../../src'; import type { ConverterOptions } from '../../src/convert'; + import { Converter } from '../../src/convert'; describe('convert', () => { @@ -205,32 +207,32 @@ describe('convert', () => { pos: 0, }; const convertedNode = instance['createNode'](tsNode, { - type: AST_NODE_TYPES.TSAbstractKeyword, - range: [0, 20], loc: { - start: { - line: 10, - column: 20, - }, end: { - line: 15, column: 25, + line: 15, + }, + start: { + column: 20, + line: 10, }, }, + range: [0, 20], + type: AST_NODE_TYPES.TSAbstractKeyword, }); expect(convertedNode).toEqual({ - type: AST_NODE_TYPES.TSAbstractKeyword, - range: [0, 20], loc: { - start: { - line: 10, - column: 20, - }, end: { - line: 15, column: 25, + line: 15, + }, + start: { + column: 20, + line: 10, }, }, + range: [0, 20], + type: AST_NODE_TYPES.TSAbstractKeyword, }); }); }); diff --git a/packages/typescript-estree/tests/lib/createParseSettings.test.ts b/packages/typescript-estree/tests/lib/createParseSettings.test.ts index d4de22b92a0e..368a2f40d50d 100644 --- a/packages/typescript-estree/tests/lib/createParseSettings.test.ts +++ b/packages/typescript-estree/tests/lib/createParseSettings.test.ts @@ -22,8 +22,8 @@ describe('createParseSettings', () => { process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE = 'true'; const parseSettings = createParseSettings('', { - projectService: undefined, project: true, + projectService: undefined, }); expect(parseSettings.projectService).toBe(projectService); @@ -43,8 +43,8 @@ describe('createParseSettings', () => { process.env.TYPESCRIPT_ESLINT_PROJECT_SERVICE = 'true'; const parseSettings = createParseSettings('', { - projectService: false, project: true, + projectService: false, }); expect(parseSettings.projectService).toBeUndefined(); diff --git a/packages/typescript-estree/tests/lib/createProjectService.test.ts b/packages/typescript-estree/tests/lib/createProjectService.test.ts index b708188722e1..7bcb827ff036 100644 --- a/packages/typescript-estree/tests/lib/createProjectService.test.ts +++ b/packages/typescript-estree/tests/lib/createProjectService.test.ts @@ -14,8 +14,11 @@ jest.mock('typescript/lib/tsserverlibrary', () => ({ server: { ...jest.requireActual('typescript/lib/tsserverlibrary').server, ProjectService: class { - logger: ts.server.Logger; eventHandler: ts.server.ProjectServiceEventHandler | undefined; + logger: ts.server.Logger; + setCompilerOptionsForInferredProjects = + mockSetCompilerOptionsForInferredProjects; + setHostConfiguration = mockSetHostConfiguration; constructor( ...args: ConstructorParameters ) { @@ -27,9 +30,6 @@ jest.mock('typescript/lib/tsserverlibrary', () => ({ } as ts.server.ProjectLoadingStartEvent); } } - setCompilerOptionsForInferredProjects = - mockSetCompilerOptionsForInferredProjects; - setHostConfiguration = mockSetHostConfiguration; }, }, })); diff --git a/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts b/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts index a1aa1a2c04e4..ca41058de14b 100644 --- a/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts +++ b/packages/typescript-estree/tests/lib/getParsedConfigFile.test.ts @@ -1,5 +1,4 @@ import path from 'node:path'; - import * as ts from 'typescript'; import { getParsedConfigFile } from '../../src/create-program/getParsedConfigFile'; @@ -7,9 +6,9 @@ import { getParsedConfigFile } from '../../src/create-program/getParsedConfigFil const mockGetParsedCommandLineOfConfigFile = jest.fn(); const mockTsserver: typeof ts = { - sys: {} as ts.System, formatDiagnostics: ts.formatDiagnostics, getParsedCommandLineOfConfigFile: mockGetParsedCommandLineOfConfigFile, + sys: {} as ts.System, // eslint-disable-next-line @typescript-eslint/no-explicit-any } as any; @@ -63,9 +62,9 @@ describe('getParsedConfigFile', () => { file: ts.createSourceFile('./tsconfig.json', '', { languageVersion: ts.ScriptTarget.Latest, }), - start: 0, length: 0, messageText: 'Oh no!', + start: 0, }, ] satisfies ts.Diagnostic[], }); @@ -87,9 +86,9 @@ describe('getParsedConfigFile', () => { file: ts.createSourceFile('./tsconfig.json', '', { languageVersion: ts.ScriptTarget.Latest, }), - start: 0, length: 0, messageText: 'Oh no!', + start: 0, } satisfies ts.Diagnostic); }, ); @@ -100,9 +99,9 @@ describe('getParsedConfigFile', () => { it('uses compiler options when parsing a config file succeeds', () => { const parsedConfigFile = { + errors: [], options: { strict: true }, raw: { compilerOptions: { strict: true } }, - errors: [], }; mockGetParsedCommandLineOfConfigFile.mockReturnValue(parsedConfigFile); expect(getParsedConfigFile(mockTsserver, 'tsconfig.json')).toEqual( diff --git a/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts b/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts index 4d9bd87fcee3..8da31477fdf0 100644 --- a/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts +++ b/packages/typescript-estree/tests/lib/getProjectConfigFiles.test.ts @@ -72,8 +72,8 @@ describe('getProjectConfigFiles', () => { getProjectConfigFiles( { filePath: './a/b/c/d.ts', - tsconfigRootDir: './a', tsconfigMatchCache, + tsconfigRootDir: './a', }, true, ); @@ -83,8 +83,8 @@ describe('getProjectConfigFiles', () => { const actual = getProjectConfigFiles( { filePath: './a/b/c/e/f.ts', - tsconfigRootDir: './a', tsconfigMatchCache, + tsconfigRootDir: './a', }, true, ); @@ -104,8 +104,8 @@ describe('getProjectConfigFiles', () => { getProjectConfigFiles( { filePath: './a/b/c/d/e.ts', - tsconfigRootDir: './a', tsconfigMatchCache, + tsconfigRootDir: './a', }, true, ); @@ -115,8 +115,8 @@ describe('getProjectConfigFiles', () => { const actual = getProjectConfigFiles( { filePath: './a/b/f/g/h.ts', - tsconfigRootDir: './a', tsconfigMatchCache, + tsconfigRootDir: './a', }, true, ); diff --git a/packages/typescript-estree/tests/lib/parse.project-true.test.ts b/packages/typescript-estree/tests/lib/parse.project-true.test.ts index bf0c3af45db2..a8e403eb8a0b 100644 --- a/packages/typescript-estree/tests/lib/parse.project-true.test.ts +++ b/packages/typescript-estree/tests/lib/parse.project-true.test.ts @@ -5,8 +5,8 @@ import * as parser from '../../src'; const PROJECT_DIR = join(__dirname, '../fixtures/projectTrue'); const config = { - tsconfigRootDir: PROJECT_DIR, project: true, + tsconfigRootDir: PROJECT_DIR, } satisfies Partial; describe('parseAndGenerateServices', () => { diff --git a/packages/typescript-estree/tests/lib/parse.test.ts b/packages/typescript-estree/tests/lib/parse.test.ts index 609fe139549d..79a6b565286a 100644 --- a/packages/typescript-estree/tests/lib/parse.test.ts +++ b/packages/typescript-estree/tests/lib/parse.test.ts @@ -1,13 +1,14 @@ -import { join, resolve } from 'node:path'; - import type { CacheDurationSeconds } from '@typescript-eslint/types'; +import type * as typescriptModule from 'typescript'; + import debug from 'debug'; import * as globbyModule from 'globby'; -import type * as typescriptModule from 'typescript'; +import { join, resolve } from 'node:path'; + +import type { TSESTreeOptions } from '../../src/parser-options'; import * as parser from '../../src'; import * as sharedParserUtilsModule from '../../src/create-program/shared'; -import type { TSESTreeOptions } from '../../src/parser-options'; import { clearGlobResolutionCache } from '../../src/parseSettings/resolveProjectList'; const FIXTURES_DIR = join(__dirname, '../fixtures/simpleProject'); @@ -72,15 +73,15 @@ describe('parseAndGenerateServices', () => { const code = 'var a = true'; const baseConfig: TSESTreeOptions = { comment: true, - tokens: true, - range: true, - loc: true, filePath: 'file.ts', + loc: true, + range: true, + tokens: true, }; const projectConfig: TSESTreeOptions = { ...baseConfig, - tsconfigRootDir: FIXTURES_DIR, project: './tsconfig.json', + tsconfigRootDir: FIXTURES_DIR, }; it('should not impact the use of parse()', () => { @@ -201,8 +202,8 @@ describe('parseAndGenerateServices', () => { const exp = expect(() => { result = parser.parseAndGenerateServices(code, { ...config, - jsx: jsxSetting, filePath: join(FIXTURES_DIR, `file${ext}`), + jsx: jsxSetting, }); }); if (!shouldThrow) { @@ -349,9 +350,9 @@ describe('parseAndGenerateServices', () => { const config: TSESTreeOptions = { comment: true, disallowAutomaticSingleRunInference: true, - tokens: true, - range: true, loc: true, + range: true, + tokens: true, tsconfigRootDir: PROJECT_DIR, }; const testParse = @@ -539,11 +540,11 @@ describe('parseAndGenerateServices', () => { const config: TSESTreeOptions = { comment: true, disallowAutomaticSingleRunInference: true, - tokens: true, - range: true, loc: true, - tsconfigRootDir: PROJECT_DIR, project: ['./**/tsconfig.json', './**/tsconfig.extra.json'], + range: true, + tokens: true, + tsconfigRootDir: PROJECT_DIR, }; const testParse = (filePath: string) => (): void => { try { @@ -649,11 +650,11 @@ describe('parseAndGenerateServices', () => { const config: TSESTreeOptions = { comment: true, disallowAutomaticSingleRunInference: true, - tokens: true, - range: true, loc: true, - tsconfigRootDir: PROJECT_DIR, project: './**/tsconfig.json', + range: true, + tokens: true, + tsconfigRootDir: PROJECT_DIR, }; const testParse = @@ -664,8 +665,8 @@ describe('parseAndGenerateServices', () => { (): void => { parser.parseAndGenerateServices(code, { ...config, - projectFolderIgnoreList, filePath: join(PROJECT_DIR, filePath, './file.ts'), + projectFolderIgnoreList, }); }; @@ -692,8 +693,8 @@ describe('parseAndGenerateServices', () => { }, disallowAutomaticSingleRunInference: true, filePath: join(FIXTURES_DIR, 'file.ts'), - tsconfigRootDir: FIXTURES_DIR, project: ['./**/tsconfig.json', './**/tsconfig.extra.json'], + tsconfigRootDir: FIXTURES_DIR, }); } diff --git a/packages/typescript-estree/tests/lib/persistentParse.test.ts b/packages/typescript-estree/tests/lib/persistentParse.test.ts index 82bc44abdf97..6a3338cf9be0 100644 --- a/packages/typescript-estree/tests/lib/persistentParse.test.ts +++ b/packages/typescript-estree/tests/lib/persistentParse.test.ts @@ -1,6 +1,5 @@ import fs from 'node:fs'; import path from 'node:path'; - import tmp from 'tmp'; import { clearCaches } from '../../src/clear-caches'; @@ -11,10 +10,10 @@ import { } from '../../src/parser'; const CONTENTS = { - foo: 'console.log("foo")', bar: 'console.log("bar")', - 'baz/bar': 'console.log("baz bar")', 'bat/baz/bar': 'console.log("bat/baz/bar")', + 'baz/bar': 'console.log("baz bar")', + foo: 'console.log("foo")', number: 'const foo = 1;', object: '(() => { })();', string: 'let a: "a" | "b";', @@ -81,11 +80,11 @@ function parseFile( ): void { parseAndGenerateServices(CONTENTS[filename], { disallowAutomaticSingleRunInference: true, - project: './tsconfig.json', - tsconfigRootDir: ignoreTsconfigRootDir ? undefined : tmpDir, filePath: relative ? path.join('src', `${filename}.ts`) : path.join(tmpDir, 'src', `${filename}.ts`), + project: './tsconfig.json', + tsconfigRootDir: ignoreTsconfigRootDir ? undefined : tmpDir, }); } @@ -243,12 +242,12 @@ function baseTests( describe('persistent parse', () => { describe('includes not ending in a slash', () => { const tsConfigExcludeBar = { - include: ['src'], exclude: ['./src/bar.ts'], + include: ['src'], }; const tsConfigIncludeAll = { - include: ['src'], exclude: [], + include: ['src'], }; baseTests(tsConfigExcludeBar, tsConfigIncludeAll); @@ -260,12 +259,12 @@ describe('persistent parse', () => { */ describe('includes ending in a slash', () => { const tsConfigExcludeBar = { - include: ['src/'], exclude: ['./src/bar.ts'], + include: ['src/'], }; const tsConfigIncludeAll = { - include: ['src/'], exclude: [], + include: ['src/'], }; baseTests(tsConfigExcludeBar, tsConfigIncludeAll); @@ -322,8 +321,8 @@ describe('persistent parse', () => { */ describe('tsconfig with overlapping globs', () => { const tsConfigExcludeBar = { - include: ['./*', './**/*', './src/**/*'], exclude: ['./src/bar.ts'], + include: ['./*', './**/*', './src/**/*'], }; const tsConfigIncludeAll = { include: ['./*', './**/*', './src/**/*'], diff --git a/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts b/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts index ea455ab20acc..0df2e12b6a9b 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo-singleRun.test.ts @@ -1,6 +1,5 @@ -import * as path from 'node:path'; - import * as glob from 'glob'; +import * as path from 'node:path'; import { createProgramFromConfigFile as createProgramFromConfigFileOriginal } from '../../src/create-program/useProvidedPrograms'; import { @@ -10,21 +9,21 @@ import { } from '../../src/parser'; const mockProgram = { + getCompilerOptions(): unknown { + return {}; + }, getSourceFile(): void { return; }, getTypeChecker(): void { return; }, - getCompilerOptions(): unknown { - return {}; - }, }; jest.mock('../../src/ast-converter', () => { return { astConverter(): unknown { - return { estree: {}, astMaps: {} }; + return { astMaps: {}, estree: {} }; }, }; }); @@ -86,11 +85,11 @@ const code = 'const foo = 5;'; // File will not be found in the first Program, but will be in the second const tsconfigs = ['./non-matching-tsconfig.json', './tsconfig.json']; const options = { + allowAutomaticSingleRunInference: true, filePath: testFiles[0], - tsconfigRootDir: path.join(process.cwd(), FIXTURES_DIR), loggerFn: false, project: tsconfigs, - allowAutomaticSingleRunInference: true, + tsconfigRootDir: path.join(process.cwd(), FIXTURES_DIR), } as const; const resolvedProject = (p: string): string => diff --git a/packages/typescript-estree/tests/lib/semanticInfo.test.ts b/packages/typescript-estree/tests/lib/semanticInfo.test.ts index c191fc65c356..415d9023a6c5 100644 --- a/packages/typescript-estree/tests/lib/semanticInfo.test.ts +++ b/packages/typescript-estree/tests/lib/semanticInfo.test.ts @@ -1,15 +1,15 @@ +import * as glob from 'glob'; import * as fs from 'node:fs'; import * as path from 'node:path'; - -import * as glob from 'glob'; import * as ts from 'typescript'; -import { clearCaches } from '../../src'; -import { createProgramFromConfigFile as createProgram } from '../../src/create-program/useProvidedPrograms'; import type { ParseAndGenerateServicesResult } from '../../src/parser'; -import { parseAndGenerateServices } from '../../src/parser'; import type { TSESTreeOptions } from '../../src/parser-options'; import type { TSESTree } from '../../src/ts-estree'; + +import { clearCaches } from '../../src'; +import { createProgramFromConfigFile as createProgram } from '../../src/create-program/useProvidedPrograms'; +import { parseAndGenerateServices } from '../../src/parser'; import { expectToHaveParserServices } from '../test-utils/expectToHaveParserServices'; import { createSnapshotTestBlock, @@ -22,19 +22,19 @@ const testFiles = glob.sync(`**/*.src.ts`, { cwd: FIXTURES_DIR, }); -function createOptions(fileName: string): TSESTreeOptions & { cwd?: string } { +function createOptions(fileName: string): { cwd?: string } & TSESTreeOptions { return { + comment: true, disallowAutomaticSingleRunInference: true, + errorOnUnknownASTType: true, + filePath: fileName, + jsx: false, loc: true, + loggerFn: false, + project: `./tsconfig.json`, range: true, tokens: true, - comment: true, - jsx: false, - errorOnUnknownASTType: true, - filePath: fileName, tsconfigRootDir: path.join(process.cwd(), FIXTURES_DIR), - project: `./tsconfig.json`, - loggerFn: false, }; } @@ -223,8 +223,8 @@ describe('semanticInfo', () => { `const x = [parseInt("5")];`, { ...createOptions(''), - project: undefined, preserveNodeMaps: true, + project: undefined, }, ); @@ -339,8 +339,8 @@ describe('semanticInfo', () => { const options = createOptions(filename); const optionsWithProjectTrue = { ...options, - project: true, programs: undefined, + project: true, }; expect(() => parseAndGenerateServices('const foo = 5;', optionsWithProjectTrue), diff --git a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts index 63eda8cff0fb..59b8f2d84c36 100644 --- a/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts +++ b/packages/typescript-estree/tests/lib/useProgramFromProjectService.test.ts @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type -- Fancy mocks */ import path from 'node:path'; - import * as ts from 'typescript'; import type { @@ -8,6 +7,7 @@ import type { TypeScriptProjectService, } from '../../src/create-program/createProjectService'; import type { ParseSettings } from '../../src/parseSettings'; + import { useProgramFromProjectService } from '../../src/useProgramFromProjectService'; const mockCreateNoProgram = jest.fn(); @@ -48,16 +48,16 @@ function createMockProjectService() { }; return { - service: service as typeof service & TypeScriptProjectService, openClientFile, + service: service as typeof service & TypeScriptProjectService, }; } const mockFileName = 'camelCaseFile.ts'; const mockParseSettings = { - filePath: `path/PascalCaseDirectory/${mockFileName}`, extraFileExtensions: [] as readonly string[], + filePath: `path/PascalCaseDirectory/${mockFileName}`, tsconfigRootDir: currentDirectory, } as ParseSettings; diff --git a/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts index 9a7468f19dff..8bbaeaef89da 100644 --- a/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts +++ b/packages/typescript-estree/tests/lib/withoutProjectParserOptions.test.ts @@ -1,4 +1,5 @@ import type { TSESTreeOptions } from '../../src'; + import { withoutProjectParserOptions } from '../../src'; describe('withoutProjectParserOptions', () => { diff --git a/packages/typescript-estree/tests/test-utils/test-utils.ts b/packages/typescript-estree/tests/test-utils/test-utils.ts index ed18eb6fb3fe..c0da2b294194 100644 --- a/packages/typescript-estree/tests/test-utils/test-utils.ts +++ b/packages/typescript-estree/tests/test-utils/test-utils.ts @@ -3,7 +3,8 @@ import type { TSESTree, TSESTreeOptions, } from '../../src'; -import { parse as parserParse, parseAndGenerateServices } from '../../src'; + +import { parseAndGenerateServices, parse as parserParse } from '../../src'; export function parseCodeAndGenerateServices( code: string, diff --git a/packages/typescript-estree/typings/typescript.d.ts b/packages/typescript-estree/typings/typescript.d.ts index de19fdb5a447..b9e2035a0192 100644 --- a/packages/typescript-estree/typings/typescript.d.ts +++ b/packages/typescript-estree/typings/typescript.d.ts @@ -20,18 +20,18 @@ declare module 'typescript' { readonly initializer?: Expression | undefined; } interface PropertyAssignment { - /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ - readonly questionToken?: QuestionToken | undefined; /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ readonly exclamationToken?: ExclamationToken | undefined; + /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ + readonly questionToken?: QuestionToken | undefined; } interface ShorthandPropertyAssignment { + /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ + readonly exclamationToken?: ExclamationToken | undefined; /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ readonly modifiers?: NodeArray | undefined; /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ readonly questionToken?: QuestionToken | undefined; - /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ - readonly exclamationToken?: ExclamationToken | undefined; } interface FunctionTypeNode { /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ From 86e59ea2a8a43239113a4cfd6c4c944b72bc82de Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Tue, 20 Aug 2024 16:54:36 -0400 Subject: [PATCH 2/3] fix: convert.ts ordering --- packages/typescript-estree/src/convert.ts | 84 +++++++++++------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index e1e09078c03d..e56bbdfa69b1 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -703,48 +703,6 @@ export class Converter { * @param result The node that will have its location data mutated * @param childRange The child node range used to expand location */ - private assertModuleSpecifier( - node: ts.ExportDeclaration | ts.ImportDeclaration, - allowNull: boolean, - ): void { - if (!allowNull && node.moduleSpecifier == null) { - this.#throwUnlessAllowInvalidAST( - node, - 'Module specifier must be a string literal.', - ); - } - - if ( - node.moduleSpecifier && - node.moduleSpecifier?.kind !== SyntaxKind.StringLiteral - ) { - this.#throwUnlessAllowInvalidAST( - node.moduleSpecifier, - 'Module specifier must be a string literal.', - ); - } - } - - private fixParentLocation( - result: TSESTree.BaseNode, - childRange: [number, number], - ): void { - if (childRange[0] < result.range[0]) { - result.range[0] = childRange[0]; - result.loc.start = getLineAndCharacterFor(result.range[0], this.ast); - } - if (childRange[1] > result.range[1]) { - result.range[1] = childRange[1]; - result.loc.end = getLineAndCharacterFor(result.range[1], this.ast); - } - } - - /** - * Converts a TypeScript node into an ESTree node. - * The core of the conversion logic: - * Identify and convert each relevant TypeScript SyntaxKind - * @returns the converted ESTree node - */ #checkModifiers(node: ts.Node): void { if (this.options.allowInvalidAST) { return; @@ -1002,6 +960,34 @@ export class Converter { } } + private assertModuleSpecifier( + node: ts.ExportDeclaration | ts.ImportDeclaration, + allowNull: boolean, + ): void { + if (!allowNull && node.moduleSpecifier == null) { + this.#throwUnlessAllowInvalidAST( + node, + 'Module specifier must be a string literal.', + ); + } + + if ( + node.moduleSpecifier && + node.moduleSpecifier?.kind !== SyntaxKind.StringLiteral + ) { + this.#throwUnlessAllowInvalidAST( + node.moduleSpecifier, + 'Module specifier must be a string literal.', + ); + } + } + + /** + * Converts a TypeScript node into an ESTree node. + * The core of the conversion logic: + * Identify and convert each relevant TypeScript SyntaxKind + * @returns the converted ESTree node + */ private convertNode(node: TSNode, parent: TSNode): TSESTree.Node | null { switch (node.kind) { case SyntaxKind.SourceFile: { @@ -3504,6 +3490,20 @@ export class Converter { } } + private fixParentLocation( + result: TSESTree.BaseNode, + childRange: [number, number], + ): void { + if (childRange[0] < result.range[0]) { + result.range[0] = childRange[0]; + result.loc.start = getLineAndCharacterFor(result.range[0], this.ast); + } + if (childRange[1] > result.range[1]) { + result.range[1] = childRange[1]; + result.loc.end = getLineAndCharacterFor(result.range[1], this.ast); + } + } + /** * Creates a getter for a property under aliasKey that returns the value under * valueKey. If suppressDeprecatedPropertyWarnings is not enabled, the From d65281e6e75f64da3586cf686464ec246f8b0ec0 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Fri, 11 Oct 2024 10:36:28 -0400 Subject: [PATCH 3/3] Thanks Kirk, moved keywords to beginning --- eslint.config.mjs | 2 +- packages/ast-spec/src/base/LiteralBase.ts | 2 +- packages/ast-spec/src/type/TSMappedType/spec.ts | 4 ++-- .../eslint-plugin/src/rules/ban-ts-comment.ts | 4 ++-- .../src/rules/class-methods-use-this.ts | 2 +- .../eslint-plugin/src/rules/member-ordering.ts | 2 +- .../src/rules/naming-convention-utils/types.ts | 2 +- .../src/rules/no-invalid-void-type.ts | 2 +- .../src/rules/no-misused-promises.ts | 4 ++-- .../src/rules/no-restricted-types.ts | 6 +++--- .../src/rules/no-use-before-define.ts | 2 +- .../src/util/collectUnusedVariables.ts | 2 +- packages/eslint-plugin/tests/configs.test.ts | 14 +++++++------- packages/eslint-plugin/tests/docs.test.ts | 2 +- .../rules/prefer-nullish-coalescing.test.ts | 8 ++++---- packages/eslint-plugin/typings/eslint-rules.d.ts | 4 ++-- packages/parser/src/parser.ts | 4 ++-- packages/rule-tester/src/RuleTester.ts | 10 +++++----- .../src/types/DependencyConstraint.ts | 2 +- .../rule-tester/src/types/InvalidTestCase.ts | 2 +- packages/rule-tester/src/types/index.ts | 2 +- .../rule-tester/src/utils/flat-config-schema.ts | 8 ++++---- packages/scope-manager/src/scope/ScopeBase.ts | 2 +- .../tests/test-utils/getSpecificNode.ts | 2 +- packages/types/src/parser-options.ts | 8 ++++---- packages/typescript-estree/src/convert.ts | 4 ++-- .../src/create-program/createProjectService.ts | 2 +- .../getWatchProgramsForProjects.ts | 2 +- .../src/parseSettings/createParseSettings.ts | 2 +- .../typescript-estree/src/parseSettings/index.ts | 2 +- packages/typescript-estree/src/parser-options.ts | 4 ++-- packages/typescript-estree/src/parser.ts | 4 ++-- packages/typescript-estree/src/source-files.ts | 2 +- .../src/ast-utils/eslint-utils/PatternMatcher.ts | 2 +- .../src/ast-utils/eslint-utils/scopeAnalysis.ts | 2 +- packages/utils/src/json-schema.ts | 8 ++++---- packages/utils/src/ts-eslint/Config.ts | 16 ++++++++-------- packages/utils/src/ts-eslint/Linter.ts | 6 +++--- packages/utils/src/ts-eslint/Processor.ts | 2 +- packages/utils/src/ts-eslint/RuleTester.ts | 4 ++-- packages/utils/src/ts-eslint/SourceCode.ts | 14 +++++++------- .../utils/src/ts-eslint/eslint/ESLintShared.ts | 6 +++--- packages/website/src/hooks/useBool.ts | 2 +- 43 files changed, 93 insertions(+), 93 deletions(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index 42abd947fa7d..26c7e212c241 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -626,7 +626,7 @@ export default tseslint.config( 'perfectionist/sort-union-types': [ 'error', { - groups: ['unknown', 'keyword', 'nullish'], + groups: ['keyword', 'unknown', 'nullish'], type: 'natural', }, ], diff --git a/packages/ast-spec/src/base/LiteralBase.ts b/packages/ast-spec/src/base/LiteralBase.ts index c878fe7b7aa5..f697b5d8ace4 100644 --- a/packages/ast-spec/src/base/LiteralBase.ts +++ b/packages/ast-spec/src/base/LiteralBase.ts @@ -4,5 +4,5 @@ import type { BaseNode } from './BaseNode'; export interface LiteralBase extends BaseNode { type: AST_NODE_TYPES.Literal; raw: string; - value: RegExp | bigint | boolean | number | string | null; + value: bigint | boolean | number | string | RegExp | null; } diff --git a/packages/ast-spec/src/type/TSMappedType/spec.ts b/packages/ast-spec/src/type/TSMappedType/spec.ts index c78d4ce5fe97..8ffed262dd5d 100644 --- a/packages/ast-spec/src/type/TSMappedType/spec.ts +++ b/packages/ast-spec/src/type/TSMappedType/spec.ts @@ -9,8 +9,8 @@ export interface TSMappedType extends BaseNode { constraint: TypeNode; key: Identifier; nameType: TypeNode | null; - optional: '+' | '-' | boolean | undefined; - readonly: '+' | '-' | boolean | undefined; + optional: boolean | '+' | '-' | undefined; + readonly: boolean | '+' | '-' | undefined; typeAnnotation: TypeNode | undefined; /** @deprecated Use {@link `constraint`} and {@link `key`} instead. */ typeParameter: TSTypeParameter; diff --git a/packages/eslint-plugin/src/rules/ban-ts-comment.ts b/packages/eslint-plugin/src/rules/ban-ts-comment.ts index 3f1379b807ff..61ded7aabf4b 100644 --- a/packages/eslint-plugin/src/rules/ban-ts-comment.ts +++ b/packages/eslint-plugin/src/rules/ban-ts-comment.ts @@ -5,9 +5,9 @@ import { AST_TOKEN_TYPES } from '@typescript-eslint/utils'; import { createRule, getStringLength, nullThrows } from '../util'; type DirectiveConfig = + | boolean | 'allow-with-description' - | { descriptionFormat: string } - | boolean; + | { descriptionFormat: string }; interface Options { minimumDescriptionLength?: number; diff --git a/packages/eslint-plugin/src/rules/class-methods-use-this.ts b/packages/eslint-plugin/src/rules/class-methods-use-this.ts index 1d3beff94d25..65ddecae73ed 100644 --- a/packages/eslint-plugin/src/rules/class-methods-use-this.ts +++ b/packages/eslint-plugin/src/rules/class-methods-use-this.ts @@ -13,7 +13,7 @@ type Options = [ { enforceForClassFields?: boolean; exceptMethods?: string[]; - ignoreClassesThatImplementAnInterface?: 'public-fields' | boolean; + ignoreClassesThatImplementAnInterface?: boolean | 'public-fields'; ignoreOverrideMethods?: boolean; }, ]; diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index f845f1f1ae75..83b297152267 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -995,7 +995,7 @@ export default createRule({ // Standardize config let order: Order | undefined; - let memberTypes: MemberType[] | string | undefined; + let memberTypes: string | MemberType[] | undefined; let optionalityOrder: OptionalityOrder | undefined; /** diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/types.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/types.ts index 41df37e8cb15..ecf98d4d5175 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/types.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/types.ts @@ -23,7 +23,7 @@ interface MatchRegex { interface Selector { custom?: MatchRegex; - filter?: MatchRegex | string; + filter?: string | MatchRegex; // format options format: PredefinedFormatsString[] | null; leadingUnderscore?: UnderscoreOptionsString; diff --git a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts index 34f3f8cb22a1..269783baf811 100644 --- a/packages/eslint-plugin/src/rules/no-invalid-void-type.ts +++ b/packages/eslint-plugin/src/rules/no-invalid-void-type.ts @@ -6,7 +6,7 @@ import { createRule } from '../util'; interface Options { allowAsThisParameter?: boolean; - allowInGenericTypeArguments?: [string, ...string[]] | boolean; + allowInGenericTypeArguments?: boolean | [string, ...string[]]; } type MessageIds = diff --git a/packages/eslint-plugin/src/rules/no-misused-promises.ts b/packages/eslint-plugin/src/rules/no-misused-promises.ts index ac8c359fc1cc..3acfde02899d 100644 --- a/packages/eslint-plugin/src/rules/no-misused-promises.ts +++ b/packages/eslint-plugin/src/rules/no-misused-promises.ts @@ -18,7 +18,7 @@ type Options = [ { checksConditionals?: boolean; checksSpreads?: boolean; - checksVoidReturn?: ChecksVoidReturnOptions | boolean; + checksVoidReturn?: boolean | ChecksVoidReturnOptions; }, ]; @@ -43,7 +43,7 @@ type MessageId = | 'voidReturnVariable'; function parseChecksVoidReturn( - checksVoidReturn: ChecksVoidReturnOptions | boolean | undefined, + checksVoidReturn: boolean | ChecksVoidReturnOptions | undefined, ): ChecksVoidReturnOptions | false { switch (checksVoidReturn) { case false: diff --git a/packages/eslint-plugin/src/rules/no-restricted-types.ts b/packages/eslint-plugin/src/rules/no-restricted-types.ts index 8192b9380c7e..97dd8fcff92a 100644 --- a/packages/eslint-plugin/src/rules/no-restricted-types.ts +++ b/packages/eslint-plugin/src/rules/no-restricted-types.ts @@ -6,13 +6,13 @@ import { createRule, objectReduceKey } from '../util'; type Types = Record< string, + | boolean + | string | { fixWith?: string; message: string; suggest?: readonly string[]; } - | boolean - | string | null >; @@ -37,7 +37,7 @@ function stringifyNode( } function getCustomMessage( - bannedType: { fixWith?: string; message?: string } | true | string | null, + bannedType: string | { fixWith?: string; message?: string } | true | null, ): string { if (!bannedType || bannedType === true) { return ''; diff --git a/packages/eslint-plugin/src/rules/no-use-before-define.ts b/packages/eslint-plugin/src/rules/no-use-before-define.ts index 8350f6477318..223a8d3b05bc 100644 --- a/packages/eslint-plugin/src/rules/no-use-before-define.ts +++ b/packages/eslint-plugin/src/rules/no-use-before-define.ts @@ -12,7 +12,7 @@ const SENTINEL_TYPE = /** * Parses a given value as options. */ -function parseOptions(options: Config | string | null): Required { +function parseOptions(options: string | Config | null): Required { let functions = true; let classes = true; let enums = true; diff --git a/packages/eslint-plugin/src/util/collectUnusedVariables.ts b/packages/eslint-plugin/src/util/collectUnusedVariables.ts index 2e74a5f6a662..065aac8e1f57 100644 --- a/packages/eslint-plugin/src/util/collectUnusedVariables.ts +++ b/packages/eslint-plugin/src/util/collectUnusedVariables.ts @@ -234,7 +234,7 @@ class UnusedVarsVisitor extends Visitor { private markVariableAsUsed(name: string, parent: TSESTree.Node): void; private markVariableAsUsed( - variableOrIdentifierOrName: ScopeVariable | TSESTree.Identifier | string, + variableOrIdentifierOrName: string | ScopeVariable | TSESTree.Identifier, parent?: TSESTree.Node, ): void { if ( diff --git a/packages/eslint-plugin/tests/configs.test.ts b/packages/eslint-plugin/tests/configs.test.ts index 3c62311271d3..53382ced824f 100644 --- a/packages/eslint-plugin/tests/configs.test.ts +++ b/packages/eslint-plugin/tests/configs.test.ts @@ -17,8 +17,8 @@ const EXTENSION_RULES = Object.entries(rules) ); function filterRules( - values: Record, -): [string, unknown[] | string][] { + values: Record, +): [string, string | unknown[]][] { return Object.entries(values).filter(([name]) => name.startsWith(RULE_NAME_PREFIX), ); @@ -84,7 +84,7 @@ function filterAndMapRuleConfigs({ } function itHasBaseRulesOverriden( - unfilteredConfigRules: Record, + unfilteredConfigRules: Record, ): void { it('has the base rules overriden by the appropriate extension rules', () => { const ruleNames = new Set(Object.keys(unfilteredConfigRules)); @@ -196,7 +196,7 @@ describe('recommended-type-checked-only.ts', () => { }); describe('strict.ts', () => { - const unfilteredConfigRules: Record = + const unfilteredConfigRules: Record = plugin.configs.strict.rules; it('contains all strict rules, excluding type checked ones', () => { @@ -217,7 +217,7 @@ describe('strict.ts', () => { }); describe('strict-type-checked.ts', () => { - const unfilteredConfigRules: Record = + const unfilteredConfigRules: Record = plugin.configs['strict-type-checked'].rules; it('contains all strict rules', () => { @@ -236,7 +236,7 @@ describe('strict-type-checked.ts', () => { }); describe('strict-type-checked-only.ts', () => { - const unfilteredConfigRules: Record = + const unfilteredConfigRules: Record = plugin.configs['strict-type-checked-only'].rules; it('contains only type-checked strict rules', () => { @@ -257,7 +257,7 @@ describe('strict-type-checked-only.ts', () => { }); describe('stylistic.ts', () => { - const unfilteredConfigRules: Record = + const unfilteredConfigRules: Record = plugin.configs.stylistic.rules; it('contains all stylistic rules, excluding deprecated or type checked ones', () => { diff --git a/packages/eslint-plugin/tests/docs.test.ts b/packages/eslint-plugin/tests/docs.test.ts index c94c88e9b931..a0f1d74dad30 100644 --- a/packages/eslint-plugin/tests/docs.test.ts +++ b/packages/eslint-plugin/tests/docs.test.ts @@ -435,7 +435,7 @@ describe('Validating rule docs', () => { function lintCodeBlock( token: mdast.Code, - shouldContainLintErrors: 'skip-check' | boolean, + shouldContainLintErrors: boolean | 'skip-check', ): void { const lang = token.lang?.trim(); if (!lang || !/^tsx?\b/i.test(lang)) { diff --git a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts index bbd655fa5d9a..85c2365739c0 100644 --- a/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts +++ b/packages/eslint-plugin/tests/rules/prefer-nullish-coalescing.test.ts @@ -30,15 +30,15 @@ const nullishTypes = ['null', 'undefined', 'null | undefined']; const ignorablePrimitiveTypes = ['string', 'number', 'boolean', 'bigint']; function typeValidTest( - cb: (type: string) => ValidTestCase | string, -): (ValidTestCase | string)[] { + cb: (type: string) => string | ValidTestCase, +): (string | ValidTestCase)[] { return types.map(type => cb(type)); } function nullishTypeTest< T extends + | string | InvalidTestCase - | ValidTestCase - | string, + | ValidTestCase, >(cb: (nullish: string, type: string) => T): T[] { return nullishTypes.flatMap(nullish => types.map(type => cb(nullish, type))); } diff --git a/packages/eslint-plugin/typings/eslint-rules.d.ts b/packages/eslint-plugin/typings/eslint-rules.d.ts index 0b39f36da45f..557a6eece2f4 100644 --- a/packages/eslint-plugin/typings/eslint-rules.d.ts +++ b/packages/eslint-plugin/typings/eslint-rules.d.ts @@ -256,11 +256,11 @@ declare module 'eslint/lib/rules/no-restricted-globals' { const rule: TSESLint.RuleModule< 'customMessage' | 'defaultMessage', ( + | string | { message?: string; name: string; } - | string )[], unknown, { @@ -539,6 +539,7 @@ declare module 'eslint/lib/rules/no-restricted-imports' { namespace rule { export type ArrayOfStringOrObject = ( + | string | { // extended allowTypeImports?: boolean; @@ -546,7 +547,6 @@ declare module 'eslint/lib/rules/no-restricted-imports' { message?: string; name: string; } - | string )[]; export type ArrayOfStringOrObjectPatterns = | { diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 6651a09183ae..ee749d2b947a 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -77,14 +77,14 @@ function getLib(compilerOptions: ts.CompilerOptions): Lib[] { } function parse( - code: ts.SourceFile | string, + code: string | ts.SourceFile, options?: ParserOptions, ): ParseForESLintResult['ast'] { return parseForESLint(code, options).ast; } function parseForESLint( - code: ts.SourceFile | string, + code: string | ts.SourceFile, parserOptions?: ParserOptions | null, ): ParseForESLintResult { if (!parserOptions || typeof parserOptions !== 'object') { diff --git a/packages/rule-tester/src/RuleTester.ts b/packages/rule-tester/src/RuleTester.ts index 6a1bd8fb0c42..4397466463f7 100644 --- a/packages/rule-tester/src/RuleTester.ts +++ b/packages/rule-tester/src/RuleTester.ts @@ -237,7 +237,7 @@ export class RuleTester extends TestFramework { * Adds the `only` property to a test to run it in isolation. */ static only( - item: ValidTestCase | string, + item: string | ValidTestCase, ): ValidTestCase; /** * Adds the `only` property to a test to run it in isolation. @@ -247,9 +247,9 @@ export class RuleTester extends TestFramework { ): InvalidTestCase; static only( item: + | string | InvalidTestCase - | ValidTestCase - | string, + | ValidTestCase, ): InvalidTestCase | ValidTestCase { if (typeof item === 'string') { return { code: item, only: true }; @@ -781,7 +781,7 @@ export class RuleTester extends TestFramework { >( ruleName: string, rule: RuleModule, - itemIn: ValidTestCase | string, + itemIn: string | ValidTestCase, seenValidTestCases: Set, ): void { const item: ValidTestCase = @@ -1322,7 +1322,7 @@ function checkDuplicateTestCase( * value is a regular expression, it is checked against the actual * value. */ -function assertMessageMatches(actual: string, expected: RegExp | string): void { +function assertMessageMatches(actual: string, expected: string | RegExp): void { if (expected instanceof RegExp) { // assert.js doesn't have a built-in RegExp match function assert.ok( diff --git a/packages/rule-tester/src/types/DependencyConstraint.ts b/packages/rule-tester/src/types/DependencyConstraint.ts index 2e9138cd401d..c271e8bba3ff 100644 --- a/packages/rule-tester/src/types/DependencyConstraint.ts +++ b/packages/rule-tester/src/types/DependencyConstraint.ts @@ -6,7 +6,7 @@ export interface RangeOptions { } export interface SemverVersionConstraint { - readonly options?: RangeOptions | boolean; + readonly options?: boolean | RangeOptions; readonly range: string; } export type AtLeastVersionConstraint = diff --git a/packages/rule-tester/src/types/InvalidTestCase.ts b/packages/rule-tester/src/types/InvalidTestCase.ts index bcd9439f5544..73e8f48a6771 100644 --- a/packages/rule-tester/src/types/InvalidTestCase.ts +++ b/packages/rule-tester/src/types/InvalidTestCase.ts @@ -76,5 +76,5 @@ export interface InvalidTestCase< /** * The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested. */ - readonly output?: string[] | string | null; + readonly output?: string | string[] | null; } diff --git a/packages/rule-tester/src/types/index.ts b/packages/rule-tester/src/types/index.ts index 6d89f7808fde..becf16d2c5c9 100644 --- a/packages/rule-tester/src/types/index.ts +++ b/packages/rule-tester/src/types/index.ts @@ -18,7 +18,7 @@ export interface RunTests< > { readonly invalid: readonly InvalidTestCase[]; // RuleTester.run also accepts strings for valid cases - readonly valid: readonly (ValidTestCase | string)[]; + readonly valid: readonly (string | ValidTestCase)[]; } export interface NormalizedRunTests< diff --git a/packages/rule-tester/src/utils/flat-config-schema.ts b/packages/rule-tester/src/utils/flat-config-schema.ts index d1fe7a894515..55730f8e6b15 100644 --- a/packages/rule-tester/src/utils/flat-config-schema.ts +++ b/packages/rule-tester/src/utils/flat-config-schema.ts @@ -10,8 +10,8 @@ import { normalizeSeverityToNumber } from './severity'; type PluginMemberName = `${string}/${string}`; interface ObjectPropertySchema { - merge: ((a: T, b: T) => T) | string; - validate: ((value: unknown) => asserts value is T) | string; + merge: string | ((a: T, b: T) => T); + validate: string | ((value: unknown) => asserts value is T); } const ruleSeverities = new Map([ @@ -279,8 +279,8 @@ const ALLOWED_SEVERITIES = new Set([0, 1, 2, 'error', 'off', 'warn']); const disableDirectiveSeveritySchema: ObjectPropertySchema = { merge( - first: SharedConfig.RuleLevel | boolean | undefined, - second: SharedConfig.RuleLevel | boolean | undefined, + first: boolean | SharedConfig.RuleLevel | undefined, + second: boolean | SharedConfig.RuleLevel | undefined, ): SharedConfig.RuleLevel { const value = second ?? first; diff --git a/packages/scope-manager/src/scope/ScopeBase.ts b/packages/scope-manager/src/scope/ScopeBase.ts index 2ffb0a7b9581..bd86ee66a262 100644 --- a/packages/scope-manager/src/scope/ScopeBase.ts +++ b/packages/scope-manager/src/scope/ScopeBase.ts @@ -374,7 +374,7 @@ abstract class ScopeBase< * References in default parameters isn't resolved to variables which are in their function body. */ protected defineVariable( - nameOrVariable: Variable | string, + nameOrVariable: string | Variable, set: Map, variables: Variable[], node: TSESTree.Identifier | null, diff --git a/packages/scope-manager/tests/test-utils/getSpecificNode.ts b/packages/scope-manager/tests/test-utils/getSpecificNode.ts index a5b6b68b00ef..0272aca3d377 100644 --- a/packages/scope-manager/tests/test-utils/getSpecificNode.ts +++ b/packages/scope-manager/tests/test-utils/getSpecificNode.ts @@ -24,7 +24,7 @@ function getSpecificNode< function getSpecificNode( ast: TSESTree.Node, selector: AST_NODE_TYPES, - cb?: (node: TSESTree.Node) => TSESTree.Node | boolean | null | undefined, + cb?: (node: TSESTree.Node) => boolean | TSESTree.Node | null | undefined, ): TSESTree.Node { let node: TSESTree.Node | null | undefined = null; simpleTraverse( diff --git a/packages/types/src/parser-options.ts b/packages/types/src/parser-options.ts index e6f3b404c96f..b2257ebb91a6 100644 --- a/packages/types/src/parser-options.ts +++ b/packages/types/src/parser-options.ts @@ -2,8 +2,8 @@ import type { Program } from 'typescript'; import type { Lib } from './lib'; -type DebugLevel = ('eslint' | 'typescript' | 'typescript-eslint')[] | boolean; -type CacheDurationSeconds = 'Infinity' | number; +type DebugLevel = boolean | ('eslint' | 'typescript' | 'typescript-eslint')[]; +type CacheDurationSeconds = number | 'Infinity'; type EcmaVersion = | 'latest' @@ -102,9 +102,9 @@ interface ParserOptions { jsxPragma?: string | null; lib?: Lib[]; programs?: Program[] | null; - project?: string[] | boolean | string | null; + project?: boolean | string | string[] | null; projectFolderIgnoreList?: string[]; - projectService?: ProjectServiceOptions | boolean; + projectService?: boolean | ProjectServiceOptions; range?: boolean; sourceType?: SourceType | undefined; tokens?: boolean; diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 1ffc1f782d44..2a4208c45871 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -338,7 +338,7 @@ export class Converter { } #throwUnlessAllowInvalidAST( - node: ts.Node | number, + node: number | ts.Node, message: string, ): asserts node is never { if (!this.options.allowInvalidAST) { @@ -3559,7 +3559,7 @@ export class Converter { } } - #throwError(node: ts.Node | number, message: string): asserts node is never { + #throwError(node: number | ts.Node, message: string): asserts node is never { let start; let end; if (typeof node === 'number') { diff --git a/packages/typescript-estree/src/create-program/createProjectService.ts b/packages/typescript-estree/src/create-program/createProjectService.ts index 2f7ed11cdff2..dfd753803231 100644 --- a/packages/typescript-estree/src/create-program/createProjectService.ts +++ b/packages/typescript-estree/src/create-program/createProjectService.ts @@ -40,7 +40,7 @@ export interface ProjectServiceSettings { } export function createProjectService( - optionsRaw: ProjectServiceOptions | boolean | undefined, + optionsRaw: boolean | ProjectServiceOptions | undefined, jsDocParsingMode: ts.JSDocParsingMode | undefined, tsconfigRootDir: string | undefined, ): ProjectServiceSettings { diff --git a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts index 7ffd9c33c7c7..dd93452b4821 100644 --- a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts +++ b/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts @@ -92,7 +92,7 @@ function saveWatchCallback( * Holds information about the file currently being linted */ const currentLintOperationState: { - code: ts.SourceFile | string; + code: string | ts.SourceFile; filePath: CanonicalPath; } = { code: '', diff --git a/packages/typescript-estree/src/parseSettings/createParseSettings.ts b/packages/typescript-estree/src/parseSettings/createParseSettings.ts index 76cba5c48e74..999107b6d4af 100644 --- a/packages/typescript-estree/src/parseSettings/createParseSettings.ts +++ b/packages/typescript-estree/src/parseSettings/createParseSettings.ts @@ -38,7 +38,7 @@ const JSDocParsingMode = { /* eslint-enable @typescript-eslint/no-unnecessary-condition */ export function createParseSettings( - code: ts.SourceFile | string, + code: string | ts.SourceFile, tsestreeOptions: Partial = {}, ): MutableParseSettings { const codeFullText = enforceCodeString(code); diff --git a/packages/typescript-estree/src/parseSettings/index.ts b/packages/typescript-estree/src/parseSettings/index.ts index e38dbc268071..1ea208210e0a 100644 --- a/packages/typescript-estree/src/parseSettings/index.ts +++ b/packages/typescript-estree/src/parseSettings/index.ts @@ -30,7 +30,7 @@ export interface MutableParseSettings { /** * Code of the file being parsed, or raw source file containing it. */ - code: ts.SourceFile | string; + code: string | ts.SourceFile; /** * Full text of the file being parsed. diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index 771a0a9d818e..48cbf0b8da1c 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -190,7 +190,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { * * Note that {@link projectService} is now preferred. */ - project?: string[] | boolean | string | null; + project?: boolean | string | string[] | null; /** * If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from @@ -204,7 +204,7 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { /** * Whether to create a shared TypeScript project service to power program creation. */ - projectService?: ProjectServiceOptions | boolean; + projectService?: boolean | ProjectServiceOptions; /** * The absolute path to the root directory for all provided `project`s. diff --git a/packages/typescript-estree/src/parser.ts b/packages/typescript-estree/src/parser.ts index 28af1b52ee1c..340bee1c15aa 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/typescript-estree/src/parser.ts @@ -115,7 +115,7 @@ function parse( } function parseWithNodeMapsInternal( - code: ts.SourceFile | string, + code: string | ts.SourceFile, options: T | undefined, shouldPreserveNodeMaps: boolean, ): ParseWithNodeMapsResult { @@ -161,7 +161,7 @@ function clearParseAndGenerateServicesCalls(): void { } function parseAndGenerateServices( - code: ts.SourceFile | string, + code: string | ts.SourceFile, tsestreeOptions: T, ): ParseAndGenerateServicesResult { /** diff --git a/packages/typescript-estree/src/source-files.ts b/packages/typescript-estree/src/source-files.ts index 8c4ae0fc87e1..18cd45670907 100644 --- a/packages/typescript-estree/src/source-files.ts +++ b/packages/typescript-estree/src/source-files.ts @@ -12,6 +12,6 @@ export function isSourceFile(code: unknown): code is ts.SourceFile { ); } -export function getCodeText(code: ts.SourceFile | string): string { +export function getCodeText(code: string | ts.SourceFile): string { return isSourceFile(code) ? code.getFullText(code) : code; } diff --git a/packages/utils/src/ast-utils/eslint-utils/PatternMatcher.ts b/packages/utils/src/ast-utils/eslint-utils/PatternMatcher.ts index 34431ded3158..3f5f4c841a5e 100644 --- a/packages/utils/src/ast-utils/eslint-utils/PatternMatcher.ts +++ b/packages/utils/src/ast-utils/eslint-utils/PatternMatcher.ts @@ -25,7 +25,7 @@ interface PatternMatcher { */ [Symbol.replace]( str: string, - replacer: ((...strs: string[]) => string) | string, + replacer: string | ((...strs: string[]) => string), ): string; /** diff --git a/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts b/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts index 43199ce05533..563c51c7782b 100644 --- a/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts +++ b/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts @@ -10,7 +10,7 @@ import type { TSESTree } from '../../ts-estree'; */ const findVariable = eslintUtils.findVariable as ( initialScope: TSESLint.Scope.Scope, - nameOrNode: TSESTree.Identifier | string, + nameOrNode: string | TSESTree.Identifier, ) => TSESLint.Scope.Variable | null; /** diff --git a/packages/utils/src/json-schema.ts b/packages/utils/src/json-schema.ts index 83ba0fd36793..1c94883578c4 100644 --- a/packages/utils/src/json-schema.ts +++ b/packages/utils/src/json-schema.ts @@ -146,7 +146,7 @@ interface JSONSchema4Base { * * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.26 */ - extends?: string[] | string | undefined; + extends?: string | string[] | undefined; id?: string | undefined; @@ -167,7 +167,7 @@ interface JSONSchema4Base { * * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.7 */ - required?: string[] | boolean | undefined; + required?: boolean | string[] | undefined; /** * This attribute is a string that provides a short description of the @@ -238,7 +238,7 @@ export interface JSONSchema4ObjectSchema extends JSONSchema4Base { * * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.4 */ - additionalProperties?: JSONSchema4 | boolean | undefined; + additionalProperties?: boolean | JSONSchema4 | undefined; /** * The `dependencies` keyword conditionally applies a sub-schema when a given @@ -302,7 +302,7 @@ export interface JSONSchema4ArraySchema extends JSONSchema4Base { * * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.6 */ - additionalItems?: JSONSchema4 | boolean | undefined; + additionalItems?: boolean | JSONSchema4 | undefined; /** * This attribute defines the allowed items in an instance array, and diff --git a/packages/utils/src/ts-eslint/Config.ts b/packages/utils/src/ts-eslint/Config.ts index 924214bf86c0..dad591e03ef5 100644 --- a/packages/utils/src/ts-eslint/Config.ts +++ b/packages/utils/src/ts-eslint/Config.ts @@ -73,7 +73,7 @@ export namespace ClassicConfig { /** * The path to other config files or the package name of shareable configs. */ - extends?: string[] | string; + extends?: string | string[]; /** * The global variable settings. */ @@ -117,15 +117,15 @@ export namespace ClassicConfig { } export interface ConfigOverride extends BaseConfig { - excludedFiles?: string[] | string; - files: string[] | string; + excludedFiles?: string | string[]; + files: string | string[]; } export interface Config extends BaseConfig { /** * The glob patterns that ignore to lint. */ - ignorePatterns?: string[] | string; + ignorePatterns?: string | string[]; /** * The root flag. */ @@ -197,9 +197,9 @@ export namespace FlatConfig { * @default "off" */ reportUnusedDisableDirectives?: + | boolean | SharedConfig.Severity - | SharedConfig.SeverityString - | boolean; + | SharedConfig.SeverityString; } export interface LanguageOptions { @@ -250,8 +250,8 @@ export namespace FlatConfig { * If not specified, the configuration object applies to all files matched by any other configuration object. */ files?: ( - | string[] // yes, a single layer of array nesting is supported | string + | string[] // yes, a single layer of array nesting is supported )[]; /** * An array of glob patterns indicating the files that the configuration object should not apply to. @@ -280,7 +280,7 @@ export namespace FlatConfig { * a string indicating the name of a processor inside of a plugin * (i.e., `"pluginName/processorName"`). */ - processor?: Processor | string; + processor?: string | Processor; /** * An object containing the configured rules. * When `files` or `ignores` are specified, these rule configurations are only available to the matching files. diff --git a/packages/utils/src/ts-eslint/Linter.ts b/packages/utils/src/ts-eslint/Linter.ts index b9bee0ee5d94..df67ddb714d8 100644 --- a/packages/utils/src/ts-eslint/Linter.ts +++ b/packages/utils/src/ts-eslint/Linter.ts @@ -84,9 +84,9 @@ declare class LinterBase { * @returns The results as an array of messages or an empty array if no messages. */ verify( - textOrSourceCode: SourceCode | string, + textOrSourceCode: string | SourceCode, config: Linter.ConfigType, - filenameOrOptions?: Linter.VerifyOptions | string, + filenameOrOptions?: string | Linter.VerifyOptions, ): Linter.LintMessage[]; //////////////////// @@ -183,7 +183,7 @@ namespace Linter { /** * Adds reported errors for unused `eslint-disable` directives. */ - reportUnusedDisableDirectives?: SeverityString | boolean; + reportUnusedDisableDirectives?: boolean | SeverityString; } export interface FixOptions extends VerifyOptions { diff --git a/packages/utils/src/ts-eslint/Processor.ts b/packages/utils/src/ts-eslint/Processor.ts index 5af746af4003..631e575690de 100644 --- a/packages/utils/src/ts-eslint/Processor.ts +++ b/packages/utils/src/ts-eslint/Processor.ts @@ -17,7 +17,7 @@ export namespace Processor { export type PreProcess = ( text: string, filename: string, - ) => ({ filename: string; text: string } | string)[]; + ) => (string | { filename: string; text: string })[]; export type PostProcess = ( messagesList: Linter.LintMessage[][], diff --git a/packages/utils/src/ts-eslint/RuleTester.ts b/packages/utils/src/ts-eslint/RuleTester.ts index a9887ad835d1..4d0a8ca2b121 100644 --- a/packages/utils/src/ts-eslint/RuleTester.ts +++ b/packages/utils/src/ts-eslint/RuleTester.ts @@ -94,7 +94,7 @@ interface InvalidTestCase< /** * The expected code after autofixes are applied. If set to `null`, the test runner will assert that no autofix is suggested. */ - readonly output?: string[] | string | null; + readonly output?: string | string[] | null; } /** @@ -156,7 +156,7 @@ interface RunTests< > { // RuleTester.run also accepts strings for valid cases readonly invalid: readonly InvalidTestCase[]; - readonly valid: readonly (ValidTestCase | string)[]; + readonly valid: readonly (string | ValidTestCase)[]; } /** diff --git a/packages/utils/src/ts-eslint/SourceCode.ts b/packages/utils/src/ts-eslint/SourceCode.ts index b5caea851b92..eefc36696be4 100644 --- a/packages/utils/src/ts-eslint/SourceCode.ts +++ b/packages/utils/src/ts-eslint/SourceCode.ts @@ -184,7 +184,7 @@ declare class TokenStore { */ getTokensAfter( node: TSESTree.Node | TSESTree.Token, - options?: T | number, + options?: number | T, ): SourceCode.ReturnTypeFromOptions[]; /** * Gets the `count` tokens that precedes a given node or token. @@ -193,7 +193,7 @@ declare class TokenStore { */ getTokensBefore( node: TSESTree.Node | TSESTree.Token, - options?: T | number, + options?: number | T, ): SourceCode.ReturnTypeFromOptions[]; /** * Gets all of the tokens between two non-overlapping nodes. @@ -205,7 +205,7 @@ declare class TokenStore { getTokensBetween( left: TSESTree.Node | TSESTree.Token, right: TSESTree.Node | TSESTree.Token, - options?: T | number, + options?: number | T, ): SourceCode.ReturnTypeFromOptions[]; } @@ -415,6 +415,7 @@ namespace SourceCode { >; export type CursorWithSkipOptions = + | number | { /** * The predicate function to choose tokens. @@ -429,10 +430,10 @@ namespace SourceCode { */ skip?: number; } - | FilterPredicate - | number; + | FilterPredicate; export type CursorWithCountOptions = + | number | { /** * The maximum count of tokens the cursor iterates. @@ -447,8 +448,7 @@ namespace SourceCode { */ includeComments?: boolean; } - | FilterPredicate - | number; + | FilterPredicate; } class SourceCode extends (ESLintSourceCode as typeof SourceCodeBase) {} diff --git a/packages/utils/src/ts-eslint/eslint/ESLintShared.ts b/packages/utils/src/ts-eslint/eslint/ESLintShared.ts index aad9b71e558b..db6e5b4de20d 100644 --- a/packages/utils/src/ts-eslint/eslint/ESLintShared.ts +++ b/packages/utils/src/ts-eslint/eslint/ESLintShared.ts @@ -42,7 +42,7 @@ export declare class ESLintBase< * @param patterns The lint target files. This can contain any of file paths, directory paths, and glob patterns. * @returns The promise that will be fulfilled with an array of LintResult objects. */ - lintFiles(patterns: string[] | string): Promise; + lintFiles(patterns: string | string[]): Promise; /** * This method lints the given source code text and then returns the results. @@ -150,7 +150,7 @@ export interface ESLintOptions { * lint messages for which the function returned true. * @default false */ - fix?: ((message: LintMessage) => boolean) | boolean; + fix?: boolean | ((message: LintMessage) => boolean); /** * The types of the rules that the `eslint.lintFiles()` and `eslint.lintText()` methods use for autofix. * @default null @@ -404,5 +404,5 @@ export interface Formatter { * The method to convert the LintResult objects to text. * Promise return supported since 8.4.0 */ - format(results: LintResult[]): Promise | string; + format(results: LintResult[]): string | Promise; } diff --git a/packages/website/src/hooks/useBool.ts b/packages/website/src/hooks/useBool.ts index 8ef2e086f422..39bec4e5fd41 100644 --- a/packages/website/src/hooks/useBool.ts +++ b/packages/website/src/hooks/useBool.ts @@ -3,7 +3,7 @@ import type { Dispatch, SetStateAction } from 'react'; import { useCallback, useState } from 'react'; export function useBool( - initialState: (() => boolean) | boolean, + initialState: boolean | (() => boolean), ): [boolean, () => void, Dispatch>] { const [value, setValue] = useState(initialState);