import-js / import-js/eslint-plugin-import

import/no-cycle crashing with external ESM modules (TypeError: Cannot read properties of null)

Open
#3,221 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
JavaScript
Stars
5.9k
Forks
1.5k
PR merge metrics
No merged PRs in 30d

Description

Minimum reproduction here (see README).

The Issue

(Please note that eslint-import-resolver-exports has been patched in this project to provide some logs)

  1. Run yarn lint:ok
  2. Linting is completed successfully
  3. Run yarn lint:not-ok
  4. Linting fails with the following error:
Oops! Something went wrong! :(

ESLint: 8.57.1

TypeError: Cannot read properties of null (reading '/Users/username/repositories/eslint-plugin-import-issue-1/src/not-ok.js')
Occurred while linting /Users/username/repositories/eslint-plugin-import-issue-1/src/not-ok.js:1
Rule: "import/no-cycle"
    at checkSourceValue (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint-plugin-import/lib/rules/no-cycle.js:116:59)
    at checkSourceValue (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint-module-utils/moduleVisitor.js:32:5)
    at checkSource (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint-module-utils/moduleVisitor.js:38:5)
    at ruleErrorHandler (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint/lib/linter/linter.js:1076:28)
    at /Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint/lib/linter/safe-emitter.js:45:58
    at Array.forEach (<anonymous>)
    at Object.emit (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint/lib/linter/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint/lib/linter/node-event-generator.js:297:26)
    at NodeEventGenerator.applySelectors (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint/lib/linter/node-event-generator.js:326:22)
    at NodeEventGenerator.enterNode (/Users/username/repositories/eslint-plugin-import-issue-1/node_modules/eslint/lib/linter/node-event-generator.js:340:14)
The Details
  • yarn lint:ok lints ./src/ok.js file with the following content:
import {default as inquirer} from 'inquirer';
  • yarn lint:not-ok lints ./src/not-ok.js file with the following content:
import {default as figures} from 'figures';
  • inquirer has the following relevant package.json fields:
{
    "type": "module",
    "exports": {
        "./package.json": "./package.json",
        ".": {
            "import": {
                "types": "./dist/esm/index.d.ts",
                "default": "./dist/esm/index.js"
            },
            "require": {
                "types": "./dist/commonjs/index.d.ts",
                "default": "./dist/commonjs/index.js"
            }
        }
    },
    "main": "./dist/commonjs/index.js",
    "module": "./dist/esm/index.js",
    "types": "./dist/commonjs/index.d.ts"
}
  • figures has the following relevant package.json fields:
{
    "type": "module",
    "exports": {
        "types": "./index.d.ts",
        "default": "./index.js"
    }
}
  • The important main difference is that inquirer is a hybrid package with both ESM and CJS entry points, whether figures is ESM only.
  • Using the following settings, we make so that require condition is preferred over import condition:
{
    "import/resolver": {
        "exports": {
            "require": true
        }
    }
}
  • So, inquirer is loaded in CJS format, while figures is loaded in ESM, which is what is making ESLint crash. In fact, if we go into the index.js of figures and remove all ESM import/export statements, the issue goes away.

  • So, it would seem that ESM is supported in project files, but not inside node_modules files, but the strange things are:

    • If we remove eslint-import-resolver-exports from the settings, the issue goes away, even if the resolver is doing its job flawlessly (see logs). But we loose support for exports.
    • The issue seems to not be present when using eslint-import-resolver-typescript.
    • It is like if eslint-import-resolver-exports was missing something in the returned data or something.

Finally, the most strange thing to me is that if we tweak eslint-import-resolver-exports to skip external modules, or just figures in this case, the issue also goes away.

Also, the following makes the issue go away:

{
    "import/no-cycle": [
        "error",
        {
            "ignoreExternal": true
        }
    ]
}

(even if, as a side effect, ignoreExternal seems to increase linting time instead of reducing it as I would have expected)

So, is import/no-cycle really checking external modules? Or it is just working because the external files are not being resolved in most cases?

Is it an issue with eslint-import-resolver-exports?

I am available to work on this (I already adopted eslint-import-resolver-exports and will publish an updated version of it in the future).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the linked minimum reproduction with yarn lint:ok and yarn lint:not-ok, then inspect lib/rules/no-cycle.js at checkSourceValue and the resolver data involved in the reported stack trace. Compare the behavior with and without eslint-import-resolver-exports, and confirm the fix by ensuring the external ESM case no longer crashes while cycle checking remains correct.

Written by the indexing model from the issue text.

Assessment

Tech stack
eslint, javascript
Domain
devtools, tooling
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.