diff --git a/packages/compat/package.json b/packages/compat/package.json index 70975dbd9..e1ae32fbf 100644 --- a/packages/compat/package.json +++ b/packages/compat/package.json @@ -48,8 +48,10 @@ "url": "https://github.com/eslint/rewrite/issues" }, "homepage": "https://github.com/eslint/rewrite/tree/main/packages/compat#readme", + "dependencies": { + "@eslint/core": "^0.15.2" + }, "devDependencies": { - "@eslint/core": "^0.15.2", "eslint": "^9.27.0" }, "peerDependencies": { diff --git a/packages/compat/src/fixup-rules.js b/packages/compat/src/fixup-rules.js index 34752d56a..aedd1a759 100644 --- a/packages/compat/src/fixup-rules.js +++ b/packages/compat/src/fixup-rules.js @@ -7,10 +7,10 @@ // Types //----------------------------------------------------------------------------- -/** @typedef {import("eslint").ESLint.Plugin} FixupPluginDefinition */ -/** @typedef {import("eslint").Rule.RuleModule} FixupRuleDefinition */ +/** @typedef {import("@eslint/core").Plugin} FixupPluginDefinition */ +/** @typedef {import("@eslint/core").RuleDefinition} FixupRuleDefinition */ /** @typedef {FixupRuleDefinition["create"]} FixupLegacyRuleDefinition */ -/** @typedef {import("eslint").Linter.Config} FixupConfig */ +/** @typedef {import("@eslint/core").ConfigObject} FixupConfig */ /** @typedef {Array} FixupConfigArray */ //----------------------------------------------------------------------------- diff --git a/packages/compat/src/ignore-file.js b/packages/compat/src/ignore-file.js index c5f996bf0..69fdf0fb8 100644 --- a/packages/compat/src/ignore-file.js +++ b/packages/compat/src/ignore-file.js @@ -14,7 +14,7 @@ import path from "node:path"; // Types //----------------------------------------------------------------------------- -/** @typedef {import("eslint").Linter.Config} FlatConfig */ +/** @typedef {import("@eslint/core").ConfigObject} FlatConfig */ //----------------------------------------------------------------------------- // Exports diff --git a/packages/config-helpers/package.json b/packages/config-helpers/package.json index 5e4388bef..b600de625 100644 --- a/packages/config-helpers/package.json +++ b/packages/config-helpers/package.json @@ -46,8 +46,10 @@ "url": "https://github.com/eslint/rewrite/issues" }, "homepage": "https://github.com/eslint/rewrite/tree/main/packages/config-helpers#readme", + "dependencies": { + "@eslint/core": "^0.15.2" + }, "devDependencies": { - "@eslint/core": "^0.15.2", "eslint": "^9.27.0", "rollup-plugin-copy": "^3.5.0" }, diff --git a/packages/config-helpers/src/define-config.js b/packages/config-helpers/src/define-config.js index eaf06f85b..3054020c0 100644 --- a/packages/config-helpers/src/define-config.js +++ b/packages/config-helpers/src/define-config.js @@ -7,10 +7,10 @@ // Type Definitions //----------------------------------------------------------------------------- -/** @typedef {import("eslint").Linter.Config} Config */ -/** @typedef {import("eslint").Linter.LegacyConfig} LegacyConfig */ -/** @typedef {import("eslint").ESLint.Plugin} Plugin */ -/** @typedef {import("eslint").Linter.RuleEntry} RuleEntry */ +/** @typedef {import("@eslint/core").ConfigObject} Config */ +/** @typedef {import("@eslint/core").LegacyConfigObject} LegacyConfig */ +/** @typedef {import("@eslint/core").Plugin} Plugin */ +/** @typedef {import("@eslint/core").RuleConfig} RuleConfig */ /** @typedef {import("./types.ts").ExtendsElement} ExtendsElement */ /** @typedef {import("./types.ts").SimpleExtendsElement} SimpleExtendsElement */ /** @typedef {import("./types.ts").ConfigWithExtends} ConfigWithExtends */ @@ -153,7 +153,7 @@ function normalizePluginConfig(userNamespace, plugin, config) { if (result.rules) { const ruleIds = Object.keys(result.rules); - /** @type {Record} */ + /** @type {Record} */ const newRules = {}; for (let i = 0; i < ruleIds.length; i++) { diff --git a/packages/config-helpers/src/global-ignores.js b/packages/config-helpers/src/global-ignores.js index 062bb15d4..b351b0cbe 100644 --- a/packages/config-helpers/src/global-ignores.js +++ b/packages/config-helpers/src/global-ignores.js @@ -7,7 +7,7 @@ // Type Definitions //----------------------------------------------------------------------------- -/** @typedef {import("eslint").Linter.Config} Config */ +/** @typedef {import("@eslint/core").ConfigObject} Config */ //----------------------------------------------------------------------------- // Helpers diff --git a/packages/config-helpers/src/types.ts b/packages/config-helpers/src/types.ts index 084f7b280..a313ea259 100644 --- a/packages/config-helpers/src/types.ts +++ b/packages/config-helpers/src/types.ts @@ -2,7 +2,7 @@ * @fileoverview Types for this package. */ -import type { Linter } from "eslint"; +import type { ConfigObject } from "@eslint/core"; /** * Infinite array type. @@ -12,19 +12,17 @@ export type InfiniteArray = T | InfiniteArray[]; /** * The type of array element in the `extends` property after flattening. */ -export type SimpleExtendsElement = string | Linter.Config; +export type SimpleExtendsElement = string | ConfigObject; /** * The type of array element in the `extends` property before flattening. */ -export type ExtendsElement = - | SimpleExtendsElement - | InfiniteArray; +export type ExtendsElement = SimpleExtendsElement | InfiniteArray; /** * Config with extends. Valid only inside of `defineConfig()`. */ -export interface ConfigWithExtends extends Linter.Config { +export interface ConfigWithExtends extends ConfigObject { extends?: ExtendsElement[]; } diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 7020f6f4a..5611f314d 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -542,6 +542,64 @@ type SuggestionMessage = { desc: string } | { messageId: string }; */ export type SuggestedEdit = SuggestedEditBase & SuggestionMessage; +/** + * The normalized version of a lint suggestion. + */ +interface LintSuggestion { + /** A short description. */ + desc: string; + + /** Fix result info. */ + fix: RuleTextEdit; + + /** Id referencing a message for the description. */ + messageId?: string | undefined; +} + +/** + * The normalized version of a lint violation message. + */ +export interface LintMessage { + /** The 1-based column number. */ + column: number; + + /** The 1-based line number. */ + line: number; + + /** The 1-based column number of the end location. */ + endColumn?: number | undefined; + + /** The 1-based line number of the end location. */ + endLine?: number | undefined; + + /** The ID of the rule which makes this message. */ + ruleId: string | null; + + /** The reported message. */ + message: string; + + /** The ID of the message in the rule's meta. */ + messageId?: string | undefined; + + /** + * Type of node. + * @deprecated `nodeType` is deprecated and will be removed in the next major version. + */ + nodeType?: string | undefined; + + /** If `true` then this is a fatal error. */ + fatal?: true | undefined; + + /** The severity of this message. */ + severity: Exclude; + + /** Information for autofix. */ + fix?: RuleTextEdit | undefined; + + /** Information for suggestions. */ + suggestions?: LintSuggestion[] | undefined; +} + // #endregion /** @@ -636,6 +694,8 @@ export type CustomRuleDefinitionType< // Config //------------------------------------------------------------------------------ +// #region Severities + /** * The human readable severity level used in a configuration. */ @@ -655,6 +715,24 @@ export type SeverityLevel = 0 | 1 | 2; */ export type Severity = SeverityName | SeverityLevel; +// #endregion + +/** + * Represents the metadata for an object, such as a plugin or processor. + */ +export interface ObjectMetaProperties { + /** @deprecated Use `meta.name` instead. */ + name?: string | undefined; + + /** @deprecated Use `meta.version` instead. */ + version?: string | undefined; + + meta?: { + name?: string | undefined; + version?: string | undefined; + }; +} + /** * Represents the configuration options for the core linter. */ @@ -699,6 +777,392 @@ export interface SettingsConfig { } /* eslint-enable @typescript-eslint/consistent-indexed-object-style -- needed to allow extension */ +/** + * The configuration for a set of files. + */ +export interface ConfigObject { + /** + * A string to identify the configuration object. Used in error messages and + * inspection tools. + */ + name?: string; + + /** + * Path to the directory where the configuration object should apply. + * `files` and `ignores` patterns in the configuration object are + * interpreted as relative to this path. + */ + basePath?: string; + + /** + * An array of glob patterns indicating the files that the configuration + * object should apply to. If not specified, the configuration object applies + * to all files + */ + files?: (string | string[])[]; + + /** + * An array of glob patterns indicating the files that the configuration + * object should not apply to. If not specified, the configuration object + * applies to all files matched by files + */ + ignores?: string[]; + + /** + * The name of the language used for linting. This is used to determine the + * parser and other language-specific settings. + * @since 9.7.0 + */ + language?: string; + + /** + * An object containing settings related to how the language is configured for + * linting. + */ + languageOptions?: LanguageOptions; + + /** + * An object containing settings related to the linting process + */ + linterOptions?: LinterOptionsConfig; + + /** + * Either an object containing preprocess() and postprocess() methods or a + * string indicating the name of a processor inside of a plugin + * (i.e., "pluginName/processorName"). + */ + processor?: string | Processor; + + /** + * An object containing a name-value mapping of plugin names to plugin objects. + * When files is specified, these plugins are only available to the matching files. + */ + plugins?: Record; + + /** + * An object containing the configured rules. When files or ignores are specified, + * these rule configurations are only available to the matching files. + */ + rules?: Partial; + + /** + * An object containing name-value pairs of information that should be + * available to all rules. + */ + settings?: Record; +} + +//------------------------------------------------------------------------------ +// Legacy Config +// https://eslint.org/docs/latest/use/configure/configuration-files#legacy-config +//------------------------------------------------------------------------------ + +/* eslint-disable @typescript-eslint/consistent-indexed-object-style, @typescript-eslint/no-explicit-any -- needed for backward compatibility */ + +/** @deprecated Only supported in legacy eslintrc config format. */ +export type GlobalAccess = + | boolean + | "off" + | "readable" + | "readonly" + | "writable" + | "writeable"; + +/** @deprecated Only supported in legacy eslintrc config format. */ +export interface GlobalsConfig { + [name: string]: GlobalAccess; +} + +/** + * The ECMAScript version of the code being linted. + * @deprecated Only supported in legacy eslintrc config format. + */ +export type EcmaVersion = + | 3 + | 5 + | 6 + | 7 + | 8 + | 9 + | 10 + | 11 + | 12 + | 13 + | 14 + | 15 + | 16 + | 17 + | 2015 + | 2016 + | 2017 + | 2018 + | 2019 + | 2020 + | 2021 + | 2022 + | 2023 + | 2024 + | 2025 + | 2026 + | "latest"; + +/** + * The type of JavaScript source code. + * @deprecated Only supported in legacy eslintrc config format. + */ +type JavaScriptSourceType = "script" | "module" | "commonjs"; + +/** + * Parser options. + * @deprecated Only supported in legacy eslintrc config format. + * @see [Specifying Parser Options](https://eslint.org/docs/latest/use/configure/language-options#specifying-parser-options) + */ +export interface JavaScriptParserOptionsConfig { + /** + * Allow the use of reserved words as identifiers (if `ecmaVersion` is 3). + * + * @default false + */ + allowReserved?: boolean | undefined; + + /** + * Accepts any valid ECMAScript version number or `'latest'`: + * + * - A version: es3, es5, es6, es7, es8, es9, es10, es11, es12, es13, es14, ..., or + * - A year: es2015, es2016, es2017, es2018, es2019, es2020, es2021, es2022, es2023, ..., or + * - `'latest'` + * + * When it's a version or a year, the value must be a number - so do not include the `es` prefix. + * + * Specifies the version of ECMAScript syntax you want to use. This is used by the parser to determine how to perform scope analysis, and it affects the default + * + * @default 5 + */ + ecmaVersion?: EcmaVersion | undefined; + + /** + * The type of JavaScript source code. Possible values are "script" for + * traditional script files, "module" for ECMAScript modules (ESM), and + * "commonjs" for CommonJS files. + * + * @default 'script' + * + * @see https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-parser-options + */ + sourceType?: JavaScriptSourceType | undefined; + + /** + * An object indicating which additional language features you'd like to use. + * + * @see https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-parser-options + */ + ecmaFeatures?: + | { + globalReturn?: boolean | undefined; + impliedStrict?: boolean | undefined; + jsx?: boolean | undefined; + experimentalObjectRestSpread?: boolean | undefined; + [key: string]: any; + } + | undefined; + [key: string]: any; +} + +/** @deprecated Only supported in legacy eslintrc config format. */ +export interface EnvironmentConfig { + /** The definition of global variables. */ + globals?: GlobalsConfig | undefined; + + /** The parser options that will be enabled under this environment. */ + parserOptions?: JavaScriptParserOptionsConfig | undefined; +} + +/** + * A configuration object that may have a `rules` block. + */ +interface HasRules { + rules?: Partial | undefined; +} + +/** + * ESLint legacy configuration. + * + * @see [ESLint Legacy Configuration](https://eslint.org/docs/latest/use/configure/) + */ +interface BaseConfig< + Rules extends RulesConfig = RulesConfig, + OverrideRules extends RulesConfig = Rules, +> extends HasRules { + $schema?: string | undefined; + + /** + * An environment provides predefined global variables. + * + * @see [Environments](https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-environments) + */ + env?: { [name: string]: boolean } | undefined; + + /** + * Extending configuration files. + * + * @see [Extends](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#extending-configuration-files) + */ + extends?: string | string[] | undefined; + + /** + * Specifying globals. + * + * @see [Globals](https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-globals) + */ + globals?: GlobalsConfig | undefined; + + /** + * Disable processing of inline comments. + * + * @see [Disabling Inline Comments](https://eslint.org/docs/latest/use/configure/rules-deprecated#disabling-inline-comments) + */ + noInlineConfig?: boolean | undefined; + + /** + * Overrides can be used to use a differing configuration for matching sub-directories and files. + * + * @see [How do overrides work](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#how-do-overrides-work) + */ + overrides?: ConfigOverride[] | undefined; + + /** + * Parser. + * + * @see [Working with Custom Parsers](https://eslint.org/docs/latest/extend/custom-parsers) + * @see [Specifying Parser](https://eslint.org/docs/latest/use/configure/parser-deprecated) + */ + parser?: string | undefined; + + /** + * Parser options. + * + * @see [Working with Custom Parsers](https://eslint.org/docs/latest/extend/custom-parsers) + * @see [Specifying Parser Options](https://eslint.org/docs/latest/use/configure/language-options-deprecated#specifying-parser-options) + */ + parserOptions?: JavaScriptParserOptionsConfig | undefined; + + /** + * Which third-party plugins define additional rules, environments, configs, etc. for ESLint to use. + * + * @see [Configuring Plugins](https://eslint.org/docs/latest/use/configure/plugins-deprecated#configure-plugins) + */ + plugins?: string[] | undefined; + + /** + * Specifying processor. + * + * @see [processor](https://eslint.org/docs/latest/use/configure/plugins-deprecated#specify-a-processor) + */ + processor?: string | undefined; + + /** + * Report unused eslint-disable comments as warning. + * + * @see [Report unused eslint-disable comments](https://eslint.org/docs/latest/use/configure/rules-deprecated#report-unused-eslint-disable-comments) + */ + reportUnusedDisableDirectives?: boolean | undefined; + + /** + * Settings. + * + * @see [Settings](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#adding-shared-settings) + */ + settings?: SettingsConfig | undefined; +} + +/** + * The overwrites that apply more differing configuration to specific files or directories. + */ +export interface ConfigOverride + extends BaseConfig { + /** + * The glob patterns for excluded files. + */ + excludedFiles?: string | string[] | undefined; + + /** + * The glob patterns for target files. + */ + files: string | string[]; +} + +/** + * ESLint legacy configuration. + * + * @see [ESLint Legacy Configuration](https://eslint.org/docs/latest/use/configure/) + */ +// https://github.com/eslint/eslint/blob/v8.57.0/conf/config-schema.js +export interface LegacyConfigObject< + Rules extends RulesConfig = RulesConfig, + OverrideRules extends RulesConfig = Rules, +> extends BaseConfig { + /** + * Tell ESLint to ignore specific files and directories. + * + * @see [Ignore Patterns](https://eslint.org/docs/latest/use/configure/ignore-deprecated#ignorepatterns-in-config-files) + */ + ignorePatterns?: string | string[] | undefined; + + /** + * @see [Using Configuration Files](https://eslint.org/docs/latest/use/configure/configuration-files-deprecated#using-configuration-files) + */ + root?: boolean | undefined; +} + +/* eslint-enable @typescript-eslint/consistent-indexed-object-style, @typescript-eslint/no-explicit-any -- needed for backward compatibility */ + +//------------------------------------------------------------------------------ +// Processors +// https://eslint.org/docs/latest/extend/plugins#processors-in-plugins +//------------------------------------------------------------------------------ + +/** + * File information passed to a processor. + */ +export interface ProcessorFile { + text: string; + filename: string; +} + +/** + * A processor is an object that can preprocess and postprocess files. + */ +export interface Processor< + T extends string | ProcessorFile = string | ProcessorFile, +> extends ObjectMetaProperties { + /** If `true` then it means the processor supports autofix. */ + supportsAutofix?: boolean | undefined; + + /** The function to extract code blocks. */ + preprocess?(text: string, filename: string): T[]; + + /** The function to merge messages. */ + postprocess?(messages: LintMessage[][], filename: string): LintMessage[]; +} + +//------------------------------------------------------------------------------ +// Plugins +// https://eslint.org/docs/latest/extend/plugins +//------------------------------------------------------------------------------ + +export interface Plugin extends ObjectMetaProperties { + meta?: ObjectMetaProperties["meta"] & { + namespace?: string | undefined; + }; + configs?: + | Record + | undefined; + environments?: Record | undefined; + languages?: Record | undefined; + processors?: Record | undefined; + rules?: Record | undefined; +} + //------------------------------------------------------------------------------ // Languages //------------------------------------------------------------------------------ diff --git a/packages/core/tests/types/types.test.ts b/packages/core/tests/types/types.test.ts index 57595338e..eb1122ace 100644 --- a/packages/core/tests/types/types.test.ts +++ b/packages/core/tests/types/types.test.ts @@ -34,6 +34,8 @@ import type { TraversalStep, } from "@eslint/core"; +import type { Linter } from "eslint"; + //----------------------------------------------------------------------------- // Helper types //----------------------------------------------------------------------------- @@ -430,3 +432,54 @@ export const shouldAllowRecommendedObject: RulesMetaDocs = { someKey: "some value", }, }; + +//------------------------------------------------------------------------------ +// Tests for config object types +//------------------------------------------------------------------------------ + +import type { ConfigObject, LegacyConfigObject } from "@eslint/core"; + +// Example ConfigObject (flat config) +const configObjectExample: ConfigObject = { + name: "example config", + files: ["**/*.js", ["**/*.ts", "**/src/*.*"]], + ignores: ["**/vendor/**"], + language: "js/js", + languageOptions: { + ecmaVersion: 2022, + sourceType: "module", + }, + linterOptions: { + noInlineConfig: false, + reportUnusedDisableDirectives: true, + }, + plugins: { + custom: { meta: { name: "custom-plugin", version: "1.0.0" } }, + }, + rules: { + "no-console": "warn", + eqeqeq: ["error", "always"], + }, + settings: { + foo: "bar", + }, +}; + +// check back compat +const oldConfigObjectExample: Linter.Config = configObjectExample; + +// Example LegacyConfigObject (eslintrc config) +const legacyConfigObjectExample: LegacyConfigObject = { + $schema: "https://json.schemastore.org/eslintrc", + env: { node: true, es2021: true }, + extends: ["eslint:recommended", "plugin:custom/recommended"], + globals: { myGlobal: "readonly", foo: "writable", bar: "off" }, + rules: { + "no-console": 2, + eqeqeq: ["error", "always"], + }, +}; + +// check back compat +const oldLegacyConfigObjectExample: Linter.LegacyConfig = + legacyConfigObjectExample; diff --git a/packages/migrate-config/package.json b/packages/migrate-config/package.json index 20436650c..d7c68c8a1 100644 --- a/packages/migrate-config/package.json +++ b/packages/migrate-config/package.json @@ -39,7 +39,7 @@ }, "homepage": "https://github.com/eslint/rewrite/tree/main/packages/migrate-config#readme", "devDependencies": { - "@types/eslint": "^9.6.0", + "@eslint/core": "^0.15.2", "eslint": "^9.27.0" }, "engines": { diff --git a/packages/migrate-config/src/migrate-config.js b/packages/migrate-config/src/migrate-config.js index c3093279e..a52683928 100644 --- a/packages/migrate-config/src/migrate-config.js +++ b/packages/migrate-config/src/migrate-config.js @@ -19,9 +19,9 @@ import * as espree from "espree"; // Types //----------------------------------------------------------------------------- -/** @typedef {import("eslint").Linter.FlatConfig} FlatConfig */ -/** @typedef {import("eslint").Linter.LegacyConfig} LegacyConfig */ -/** @typedef {import("eslint").Linter.ConfigOverride} ConfigOverride */ +/** @typedef {import("@eslint/core").ConfigObject} FlatConfig */ +/** @typedef {import("@eslint/core").LegacyConfigObject} LegacyConfig */ +/** @typedef {import("@eslint/core").ConfigOverride} ConfigOverride */ /** @typedef {import("recast").types.namedTypes.ObjectExpression} ObjectExpression */ /** @typedef {import("recast").types.namedTypes.ArrayExpression} ArrayExpression */ /** @typedef {import("recast").types.namedTypes.CallExpression} CallExpression */