diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 351a7a484..1ebd51424 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,10 +1,10 @@
{
- "packages/compat": "2.0.1",
+ "packages/compat": "2.0.2",
"packages/config-array": "0.23.0",
- "packages/config-helpers": "0.5.1",
- "packages/core": "1.0.1",
+ "packages/config-helpers": "0.5.2",
+ "packages/core": "1.1.0",
"packages/mcp": "0.2.0",
- "packages/migrate-config": "2.0.1",
+ "packages/migrate-config": "2.0.2",
"packages/object-schema": "3.0.0",
- "packages/plugin-kit": "0.5.1"
+ "packages/plugin-kit": "0.6.0"
}
diff --git a/README.md b/README.md
index bd28db4cd..34805e80d 100644
--- a/README.md
+++ b/README.md
@@ -33,8 +33,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/knip.json b/knip.json
index 8b84e6971..fb248cb6d 100644
--- a/knip.json
+++ b/knip.json
@@ -27,7 +27,7 @@
"project": ["src/**/*.{cts,js,ts}", "tests/*.{cts,js,ts}"]
},
"packages/object-schema": {
- "entry": ["tests/**/*.{cts,js,ts}", "src/types.ts"],
+ "entry": ["tests/**/*.{cts,js,ts}"],
"project": ["src/**/*.{cts,js,ts}", "tests/**/*.{cts,js,ts}"]
},
"packages/plugin-kit": {
diff --git a/package.json b/package.json
index bada0037f..b35111c86 100644
--- a/package.json
+++ b/package.json
@@ -44,7 +44,7 @@
"knip": "^5.62.0",
"lint-staged": "^16.0.0",
"mocha": "^11.5.0",
- "prettier": "^3.7.3",
+ "prettier": "3.8.1",
"rollup": "^4.52.3",
"typescript": "^5.8.3",
"typescript-eslint": "^8.0.0",
diff --git a/packages/compat/CHANGELOG.md b/packages/compat/CHANGELOG.md
index a952d1817..b361a1ed0 100644
--- a/packages/compat/CHANGELOG.md
+++ b/packages/compat/CHANGELOG.md
@@ -1,5 +1,19 @@
# Changelog
+## [2.0.2](https://github.com/eslint/rewrite/compare/compat-v2.0.1...compat-v2.0.2) (2026-01-29)
+
+
+### Bug Fixes
+
+* add eslint 10 as peer dependency ([#361](https://github.com/eslint/rewrite/issues/361)) ([ecb37dc](https://github.com/eslint/rewrite/commit/ecb37dcafc6513649c03f245f0f2505e7eb10dd1))
+
+
+### Dependencies
+
+* The following workspace dependencies were updated
+ * dependencies
+ * @eslint/core bumped from ^1.0.1 to ^1.1.0
+
## [2.0.1](https://github.com/eslint/rewrite/compare/compat-v2.0.0...compat-v2.0.1) (2026-01-08)
diff --git a/packages/compat/README.md b/packages/compat/README.md
index cfddbca29..64986e26f 100644
--- a/packages/compat/README.md
+++ b/packages/compat/README.md
@@ -203,8 +203,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/compat/jsr.json b/packages/compat/jsr.json
index 7f2a53fa5..b4dbbc65f 100644
--- a/packages/compat/jsr.json
+++ b/packages/compat/jsr.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/compat",
- "version": "2.0.1",
+ "version": "2.0.2",
"exports": "./dist/esm/index.js",
"publish": {
"include": [
diff --git a/packages/compat/package.json b/packages/compat/package.json
index 09893a10a..9dd1cf8b7 100644
--- a/packages/compat/package.json
+++ b/packages/compat/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/compat",
- "version": "2.0.1",
+ "version": "2.0.2",
"description": "Compatibility utilities for ESLint",
"type": "module",
"main": "dist/esm/index.js",
@@ -50,14 +50,14 @@
},
"homepage": "https://github.com/eslint/rewrite/tree/main/packages/compat#readme",
"dependencies": {
- "@eslint/core": "^1.0.1"
+ "@eslint/core": "^1.1.0"
},
"devDependencies": {
"@types/node": "^24.7.2",
"eslint": "^9.27.0"
},
"peerDependencies": {
- "eslint": "^8.40 || 9"
+ "eslint": "^8.40 || 9 || 10"
},
"peerDependenciesMeta": {
"eslint": {
diff --git a/packages/config-array/README.md b/packages/config-array/README.md
index 5603ae1e5..fb7bfeadb 100644
--- a/packages/config-array/README.md
+++ b/packages/config-array/README.md
@@ -360,8 +360,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/config-helpers/CHANGELOG.md b/packages/config-helpers/CHANGELOG.md
index 40f4d73d5..822afa70f 100644
--- a/packages/config-helpers/CHANGELOG.md
+++ b/packages/config-helpers/CHANGELOG.md
@@ -1,5 +1,14 @@
# Changelog
+## [0.5.2](https://github.com/eslint/rewrite/compare/config-helpers-v0.5.1...config-helpers-v0.5.2) (2026-01-29)
+
+
+### Dependencies
+
+* The following workspace dependencies were updated
+ * dependencies
+ * @eslint/core bumped from ^1.0.1 to ^1.1.0
+
## [0.5.1](https://github.com/eslint/rewrite/compare/config-helpers-v0.5.0...config-helpers-v0.5.1) (2026-01-08)
diff --git a/packages/config-helpers/README.md b/packages/config-helpers/README.md
index c31eaa4fc..42edbdebd 100644
--- a/packages/config-helpers/README.md
+++ b/packages/config-helpers/README.md
@@ -89,8 +89,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/config-helpers/jsr.json b/packages/config-helpers/jsr.json
index 6017258b1..216e923c1 100644
--- a/packages/config-helpers/jsr.json
+++ b/packages/config-helpers/jsr.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/config-helpers",
- "version": "0.5.1",
+ "version": "0.5.2",
"exports": "./dist/esm/index.js",
"publish": {
"include": [
diff --git a/packages/config-helpers/package.json b/packages/config-helpers/package.json
index ea8319735..9487d83f1 100644
--- a/packages/config-helpers/package.json
+++ b/packages/config-helpers/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/config-helpers",
- "version": "0.5.1",
+ "version": "0.5.2",
"description": "Helper utilities for creating ESLint configuration",
"type": "module",
"main": "dist/esm/index.js",
@@ -49,7 +49,7 @@
},
"homepage": "https://github.com/eslint/rewrite/tree/main/packages/config-helpers#readme",
"dependencies": {
- "@eslint/core": "^1.0.1"
+ "@eslint/core": "^1.1.0"
},
"devDependencies": {
"rollup-plugin-copy": "^3.5.0"
diff --git a/packages/config-helpers/tests/pnpm/pnpm-workspace.yaml b/packages/config-helpers/tests/pnpm/pnpm-workspace.yaml
new file mode 100644
index 000000000..e49fded65
--- /dev/null
+++ b/packages/config-helpers/tests/pnpm/pnpm-workspace.yaml
@@ -0,0 +1,3 @@
+overrides:
+ # Prevents an ERR_PNPM_NO_MATCHING_VERSION error when @eslint/core is bumped to a yet unpublished version.
+ "@eslint/core": file:../../../core
diff --git a/packages/core/CHANGELOG.md b/packages/core/CHANGELOG.md
index 6701fd20f..e95c4d2f7 100644
--- a/packages/core/CHANGELOG.md
+++ b/packages/core/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## [1.1.0](https://github.com/eslint/rewrite/compare/core-v1.0.1...core-v1.1.0) (2026-01-29)
+
+
+### Features
+
+* Add custom rule type helpers to `@eslint/plugin-kit` ([#355](https://github.com/eslint/rewrite/issues/355)) ([8ac8530](https://github.com/eslint/rewrite/commit/8ac853046aa1d4288d06d639be234c09988ade5e))
+
## [1.0.1](https://github.com/eslint/rewrite/compare/core-v1.0.0...core-v1.0.1) (2026-01-08)
diff --git a/packages/core/README.md b/packages/core/README.md
index 7469d712a..496c91e4f 100644
--- a/packages/core/README.md
+++ b/packages/core/README.md
@@ -21,8 +21,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/core/jsr.json b/packages/core/jsr.json
index cde9d68e6..f342dd745 100644
--- a/packages/core/jsr.json
+++ b/packages/core/jsr.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/core",
- "version": "1.0.1",
+ "version": "1.1.0",
"exports": "./dist/esm/types.d.ts",
"publish": {
"include": [
diff --git a/packages/core/package.json b/packages/core/package.json
index d473559f9..86984e2e6 100644
--- a/packages/core/package.json
+++ b/packages/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/core",
- "version": "1.0.1",
+ "version": "1.1.0",
"description": "Runtime-agnostic core of ESLint",
"type": "module",
"types": "./dist/esm/types.d.ts",
diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts
index 84e198b3e..8f3f44ddf 100644
--- a/packages/core/src/types.ts
+++ b/packages/core/src/types.ts
@@ -602,6 +602,7 @@ export interface RuleDefinition<
/**
* Defaults for non-language-related `RuleDefinition` options.
+ * @deprecated Use the same type from `@eslint/plugin-kit` instead.
*/
export interface CustomRuleTypeDefinitions {
RuleOptions: unknown[];
@@ -611,6 +612,7 @@ export interface CustomRuleTypeDefinitions {
/**
* A helper type to define language specific specializations of the `RuleDefinition` type.
+ * @deprecated Use the same type from `@eslint/plugin-kit` instead.
*
* @example
* ```ts
diff --git a/packages/mcp/README.md b/packages/mcp/README.md
index 291b0c867..3a43924c3 100644
--- a/packages/mcp/README.md
+++ b/packages/mcp/README.md
@@ -35,8 +35,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/migrate-config/CHANGELOG.md b/packages/migrate-config/CHANGELOG.md
index aca15943e..fb23e747e 100644
--- a/packages/migrate-config/CHANGELOG.md
+++ b/packages/migrate-config/CHANGELOG.md
@@ -1,5 +1,16 @@
# Changelog
+## [2.0.2](https://github.com/eslint/rewrite/compare/migrate-config-v2.0.1...migrate-config-v2.0.2) (2026-01-29)
+
+
+### Dependencies
+
+* The following workspace dependencies were updated
+ * dependencies
+ * @eslint/compat bumped from ^2.0.1 to ^2.0.2
+ * devDependencies
+ * @eslint/core bumped from ^1.0.1 to ^1.1.0
+
## [2.0.1](https://github.com/eslint/rewrite/compare/migrate-config-v2.0.0...migrate-config-v2.0.1) (2026-01-08)
diff --git a/packages/migrate-config/README.md b/packages/migrate-config/README.md
index 12ca07f51..7ed6b3e54 100644
--- a/packages/migrate-config/README.md
+++ b/packages/migrate-config/README.md
@@ -102,8 +102,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/migrate-config/package.json b/packages/migrate-config/package.json
index f4b0bd0d2..9beec7127 100644
--- a/packages/migrate-config/package.json
+++ b/packages/migrate-config/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/migrate-config",
- "version": "2.0.1",
+ "version": "2.0.2",
"description": "Configuration migration for ESLint",
"type": "module",
"bin": {
@@ -39,14 +39,14 @@
},
"homepage": "https://github.com/eslint/rewrite/tree/main/packages/migrate-config#readme",
"devDependencies": {
- "@eslint/core": "^1.0.1",
+ "@eslint/core": "^1.1.0",
"eslint": "^9.27.0"
},
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
},
"dependencies": {
- "@eslint/compat": "^2.0.1",
+ "@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"camelcase": "^8.0.0",
"espree": "^10.4.0",
diff --git a/packages/object-schema/README.md b/packages/object-schema/README.md
index 291e50b29..36ea30cbf 100644
--- a/packages/object-schema/README.md
+++ b/packages/object-schema/README.md
@@ -232,8 +232,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/plugin-kit/CHANGELOG.md b/packages/plugin-kit/CHANGELOG.md
index 5bbc0c57c..22134e4fa 100644
--- a/packages/plugin-kit/CHANGELOG.md
+++ b/packages/plugin-kit/CHANGELOG.md
@@ -1,5 +1,20 @@
# Changelog
+## [0.6.0](https://github.com/eslint/rewrite/compare/plugin-kit-v0.5.1...plugin-kit-v0.6.0) (2026-01-29)
+
+
+### Features
+
+* add `CustomRuleVisitorWithExit` type to `@eslint/plugin-kit` ([#351](https://github.com/eslint/rewrite/issues/351)) ([e7d1be4](https://github.com/eslint/rewrite/commit/e7d1be4066b38142b38e21e7877bf9b530b65ec9))
+* Add custom rule type helpers to `@eslint/plugin-kit` ([#355](https://github.com/eslint/rewrite/issues/355)) ([8ac8530](https://github.com/eslint/rewrite/commit/8ac853046aa1d4288d06d639be234c09988ade5e))
+
+
+### Dependencies
+
+* The following workspace dependencies were updated
+ * dependencies
+ * @eslint/core bumped from ^1.0.1 to ^1.1.0
+
## [0.5.1](https://github.com/eslint/rewrite/compare/plugin-kit-v0.5.0...plugin-kit-v0.5.1) (2026-01-08)
diff --git a/packages/plugin-kit/README.md b/packages/plugin-kit/README.md
index 9cfc36de7..3b6ab70ff 100644
--- a/packages/plugin-kit/README.md
+++ b/packages/plugin-kit/README.md
@@ -265,8 +265,8 @@ to get your logo on our READMEs and [website](https://eslint.org/sponsors).
Platinum Sponsors

Gold Sponsors

Silver Sponsors
-

Bronze Sponsors
-

+

Bronze Sponsors
+

Technology Sponsors
Technology sponsors allow us to use their products and services for free as part of a contribution to the open source ecosystem and our work.

diff --git a/packages/plugin-kit/jsr.json b/packages/plugin-kit/jsr.json
index cf7c0b152..5b9455139 100644
--- a/packages/plugin-kit/jsr.json
+++ b/packages/plugin-kit/jsr.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/plugin-kit",
- "version": "0.5.1",
+ "version": "0.6.0",
"exports": "./dist/esm/index.js",
"publish": {
"include": [
diff --git a/packages/plugin-kit/package.json b/packages/plugin-kit/package.json
index d3388eb4f..ca0a191bf 100644
--- a/packages/plugin-kit/package.json
+++ b/packages/plugin-kit/package.json
@@ -1,6 +1,6 @@
{
"name": "@eslint/plugin-kit",
- "version": "0.5.1",
+ "version": "0.6.0",
"description": "Utilities for building ESLint plugins.",
"author": "Nicholas C. Zakas",
"type": "module",
@@ -49,7 +49,7 @@
],
"license": "Apache-2.0",
"dependencies": {
- "@eslint/core": "^1.0.1",
+ "@eslint/core": "^1.1.0",
"levn": "^0.4.1"
},
"devDependencies": {
diff --git a/packages/plugin-kit/src/source-code.js b/packages/plugin-kit/src/source-code.js
index c02da02f3..3f661b465 100644
--- a/packages/plugin-kit/src/source-code.js
+++ b/packages/plugin-kit/src/source-code.js
@@ -19,9 +19,20 @@
/** @typedef {import("@eslint/core").DirectiveType} DirectiveType */
/** @typedef {import("@eslint/core").SourceCodeBaseTypeOptions} SourceCodeBaseTypeOptions */
/**
- * @typedef {import("@eslint/core").TextSourceCode} TextSourceCode
+ * @typedef {import("@eslint/core").TextSourceCode} TextSourceCode
* @template {SourceCodeBaseTypeOptions} [Options=SourceCodeBaseTypeOptions]
*/
+/** @typedef {import("@eslint/core").RuleVisitor} RuleVisitor */
+/**
+ * @typedef {import("./types.ts").CustomRuleVisitorWithExit} CustomRuleVisitorWithExit
+ * @template {RuleVisitor} RuleVisitorType
+ */
+/** @typedef {import("./types.ts").CustomRuleTypeDefinitions} CustomRuleTypeDefinitions */
+/**
+ * @typedef {import("./types.ts").CustomRuleDefinitionType} CustomRuleDefinitionType
+ * @template {Omit} LanguageSpecificOptions
+ * @template {Partial} Options
+ */
//-----------------------------------------------------------------------------
// Helpers
diff --git a/packages/plugin-kit/src/types.ts b/packages/plugin-kit/src/types.ts
index d3f6a888d..19a5c672c 100644
--- a/packages/plugin-kit/src/types.ts
+++ b/packages/plugin-kit/src/types.ts
@@ -3,5 +3,79 @@
* @author Nicholas C. Zakas
*/
+//------------------------------------------------------------------------------
+// Imports
+//------------------------------------------------------------------------------
+
+import type {
+ RuleDefinition,
+ RuleDefinitionTypeOptions,
+ RuleVisitor,
+} from "@eslint/core";
+
+//------------------------------------------------------------------------------
+// Exports
+//------------------------------------------------------------------------------
+
+/**
+ * Defaults for non-language-related `RuleDefinition` options.
+ */
+export interface CustomRuleTypeDefinitions {
+ RuleOptions: unknown[];
+ MessageIds: string;
+ ExtRuleDocs: Record;
+}
+
+/**
+ * A helper type to define language specific specializations of the `RuleDefinition` type.
+ *
+ * @example
+ * ```ts
+ * type YourRuleDefinition<
+ * Options extends Partial = {},
+ * > = CustomRuleDefinitionType<
+ * {
+ * LangOptions: YourLanguageOptions;
+ * Code: YourSourceCode;
+ * Visitor: YourRuleVisitor;
+ * Node: YourNode;
+ * },
+ * Options
+ * >;
+ * ```
+ */
+export type CustomRuleDefinitionType<
+ LanguageSpecificOptions extends Omit<
+ RuleDefinitionTypeOptions,
+ keyof CustomRuleTypeDefinitions
+ >,
+ Options extends Partial,
+> = RuleDefinition<
+ // Language specific type options (non-configurable)
+ LanguageSpecificOptions &
+ Required<
+ // Rule specific type options (custom)
+ Options &
+ // Rule specific type options (defaults)
+ Omit
+ >
+>;
+
+/**
+ * Adds matching `:exit` selector properties for each key of a `RuleVisitor`.
+ */
+export type CustomRuleVisitorWithExit = {
+ [Key in keyof RuleVisitorType as
+ | Key
+ | `${Key & string}:exit`]: RuleVisitorType[Key];
+};
+
+/**
+ * A map of names to string values, or `null` when no value is provided.
+ */
export type StringConfig = Record;
+
+/**
+ * A map of names to boolean flags.
+ */
export type BooleanConfig = Record;
diff --git a/packages/plugin-kit/tests/types/types.test.ts b/packages/plugin-kit/tests/types/types.test.ts
index 0f2eaa0de..53868c5aa 100644
--- a/packages/plugin-kit/tests/types/types.test.ts
+++ b/packages/plugin-kit/tests/types/types.test.ts
@@ -7,16 +7,20 @@
// Imports
//-----------------------------------------------------------------------------
+import type { LanguageOptions, RuleVisitor } from "@eslint/core";
import {
- BooleanConfig,
+ type BooleanConfig,
CallMethodStep,
ConfigCommentParser,
+ type CustomRuleDefinitionType,
+ type CustomRuleTypeDefinitions,
+ type CustomRuleVisitorWithExit,
Directive,
- DirectiveType,
- RulesConfig,
- SourceLocation,
- SourceRange,
- StringConfig,
+ type DirectiveType,
+ type RulesConfig,
+ type SourceLocation,
+ type SourceRange,
+ type StringConfig,
TextSourceCodeBase,
VisitNodeStep,
} from "@eslint/plugin-kit";
@@ -182,3 +186,168 @@ step1.kind satisfies 1;
step1.phase satisfies 1 | 2;
step1.target satisfies object;
step1.type satisfies "visit";
+
+// CustomRuleDefinitionType
+interface TestNode {
+ type: string;
+ start: number;
+}
+
+interface TestLanguageOptions extends LanguageOptions {
+ ecmaVersion?: number;
+}
+
+interface TestRuleVisitor extends RuleVisitor {
+ Foo?: (node: TestNode) => void;
+}
+
+type TestRuleDefinition<
+ Options extends Partial =
+ CustomRuleTypeDefinitions,
+> = CustomRuleDefinitionType<
+ {
+ LangOptions: TestLanguageOptions;
+ Code: TestTextSourceCode;
+ Visitor: TestRuleVisitor;
+ Node: TestNode;
+ },
+ Options
+>;
+
+const testRule: TestRuleDefinition<{
+ RuleOptions: [{ foo: string; bar: number }];
+ MessageIds: "badFoo" | "wrongBar";
+ ExtRuleDocs: { foo: boolean; bar: number };
+}> = {
+ meta: {
+ type: "problem",
+ fixable: "code",
+ docs: {
+ recommended: true,
+ foo: true,
+ // @ts-expect-error -- bar should be number, not string
+ bar: "1",
+ },
+ deprecated: {
+ message: "use something else",
+ url: "https://example.com",
+ replacedBy: [
+ {
+ message: "use this instead",
+ url: "https://example.com",
+ rule: {
+ name: "new-rule",
+ url: "https://example.com/rules/new-rule",
+ },
+ plugin: {
+ name: "new-plugin",
+ url: "https://example.com/plugins/new-plugin",
+ },
+ },
+ ],
+ },
+ schema: [
+ {
+ type: "object",
+ properties: {
+ foo: {
+ type: "string",
+ },
+ bar: {
+ type: "integer",
+ },
+ },
+ additionalProperties: false,
+ },
+ ],
+ defaultOptions: [
+ {
+ foo: "always",
+ bar: 5,
+ // @ts-expect-error -- invalid default option "baz"
+ baz: "invalid",
+ },
+ ],
+ messages: {
+ badFoo: "change this foo",
+ wrongBar: "fix this bar",
+ // @ts-expect-error -- invalid message id "baz"
+ baz: "invalid message",
+ },
+ language: "javascript",
+ dialects: ["javascript", "typescript"],
+ },
+
+ create(context) {
+ context.languageOptions.ecmaVersion satisfies number | undefined;
+ context.options satisfies [{ foo: string; bar: number }];
+ context.sourceCode satisfies TestTextSourceCode;
+
+ return {
+ Foo(node) {
+ if (context.options[0].foo === "always") {
+ context.report({
+ messageId: "badFoo",
+ loc: {
+ start: { line: node.start, column: 1 },
+ end: { line: node.start + 1, column: Infinity },
+ },
+ });
+ }
+ },
+ };
+ },
+};
+
+type Rule1 = TestRuleDefinition;
+type Rule2 = TestRuleDefinition<{}>;
+type Rule3 = TestRuleDefinition<{
+ RuleOptions: [number, string];
+ MessageIds: "foo" | "bar";
+ ExtRuleDocs: { baz: number; qux: string };
+}>;
+// @ts-expect-error -- non-object not allowed
+type Rule4 = TestRuleDefinition;
+// @ts-expect-error -- non-customizable properties not allowed
+type Rule5 = TestRuleDefinition<{ Code: TestTextSourceCode }>;
+// @ts-expect-error -- undefined value not allowed for optional property
+type Rule6 = TestRuleDefinition<{ RuleOptions: undefined }>;
+
+// CustomRuleVisitorWithExit
+type TestVisitor = {
+ Program: (node: { type: "Program" }) => void;
+ Identifier: (node: { type: "Identifier"; name: string }) => void;
+ "FunctionDeclaration > Identifier": (node: { type: "Identifier" }) => void;
+};
+
+type VisitorWithExit = CustomRuleVisitorWithExit;
+
+const visitor: VisitorWithExit = {
+ Program(node) {
+ node.type satisfies "Program";
+ },
+ Identifier(node) {
+ node.type satisfies "Identifier";
+ node.name satisfies string;
+ },
+ "FunctionDeclaration > Identifier"(node) {
+ node.type satisfies "Identifier";
+ },
+ "Program:exit"(node) {
+ node.type satisfies "Program";
+ },
+ "Identifier:exit"(node) {
+ node.type satisfies "Identifier";
+ node.name satisfies string;
+ },
+ "FunctionDeclaration > Identifier:exit"(node) {
+ node.type satisfies "Identifier";
+ },
+ // @ts-expect-error -- Extra keys should not be allowed
+ Foo() {},
+};
+
+visitor.Program satisfies TestVisitor["Program"];
+visitor["Program:exit"] satisfies TestVisitor["Program"];
+// @ts-expect-error -- Exit key must correspond to an existing selector
+visitor["Expression:exit"] = () => {};
diff --git a/tools/build-cts.js b/tools/build-cts.js
index 35a976bb8..bed0ae74a 100644
--- a/tools/build-cts.js
+++ b/tools/build-cts.js
@@ -24,9 +24,6 @@ if (!newFilename) {
}
const oldSourceText = await readFile(filename, "utf-8");
-const newSourceText = oldSourceText.replaceAll(
- ' from "./types.ts";\n',
- ' from "./types.cts";\n',
-);
+const newSourceText = oldSourceText.replaceAll('"./types.ts"', '"./types.cts"');
await writeFile(newFilename, newSourceText);