Skip to content

refactor: improve group matching computation#733

Draft
hugop95 wants to merge 21 commits into
azat-io:mainfrom
hugop95:refactor/groups
Draft

refactor: improve group matching computation#733
hugop95 wants to merge 21 commits into
azat-io:mainfrom
hugop95:refactor/groups

Conversation

@hugop95
Copy link
Copy Markdown
Contributor

@hugop95 hugop95 commented Apr 5, 2026

Description

oxlint's implementation of group matching is technically a bit more elegant than the current one.

  • The current approach asked: "Here are all names this element could be called. Which one did the user configure?
  • The new approach asks: "Here are the groups the user actually configured, sorted by specificity. Which one does this element match?"

The current approach, in theory, is opening a known and accepted possibility for permutation explosion. Performance impact was mitigated through caching.

/**
* Generates all permutations of an array. This allows variations like
* `'abstract-override-protected-get-method'`,
* `'override-protected-abstract-get-method'`,
* `'protected-abstract-override-get-method'`, etc., to be entered by the user
* and always match the same group. Note that this can theoretically cause
* performance issues if too many modifiers are entered at once (e.g., 8
* modifiers result in 40,320 permutations, 9 in 362,880).
*
* @param elements - The array of elements to permute.
* @returns An array containing all permutations of the input elements.
*/
function getPermutations(elements: string[]): string[][] {

In practice, this was very unlikely/impossible due to the number of possible modifiers.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 5, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b2ec3f70-78e0-4292-993c-25bf523252ae

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The PR refactors the group computation system across ~40 rule files and utilities. It removes module-level caching mechanisms (cachedGroupsByModifiersAndSelectors) and standalone utility functions (generatePredefinedGroups, computeGroup), replacing them with a new GroupMatcher class that encapsulates group computation logic. Each rule now instantiates a GroupMatcher once and delegates group computation to it.

Changes

Cohort / File(s) Summary
Core Utilities - Group Computation
utils/group-matcher.ts
Added new GroupMatcher class that centralizes group computation logic with support for custom group matching, predefined group generation, and selector/modifier matching.
Removed Core Utilities
utils/compute-group.ts, utils/generate-predefined-groups.ts, utils/get-array-combinations.ts
Deleted obsolete group computation utilities that are now superseded by GroupMatcher functionality.
Updated Type System
utils/does-custom-group-match.ts
Simplified function signature by consolidating parameters into a single typed object; updated generic type handling for custom group matching.
Sort Arrays Family
rules/sort-array-includes.ts, rules/sort-arrays.ts, rules/sort-arrays/sort-array.ts, rules/sort-arrays/types.ts
Removed module-level cache and replaced computeGroup calls with GroupMatcher instance; added allModifiers constant to types.
Sort Classes
rules/sort-classes/sort-class.ts, rules/sort-classes/types.ts
Replaced generatePredefinedGroups + computeGroup flow with GroupMatcher; reordered allSelectors and allModifiers constants for class members and modifiers.
Sort Decorators
rules/sort-decorators.ts, rules/sort-decorators/types.ts
Refactored to instantiate GroupMatcher per rule execution; updated function signature to accept single parameters object; exported AdditionalSortOptions, allSelectors, allModifiers, and Selector/Modifier types.
Sort Enums
rules/sort-enums/sort-enum.ts, rules/sort-enums/types.ts
Switched group configuration validation to use full allSelectors/allModifiers instead of empty arrays; instantiated GroupMatcher for group computation.
Sort Exports
rules/sort-exports.ts
Removed module-level cache; instantiated GroupMatcher once per rule creation; replaced computeGroup calls with groupMatcher.computeGroup(...).
Sort Heritage Clauses
rules/sort-heritage-clauses/sort-heritage-clause.ts, rules/sort-heritage-clauses/types.ts
Updated to validate using full selector/modifier sets; instantiated GroupMatcher; added allSelectors, allModifiers, and derived Selector/Modifier types.
Sort Import Attributes
rules/sort-import-attributes/sort-import-or-export-attributes.ts, rules/sort-import-attributes/types.ts
Replaced cache/precomputation flow with GroupMatcher; added exported allSelectors/allModifiers and Selector/Modifier types.
Sort Imports
rules/sort-imports.ts, rules/sort-imports/types.ts
Removed module-level cache and custom helper computeGroupExceptUnknown; instantiated GroupMatcher per rule; reordered allSelectors and allModifiers constants.
Sort Intersection Types
rules/sort-intersection-types.ts
Removed module-level cachedGroupsByModifiersAndSelectors cache variable.
Sort JSX Props
rules/sort-jsx-props/sort-jsx-object.ts
Removed local cache and generatePredefinedGroups flow; instantiated GroupMatcher once per invocation; updated group computation call signature.
Sort Maps
rules/sort-maps/sort-potential-map.ts, rules/sort-maps/types.ts
Updated validation to use full selector/modifier sets; instantiated GroupMatcher; added allSelectors, allModifiers, and derived union types.
Sort Modules
rules/sort-modules.ts, rules/sort-modules/types.ts
Replaced cache/precomputation with GroupMatcher; threaded matcher through recursive calls; exported CustomGroupMatchOptions interface and AdditionalSortOptions type.
Sort Named Exports
rules/sort-named-exports/sort-named-export.ts
Removed module-level cache; instantiated GroupMatcher per invocation; updated group computation to use groupMatcher.computeGroup(...).
Sort Named Imports
rules/sort-named-imports/sort-named-import.ts
Removed module-level cache; replaced computeGroup with GroupMatcher.computeGroup; adjusted selector/modifier parameter passing.
Sort Object Types
rules/sort-object-types/sort-object-type-elements.ts, rules/sort-object-types/types.ts
Removed file-level cache and generatePredefinedGroups import; instantiated GroupMatcher; reordered allSelectors and allModifiers constants.
Sort Objects
rules/sort-objects/sort-object.ts, rules/sort-objects/types.ts
Removed module-level predefined-group caching; instantiated per-invocation GroupMatcher; reordered allSelectors constant.
Sort Sets
rules/sort-sets.ts
Removed module-level cachedGroupsByModifiersAndSelectors cache variable.
Sort Union Types
rules/sort-union-types.ts, rules/sort-union-types/sort-union-or-intersection-types.ts, rules/sort-union-types/types.ts
Removed module-level cache; replaced function signature to remove cachedGroupsByModifiersAndSelectors parameter; instantiated GroupMatcher; added allModifiers constant and derived Modifier type.
Sort Variable Declarations
rules/sort-variable-declarations/sort-variable-declaration.ts, rules/sort-variable-declarations/types.ts
Removed file-level cache; updated validation to use full allModifiers; instantiated GroupMatcher; added allModifiers constant to types.
Test Changes
test/utils/compute-group.test.ts, test/utils/generate-predefined-groups.test.ts, test/utils/get-array-combinations.test.ts
Deleted test suites for removed utilities (computeGroup, generatePredefinedGroups, getArrayCombinations).
Test Updates
test/utils/does-custom-group-match.test.ts, test/utils/validate-groups-configuration.test.ts
Updated does-custom-group-match tests to include groupName field in custom group objects; inlined getArrayCombinations helper in validation tests.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~75 minutes

Possibly related PRs

  • PR #720: Modifies the group-computation/caching logic in union/intersection sorting; directly overlaps with changes to rules/sort-union-types/* files.
  • PR #705: Refactors rules/sort-classes/sort-class.ts group computation; same file scope as this PR's class-sorting changes.
  • PR #629: Introduces/updates allSelectors/allModifiers constants and derives Selector/Modifier types from them; aligns with this PR's type system changes.

Suggested reviewers

  • azat-io
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'refactor: improve group matching computation' clearly and concisely describes the main change—refactoring the group matching logic to use a new computation approach. It accurately reflects the primary objective without being overly verbose or generic.
Description check ✅ Passed The PR description provides good context with a reference to the oxlint implementation and explains the problem/solution clearly. However, it lacks explicit mention of the testing approach and is missing some sections from the template like 'Reviewer notes' which are marked optional.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@hugop95 hugop95 marked this pull request as ready for review April 5, 2026 09:43
@hugop95 hugop95 marked this pull request as draft April 5, 2026 09:43
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 5, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (2dbe189) to head (0006fa6).

Additional details and impacted files
@@            Coverage Diff            @@
##              main      #733   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files          224       224           
  Lines         4400      4416   +16     
  Branches      1375      1374    -1     
=========================================
+ Hits          4400      4416   +16     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (2)
rules/sort-imports/types.ts (1)

151-162: Add precedence regression tests for this reordered selector/modifier registry.

Because GroupMatcher compares by selector/modifier index, this reorder changes matching priority. Please lock expected precedence with focused rule tests for overlapping cases (e.g., imports that can satisfy both type/path/style-related groups).

Also applies to: 174-180

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/sort-imports/types.ts` around lines 151 - 162, The reordered
selector/modifier registry in rules/sort-imports/types.ts (the array containing
'type','side-effect-style','side-effect','style','tsconfig-path','index','sibling','parent','subpath','internal','builtin','external')
changes GroupMatcher's index-based precedence; add focused regression tests that
assert exact matching priority for overlapping import cases (e.g., imports that
could match both 'type' and 'tsconfig-path', 'style' and 'side-effect-style', or
'internal' vs 'external') to lock the new order, and duplicate the same targeted
precedence tests for the other reordered block referenced around the second
region (lines 174-180) so future reorderings will fail the tests if precedence
changes.
rules/sort-classes/types.ts (1)

133-143: Please pin the new class-member precedence with targeted overlap tests.

This reorder is behavioral under GroupMatcher index-based comparison. Adding focused tests for overlapping matches (e.g., generic vs specialized selectors, multi-modifier matches) will protect the intended ordering semantics.

Also applies to: 149-161

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/sort-classes/types.ts` around lines 133 - 143, The new ordering in the
class-member precedence list (allSelectors) introduces behavioral changes under
GroupMatcher index-based comparison; add focused unit tests that pin this
ordering by asserting overlap resolution between generic and specialized
selectors and multi-modifier combinations. Create targeted tests that exercise
overlapping cases (e.g., 'property' vs 'function-property', 'method' vs
'get-method'/'set-method', static vs instance matches) to ensure the
GroupMatcher picks the intended selector by index; also add the same style of
overlap tests for the second selector array in this module to cover both changed
lists. Ensure tests are deterministic by constructing minimal class/member
examples that match multiple selectors and asserting the expected selector is
chosen.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@rules/sort-decorators.ts`:
- Around line 98-155: The visitor calls to sortDecorators (in the Decorator
visitor and the PropertyDefinition, AccessorProperty, MethodDefinition,
ClassDeclaration handlers) do not pass the selector/modifier context, causing
the grouping logic to see selectors:[] and modifiers:[] and miss
selector/modifier-specific groups; update each call (including the Decorator
branch that handles parameter decorators and the calls that use
getNodeDecorators) to pass the node's selector (e.g., "parameter" for the
Decorator/parameter case, "property", "accessor", "method", "class" for the
respective handlers) and the node's modifier metadata
(static/readonly/visibility/etc.) to sortDecorators so the groupMatcher can
match selector- or modifier-scoped groups. Ensure the Decorator branch that
inspects decorator.parent/FunctionExpression uses the parameter selector and
that calls using getNodeDecorators forward the originating AST node or an
extracted { selector, modifiers } object into sortDecorators.

In `@rules/sort-modules/types.ts`:
- Around line 103-110: The array allModifiers was reordered and that changes the
predefined-group naming surface; revert the change by restoring the original
sequence so 'async' and 'decorated' remain in their previous positions (i.e.,
keep allModifiers as it was before the refactor) so existing groups/customGroups
string matches are preserved; ensure the exported type Modifier remains derived
from (typeof allModifiers)[number] and do not alter ordering unless you provide
an explicit migration path for groups/customGroups entries.

---

Nitpick comments:
In `@rules/sort-classes/types.ts`:
- Around line 133-143: The new ordering in the class-member precedence list
(allSelectors) introduces behavioral changes under GroupMatcher index-based
comparison; add focused unit tests that pin this ordering by asserting overlap
resolution between generic and specialized selectors and multi-modifier
combinations. Create targeted tests that exercise overlapping cases (e.g.,
'property' vs 'function-property', 'method' vs 'get-method'/'set-method', static
vs instance matches) to ensure the GroupMatcher picks the intended selector by
index; also add the same style of overlap tests for the second selector array in
this module to cover both changed lists. Ensure tests are deterministic by
constructing minimal class/member examples that match multiple selectors and
asserting the expected selector is chosen.

In `@rules/sort-imports/types.ts`:
- Around line 151-162: The reordered selector/modifier registry in
rules/sort-imports/types.ts (the array containing
'type','side-effect-style','side-effect','style','tsconfig-path','index','sibling','parent','subpath','internal','builtin','external')
changes GroupMatcher's index-based precedence; add focused regression tests that
assert exact matching priority for overlapping import cases (e.g., imports that
could match both 'type' and 'tsconfig-path', 'style' and 'side-effect-style', or
'internal' vs 'external') to lock the new order, and duplicate the same targeted
precedence tests for the other reordered block referenced around the second
region (lines 174-180) so future reorderings will fail the tests if precedence
changes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e8fe8a24-9463-4f81-ab22-e8e27a749345

📥 Commits

Reviewing files that changed from the base of the PR and between b98c82d and 007d1d8.

📒 Files selected for processing (45)
  • rules/sort-array-includes.ts
  • rules/sort-arrays.ts
  • rules/sort-arrays/sort-array.ts
  • rules/sort-arrays/types.ts
  • rules/sort-classes/sort-class.ts
  • rules/sort-classes/types.ts
  • rules/sort-decorators.ts
  • rules/sort-decorators/types.ts
  • rules/sort-enums/sort-enum.ts
  • rules/sort-enums/types.ts
  • rules/sort-exports.ts
  • rules/sort-heritage-clauses/sort-heritage-clause.ts
  • rules/sort-heritage-clauses/types.ts
  • rules/sort-import-attributes/sort-import-or-export-attributes.ts
  • rules/sort-import-attributes/types.ts
  • rules/sort-imports.ts
  • rules/sort-imports/types.ts
  • rules/sort-intersection-types.ts
  • rules/sort-jsx-props/sort-jsx-object.ts
  • rules/sort-maps/sort-potential-map.ts
  • rules/sort-maps/types.ts
  • rules/sort-modules.ts
  • rules/sort-modules/types.ts
  • rules/sort-named-exports/sort-named-export.ts
  • rules/sort-named-imports/sort-named-import.ts
  • rules/sort-object-types/sort-object-type-elements.ts
  • rules/sort-object-types/types.ts
  • rules/sort-objects/sort-object.ts
  • rules/sort-objects/types.ts
  • rules/sort-sets.ts
  • rules/sort-union-types.ts
  • rules/sort-union-types/sort-union-or-intersection-types.ts
  • rules/sort-union-types/types.ts
  • rules/sort-variable-declarations/sort-variable-declaration.ts
  • rules/sort-variable-declarations/types.ts
  • test/utils/compute-group.test.ts
  • test/utils/does-custom-group-match.test.ts
  • test/utils/generate-predefined-groups.test.ts
  • test/utils/get-array-combinations.test.ts
  • test/utils/validate-groups-configuration.test.ts
  • utils/compute-group.ts
  • utils/does-custom-group-match.ts
  • utils/generate-predefined-groups.ts
  • utils/get-array-combinations.ts
  • utils/group-matcher.ts
💤 Files with no reviewable changes (11)
  • rules/sort-array-includes.ts
  • rules/sort-union-types.ts
  • rules/sort-sets.ts
  • rules/sort-arrays.ts
  • test/utils/generate-predefined-groups.test.ts
  • rules/sort-intersection-types.ts
  • test/utils/get-array-combinations.test.ts
  • test/utils/compute-group.test.ts
  • utils/get-array-combinations.ts
  • utils/generate-predefined-groups.ts
  • utils/compute-group.ts

Comment thread rules/sort-decorators.ts
Comment on lines +98 to +155
return {
Decorator: decorator => {
if (!options.sortOnParameters) {
return
}
if (
'decorators' in decorator.parent &&
decorator.parent.type === AST_NODE_TYPES.Identifier &&
decorator.parent.parent.type === AST_NODE_TYPES.FunctionExpression
) {
let { decorators } = decorator.parent
if (decorator !== decorators[0]) {
return
}
sortDecorators({ groupMatcher, decorators, options, context })
}
},
PropertyDefinition: propertyDefinition => {
if (options.sortOnProperties) {
sortDecorators({
decorators: getNodeDecorators(propertyDefinition),
groupMatcher,
context,
options,
})
}
},
AccessorProperty: accessorDefinition => {
if (options.sortOnAccessors) {
sortDecorators({
decorators: getNodeDecorators(accessorDefinition),
groupMatcher,
context,
options,
})
}
},
MethodDefinition: methodDefinition => {
if (options.sortOnMethods) {
sortDecorators({
decorators: getNodeDecorators(methodDefinition),
groupMatcher,
context,
options,
})
}
},
ClassDeclaration: declaration => {
if (options.sortOnClasses) {
sortDecorators({
decorators: getNodeDecorators(declaration),
groupMatcher,
context,
options,
})
}
},
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Pass selector/modifier context into sortDecorators().

These call sites now drop whether the decorators belong to a parameter, property, accessor, method, or class, and the helper consequently computes every group with selectors: [] / modifiers: []. Any predefined or custom decorator group that filters by selector/modifier becomes unreachable and falls back to the generic group.

Also applies to: 226-264

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/sort-decorators.ts` around lines 98 - 155, The visitor calls to
sortDecorators (in the Decorator visitor and the PropertyDefinition,
AccessorProperty, MethodDefinition, ClassDeclaration handlers) do not pass the
selector/modifier context, causing the grouping logic to see selectors:[] and
modifiers:[] and miss selector/modifier-specific groups; update each call
(including the Decorator branch that handles parameter decorators and the calls
that use getNodeDecorators) to pass the node's selector (e.g., "parameter" for
the Decorator/parameter case, "property", "accessor", "method", "class" for the
respective handlers) and the node's modifier metadata
(static/readonly/visibility/etc.) to sortDecorators so the groupMatcher can
match selector- or modifier-scoped groups. Ensure the Decorator branch that
inspects decorator.parent/FunctionExpression uses the parameter selector and
that calls using getNodeDecorators forward the originating AST node or an
extracted { selector, modifiers } object into sortDecorators.

