Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/plugin-kit/src/source-code.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@
* @typedef {import("@eslint/core").TextSourceCode<Options>} TextSourceCode<Options>
* @template {SourceCodeBaseTypeOptions} [Options=SourceCodeBaseTypeOptions]
*/
/** @typedef {import("@eslint/core").RuleVisitor} RuleVisitor */
/**
* @typedef {import("./types.ts").CustomRuleVisitorWithExit<RuleVisitorType>} CustomRuleVisitorWithExit<RuleVisitorType>
* @template {RuleVisitor} RuleVisitorType
*/

//-----------------------------------------------------------------------------
// Helpers
Expand Down
26 changes: 26 additions & 0 deletions packages/plugin-kit/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,31 @@
* @author Nicholas C. Zakas
*/

//------------------------------------------------------------------------------
// Imports
//------------------------------------------------------------------------------

import type { RuleVisitor } from "@eslint/core";

//------------------------------------------------------------------------------
// Exports
//------------------------------------------------------------------------------

/**
* Adds matching `:exit` selector properties for each key of a `RuleVisitor`.
*/
export type CustomRuleVisitorWithExit<RuleVisitorType extends RuleVisitor> = {
[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<string, string | null>;

/**
* A map of names to boolean flags.
*/
export type BooleanConfig = Record<string, boolean>;
51 changes: 45 additions & 6 deletions packages/plugin-kit/tests/types/types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,16 @@
//-----------------------------------------------------------------------------

import {
BooleanConfig,
type BooleanConfig,
CallMethodStep,
ConfigCommentParser,
type CustomRuleVisitorWithExit,
Directive,
DirectiveType,
RulesConfig,
SourceLocation,
SourceRange,
StringConfig,
type DirectiveType,
type RulesConfig,
type SourceLocation,
type SourceRange,
type StringConfig,
TextSourceCodeBase,
VisitNodeStep,
} from "@eslint/plugin-kit";
Expand Down Expand Up @@ -182,3 +183,41 @@ step1.kind satisfies 1;
step1.phase satisfies 1 | 2;
step1.target satisfies object;
step1.type satisfies "visit";

type TestVisitor = {
Program: (node: { type: "Program" }) => void;
Identifier: (node: { type: "Identifier"; name: string }) => void;
"FunctionDeclaration > Identifier": (node: { type: "Identifier" }) => void;
};

type VisitorWithExit = CustomRuleVisitorWithExit<TestVisitor>;

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"] = () => {};
5 changes: 1 addition & 4 deletions tools/build-cts.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);