eslint-plugin-import icon indicating copy to clipboard operation
eslint-plugin-import copied to clipboard

no-relative-parent-imports over-reporting when import/resolver = typescript

Open michaelfarrell76 opened this issue 6 years ago • 24 comments
trafficstars

I have been using the following tslint rule:

"no-relative-imports": [true, "allow-siblings"],

to forbid any relative imports such as import constants from '../constants'

I am trying to migrate my tslint rules to eslint, and it seems like the rule import/no-relative-parent-imports should be what I am looking for. However, when I turn the rule on, all of my imports that are path rewrites in my tsconfig file report errors. See image below.

Screen Shot 2019-06-22 at 4 53 56 PM

I have the following tsconfig.json

  ...
  "baseUrl": ".",
  "paths": {
     "@commons/*": ["./commons/src/*"]
  },
  ...

And the following eslintrc.js

 ...
 "import/no-relative-parent-imports": ["warn"],
 ...
 "settings": {
    "import/resolver": {
      "typescript": {},
    }
  }

...

When I log out the input before the error is reported here, I see the following paths getting reported:

../../types.ts
../../types.ts { id: 'import/no-relative-parent-imports',

It seems as though the typescript import/resolver is translating the paths before they are applied to this eslint check. Is there a way that I can configure my eslint to work with this use case? or is this not yet possible

michaelfarrell76 avatar Jun 22 '19 23:06 michaelfarrell76

the point of the rule is about resolved parent imports, not aliased ones - if all you want is to block ../ you can use no-restricted-syntax and an AST selector.

I think it would work the same with a webpack alias.

ljharb avatar Jun 25 '19 01:06 ljharb

What TS parser are you using? I don't think it's the resolver, I think it's the TS parser rewriting the path before the lint rule runs.

benmosher avatar Jun 29 '19 03:06 benmosher

@benmosher "parser": "@typescript-eslint/parser", the parser is rewriting, I can allow for the parser to rewrite but have the rule be applied before then

michaelfarrell76 avatar Jun 29 '19 21:06 michaelfarrell76

I'm not sure what you mean. I think the parser always runs before the lint rule.

The parser would need to choose not to process the paths first. I am not 100% sure it's doing this but when I looked at the code for no-relative-parent-imports IIRC it's using the path straight from the AST.

benmosher avatar Jul 01 '19 19:07 benmosher

Sorry, I just double-checked and I must have looked in the wrong place before. It is resolving the path inside the rule which means it is the plugin's problem.

benmosher avatar Jul 01 '19 19:07 benmosher

wait, @ljharb, by this

the point of the rule is about resolved parent imports, not aliased ones

you mean that you think this rule shouldn't only fire on import paths that start with ..?

benmosher avatar Jul 01 '19 19:07 benmosher

I think the fix for #1123 was an overcorrection and it should still check for a leading . in the path. if you agree, @ljharb?

benmosher avatar Jul 01 '19 19:07 benmosher

@benmosher no, what i mean is, the path you type in your code shouldn't matter - only what it resolves to should matter.

ljharb avatar Jul 03 '19 06:07 ljharb

if all you want is to block ../ you can use no-restricted-syntax and an AST selector

@ljharb This is not a great option when extending a config such as eslint-config-airbnb that already enables no-restricted-syntax with its own config, since any options I set on the rule would clobber the ones from the shared config. I could write my own rule, but that seems like overkill.

And while some might be using this rule to prevent resolution of imports higher in the tree, I just want to prevent the use of .. in imports since it makes them inherently fragile if files are moved to a different level in the tree, and because paths starting with chains of ../.. are hard to read. I do specifically care about the way that import paths are specified.

smably avatar Jul 15 '19 03:07 smably

@smably you're correct about the difficulty there; you could write your own rule using eslint-rule-composer and no-restricted-syntax, though.

.. doesn't make things any more fragile than literally any other path. Any file rename or move potentially means you have to update all consumers. The "hard to read" part, I disagree with but recognize is subjective.

ljharb avatar Jul 15 '19 04:07 ljharb

.. doesn't make things any more fragile than literally any other path.

It may be true that the path is equally "fragile" on a rename or move but if the paths are absolute (or pseudo-absolute by using an alias), when you move a file you have a much stronger understanding of where that path moved to.

Take for example the two pieces of code:

Relative

import addTwoNumbers from '../addToNumbers';

Aliased

import addTwoNumbers from '@backend/utils/addToNumbers';

Say i now move the function addToNumbers to my common utility function module because I want to share it with my frontend project.

the new code will be

Aliased Updated

import addTwoNumbers from '@commons/utils/addToNumbers';

Both of the relative and aliased paths will require an update of course but I can now do a find and replace in my editor for @backend/utils/addToNumbers -> @commons/utils/addToNumbers which is incredibly easy in the case of aliased paths, but I will have to manually go through all relative paths because a find and replace on ../ is not as simple.

However, I do understand if this is the wrong rule for this desired outcome.

michaelfarrell76 avatar Jul 16 '19 00:07 michaelfarrell76

Yes - I think you want a custom rule that forces every specifier to be bare - ie, to forbid relative paths entirely.

ljharb avatar Jul 16 '19 05:07 ljharb

just ran into the same issue. an easy solution maybe: https://github.com/benmosher/eslint-plugin-import/issues/669#issuecomment-316438608

mosanger avatar Jul 17 '19 15:07 mosanger

The unfortunate thing about the workaround in #669 is that it doesn't allow adding custom error messages, because no-restricted-import only allows custom error messages for exact path matches (but not patterns). So the developer will see "this import is restricted by a pattern" but no explanation of why.

bduffany avatar Jun 12 '20 20:06 bduffany

I'm running into an issue that ../../foo/bar.ts is correctly reported as an error but ../../foo/bar is not. Is that within the scope of this issue or should I start a new one?

bduffany avatar Jun 12 '20 20:06 bduffany

I would expect both to resolve to the same thing if the typescript resolver is set up properly.

ljharb avatar Jun 13 '20 05:06 ljharb

@ljharb they do both resolve to the same thing and import correctly at runtime. But one is reported as an error by ESLint when no-restricted-import is enabled and one is not. I would expect both to be reported as errors by ESLint because both are relative imports.

bduffany avatar Jun 16 '20 21:06 bduffany

Yes, I agree with you.

ljharb avatar Jun 16 '20 22:06 ljharb

Any news for this problem? It is prohibiting the use of the no-relative-parent-imports rule in TS packages with path aliases.

adarnon avatar Jan 26 '21 20:01 adarnon

Here is how I implemented this on a NestJS project with Typescript:

module.exports = {
  rules: {
    'no-restricted-imports': ['error', {'patterns': ['..*']}],
  },
};

It prevents any import statement that references the parent dir as relative, forcing the use of an alias. I didn't figure out how to add a custom message.

josephdpurcell avatar Apr 21 '21 17:04 josephdpurcell

I didn't figure out how to add a custom message.

Here's an example of a custom message (docs):

module.exports = {
  rules: {
    'no-restricted-imports': [
      'error',
      {
        patterns: [
          {
            group: ['../*'],
            message: 'Usage of relative parent imports is not allowed.',
          },
        ],
      },
    ],
  },
};

johnjensenish avatar Jul 02 '21 01:07 johnjensenish

close in favor of https://github.com/import-js/eslint-import-resolver-typescript

Feel free to comment if it still occurs.

JounQin avatar Jul 19 '22 19:07 JounQin

@jounqin this one seems to already be using the TS resolver

ljharb avatar Jul 19 '22 19:07 ljharb

@JounQin this one seems to already be using the TS resolver

Hah, sorry to misread the thread.

But there is no reproduction was provided, so it's hard to tell what was the cause then.

JounQin avatar Jul 19 '22 20:07 JounQin