eslint: Bug: no-restricted-imports shows an error only on last element when using an array of different importNames and same name

Environment

Environment Info:

Node version: v15.10.0 npm version: v7.5.3 Local ESLint version: v7.27.0 (Currently used) Global ESLint version: Not found Operating System: darwin 20.6.0

What parser are you using?

@typescript-eslint/parser

What did you do?

Configuration
'use strict'

module.exports = {
  root: true,
  plugins: ['@typescript-eslint', 'react', 'jest', 'testing-library', 'prettier'],
  settings: {
    react: {
      pragma: 'React',
      version: '16.3'
    }
  },
  extends: [
    '@react-native-community',
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:jest/recommended',
    'plugin:testing-library/react',
    'prettier'
  ],
  env: {
    browser: true,
    commonjs: true,
    es6: true,
    node: true,
    jest: true
  },
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 7,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
      generators: true,
      impliedStrict: true,
      experimentalObjectRestSpread: true
    }
  },
  rules: {
    'react/prop-types': [0],
    'prettier/prettier': 'error',
    '@typescript-eslint/explicit-member-accessibility': 'off',
    '@typescript-eslint/no-floating-promises': 'off',
    'jest/no-try-expect': 'off',
    'jest/no-conditional-expect': 'off',
    'react-hooks/exhaustive-deps': 'warn',
    'no-redeclare': 'warn',
    'testing-library/prefer-screen-queries': 'off', //https://github.com/testing-library/eslint-plugin-testing-library/blob/main/docs/rules/prefer-screen-queries.md
    'testing-library/await-async-query': 'warn',
    /* Temporally inactive rules to be changed ultimately little by little */
    'jest/no-mocks-import': 'warn',
    'react/display-name': 'warn',
    'react/no-did-update-set-state': 'warn',
    'no-console': 'error',
    'no-restricted-imports': [
      'error',
      {
        paths: [
          { name: 'react-native', importNames: ['Text'], message: 'import Text from ui/_components instead ' },
          {
            name: 'react-native',
            importNames: ['TextInput'],
            message: 'import TextInput from ui/_components instead '
          },
          { name: 'react-native', importNames: ['View'], message: 'import View from ui/_components instead ' },
          {
            name: 'react-native',
            importNames: ['ScrollView'],
            message: 'import ScrollView from ui/_components instead '
          },
          {
            name: 'react-native',
            importNames: ['KeyboardAvoidingView'],
            message: 'import KeyboardAvoidingView from ui/_components instead '
          },
          {
            name: 'react-native',
            importNames: ['ImageBackground'],
            message: 'import ImageBackground from ui/_components instead '
          },
          {
            name: 'react-native',
            importNames: ['Image'],
            message: 'import Image from ui/_components instead '
          }
        ]
      }
    ]
  },
  overrides: [
    {
      files: ['*.ts', '*.tsx'],
      rules: {
        '@typescript-eslint/explicit-member-accessibility': ['error', { accessibility: 'no-public' }],
        'no-unused-vars': 'off' //Causes duplicates with typescript-eslint/no-unused-vars
      }
    }
  ],
  globals: {
    process: true,
    fetchMock: true
  }
}

import { Image , Text, ScrollView } from 'react-native'

Eslint only shows an error on Image as it is de last element of the array. If moving Text for example to the end of the array then it will show an error only on Text not on Image or ScrollView

What did you expect to happen?

$ eslint --quiet --ext=js,jsx,ts,tsx ./src

/Users/user1/workspace/MyAPP/src/ui/_components/atoms/Icon/Icon.tsx 2:10 error ‘Image’ import from ‘react-native’ is restricted. import Image from ui/_components instead no-restricted-imports 2:17 error ‘ScrollView’ import from ‘react-native’ is restricted. import ScrollView from ui/_components instead no-restricted-imports 2:29 error ‘Text’ import from ‘react-native’ is restricted. import Text from ui/_components instead no-restricted-imports

✖ 3 problems (3 errors, 0 warnings)

error Command failed with exit code 1.

What actually happened?

$ eslint --quiet --ext=js,jsx,ts,tsx ./src

/Users/user1/workspace/MyAPP/src/ui/_components/atoms/Icon/Icon.tsx 2:10 error ‘Image’ import from ‘react-native’ is restricted. import Image from ui/_components instead no-restricted-imports

✖ 1 problem (1 error, 0 warnings)

error Command failed with exit code 1.

Participation

  • I am willing to submit a pull request for this issue.

Additional comments

No response

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Reactions: 1
  • Comments: 21 (20 by maintainers)

Commits related to this issue

Most upvoted comments

FYI: the test that ensures errors thrown in rules are bubbled up:

https://github.com/eslint/eslint/blob/04e91b615743cbb25cd9103e7329b056bd1572ad/tests/lib/linter/linter.js#L79

We can’t really convert thrown errors into linting errors because we don’t have any location information to associate with it (because the error isn’t in the file being linted but rather in the rule source).

On the other hand, it seems feasible to merge multiple path objects with the same name into one before running the rule. I’d argue that behavior is more expected than the current one.

As a solution can we introduce a new option importNameWithMessage which will be an Array that will contain objects with the key importName and message something like this

"rules": {
        "no-restricted-imports": ["error", 
        {
            paths: [
                {
                    name: "react-native",
                    importNamesWithMessage: [
                        {
                            importName: "TextInput",
                            message: "import TextInput from ui/_components instead"
                        },
                        {
                            importName: "Image",
                            message: "import Image from ui/_components instead"
                        },
                    ]
                }
            ]
        }
    ]
    }

The use case of a custom message for each named import seems valuable; if it was meant to be unique names, I’d expect it to have been an object with paths as keys instead of an array.