Skip to content

Conversation

@stephenjason89
Copy link
Contributor

@stephenjason89 stephenjason89 commented May 17, 2025

This PR introduces support for two additional options in the extensions rule:
• fix – enables auto-fixing of extension usage based on the configured pattern.
• pathGroupOverrides – allows overriding extension behavior for specific path groups.

close #318


Important

Adds fix and pathGroupOverrides options to extensions rule for auto-fixing and path-specific behavior overrides.

  • Behavior:
    • Adds fix option to extensions rule in extensions.ts for auto-fixing extension usage.
    • Adds pathGroupOverrides option to override extension behavior for specific paths.
    • Modifies moduleVisitor to respect pathGroupOverrides and apply fix logic.
  • Schema and Options:
    • Updates properties schema to include fix and pathGroupOverrides.
    • Updates NormalizedOptions and related interfaces to support new options.
  • Functions:
    • Adds computeOverrideAction() to determine action based on pathGroupOverrides.
    • Modifies buildProperties() to handle new options.

This description was created by Ellipsis for c71d953. You can customize this summary. It will automatically update as commits are pushed.

Summary by CodeRabbit

  • New Features

    • Added a new option to override extension enforcement for specific import paths, allowing users to enforce or ignore rules based on path patterns.
    • Introduced an option to automatically fix missing or unexpected file extensions in import statements.
  • Improvements

    • Enhanced flexibility and control over extension enforcement with path-based overrides.
    • Enabled automatic code fixes for extension-related issues when configured.

@changeset-bot
Copy link

changeset-bot bot commented May 17, 2025

⚠️ No Changeset found

Latest commit: 8cd5a89

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@petercat-assistant
Copy link

Walkthrough

This PR adds support for two new options in the extensions rule: fix, which enables automatic fixing of extension usage based on a configured pattern, and pathGroupOverrides, which allows for overriding extension behavior for specific path groups. These changes enhance the flexibility and functionality of the rule.

Changes

File Summary
src/rules/extensions.ts Added support for fix and pathGroupOverrides options in the extensions rule, including new interfaces and logic to handle these options.

return true
function computeOverrideAction(overrides: PathGroupOverride[], path: string) {
for (const { pattern, patternOptions, action } of overrides) {
if (minimatch(path, pattern, patternOptions || { nocomment: true })) {

Choose a reason for hiding this comment

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

The use of minimatch here should be carefully validated to ensure that the patternOptions do not introduce any security vulnerabilities, such as ReDoS (Regular Expression Denial of Service). Consider validating or sanitizing patternOptions before use.

@codesandbox-ci
Copy link

codesandbox-ci bot commented May 17, 2025

This pull request is automatically built and testable in CodeSandbox.

To see build info of the built libraries, click here or the icon next to each commit SHA.

@coderabbitai
Copy link

coderabbitai bot commented May 17, 2025

"""

Walkthrough

This update to the extensions rule introduces a new configuration option, pathGroupOverrides, allowing users to specify path patterns with override actions (enforce or ignore). A fix option is also added to enable automatic correction of file extension issues. The rule’s logic and schema are updated accordingly, including new type definitions and helper functions.

Changes

File(s) Change Summary
src/rules/extensions.ts Added pathGroupOverrides option, new types and helper function for override logic, integrated override checks and fix option into rule logic, updated schema and metadata, simplified isExternalRootModule function.

Sequence Diagram(s)

sequenceDiagram
    participant UserConfig
    participant Rule
    participant computeOverrideAction
    participant Fixer

    UserConfig->>Rule: Provide import path and options (with pathGroupOverrides, fix)
    Rule->>computeOverrideAction: Check for override action on import path
    computeOverrideAction-->>Rule: Return 'enforce', 'ignore', or undefined
    alt action is 'ignore'
        Rule-->>Rule: Skip extension enforcement
    else action is 'enforce' or undefined
        Rule-->>Rule: Proceed with extension checks
        alt fix option is true and issue found
            Rule->>Fixer: Apply autofix (add/remove extension)
        end
    end
Loading

Poem

🐇
A hop, a skip, a path override—
Now rules can flex and not collide!
With fixes swift for files askew,
Extensions polished, shiny, new.
Patterns matched with gentle care,
The code hops forward, light as air!

"""

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/rules/extensions.ts

Oops! Something went wrong! :(

ESLint: 9.27.0

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/lib/index.js' imported from /eslint.config.js
at finalizeResolution (node:internal/modules/esm/resolve:274:11)
at moduleResolve (node:internal/modules/esm/resolve:859:10)
at defaultResolve (node:internal/modules/esm/resolve:983:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:799:12)
at #cachedDefaultResolve (node:internal/modules/esm/loader:723:25)
at ModuleLoader.resolve (node:internal/modules/esm/loader:706:38)
at ModuleLoader.getModuleJobForImport (node:internal/modules/esm/loader:307:38)
at #link (node:internal/modules/esm/module_job:163:49)

Note

⚡️ AI Code Reviews for VS Code, Cursor, Windsurf

CodeRabbit now has a plugin for VS Code, Cursor and Windsurf. This brings AI code reviews directly in the code editor. Each commit is reviewed immediately, finding bugs before the PR is raised. Seamless context handoff to your AI code agent ensures that you can easily incorporate review feedback.
Learn more here.


Note

⚡️ Faster reviews with caching

CodeRabbit now supports caching for code and dependencies, helping speed up reviews. This means quicker feedback, reduced wait times, and a smoother review experience overall. Cached data is encrypted and stored securely. This feature will be automatically enabled for all accounts on May 16th. To opt out, configure Review - Disable Cache at either the organization or repository level. If you prefer to disable all data retention across your organization, simply turn off the Data Retention setting under your Organization Settings.
Enjoy the performance boost—your workflow just got faster.


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between c71d953 and 8cd5a89.

📒 Files selected for processing (1)
  • src/rules/extensions.ts (12 hunks)
🔇 Additional comments (12)
src/rules/extensions.ts (12)

3-4: The new import for minimatch is correctly added.

The minimatch import is needed for the pattern matching functionality introduced with the pathGroupOverrides option.


37-52: Well-structured schema for pathGroupOverrides.

The schema definition for pathGroupOverrides is comprehensive and follows good practices:

  • Properly typed as an array
  • Each item has clearly defined properties
  • Required fields are specified
  • Uses additionalProperties: false to prevent unexpected properties

This provides good validation for user configurations.


64-66: Interface definitions for new options are well-structured.

The new interfaces and properties are properly defined:

  • Optional fix boolean property
  • Well-typed PathGroupOverride interface with all required properties
  • Consistent addition to both interface variants

This ensures type safety throughout the codebase.

Also applies to: 68-72, 77-78


94-95: NormalizedOptions updated to include new properties.

The NormalizedOptions interface correctly includes the new properties, maintaining type consistency throughout the codebase.


106-107: Good implementation of default values and option handling.

The buildProperties function is properly extended to:

  • Set sensible defaults for new options
  • Extract user-provided values from the configuration
  • Use Boolean() to ensure type consistency for the fix option
  • Validate that pathGroupOverrides is an array before assignment

This ensures robust handling of user configuration.

Also applies to: 145-151


167-168: Good simplification of the isExternalRootModule function.

The function has been refactored to use a single return statement with a logical expression, which improves readability while maintaining the same functionality.


187-187: Proper metadata update to enable autofix capability.

Adding fixable: 'code' correctly indicates that this rule can now automatically fix issues, which is necessary for the new fix functionality to work with ESLint's --fix command line option.


265-270: Good implementation of path override checks.

The rule now properly checks for path overrides before proceeding with the normal checks. Early returning when the action is 'ignore' is an efficient approach that avoids unnecessary processing.


272-277: Correctly modified condition to respect overrides for built-in modules.

The condition has been updated to only check for built-in modules when there's no override action. This ensures that overrides take precedence, which aligns with the feature's intended behavior.


283-285: External module check properly respects overrides.

Similar to the built-in module check, the external root module check now respects overrides, ensuring consistent behavior.


325-337: Good implementation of fix functionality for missing extensions.

The fix implementation for missing extensions is well-structured:

  • Only applies when props.fix is true and extension exists
  • Uses object spread to conditionally include the fix property
  • Correctly constructs the fixed import path with the extension
  • Properly formats the string with JSON.stringify to handle quotes

This will provide accurate automatic fixes for missing extensions.


351-362: Good implementation of fix functionality for unexpected extensions.

The fix implementation for unexpected extensions:

  • Is correctly conditional on props.fix being true
  • Properly removes the extension from the import path
  • Uses JSON.stringify to handle quotes correctly

This will provide accurate automatic fixes for unexpected extensions.

✨ Finishing Touches
  • 📝 Generate Docstrings

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@ellipsis-dev ellipsis-dev bot left a comment

Choose a reason for hiding this comment

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

Caution

Changes requested ❌

Reviewed everything up to c71d953 in 2 minutes and 43 seconds. Click for details.
  • Reviewed 193 lines of code in 1 files
  • Skipped 0 files when reviewing.
  • Skipped posting 4 draft comments. View those below.
  • Modify your settings and rules to customize what types of comments Ellipsis leaves. And don't forget to react with 👍 or 👎 to teach Ellipsis.
1. src/rules/extensions.ts:271
  • Draft comment:
    Consider using an explicit check (e.g. 'overrideAction === undefined') instead of relying on the falsy check (!overrideAction) for built-in and external module conditions for clarity.
  • Reason this comment was not posted:
    Decided after close inspection that this draft comment was likely wrong and/or not actionable: usefulness confidence = 10% vs. threshold = 50% The current !overrideAction check is technically correct since overrideAction can only be 'enforce', 'ignore' or undefined. Both 'enforce' and 'ignore' are truthy strings, so !overrideAction will only be true when it's undefined. While an explicit check might be marginally clearer, the current code is not incorrect or confusing enough to warrant a comment. The suggestion could make the code slightly more explicit and self-documenting. Some developers prefer explicit undefined checks over falsy checks. While explicit checks can be good practice, this case is straightforward enough that the current code is clear and correct. The comment is suggesting a style preference rather than fixing a real issue. This comment should be removed as it suggests a minor style change that doesn't meaningfully improve the code's clarity or correctness.
2. src/rules/extensions.ts:321
  • Draft comment:
    Consider refactoring the duplicate fix logic into a helper function to reduce redundancy and ease future maintenance.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
3. src/rules/extensions.ts:171
  • Draft comment:
    Verify that the minimatch option '{ nocomment: true }' is intended; consider checking the minimatch documentation to ensure correctness.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None
4. src/rules/extensions.ts:36
  • Draft comment:
    Review the strict schema for pathGroupOverrides (with additionalProperties: false); ensure that this restriction is intentional for future extensibility.
  • Reason this comment was not posted:
    Confidence changes required: 33% <= threshold 50% None

Workflow ID: wflow_GPqJm5q3tJgq7bZj

You can customize Ellipsis by changing your verbosity settings, reacting with 👍 or 👎, replying to comments, or adding code review rules.

const extensionRequired = isUseOfExtensionRequired(
extension,
isPackage,
!overrideAction && isPackage,
Copy link

Choose a reason for hiding this comment

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

Pass an explicit value for the isPackage parameter instead of using !overrideAction && isPackage when calling isUseOfExtensionRequired for improved readability.

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: 1

🔭 Outside diff range comments (1)
src/rules/extensions.ts (1)

26-53: 🛠️ Refactor suggestion

fix option is implemented but not declared in the JSON-schema

The runtime code already consumes props.fix, yet the option is not listed in the schema inside properties.
Without the schema entry, tooling (e.g. editors & eslint --print-config) will not offer autocompletion/validation and some CI pipelines that treat unknown properties as errors will fail.

     checkTypeImports: {
       type: 'boolean' as const,
     },
+    fix: {
+      type: 'boolean' as const,
+    },
♻️ Duplicate comments (1)
src/rules/extensions.ts (1)

169-175: Security reminder: minimatch patterns can be expensive

The earlier review already highlighted the need to validate/limit patternOptions (and potentially the pattern length) to mitigate ReDoS vectors in minimatch.
Re-evaluate whether additional safeguards (e.g. timeouts, max pattern length) are required here.

🧹 Nitpick comments (2)
src/rules/extensions.ts (2)

144-151: pathGroupOverrides from multiple config objects silently overwrite each other

buildProperties assigns the last-seen overrides array and discards earlier ones, which is surprising if a user splits configuration across several option objects.

Consider concatenating instead:

-      result.pathGroupOverrides = obj.pathGroupOverrides
+      result.pathGroupOverrides = [
+        ...result.pathGroupOverrides,
+        ...obj.pathGroupOverrides,
+      ]

321-330: Autofix changes quote style

JSON.stringify always produces double-quoted strings, which may alter the original quote style (', ", or `) and trigger other style-rules.
You can preserve the existing delimiter via source.raw[0] or context.getSourceCode().getText(source).

A minimal fix:

-      JSON.stringify(`${importPathWithQueryString}.${extension}`),
+      `${source.raw[0]}${importPathWithQueryString}.${extension}${source.raw[0]}`,

Apply the same technique in the “unexpected” branch below.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Cache: Disabled due to data retention organization setting
Knowledge Base: Disabled due to data retention organization setting

📥 Commits

Reviewing files that changed from the base of the PR and between de7bae3 and c71d953.

📒 Files selected for processing (1)
  • src/rules/extensions.ts (12 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: Codacy Static Code Analysis

@pkg-pr-new
Copy link

pkg-pr-new bot commented May 17, 2025

Open in StackBlitz

npm i https://pkg.pr.new/eslint-plugin-import-x@326

commit: 8cd5a89

@sonarqubecloud
Copy link

@codecov
Copy link

codecov bot commented May 17, 2025

Codecov Report

Attention: Patch coverage is 59.25926% with 11 lines in your changes missing coverage. Please review.

Project coverage is 95.81%. Comparing base (de7bae3) to head (8cd5a89).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
src/rules/extensions.ts 59.25% 10 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master     #326      +/-   ##
==========================================
- Coverage   96.02%   95.81%   -0.22%     
==========================================
  Files          92       92              
  Lines        4758     4778      +20     
  Branches     1789     1803      +14     
==========================================
+ Hits         4569     4578       +9     
- Misses        188      198      +10     
- Partials        1        2       +1     

☔ 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
Member

@JounQin JounQin left a comment

Choose a reason for hiding this comment

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

@stephenjason89 CI is only broken on Node 20 and please add test cases for it.

ignorePackages?: boolean
checkTypeImports?: boolean
pattern: ModifierByFileExtension
fix?: boolean
Copy link
Member

@JounQin JounQin May 17, 2025

Choose a reason for hiding this comment

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

Some kind of related to #230.

@JounQin
Copy link
Member

JounQin commented May 17, 2025

image

Got no idea about this.

@JounQin JounQin changed the title feat(extensions): support fix and pathGroupOverrides options feat(extensions): support pathGroupOverrides and fix options May 17, 2025
@JounQin JounQin closed this in #327 May 17, 2025
@stephenjason89
Copy link
Contributor Author

image Got no idea about this.

Hey, just catching up — I wasn’t able to reply earlier since it was the weekend here in the Philippines.

I saw the 403 error you encountered. Just to clarify, it looks like you were already working locally on the branch since your own commits came after mine. So I was a bit surprised the original PR wasn’t kept open and merged — it would’ve helped preserve the original history and attribution.

Totally appreciate the improvements you made though. Just sharing this for context and in the spirit of smoother collaboration moving forward. Thanks again!

@JounQin
Copy link
Member

JounQin commented May 19, 2025

I saw the 403 error you encountered. Just to clarify, it looks like you were already working locally on the branch since your own commits came after mine. So I was a bit surprised the original PR wasn’t kept open and merged — it would’ve helped preserve the original history and attribution.

I believe that's because your fork is based on https://github.com/import-js/eslint-plugin-import instead of this repo, so I got no permission to push changes to your fork.

@stephenjason89
Copy link
Contributor Author

Ahh that makes sense now — thanks for explaining! I really hate how the fork network works sometimes 😅

@JounQin
Copy link
Member

JounQin commented May 19, 2025

Ahh that makes sense now — thanks for explaining! I really hate how the fork network works sometimes 😅

Yeah, see https://x.com/JounQin/status/1924325252987015345.

@stephenjason89
Copy link
Contributor Author

Ahh that makes sense now — thanks for explaining! I really hate how the fork network works sometimes 😅

Yeah, see x.com/JounQin/status/1924325252987015345.

I guess I was the last known victim of the cursed fork network 😅
Glad to hear it’s been freed!

@JounQin
Copy link
Member

JounQin commented May 19, 2025

I guess I was the last known victim of the cursed fork network 😅

Actually co-author a common pattern to collaborate for git, example: angular/angular#41349.

But I've just added you into the co-authors in the release note: https://github.com/un-ts/eslint-plugin-import-x/releases/tag/v4.12.0, hope it will make you feel better.

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.

Port enhance import extension enforcement with autofix support

3 participants