Skip to content

fix: align prefer-const with ESLint implementation#621

Merged
fansenze merged 1 commit intomainfrom
fix/prefer-const-20260409
Apr 9, 2026
Merged

fix: align prefer-const with ESLint implementation#621
fansenze merged 1 commit intomainfrom
fix/prefer-const-20260409

Conversation

@fansenze
Copy link
Copy Markdown
Contributor

@fansenze fansenze commented Apr 9, 2026

Summary

  • Fix 9 bugs in the prefer-const rule to fully align detection, reporting location, and auto-fix behavior with ESLint's implementation.
  • Implement letconst auto-fix when all bindings in the VariableDeclarationList are const-eligible.
  • Extract FindEnclosingScope and VisitDestructuringIdentifiers as public utilities in internal/utils/ for reuse by other rules (e.g., no-var).
  • Refactor to use existing public functions: utils.CollectBindingNames, ast.IsFunctionLikeOrClassStaticBlockDeclaration.

Bug fixes

# Bug Type
1 hasUnmergeableTarget checked same VDL instead of same block scope false negative
2 hasTargetNotInSet missed leaf Identifier nodes in PropertyAssignment values logic defect
3 destructuring: "all" didn't check write-level destructuring grouping false negative
4 findEnclosingScope missing ClassStaticBlockDeclaration false negative
5 hasTargetNotInSet missing SpreadAssignment in object destructuring false positive
6 Shorthand name-based matching false-matched shadowed variables (3 functions) false negative
7 countWritesByName lacked scope awareness for shadowed variables false negative
8 Reporting vs fix suppression conflated for same-scope var/const in destructuring false negative
9 collectBlockAllVarNames missed imports/params/function declarations — used name-set instead of symbol-based scope checking false negative

Code quality improvements

  • countWritesByNamecountWritesBySym: accept symbol from caller instead of fragile re-resolution
  • hasNonReportableDestructuringTarget: replaced name-set approach with TypeChecker symbol-based scope comparison to handle all declaration types (imports, parameters, function/class declarations)
  • Eliminated duplicate isReadBeforeFirstAssign call in shouldReport
  • Removed redundant collectBlockAllVarNames function

Verification

  • 193 Go test cases across 8 dimensions (vs ESLint's 125), 0 failures
  • ESLint comparison: 3 config combinations × comprehensive test file = all matched
  • Auto-fix: --fix output byte-identical to ESLint on same input
  • E2E: rsbuild (5 errors) + rspack (2 errors), all matching ESLint

Related Links

Checklist

  • Tests updated (or not required).
  • Documentation updated (or not required).

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request enhances the prefer-const rule by implementing auto-fix capabilities for variable declaration lists and improving the handling of destructuring assignments to align with ESLint semantics. It introduces several utility functions for scope resolution and destructuring traversal. Feedback focuses on optimizing performance by caching block-level variable lookups and ensuring correct symbol resolution in the write-counting logic to properly handle variable shadowing.

Comment thread internal/rules/prefer_const/prefer_const.go Outdated
Comment thread internal/rules/prefer_const/prefer_const.go Outdated
@fansenze fansenze force-pushed the fix/prefer-const-20260409 branch from 0d71863 to 71f39b6 Compare April 9, 2026 09:00
Fix 8 bugs in the prefer-const rule to fully align detection, reporting
location, and auto-fix behavior with ESLint's implementation.

Bug fixes:
- Fix cross-declaration destructuring in same scope not being reported
- Fix `hasTargetNotInSet` missing leaf Identifier nodes in PropertyAssignment
- Fix `destructuring: "all"` not checking write-level destructuring grouping
- Fix `findEnclosingScope` missing ClassStaticBlockDeclaration
- Fix `hasTargetNotInSet` missing SpreadAssignment in object destructuring
- Fix shorthand name-based matching false-matching shadowed variables
- Fix `countWritesByName` lacking scope awareness for shadowed variables
- Fix reporting vs fix suppression for same-scope var/const in destructuring

Auto-fix:
- Implement `let` → `const` auto-fix when all bindings in VDL are const-eligible
- Correctly suppress fix when not all bindings can be const or declarations are uninitialized

Public utilities extracted:
- `utils.FindEnclosingScope` — reusable scope boundary finder (also adopted by no-var)
- `utils.VisitDestructuringIdentifiers` — reusable destructuring assignment pattern walker

Refactored to use existing public functions:
- Replace custom `collectBindingNames` with `utils.CollectBindingNames`
- Replace hardcoded scope boundary list with `ast.IsFunctionLikeOrClassStaticBlockDeclaration`

Test coverage: 192 test cases across 8 dimensions (vs ESLint's 125).
@fansenze fansenze force-pushed the fix/prefer-const-20260409 branch from 71f39b6 to 8b82f03 Compare April 9, 2026 09:17
@fansenze fansenze merged commit 1c1e472 into main Apr 9, 2026
11 checks passed
@fansenze fansenze deleted the fix/prefer-const-20260409 branch April 9, 2026 09:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants