Skip to content

Conversation

@azat-io
Copy link
Owner

@azat-io azat-io commented Nov 23, 2025

Description

Clarified and repositioned our /* v8 ignore ... */ hints so they still align with the intended AST nodes under Vitest 4’s new coverage stack (esbuild 0.25 + ast-v8-to-istanbul@0.3.8). Without this, the transpiled output moved those comments away from the relevant branches, causing them to count toward coverage again; the tests now confirm all defensive paths are exercised or explicitly ignored.

Additional context

N/A.


What is the purpose of this pull request?

  • Bug fix
  • New Feature
  • Documentation update
  • Other

Before submitting the PR, please make sure you do the following

  • Check that there isn't already a PR that solves the problem the same way to avoid creating a duplicate.
  • Provide a description in this PR that addresses what the PR is solving, or reference the issue that it solves.
  • Ideally, include relevant tests that fail without this PR but pass with it.
  • Read contribution guidelines.

@coderabbitai
Copy link

coderabbitai bot commented Nov 23, 2025

📝 Walkthrough

Summary by CodeRabbit

  • Dependencies

    • Upgraded vitest and coverage-v8 to v4.0.13.
  • Tests

    • Added comprehensive unit tests for utility functions.
    • Expanded test coverage with new test cases for edge scenarios and regression validation.
    • Migrated test configuration to dedicated vitest config file with 100% coverage thresholds.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

Bump Vitest dev dependencies, add a dedicated Vitest config with v8 coverage thresholds, adjust many v8/@preserve/exhaustive-guard comments, replace some null-checks with non-null assertions, and add/update unit tests and test mocks. No public API signature changes.

Changes

Cohort / File(s) Summary
Dependency upgrades
package.json
Bump vitest and @vitest/coverage-v8 from ^3.2.4 to ^4.0.13.
Vitest config / coverage
vite.config.ts, vitest.config.ts
Remove test.coverage from vite.config.ts; add vitest.config.ts exporting merged Vite config with 100% v8 coverage thresholds.
Non-null assertion refactors
rules/sort-enums.ts, utils/make-newlines-between-fixes.ts
Replace conditional checks with non-null assertions (assume initializer/computeRangeReplacement presence) and push fixes unconditionally.
v8-ignore / @preserve comment updates
rules/sort-heritage-clauses.ts, rules/sort-imports.ts, rules/sort-switch-case.ts, utils/compute-group-name.ts, utils/compute-groups-names.ts, utils/get-eslint-disabled-lines.ts, utils/get-group-index.ts, utils/compute-nodes-in-circular-dependencies.ts, test/utils/validate-rule-json-schema.ts
Reword/reposition v8 ignore comments, add -- @preserve`` notes and exhaustive-guard comments; remove or replace older ignore pragmas.
Formatting / minor refactors
utils/get-enum-members.ts, utils/get-node-decorators.ts, utils/complete.ts
Reformat return expressions, wrap returns in parentheses, add minor inline comments, and remove redundant v8 ignore comments.
Rule comment cleanup
rules/sort-object-types.ts
Remove a no-op v8 ignore comment in getNodeName for TSMethodSignature.
Test additions
test/rules/sort-array-includes.test.ts, test/rules/sort-modules.test.ts, test/rules/sort-objects.test.ts
Add tests for non-applicability and edge-case inputs: arrays used with other methods, empty/single-statement files, exports without declarations, module declarations without body, and a TODO regression for destructured object params.
New utility tests
test/utils/get-enum-members.test.ts, test/utils/get-node-decorators.test.ts
Add unit tests for getEnumMembers and getNodeDecorators behaviors including fallback cases.
Test mock change
test/rules/sort-imports/read-closest-ts-config-by-path.test.ts
Update node:module mock: createModuleResolutionCache now accepts (_contextCwd, getCanonicalFileName, _options), calls getCanonicalFileName('test.ts'), and returns vi.fn().
Minor comment/guard edits
utils/compute-groups-names.ts, utils/get-group-index.ts, utils/get-eslint-disabled-lines.ts
Insert exhaustive-guard comments and tweak v8-ignore placements; no behavior changes.

Sequence Diagram(s)

sequenceDiagram
  participant Caller as makeNewlinesBetweenFixes
  participant Compute as computeRangeReplacement
  participant Fixes as fixesArray

  Note over Caller,Compute: Previous flow — conditional push
  Caller->>Compute: computeRangeReplacement(...)
  alt rangeReplacement truthy
    Compute-->>Caller: RangeReplacement
    Caller->>Fixes: push(rangeReplacement)
  else
    Compute-->>Caller: undefined
    Caller-->>Fixes: (no push)
  end

  Note over Caller,Compute: New flow — unconditional push with non-null assertion
  Caller->>Compute: computeRangeReplacement(...)
  Compute-->>Caller: RangeReplacement (assumed non-null)
  Caller->>Fixes: push(rangeReplacement!)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • Areas to inspect closely:
    • utils/make-newlines-between-fixes.ts — ensure computeRangeReplacement cannot return undefined in any path before forcing non-null.
    • rules/sort-enums.ts — validate safety of member.initializer! usage.
    • test/rules/sort-imports/read-closest-ts-config-by-path.test.ts — confirm mocked createModuleResolutionCache signature and side-effect match expectations.
    • vitest.config.ts / CI — verify relocating coverage thresholds preserves CI behavior.

Possibly related PRs

Suggested reviewers

  • hugop95

Pre-merge checks

❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
Title check ❓ Inconclusive The title 'test: improve test coverage' is generic and vague, using non-descriptive phrasing that doesn't convey the specific technical changes or the core issue being addressed. Consider a more specific title that reflects the actual change, such as 'test: reposition v8 coverage ignore comments for Vitest 4 compatibility' or 'chore: align v8 ignore hints with Vitest 4 esbuild transpilation'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description check ✅ Passed The description adequately explains the purpose (repositioning v8 ignore comments for Vitest 4 compatibility), provides context about the technical issue, and addresses the required template sections with appropriate checkbox selections.

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.

@codecov
Copy link

codecov bot commented Nov 23, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (358217d) to head (d2dc998).
⚠️ Report is 1 commits behind head on next.

Additional details and impacted files
@@             Coverage Diff             @@
##              next      #618     +/-   ##
===========================================
  Coverage   100.00%   100.00%             
===========================================
  Files          113       114      +1     
  Lines         9101      3313   -5788     
  Branches      1743      1003    -740     
===========================================
- Hits          9101      3313   -5788     

☔ 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

@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: 0

🧹 Nitpick comments (4)
utils/make-newlines-between-fixes.ts (1)

165-172: Non‑null assertion hides a mismatch between computeRangeReplacement’s type/docs and implementation

computeRangeReplacement is declared (and documented) as returning undefined | string, but its current implementation always returns a string. Asserting non‑null at the call site works today, but it relies on a hidden invariant and makes future changes to computeRangeReplacement easier to break silently.

Consider tightening the function contract instead and dropping the ! here:

-    let rangeReplacement = computeRangeReplacement({
+    let rangeReplacement = computeRangeReplacement({
       isOnSameLine:
         sortingNode.node.loc.end.line === nextSortingNode.node.loc.start.line,
       textBetweenNodes,
       newlinesBetween,
-    })!
+    })
 
     fixes.push(fixer.replaceTextRange(rangeToReplace, rangeReplacement))

Then update computeRangeReplacement’s return type (and JSDoc) to string only, reflecting the actual behavior. This keeps coverage-friendly control flow while remaining type‑safe and self‑documenting.

test/utils/get-enum-members.test.ts (1)

7-35: Good coverage of both enum AST shapes

The tests cleanly cover both the modern members property and the legacy body.members shape, and the identity assertions (toBe) ensure you’re not accidentally cloning. If you ever see real-world nodes that expose both members and body.members, adding a third precedence test could be a small future enhancement, but what’s here is solid.

utils/get-enum-members.ts (1)

24-30: Consider aligning doc wording with the nullish-coalescing order

The implementation prefers value.body?.members and falls back to value.members, while the comment reads as though body?.members is the backward-compat fallback for older parsers. Behavior is fine given your supported shapes, but you may want to either flip the expression to value.members ?? value.body?.members or tweak the comment so it matches the actual precedence.

rules/sort-enums.ts (1)

134-140: Non‑null assertions on enum initializers are justified by the precondition

Relying on members.every(({ initializer }) => initializer) before the reduce makes member.initializer! and the unconditional numericValue: getExpressionNumberValue(member.initializer!) safe, and simplifies the per‑member logic. Just keep in mind that any future change relaxing that guard would need corresponding adjustments here.

Also applies to: 159-167

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0403705 and a927a09.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (24)
  • package.json (2 hunks)
  • rules/sort-enums.ts (5 hunks)
  • rules/sort-heritage-clauses.ts (1 hunks)
  • rules/sort-imports.ts (2 hunks)
  • rules/sort-object-types.ts (0 hunks)
  • rules/sort-switch-case.ts (4 hunks)
  • test/rules/sort-array-includes.test.ts (1 hunks)
  • test/rules/sort-imports/read-closest-ts-config-by-path.test.ts (1 hunks)
  • test/rules/sort-modules.test.ts (1 hunks)
  • test/rules/sort-objects.test.ts (1 hunks)
  • test/utils/get-enum-members.test.ts (1 hunks)
  • test/utils/get-node-decorators.test.ts (1 hunks)
  • test/utils/validate-rule-json-schema.ts (2 hunks)
  • utils/complete.ts (1 hunks)
  • utils/compute-group-name.ts (1 hunks)
  • utils/compute-groups-names.ts (1 hunks)
  • utils/compute-nodes-in-circular-dependencies.ts (2 hunks)
  • utils/get-enum-members.ts (1 hunks)
  • utils/get-eslint-disabled-lines.ts (3 hunks)
  • utils/get-group-index.ts (1 hunks)
  • utils/get-node-decorators.ts (1 hunks)
  • utils/make-newlines-between-fixes.ts (1 hunks)
  • vite.config.ts (0 hunks)
  • vitest.config.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • rules/sort-object-types.ts
  • vite.config.ts
🧰 Additional context used
🧬 Code graph analysis (5)
test/utils/get-enum-members.test.ts (1)
utils/get-enum-members.ts (1)
  • getEnumMembers (24-31)
utils/compute-groups-names.ts (1)
utils/is-newlines-between-option.ts (1)
  • isNewlinesBetweenOption (36-40)
utils/compute-group-name.ts (1)
utils/is-newlines-between-option.ts (1)
  • isNewlinesBetweenOption (36-40)
test/utils/get-node-decorators.test.ts (1)
utils/get-node-decorators.ts (1)
  • getNodeDecorators (32-39)
utils/get-group-index.ts (1)
utils/is-newlines-between-option.ts (1)
  • isNewlinesBetweenOption (36-40)
🔇 Additional comments (20)
utils/complete.ts (1)

103-107: V8 ignore guard is well‑placed and non‑intrusive

The new /* v8 ignore else */ comment correctly targets the defensive branch in the array comparison loop without affecting logic or readability.

test/rules/sort-objects.test.ts (1)

923-1037: Additional destructuring test accurately exercises nested default case

The new valid case with a: { nested } = { nested: 'default' } and b correctly asserts that nested default initializers without cross‑property dependencies are treated as safe, which strengthens coverage without changing rule behavior.

utils/compute-groups-names.ts (1)

17-30: Exhaustive-guard comments match existing control flow

The added v8 ignore/@preserve comments accurately document the isNewlinesBetweenOption branch and the final UnreachableCaseError as exhaustive guards, without altering how unknown group options are handled.

rules/sort-switch-case.ts (2)

140-195: Default‑clause ordering comment clarifies intent

The new “Ensure default is at the end” comment succinctly describes the surrounding swap logic and makes the invariant of sortingNodesGroupWithDefault explicit, with no impact on behavior.


197-267: Block‑sorting guards and coverage hints are consistent with existing logic

The added comments around block ordering (including the v8 ignore if for the b === lastNodeGroup comparator branch and the note about deferring fixes until the second iteration) clearly document defensive paths that are hard to hit in tests, without changing how groups are sorted or how fixes are generated.

package.json (1)

63-132: Vitest tooling bump looks aligned; confirm CI on Vitest 4

Upgrading @vitest/coverage-v8 and vitest to ^4.0.13 matches the new v8 coverage setup; just ensure your CI matrix (Node versions, reporters, coverage flags) has been exercised against Vitest 4 and still passes.

utils/compute-group-name.ts (1)

16-31: Exhaustive-guard annotations are clear and behavior‑preserving

The new v8 ignore/@preserve comments correctly mark the isNewlinesBetweenOption branch and final UnreachableCaseError as exhaustive guards for unsupported group shapes, without changing the semantics of computeGroupName.

test/utils/validate-rule-json-schema.ts (1)

21-44: Coverage-guard comments correctly identify defensive schema assertions

The added v8 ignore if comments on the schema‑description and weak index‑signature checks accurately describe them as defensive guards that are difficult to exercise in unit tests, while leaving the validation behavior unchanged.

test/rules/sort-array-includes.test.ts (1)

5769-5795: New non-applicability tests look correct and targeted

The added cases accurately pin down that the rule ignores arrays passed through other methods and computed property access to ['includes'], which matches the intended scope without overfitting the implementation.

utils/get-node-decorators.ts (1)

32-38: Decorator accessor remains simple and robust

Wrapping the return and keeping the no-unnecessary-condition suppression preserves the intended “safe accessor” behavior while playing nicely with linting; no functional issues here.

test/rules/sort-modules.test.ts (1)

23-60: New alphabetical tests nicely cover edge-module shapes

The added valid cases for empty files, single-statement files, export lists, and module declarations without bodies look correct and align with the rule’s expected “no-op” behavior; good targeted coverage with no behavior changes required.

utils/compute-nodes-in-circular-dependencies.ts (1)

55-63: Coverage pragmas keep DFS logic intact

The added v8 ignore comments around the cycleStartIndex !== -1 check and the dependencyElement guard don’t affect the DFS or cycle detection semantics; they simply mark defensive paths for coverage and are consistent with the existing structure.

Also applies to: 69-77

rules/sort-enums.ts (1)

326-329: Updated v8 ignore guards around unreachable branches look consistent

The refined v8 ignore comments on the default branches of getBinaryExpressionNumberValue, computeNodeValueGetter, and getUnaryExpressionNumberValue correctly annotate the “should be unreachable” paths without changing control flow or error behavior.

Also applies to: 349-352, 396-399

utils/get-group-index.ts (1)

52-65: Exhaustive-guard comments correctly document non-matching group directives

The added v8 ignore comments around the isNewlinesBetweenOption check and the UnreachableCaseError make the intent of these defensive branches explicit without altering the matching behavior for real group entries.

rules/sort-imports.ts (1)

590-608: Coverage hints around rare TS import-equals shapes are non-intrusive

The /* v8 ignore if */ before the !qualifiedName guard and the final /* v8 ignore next */ before returning null in getQualifiedNameDependencyName simply mark defensive/unreachable paths for coverage; the dependency resolution logic for TSImportEqualsDeclaration stays unchanged.

Also applies to: 641-652

utils/get-eslint-disabled-lines.ts (1)

58-65: Refined disable/enable coverage guards keep state machine behavior intact

The added v8 ignore comments and the scoped eslint-enable case preserve the original handling of eslint-disable* / eslint-enable directives (including the “enable without prior disable” early-continue) while just annotating hard-to-hit or unreachable paths for coverage.

Also applies to: 76-91

rules/sort-heritage-clauses.ts (1)

210-224: Heritage-clause name extraction remains defensive with clearer coverage hints

The added v8 ignore comments just document the recursive property branch and the final “unexpected expression” throw as exhaustive guards; the function still correctly handles identifiers, member-like expressions, and fails loudly on unsupported shapes.

test/utils/get-node-decorators.test.ts (1)

1-46: New tests give direct, type-safe coverage for getNodeDecorators

The helper type NodeWithDecoratorsParameter plus the minimal AST stubs exercise both “decorators present” and “decorators missing” paths cleanly; this is a good, low-noise addition to utility coverage.

vitest.config.ts (1)

1-19: LGTM! Clean Vitest configuration with strict coverage enforcement.

The configuration correctly merges the base Vite config with test-specific settings and enforces 100% coverage thresholds across all metrics, aligning with the PR's goal of improving test coverage under Vitest 4's v8 provider.

test/rules/sort-imports/read-closest-ts-config-by-path.test.ts (1)

30-37: LGTM! Mock enhancement for coverage.

The updated mock now exercises the getCanonicalFileName callback by invoking it with a test value, ensuring that code paths passing this callback are covered. This aligns with the PR's goal of improving test coverage under Vitest 4.

Copy link
Contributor

@hugop95 hugop95 left a comment

Choose a reason for hiding this comment

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

@azat-io Nice ✨!

I think that we just discovered a bug in sort-objects. Let me know if you want to take care of it or if I should make a fix 👍

