From 5378779bb67c9c193c48137ecbc509bdc305bc0b Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 10 May 2025 21:52:52 -0400 Subject: [PATCH 1/3] Package split: parser-services --- .vscode/settings.json | 2 + packages/parser-services/LICENSE | 21 ++++ packages/parser-services/README.md | 3 + packages/parser-services/package.json | 65 ++++++++++ packages/parser-services/project.json | 16 +++ .../src/clear-caches.ts | 3 - .../WatchCompilerHostOfConfigFile.ts | 0 .../create-program/createIsolatedProgram.ts | 2 +- .../create-program/createProjectProgram.ts | 5 +- .../createProjectProgramError.ts | 3 +- .../create-program/createProjectService.ts | 3 +- .../src/create-program/createSourceFile.ts | 4 +- .../src/create-program/describeFilePath.ts | 0 .../src/create-program/getParsedConfigFile.ts | 0 .../src/create-program/getScriptKind.ts | 0 .../getWatchProgramsForProjects.ts | 2 +- .../src/create-program/shared.ts | 3 +- .../src/create-program/useProvidedPrograms.ts | 2 +- .../src/create-program/utils.ts | 22 ++++ .../validateDefaultProjectForFilesGlob.ts | 0 .../src/createParserServices.ts | 5 +- packages/parser-services/src/index.ts | 6 + .../src/parseSettings/ExpiringCache.ts | 0 .../src/parseSettings/createParseSettings.ts | 8 +- .../parseSettings/getProjectConfigFiles.ts | 2 +- .../src/parseSettings/index.ts | 6 +- .../src/parseSettings/inferSingleRun.ts | 3 +- .../src/parseSettings/resolveProjectList.ts | 9 +- .../src/parseSettings/warnAboutTSVersion.ts | 4 +- .../src/parser.ts | 31 +++-- .../src/semantic-or-syntactic-errors.ts | 119 ++++++++++++++++++ .../src/source-files.ts | 0 packages/parser-services/src/types.ts | 29 +++++ .../src/use-at-your-own-risk.ts | 6 + .../src/useProgramFromProjectService.ts | 0 packages/parser-services/src/version.ts | 3 + .../src/withoutProjectParserOptions.ts | 0 packages/parser-services/tsconfig.build.json | 17 +++ packages/parser-services/tsconfig.json | 16 +++ packages/parser-services/tsconfig.spec.json | 18 +++ .../parser-services/typings/typescript.d.ts | 57 +++++++++ packages/parser-services/vitest.config.mts | 22 ++++ packages/parser/package.json | 1 + packages/parser/src/index.ts | 6 +- packages/parser/src/parser.ts | 12 +- packages/parser/tsconfig.build.json | 3 + packages/parser/tsconfig.json | 3 + .../src/getConstrainedTypeAtLocation.ts | 6 +- packages/type-utils/src/getDeclaration.ts | 6 +- .../typeDeclaredInFile.ts | 2 +- packages/typescript-estree/package.json | 2 - .../typescript-estree/src/ast-converter.ts | 37 ++++-- packages/typescript-estree/src/convert.ts | 26 +--- packages/typescript-estree/src/errors.ts | 72 +++++++++++ packages/typescript-estree/src/index.ts | 25 ++-- packages/typescript-estree/src/node-maps.ts | 27 ++++ packages/typescript-estree/src/node-utils.ts | 55 -------- .../typescript-estree/src/parser-options.ts | 43 ------- .../src/semantic-or-syntactic-errors.ts | 116 +---------------- .../src/use-at-your-own-risk.ts | 5 - packages/utils/package.json | 1 + .../src/eslint-utils/getParserServices.ts | 2 +- packages/utils/src/ts-estree.ts | 2 +- packages/utils/tsconfig.build.json | 3 + packages/utils/tsconfig.json | 3 + tsconfig.json | 1 + yarn.lock | 21 +++- 67 files changed, 653 insertions(+), 344 deletions(-) create mode 100644 packages/parser-services/LICENSE create mode 100644 packages/parser-services/README.md create mode 100644 packages/parser-services/package.json create mode 100644 packages/parser-services/project.json rename packages/{typescript-estree => parser-services}/src/clear-caches.ts (91%) rename packages/{typescript-estree => parser-services}/src/create-program/WatchCompilerHostOfConfigFile.ts (100%) rename packages/{typescript-estree => parser-services}/src/create-program/createIsolatedProgram.ts (96%) rename packages/{typescript-estree => parser-services}/src/create-program/createProjectProgram.ts (89%) rename packages/{typescript-estree => parser-services}/src/create-program/createProjectProgramError.ts (98%) rename packages/{typescript-estree => parser-services}/src/create-program/createProjectService.ts (98%) rename packages/{typescript-estree => parser-services}/src/create-program/createSourceFile.ts (95%) rename packages/{typescript-estree => parser-services}/src/create-program/describeFilePath.ts (100%) rename packages/{typescript-estree => parser-services}/src/create-program/getParsedConfigFile.ts (100%) rename packages/{typescript-estree => parser-services}/src/create-program/getScriptKind.ts (100%) rename packages/{typescript-estree => parser-services}/src/create-program/getWatchProgramsForProjects.ts (99%) rename packages/{typescript-estree => parser-services}/src/create-program/shared.ts (98%) rename packages/{typescript-estree => parser-services}/src/create-program/useProvidedPrograms.ts (97%) create mode 100644 packages/parser-services/src/create-program/utils.ts rename packages/{typescript-estree => parser-services}/src/create-program/validateDefaultProjectForFilesGlob.ts (100%) rename packages/{typescript-estree => parser-services}/src/createParserServices.ts (91%) create mode 100644 packages/parser-services/src/index.ts rename packages/{typescript-estree => parser-services}/src/parseSettings/ExpiringCache.ts (100%) rename packages/{typescript-estree => parser-services}/src/parseSettings/createParseSettings.ts (95%) rename packages/{typescript-estree => parser-services}/src/parseSettings/getProjectConfigFiles.ts (96%) rename packages/{typescript-estree => parser-services}/src/parseSettings/index.ts (93%) rename packages/{typescript-estree => parser-services}/src/parseSettings/inferSingleRun.ts (97%) rename packages/{typescript-estree => parser-services}/src/parseSettings/resolveProjectList.ts (93%) rename packages/{typescript-estree => parser-services}/src/parseSettings/warnAboutTSVersion.ts (92%) rename packages/{typescript-estree => parser-services}/src/parser.ts (94%) create mode 100644 packages/parser-services/src/semantic-or-syntactic-errors.ts rename packages/{typescript-estree => parser-services}/src/source-files.ts (100%) create mode 100644 packages/parser-services/src/types.ts create mode 100644 packages/parser-services/src/use-at-your-own-risk.ts rename packages/{typescript-estree => parser-services}/src/useProgramFromProjectService.ts (100%) create mode 100644 packages/parser-services/src/version.ts rename packages/{typescript-estree => parser-services}/src/withoutProjectParserOptions.ts (100%) create mode 100644 packages/parser-services/tsconfig.build.json create mode 100644 packages/parser-services/tsconfig.json create mode 100644 packages/parser-services/tsconfig.spec.json create mode 100644 packages/parser-services/typings/typescript.d.ts create mode 100644 packages/parser-services/vitest.config.mts create mode 100644 packages/typescript-estree/src/errors.ts create mode 100644 packages/typescript-estree/src/node-maps.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 896fbaebbb3a..f48612982bca 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,6 @@ { + "eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }], + // This matches the value configured on the autoformatter "editor.rulers": [80], diff --git a/packages/parser-services/LICENSE b/packages/parser-services/LICENSE new file mode 100644 index 000000000000..310a18f8a6cb --- /dev/null +++ b/packages/parser-services/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 typescript-eslint and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/parser-services/README.md b/packages/parser-services/README.md new file mode 100644 index 000000000000..e4797e146dac --- /dev/null +++ b/packages/parser-services/README.md @@ -0,0 +1,3 @@ +# `@typescript-eslint/parser-services` + +TODO diff --git a/packages/parser-services/package.json b/packages/parser-services/package.json new file mode 100644 index 000000000000..3c0a42e07fe5 --- /dev/null +++ b/packages/parser-services/package.json @@ -0,0 +1,65 @@ +{ + "name": "@typescript-eslint/parser-services", + "version": "8.32.0", + "description": "TODO", + "files": [ + "dist", + "!*.tsbuildinfo", + "package.json", + "README.md", + "LICENSE" + ], + "type": "commonjs", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "types": "./dist/index.d.ts", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/typescript-eslint/typescript-eslint.git", + "directory": "packages/parser-services" + }, + "bugs": { + "url": "https://github.com/typescript-eslint/typescript-eslint/issues" + }, + "homepage": "https://typescript-eslint.io", + "license": "MIT", + "keywords": [ + "eslint", + "typescript", + "estree" + ], + "scripts": { + "build": "tsc -b tsconfig.build.json", + "clean": "tsc -b tsconfig.build.json --clean", + "postclean": "rimraf dist/ coverage/", + "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", + "lint": "npx nx lint", + "test": "vitest --run --config=$INIT_CWD/vitest.config.mts", + "check-types": "npx nx typecheck" + }, + "dependencies": { + "@typescript-eslint/typescript-estree": "^8.32.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3" + }, + "devDependencies": { + "@vitest/coverage-v8": "^3.1.2", + "prettier": "^3.2.5", + "rimraf": "*", + "typescript": "*", + "vitest": "^3.1.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } +} diff --git a/packages/parser-services/project.json b/packages/parser-services/project.json new file mode 100644 index 000000000000..efa611dad79d --- /dev/null +++ b/packages/parser-services/project.json @@ -0,0 +1,16 @@ +{ + "name": "parser-services", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "library", + "root": "packages/parser-services", + "sourceRoot": "packages/parser-services/src", + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/vite:test" + } + } +} diff --git a/packages/typescript-estree/src/clear-caches.ts b/packages/parser-services/src/clear-caches.ts similarity index 91% rename from packages/typescript-estree/src/clear-caches.ts rename to packages/parser-services/src/clear-caches.ts index 5e9867d3beab..81a69c559db4 100644 --- a/packages/typescript-estree/src/clear-caches.ts +++ b/packages/parser-services/src/clear-caches.ts @@ -24,6 +24,3 @@ export function clearCaches(): void { clearTSServerProjectService(); clearGlobCache(); } - -// TODO - delete this in next major -export const clearProgramCache = clearCaches; diff --git a/packages/typescript-estree/src/create-program/WatchCompilerHostOfConfigFile.ts b/packages/parser-services/src/create-program/WatchCompilerHostOfConfigFile.ts similarity index 100% rename from packages/typescript-estree/src/create-program/WatchCompilerHostOfConfigFile.ts rename to packages/parser-services/src/create-program/WatchCompilerHostOfConfigFile.ts diff --git a/packages/typescript-estree/src/create-program/createIsolatedProgram.ts b/packages/parser-services/src/create-program/createIsolatedProgram.ts similarity index 96% rename from packages/typescript-estree/src/create-program/createIsolatedProgram.ts rename to packages/parser-services/src/create-program/createIsolatedProgram.ts index e952931155aa..83fa93ec57dc 100644 --- a/packages/typescript-estree/src/create-program/createIsolatedProgram.ts +++ b/packages/parser-services/src/create-program/createIsolatedProgram.ts @@ -8,7 +8,7 @@ import { getScriptKind } from './getScriptKind'; import { createDefaultCompilerOptionsFromExtra } from './shared'; const log = debug( - 'typescript-eslint:typescript-estree:create-program:createIsolatedProgram', + 'typescript-eslint:parser-services:create-program:createIsolatedProgram', ); /** diff --git a/packages/typescript-estree/src/create-program/createProjectProgram.ts b/packages/parser-services/src/create-program/createProjectProgram.ts similarity index 89% rename from packages/typescript-estree/src/create-program/createProjectProgram.ts rename to packages/parser-services/src/create-program/createProjectProgram.ts index 00c8ae67c9bc..b30e38991d09 100644 --- a/packages/typescript-estree/src/create-program/createProjectProgram.ts +++ b/packages/parser-services/src/create-program/createProjectProgram.ts @@ -2,12 +2,12 @@ import type * as ts from 'typescript'; import debug from 'debug'; -import type { ParseSettings } from '../parseSettings'; import type { ASTAndDefiniteProgram } from './shared'; -import { firstDefined } from '../node-utils'; import { createProjectProgramError } from './createProjectProgramError'; import { getAstFromProgram } from './shared'; +import { ParseSettings } from '../parseSettings'; +import { firstDefined } from './utils'; const log = debug( 'typescript-eslint:typescript-estree:create-program:createProjectProgram', @@ -23,6 +23,7 @@ export function createProjectProgram( ): ASTAndDefiniteProgram { log('Creating project program for: %s', parseSettings.filePath); + // TODO: switch to .find()? const astAndProgram = firstDefined(programsForProjects, currentProgram => getAstFromProgram(currentProgram, parseSettings.filePath), ); diff --git a/packages/typescript-estree/src/create-program/createProjectProgramError.ts b/packages/parser-services/src/create-program/createProjectProgramError.ts similarity index 98% rename from packages/typescript-estree/src/create-program/createProjectProgramError.ts rename to packages/parser-services/src/create-program/createProjectProgramError.ts index f1474d344bf6..124035febc49 100644 --- a/packages/typescript-estree/src/create-program/createProjectProgramError.ts +++ b/packages/parser-services/src/create-program/createProjectProgramError.ts @@ -2,10 +2,9 @@ import type * as ts from 'typescript'; import path from 'node:path'; -import type { ParseSettings } from '../parseSettings'; - import { describeFilePath } from './describeFilePath'; import { DEFAULT_EXTRA_FILE_EXTENSIONS } from './shared'; +import { ParseSettings } from '../parseSettings'; export function createProjectProgramError( parseSettings: ParseSettings, diff --git a/packages/typescript-estree/src/create-program/createProjectService.ts b/packages/parser-services/src/create-program/createProjectService.ts similarity index 98% rename from packages/typescript-estree/src/create-program/createProjectService.ts rename to packages/parser-services/src/create-program/createProjectService.ts index 26b2c5421612..00f6db76e7f1 100644 --- a/packages/typescript-estree/src/create-program/createProjectService.ts +++ b/packages/parser-services/src/create-program/createProjectService.ts @@ -3,10 +3,9 @@ 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'; +import { ProjectServiceOptions } from '@typescript-eslint/types'; const DEFAULT_PROJECT_MATCHED_FILES_THRESHOLD = 8; diff --git a/packages/typescript-estree/src/create-program/createSourceFile.ts b/packages/parser-services/src/create-program/createSourceFile.ts similarity index 95% rename from packages/typescript-estree/src/create-program/createSourceFile.ts rename to packages/parser-services/src/create-program/createSourceFile.ts index bfe947fd1ef6..0f30ace060bf 100644 --- a/packages/typescript-estree/src/create-program/createSourceFile.ts +++ b/packages/parser-services/src/create-program/createSourceFile.ts @@ -1,11 +1,11 @@ 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 { ParseSettings } from '../parseSettings'; +import { isSourceFile } from '../source-files'; const log = debug( 'typescript-eslint:typescript-estree:create-program:createSourceFile', diff --git a/packages/typescript-estree/src/create-program/describeFilePath.ts b/packages/parser-services/src/create-program/describeFilePath.ts similarity index 100% rename from packages/typescript-estree/src/create-program/describeFilePath.ts rename to packages/parser-services/src/create-program/describeFilePath.ts diff --git a/packages/typescript-estree/src/create-program/getParsedConfigFile.ts b/packages/parser-services/src/create-program/getParsedConfigFile.ts similarity index 100% rename from packages/typescript-estree/src/create-program/getParsedConfigFile.ts rename to packages/parser-services/src/create-program/getParsedConfigFile.ts diff --git a/packages/typescript-estree/src/create-program/getScriptKind.ts b/packages/parser-services/src/create-program/getScriptKind.ts similarity index 100% rename from packages/typescript-estree/src/create-program/getScriptKind.ts rename to packages/parser-services/src/create-program/getScriptKind.ts diff --git a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts b/packages/parser-services/src/create-program/getWatchProgramsForProjects.ts similarity index 99% rename from packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts rename to packages/parser-services/src/create-program/getWatchProgramsForProjects.ts index b745af116bb4..4d13c9f9828b 100644 --- a/packages/typescript-estree/src/create-program/getWatchProgramsForProjects.ts +++ b/packages/parser-services/src/create-program/getWatchProgramsForProjects.ts @@ -2,7 +2,6 @@ import debug from 'debug'; import fs from 'node:fs'; import * as ts from 'typescript'; -import type { ParseSettings } from '../parseSettings'; import type { CanonicalPath } from './shared'; import type { WatchCompilerHostOfConfigFile } from './WatchCompilerHostOfConfigFile'; @@ -13,6 +12,7 @@ import { createHash, getCanonicalFileName, } from './shared'; +import { ParseSettings } from '../parseSettings'; const log = debug( 'typescript-eslint:typescript-estree:create-program:getWatchProgramsForProjects', diff --git a/packages/typescript-estree/src/create-program/shared.ts b/packages/parser-services/src/create-program/shared.ts similarity index 98% rename from packages/typescript-estree/src/create-program/shared.ts rename to packages/parser-services/src/create-program/shared.ts index 07a67cbb9b38..0f1e63f4130f 100644 --- a/packages/typescript-estree/src/create-program/shared.ts +++ b/packages/parser-services/src/create-program/shared.ts @@ -2,8 +2,7 @@ import type { Program } from 'typescript'; import path from 'node:path'; import * as ts from 'typescript'; - -import type { ParseSettings } from '../parseSettings'; +import { ParseSettings } from '../parseSettings'; export interface ASTAndNoProgram { ast: ts.SourceFile; diff --git a/packages/typescript-estree/src/create-program/useProvidedPrograms.ts b/packages/parser-services/src/create-program/useProvidedPrograms.ts similarity index 97% rename from packages/typescript-estree/src/create-program/useProvidedPrograms.ts rename to packages/parser-services/src/create-program/useProvidedPrograms.ts index f84767ea19c7..6b3ff2a11848 100644 --- a/packages/typescript-estree/src/create-program/useProvidedPrograms.ts +++ b/packages/parser-services/src/create-program/useProvidedPrograms.ts @@ -2,11 +2,11 @@ import debug from 'debug'; import * as path from 'node:path'; import * as ts from 'typescript'; -import type { ParseSettings } from '../parseSettings'; import type { ASTAndDefiniteProgram } from './shared'; import { getParsedConfigFile } from './getParsedConfigFile'; import { getAstFromProgram } from './shared'; +import { ParseSettings } from '../parseSettings'; const log = debug( 'typescript-eslint:typescript-estree:create-program:useProvidedPrograms', diff --git a/packages/parser-services/src/create-program/utils.ts b/packages/parser-services/src/create-program/utils.ts new file mode 100644 index 000000000000..87333d022f4f --- /dev/null +++ b/packages/parser-services/src/create-program/utils.ts @@ -0,0 +1,22 @@ +/** + * Like `forEach`, but suitable for use with numbers and strings (which may be falsy). + * @todo Switch to .find()? + */ +export function firstDefined( + array: readonly T[] | undefined, + callback: (element: T, index: number) => U | undefined, +): U | undefined { + // eslint-disable-next-line @typescript-eslint/internal/eqeq-nullish + if (array === undefined) { + return undefined; + } + + for (let i = 0; i < array.length; i++) { + const result = callback(array[i], i); + // eslint-disable-next-line @typescript-eslint/internal/eqeq-nullish + if (result !== undefined) { + return result; + } + } + return undefined; +} diff --git a/packages/typescript-estree/src/create-program/validateDefaultProjectForFilesGlob.ts b/packages/parser-services/src/create-program/validateDefaultProjectForFilesGlob.ts similarity index 100% rename from packages/typescript-estree/src/create-program/validateDefaultProjectForFilesGlob.ts rename to packages/parser-services/src/create-program/validateDefaultProjectForFilesGlob.ts diff --git a/packages/typescript-estree/src/createParserServices.ts b/packages/parser-services/src/createParserServices.ts similarity index 91% rename from packages/typescript-estree/src/createParserServices.ts rename to packages/parser-services/src/createParserServices.ts index ee6f18915d9c..0974be6b1ed7 100644 --- a/packages/typescript-estree/src/createParserServices.ts +++ b/packages/parser-services/src/createParserServices.ts @@ -1,7 +1,6 @@ +import { ASTMaps } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; - -import type { ASTMaps } from './convert'; -import type { ParserServices } from './parser-options'; +import { ParserServices } from './types'; export function createParserServices( astMaps: ASTMaps, diff --git a/packages/parser-services/src/index.ts b/packages/parser-services/src/index.ts new file mode 100644 index 000000000000..8b2d2b7f2a37 --- /dev/null +++ b/packages/parser-services/src/index.ts @@ -0,0 +1,6 @@ +export * from './clear-caches'; +export { getCanonicalFileName } from './create-program/shared'; +export type * from './types'; +export { createProgramFromConfigFile as createProgram } from './create-program/useProvidedPrograms'; +export * from './withoutProjectParserOptions'; +export * from './parser'; diff --git a/packages/typescript-estree/src/parseSettings/ExpiringCache.ts b/packages/parser-services/src/parseSettings/ExpiringCache.ts similarity index 100% rename from packages/typescript-estree/src/parseSettings/ExpiringCache.ts rename to packages/parser-services/src/parseSettings/ExpiringCache.ts diff --git a/packages/typescript-estree/src/parseSettings/createParseSettings.ts b/packages/parser-services/src/parseSettings/createParseSettings.ts similarity index 95% rename from packages/typescript-estree/src/parseSettings/createParseSettings.ts rename to packages/parser-services/src/parseSettings/createParseSettings.ts index 6a1c42008c6b..29592ceffbd2 100644 --- a/packages/typescript-estree/src/parseSettings/createParseSettings.ts +++ b/packages/parser-services/src/parseSettings/createParseSettings.ts @@ -2,12 +2,11 @@ import debug from 'debug'; import path from 'node:path'; import * as ts from 'typescript'; -import type { ProjectServiceSettings } from '../create-program/createProjectService'; -import type { TSESTreeOptions } from '../parser-options'; +import type { ProjectServiceSettings } from '../../../parser-services/src/create-program/createProjectService'; import type { MutableParseSettings } from './index'; -import { createProjectService } from '../create-program/createProjectService'; -import { ensureAbsolutePath } from '../create-program/shared'; +import { createProjectService } from '../../../parser-services/src/create-program/createProjectService'; +import { ensureAbsolutePath } from '../../../parser-services/src/create-program/shared'; import { isSourceFile } from '../source-files'; import { DEFAULT_TSCONFIG_CACHE_DURATION_SECONDS, @@ -17,6 +16,7 @@ import { getProjectConfigFiles } from './getProjectConfigFiles'; import { inferSingleRun } from './inferSingleRun'; import { resolveProjectList } from './resolveProjectList'; import { warnAboutTSVersion } from './warnAboutTSVersion'; +import { TSESTreeOptions } from '@typescript-eslint/typescript-estree'; const log = debug( 'typescript-eslint:typescript-estree:parseSettings:createParseSettings', diff --git a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts b/packages/parser-services/src/parseSettings/getProjectConfigFiles.ts similarity index 96% rename from packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts rename to packages/parser-services/src/parseSettings/getProjectConfigFiles.ts index f7f3dc8851b8..f6bfd0cb325d 100644 --- a/packages/typescript-estree/src/parseSettings/getProjectConfigFiles.ts +++ b/packages/parser-services/src/parseSettings/getProjectConfigFiles.ts @@ -2,8 +2,8 @@ import debug from 'debug'; import * as fs from 'node:fs'; import * as path from 'node:path'; -import type { TSESTreeOptions } from '../parser-options'; import type { ParseSettings } from './index'; +import { TSESTreeOptions } from '@typescript-eslint/typescript-estree'; const log = debug( 'typescript-eslint:typescript-estree:parseSettings:getProjectConfigFiles', diff --git a/packages/typescript-estree/src/parseSettings/index.ts b/packages/parser-services/src/parseSettings/index.ts similarity index 93% rename from packages/typescript-estree/src/parseSettings/index.ts rename to packages/parser-services/src/parseSettings/index.ts index 1ea208210e0a..5d188bc263e3 100644 --- a/packages/typescript-estree/src/parseSettings/index.ts +++ b/packages/parser-services/src/parseSettings/index.ts @@ -1,8 +1,8 @@ +import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; -import type { ProjectServiceSettings } from '../create-program/createProjectService'; -import type { CanonicalPath } from '../create-program/shared'; -import type { TSESTree } from '../ts-estree'; +import type { ProjectServiceSettings } from '../../../parser-services/src/create-program/createProjectService'; +import type { CanonicalPath } from '../../../parser-services/src/create-program/shared'; import type { CacheLike } from './ExpiringCache'; type DebugModule = 'eslint' | 'typescript' | 'typescript-eslint'; diff --git a/packages/typescript-estree/src/parseSettings/inferSingleRun.ts b/packages/parser-services/src/parseSettings/inferSingleRun.ts similarity index 97% rename from packages/typescript-estree/src/parseSettings/inferSingleRun.ts rename to packages/parser-services/src/parseSettings/inferSingleRun.ts index 8007e6ccd66a..7fd8c81902e6 100644 --- a/packages/typescript-estree/src/parseSettings/inferSingleRun.ts +++ b/packages/parser-services/src/parseSettings/inferSingleRun.ts @@ -1,7 +1,6 @@ +import { TSESTreeOptions } from '@typescript-eslint/typescript-estree'; import path from 'node:path'; -import type { TSESTreeOptions } from '../parser-options'; - /** * ESLint (and therefore typescript-eslint) is used in both "single run"/one-time contexts, * such as an ESLint CLI invocation, and long-running sessions (such as continuous feedback diff --git a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts b/packages/parser-services/src/parseSettings/resolveProjectList.ts similarity index 93% rename from packages/typescript-estree/src/parseSettings/resolveProjectList.ts rename to packages/parser-services/src/parseSettings/resolveProjectList.ts index f29bf0026469..4404a1a4cdce 100644 --- a/packages/typescript-estree/src/parseSettings/resolveProjectList.ts +++ b/packages/parser-services/src/parseSettings/resolveProjectList.ts @@ -1,22 +1,23 @@ +import type { TSESTreeOptions } from '@typescript-eslint/typescript-estree'; + import debug from 'debug'; import { sync as globSync } from 'fast-glob'; import isGlob from 'is-glob'; -import type { CanonicalPath } from '../create-program/shared'; -import type { TSESTreeOptions } from '../parser-options'; +import type { CanonicalPath } from '../../../parser-services/src/create-program/shared'; import { createHash, ensureAbsolutePath, getCanonicalFileName, -} from '../create-program/shared'; +} from '../../../parser-services/src/create-program/shared'; import { DEFAULT_TSCONFIG_CACHE_DURATION_SECONDS, ExpiringCache, } from './ExpiringCache'; const log = debug( - 'typescript-eslint:typescript-estree:parseSettings:resolveProjectList', + 'typescript-eslint:parser-services:parseSettings:resolveProjectList', ); let RESOLUTION_CACHE: ExpiringCache< diff --git a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts b/packages/parser-services/src/parseSettings/warnAboutTSVersion.ts similarity index 92% rename from packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts rename to packages/parser-services/src/parseSettings/warnAboutTSVersion.ts index 8ac2801476bd..4dd06a275d46 100644 --- a/packages/typescript-estree/src/parseSettings/warnAboutTSVersion.ts +++ b/packages/parser-services/src/parseSettings/warnAboutTSVersion.ts @@ -3,7 +3,7 @@ import * as ts from 'typescript'; import type { ParseSettings } from './index'; -import { version as TYPESCRIPT_ESTREE_VERSION } from '../version'; +import { version as PARSER_SERVICES_VERSION } from '../version'; /** * This needs to be kept in sync with package.json in the typescript-eslint monorepo @@ -43,7 +43,7 @@ export function warnAboutTSVersion( '\n', 'WARNING: You are currently running a version of TypeScript which is not officially supported by @typescript-eslint/typescript-estree.', '\n', - `* @typescript-eslint/typescript-estree version: ${TYPESCRIPT_ESTREE_VERSION}`, + `* @typescript-eslint/parser-services version: ${PARSER_SERVICES_VERSION}`, `* Supported TypeScript versions: ${SUPPORTED_TYPESCRIPT_VERSIONS}`, `* Your TypeScript version: ${ACTIVE_TYPESCRIPT_VERSION}`, '\n', diff --git a/packages/typescript-estree/src/parser.ts b/packages/parser-services/src/parser.ts similarity index 94% rename from packages/typescript-estree/src/parser.ts rename to packages/parser-services/src/parser.ts index 1c0c6e42aa83..626921fdfb91 100644 --- a/packages/typescript-estree/src/parser.ts +++ b/packages/parser-services/src/parser.ts @@ -1,18 +1,14 @@ import type * as ts from 'typescript'; +import { + astConverter, + convertTSErrorToTSESTreeError, +} from '@typescript-eslint/typescript-estree'; 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'; import { createProjectProgram } from './create-program/createProjectProgram'; import { @@ -26,10 +22,16 @@ import { } from './create-program/useProvidedPrograms'; import { createParserServices } from './createParserServices'; import { createParseSettings } from './parseSettings/createParseSettings'; -import { getFirstSemanticOrSyntacticError } from './semantic-or-syntactic-errors'; import { useProgramFromProjectService } from './useProgramFromProjectService'; +import type { + ParserServicesNodeMaps, + TSESTree, + TSESTreeOptions, +} from '@typescript-eslint/typescript-estree'; +import { ParserServices } from './types'; +import { getFirstSemanticOrSyntacticError } from './semantic-or-syntactic-errors'; -const log = debug('typescript-eslint:typescript-estree:parser'); +const log = debug('typescript-eslint:parser-services:parser'); /** * Cache existing programs for the single run use-case. @@ -101,6 +103,7 @@ export interface ParseAndGenerateServicesResult { ast: AST; services: ParserServices; } + interface ParseWithNodeMapsResult extends ParserServicesNodeMaps { ast: AST; @@ -148,7 +151,8 @@ function parseWithNodeMapsInternal( ); return { - ast: estree as AST, + // @ts-expect-error -- TODO: I don't know why this is no longer working... + ast: estree, esTreeNodeToTSNodeMap: astMaps.esTreeNodeToTSNodeMap, tsNodeToESTreeNodeMap: astMaps.tsNodeToESTreeNodeMap, }; @@ -265,7 +269,7 @@ export function parseAndGenerateServices< if (program && parseSettings.errorOnTypeScriptSyntacticAndSemanticIssues) { const error = getFirstSemanticOrSyntacticError(program, ast); if (error) { - throw convertError(error); + throw convertTSErrorToTSESTreeError(error); } } @@ -273,7 +277,8 @@ export function parseAndGenerateServices< * Return the converted AST and additional parser services */ return { - ast: estree as AST, + // @ts-expect-error -- TODO: I don't know why this is no longer working... + ast: estree, services: createParserServices(astMaps, program), }; } diff --git a/packages/parser-services/src/semantic-or-syntactic-errors.ts b/packages/parser-services/src/semantic-or-syntactic-errors.ts new file mode 100644 index 000000000000..a88a3615d9f8 --- /dev/null +++ b/packages/parser-services/src/semantic-or-syntactic-errors.ts @@ -0,0 +1,119 @@ +import type { + Diagnostic, + DiagnosticWithLocation, + Program, + SourceFile, +} from 'typescript'; + +import { flattenDiagnosticMessageText, sys } from 'typescript'; + +export interface SemanticOrSyntacticError extends Diagnostic { + message: string; +} + +/** + * By default, diagnostics from the TypeScript compiler contain all errors - regardless of whether + * they are related to generic ECMAScript standards, or TypeScript-specific constructs. + * + * Therefore, we filter out all diagnostics, except for the ones we explicitly want to consider when + * the user opts in to throwing errors on semantic issues. + */ +export function getFirstSemanticOrSyntacticError( + program: Program, + ast: SourceFile, +): SemanticOrSyntacticError | undefined { + try { + const supportedSyntacticDiagnostics = allowlistSupportedDiagnostics( + program.getSyntacticDiagnostics(ast), + ); + if (supportedSyntacticDiagnostics.length > 0) { + return convertDiagnosticToSemanticOrSyntacticError( + supportedSyntacticDiagnostics[0], + ); + } + const supportedSemanticDiagnostics = allowlistSupportedDiagnostics( + program.getSemanticDiagnostics(ast), + ); + if (supportedSemanticDiagnostics.length > 0) { + return convertDiagnosticToSemanticOrSyntacticError( + supportedSemanticDiagnostics[0], + ); + } + return undefined; + } catch (e) { + /** + * TypeScript compiler has certain Debug.fail() statements in, which will cause the diagnostics + * retrieval above to throw. + * + * E.g. from ast-alignment-tests + * "Debug Failure. Shouldn't ever directly check a JsxOpeningElement" + * + * For our current use-cases this is undesired behavior, so we just suppress it + * and log a warning. + */ + /* istanbul ignore next */ + console.warn(`Warning From TSC: "${(e as Error).message}`); // eslint-disable-line no-console + /* istanbul ignore next */ + return undefined; + } +} + +function allowlistSupportedDiagnostics( + diagnostics: readonly (Diagnostic | DiagnosticWithLocation)[], +): readonly (Diagnostic | DiagnosticWithLocation)[] { + return diagnostics.filter(diagnostic => { + switch (diagnostic.code) { + case 1013: // "A rest parameter or binding pattern may not have a trailing comma." + case 1014: // "A rest parameter must be last in a parameter list." + case 1044: // "'{0}' modifier cannot appear on a module or namespace element." + case 1045: // "A '{0}' modifier cannot be used with an interface declaration." + case 1048: // "A rest parameter cannot have an initializer." + case 1049: // "A 'set' accessor must have exactly one parameter." + case 1070: // "'{0}' modifier cannot appear on a type member." + case 1071: // "'{0}' modifier cannot appear on an index signature." + case 1085: // "Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '{0}'." + case 1090: // "'{0}' modifier cannot appear on a parameter." + case 1096: // "An index signature must have exactly one parameter." + case 1097: // "'{0}' list cannot be empty." + case 1098: // "Type parameter list cannot be empty." + case 1099: // "Type argument list cannot be empty." + case 1117: // "An object literal cannot have multiple properties with the same name in strict mode." + case 1121: // "Octal literals are not allowed in strict mode." + case 1123: // "Variable declaration list cannot be empty." + case 1141: // "String literal expected." + case 1162: // "An object member cannot be declared optional." + case 1164: // "Computed property names are not allowed in enums." + case 1172: // "'extends' clause already seen." + case 1173: // "'extends' clause must precede 'implements' clause." + case 1175: // "'implements' clause already seen." + case 1176: // "Interface declaration cannot have 'implements' clause." + case 1190: // "The variable declaration of a 'for...of' statement cannot have an initializer." + case 1196: // "Catch clause variable type annotation must be 'any' or 'unknown' if specified." + case 1200: // "Line terminator not permitted before arrow." + case 1206: // "Decorators are not valid here." + case 1211: // "A class declaration without the 'default' modifier must have a name." + case 1242: // "'abstract' modifier can only appear on a class, method, or property declaration." + case 1246: // "An interface property cannot have an initializer." + case 1255: // "A definite assignment assertion '!' is not permitted in this context." + case 1308: // "'await' expression is only allowed within an async function." + case 2364: // "The left-hand side of an assignment expression must be a variable or a property access." + case 2369: // "A parameter property is only allowed in a constructor implementation." + case 2452: // "An enum member cannot have a numeric name." + case 2462: // "A rest element must be last in a destructuring pattern." + case 8017: // "Octal literal types must use ES2015 syntax. Use the syntax '{0}'." + case 17012: // "'{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{2}'?" + case 17013: // "Meta-property '{0}' is only allowed in the body of a function declaration, function expression, or constructor." + return true; + } + return false; + }); +} + +function convertDiagnosticToSemanticOrSyntacticError( + diagnostic: Diagnostic, +): SemanticOrSyntacticError { + return { + ...diagnostic, + message: flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine), + }; +} diff --git a/packages/typescript-estree/src/source-files.ts b/packages/parser-services/src/source-files.ts similarity index 100% rename from packages/typescript-estree/src/source-files.ts rename to packages/parser-services/src/source-files.ts diff --git a/packages/parser-services/src/types.ts b/packages/parser-services/src/types.ts new file mode 100644 index 000000000000..7c31e060fb10 --- /dev/null +++ b/packages/parser-services/src/types.ts @@ -0,0 +1,29 @@ +import { + ParserServicesNodeMaps, + TSESTree, +} from '@typescript-eslint/typescript-estree'; +import ts from 'typescript'; + +export interface ParserServicesBase { + emitDecoratorMetadata: boolean | undefined; + experimentalDecorators: boolean | undefined; + isolatedDeclarations: boolean | undefined; +} + +export interface ParserServicesWithTypeInformation + extends ParserServicesNodeMaps, + ParserServicesBase { + getSymbolAtLocation: (node: TSESTree.Node) => ts.Symbol | undefined; + getTypeAtLocation: (node: TSESTree.Node) => ts.Type; + program: ts.Program; +} + +export interface ParserServicesWithoutTypeInformation + extends ParserServicesNodeMaps, + ParserServicesBase { + program: null; +} + +export type ParserServices = + | ParserServicesWithoutTypeInformation + | ParserServicesWithTypeInformation; diff --git a/packages/parser-services/src/use-at-your-own-risk.ts b/packages/parser-services/src/use-at-your-own-risk.ts new file mode 100644 index 000000000000..a144380b68f3 --- /dev/null +++ b/packages/parser-services/src/use-at-your-own-risk.ts @@ -0,0 +1,6 @@ +// required by website +export * from './create-program/getScriptKind'; +export type { ParseSettings } from './parseSettings'; + +// required by packages/type-utils +export { getCanonicalFileName } from './create-program/shared'; diff --git a/packages/typescript-estree/src/useProgramFromProjectService.ts b/packages/parser-services/src/useProgramFromProjectService.ts similarity index 100% rename from packages/typescript-estree/src/useProgramFromProjectService.ts rename to packages/parser-services/src/useProgramFromProjectService.ts diff --git a/packages/parser-services/src/version.ts b/packages/parser-services/src/version.ts new file mode 100644 index 000000000000..1a7b810e764a --- /dev/null +++ b/packages/parser-services/src/version.ts @@ -0,0 +1,3 @@ +// note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder +// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access +export const version: string = require('../package.json').version; diff --git a/packages/typescript-estree/src/withoutProjectParserOptions.ts b/packages/parser-services/src/withoutProjectParserOptions.ts similarity index 100% rename from packages/typescript-estree/src/withoutProjectParserOptions.ts rename to packages/parser-services/src/withoutProjectParserOptions.ts diff --git a/packages/parser-services/tsconfig.build.json b/packages/parser-services/tsconfig.build.json new file mode 100644 index 000000000000..241b39d618e6 --- /dev/null +++ b/packages/parser-services/tsconfig.build.json @@ -0,0 +1,17 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo", + "emitDeclarationOnly": false, + "types": ["node"] + }, + "include": ["src/**/*.ts", "typings"], + "references": [ + { + "path": "../typescript-estree/tsconfig.build.json" + } + ] +} diff --git a/packages/parser-services/tsconfig.json b/packages/parser-services/tsconfig.json new file mode 100644 index 000000000000..4733311e9be9 --- /dev/null +++ b/packages/parser-services/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "../typescript-estree" + }, + { + "path": "./tsconfig.build.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/parser-services/tsconfig.spec.json b/packages/parser-services/tsconfig.spec.json new file mode 100644 index 000000000000..872d3c655b27 --- /dev/null +++ b/packages/parser-services/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc/packages/types/vitest", + "resolveJsonModule": true, + "types": ["vitest/globals", "vitest/importMeta"] + }, + "include": ["vitest.config.mts", "package.json", "tests"], + "exclude": ["**/fixtures/**"], + "references": [ + { + "path": "./tsconfig.build.json" + }, + { + "path": "../../tsconfig.spec.json" + } + ] +} diff --git a/packages/parser-services/typings/typescript.d.ts b/packages/parser-services/typings/typescript.d.ts new file mode 100644 index 000000000000..7a665b57abbe --- /dev/null +++ b/packages/parser-services/typings/typescript.d.ts @@ -0,0 +1,57 @@ +import 'typescript'; + +// these additions are marked as internal to typescript +declare module 'typescript' { + interface SourceFile { + externalModuleIndicator?: Node | true; + parseDiagnostics: DiagnosticWithLocation[]; + } + + interface JSDocContainer { + jsDoc?: JSDoc[]; + } + + // add back the deprecated properties that were removed in newer TS versions + // make sure these properties are marked as @ deprecated so they're flagged + // by the `@typescript-eslint/no-deprecated` lint rule + + interface PropertySignature { + /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ + readonly initializer?: Expression | undefined; + } + interface PropertyAssignment { + /** @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; + } + interface FunctionTypeNode { + /** @deprecated removed in 5.0 but we want to keep it for backwards compatibility checks! */ + readonly modifiers?: NodeArray | undefined; + } + + /** + * @deprecated don't use this directly as it does not exist pre-4.8; instead use getDecorators from `src/getModifiers.ts`. + */ + function getDecorators(node: HasDecorators): readonly Decorator[] | undefined; + /** + * @deprecated don't use this directly as it does not exist pre-4.8; instead use getModifiers from `src/getModifiers.ts`. + */ + function getModifiers(node: HasModifiers): readonly Modifier[] | undefined; + /** + * @deprecated don't use this directly as it does not exist pre-4.8; instead use getModifiers from `src/getModifiers.ts`. + */ + function canHaveModifiers(node: Node): node is HasModifiers; + /** + * @deprecated don't use this directly as it does not exist pre-4.8; instead use getDecorators from `src/getModifiers.ts`. + */ + function canHaveDecorators(node: Node): node is HasDecorators; +} diff --git a/packages/parser-services/vitest.config.mts b/packages/parser-services/vitest.config.mts new file mode 100644 index 000000000000..136e4f77b392 --- /dev/null +++ b/packages/parser-services/vitest.config.mts @@ -0,0 +1,22 @@ +import * as path from 'node:path'; +import { defineConfig, mergeConfig } from 'vitest/config'; + +import { vitestBaseConfig } from '../../vitest.config.base.mjs'; +import packageJson from './package.json' with { type: 'json' }; + +const vitestConfig = mergeConfig( + vitestBaseConfig, + + defineConfig({ + root: import.meta.dirname, + + test: { + dir: path.join(import.meta.dirname, 'tests'), + name: packageJson.name.replace('@typescript-eslint/', ''), + passWithNoTests: true, + root: import.meta.dirname, + }, + }), +); + +export default vitestConfig; diff --git a/packages/parser/package.json b/packages/parser/package.json index 659172ce81e9..0afd53b02300 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -52,6 +52,7 @@ "typescript": ">=4.8.4 <5.9.0" }, "dependencies": { + "@typescript-eslint/parser-services": "8.32.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.0", diff --git a/packages/parser/src/index.ts b/packages/parser/src/index.ts index a1af2c02cd4b..db293b5b4762 100644 --- a/packages/parser/src/index.ts +++ b/packages/parser/src/index.ts @@ -1,12 +1,12 @@ export { parse, parseForESLint, type ParserOptions } from './parser'; export { - clearCaches, - createProgram, type ParserServices, type ParserServicesWithoutTypeInformation, type ParserServicesWithTypeInformation, + clearCaches, + createProgram, withoutProjectParserOptions, -} from '@typescript-eslint/typescript-estree'; +} from '@typescript-eslint/parser-services'; // note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index f4a50c81a505..85cea7348102 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -1,18 +1,18 @@ +import { + AST, + parseAndGenerateServices, + type ParserServices, +} from '@typescript-eslint/parser-services'; import type { AnalyzeOptions, ScopeManager, } from '@typescript-eslint/scope-manager'; import type { Lib, ParserOptions, TSESTree } from '@typescript-eslint/types'; -import type { - AST, - ParserServices, - TSESTreeOptions, -} from '@typescript-eslint/typescript-estree'; +import type { TSESTreeOptions } from '@typescript-eslint/typescript-estree'; import type { VisitorKeys } from '@typescript-eslint/visitor-keys'; import type * as ts from 'typescript'; import { analyze } from '@typescript-eslint/scope-manager'; -import { parseAndGenerateServices } from '@typescript-eslint/typescript-estree'; import { visitorKeys } from '@typescript-eslint/visitor-keys'; import debug from 'debug'; import { ScriptTarget } from 'typescript'; diff --git a/packages/parser/tsconfig.build.json b/packages/parser/tsconfig.build.json index ca2c74a7ac78..bee92c2f0195 100644 --- a/packages/parser/tsconfig.build.json +++ b/packages/parser/tsconfig.build.json @@ -2,6 +2,9 @@ "extends": "../../tsconfig.build.json", "compilerOptions": {}, "references": [ + { + "path": "../parser-services/tsconfig.build.json" + }, { "path": "../visitor-keys/tsconfig.build.json" }, diff --git a/packages/parser/tsconfig.json b/packages/parser/tsconfig.json index 8122a5aaab8a..fd04f00b8cc1 100644 --- a/packages/parser/tsconfig.json +++ b/packages/parser/tsconfig.json @@ -3,6 +3,9 @@ "files": [], "include": [], "references": [ + { + "path": "../parser-services" + }, { "path": "../visitor-keys" }, diff --git a/packages/type-utils/src/getConstrainedTypeAtLocation.ts b/packages/type-utils/src/getConstrainedTypeAtLocation.ts index d31df29ab5b1..f79c75633e4d 100644 --- a/packages/type-utils/src/getConstrainedTypeAtLocation.ts +++ b/packages/type-utils/src/getConstrainedTypeAtLocation.ts @@ -1,7 +1,5 @@ -import type { - ParserServicesWithTypeInformation, - TSESTree, -} from '@typescript-eslint/typescript-estree'; +import { ParserServicesWithTypeInformation } from '@typescript-eslint/utils'; +import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; /** diff --git a/packages/type-utils/src/getDeclaration.ts b/packages/type-utils/src/getDeclaration.ts index 9e8d8b770248..9c9cd40f057c 100644 --- a/packages/type-utils/src/getDeclaration.ts +++ b/packages/type-utils/src/getDeclaration.ts @@ -1,7 +1,5 @@ -import type { - ParserServicesWithTypeInformation, - TSESTree, -} from '@typescript-eslint/typescript-estree'; +import type { TSESTree } from '@typescript-eslint/typescript-estree'; +import { ParserServicesWithTypeInformation } from '@typescript-eslint/utils'; import type * as ts from 'typescript'; /** diff --git a/packages/type-utils/src/typeOrValueSpecifiers/typeDeclaredInFile.ts b/packages/type-utils/src/typeOrValueSpecifiers/typeDeclaredInFile.ts index 548767a5a703..1ea7580a5808 100644 --- a/packages/type-utils/src/typeOrValueSpecifiers/typeDeclaredInFile.ts +++ b/packages/type-utils/src/typeOrValueSpecifiers/typeDeclaredInFile.ts @@ -1,7 +1,7 @@ import type * as ts from 'typescript'; -import { getCanonicalFileName } from '@typescript-eslint/typescript-estree'; import path from 'node:path'; +import { getCanonicalFileName } from '@typescript-eslint/parser-services'; export function typeDeclaredInFile( relativePath: string | undefined, diff --git a/packages/typescript-estree/package.json b/packages/typescript-estree/package.json index 56f0f128a669..04792485d313 100644 --- a/packages/typescript-estree/package.json +++ b/packages/typescript-estree/package.json @@ -55,8 +55,6 @@ "@typescript-eslint/types": "8.32.0", "@typescript-eslint/visitor-keys": "8.32.0", "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", "minimatch": "^9.0.4", "semver": "^7.6.0", "ts-api-utils": "^2.1.0" diff --git a/packages/typescript-estree/src/ast-converter.ts b/packages/typescript-estree/src/ast-converter.ts index 65b993cbefa9..8250a4b6089d 100644 --- a/packages/typescript-estree/src/ast-converter.ts +++ b/packages/typescript-estree/src/ast-converter.ts @@ -1,17 +1,28 @@ 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 { Converter } from './convert'; import { convertComments } from './convert-comments'; import { convertTokens } from './node-utils'; import { simpleTraverse } from './simple-traverse'; +import { convertTSErrorToTSESTreeError } from './errors'; + +export interface AstConverterSettings { + allowInvalidAST?: boolean | undefined; + codeFullText: string; + comment?: boolean; + errorOnUnknownASTType?: boolean | undefined; + loc?: boolean; + range?: boolean; + suppressDeprecatedPropertyWarnings?: boolean | undefined; + tokens?: TSESTree.Token[] | null; +} export function astConverter( ast: SourceFile, - parseSettings: ParseSettings, + settings: AstConverterSettings, shouldPreserveNodeMaps: boolean, ): { astMaps: ASTMaps; estree: TSESTree.Program } { /** @@ -20,18 +31,18 @@ export function astConverter( */ const { parseDiagnostics } = ast; if (parseDiagnostics.length) { - throw convertError(parseDiagnostics[0]); + throw convertTSErrorToTSESTreeError(parseDiagnostics[0]); } /** * Recursively convert the TypeScript AST into an ESTree-compatible AST */ const instance = new Converter(ast, { - allowInvalidAST: parseSettings.allowInvalidAST, - errorOnUnknownASTType: parseSettings.errorOnUnknownASTType, + allowInvalidAST: settings.allowInvalidAST, + errorOnUnknownASTType: settings.errorOnUnknownASTType, shouldPreserveNodeMaps, suppressDeprecatedPropertyWarnings: - parseSettings.suppressDeprecatedPropertyWarnings, + settings.suppressDeprecatedPropertyWarnings, }); const estree = instance.convertProgram(); @@ -39,15 +50,15 @@ export function astConverter( /** * Optionally remove range and loc if specified */ - if (!parseSettings.range || !parseSettings.loc) { + if (!settings.range || !settings.loc) { simpleTraverse(estree, { enter: node => { - if (!parseSettings.range) { + if (!settings.range) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- TS 4.0 made this an error because the types aren't optional // @ts-expect-error delete node.range; } - if (!parseSettings.loc) { + if (!settings.loc) { // eslint-disable-next-line @typescript-eslint/ban-ts-comment -- TS 4.0 made this an error because the types aren't optional // @ts-expect-error delete node.loc; @@ -59,15 +70,15 @@ export function astConverter( /** * Optionally convert and include all tokens in the AST */ - if (parseSettings.tokens) { + if (settings.tokens) { estree.tokens = convertTokens(ast); } /** * Optionally convert and include all comments in the AST */ - if (parseSettings.comment) { - estree.comments = convertComments(ast, parseSettings.codeFullText); + if (settings.comment) { + estree.comments = convertComments(ast, settings.codeFullText); } const astMaps = instance.getASTMaps(); diff --git a/packages/typescript-estree/src/convert.ts b/packages/typescript-estree/src/convert.ts index 22c0257505a2..ffdf1d3af3d0 100644 --- a/packages/typescript-estree/src/convert.ts +++ b/packages/typescript-estree/src/convert.ts @@ -2,18 +2,12 @@ /* 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 type { TSError } from './node-utils'; -import type { - ParserWeakMap, - ParserWeakMapESTreeToTSNode, -} from './parser-options'; -import type { SemanticOrSyntacticError } from './semantic-or-syntactic-errors'; +import type { ParserWeakMap, ParserWeakMapESTreeToTSNode } from './node-maps'; import type { TSESTree, TSESTreeToTSNode, TSNode } from './ts-estree'; import { getDecorators, getModifiers } from './getModifiers'; import { canContainDirective, - createError, findNextToken, getBinaryExpressionType, getContainingFunction, @@ -40,6 +34,7 @@ import { unescapeStringLiteralText, } from './node-utils'; import { AST_NODE_TYPES } from './ts-estree'; +import { createTSESTreeError } from './errors'; const SyntaxKind = ts.SyntaxKind; @@ -50,21 +45,6 @@ export interface ConverterOptions { suppressDeprecatedPropertyWarnings?: boolean; } -/** - * Extends and formats a given error object - * @param error the error object - * @returns converted error object - */ -export function convertError( - error: SemanticOrSyntacticError | ts.DiagnosticWithLocation, -): TSError { - return createError( - ('message' in error && error.message) || (error.messageText as string), - error.file!, - error.start!, - ); -} - export interface ASTMaps { esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode; tsNodeToESTreeNodeMap: ParserWeakMap; @@ -392,7 +372,7 @@ export class Converter { end = node.getEnd(); } - throw createError(message, this.ast, start, end); + throw createTSESTreeError(message, this.ast, start, end); } #throwUnlessAllowInvalidAST( diff --git a/packages/typescript-estree/src/errors.ts b/packages/typescript-estree/src/errors.ts new file mode 100644 index 000000000000..0e1bd6194a15 --- /dev/null +++ b/packages/typescript-estree/src/errors.ts @@ -0,0 +1,72 @@ +import * as ts from 'typescript'; +import { SemanticOrSyntacticError } from './semantic-or-syntactic-errors'; + +/** + * Extends and formats a given error object + * @param error the error object + * @returns converted error object + */ +export function convertTSErrorToTSESTreeError( + error: SemanticOrSyntacticError | ts.DiagnosticWithLocation, +): TSESTreeError { + return createTSESTreeError( + ('message' in error && error.message) || (error.messageText as string), + error.file!, + error.start!, + ); +} + +export function createTSESTreeError( + message: string, + ast: ts.SourceFile, + startIndex: number, + endIndex: number = startIndex, +): TSESTreeError { + const [start, end] = [startIndex, endIndex].map(offset => { + const { character: column, line } = + ast.getLineAndCharacterOfPosition(offset); + return { column, line: line + 1, offset }; + }); + return new TSESTreeError(message, ast.fileName, { end, start }); +} + +export class TSESTreeError extends Error { + constructor( + message: string, + public readonly fileName: string, + public readonly location: { + end: { + column: number; + line: number; + offset: number; + }; + start: { + column: number; + line: number; + offset: number; + }; + }, + ) { + super(message); + Object.defineProperty(this, 'name', { + configurable: true, + enumerable: false, + value: new.target.name, + }); + } + + // For old version of ESLint https://github.com/typescript-eslint/typescript-eslint/pull/6556#discussion_r1123237311 + get index(): number { + return this.location.start.offset; + } + + // https://github.com/eslint/eslint/blob/b09a512107249a4eb19ef5a37b0bd672266eafdb/lib/linter/linter.js#L853 + get lineNumber(): number { + return this.location.start.line; + } + + // https://github.com/eslint/eslint/blob/b09a512107249a4eb19ef5a37b0bd672266eafdb/lib/linter/linter.js#L854 + get column(): number { + return this.location.start.column; + } +} diff --git a/packages/typescript-estree/src/index.ts b/packages/typescript-estree/src/index.ts index 39e921e8762a..bd18dc68e8b9 100644 --- a/packages/typescript-estree/src/index.ts +++ b/packages/typescript-estree/src/index.ts @@ -1,23 +1,14 @@ -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 './ast-converter'; +export * from './errors'; export * from './getModifiers'; -export { TSError } from './node-utils'; -export { - type AST, - parse, - parseAndGenerateServices, - type ParseAndGenerateServicesResult, -} from './parser'; export type { - ParserServices, - ParserServicesWithoutTypeInformation, - ParserServicesWithTypeInformation, - TSESTreeOptions, -} from './parser-options'; + ASTMaps, + ParserServicesNodeMaps, + ParserWeakMap, + ParserWeakMapESTreeToTSNode, +} from './node-maps'; +export type { TSESTreeOptions } from './parser-options'; export { simpleTraverse } from './simple-traverse'; export * from './ts-estree'; export { typescriptVersionIsAtLeast } from './version-check'; export { version } from './version'; -export { withoutProjectParserOptions } from './withoutProjectParserOptions'; diff --git a/packages/typescript-estree/src/node-maps.ts b/packages/typescript-estree/src/node-maps.ts new file mode 100644 index 000000000000..ce882838def1 --- /dev/null +++ b/packages/typescript-estree/src/node-maps.ts @@ -0,0 +1,27 @@ +import type { TSESTree, TSESTreeToTSNode, TSNode, TSToken } from './ts-estree'; + +// This lets us use generics to type the return value, and removes the need to +// handle the undefined type in the get method +export interface ParserWeakMap { + // This is unsafe internally, so it should only be exposed via safe wrappers. + // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters + get(key: Key): Value; + has(key: unknown): boolean; +} + +export interface ParserWeakMapESTreeToTSNode< + Key extends TSESTree.Node = TSESTree.Node, +> { + get(key: KeyBase): TSESTreeToTSNode; + has(key: unknown): boolean; +} + +export interface ASTMaps { + esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode; + tsNodeToESTreeNodeMap: ParserWeakMap; +} + +export interface ParserServicesNodeMaps { + esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode; + tsNodeToESTreeNodeMap: ParserWeakMap; +} diff --git a/packages/typescript-estree/src/node-utils.ts b/packages/typescript-estree/src/node-utils.ts index f2f60c777bd1..d3e8a55314ae 100644 --- a/packages/typescript-estree/src/node-utils.ts +++ b/packages/typescript-estree/src/node-utils.ts @@ -653,61 +653,6 @@ export function convertTokens(ast: ts.SourceFile): TSESTree.Token[] { return result; } -export class TSError extends Error { - constructor( - message: string, - public readonly fileName: string, - public readonly location: { - end: { - column: number; - line: number; - offset: number; - }; - start: { - column: number; - line: number; - offset: number; - }; - }, - ) { - super(message); - Object.defineProperty(this, 'name', { - configurable: true, - enumerable: false, - value: new.target.name, - }); - } - - // For old version of ESLint https://github.com/typescript-eslint/typescript-eslint/pull/6556#discussion_r1123237311 - get index(): number { - return this.location.start.offset; - } - - // https://github.com/eslint/eslint/blob/b09a512107249a4eb19ef5a37b0bd672266eafdb/lib/linter/linter.js#L853 - get lineNumber(): number { - return this.location.start.line; - } - - // https://github.com/eslint/eslint/blob/b09a512107249a4eb19ef5a37b0bd672266eafdb/lib/linter/linter.js#L854 - get column(): number { - return this.location.start.column; - } -} - -export function createError( - message: string, - ast: ts.SourceFile, - startIndex: number, - endIndex: number = startIndex, -): TSError { - const [start, end] = [startIndex, endIndex].map(offset => { - const { character: column, line } = - ast.getLineAndCharacterOfPosition(offset); - return { column, line: line + 1, offset }; - }); - return new TSError(message, ast.fileName, { end, start }); -} - export function nodeHasIllegalDecorators( node: ts.Node, ): node is { illegalDecorators: ts.Node[] } & ts.Node { diff --git a/packages/typescript-estree/src/parser-options.ts b/packages/typescript-estree/src/parser-options.ts index d3f8c8649fc5..f0de6791aaa6 100644 --- a/packages/typescript-estree/src/parser-options.ts +++ b/packages/typescript-estree/src/parser-options.ts @@ -7,8 +7,6 @@ import type { } from '@typescript-eslint/types'; import type * as ts from 'typescript'; -import type { TSESTree, TSESTreeToTSNode, TSNode, TSToken } from './ts-estree'; - export type { ProjectServiceOptions } from '@typescript-eslint/types'; ////////////////////////////////////////////////////////// @@ -220,44 +218,3 @@ interface ParseAndGenerateServicesOptions extends ParseOptions { } export type TSESTreeOptions = ParseAndGenerateServicesOptions; - -// This lets us use generics to type the return value, and removes the need to -// handle the undefined type in the get method -export interface ParserWeakMap { - // This is unsafe internally, so it should only be exposed via safe wrappers. - // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-parameters - get(key: Key): Value; - has(key: unknown): boolean; -} - -export interface ParserWeakMapESTreeToTSNode< - Key extends TSESTree.Node = TSESTree.Node, -> { - get(key: KeyBase): TSESTreeToTSNode; - has(key: unknown): boolean; -} - -export interface ParserServicesBase { - emitDecoratorMetadata: boolean | undefined; - experimentalDecorators: boolean | undefined; - isolatedDeclarations: boolean | undefined; -} -export interface ParserServicesNodeMaps { - esTreeNodeToTSNodeMap: ParserWeakMapESTreeToTSNode; - tsNodeToESTreeNodeMap: ParserWeakMap; -} -export interface ParserServicesWithTypeInformation - extends ParserServicesNodeMaps, - ParserServicesBase { - getSymbolAtLocation: (node: TSESTree.Node) => ts.Symbol | undefined; - getTypeAtLocation: (node: TSESTree.Node) => ts.Type; - program: ts.Program; -} -export interface ParserServicesWithoutTypeInformation - extends ParserServicesNodeMaps, - ParserServicesBase { - program: null; -} -export type ParserServices = - | ParserServicesWithoutTypeInformation - | ParserServicesWithTypeInformation; diff --git a/packages/typescript-estree/src/semantic-or-syntactic-errors.ts b/packages/typescript-estree/src/semantic-or-syntactic-errors.ts index a88a3615d9f8..e24f16c74540 100644 --- a/packages/typescript-estree/src/semantic-or-syntactic-errors.ts +++ b/packages/typescript-estree/src/semantic-or-syntactic-errors.ts @@ -1,119 +1,5 @@ -import type { - Diagnostic, - DiagnosticWithLocation, - Program, - SourceFile, -} from 'typescript'; - -import { flattenDiagnosticMessageText, sys } from 'typescript'; +import type { Diagnostic } from 'typescript'; export interface SemanticOrSyntacticError extends Diagnostic { message: string; } - -/** - * By default, diagnostics from the TypeScript compiler contain all errors - regardless of whether - * they are related to generic ECMAScript standards, or TypeScript-specific constructs. - * - * Therefore, we filter out all diagnostics, except for the ones we explicitly want to consider when - * the user opts in to throwing errors on semantic issues. - */ -export function getFirstSemanticOrSyntacticError( - program: Program, - ast: SourceFile, -): SemanticOrSyntacticError | undefined { - try { - const supportedSyntacticDiagnostics = allowlistSupportedDiagnostics( - program.getSyntacticDiagnostics(ast), - ); - if (supportedSyntacticDiagnostics.length > 0) { - return convertDiagnosticToSemanticOrSyntacticError( - supportedSyntacticDiagnostics[0], - ); - } - const supportedSemanticDiagnostics = allowlistSupportedDiagnostics( - program.getSemanticDiagnostics(ast), - ); - if (supportedSemanticDiagnostics.length > 0) { - return convertDiagnosticToSemanticOrSyntacticError( - supportedSemanticDiagnostics[0], - ); - } - return undefined; - } catch (e) { - /** - * TypeScript compiler has certain Debug.fail() statements in, which will cause the diagnostics - * retrieval above to throw. - * - * E.g. from ast-alignment-tests - * "Debug Failure. Shouldn't ever directly check a JsxOpeningElement" - * - * For our current use-cases this is undesired behavior, so we just suppress it - * and log a warning. - */ - /* istanbul ignore next */ - console.warn(`Warning From TSC: "${(e as Error).message}`); // eslint-disable-line no-console - /* istanbul ignore next */ - return undefined; - } -} - -function allowlistSupportedDiagnostics( - diagnostics: readonly (Diagnostic | DiagnosticWithLocation)[], -): readonly (Diagnostic | DiagnosticWithLocation)[] { - return diagnostics.filter(diagnostic => { - switch (diagnostic.code) { - case 1013: // "A rest parameter or binding pattern may not have a trailing comma." - case 1014: // "A rest parameter must be last in a parameter list." - case 1044: // "'{0}' modifier cannot appear on a module or namespace element." - case 1045: // "A '{0}' modifier cannot be used with an interface declaration." - case 1048: // "A rest parameter cannot have an initializer." - case 1049: // "A 'set' accessor must have exactly one parameter." - case 1070: // "'{0}' modifier cannot appear on a type member." - case 1071: // "'{0}' modifier cannot appear on an index signature." - case 1085: // "Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '{0}'." - case 1090: // "'{0}' modifier cannot appear on a parameter." - case 1096: // "An index signature must have exactly one parameter." - case 1097: // "'{0}' list cannot be empty." - case 1098: // "Type parameter list cannot be empty." - case 1099: // "Type argument list cannot be empty." - case 1117: // "An object literal cannot have multiple properties with the same name in strict mode." - case 1121: // "Octal literals are not allowed in strict mode." - case 1123: // "Variable declaration list cannot be empty." - case 1141: // "String literal expected." - case 1162: // "An object member cannot be declared optional." - case 1164: // "Computed property names are not allowed in enums." - case 1172: // "'extends' clause already seen." - case 1173: // "'extends' clause must precede 'implements' clause." - case 1175: // "'implements' clause already seen." - case 1176: // "Interface declaration cannot have 'implements' clause." - case 1190: // "The variable declaration of a 'for...of' statement cannot have an initializer." - case 1196: // "Catch clause variable type annotation must be 'any' or 'unknown' if specified." - case 1200: // "Line terminator not permitted before arrow." - case 1206: // "Decorators are not valid here." - case 1211: // "A class declaration without the 'default' modifier must have a name." - case 1242: // "'abstract' modifier can only appear on a class, method, or property declaration." - case 1246: // "An interface property cannot have an initializer." - case 1255: // "A definite assignment assertion '!' is not permitted in this context." - case 1308: // "'await' expression is only allowed within an async function." - case 2364: // "The left-hand side of an assignment expression must be a variable or a property access." - case 2369: // "A parameter property is only allowed in a constructor implementation." - case 2452: // "An enum member cannot have a numeric name." - case 2462: // "A rest element must be last in a destructuring pattern." - case 8017: // "Octal literal types must use ES2015 syntax. Use the syntax '{0}'." - case 17012: // "'{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{2}'?" - case 17013: // "Meta-property '{0}' is only allowed in the body of a function declaration, function expression, or constructor." - return true; - } - return false; - }); -} - -function convertDiagnosticToSemanticOrSyntacticError( - diagnostic: Diagnostic, -): SemanticOrSyntacticError { - return { - ...diagnostic, - message: flattenDiagnosticMessageText(diagnostic.messageText, sys.newLine), - }; -} 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 06cc89e1a5ac..89b4e4136e7e 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,6 @@ // required by website export * from './ast-converter'; -export * from './create-program/getScriptKind'; -export type { ParseSettings } from './parseSettings'; // required by packages/utils/src/ts-estree.ts export * from './getModifiers'; export { typescriptVersionIsAtLeast } from './version-check'; - -// required by packages/type-utils -export { getCanonicalFileName } from './create-program/shared'; diff --git a/packages/utils/package.json b/packages/utils/package.json index 9c0a1e6ec872..12d5b7518c4e 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -63,6 +63,7 @@ }, "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/parser-services": "8.32.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.0" diff --git a/packages/utils/src/eslint-utils/getParserServices.ts b/packages/utils/src/eslint-utils/getParserServices.ts index 1581638f58d8..51f55a0f9137 100644 --- a/packages/utils/src/eslint-utils/getParserServices.ts +++ b/packages/utils/src/eslint-utils/getParserServices.ts @@ -2,7 +2,7 @@ import type * as TSESLint from '../ts-eslint'; import type { ParserServices, ParserServicesWithTypeInformation, -} from '../ts-estree'; +} from '@typescript-eslint/parser-services'; import { parserSeemsToBeTSESLint } from './parserSeemsToBeTSESLint'; diff --git a/packages/utils/src/ts-estree.ts b/packages/utils/src/ts-estree.ts index 6c61253a1f05..8aca30ad7dbd 100644 --- a/packages/utils/src/ts-estree.ts +++ b/packages/utils/src/ts-estree.ts @@ -11,4 +11,4 @@ export type { ParserServices, ParserServicesWithoutTypeInformation, ParserServicesWithTypeInformation, -} from '@typescript-eslint/typescript-estree'; +} from '@typescript-eslint/parser-services'; diff --git a/packages/utils/tsconfig.build.json b/packages/utils/tsconfig.build.json index f99a3f7e1b40..726fd5919df0 100644 --- a/packages/utils/tsconfig.build.json +++ b/packages/utils/tsconfig.build.json @@ -2,6 +2,9 @@ "extends": "../../tsconfig.build.json", "compilerOptions": {}, "references": [ + { + "path": "../parser-services/tsconfig.build.json" + }, { "path": "../typescript-estree/tsconfig.build.json" }, diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json index bda7a07530ab..bda3cfd7f502 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -3,6 +3,9 @@ "files": [], "include": [], "references": [ + { + "path": "../parser-services" + }, { "path": "../typescript-estree" }, diff --git a/tsconfig.json b/tsconfig.json index 5a3d4d28b9e8..39cbb87e663c 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ { "path": "./packages/eslint-plugin-internal" }, { "path": "./packages/integration-tests" }, { "path": "./packages/parser" }, + { "path": "./packages/parser-services" }, { "path": "./packages/rule-schema-to-typescript-types" }, { "path": "./packages/rule-tester" }, { "path": "./packages/scope-manager" }, diff --git a/yarn.lock b/yarn.lock index 0b52f47c9fe5..86050389977f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5573,10 +5573,27 @@ __metadata: languageName: unknown linkType: soft +"@typescript-eslint/parser-services@8.32.0, @typescript-eslint/parser-services@workspace:packages/parser-services": + version: 0.0.0-use.local + resolution: "@typescript-eslint/parser-services@workspace:packages/parser-services" + dependencies: + "@typescript-eslint/typescript-estree": ^8.32.0 + "@vitest/coverage-v8": ^3.1.2 + debug: ^4.3.4 + fast-glob: ^3.3.2 + is-glob: ^4.0.3 + prettier: ^3.2.5 + rimraf: "*" + typescript: "*" + vitest: ^3.1.2 + languageName: unknown + linkType: soft + "@typescript-eslint/parser@8.32.0, @typescript-eslint/parser@workspace:*, @typescript-eslint/parser@workspace:packages/parser": version: 0.0.0-use.local resolution: "@typescript-eslint/parser@workspace:packages/parser" dependencies: + "@typescript-eslint/parser-services": 8.32.0 "@typescript-eslint/scope-manager": 8.32.0 "@typescript-eslint/types": 8.32.0 "@typescript-eslint/typescript-estree": 8.32.0 @@ -5752,7 +5769,7 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/typescript-estree@8.32.0, @typescript-eslint/typescript-estree@workspace:*, @typescript-eslint/typescript-estree@workspace:^, @typescript-eslint/typescript-estree@workspace:packages/typescript-estree": +"@typescript-eslint/typescript-estree@8.32.0, @typescript-eslint/typescript-estree@^8.32.0, @typescript-eslint/typescript-estree@workspace:*, @typescript-eslint/typescript-estree@workspace:^, @typescript-eslint/typescript-estree@workspace:packages/typescript-estree": version: 0.0.0-use.local resolution: "@typescript-eslint/typescript-estree@workspace:packages/typescript-estree" dependencies: @@ -5761,9 +5778,7 @@ __metadata: "@typescript-eslint/visitor-keys": 8.32.0 "@vitest/coverage-v8": ^3.1.3 debug: ^4.3.4 - fast-glob: ^3.3.2 glob: "*" - is-glob: ^4.0.3 minimatch: ^9.0.4 prettier: ^3.2.5 rimraf: "*" From e44bcfc37f44ff3ffc81e43ec06dcfd222742fb7 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 10 May 2025 22:22:58 -0400 Subject: [PATCH 2/3] Package split: types-eslint --- .../src/rules/member-ordering.ts | 9 +- .../rules/naming-convention-utils/schema.ts | 18 +- packages/parser-services/package.json | 1 + .../src/createParserServices.ts | 2 +- packages/parser-services/src/index.ts | 1 - packages/parser-services/src/parser.ts | 2 +- packages/parser-services/tsconfig.build.json | 3 + packages/parser-services/tsconfig.json | 3 + packages/parser/src/index.ts | 8 +- packages/parser/src/parser.ts | 3 +- .../src/utils/getRuleOptionsSchema.ts | 2 +- .../type-utils/src/TypeOrValueSpecifier.ts | 2 +- packages/type-utils/src/isTypeReadonly.ts | 2 +- packages/types-eslint/LICENSE | 21 + packages/types-eslint/README.md | 3 + packages/types-eslint/package.json | 67 +++ packages/types-eslint/project.json | 16 + .../src/ts-eslint => types-eslint/src}/AST.ts | 5 +- .../ts-eslint => types-eslint/src}/Config.ts | 0 .../ts-eslint => types-eslint/src}/ESLint.ts | 0 packages/types-eslint/src/JSONSchema4.ts | 499 +++++++++++++++++ .../ts-eslint => types-eslint/src}/Linter.ts | 1 + .../ts-eslint => types-eslint/src}/Parser.ts | 3 +- .../src}/ParserOptions.ts | 0 .../src/ParserServices.ts} | 4 + .../src}/Processor.ts | 0 .../ts-eslint => types-eslint/src}/Rule.ts | 5 +- .../src}/RuleTester.ts | 6 +- .../ts-eslint => types-eslint/src}/Scope.ts | 0 .../src}/SourceCode.ts | 4 +- .../src}/eslint/ESLintShared.ts | 0 .../src}/eslint/FlatESLint.ts | 1 + .../src}/eslint/LegacyESLint.ts | 1 + .../ts-eslint => types-eslint/src}/index.ts | 2 + packages/types-eslint/tsconfig.build.json | 18 + packages/types-eslint/tsconfig.json | 19 + packages/types-eslint/tsconfig.spec.json | 26 + packages/types-eslint/vitest.config.mts | 26 + packages/utils/package.json | 1 + .../eslint-utils/ReferenceTracker.ts | 2 +- .../ast-utils/eslint-utils/astUtilities.ts | 2 +- .../ast-utils/eslint-utils/scopeAnalysis.ts | 3 +- .../src/eslint-utils/InferTypesFromRule.ts | 5 +- .../utils/src/eslint-utils/RuleCreator.ts | 7 +- .../src/eslint-utils/getParserServices.ts | 4 +- packages/utils/src/index.ts | 5 +- packages/utils/src/json-schema.ts | 520 +----------------- packages/utils/src/ts-estree.ts | 2 +- packages/utils/tsconfig.build.json | 3 + packages/utils/tsconfig.json | 3 + tsconfig.json | 1 + yarn.lock | 48 ++ 52 files changed, 852 insertions(+), 537 deletions(-) create mode 100644 packages/types-eslint/LICENSE create mode 100644 packages/types-eslint/README.md create mode 100644 packages/types-eslint/package.json create mode 100644 packages/types-eslint/project.json rename packages/{utils/src/ts-eslint => types-eslint/src}/AST.ts (76%) rename packages/{utils/src/ts-eslint => types-eslint/src}/Config.ts (100%) rename packages/{utils/src/ts-eslint => types-eslint/src}/ESLint.ts (100%) create mode 100644 packages/types-eslint/src/JSONSchema4.ts rename packages/{utils/src/ts-eslint => types-eslint/src}/Linter.ts (99%) rename packages/{utils/src/ts-eslint => types-eslint/src}/Parser.ts (96%) rename packages/{utils/src/ts-eslint => types-eslint/src}/ParserOptions.ts (100%) rename packages/{parser-services/src/types.ts => types-eslint/src/ParserServices.ts} (77%) rename packages/{utils/src/ts-eslint => types-eslint/src}/Processor.ts (100%) rename packages/{utils/src/ts-eslint => types-eslint/src}/Rule.ts (99%) rename packages/{utils/src/ts-eslint => types-eslint/src}/RuleTester.ts (97%) rename packages/{utils/src/ts-eslint => types-eslint/src}/Scope.ts (100%) rename packages/{utils/src/ts-eslint => types-eslint/src}/SourceCode.ts (98%) rename packages/{utils/src/ts-eslint => types-eslint/src}/eslint/ESLintShared.ts (100%) rename packages/{utils/src/ts-eslint => types-eslint/src}/eslint/FlatESLint.ts (98%) rename packages/{utils/src/ts-eslint => types-eslint/src}/eslint/LegacyESLint.ts (98%) rename packages/{utils/src/ts-eslint => types-eslint/src}/index.ts (82%) create mode 100644 packages/types-eslint/tsconfig.build.json create mode 100644 packages/types-eslint/tsconfig.json create mode 100644 packages/types-eslint/tsconfig.spec.json create mode 100644 packages/types-eslint/vitest.config.mts diff --git a/packages/eslint-plugin/src/rules/member-ordering.ts b/packages/eslint-plugin/src/rules/member-ordering.ts index 7ae9ec7627cf..5a8e436f4548 100644 --- a/packages/eslint-plugin/src/rules/member-ordering.ts +++ b/packages/eslint-plugin/src/rules/member-ordering.ts @@ -1,7 +1,7 @@ // This rule was feature-frozen before we enabled no-property-in-node. /* eslint-disable eslint-plugin/no-property-in-node */ -import type { JSONSchema, TSESLint, TSESTree } from '@typescript-eslint/utils'; +import type { TSESLint, TSESTree } from '@typescript-eslint/utils'; import { AST_NODE_TYPES } from '@typescript-eslint/utils'; import naturalCompare from 'natural-compare'; @@ -12,6 +12,7 @@ import { getNameFromMember, MemberNameType, } from '../util'; +import { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; export type MessageIds = | 'incorrectGroupOrder' @@ -91,12 +92,12 @@ export type Options = [ }, ]; -const neverConfig: JSONSchema.JSONSchema4 = { +const neverConfig: JSONSchema4 = { type: 'string', enum: ['never'], }; -const arrayConfig = (memberTypes: string): JSONSchema.JSONSchema4 => ({ +const arrayConfig = (memberTypes: string): JSONSchema4 => ({ type: 'array', items: { oneOf: [ @@ -113,7 +114,7 @@ const arrayConfig = (memberTypes: string): JSONSchema.JSONSchema4 => ({ }, }); -const objectConfig = (memberTypes: string): JSONSchema.JSONSchema4 => ({ +const objectConfig = (memberTypes: string): JSONSchema4 => ({ type: 'object', additionalProperties: false, properties: { diff --git a/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts b/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts index 4bd08bb91cd3..dcc0e56a11a6 100644 --- a/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts +++ b/packages/eslint-plugin/src/rules/naming-convention-utils/schema.ts @@ -1,4 +1,4 @@ -import type { JSONSchema } from '@typescript-eslint/utils'; +import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; import type { IndividualAndMetaSelectorsString, @@ -15,7 +15,7 @@ import { UnderscoreOptions, } from './enums'; -const $DEFS: Record = { +const $DEFS: Record = { // enums predefinedFormats: { enum: getEnumNames(PredefinedFormats), @@ -64,16 +64,16 @@ const $DEFS: Record = { }, }; -const UNDERSCORE_SCHEMA: JSONSchema.JSONSchema4 = { +const UNDERSCORE_SCHEMA: JSONSchema4 = { $ref: '#/$defs/underscoreOptions', }; -const PREFIX_SUFFIX_SCHEMA: JSONSchema.JSONSchema4 = { +const PREFIX_SUFFIX_SCHEMA: JSONSchema4 = { $ref: '#/$defs/prefixSuffixConfig', }; -const MATCH_REGEX_SCHEMA: JSONSchema.JSONSchema4 = { +const MATCH_REGEX_SCHEMA: JSONSchema4 = { $ref: '#/$defs/matchRegexConfig', }; -type JSONSchemaProperties = Record; +type JSONSchemaProperties = Record; const FORMAT_OPTIONS_PROPERTIES: JSONSchemaProperties = { custom: MATCH_REGEX_SCHEMA, failureMessage: { @@ -91,7 +91,7 @@ function selectorSchema( selectorString: IndividualAndMetaSelectorsString, allowType: boolean, modifiers?: ModifiersString[], -): JSONSchema.JSONSchema4[] { +): JSONSchema4[] { const selector: JSONSchemaProperties = { filter: { oneOf: [ @@ -141,7 +141,7 @@ function selectorSchema( ]; } -function selectorsSchema(): JSONSchema.JSONSchema4 { +function selectorsSchema(): JSONSchema4 { return { additionalProperties: false, description: 'Multiple selectors in one config', @@ -185,7 +185,7 @@ function selectorsSchema(): JSONSchema.JSONSchema4 { }; } -export const SCHEMA: JSONSchema.JSONSchema4 = { +export const SCHEMA: JSONSchema4 = { $defs: $DEFS, additionalItems: false, items: { diff --git a/packages/parser-services/package.json b/packages/parser-services/package.json index 3c0a42e07fe5..825b494abf6c 100644 --- a/packages/parser-services/package.json +++ b/packages/parser-services/package.json @@ -46,6 +46,7 @@ "check-types": "npx nx typecheck" }, "dependencies": { + "@typescript-eslint/types-eslint": "^8.32.0", "@typescript-eslint/typescript-estree": "^8.32.0", "debug": "^4.3.4", "fast-glob": "^3.3.2", diff --git a/packages/parser-services/src/createParserServices.ts b/packages/parser-services/src/createParserServices.ts index 0974be6b1ed7..d6da57c32edb 100644 --- a/packages/parser-services/src/createParserServices.ts +++ b/packages/parser-services/src/createParserServices.ts @@ -1,6 +1,6 @@ +import { ParserServices } from '@typescript-eslint/types-eslint'; import { ASTMaps } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; -import { ParserServices } from './types'; export function createParserServices( astMaps: ASTMaps, diff --git a/packages/parser-services/src/index.ts b/packages/parser-services/src/index.ts index 8b2d2b7f2a37..1a2306afa7a5 100644 --- a/packages/parser-services/src/index.ts +++ b/packages/parser-services/src/index.ts @@ -1,6 +1,5 @@ export * from './clear-caches'; export { getCanonicalFileName } from './create-program/shared'; -export type * from './types'; export { createProgramFromConfigFile as createProgram } from './create-program/useProvidedPrograms'; export * from './withoutProjectParserOptions'; export * from './parser'; diff --git a/packages/parser-services/src/parser.ts b/packages/parser-services/src/parser.ts index 626921fdfb91..6b79c3376501 100644 --- a/packages/parser-services/src/parser.ts +++ b/packages/parser-services/src/parser.ts @@ -28,7 +28,7 @@ import type { TSESTree, TSESTreeOptions, } from '@typescript-eslint/typescript-estree'; -import { ParserServices } from './types'; +import { ParserServices } from '@typescript-eslint/types-eslint'; import { getFirstSemanticOrSyntacticError } from './semantic-or-syntactic-errors'; const log = debug('typescript-eslint:parser-services:parser'); diff --git a/packages/parser-services/tsconfig.build.json b/packages/parser-services/tsconfig.build.json index 241b39d618e6..4c747629e66f 100644 --- a/packages/parser-services/tsconfig.build.json +++ b/packages/parser-services/tsconfig.build.json @@ -10,6 +10,9 @@ }, "include": ["src/**/*.ts", "typings"], "references": [ + { + "path": "../types-eslint/tsconfig.build.json" + }, { "path": "../typescript-estree/tsconfig.build.json" } diff --git a/packages/parser-services/tsconfig.json b/packages/parser-services/tsconfig.json index 4733311e9be9..e5d40828187b 100644 --- a/packages/parser-services/tsconfig.json +++ b/packages/parser-services/tsconfig.json @@ -3,6 +3,9 @@ "files": [], "include": [], "references": [ + { + "path": "../types-eslint" + }, { "path": "../typescript-estree" }, diff --git a/packages/parser/src/index.ts b/packages/parser/src/index.ts index db293b5b4762..9bb87e85c34d 100644 --- a/packages/parser/src/index.ts +++ b/packages/parser/src/index.ts @@ -1,8 +1,10 @@ +export type { + ParserServices, + ParserServicesWithoutTypeInformation, + ParserServicesWithTypeInformation, +} from '@typescript-eslint/types-eslint'; export { parse, parseForESLint, type ParserOptions } from './parser'; export { - type ParserServices, - type ParserServicesWithoutTypeInformation, - type ParserServicesWithTypeInformation, clearCaches, createProgram, withoutProjectParserOptions, diff --git a/packages/parser/src/parser.ts b/packages/parser/src/parser.ts index 85cea7348102..d8a9dd3a2a6a 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -1,7 +1,8 @@ +import type { ParserServices } from '@typescript-eslint/types-eslint'; + import { AST, parseAndGenerateServices, - type ParserServices, } from '@typescript-eslint/parser-services'; import type { AnalyzeOptions, diff --git a/packages/rule-tester/src/utils/getRuleOptionsSchema.ts b/packages/rule-tester/src/utils/getRuleOptionsSchema.ts index f5977c95c8c8..c461983f3b7e 100644 --- a/packages/rule-tester/src/utils/getRuleOptionsSchema.ts +++ b/packages/rule-tester/src/utils/getRuleOptionsSchema.ts @@ -1,6 +1,6 @@ // Forked from https://github.com/eslint/eslint/blob/ad9dd6a933fd098a0d99c6a9aa059850535c23ee/lib/shared/config-validator.js#LL50-L82C2 -import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; +import type { JSONSchema4 } from '@typescript-eslint/types-eslint'; import type { AnyRuleModule } from '@typescript-eslint/utils/ts-eslint'; import { isReadonlyArray } from './isReadonlyArray'; diff --git a/packages/type-utils/src/TypeOrValueSpecifier.ts b/packages/type-utils/src/TypeOrValueSpecifier.ts index 4c8f1211a8be..fd2ea56fdbaa 100644 --- a/packages/type-utils/src/TypeOrValueSpecifier.ts +++ b/packages/type-utils/src/TypeOrValueSpecifier.ts @@ -1,4 +1,4 @@ -import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; +import type { JSONSchema4 } from '@typescript-eslint/types-eslint'; import type * as ts from 'typescript'; import * as tsutils from 'ts-api-utils'; diff --git a/packages/type-utils/src/isTypeReadonly.ts b/packages/type-utils/src/isTypeReadonly.ts index c874a60f164a..c27d57024cc3 100644 --- a/packages/type-utils/src/isTypeReadonly.ts +++ b/packages/type-utils/src/isTypeReadonly.ts @@ -1,4 +1,4 @@ -import type { JSONSchema4 } from '@typescript-eslint/utils/json-schema'; +import type { JSONSchema4 } from '@typescript-eslint/types-eslint'; import { ESLintUtils } from '@typescript-eslint/utils'; import * as tsutils from 'ts-api-utils'; diff --git a/packages/types-eslint/LICENSE b/packages/types-eslint/LICENSE new file mode 100644 index 000000000000..310a18f8a6cb --- /dev/null +++ b/packages/types-eslint/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 typescript-eslint and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/types-eslint/README.md b/packages/types-eslint/README.md new file mode 100644 index 000000000000..663b7917077b --- /dev/null +++ b/packages/types-eslint/README.md @@ -0,0 +1,3 @@ +# `@typescript-eslint/types-eslint` + +TODO diff --git a/packages/types-eslint/package.json b/packages/types-eslint/package.json new file mode 100644 index 000000000000..12c765cae708 --- /dev/null +++ b/packages/types-eslint/package.json @@ -0,0 +1,67 @@ +{ + "name": "@typescript-eslint/types-eslint", + "version": "8.32.0", + "description": "TODO", + "files": [ + "dist", + "!*.tsbuildinfo", + "package.json", + "README.md", + "LICENSE" + ], + "type": "commonjs", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "types": "./dist/index.d.ts", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/typescript-eslint/typescript-eslint.git", + "directory": "packages/types-eslint" + }, + "bugs": { + "url": "https://github.com/typescript-eslint/typescript-eslint/issues" + }, + "homepage": "https://typescript-eslint.io/packages/types-eslint", + "license": "MIT", + "keywords": [ + "eslint", + "typescript", + "estree" + ], + "scripts": { + "build": "tsc -b tsconfig.build.json", + "clean": "rimraf dist/ coverage/", + "clean-fixtures": "rimraf -g \"./src/**/fixtures/**/snapshots\"", + "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", + "generate-lib": "npx nx generate-lib repo", + "lint": "npx nx lint", + "test": "vitest --run --config=$INIT_CWD/vitest.config.mts", + "check-types": "npx nx typecheck" + }, + "dependencies": { + "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/visitor-keys": "8.32.0" + }, + "devDependencies": { + "@typescript-eslint/typescript-estree": "8.32.0", + "@vitest/coverage-v8": "^3.1.2", + "@vitest/pretty-format": "^3.1.2", + "glob": "*", + "prettier": "^3.2.5", + "rimraf": "*", + "typescript": "*", + "vitest": "^3.1.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } +} diff --git a/packages/types-eslint/project.json b/packages/types-eslint/project.json new file mode 100644 index 000000000000..8dda0be79656 --- /dev/null +++ b/packages/types-eslint/project.json @@ -0,0 +1,16 @@ +{ + "name": "types-eslint", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "root": "packages/types-eslint", + "sourceRoot": "packages/types-eslint/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/vite:test" + } + } +} diff --git a/packages/utils/src/ts-eslint/AST.ts b/packages/types-eslint/src/AST.ts similarity index 76% rename from packages/utils/src/ts-eslint/AST.ts rename to packages/types-eslint/src/AST.ts index cc4a74f4f038..ad6d0752ea59 100644 --- a/packages/utils/src/ts-eslint/AST.ts +++ b/packages/types-eslint/src/AST.ts @@ -1,6 +1,9 @@ /* eslint-disable @typescript-eslint/no-namespace, no-restricted-syntax */ -import type { AST_TOKEN_TYPES, TSESTree } from '../ts-estree'; +import type { + AST_TOKEN_TYPES, + TSESTree, +} from '@typescript-eslint/typescript-estree'; namespace AST { export type TokenType = AST_TOKEN_TYPES; diff --git a/packages/utils/src/ts-eslint/Config.ts b/packages/types-eslint/src/Config.ts similarity index 100% rename from packages/utils/src/ts-eslint/Config.ts rename to packages/types-eslint/src/Config.ts diff --git a/packages/utils/src/ts-eslint/ESLint.ts b/packages/types-eslint/src/ESLint.ts similarity index 100% rename from packages/utils/src/ts-eslint/ESLint.ts rename to packages/types-eslint/src/ESLint.ts diff --git a/packages/types-eslint/src/JSONSchema4.ts b/packages/types-eslint/src/JSONSchema4.ts new file mode 100644 index 000000000000..b188a25a372e --- /dev/null +++ b/packages/types-eslint/src/JSONSchema4.ts @@ -0,0 +1,499 @@ +// TODO: Maybe put these in a separate package too, while we're at it? + +/** + * This is a fork of https://github.com/DefinitelyTyped/DefinitelyTyped/blob/13f63c2eb8d7479caf01ab8d72f9e3683368a8f5/types/json-schema/index.d.ts + * We intentionally fork this because: + * - ESLint ***ONLY*** supports JSONSchema v4 + * - We want to provide stricter types + */ + +//================================================================================================== +// JSON Schema Draft 04 +//================================================================================================== + +/** + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1 + */ +export type JSONSchema4TypeName = + | 'any' + | 'array' + | 'boolean' + | 'integer' + | 'null' + | 'number' + | 'object' + | 'string'; + +/** + * @see https://tools.ietf.org/html/draft-zyp-json-schema-04#section-3.5 + */ +export type JSONSchema4Type = boolean | number | string | null; + +export type JSONSchema4TypeExtended = + | JSONSchema4Array + | JSONSchema4Object + | JSONSchema4Type; + +export interface JSONSchema4Object { + [key: string]: JSONSchema4TypeExtended; +} + +// Workaround for infinite type recursion +// https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540 +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface JSONSchema4Array extends Array {} + +/** + * Meta schema + * + * Recommended values: + * - 'http://json-schema.org/schema#' + * - 'http://json-schema.org/hyper-schema#' + * - 'http://json-schema.org/draft-04/schema#' + * - 'http://json-schema.org/draft-04/hyper-schema#' + * - 'http://json-schema.org/draft-03/schema#' + * - 'http://json-schema.org/draft-03/hyper-schema#' + * + * @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-5 + */ +export type JSONSchema4Version = string; + +/** + * JSON Schema V4 + * @see https://tools.ietf.org/html/draft-zyp-json-schema-04 + */ +export type JSONSchema4 = + | JSONSchema4AllOfSchema + | JSONSchema4AnyOfSchema + | JSONSchema4AnySchema + | JSONSchema4ArraySchema + | JSONSchema4BooleanSchema + | JSONSchema4MultiSchema + | JSONSchema4NullSchema + | JSONSchema4NumberSchema + | JSONSchema4ObjectSchema + | JSONSchema4OneOfSchema + | JSONSchema4RefSchema + | JSONSchema4StringSchema; + +interface JSONSchema4Base { + /** + * Reusable definitions that can be referenced via `$ref` + */ + $defs?: Record | undefined; + + /** + * Path to a schema defined in `definitions`/`$defs` that will form the base + * for this schema. + * + * If you are defining an "array" schema (`schema: [ ... ]`) for your rule + * then you should prefix this with `items/0` so that the validator can find + * your definitions. + * + * eg: `'#/items/0/definitions/myDef'` + * + * Otherwise if you are defining an "object" schema (`schema: { ... }`) for + * your rule you can directly reference your definitions + * + * eg: `'#/definitions/myDef'` + */ + $ref?: string | undefined; + + $schema?: JSONSchema4Version | undefined; + + /** + * (AND) Must be valid against all of the sub-schemas + */ + allOf?: JSONSchema4[] | undefined; + + /** + * (OR) Must be valid against any of the sub-schemas + */ + anyOf?: JSONSchema4[] | undefined; + + /** + * The default value for the item if not present + */ + default?: JSONSchema4TypeExtended | undefined; + + /** + * Reusable definitions that can be referenced via `$ref` + */ + definitions?: Record | undefined; + + /** + * This attribute is a string that provides a full description of the of + * purpose the instance property. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.22 + */ + description?: string | undefined; + + /** + * The value of this property MUST be another schema which will provide + * a base schema which the current schema will inherit from. The + * inheritance rules are such that any instance that is valid according + * to the current schema MUST be valid according to the referenced + * schema. This MAY also be an array, in which case, the instance MUST + * be valid for all the schemas in the array. A schema that extends + * another schema MAY define additional attributes, constrain existing + * attributes, or add other constraints. + * + * Conceptually, the behavior of extends can be seen as validating an + * instance against all constraints in the extending schema as well as + * the extended schema(s). + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.26 + */ + extends?: string | string[] | undefined; + + id?: string | undefined; + + /** + * (NOT) Must not be valid against the given schema + */ + not?: JSONSchema4 | undefined; + + /** + * (XOR) Must be valid against exactly one of the sub-schemas + */ + oneOf?: JSONSchema4[] | undefined; + + /** + * This attribute indicates if the instance must have a value, and not + * be undefined. This is false by default, making the instance + * optional. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.7 + */ + required?: boolean | string[] | undefined; + + /** + * This attribute is a string that provides a short description of the + * instance property. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.21 + */ + title?: string | undefined; + + /** + * A single type, or a union of simple types + */ + type?: JSONSchema4TypeName | JSONSchema4TypeName[] | undefined; +} + +export interface JSONSchema4RefSchema extends JSONSchema4Base { + $ref: string; + type?: undefined; +} + +export interface JSONSchema4AllOfSchema extends JSONSchema4Base { + allOf: JSONSchema4[]; + type?: undefined; +} + +export interface JSONSchema4AnyOfSchema extends JSONSchema4Base { + anyOf: JSONSchema4[]; + type?: undefined; +} + +export interface JSONSchema4OneOfSchema extends JSONSchema4Base { + oneOf: JSONSchema4[]; + type?: undefined; +} + +export interface JSONSchema4MultiSchema + extends Omit, + Omit, + Omit, + Omit, + Omit, + Omit, + Omit { + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: JSONSchema4Type[]; + type: JSONSchema4TypeName[]; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/object.html + */ +export interface JSONSchema4ObjectSchema extends JSONSchema4Base { + /** + * This attribute defines a schema for all properties that are not + * explicitly defined in an object type definition. If specified, the + * value MUST be a schema or a boolean. If false is provided, no + * additional properties are allowed beyond the properties defined in + * the schema. The default value is an empty schema which allows any + * value for additional properties. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.4 + */ + additionalProperties?: boolean | JSONSchema4 | undefined; + + /** + * The `dependencies` keyword conditionally applies a sub-schema when a given + * property is present. This schema is applied in the same way `allOf` applies + * schemas. Nothing is merged or extended. Both schemas apply independently. + */ + dependencies?: Record | undefined; + + /** + * The maximum number of properties allowed for record-style schemas + */ + maxProperties?: number | undefined; + + /** + * The minimum number of properties required for record-style schemas + */ + minProperties?: number | undefined; + + /** + * This attribute is an object that defines the schema for a set of + * property names of an object instance. The name of each property of + * this attribute's object is a regular expression pattern in the ECMA + * 262/Perl 5 format, while the value is a schema. If the pattern + * matches the name of a property on the instance object, the value of + * the instance's property MUST be valid against the pattern name's + * schema value. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.3 + */ + patternProperties?: Record | undefined; + + /** + * This attribute is an object with property definitions that define the + * valid values of instance object property values. When the instance + * value is an object, the property values of the instance object MUST + * conform to the property definitions in this object. In this object, + * each property definition's value MUST be a schema, and the property's + * name MUST be the name of the instance property that it defines. The + * instance property value MUST be valid according to the schema from + * the property definition. Properties are considered unordered, the + * order of the instance properties MAY be in any order. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.2 + */ + properties?: Record | undefined; + + type: 'object'; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/array.html + */ +export interface JSONSchema4ArraySchema extends JSONSchema4Base { + /** + * May only be defined when "items" is defined, and is a tuple of JSONSchemas. + * + * This provides a definition for additional items in an array instance + * when tuple definitions of the items is provided. This can be false + * to indicate additional items in the array are not allowed, or it can + * be a schema that defines the schema of the additional items. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.6 + */ + additionalItems?: boolean | JSONSchema4 | undefined; + + /** + * This attribute defines the allowed items in an instance array, and + * MUST be a schema or an array of schemas. The default value is an + * empty schema which allows any value for items in the instance array. + * + * When this attribute value is a schema and the instance value is an + * array, then all the items in the array MUST be valid according to the + * schema. + * + * When this attribute value is an array of schemas and the instance + * value is an array, each position in the instance array MUST conform + * to the schema in the corresponding position for this array. This + * called tuple typing. When tuple typing is used, additional items are + * allowed, disallowed, or constrained by the "additionalItems" + * (Section 5.6) attribute using the same rules as + * "additionalProperties" (Section 5.4) for objects. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.5 + */ + items?: JSONSchema4 | JSONSchema4[] | undefined; + + /** + * Defines the maximum length of an array + */ + maxItems?: number | undefined; + + /** + * Defines the minimum length of an array + */ + minItems?: number | undefined; + + type: 'array'; + + /** + * Enforces that all items in the array are unique + */ + uniqueItems?: boolean | undefined; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/string.html + */ +export interface JSONSchema4StringSchema extends JSONSchema4Base { + enum?: string[] | undefined; + + /** + * The `format` keyword allows for basic semantic identification of certain + * kinds of string values that are commonly used. + * + * For example, because JSON doesn’t have a “DateTime” type, dates need to be + * encoded as strings. `format` allows the schema author to indicate that the + * string value should be interpreted as a date. + * + * ajv v6 provides a few built-in formats - all other strings will cause AJV + * to throw during schema compilation + */ + format?: + | 'date' + | 'date-time' + | 'email' + | 'hostname' + | 'ipv4' + | 'ipv6' + | 'json-pointer' + | 'json-pointer-uri-fragment' + | 'regex' + | 'relative-json-pointer' + | 'time' + | 'uri' + | 'uri-reference' + | 'uri-template' + | 'url' + | 'uuid' + | undefined; + + /** + * The maximum allowed length for the string + */ + maxLength?: number | undefined; + + /** + * The minimum allowed length for the string + */ + minLength?: number | undefined; + + /** + * The `pattern` keyword is used to restrict a string to a particular regular + * expression. The regular expression syntax is the one defined in JavaScript + * (ECMA 262 specifically) with Unicode support. + * + * When defining the regular expressions, it’s important to note that the + * string is considered valid if the expression matches anywhere within the + * string. For example, the regular expression "p" will match any string with + * a p in it, such as "apple" not just a string that is simply "p". Therefore, + * it is usually less confusing, as a matter of course, to surround the + * regular expression in ^...$, for example, "^p$", unless there is a good + * reason not to do so. + */ + pattern?: string | undefined; + + type: 'string'; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/numeric.html + */ +export interface JSONSchema4NumberSchema extends JSONSchema4Base { + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: number[] | undefined; + + /** + * The exclusive minimum allowed value for the number + * - `true` = `x < maximum` + * - `false` = `x <= maximum` + * + * Default is `false` + */ + exclusiveMaximum?: boolean | undefined; + + /** + * Indicates whether or not `minimum` is the inclusive or exclusive minimum + * - `true` = `x > minimum` + * - `false` = `x ≥ minimum` + * + * Default is `false` + */ + exclusiveMinimum?: boolean | undefined; + + /** + * The maximum allowed value for the number + */ + maximum?: number | undefined; + + /** + * The minimum allowed value for the number + */ + minimum?: number | undefined; + + /** + * Numbers can be restricted to a multiple of a given number, using the + * `multipleOf` keyword. It may be set to any positive number. + */ + multipleOf?: number | undefined; + + type: 'integer' | 'number'; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/boolean.html + */ +export interface JSONSchema4BooleanSchema extends JSONSchema4Base { + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: boolean[] | undefined; + + type: 'boolean'; +} + +/** + * @see https://json-schema.org/understanding-json-schema/reference/null.html + */ +export interface JSONSchema4NullSchema extends JSONSchema4Base { + /** + * This provides an enumeration of all possible values that are valid + * for the instance property. This MUST be an array, and each item in + * the array represents a possible value for the instance value. If + * this attribute is defined, the instance value MUST be one of the + * values in the array in order for the schema to be valid. + * + * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 + */ + enum?: null[] | undefined; + + type: 'null'; +} + +export interface JSONSchema4AnySchema extends JSONSchema4Base { + type: 'any'; +} diff --git a/packages/utils/src/ts-eslint/Linter.ts b/packages/types-eslint/src/Linter.ts similarity index 99% rename from packages/utils/src/ts-eslint/Linter.ts rename to packages/types-eslint/src/Linter.ts index 499213d95f3b..02203816a771 100644 --- a/packages/utils/src/ts-eslint/Linter.ts +++ b/packages/types-eslint/src/Linter.ts @@ -316,6 +316,7 @@ namespace Linter { * simply parses and reports on the code. In particular, the Linter object does not process configuration objects * or files. */ +// @ts-expect-error -- TODO: I don't know why this is now needed... class Linter extends (ESLintLinter as typeof LinterBase) {} export { Linter }; diff --git a/packages/utils/src/ts-eslint/Parser.ts b/packages/types-eslint/src/Parser.ts similarity index 96% rename from packages/utils/src/ts-eslint/Parser.ts rename to packages/types-eslint/src/Parser.ts index ad9f5763054f..193966ac9b29 100644 --- a/packages/utils/src/ts-eslint/Parser.ts +++ b/packages/types-eslint/src/Parser.ts @@ -1,8 +1,9 @@ /* eslint-disable @typescript-eslint/no-namespace */ -import type { ParserServices, TSESTree } from '../ts-estree'; +import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type { ParserOptions } from './ParserOptions'; import type { Scope } from './Scope'; +import { ParserServices } from './ParserServices'; export namespace Parser { export interface ParserMeta { diff --git a/packages/utils/src/ts-eslint/ParserOptions.ts b/packages/types-eslint/src/ParserOptions.ts similarity index 100% rename from packages/utils/src/ts-eslint/ParserOptions.ts rename to packages/types-eslint/src/ParserOptions.ts diff --git a/packages/parser-services/src/types.ts b/packages/types-eslint/src/ParserServices.ts similarity index 77% rename from packages/parser-services/src/types.ts rename to packages/types-eslint/src/ParserServices.ts index 7c31e060fb10..8facb6cdb0a8 100644 --- a/packages/parser-services/src/types.ts +++ b/packages/types-eslint/src/ParserServices.ts @@ -4,6 +4,10 @@ import { } from '@typescript-eslint/typescript-estree'; import ts from 'typescript'; +// NOTE: These types are intentionally in types-eslint, not parser-services, +// so that packages such as rule-creator can refer to them without taking a full +// dependency on all the runtime logic & dependencies of parser-services. + export interface ParserServicesBase { emitDecoratorMetadata: boolean | undefined; experimentalDecorators: boolean | undefined; diff --git a/packages/utils/src/ts-eslint/Processor.ts b/packages/types-eslint/src/Processor.ts similarity index 100% rename from packages/utils/src/ts-eslint/Processor.ts rename to packages/types-eslint/src/Processor.ts diff --git a/packages/utils/src/ts-eslint/Rule.ts b/packages/types-eslint/src/Rule.ts similarity index 99% rename from packages/utils/src/ts-eslint/Rule.ts rename to packages/types-eslint/src/Rule.ts index 35cd1c7f7a0c..5ab1df864ebc 100644 --- a/packages/utils/src/ts-eslint/Rule.ts +++ b/packages/types-eslint/src/Rule.ts @@ -1,10 +1,11 @@ -import type { JSONSchema4 } from '../json-schema'; -import type { ParserServices, TSESTree } from '../ts-estree'; +import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type { AST } from './AST'; import type { FlatConfig } from './Config'; import type { Linter } from './Linter'; import type { Scope } from './Scope'; import type { SourceCode } from './SourceCode'; +import { JSONSchema4 } from './JSONSchema4'; +import { ParserServices } from './ParserServices'; export type RuleRecommendation = 'recommended' | 'strict' | 'stylistic'; diff --git a/packages/utils/src/ts-eslint/RuleTester.ts b/packages/types-eslint/src/RuleTester.ts similarity index 97% rename from packages/utils/src/ts-eslint/RuleTester.ts rename to packages/types-eslint/src/RuleTester.ts index 409baf2a08a4..a0a60d535c79 100644 --- a/packages/utils/src/ts-eslint/RuleTester.ts +++ b/packages/types-eslint/src/RuleTester.ts @@ -1,7 +1,6 @@ /* eslint-disable @typescript-eslint/no-deprecated */ import { RuleTester as ESLintRuleTester } from 'eslint'; -import type { AST_NODE_TYPES, AST_TOKEN_TYPES } from '../ts-estree'; import type { ClassicConfig } from './Config'; import type { Linter } from './Linter'; import type { ParserOptions } from './ParserOptions'; @@ -11,6 +10,10 @@ import type { RuleModule, SharedConfigurationSettings, } from './Rule'; +import { + AST_NODE_TYPES, + AST_TOKEN_TYPES, +} from '@typescript-eslint/typescript-estree'; /** * @deprecated Use `@typescript-eslint/rule-tester` instead. @@ -226,4 +229,5 @@ declare class RuleTesterBase { /** * @deprecated Use `@typescript-eslint/rule-tester` instead. */ +// @ts-expect-error -- TODO: I don't know why this is now needed... export class RuleTester extends (ESLintRuleTester as typeof RuleTesterBase) {} diff --git a/packages/utils/src/ts-eslint/Scope.ts b/packages/types-eslint/src/Scope.ts similarity index 100% rename from packages/utils/src/ts-eslint/Scope.ts rename to packages/types-eslint/src/Scope.ts diff --git a/packages/utils/src/ts-eslint/SourceCode.ts b/packages/types-eslint/src/SourceCode.ts similarity index 98% rename from packages/utils/src/ts-eslint/SourceCode.ts rename to packages/types-eslint/src/SourceCode.ts index f4afb79f2dad..64c4a27180c2 100644 --- a/packages/utils/src/ts-eslint/SourceCode.ts +++ b/packages/types-eslint/src/SourceCode.ts @@ -2,9 +2,10 @@ import { SourceCode as ESLintSourceCode } from 'eslint'; -import type { ParserServices, TSESTree } from '../ts-estree'; +import type { TSESTree } from '@typescript-eslint/typescript-estree'; import type { Parser } from './Parser'; import type { Scope } from './Scope'; +import { ParserServices } from './ParserServices'; declare class TokenStore { /** @@ -451,6 +452,7 @@ namespace SourceCode { | FilterPredicate; } +// @ts-expect-error -- TODO: I don't know why this is now needed... class SourceCode extends (ESLintSourceCode as typeof SourceCodeBase) {} export { SourceCode }; diff --git a/packages/utils/src/ts-eslint/eslint/ESLintShared.ts b/packages/types-eslint/src/eslint/ESLintShared.ts similarity index 100% rename from packages/utils/src/ts-eslint/eslint/ESLintShared.ts rename to packages/types-eslint/src/eslint/ESLintShared.ts diff --git a/packages/utils/src/ts-eslint/eslint/FlatESLint.ts b/packages/types-eslint/src/eslint/FlatESLint.ts similarity index 98% rename from packages/utils/src/ts-eslint/eslint/FlatESLint.ts rename to packages/types-eslint/src/eslint/FlatESLint.ts index 085a9e0fdfa9..a57d429f01a6 100644 --- a/packages/utils/src/ts-eslint/eslint/FlatESLint.ts +++ b/packages/types-eslint/src/eslint/FlatESLint.ts @@ -34,6 +34,7 @@ declare class FlatESLintBase extends Shared.ESLintBase< * * If you want to lint code on browsers, use the Linter class instead. */ +// @ts-expect-error -- TODO: I don't know why this is now needed... export class FlatESLint extends (ESLintFlatESLint as typeof FlatESLintBase) {} export namespace FlatESLint { export interface ESLintOptions diff --git a/packages/utils/src/ts-eslint/eslint/LegacyESLint.ts b/packages/types-eslint/src/eslint/LegacyESLint.ts similarity index 98% rename from packages/utils/src/ts-eslint/eslint/LegacyESLint.ts rename to packages/types-eslint/src/eslint/LegacyESLint.ts index 6dc316991688..6943d9a8f6f4 100644 --- a/packages/utils/src/ts-eslint/eslint/LegacyESLint.ts +++ b/packages/types-eslint/src/eslint/LegacyESLint.ts @@ -20,6 +20,7 @@ declare class LegacyESLintBase extends Shared.ESLintBase< * * If you want to lint code on browsers, use the Linter class instead. */ +// @ts-expect-error -- TODO: I don't know why this is now needed... export class LegacyESLint extends (ESLintLegacyESLint as typeof LegacyESLintBase) {} export namespace LegacyESLint { export interface ESLintOptions diff --git a/packages/utils/src/ts-eslint/index.ts b/packages/types-eslint/src/index.ts similarity index 82% rename from packages/utils/src/ts-eslint/index.ts rename to packages/types-eslint/src/index.ts index 217b46dcbf7d..2908a50fb5e0 100644 --- a/packages/utils/src/ts-eslint/index.ts +++ b/packages/types-eslint/src/index.ts @@ -1,9 +1,11 @@ export * from './AST'; +export * from './JSONSchema4'; export * from './Config'; export * from './ESLint'; export * from './Linter'; export * from './Parser'; export * from './ParserOptions'; +export * from './ParserServices'; export * from './Processor'; export * from './Rule'; export * from './RuleTester'; diff --git a/packages/types-eslint/tsconfig.build.json b/packages/types-eslint/tsconfig.build.json new file mode 100644 index 000000000000..6ad59da4bb89 --- /dev/null +++ b/packages/types-eslint/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo", + "emitDeclarationOnly": false, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["vitest.config.mts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "references": [ + { + "path": "../typescript-estree/tsconfig.build.json" + } + ] +} diff --git a/packages/types-eslint/tsconfig.json b/packages/types-eslint/tsconfig.json new file mode 100644 index 000000000000..e5d40828187b --- /dev/null +++ b/packages/types-eslint/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "../types-eslint" + }, + { + "path": "../typescript-estree" + }, + { + "path": "./tsconfig.build.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/types-eslint/tsconfig.spec.json b/packages/types-eslint/tsconfig.spec.json new file mode 100644 index 000000000000..cc2ef165b048 --- /dev/null +++ b/packages/types-eslint/tsconfig.spec.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc/packages/types-eslint", + "module": "NodeNext", + "resolveJsonModule": true, + "types": ["node", "vitest/globals", "vitest/importMeta"] + }, + "include": [ + "vitest.config.mts", + "package.json", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts", + "tests" + ], + "exclude": ["**/fixtures/**"], + "references": [ + { + "path": "./tsconfig.build.json" + }, + { + "path": "../../tsconfig.spec.json" + } + ] +} diff --git a/packages/types-eslint/vitest.config.mts b/packages/types-eslint/vitest.config.mts new file mode 100644 index 000000000000..b3cf1f898a70 --- /dev/null +++ b/packages/types-eslint/vitest.config.mts @@ -0,0 +1,26 @@ +import * as path from 'node:path'; +import { defineProject, mergeConfig } from 'vitest/config'; + +import { vitestBaseConfig } from '../../vitest.config.base.mjs'; +import packageJson from './package.json' with { type: 'json' }; + +const vitestConfig = mergeConfig( + vitestBaseConfig, + + defineProject({ + root: import.meta.dirname, + + test: { + dir: path.join(import.meta.dirname, 'tests'), + name: packageJson.name.replace('@typescript-eslint/', ''), + root: import.meta.dirname, + + setupFiles: [ + './tests/test-utils/serializers/index.ts', + './tests/test-utils/custom-matchers/custom-matchers.ts', + ], + }, + }), +); + +export default vitestConfig; diff --git a/packages/utils/package.json b/packages/utils/package.json index 12d5b7518c4e..d3f9852f2515 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -66,6 +66,7 @@ "@typescript-eslint/parser-services": "8.32.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/types-eslint": "8.32.0", "@typescript-eslint/typescript-estree": "8.32.0" }, "peerDependencies": { diff --git a/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts b/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts index 5fca306bddf7..fe995439539b 100644 --- a/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts +++ b/packages/utils/src/ast-utils/eslint-utils/ReferenceTracker.ts @@ -1,7 +1,7 @@ /* eslint-disable @typescript-eslint/no-namespace */ import * as eslintUtils from '@eslint-community/eslint-utils'; -import type * as TSESLint from '../../ts-eslint'; +import type * as TSESLint from '@typescript-eslint/types-eslint'; import type { TSESTree } from '../../ts-estree'; const ReferenceTrackerREAD: unique symbol = eslintUtils.ReferenceTracker.READ; diff --git a/packages/utils/src/ast-utils/eslint-utils/astUtilities.ts b/packages/utils/src/ast-utils/eslint-utils/astUtilities.ts index 8113319b68de..299b02a0652b 100644 --- a/packages/utils/src/ast-utils/eslint-utils/astUtilities.ts +++ b/packages/utils/src/ast-utils/eslint-utils/astUtilities.ts @@ -1,6 +1,6 @@ import * as eslintUtils from '@eslint-community/eslint-utils'; -import type * as TSESLint from '../../ts-eslint'; +import type * as TSESLint from '@typescript-eslint/types-eslint'; import type { TSESTree } from '../../ts-estree'; /** diff --git a/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts b/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts index 1f7af13dd3cb..2988ef90138a 100644 --- a/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts +++ b/packages/utils/src/ast-utils/eslint-utils/scopeAnalysis.ts @@ -1,6 +1,7 @@ +import type * as TSESLint from '@typescript-eslint/types-eslint'; + import * as eslintUtils from '@eslint-community/eslint-utils'; -import type * as TSESLint from '../../ts-eslint'; import type { TSESTree } from '../../ts-estree'; /** diff --git a/packages/utils/src/eslint-utils/InferTypesFromRule.ts b/packages/utils/src/eslint-utils/InferTypesFromRule.ts index 2e8dc3f232a1..92e9c4d31ff5 100644 --- a/packages/utils/src/eslint-utils/InferTypesFromRule.ts +++ b/packages/utils/src/eslint-utils/InferTypesFromRule.ts @@ -1,4 +1,7 @@ -import type { RuleCreateFunction, RuleModule } from '../ts-eslint'; +import type { + RuleCreateFunction, + RuleModule, +} from '@typescript-eslint/types-eslint'; /** * Uses type inference to fetch the Options type from the given RuleModule diff --git a/packages/utils/src/eslint-utils/RuleCreator.ts b/packages/utils/src/eslint-utils/RuleCreator.ts index cd06aee6231f..7ea670cc7c56 100644 --- a/packages/utils/src/eslint-utils/RuleCreator.ts +++ b/packages/utils/src/eslint-utils/RuleCreator.ts @@ -4,7 +4,7 @@ import type { RuleMetaData, RuleMetaDataDocs, RuleModule, -} from '../ts-eslint/Rule'; +} from '@typescript-eslint/types-eslint'; import { applyDefault } from './applyDefault'; @@ -119,4 +119,7 @@ RuleCreator.withoutDocs = function withoutDocs< return createRule(args); }; -export { type RuleListener, type RuleModule } from '../ts-eslint/Rule'; +export { + type RuleListener, + type RuleModule, +} from '@typescript-eslint/types-eslint'; diff --git a/packages/utils/src/eslint-utils/getParserServices.ts b/packages/utils/src/eslint-utils/getParserServices.ts index 51f55a0f9137..174397496573 100644 --- a/packages/utils/src/eslint-utils/getParserServices.ts +++ b/packages/utils/src/eslint-utils/getParserServices.ts @@ -1,8 +1,8 @@ -import type * as TSESLint from '../ts-eslint'; +import type * as TSESLint from '@typescript-eslint/types-eslint'; import type { ParserServices, ParserServicesWithTypeInformation, -} from '@typescript-eslint/parser-services'; +} from '@typescript-eslint/types-eslint'; import { parserSeemsToBeTSESLint } from './parserSeemsToBeTSESLint'; diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index d6d907cd0ef4..34f8832542ee 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -1,7 +1,8 @@ +// TODO: Should this be deprecated? Probably not, since it's convenient, right? +export * as TSESLint from '@typescript-eslint/types-eslint'; + export * as ASTUtils from './ast-utils'; export * as ESLintUtils from './eslint-utils'; -export * as JSONSchema from './json-schema'; -export * as TSESLint from './ts-eslint'; export * from './ts-estree'; export * as TSUtils from './ts-utils'; diff --git a/packages/utils/src/json-schema.ts b/packages/utils/src/json-schema.ts index bfa890aac372..1442a421e4dd 100644 --- a/packages/utils/src/json-schema.ts +++ b/packages/utils/src/json-schema.ts @@ -1,497 +1,23 @@ -/** - * This is a fork of https://github.com/DefinitelyTyped/DefinitelyTyped/blob/13f63c2eb8d7479caf01ab8d72f9e3683368a8f5/types/json-schema/index.d.ts - * We intentionally fork this because: - * - ESLint ***ONLY*** supports JSONSchema v4 - * - We want to provide stricter types - */ - -//================================================================================================== -// JSON Schema Draft 04 -//================================================================================================== - -/** - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.1 - */ -export type JSONSchema4TypeName = - | 'any' - | 'array' - | 'boolean' - | 'integer' - | 'null' - | 'number' - | 'object' - | 'string'; - -/** - * @see https://tools.ietf.org/html/draft-zyp-json-schema-04#section-3.5 - */ -export type JSONSchema4Type = boolean | number | string | null; - -export type JSONSchema4TypeExtended = - | JSONSchema4Array - | JSONSchema4Object - | JSONSchema4Type; - -export interface JSONSchema4Object { - [key: string]: JSONSchema4TypeExtended; -} - -// Workaround for infinite type recursion -// https://github.com/Microsoft/TypeScript/issues/3496#issuecomment-128553540 -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export interface JSONSchema4Array extends Array {} - -/** - * Meta schema - * - * Recommended values: - * - 'http://json-schema.org/schema#' - * - 'http://json-schema.org/hyper-schema#' - * - 'http://json-schema.org/draft-04/schema#' - * - 'http://json-schema.org/draft-04/hyper-schema#' - * - 'http://json-schema.org/draft-03/schema#' - * - 'http://json-schema.org/draft-03/hyper-schema#' - * - * @see https://tools.ietf.org/html/draft-handrews-json-schema-validation-01#section-5 - */ -export type JSONSchema4Version = string; - -/** - * JSON Schema V4 - * @see https://tools.ietf.org/html/draft-zyp-json-schema-04 - */ -export type JSONSchema4 = - | JSONSchema4AllOfSchema - | JSONSchema4AnyOfSchema - | JSONSchema4AnySchema - | JSONSchema4ArraySchema - | JSONSchema4BooleanSchema - | JSONSchema4MultiSchema - | JSONSchema4NullSchema - | JSONSchema4NumberSchema - | JSONSchema4ObjectSchema - | JSONSchema4OneOfSchema - | JSONSchema4RefSchema - | JSONSchema4StringSchema; - -interface JSONSchema4Base { - /** - * Reusable definitions that can be referenced via `$ref` - */ - $defs?: Record | undefined; - - /** - * Path to a schema defined in `definitions`/`$defs` that will form the base - * for this schema. - * - * If you are defining an "array" schema (`schema: [ ... ]`) for your rule - * then you should prefix this with `items/0` so that the validator can find - * your definitions. - * - * eg: `'#/items/0/definitions/myDef'` - * - * Otherwise if you are defining an "object" schema (`schema: { ... }`) for - * your rule you can directly reference your definitions - * - * eg: `'#/definitions/myDef'` - */ - $ref?: string | undefined; - - $schema?: JSONSchema4Version | undefined; - - /** - * (AND) Must be valid against all of the sub-schemas - */ - allOf?: JSONSchema4[] | undefined; - - /** - * (OR) Must be valid against any of the sub-schemas - */ - anyOf?: JSONSchema4[] | undefined; - - /** - * The default value for the item if not present - */ - default?: JSONSchema4TypeExtended | undefined; - - /** - * Reusable definitions that can be referenced via `$ref` - */ - definitions?: Record | undefined; - - /** - * This attribute is a string that provides a full description of the of - * purpose the instance property. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.22 - */ - description?: string | undefined; - - /** - * The value of this property MUST be another schema which will provide - * a base schema which the current schema will inherit from. The - * inheritance rules are such that any instance that is valid according - * to the current schema MUST be valid according to the referenced - * schema. This MAY also be an array, in which case, the instance MUST - * be valid for all the schemas in the array. A schema that extends - * another schema MAY define additional attributes, constrain existing - * attributes, or add other constraints. - * - * Conceptually, the behavior of extends can be seen as validating an - * instance against all constraints in the extending schema as well as - * the extended schema(s). - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.26 - */ - extends?: string | string[] | undefined; - - id?: string | undefined; - - /** - * (NOT) Must not be valid against the given schema - */ - not?: JSONSchema4 | undefined; - - /** - * (XOR) Must be valid against exactly one of the sub-schemas - */ - oneOf?: JSONSchema4[] | undefined; - - /** - * This attribute indicates if the instance must have a value, and not - * be undefined. This is false by default, making the instance - * optional. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.7 - */ - required?: boolean | string[] | undefined; - - /** - * This attribute is a string that provides a short description of the - * instance property. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.21 - */ - title?: string | undefined; - - /** - * A single type, or a union of simple types - */ - type?: JSONSchema4TypeName | JSONSchema4TypeName[] | undefined; -} - -export interface JSONSchema4RefSchema extends JSONSchema4Base { - $ref: string; - type?: undefined; -} - -export interface JSONSchema4AllOfSchema extends JSONSchema4Base { - allOf: JSONSchema4[]; - type?: undefined; -} - -export interface JSONSchema4AnyOfSchema extends JSONSchema4Base { - anyOf: JSONSchema4[]; - type?: undefined; -} - -export interface JSONSchema4OneOfSchema extends JSONSchema4Base { - oneOf: JSONSchema4[]; - type?: undefined; -} - -export interface JSONSchema4MultiSchema - extends Omit, - Omit, - Omit, - Omit, - Omit, - Omit, - Omit { - /** - * This provides an enumeration of all possible values that are valid - * for the instance property. This MUST be an array, and each item in - * the array represents a possible value for the instance value. If - * this attribute is defined, the instance value MUST be one of the - * values in the array in order for the schema to be valid. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 - */ - enum?: JSONSchema4Type[]; - type: JSONSchema4TypeName[]; -} - -/** - * @see https://json-schema.org/understanding-json-schema/reference/object.html - */ -export interface JSONSchema4ObjectSchema extends JSONSchema4Base { - /** - * This attribute defines a schema for all properties that are not - * explicitly defined in an object type definition. If specified, the - * value MUST be a schema or a boolean. If false is provided, no - * additional properties are allowed beyond the properties defined in - * the schema. The default value is an empty schema which allows any - * value for additional properties. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.4 - */ - additionalProperties?: boolean | JSONSchema4 | undefined; - - /** - * The `dependencies` keyword conditionally applies a sub-schema when a given - * property is present. This schema is applied in the same way `allOf` applies - * schemas. Nothing is merged or extended. Both schemas apply independently. - */ - dependencies?: Record | undefined; - - /** - * The maximum number of properties allowed for record-style schemas - */ - maxProperties?: number | undefined; - - /** - * The minimum number of properties required for record-style schemas - */ - minProperties?: number | undefined; - - /** - * This attribute is an object that defines the schema for a set of - * property names of an object instance. The name of each property of - * this attribute's object is a regular expression pattern in the ECMA - * 262/Perl 5 format, while the value is a schema. If the pattern - * matches the name of a property on the instance object, the value of - * the instance's property MUST be valid against the pattern name's - * schema value. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.3 - */ - patternProperties?: Record | undefined; - - /** - * This attribute is an object with property definitions that define the - * valid values of instance object property values. When the instance - * value is an object, the property values of the instance object MUST - * conform to the property definitions in this object. In this object, - * each property definition's value MUST be a schema, and the property's - * name MUST be the name of the instance property that it defines. The - * instance property value MUST be valid according to the schema from - * the property definition. Properties are considered unordered, the - * order of the instance properties MAY be in any order. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.2 - */ - properties?: Record | undefined; - - type: 'object'; -} - -/** - * @see https://json-schema.org/understanding-json-schema/reference/array.html - */ -export interface JSONSchema4ArraySchema extends JSONSchema4Base { - /** - * May only be defined when "items" is defined, and is a tuple of JSONSchemas. - * - * This provides a definition for additional items in an array instance - * when tuple definitions of the items is provided. This can be false - * to indicate additional items in the array are not allowed, or it can - * be a schema that defines the schema of the additional items. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.6 - */ - additionalItems?: boolean | JSONSchema4 | undefined; - - /** - * This attribute defines the allowed items in an instance array, and - * MUST be a schema or an array of schemas. The default value is an - * empty schema which allows any value for items in the instance array. - * - * When this attribute value is a schema and the instance value is an - * array, then all the items in the array MUST be valid according to the - * schema. - * - * When this attribute value is an array of schemas and the instance - * value is an array, each position in the instance array MUST conform - * to the schema in the corresponding position for this array. This - * called tuple typing. When tuple typing is used, additional items are - * allowed, disallowed, or constrained by the "additionalItems" - * (Section 5.6) attribute using the same rules as - * "additionalProperties" (Section 5.4) for objects. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.5 - */ - items?: JSONSchema4 | JSONSchema4[] | undefined; - - /** - * Defines the maximum length of an array - */ - maxItems?: number | undefined; - - /** - * Defines the minimum length of an array - */ - minItems?: number | undefined; - - type: 'array'; - - /** - * Enforces that all items in the array are unique - */ - uniqueItems?: boolean | undefined; -} - -/** - * @see https://json-schema.org/understanding-json-schema/reference/string.html - */ -export interface JSONSchema4StringSchema extends JSONSchema4Base { - enum?: string[] | undefined; - - /** - * The `format` keyword allows for basic semantic identification of certain - * kinds of string values that are commonly used. - * - * For example, because JSON doesn’t have a “DateTime” type, dates need to be - * encoded as strings. `format` allows the schema author to indicate that the - * string value should be interpreted as a date. - * - * ajv v6 provides a few built-in formats - all other strings will cause AJV - * to throw during schema compilation - */ - format?: - | 'date' - | 'date-time' - | 'email' - | 'hostname' - | 'ipv4' - | 'ipv6' - | 'json-pointer' - | 'json-pointer-uri-fragment' - | 'regex' - | 'relative-json-pointer' - | 'time' - | 'uri' - | 'uri-reference' - | 'uri-template' - | 'url' - | 'uuid' - | undefined; - - /** - * The maximum allowed length for the string - */ - maxLength?: number | undefined; - - /** - * The minimum allowed length for the string - */ - minLength?: number | undefined; - - /** - * The `pattern` keyword is used to restrict a string to a particular regular - * expression. The regular expression syntax is the one defined in JavaScript - * (ECMA 262 specifically) with Unicode support. - * - * When defining the regular expressions, it’s important to note that the - * string is considered valid if the expression matches anywhere within the - * string. For example, the regular expression "p" will match any string with - * a p in it, such as "apple" not just a string that is simply "p". Therefore, - * it is usually less confusing, as a matter of course, to surround the - * regular expression in ^...$, for example, "^p$", unless there is a good - * reason not to do so. - */ - pattern?: string | undefined; - - type: 'string'; -} - -/** - * @see https://json-schema.org/understanding-json-schema/reference/numeric.html - */ -export interface JSONSchema4NumberSchema extends JSONSchema4Base { - /** - * This provides an enumeration of all possible values that are valid - * for the instance property. This MUST be an array, and each item in - * the array represents a possible value for the instance value. If - * this attribute is defined, the instance value MUST be one of the - * values in the array in order for the schema to be valid. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 - */ - enum?: number[] | undefined; - - /** - * The exclusive minimum allowed value for the number - * - `true` = `x < maximum` - * - `false` = `x <= maximum` - * - * Default is `false` - */ - exclusiveMaximum?: boolean | undefined; - - /** - * Indicates whether or not `minimum` is the inclusive or exclusive minimum - * - `true` = `x > minimum` - * - `false` = `x ≥ minimum` - * - * Default is `false` - */ - exclusiveMinimum?: boolean | undefined; - - /** - * The maximum allowed value for the number - */ - maximum?: number | undefined; - - /** - * The minimum allowed value for the number - */ - minimum?: number | undefined; - - /** - * Numbers can be restricted to a multiple of a given number, using the - * `multipleOf` keyword. It may be set to any positive number. - */ - multipleOf?: number | undefined; - - type: 'integer' | 'number'; -} - -/** - * @see https://json-schema.org/understanding-json-schema/reference/boolean.html - */ -export interface JSONSchema4BooleanSchema extends JSONSchema4Base { - /** - * This provides an enumeration of all possible values that are valid - * for the instance property. This MUST be an array, and each item in - * the array represents a possible value for the instance value. If - * this attribute is defined, the instance value MUST be one of the - * values in the array in order for the schema to be valid. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 - */ - enum?: boolean[] | undefined; - - type: 'boolean'; -} - -/** - * @see https://json-schema.org/understanding-json-schema/reference/null.html - */ -export interface JSONSchema4NullSchema extends JSONSchema4Base { - /** - * This provides an enumeration of all possible values that are valid - * for the instance property. This MUST be an array, and each item in - * the array represents a possible value for the instance value. If - * this attribute is defined, the instance value MUST be one of the - * values in the array in order for the schema to be valid. - * - * @see https://tools.ietf.org/html/draft-zyp-json-schema-03#section-5.19 - */ - enum?: null[] | undefined; - - type: 'null'; -} - -export interface JSONSchema4AnySchema extends JSONSchema4Base { - type: 'any'; -} +// TODO: Maybe put these in a separate package too, while we're at it? + +export type { + JSONSchema4, + JSONSchema4AllOfSchema, + JSONSchema4AnyOfSchema, + JSONSchema4AnySchema, + JSONSchema4Array, + JSONSchema4ArraySchema, + JSONSchema4BooleanSchema, + JSONSchema4MultiSchema, + JSONSchema4NullSchema, + JSONSchema4NumberSchema, + JSONSchema4Object, + JSONSchema4ObjectSchema, + JSONSchema4OneOfSchema, + JSONSchema4RefSchema, + JSONSchema4StringSchema, + JSONSchema4Type, + JSONSchema4TypeExtended, + JSONSchema4TypeName, + JSONSchema4Version, +} from '@typescript-eslint/types-eslint'; diff --git a/packages/utils/src/ts-estree.ts b/packages/utils/src/ts-estree.ts index 8aca30ad7dbd..794cef380154 100644 --- a/packages/utils/src/ts-estree.ts +++ b/packages/utils/src/ts-estree.ts @@ -11,4 +11,4 @@ export type { ParserServices, ParserServicesWithoutTypeInformation, ParserServicesWithTypeInformation, -} from '@typescript-eslint/parser-services'; +} from '@typescript-eslint/types-eslint'; diff --git a/packages/utils/tsconfig.build.json b/packages/utils/tsconfig.build.json index 726fd5919df0..1a2f825ae168 100644 --- a/packages/utils/tsconfig.build.json +++ b/packages/utils/tsconfig.build.json @@ -11,6 +11,9 @@ { "path": "../types/tsconfig.build.json" }, + { + "path": "../types-eslint/tsconfig.build.json" + }, { "path": "../scope-manager/tsconfig.build.json" } diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json index bda3cfd7f502..6af493771d15 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -12,6 +12,9 @@ { "path": "../types" }, + { + "path": "../types-eslint" + }, { "path": "../scope-manager" }, diff --git a/tsconfig.json b/tsconfig.json index 39cbb87e663c..0cef6c88aeac 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -18,6 +18,7 @@ { "path": "./packages/types" }, { "path": "./packages/typescript-eslint" }, { "path": "./packages/typescript-estree" }, + { "path": "./packages/types-eslint" }, { "path": "./packages/type-utils" }, { "path": "./packages/utils" }, { "path": "./packages/visitor-keys" }, diff --git a/yarn.lock b/yarn.lock index 86050389977f..6eaa98aeb0ec 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5577,6 +5577,7 @@ __metadata: version: 0.0.0-use.local resolution: "@typescript-eslint/parser-services@workspace:packages/parser-services" dependencies: + "@typescript-eslint/types-eslint": ^8.32.0 "@typescript-eslint/typescript-estree": ^8.32.0 "@vitest/coverage-v8": ^3.1.2 debug: ^4.3.4 @@ -5611,6 +5612,35 @@ __metadata: languageName: unknown linkType: soft +"@typescript-eslint/rule-creator@workspace:packages/rule-creator": + version: 0.0.0-use.local + resolution: "@typescript-eslint/rule-creator@workspace:packages/rule-creator" + dependencies: + "@types/json-stable-stringify-without-jsonify": ^1.0.2 + "@types/lodash.merge": 4.6.9 + "@typescript-eslint/parser": 8.32.0 + "@typescript-eslint/types-eslint": 8.32.0 + "@typescript-eslint/typescript-estree": 8.32.0 + "@typescript-eslint/utils": 8.32.0 + "@vitest/coverage-v8": ^3.1.2 + ajv: ^6.12.6 + chai: ^5.2.0 + eslint-visitor-keys: ^4.2.0 + espree: ^10.3.0 + esprima: ^4.0.1 + json-stable-stringify-without-jsonify: ^1.0.1 + lodash.merge: 4.6.2 + mocha: ^11.0.0 + semver: ^7.6.0 + sinon: ^20.0.0 + source-map-support: ^0.5.21 + typescript: "*" + vitest: ^3.1.2 + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + languageName: unknown + linkType: soft + "@typescript-eslint/rule-schema-to-typescript-types@8.32.0, @typescript-eslint/rule-schema-to-typescript-types@workspace:*, @typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types": version: 0.0.0-use.local resolution: "@typescript-eslint/rule-schema-to-typescript-types@workspace:packages/rule-schema-to-typescript-types" @@ -5692,6 +5722,23 @@ __metadata: languageName: unknown linkType: soft +"@typescript-eslint/types-eslint@8.32.0, @typescript-eslint/types-eslint@^8.32.0, @typescript-eslint/types-eslint@workspace:packages/types-eslint": + version: 0.0.0-use.local + resolution: "@typescript-eslint/types-eslint@workspace:packages/types-eslint" + dependencies: + "@typescript-eslint/types": 8.32.0 + "@typescript-eslint/typescript-estree": 8.32.0 + "@typescript-eslint/visitor-keys": 8.32.0 + "@vitest/coverage-v8": ^3.1.2 + "@vitest/pretty-format": ^3.1.2 + glob: "*" + prettier: ^3.2.5 + rimraf: "*" + typescript: "*" + vitest: ^3.1.2 + languageName: unknown + linkType: soft + "@typescript-eslint/types@8.32.0, @typescript-eslint/types@^8.9.0, @typescript-eslint/types@workspace:*, @typescript-eslint/types@workspace:^, @typescript-eslint/types@workspace:packages/types": version: 0.0.0-use.local resolution: "@typescript-eslint/types@workspace:packages/types" @@ -5796,6 +5843,7 @@ __metadata: resolution: "@typescript-eslint/utils@workspace:packages/utils" dependencies: "@eslint-community/eslint-utils": ^4.7.0 + "@typescript-eslint/parser-services": 8.32.0 "@typescript-eslint/scope-manager": 8.32.0 "@typescript-eslint/types": 8.32.0 "@typescript-eslint/typescript-estree": 8.32.0 From 90c32b3a50b436e27ea5b91450eb350bbda33dfd Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 10 May 2025 22:35:58 -0400 Subject: [PATCH 3/3] Package split: rule-creator --- packages/eslint-plugin-internal/package.json | 1 + .../src/util/createRule.ts | 4 +- .../tsconfig.build.json | 3 + packages/eslint-plugin-internal/tsconfig.json | 3 + packages/eslint-plugin/package.json | 1 + packages/eslint-plugin/src/util/createRule.ts | 4 +- packages/eslint-plugin/src/util/index.ts | 1 - packages/eslint-plugin/tsconfig.build.json | 3 + packages/eslint-plugin/tsconfig.json | 3 + packages/rule-creator/LICENSE | 21 ++++++ packages/rule-creator/README.md | 3 + packages/rule-creator/package.json | 67 +++++++++++++++++++ packages/rule-creator/project.json | 16 +++++ .../src}/RuleCreator.ts | 0 .../src}/applyDefault.ts | 0 packages/rule-creator/src/deepMerge.ts | 51 ++++++++++++++ packages/rule-creator/src/index.ts | 1 + packages/rule-creator/tsconfig.build.json | 18 +++++ packages/rule-creator/tsconfig.json | 16 +++++ packages/rule-creator/tsconfig.spec.json | 26 +++++++ packages/rule-creator/vitest.config.mts | 21 ++++++ packages/utils/package.json | 1 + packages/utils/src/eslint-utils/index.ts | 5 +- packages/utils/tsconfig.build.json | 3 + packages/utils/tsconfig.json | 3 + yarn.lock | 30 +++------ 26 files changed, 279 insertions(+), 26 deletions(-) create mode 100644 packages/rule-creator/LICENSE create mode 100644 packages/rule-creator/README.md create mode 100644 packages/rule-creator/package.json create mode 100644 packages/rule-creator/project.json rename packages/{utils/src/eslint-utils => rule-creator/src}/RuleCreator.ts (100%) rename packages/{utils/src/eslint-utils => rule-creator/src}/applyDefault.ts (100%) create mode 100644 packages/rule-creator/src/deepMerge.ts create mode 100644 packages/rule-creator/src/index.ts create mode 100644 packages/rule-creator/tsconfig.build.json create mode 100644 packages/rule-creator/tsconfig.json create mode 100644 packages/rule-creator/tsconfig.spec.json create mode 100644 packages/rule-creator/vitest.config.mts diff --git a/packages/eslint-plugin-internal/package.json b/packages/eslint-plugin-internal/package.json index 458bee57df6a..e19086fef231 100644 --- a/packages/eslint-plugin-internal/package.json +++ b/packages/eslint-plugin-internal/package.json @@ -24,6 +24,7 @@ }, "dependencies": { "@prettier/sync": "^0.5.1", + "@typescript-eslint/rule-creator": "workspace:*", "@typescript-eslint/rule-tester": "workspace:*", "@typescript-eslint/scope-manager": "workspace:*", "@typescript-eslint/type-utils": "workspace:*", diff --git a/packages/eslint-plugin-internal/src/util/createRule.ts b/packages/eslint-plugin-internal/src/util/createRule.ts index 628498d08dad..4466eabd61c7 100644 --- a/packages/eslint-plugin-internal/src/util/createRule.ts +++ b/packages/eslint-plugin-internal/src/util/createRule.ts @@ -1,4 +1,4 @@ -import { ESLintUtils } from '@typescript-eslint/utils'; +import { RuleCreator } from '@typescript-eslint/rule-creator'; // note - cannot migrate this to an import statement because it will make TSC copy the package.json to the dist folder // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment @@ -8,7 +8,7 @@ export interface ESLintPluginInternalDocs { requiresTypeChecking?: true; } -export const createRule = ESLintUtils.RuleCreator( +export const createRule = RuleCreator( name => `https://github.com/typescript-eslint/typescript-eslint/blob/v${version}/packages/eslint-plugin-internal/src/rules/${name}.ts`, ); diff --git a/packages/eslint-plugin-internal/tsconfig.build.json b/packages/eslint-plugin-internal/tsconfig.build.json index f7ebbac5e0c2..2b046c51b476 100644 --- a/packages/eslint-plugin-internal/tsconfig.build.json +++ b/packages/eslint-plugin-internal/tsconfig.build.json @@ -5,6 +5,9 @@ { "path": "../type-utils/tsconfig.build.json" }, + { + "path": "../rule-creator/tsconfig.build.json" + }, { "path": "../scope-manager/tsconfig.build.json" }, diff --git a/packages/eslint-plugin-internal/tsconfig.json b/packages/eslint-plugin-internal/tsconfig.json index 9df0fb2d2e38..c0cdc3260a69 100644 --- a/packages/eslint-plugin-internal/tsconfig.json +++ b/packages/eslint-plugin-internal/tsconfig.json @@ -6,6 +6,9 @@ { "path": "../type-utils" }, + { + "path": "../rule-creator" + }, { "path": "../scope-manager" }, diff --git a/packages/eslint-plugin/package.json b/packages/eslint-plugin/package.json index f336fba2b209..e33a178dde8b 100644 --- a/packages/eslint-plugin/package.json +++ b/packages/eslint-plugin/package.json @@ -61,6 +61,7 @@ }, "dependencies": { "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/rule-creator": "8.32.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/type-utils": "8.32.0", "@typescript-eslint/utils": "8.32.0", diff --git a/packages/eslint-plugin/src/util/createRule.ts b/packages/eslint-plugin/src/util/createRule.ts index 80611a8fdb89..e92dc1d23ba1 100644 --- a/packages/eslint-plugin/src/util/createRule.ts +++ b/packages/eslint-plugin/src/util/createRule.ts @@ -1,7 +1,7 @@ -import { ESLintUtils } from '@typescript-eslint/utils'; +import { RuleCreator } from '@typescript-eslint/rule-creator'; import type { ESLintPluginDocs } from '../../rules'; -export const createRule = ESLintUtils.RuleCreator( +export const createRule = RuleCreator( name => `https://typescript-eslint.io/rules/${name}`, ); diff --git a/packages/eslint-plugin/src/util/index.ts b/packages/eslint-plugin/src/util/index.ts index 035fca0cec4a..995d97d6a445 100644 --- a/packages/eslint-plugin/src/util/index.ts +++ b/packages/eslint-plugin/src/util/index.ts @@ -34,7 +34,6 @@ export * from './truthinessUtils'; export * from '@typescript-eslint/type-utils'; export const { - applyDefault, deepMerge, getParserServices, isObjectNotArray, diff --git a/packages/eslint-plugin/tsconfig.build.json b/packages/eslint-plugin/tsconfig.build.json index 04b59df7bb50..dfa993baa1d8 100644 --- a/packages/eslint-plugin/tsconfig.build.json +++ b/packages/eslint-plugin/tsconfig.build.json @@ -5,6 +5,9 @@ { "path": "../visitor-keys/tsconfig.build.json" }, + { + "path": "../rule-creator/tsconfig.build.json" + }, { "path": "../type-utils/tsconfig.build.json" }, diff --git a/packages/eslint-plugin/tsconfig.json b/packages/eslint-plugin/tsconfig.json index 57673ed7cbf0..fd7ad5b96984 100644 --- a/packages/eslint-plugin/tsconfig.json +++ b/packages/eslint-plugin/tsconfig.json @@ -9,6 +9,9 @@ { "path": "../type-utils" }, + { + "path": "../rule-creator" + }, { "path": "../scope-manager" }, diff --git a/packages/rule-creator/LICENSE b/packages/rule-creator/LICENSE new file mode 100644 index 000000000000..310a18f8a6cb --- /dev/null +++ b/packages/rule-creator/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 typescript-eslint and other contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/rule-creator/README.md b/packages/rule-creator/README.md new file mode 100644 index 000000000000..fe79fc9c2571 --- /dev/null +++ b/packages/rule-creator/README.md @@ -0,0 +1,3 @@ +# `@typescript-eslint/rule-creator` + +TODO diff --git a/packages/rule-creator/package.json b/packages/rule-creator/package.json new file mode 100644 index 000000000000..417f9d735665 --- /dev/null +++ b/packages/rule-creator/package.json @@ -0,0 +1,67 @@ +{ + "name": "@typescript-eslint/rule-creator", + "version": "8.32.0", + "description": "TODO", + "files": [ + "dist", + "!*.tsbuildinfo", + "package.json", + "README.md", + "LICENSE" + ], + "type": "commonjs", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./package.json": "./package.json" + }, + "types": "./dist/index.d.ts", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/typescript-eslint/typescript-eslint.git", + "directory": "packages/rule-creator" + }, + "bugs": { + "url": "https://github.com/typescript-eslint/typescript-eslint/issues" + }, + "homepage": "https://typescript-eslint.io/packages/rule-creator", + "license": "MIT", + "keywords": [ + "eslint", + "typescript", + "estree" + ], + "scripts": { + "build": "tsc -b tsconfig.build.json", + "clean": "rimraf dist/ coverage/", + "clean-fixtures": "rimraf -g \"./src/**/fixtures/**/snapshots\"", + "format": "prettier --write \"./**/*.{ts,mts,cts,tsx,js,mjs,cjs,jsx,json,md,css}\" --ignore-path ../../.prettierignore", + "generate-lib": "npx nx generate-lib repo", + "lint": "npx nx lint", + "test": "vitest --run --config=$INIT_CWD/vitest.config.mts", + "check-types": "npx nx typecheck" + }, + "dependencies": { + "@typescript-eslint/types": "8.32.0", + "@typescript-eslint/visitor-keys": "8.32.0" + }, + "devDependencies": { + "@typescript-eslint/typescript-estree": "8.32.0", + "@vitest/coverage-v8": "^3.1.2", + "@vitest/pretty-format": "^3.1.2", + "glob": "*", + "prettier": "^3.2.5", + "rimraf": "*", + "typescript": "*", + "vitest": "^3.1.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } +} diff --git a/packages/rule-creator/project.json b/packages/rule-creator/project.json new file mode 100644 index 000000000000..d97cc4854dd9 --- /dev/null +++ b/packages/rule-creator/project.json @@ -0,0 +1,16 @@ +{ + "name": "rule-creator", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "root": "packages/rule-creator", + "sourceRoot": "packages/rule-creator/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"] + }, + "test": { + "executor": "@nx/vite:test" + } + } +} diff --git a/packages/utils/src/eslint-utils/RuleCreator.ts b/packages/rule-creator/src/RuleCreator.ts similarity index 100% rename from packages/utils/src/eslint-utils/RuleCreator.ts rename to packages/rule-creator/src/RuleCreator.ts diff --git a/packages/utils/src/eslint-utils/applyDefault.ts b/packages/rule-creator/src/applyDefault.ts similarity index 100% rename from packages/utils/src/eslint-utils/applyDefault.ts rename to packages/rule-creator/src/applyDefault.ts diff --git a/packages/rule-creator/src/deepMerge.ts b/packages/rule-creator/src/deepMerge.ts new file mode 100644 index 000000000000..4246b875815d --- /dev/null +++ b/packages/rule-creator/src/deepMerge.ts @@ -0,0 +1,51 @@ +// TODO: Dedupe from utils/src/eslint-utils? Separate package? + +export type ObjectLike = Record; + +/** + * Check if the variable contains an object strictly rejecting arrays + * @returns `true` if obj is an object + */ +export function isObjectNotArray(obj: unknown): obj is ObjectLike { + return typeof obj === 'object' && obj != null && !Array.isArray(obj); +} + +/** + * Pure function - doesn't mutate either parameter! + * Merges two objects together deeply, overwriting the properties in first with the properties in second + * @param first The first object + * @param second The second object + * @returns a new object + */ +export function deepMerge( + first: ObjectLike = {}, + second: ObjectLike = {}, +): Record { + // get the unique set of keys across both objects + const keys = new Set([...Object.keys(first), ...Object.keys(second)]); + + return Object.fromEntries( + [...keys].map(key => { + const firstHasKey = key in first; + const secondHasKey = key in second; + const firstValue = first[key]; + const secondValue = second[key]; + + let value; + if (firstHasKey && secondHasKey) { + if (isObjectNotArray(firstValue) && isObjectNotArray(secondValue)) { + // object type + value = deepMerge(firstValue, secondValue); + } else { + // value type + value = secondValue; + } + } else if (firstHasKey) { + value = firstValue; + } else { + value = secondValue; + } + return [key, value]; + }), + ); +} diff --git a/packages/rule-creator/src/index.ts b/packages/rule-creator/src/index.ts new file mode 100644 index 000000000000..ecac75f64d57 --- /dev/null +++ b/packages/rule-creator/src/index.ts @@ -0,0 +1 @@ +export * from './RuleCreator'; diff --git a/packages/rule-creator/tsconfig.build.json b/packages/rule-creator/tsconfig.build.json new file mode 100644 index 000000000000..32c684a7f553 --- /dev/null +++ b/packages/rule-creator/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "src", + "outDir": "dist", + "tsBuildInfoFile": "dist/tsconfig.build.tsbuildinfo", + "emitDeclarationOnly": false, + "types": ["node"] + }, + "include": ["src/**/*.ts"], + "exclude": ["vitest.config.mts", "src/**/*.spec.ts", "src/**/*.test.ts"], + "references": [ + { + "path": "../types-eslint/tsconfig.build.json" + } + ] +} diff --git a/packages/rule-creator/tsconfig.json b/packages/rule-creator/tsconfig.json new file mode 100644 index 000000000000..7b4c81fb1f51 --- /dev/null +++ b/packages/rule-creator/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "../types-eslint" + }, + { + "path": "./tsconfig.build.json" + }, + { + "path": "./tsconfig.spec.json" + } + ] +} diff --git a/packages/rule-creator/tsconfig.spec.json b/packages/rule-creator/tsconfig.spec.json new file mode 100644 index 000000000000..484d402ed5cb --- /dev/null +++ b/packages/rule-creator/tsconfig.spec.json @@ -0,0 +1,26 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc/packages/rule-creator", + "module": "NodeNext", + "resolveJsonModule": true, + "types": ["node", "vitest/globals", "vitest/importMeta"] + }, + "include": [ + "vitest.config.mts", + "package.json", + "src/**/*.test.ts", + "src/**/*.spec.ts", + "src/**/*.d.ts", + "tests" + ], + "exclude": ["**/fixtures/**"], + "references": [ + { + "path": "./tsconfig.build.json" + }, + { + "path": "../../tsconfig.spec.json" + } + ] +} diff --git a/packages/rule-creator/vitest.config.mts b/packages/rule-creator/vitest.config.mts new file mode 100644 index 000000000000..ddc038f86b56 --- /dev/null +++ b/packages/rule-creator/vitest.config.mts @@ -0,0 +1,21 @@ +import * as path from 'node:path'; +import { defineProject, mergeConfig } from 'vitest/config'; + +import { vitestBaseConfig } from '../../vitest.config.base.mjs'; +import packageJson from './package.json' with { type: 'json' }; + +const vitestConfig = mergeConfig( + vitestBaseConfig, + + defineProject({ + root: import.meta.dirname, + + test: { + dir: path.join(import.meta.dirname, 'tests'), + name: packageJson.name.replace('@typescript-eslint/', ''), + root: import.meta.dirname, + }, + }), +); + +export default vitestConfig; diff --git a/packages/utils/package.json b/packages/utils/package.json index d3f9852f2515..7ea08ae0b968 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -64,6 +64,7 @@ "dependencies": { "@eslint-community/eslint-utils": "^4.7.0", "@typescript-eslint/parser-services": "8.32.0", + "@typescript-eslint/rule-creator": "8.32.0", "@typescript-eslint/scope-manager": "8.32.0", "@typescript-eslint/types": "8.32.0", "@typescript-eslint/types-eslint": "8.32.0", diff --git a/packages/utils/src/eslint-utils/index.ts b/packages/utils/src/eslint-utils/index.ts index 632b6e051981..c12b7e7c5344 100644 --- a/packages/utils/src/eslint-utils/index.ts +++ b/packages/utils/src/eslint-utils/index.ts @@ -1,6 +1,7 @@ -export * from './applyDefault'; export * from './deepMerge'; export * from './getParserServices'; export * from './InferTypesFromRule'; export * from './nullThrows'; -export * from './RuleCreator'; + +/** @deprecated - use @typescript-eslint/rule-creator directly */ +export * from '@typescript-eslint/rule-creator'; diff --git a/packages/utils/tsconfig.build.json b/packages/utils/tsconfig.build.json index 1a2f825ae168..1e00e91c2144 100644 --- a/packages/utils/tsconfig.build.json +++ b/packages/utils/tsconfig.build.json @@ -5,6 +5,9 @@ { "path": "../parser-services/tsconfig.build.json" }, + { + "path": "../rule-creator/tsconfig.build.json" + }, { "path": "../typescript-estree/tsconfig.build.json" }, diff --git a/packages/utils/tsconfig.json b/packages/utils/tsconfig.json index 6af493771d15..4e47ed69a720 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -6,6 +6,9 @@ { "path": "../parser-services" }, + { + "path": "../rule-creator" + }, { "path": "../typescript-estree" }, diff --git a/yarn.lock b/yarn.lock index 6eaa98aeb0ec..42542cafa12b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5512,6 +5512,7 @@ __metadata: resolution: "@typescript-eslint/eslint-plugin-internal@workspace:packages/eslint-plugin-internal" dependencies: "@prettier/sync": ^0.5.1 + "@typescript-eslint/rule-creator": "workspace:*" "@typescript-eslint/rule-tester": "workspace:*" "@typescript-eslint/scope-manager": "workspace:*" "@typescript-eslint/type-utils": "workspace:*" @@ -5530,6 +5531,7 @@ __metadata: "@eslint-community/regexpp": ^4.10.0 "@types/mdast": ^4.0.3 "@types/natural-compare": "*" + "@typescript-eslint/rule-creator": 8.32.0 "@typescript-eslint/rule-schema-to-typescript-types": 8.32.0 "@typescript-eslint/rule-tester": 8.32.0 "@typescript-eslint/scope-manager": 8.32.0 @@ -5612,32 +5614,20 @@ __metadata: languageName: unknown linkType: soft -"@typescript-eslint/rule-creator@workspace:packages/rule-creator": +"@typescript-eslint/rule-creator@8.32.0, @typescript-eslint/rule-creator@workspace:*, @typescript-eslint/rule-creator@workspace:packages/rule-creator": version: 0.0.0-use.local resolution: "@typescript-eslint/rule-creator@workspace:packages/rule-creator" dependencies: - "@types/json-stable-stringify-without-jsonify": ^1.0.2 - "@types/lodash.merge": 4.6.9 - "@typescript-eslint/parser": 8.32.0 - "@typescript-eslint/types-eslint": 8.32.0 + "@typescript-eslint/types": 8.32.0 "@typescript-eslint/typescript-estree": 8.32.0 - "@typescript-eslint/utils": 8.32.0 + "@typescript-eslint/visitor-keys": 8.32.0 "@vitest/coverage-v8": ^3.1.2 - ajv: ^6.12.6 - chai: ^5.2.0 - eslint-visitor-keys: ^4.2.0 - espree: ^10.3.0 - esprima: ^4.0.1 - json-stable-stringify-without-jsonify: ^1.0.1 - lodash.merge: 4.6.2 - mocha: ^11.0.0 - semver: ^7.6.0 - sinon: ^20.0.0 - source-map-support: ^0.5.21 + "@vitest/pretty-format": ^3.1.2 + glob: "*" + prettier: ^3.2.5 + rimraf: "*" typescript: "*" vitest: ^3.1.2 - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 languageName: unknown linkType: soft @@ -5844,8 +5834,10 @@ __metadata: dependencies: "@eslint-community/eslint-utils": ^4.7.0 "@typescript-eslint/parser-services": 8.32.0 + "@typescript-eslint/rule-creator": 8.32.0 "@typescript-eslint/scope-manager": 8.32.0 "@typescript-eslint/types": 8.32.0 + "@typescript-eslint/types-eslint": 8.32.0 "@typescript-eslint/typescript-estree": 8.32.0 "@vitest/coverage-v8": ^3.1.3 prettier: ^3.2.5