Skip to content

feat: Add getPossibleTypesForSelectorClass to Language interface#148

Open
Kuldeep2822k wants to merge 7 commits into
eslint:mainfrom
Kuldeep2822k:2026-selector-class-types
Open

feat: Add getPossibleTypesForSelectorClass to Language interface#148
Kuldeep2822k wants to merge 7 commits into
eslint:mainfrom
Kuldeep2822k:2026-selector-class-types

Conversation

@Kuldeep2822k
Copy link
Copy Markdown

Summary

Add an optional getPossibleTypesForSelectorClass(className) method to the Language interface that allows languages to declare which AST node types could match a given pseudo-class selector (e.g., :function). This removes hardcoded JavaScript-specific logic from the core selector analysis in lib/linter/esquery.js and enables any language plugin to provide the same optimization.

Related Issues

  • Discussion #20856 — Original discussion: "Should we move JS-specific ESQuery analysis logic into the Language interface?"
  • RFC #99 — ESLint Language Plugins (introduced the Language interface)
  • esquery External class resolve PR — The mechanism that enabled matchesSelectorClass()

@eslint-github-bot
Copy link
Copy Markdown

Hi @Kuldeep2822k!, thanks for the Pull Request

The pull request title isn't properly formatted. We ask that you update the pull request title to match this format, as we use it to generate changelogs and automate releases.

  • The commit message tag wasn't recognized. Did you mean "docs", "fix", or "feat"?
  • There should be a space following the initial tag and colon, for example 'feat: Message'.
  • The first letter of the tag should be in lowercase

To Fix: You can fix this problem by clicking 'Edit' next to the pull request title at the top of this page.

Read more about contributing to ESLint here

@Kuldeep2822k Kuldeep2822k changed the title New: Add getPossibleTypesForSelectorClass to Language interface feat: Add getPossibleTypesForSelectorClass to Language interface May 23, 2026
@Kuldeep2822k Kuldeep2822k marked this pull request as draft May 23, 2026 18:36
@Kuldeep2822k Kuldeep2822k marked this pull request as ready for review May 23, 2026 18:51

## Help Needed

I am willing to submit a pull request with the reference implementation for this RFC once it is accepted. Performance benchmarking (using `npm run test:performance`) will be done to confirm there is no regression.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tested the performance with and without the current switch case for "class" in analyzeParsedSelector using npm run test:performance. There was no difference as no core rule uses the :function selector, so we would need another benchmark for this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right — no core rule uses :function, so test:performance can't exercise this path. I've dropped that reference from the RFC. The architectural framing (delegating static-analysis ownership to the language plugin) was always the primary motivation here .

fallback: vk.getKeys,
matchClass: this.#language.matchesSelectorClass ?? (() => false),
nodeTypeKey: this.#language.nodeTypeKey,
+ language: this.#language,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The other properties and methods from this.#language are passed directly, so why pass the whole language instead of only getPossibleTypesForSelectorClass?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point, you're right. I'll switch to passing only the method.
The reason I had it as the full language was the cache — it's currently a WeakMap keyed by language object. Since the JS language exports a singleton and getSelectorClassNodeTypes is a stable reference, I can key the cache on the method instead and keep the pattern consistent:
js getSelectorClassNodeTypes: this.#language.getSelectorClassNodeTypes,
Pushing an update shortl

const noLanguageCache = new Map();

function getLanguageCache(language) {
if (!language) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The language is always set, so there is no need for noLanguageCache.

- ];
- }
- return null;
+ return language?.getPossibleTypesForSelectorClass?.(selector.name) ?? null;
Copy link
Copy Markdown
Contributor

@DMartens DMartens May 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
+ return language?.getPossibleTypesForSelectorClass?.(selector.name) ?? null;
+ return language.getPossibleTypesForSelectorClass?.(selector.name) ?? null;

The language cannot be nullish.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants