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

[no-extraneous-dependencies] relative path that refers to file outside package.json should error

Open
#3,067 13 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

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

Description

Hi, I'm not sure if the current behavior is intended or not, so I want to start a discussion.

Simple setup
Directory
src/
├── package.json
├── node_modules/
├── .eslintrc.json
├── tsconfig.json
├── client/
├── server/
│   ├── package.json
│   ├── node_modules/
│   └── index.ts
└── shared/
    └── util.ts
tsconfig
{
  "compilerOptions": {
    "paths": {
      "@/utils/*": ["./utils/*"]
    }
}
eslint
"import/no-extraneous-dependencies": ["error", { "packageDir": [".", "./server"] }],
Example 1 with TS Path Alias: Errors as expected

However, the below uses the typescript path alias, which does error. In this case, the plugin resolves it as an external import. https://github.com/import-js/eslint-plugin-import/blob/main/src/core/importType.js#L100

// src/server/index.ts
import util from '@/shared/util';
Example 2 with relative import: No error (Bug?)

When doing the following, there is no error from the rule. This is because the plugin considers it a parent import. https://github.com/import-js/eslint-plugin-import/blob/main/src/core/importType.js#L97

// src/server/index.ts
import util from '../shared/util';
Discussion

I'm not sure I agree with the discrepancy in the above behavior. It doesn't really make sense to me that both methods resolve to the same file, but the rule treats them differently. I think using a relative path to refer to a file outside the enclosing package.json context should cause no-extraneous-dependencies to error.

Next Steps / Solution (?)

The core of the issue seems to be that the typeTest() function is overloaded. In this case, it actually seems like it's a bug when used for this rule. In Example 2, typeTest returns "parent", causing the rule to fail to report the error. The correct behavior was actually for typeTest to return "external".

(aside: I think the above bug makes isExternalModule() and isExternalModuleMain() bugged as well)

@ljharb Is the above assessment accurate?

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

Start by reading src/core/importType.js, especially typeTest(), isExternalModule(), and isExternalModuleMain(), then inspect src/rules/no-extraneous-dependencies.js where the result is used. Reproduce the two imports from the issue and review existing rule tests if available. Done means the relative import outside the package.json context is handled consistently with the path-alias case.

Written by the indexing model from the issue text.

Assessment

Tech stack
javascript, typescript
Domain
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.