Skip to content

feat(linter/eslint): implement id-match rule#22379

Merged
camc314 merged 6 commits into
oxc-project:mainfrom
v-sayapin:feat-linter-id-match
May 18, 2026
Merged

feat(linter/eslint): implement id-match rule#22379
camc314 merged 6 commits into
oxc-project:mainfrom
v-sayapin:feat-linter-id-match

Conversation

@v-sayapin

@v-sayapin v-sayapin commented May 13, 2026

Copy link
Copy Markdown
Contributor

This PR implements the eslint/id-match rule, which enforces a configured naming regex for identifiers

ESLint ref: https://eslint.org/docs/latest/rules/id-match

Issue: #479

Behavior Differences from ESLint

This implementation is intentionally stricter in two cases:

  • Computed destructuring keys are checked, for example const { [bad_name]: x } = obj and ({ [bad_name]: x } = obj), because the computed key is a normal reference expression, not a binding introduced by destructuring
  • With properties enabled, ordinary top-level dynamic import option keys are checked, for example import("x", { bad_option: true }). Import attributes inside with { ... } are still ignored

TypeScript

TypeScript syntax is supported on a best-effort basis for identifiers that flow through the same visited AST node kinds and transparent wrappers such as as, satisfies, non-null assertions, and instantiation expressions

This is not a replacement for @typescript-eslint/naming-convention or future tsgolint naming-convention work: oxc-project/tsgolint#186

Regex Compatibility

The pattern is compiled with Rust regex syntax. JavaScript-specific regex features such as lookaround and backreferences are not supported. Unicode escapes should use Rust syntax, for example \u{XXXX}

Algorithmic Complexity

The generated rule runner limits the hot path to identifier-like AST nodes:

  • BindingIdentifier
  • IdentifierReference
  • IdentifierName
  • PrivateIdentifier
  • LabelIdentifier

Each visited identifier first runs the regex check and returns immediately when the name matches

For non-default configurations, the hot path is linear in the total length of checked identifier names, with additional ancestor/context checks only for failed regex matches

Space complexity is O(1) beyond the compiled regex and options. The hot path does not allocate unless a diagnostic is emitted

The default pattern ^.+$ matches every non-empty identifier name, so should_run skips rule work entirely for the default configuration

AI Disclosure

Claude Opus 4.7 & Codex GPT 5.5

  • Code review
  • Comparison with ESLint ref rule behavior
  • Discussion of edge cases
  • Writing and validating tests

@v-sayapin v-sayapin requested a review from camc314 as a code owner May 13, 2026 10:42
@v-sayapin

Copy link
Copy Markdown
Contributor Author

@codex review, use the repository skill $performance-lint-rules

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Nice work!

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@camc314 camc314 self-assigned this May 13, 2026
@codspeed-hq

codspeed-hq Bot commented May 14, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 4 untouched benchmarks
⏩ 47 skipped benchmarks1


Comparing v-sayapin:feat-linter-id-match (2473807) with main (0f26de6)

Open in CodSpeed

Footnotes

  1. 47 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

@v-sayapin v-sayapin marked this pull request as draft May 15, 2026 23:05
@v-sayapin v-sayapin force-pushed the feat-linter-id-match branch from 40503c6 to 6759565 Compare May 17, 2026 11:21
@v-sayapin v-sayapin marked this pull request as ready for review May 17, 2026 11:21
@v-sayapin v-sayapin requested a review from overlookmotel as a code owner May 17, 2026 11:21
Comment thread crates/oxc_linter/src/rules/eslint/id_match.rs
Comment thread crates/oxc_linter/src/rules/eslint/id_match.rs Outdated
Comment thread crates/oxc_linter/src/rules/eslint/id_match.rs Outdated
Comment thread crates/oxc_linter/src/rules/eslint/id_match.rs Outdated
@camc314 camc314 requested a review from Copilot May 18, 2026 09:00

@camc314 camc314 left a comment

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.

thank you!

@camc314 camc314 merged commit 0440b0f into oxc-project:main May 18, 2026
28 checks passed

Copilot AI left a comment

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.

Pull request overview

Implements the ESLint id-match rule in oxc_linter, enforcing a configurable identifier naming regex (with options for class fields, properties, destructuring behavior, and declarations-only mode), and wires it into the generated rule registry + published schemas.

