Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change Request: Update RuleVisitor interface #134

Open
1 of 7 tasks
nzakas opened this issue Nov 22, 2024 · 0 comments
Open
1 of 7 tasks

Change Request: Update RuleVisitor interface #134

nzakas opened this issue Nov 22, 2024 · 0 comments
Labels
enhancement New feature or request

Comments

@nzakas
Copy link
Member

nzakas commented Nov 22, 2024

Which packages would you like to change?

  • @eslint/compat
  • @eslint/config-array
  • @eslint/core
  • @eslint/migrate-config
  • @eslint/object-schema
  • @eslint/plugin-kit

What problem do you want to solve?

The RuleVisitor interface is currently defined as follows:

export interface RuleVisitor {
	/**
	 * Called for each node in the AST or at specific times during the traversal.
	 */
	[key: string]: (...args: any[]) => void;
}

However, this is causing problems when trying to extend RuleVisitor under strict TypeScript mode, as seen in these PRs:

The errors take the form of the following:

error TS2411: Property 'Document' of type '((node: DocumentNode$1) => void) | undefined' is not assignable to 'string' index type '(...args: any[]) => void'.

What do you think is the correct solution?

The problem is that the method defined in RuleVisitor is not optional.

I can see a few different options:

  1. Remove all methods. We can remove any predefined methods from RuleVisitor and leave essentially a blank interface:
export interface RuleVisitor {
	/**
	 * Called for each node in the AST or at specific times during the traversal.
	 */
-	[key: string]: (...args: any[]) => void;
}

That would give consumers something to extend from so that it logically looks like there's some relationship between the core types and consumer types. I'm not sure it's valuable.

  1. Convert to a mapped type. We can change it to a mapped type as suggested by @fasttime here:
- export interface RuleVisitor {
+ export type RuleVisitor = {
	/**
	 * Called for each node in the AST or at specific times during the traversal.
	 */
-	[key: string]: (...args: any[]) => void;
+	[key in string]?: (...args: any[]) => void;
}

Defining all methods to be optional also seems to make RuleVisitor mostly useless.

  1. Eliminate RuleVisitor interface completely. Because we don't know what the visitor will look like for any particular language, maybe it's a bad idea to try and enforce anything in particular. We could just define the RuleDefinitionTypeOptions#Visitor as Object, which would allow any non-primitive type to be used, and then we don't need RuleVisitor at all:
export interface RuleDefinitionTypeOptions {
	LangOptions: LanguageOptions;
	Code: SourceCode;
	RuleOptions: unknown[];
-	Visitor: RuleVisitor;
+	Visitor: Object;
	Node: unknown;
	MessageIds: string;
	ExtRuleDocs: unknown;
}

I think this is my favorite approach, but I'd like some insights from @JoshuaKGoldberg and @fasttime on all of the options and their ramifications.

Participation

  • I am willing to submit a pull request for this change.

Additional comments

No response

@nzakas nzakas added the enhancement New feature or request label Nov 22, 2024
@github-project-automation github-project-automation bot moved this to Needs Triage in Triage Nov 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: Needs Triage
Development

No branches or pull requests

1 participant