Comment on lines 103 to +110
export let allModifiers = [
'async',
'declare',
'decorated',
'default',
'async',
'decorated',
'export',
] as const
export type Modifier = (typeof allModifiers)[number]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Keep the existing sort-modules modifier order.

allModifiers is part of the predefined-group naming surface, so reordering 'async' / 'decorated' changes which strings existing groups / customGroups entries match. That turns this refactor into a config-breaking change unless the previous order is preserved or explicitly migrated.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rules/sort-modules/types.ts` around lines 103 - 110, The array allModifiers
was reordered and that changes the predefined-group naming surface; revert the
change by restoring the original sequence so 'async' and 'decorated' remain in
their previous positions (i.e., keep allModifiers as it was before the refactor)
so existing groups/customGroups string matches are preserved; ensure the
exported type Modifier remains derived from (typeof allModifiers)[number] and do
not alter ordering unless you provide an explicit migration path for
groups/customGroups entries.

@hugop95 hugop95 force-pushed the refactor/groups branch 4 times, most recently from 82484a7 to 85c2b2e Compare April 11, 2026 20:58
@hugop95 hugop95 force-pushed the refactor/groups branch 2 times, most recently from d7346e4 to edc957e Compare April 20, 2026 13:52
@hugop95 hugop95 force-pushed the refactor/groups branch 2 times, most recently from 8f07363 to 94dadc3 Compare May 2, 2026 20:45
@hugop95 hugop95 force-pushed the refactor/groups branch from 94dadc3 to 0006fa6 Compare May 12, 2026 21:35
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.

1 participant