it('ignores computed property access', async () => {
await valid({
code: dedent`
['c', 'b', 'a']['includes']('a')
Copy link
Contributor

Choose a reason for hiding this comment

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

@azat-io

I didn't think of that use case ! 😄
I don't think it will every be used though.

Copy link
Owner Author

Choose a reason for hiding this comment

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

This is a new requirement for Vitest to ensure test coverage. It would have been necessary if it were a lie. We need tests to ensure that 'if' is 'false'.

options: [options],
})

await valid({
Copy link
Contributor

Choose a reason for hiding this comment

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

@azat-io

I don't think that this test suits: a and b don't depend on each other.

However, I realize that the following is marked as valid even though it shouldn't:

let {
  a = nested,
  b: { nested } = { nested: 'default' },
} = obj;

It's an uncommon use case !

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes, thanks.

I created new issue:
#619

And added TODO comment before the test case.

} as unknown as TSESTree.Decorator
}

function createNodeWithDecorators(
Copy link
Contributor

Choose a reason for hiding this comment

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

@azat-io

[nit] You can write this in a concise way as well:

function createNodeWithDecorators(
  decorators?: TSESTree.Decorator[],
): NodeWithDecoratorsParameter {
    return {
      type: 'ClassDeclaration',
      ...(decorators ? { decorators} : {}) ,
    } as unknown as NodeWithDecoratorsParameter
  }
}

Copy link
Owner Author

Choose a reason for hiding this comment

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

Fixed

Copy link

@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: 0

🧹 Nitpick comments (1)
rules/sort-enums.ts (1)

140-179: Non-null assertions on member.initializer are consistent with the guard

Using member.initializer! for both extractDependencies and getExpressionNumberValue is safe given the early return when any member lacks an initializer (members.every(({ initializer }) => initializer)). This also makes control flow clearer than repeated optional checks.

If you want to make the invariant more obvious to future readers, you could add a short comment near the every check noting that later code assumes member.initializer is always defined.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a927a09 and a36bddf.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (24)
  • package.json (2 hunks)
  • rules/sort-enums.ts (5 hunks)
  • rules/sort-heritage-clauses.ts (1 hunks)
  • rules/sort-imports.ts (2 hunks)
  • rules/sort-object-types.ts (0 hunks)
  • rules/sort-switch-case.ts (4 hunks)
  • test/rules/sort-array-includes.test.ts (1 hunks)
  • test/rules/sort-imports/read-closest-ts-config-by-path.test.ts (1 hunks)
  • test/rules/sort-modules.test.ts (1 hunks)
  • test/rules/sort-objects.test.ts (1 hunks)
  • test/utils/get-enum-members.test.ts (1 hunks)
  • test/utils/get-node-decorators.test.ts (1 hunks)
  • test/utils/validate-rule-json-schema.ts (2 hunks)
  • utils/complete.ts (1 hunks)
  • utils/compute-group-name.ts (1 hunks)
  • utils/compute-groups-names.ts (1 hunks)
  • utils/compute-nodes-in-circular-dependencies.ts (2 hunks)
  • utils/get-enum-members.ts (1 hunks)
  • utils/get-eslint-disabled-lines.ts (3 hunks)
  • utils/get-group-index.ts (1 hunks)
  • utils/get-node-decorators.ts (1 hunks)
  • utils/make-newlines-between-fixes.ts (1 hunks)
  • vite.config.ts (0 hunks)
  • vitest.config.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • rules/sort-object-types.ts
  • vite.config.ts
✅ Files skipped from review due to trivial changes (1)
  • utils/complete.ts
🚧 Files skipped from review as they are similar to previous changes (15)
  • test/utils/get-enum-members.test.ts
  • test/utils/validate-rule-json-schema.ts
  • utils/make-newlines-between-fixes.ts
  • test/rules/sort-objects.test.ts
  • utils/compute-groups-names.ts
  • utils/compute-group-name.ts
  • vitest.config.ts
  • utils/get-node-decorators.ts
  • test/rules/sort-modules.test.ts
  • test/rules/sort-array-includes.test.ts
  • test/utils/get-node-decorators.test.ts
  • rules/sort-switch-case.ts
  • utils/get-group-index.ts
  • rules/sort-imports.ts
  • utils/get-eslint-disabled-lines.ts
🔇 Additional comments (9)
rules/sort-enums.ts (3)

299-335: getBinaryExpressionNumberValue default branch and coverage hint look good

The default arm returning null for unsupported operators is a sensible defensive fallback, and the /* v8 ignore next 2 -- @preserve Unsure if we can reach it. */ comment is correctly positioned immediately before the unreachable default to keep coverage noise down.


345-358: Unreachable sortByValue default with v8 ignore is appropriate

Given the declared sortByValue enum ('always' | 'ifNumericEnum' | 'never'), the default case throwing UnreachableCaseError is a good safety net. The /* v8 ignore next 2 -- @preserve Unsure if we can reach it. */ keeps this defensive path out of coverage metrics without changing behavior.


395-405: Unary operator fallback and coverage hint are consistent with the rest

Falling back to null for unhandled unary operators matches the binary-expression helper’s behavior, and the new v8 ignore comment is aligned with the default arm so coverage won’t be penalized for this defensive path.

test/rules/sort-imports/read-closest-ts-config-by-path.test.ts (1)

30-37: LGTM! Mock now exercises the callback parameter.

The updated mock signature properly exercises the getCanonicalFileName callback by invoking it during cache creation. This ensures the code path that provides and uses this callback is covered by tests, aligning with the PR's objective to improve test coverage.

rules/sort-heritage-clauses.ts (1)

221-225: LGTM! Coverage hints properly aligned for Vitest 4.

The repositioned v8 ignore directives with @preserve ensure the coverage tool correctly excludes these defensive branches after transpilation. The exhaustive-guard comment on line 221 and the should-never-throw comment on line 225 accurately describe their purpose.

utils/compute-nodes-in-circular-dependencies.ts (2)

55-62: Cycle index guard and v8 directive keep cycle detection behavior intact

The cycleStartIndex guard remains purely defensive, and the added /* v8 ignore else */ correctly documents the unreachable-else assumption without changing how cycles are collected from path. No changes needed.


69-79: Dependency guard + v8 ignore comment preserve defensive behavior

Wrapping the recursive call in if (dependencyElement) with a /* v8 ignore next */ comment keeps the previous defensive fallback (skip when lookup fails) while making the intended “missing dependency is unreachable” assumption explicit for coverage. Logic and control flow are unchanged.

utils/get-enum-members.ts (1)

27-30: Parenthesized return + eslint-disable comment are behavior-neutral

The function still returns value.body?.members ?? value.members with the same precedence and nullish-coalescing behavior; only formatting and comment placement changed. The inline eslint-disable-next-line clearly applies to the legacy body access. All good.

package.json (1)

86-86: Version bump to Vitest 4.0.13 is compatible and properly configured.

Verification confirms Vitest 4.0.13 is a stable release with no breaking changes in this patch version. The migration from v3 to v4 has been properly implemented:

  • vitest.config.ts correctly configured with v8 coverage provider and 100% thresholds
  • vite.config.ts properly updated (test.coverage removed)
  • @vitest/coverage-v8 matched to version 4.0.13
  • Node engine constraint (^20.0.0 || >=22.0.0) is compatible with Vitest 4

Changes approved.

@azat-io azat-io merged commit 69566b5 into next Nov 25, 2025
11 of 12 checks passed
Copy link

@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: 0

🧹 Nitpick comments (2)
utils/get-eslint-disabled-lines.ts (1)

76-90: Block-scoped eslint-enable case and coverage hints are correct but slightly brittle

Wrapping the 'eslint-enable' case body in { ... } is semantically neutral here (no new lexical bindings), and continue still targets the surrounding for loop while break still exits the switch, so runtime behavior is unchanged. The added v8 ignore hints for the defensive if (!lineRulePermanentlyDisabled) and the unreachable default case also match their intent.

The only minor downside is that /* v8 ignore next ... */ counts are easy to desynchronize if more statements are inserted into these cases in the future; a quick comment near them (or test that asserts coverage expectations) can help catch accidental drift later.

utils/make-newlines-between-fixes.ts (1)

165-172: Avoid non‑null assertion by tightening computeRangeReplacement’s return type

computeRangeReplacement is typed/JSDoc’d as returning undefined | string, but the implementation always returns a string. The ! at the call site is only compensating for this mismatch and could hide future regressions if undefined is reintroduced.

You can simplify and make this safer by narrowing the helper’s return type to string, updating its JSDoc, and dropping the non‑null assertion:

-    let rangeReplacement = computeRangeReplacement({
-      isOnSameLine:
-        sortingNode.node.loc.end.line === nextSortingNode.node.loc.start.line,
-      textBetweenNodes,
-      newlinesBetween,
-    })!
-
-    fixes.push(fixer.replaceTextRange(rangeToReplace, rangeReplacement))
+    let rangeReplacement = computeRangeReplacement({
+      isOnSameLine:
+        sortingNode.node.loc.end.line === nextSortingNode.node.loc.start.line,
+      textBetweenNodes,
+      newlinesBetween,
+    })
+
+    fixes.push(fixer.replaceTextRange(rangeToReplace, rangeReplacement))

And for the helper itself (JSDoc + signature) something along these lines:

/**
 * @returns Replacement text with correct newlines.
 */
function computeRangeReplacement({
  textBetweenNodes,
  newlinesBetween,
  isOnSameLine,
}: {
  textBetweenNodes: string
  newlinesBetween: number
  isOnSameLine: boolean
}): string {
  // existing implementation unchanged
}
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a36bddf and d2dc998.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml
📒 Files selected for processing (24)
  • package.json (2 hunks)
  • rules/sort-enums.ts (5 hunks)
  • rules/sort-heritage-clauses.ts (1 hunks)
  • rules/sort-imports.ts (2 hunks)
  • rules/sort-object-types.ts (0 hunks)
  • rules/sort-switch-case.ts (4 hunks)
  • test/rules/sort-array-includes.test.ts (1 hunks)
  • test/rules/sort-imports/read-closest-ts-config-by-path.test.ts (1 hunks)
  • test/rules/sort-modules.test.ts (1 hunks)
  • test/rules/sort-objects.test.ts (1 hunks)
  • test/utils/get-enum-members.test.ts (1 hunks)
  • test/utils/get-node-decorators.test.ts (1 hunks)
  • test/utils/validate-rule-json-schema.ts (2 hunks)
  • utils/complete.ts (1 hunks)
  • utils/compute-group-name.ts (1 hunks)
  • utils/compute-groups-names.ts (1 hunks)
  • utils/compute-nodes-in-circular-dependencies.ts (2 hunks)
  • utils/get-enum-members.ts (1 hunks)
  • utils/get-eslint-disabled-lines.ts (3 hunks)
  • utils/get-group-index.ts (1 hunks)
  • utils/get-node-decorators.ts (1 hunks)
  • utils/make-newlines-between-fixes.ts (1 hunks)
  • vite.config.ts (0 hunks)
  • vitest.config.ts (1 hunks)
💤 Files with no reviewable changes (2)
  • rules/sort-object-types.ts
  • vite.config.ts
✅ Files skipped from review due to trivial changes (2)
  • test/utils/validate-rule-json-schema.ts
  • rules/sort-switch-case.ts
🚧 Files skipped from review as they are similar to previous changes (14)
  • test/utils/get-enum-members.test.ts
  • utils/compute-group-name.ts
  • test/rules/sort-objects.test.ts
  • rules/sort-enums.ts
  • test/rules/sort-modules.test.ts
  • utils/compute-nodes-in-circular-dependencies.ts
  • utils/complete.ts
  • utils/get-group-index.ts
  • utils/get-node-decorators.ts
  • vitest.config.ts
  • test/rules/sort-imports/read-closest-ts-config-by-path.test.ts
  • rules/sort-heritage-clauses.ts
  • rules/sort-imports.ts
  • test/utils/get-node-decorators.test.ts
🧰 Additional context used
🧬 Code graph analysis (1)
utils/compute-groups-names.ts (1)
utils/is-newlines-between-option.ts (1)
  • isNewlinesBetweenOption (36-40)
🔇 Additional comments (5)
utils/get-enum-members.ts (1)

27-30: Test coverage verified for both code paths.

The tests confirm that both the direct members access and the body?.members fallback are exercised:

  • Test 1 covers direct member access on modern AST shape
  • Test 2 covers fallback to legacy body.members when needed

The removal of the v8 ignore directive is justified—both defensive paths are now explicitly tested.

package.json (1)

86-86: Vitest devDependency bumps look consistent with the new coverage setup

Moving both @vitest/coverage-v8 and vitest to the same ^4.0.13 range matches the dedicated Vitest v4 coverage config and keeps tooling in sync. No issues from the package.json side.

Please just double‑check against the Vitest 4 docs that vitest --run --coverage still maps to the expected coverage provider/settings in your new vitest.config.ts (in case any CLI flags changed semantics between v3 and v4).

Also applies to: 131-131

test/rules/sort-array-includes.test.ts (1)

5477-5504: Additional “non-applicability” tests for sort-array-includes look solid

The new cases for .map/.filter/.forEach and ['includes'] computed access clearly lock in the intended “ignore non-.includes / computed property” behavior while driving coverage on those guard branches. No issues.

utils/compute-groups-names.ts (1)

24-29: Exhaustive guard and v8 coverage hints look consistent and non-breaking

The new /* v8 ignore else */ and /* v8 ignore next */ comments clearly target the unreachable “unsupported group option” path without changing the control flow: the three valid shapes are still handled explicitly, and everything else still falls through to new UnreachableCaseError(group). This should be more stable than a ignore next 3 span against future transpilation changes, and it aligns with the exhaustive-guard pattern used elsewhere in the plugin.

Given these directives depend on how the current Vitest + esbuild + ast-v8-to-istanbul stack interprets them, it’s worth re-checking coverage locally after any future tooling upgrades to ensure the hints still attach to the intended branches.

utils/get-eslint-disabled-lines.ts (1)

58-64: Includes‑rule false branch v8 ignore looks safe and non‑behavioral

The new /* v8 ignore next 3 -- @preserve … */ on the !includesRule path is purely for coverage tooling and doesn’t alter control flow: the early continue remains exactly as before and still correctly skips comments that don’t apply to the target rule. From a runtime perspective this segment remains sound.

@azat-io azat-io deleted the test/coverage branch November 25, 2025 10:46
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