Changes:

  • Add eslint/id-match rule implementation with extensive JS/TS test coverage and snapshots.
  • Introduce deserialize_required_regex_option helper for required regex string config parsing.
  • Register the new rule across generated enums/runners and update configuration schema/snapshots.

Reviewed changes

Copilot reviewed 8 out of 10 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tasks/website_linter/src/snapshots/schema_json.snap Adds id-match to the website schema snapshot rule list.
npm/oxlint/configuration_schema.json Adds id-match to the published configuration schema rule list.
crates/oxc_linter/src/utils/config.rs Adds deserialize_required_regex_option helper for pattern deserialization.
crates/oxc_linter/src/snapshots/eslint_id_match.snap Adds snapshot output for the JS/TSX coverage of id-match.
crates/oxc_linter/src/snapshots/eslint_id_match@ts.snap Adds snapshot output for TS-specific coverage of id-match.
crates/oxc_linter/src/rules/eslint/id_match.rs New rule implementation + unit tests and config validation tests.
crates/oxc_linter/src/rules.rs Exposes the eslint::id_match module.
crates/oxc_linter/src/generated/rules_enum.rs Registers EslintIdMatch in the generated rule enum/dispatch.
crates/oxc_linter/src/generated/rule_runner_impls.rs Adds the rule runner node-type bitset for id-match.
apps/oxlint/src-js/package/config.generated.ts Adds id-match to the generated JS config typings.

Comment thread crates/oxc_linter/src/rules/eslint/id_match.rs
Comment thread crates/oxc_linter/src/rules/eslint/id_match.rs
Comment thread crates/oxc_linter/src/rules/eslint/id_match.rs
camc314 pushed a commit that referenced this pull request May 18, 2026
# Oxlint
### 🚀 Features

- 1ae291e linter/no-underscore-dangle: Add `allowInUsingDeclarations`
option (#22483) (吴杨帆)
- 0440b0f linter/eslint: Implement `id-match` rule (#22379) (Vladislav
Sayapin)
- 65bf119 linter: Implement react no-object-type-as-default-prop
(#22481) (uhyo)
- 2a6ddce linter/eslint: Implement `no-implied-eval` rule (#22391)
(Vladislav Sayapin)
- d3a3c1d linter: Auto detect agents from CLI and transition to the
agent output format (#22068) (Jovi De Croock)
- 625758a linter/vitest: Implement padding-around-after-all-blocks rule
(#21788) (kapobajza)
- 37680b0 linter: Implement react no-unstable-nested-components (#22248)
(Jovi De Croock)
- d8d9c74 linter: Implement import/newline-after-import rule (#19142)
(Ryuya Yanagi)

### 🐛 Bug Fixes

- 3f59e03 linter: Only call rayon/miette/tracing inits once (#21899)
(Matiss Janis Aboltins)
- 602dfd6 linter/promise/no-return-wrap: Detect Promise calls in all
branches (#22474) (zennnnnnn11)
- e182aee linter: Allow dialogs and popovers for no_autofocus (#22289)
(mehm8128)
- 7ffb710 linter/jest/vitest: Jest/no-standalone-expect ignores
additionalTestBlockFunctions option for jest/vitest hooks (#22477)
(kapobajza)
- c6f2d3f linter: Add more expression support for iframe-has-title
(#22460) (mehm8128)
- 5747ff1 linter: Avoid enabling jest with vitest plugin (#22499)
(camc314)
- 863984f linter/no-find-dom-node: Run on all files (#22479) (bab)

### ⚡ Performance

- 2afef79 linter: Optimize `no-loop-func` (#22491) (camchenry)
- 4c9ca72 oxlint: Align walker thread count with rayon pool (#22494)
(Boshen)

### 📚 Documentation

- f7967c7 linter/id-match: Clarify `onlyDeclarations` config docs
(#22523) (camc314)
- 1e0c97f linter: Fix closing code block in documentation for
`padding-around-after-all-blocks` rule. (#22513) (connorshea)
- a9049fd linter: Exclude directly provide autoFocus to dialog pattern
(#22510) (mehm8128)
# Oxfmt
### 🐛 Bug Fixes

- 8ee946f formatter/sort_imports: Use label to classify lines (#22512)
(leaysgur)
- 8c1da44 formatter: Normalize destructuring keys in DCR (#22478)
(camc314)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants