eslint-plugin-import-x

repository·master·Indexed 20 days ago

https://github.com/un-ts/eslint-plugin-import-x

A high-performance ESLint plugin for linting ES2015+ import/export syntax. A fork of eslint-plugin-import, it utilizes a custom Rust-based resolver and get-tsconfig for improved speed and modernity. It supports both ESLint Flat Config and legacy .eslintrc formats, providing rules for helpful warnings, module systems, static analysis, and style guides.

Tokens
37.9K
Snippets
129
Records
166
Agent score
69%

What's inside eslint-plugin-import-x

  1. Understand when `import-x/no-import-module-exports` fails or passes

    master

    Fails

    The rule triggers when import statements and CommonJS exports are mixed in the same file:

    import { stuff } from 'starwars'
    module.exports = thing
    
    import * as allThings from 'starwars'
    exports.bar = thing
    
    import thing from 'other-thing'
    exports.foo = bar
    
    import thing from 'starwars'
    const baz = (module.exports = thing)
    console.log(baz)

    Passes

    • The Main Module: The rule is omitted for the file defined as the main entry point in your package.json.
    • Pure CommonJS: Files using only require and module.exports without any import statements.
    • Pure ESM: Files using only import and export statements.
    • Explicit Exceptions: Files that match the exceptions glob pattern in your configuration.

    Example of a passing package.json and its corresponding lib/index.js (the main module):

    {
      "main": "lib/index.js"
    }
    // lib/index.js (Passes because it is the 'main' module)
    import foo from 'path'
    module.exports = foo
  2. Understand the Resolver return value

    master

    All resolvers must return an object indicating if the module was found and, if applicable, its location. The first resolver to return { found: true } is treated as the source of truth.

    Return Object Schema

    • found (boolean): true if the source module can be resolved relative to file, otherwise false.
    • path (string | null):
      • An absolute path string if the module is located on the filesystem.
      • null if the module is a core/built-in module (e.g., fs or crypto) that can be resolved but does not have a specific file path the plugin needs to parse.

    If found is false, the path key is not required.

  3. Understand the import-x/export rule

    master

    The import-x/export rule detects conflicting or redundant export declarations within a single module. It specifically reports:

    • Multiple default exports: Attempting to export a default value more than once.
    • Duplicate named exports: Exporting the same identifier name multiple times (e.g., using both a declaration and an explicit export object).
    • Ambiguous re-exports: When multiple re-exports target the same name, the rule reports all of them because it cannot determine which one is the intended export.

    This rule is included in the following configurations:

    • errors
    • flat/errors
    • flat/recommended
    • recommended
    // Example: Multiple default exports
    export default class MyClass { /*...*/ }
    
    function makeClass() { return new MyClass(...arguments) }
    export default makeClass // Error: Multiple default exports.
  4. Understand the `import-x/group-exports` rule

    master

    The import-x/group-exports rule ensures that all exports of a module are consolidated into a single declaration. This makes it easier to identify the public API of a file at a glance.

    It reports two main types of violations:

    1. Multiple named export declarations: Using multiple export statements for variables or types in a single file.
    2. Multiple CommonJS assignments: Performing multiple assignments to module.exports or the exports object in a single file.

    Rationale: By requiring a single export declaration, all exports remain in one place, improving code readability and discoverability.

  5. How unusedExports works

    master

    When unusedExports: true is set, the rule reports exports that are not used by any other module in the project via static imports.

    Key Behaviors:

    • export * behavior: Using export * from 'module' only considers named exports and ignores the default export of the source module.
    • Package Entry Points: Exports from files listed as main, browser, or bin in package.json are ignored by default, unless the package is marked as private: true in package.json.
    // file-a.js
    export const a = 1 // Reported if not used elsewhere
    export { b, c }      // Not reported if used elsewhere
    export { d as e }     // Not reported if used elsewhere
    
    // file-c.js
    export default () => {} // Reported if using 'export *' from file-c
  6. Understand limitations and related rules for import-x/no-mutable-exports

    master

    Currently, import-x/no-mutable-exports does not flag the reassignment of exported function or class identifiers.

    To prevent general reassignment of these identifiers (both exported and unexported), you should complement this rule with the following core ESLint rules:

    • no-func-assign: Prevents assigning values to function identifiers.
    • no-class-assign: Prevents assigning values to class identifiers.
  7. Allowing empty dynamic imports with `allowEmpty: true`

    master

    If you set allowEmpty: true in the rule configuration, the rule will permit dynamic imports that do not have a webpackChunkName specified. This includes imports with no leading comment at all, or imports with a leading comment that contains other webpack magic comments but lacks a webpackChunkName.

    Note: Even with allowEmpty: true, if you do provide a webpackChunkName comment, it must still follow the correct formatting rules. Incorrectly formatted comments will still trigger an error.

    // Valid when allowEmpty: true
    import('someModule')
    
    // Still invalid even if allowEmpty: true (due to bad formatting)
    import(
      /*webpackChunkName:"someModule"*/
      'someModule'
    )
  8. Understand the `import-x/default` rule

    master

    The import-x/default rule ensures that when you attempt to use a default import, the target module actually provides a default export.

    Behavior:

    • If you request a default import, the rule reports an error if no default export is found in the module.
    • For ES7-style modules, it reports if a default is named and exported but cannot be found in the referenced module.
    • For npm packages, the plugin attempts to find exported names via the jsnext:main field in package.json (e.g., Redux supports this).
    • Exclusions: Module paths that are [ignored] or are not [unambiguously an ES module] will not be reported.

    Included in these configurations:

    • errors
    • flat/errors
    • flat/recommended
    • recommended
  9. Use exceptions in no-restricted-paths zones

    master

    You can use the except attribute within a zone to allow specific imports that would otherwise be blocked by the from path.

    Important constraints:

    1. If your from configuration uses glob patterns, your except configuration must also be an array of glob patterns.
    2. If your from configuration uses directory paths, your except paths are relative to the from directory and cannot use .. to backtrack to a parent directory.

    Example: Directory-based exception

    Given a structure where server/one is restricted from being imported into server/one/a.js, but you want to allow imports from a specific sub-folder ./one within that restricted path:

    {
      "zones": [
        {
          "target": "./tests/files/restricted-paths/server/one",
          "from": "./tests/files/restricted-paths/server",
          "except": ["./one"]
        }
      ]
    }
    {
      "zones": [
        {
          "target": "./tests/files/restricted-paths/server/one",
          "from": "./tests/files/restricted-paths/server",
          "except": ["./one"]
        }
      ]
    }