Skip to content

Commit 90228e5

Browse files
authored
feat: support JSRuleDefinition type (#19604)
* feat: support `JSRuleDefinition` type * wip: remove `Rule.RuleModule` from test * wip: create more tests * wip: move `JSRuleDefinition` types to top-level export
1 parent f80b746 commit 90228e5

File tree

2 files changed

+112
-1
lines changed

2 files changed

+112
-1
lines changed

lib/types/index.d.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1262,6 +1262,29 @@ export namespace Rule {
12621262
}
12631263
}
12641264

1265+
export type JSRuleDefinitionTypeOptions = {
1266+
RuleOptions: unknown[];
1267+
MessageIds: string;
1268+
ExtRuleDocs: Record<string, unknown>;
1269+
};
1270+
1271+
export type JSRuleDefinition<
1272+
Options extends Partial<JSRuleDefinitionTypeOptions> = {},
1273+
> = RuleDefinition<
1274+
// Language specific type options (non-configurable)
1275+
{
1276+
LangOptions: Linter.LanguageOptions;
1277+
Code: SourceCode;
1278+
Visitor: Rule.NodeListener;
1279+
Node: ESTree.Node;
1280+
} & Required<
1281+
// Rule specific type options (custom)
1282+
Options &
1283+
// Rule specific type options (defaults)
1284+
Omit<JSRuleDefinitionTypeOptions, keyof Options>
1285+
>
1286+
>;
1287+
12651288
// #region Linter
12661289

12671290
export class Linter {

tests/lib/types/types.test.ts

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import {
3131
Linter,
3232
loadESLint,
3333
Rule,
34+
JSRuleDefinition,
3435
RuleTester,
3536
Scope,
3637
SourceCode,
@@ -52,7 +53,7 @@ import {
5253
StaticBlock,
5354
WhileStatement,
5455
} from "estree";
55-
import { Language, RuleDefinition } from "@eslint/core";
56+
import { Language, RuleDefinition, SettingsConfig } from "@eslint/core";
5657

5758
const SOURCE = `var foo = bar;`;
5859

@@ -809,6 +810,93 @@ type DeprecatedRuleContextKeys =
809810
},
810811
});
811812

813+
// All options optional - JSRuleDefinition and JSRuleDefinition<{}>
814+
// should be the same type.
815+
(rule1: JSRuleDefinition, rule2: JSRuleDefinition<{}>) => {
816+
rule1 satisfies typeof rule2;
817+
rule2 satisfies typeof rule1;
818+
};
819+
820+
// Type restrictions should be enforced
821+
(): JSRuleDefinition<{
822+
RuleOptions: [string, number];
823+
MessageIds: "foo" | "bar";
824+
ExtRuleDocs: { foo: string; bar: number };
825+
}> => ({
826+
meta: {
827+
messages: {
828+
foo: "FOO",
829+
830+
// @ts-expect-error Wrong type for message ID
831+
bar: 42,
832+
},
833+
docs: {
834+
foo: "FOO",
835+
836+
// @ts-expect-error Wrong type for declared property
837+
bar: "BAR",
838+
839+
// @ts-expect-error Wrong type for predefined property
840+
description: 42,
841+
},
842+
},
843+
create({ options }) {
844+
// Types for rule options
845+
options[0] satisfies string;
846+
options[1] satisfies number;
847+
848+
return {};
849+
},
850+
});
851+
852+
// Undeclared properties should produce an error
853+
(): JSRuleDefinition<{
854+
MessageIds: "foo" | "bar";
855+
ExtRuleDocs: { foo: number; bar: string };
856+
}> => ({
857+
meta: {
858+
messages: {
859+
foo: "FOO",
860+
861+
// Declared message ID is not required
862+
// bar: "BAR",
863+
864+
// @ts-expect-error Undeclared message ID is not allowed
865+
baz: "BAZ",
866+
},
867+
docs: {
868+
foo: 42,
869+
870+
// Declared property is not required
871+
// bar: "BAR",
872+
873+
// @ts-expect-error Undeclared property key is not allowed
874+
baz: "BAZ",
875+
876+
// Predefined property is allowed
877+
description: "Lorem ipsum",
878+
},
879+
},
880+
create() {
881+
return {};
882+
},
883+
});
884+
885+
(): JSRuleDefinition => ({
886+
create(context) {
887+
context.cwd satisfies string; // $ExpectType string
888+
context.filename satisfies string; // $ExpectType string
889+
context.id satisfies string; // $ExpectType string
890+
context.languageOptions satisfies Linter.LanguageOptions; // $ExpectType LanguageOptions
891+
context.options satisfies unknown[]; // $ExpectType unknown[]
892+
context.physicalFilename satisfies string; // $ExpectType string
893+
context.settings satisfies SettingsConfig; // $ExpectType SettingsConfig
894+
context.sourceCode satisfies SourceCode; // $ExpectType SourceCode
895+
896+
return {};
897+
},
898+
});
899+
812900
// #endregion
813901

814902
// #region Linter

0 commit comments

Comments
 (0)