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/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/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/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/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..825b494abf6c --- /dev/null +++ b/packages/parser-services/package.json @@ -0,0 +1,66 @@ +{ + "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/types-eslint": "^8.32.0", + "@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 89% rename from packages/typescript-estree/src/createParserServices.ts rename to packages/parser-services/src/createParserServices.ts index ee6f18915d9c..d6da57c32edb 100644 --- a/packages/typescript-estree/src/createParserServices.ts +++ b/packages/parser-services/src/createParserServices.ts @@ -1,8 +1,7 @@ +import { ParserServices } from '@typescript-eslint/types-eslint'; +import { ASTMaps } from '@typescript-eslint/typescript-estree'; import type * as ts from 'typescript'; -import type { ASTMaps } from './convert'; -import type { ParserServices } from './parser-options'; - export function createParserServices( astMaps: ASTMaps, program: ts.Program | null, diff --git a/packages/parser-services/src/index.ts b/packages/parser-services/src/index.ts new file mode 100644 index 000000000000..1a2306afa7a5 --- /dev/null +++ b/packages/parser-services/src/index.ts @@ -0,0 +1,5 @@ +export * from './clear-caches'; +export { getCanonicalFileName } from './create-program/shared'; +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..6b79c3376501 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 '@typescript-eslint/types-eslint'; +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/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..4c747629e66f --- /dev/null +++ b/packages/parser-services/tsconfig.build.json @@ -0,0 +1,20 @@ +{ + "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": "../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 new file mode 100644 index 000000000000..e5d40828187b --- /dev/null +++ b/packages/parser-services/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/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..9bb87e85c34d 100644 --- a/packages/parser/src/index.ts +++ b/packages/parser/src/index.ts @@ -1,12 +1,14 @@ +export type { + ParserServices, + ParserServicesWithoutTypeInformation, + ParserServicesWithTypeInformation, +} from '@typescript-eslint/types-eslint'; export { parse, parseForESLint, type ParserOptions } from './parser'; export { clearCaches, createProgram, - type ParserServices, - type ParserServicesWithoutTypeInformation, - type ParserServicesWithTypeInformation, 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..d8a9dd3a2a6a 100644 --- a/packages/parser/src/parser.ts +++ b/packages/parser/src/parser.ts @@ -1,18 +1,19 @@ +import type { ParserServices } from '@typescript-eslint/types-eslint'; + +import { + AST, + parseAndGenerateServices, +} 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/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 96% rename from packages/utils/src/eslint-utils/RuleCreator.ts rename to packages/rule-creator/src/RuleCreator.ts index cd06aee6231f..7ea670cc7c56 100644 --- a/packages/utils/src/eslint-utils/RuleCreator.ts +++ b/packages/rule-creator/src/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/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/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/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/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/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/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/types-eslint/src/ParserServices.ts b/packages/types-eslint/src/ParserServices.ts new file mode 100644 index 000000000000..8facb6cdb0a8 --- /dev/null +++ b/packages/types-eslint/src/ParserServices.ts @@ -0,0 +1,33 @@ +import { + ParserServicesNodeMaps, + TSESTree, +} 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; + 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/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/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..7ea08ae0b968 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -63,8 +63,11 @@ }, "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" }, "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/getParserServices.ts b/packages/utils/src/eslint-utils/getParserServices.ts index 1581638f58d8..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 '../ts-estree'; +} from '@typescript-eslint/types-eslint'; import { parserSeemsToBeTSESLint } from './parserSeemsToBeTSESLint'; 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/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 6c61253a1f05..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/typescript-estree'; +} from '@typescript-eslint/types-eslint'; diff --git a/packages/utils/tsconfig.build.json b/packages/utils/tsconfig.build.json index f99a3f7e1b40..1e00e91c2144 100644 --- a/packages/utils/tsconfig.build.json +++ b/packages/utils/tsconfig.build.json @@ -2,12 +2,21 @@ "extends": "../../tsconfig.build.json", "compilerOptions": {}, "references": [ + { + "path": "../parser-services/tsconfig.build.json" + }, + { + "path": "../rule-creator/tsconfig.build.json" + }, { "path": "../typescript-estree/tsconfig.build.json" }, { "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 bda7a07530ab..4e47ed69a720 100644 --- a/packages/utils/tsconfig.json +++ b/packages/utils/tsconfig.json @@ -3,12 +3,21 @@ "files": [], "include": [], "references": [ + { + "path": "../parser-services" + }, + { + "path": "../rule-creator" + }, { "path": "../typescript-estree" }, { "path": "../types" }, + { + "path": "../types-eslint" + }, { "path": "../scope-manager" }, diff --git a/tsconfig.json b/tsconfig.json index 5a3d4d28b9e8..0cef6c88aeac 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,12 +11,14 @@ { "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" }, { "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 0b52f47c9fe5..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 @@ -5573,10 +5575,28 @@ __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/types-eslint": ^8.32.0 + "@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 @@ -5594,6 +5614,23 @@ __metadata: languageName: unknown linkType: soft +"@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: + "@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/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" @@ -5675,6 +5712,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" @@ -5752,7 +5806,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 +5815,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: "*" @@ -5781,8 +5833,11 @@ __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/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 pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy