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

[import/order] Inconsistent ordering

Open
#1,867 1 comment 0 reactions 0 assignees View on GitHub
enhancement help wanted import/export ordering
Dominant language
JavaScript
Stars
5.9k
Forks
1.5k
PR merge metrics
No merged PRs in 30d

Description

Looks like import order is not fixed in single step. I'm using graphql codegen and running eslint fix after codegen and after recent update to codegen and setting option to generate some imports as types, it no longer fixes order in a singe step. Here are results (changed import names a bit but left same initial capital letter)
```
// Initial generated file .../__generated__/T.tsx

import type * as Types from '../../../../../generated/graphql';

import type { Shared_TicketFragment } from 'r/components/T/__generated__/T';
import type { Shared_Ticket_DetailsFragment } from 'r/components/T/__generated__/D';
import type { Shared_Ticket_LogFragment } from 'r/components/T/__generated__/L';
import type { Shared_Ticket_CustomerFragment } from 'r/components/T/__generated__/C';
import type { Shared_Ticket_ManageFragment } from 'r/components/T/__generated__/M';
import gql from 'graphql-tag';
import { Shared_TicketFragmentDoc } from 'r/components/T/__generated__/T';
import { Shared_Ticket_DetailsFragmentDoc } from 'r/components/T/__generated__/D';
import { Shared_Ticket_LogFragmentDoc } from 'r/components/T/__generated__/L';
import { Shared_Ticket_CustomerFragmentDoc } from 'r/components/T/__generated__/C';
import { Shared_Ticket_ManageFragmentDoc } from 'r/components/T/__generated__/M';
import type * as ApolloReactCommon from '@apollo/react-common';
import * as ApolloReactHooks from '@apollo/react-hooks';

// Step 1
import type * as ApolloReactCommon from '@apollo/react-common';
import * as ApolloReactHooks from '@apollo/react-hooks';
import gql from 'graphql-tag';
import type { Shared_Ticket_CustomerFragment } from 'r/components/T/__generated__/C';
import { Shared_Ticket_CustomerFragmentDoc } from 'r/components/T/__generated__/C';
import type { Shared_Ticket_DetailsFragment } from 'r/components/T/__generated__/D';
import { Shared_Ticket_DetailsFragmentDoc } from 'r/components/T/__generated__/D';
import type { Shared_Ticket_LogFragment } from 'r/components/T/__generated__/L';
import { Shared_Ticket_LogFragmentDoc } from 'r/components/T/__generated__/L';
import type { Shared_Ticket_ManageFragment } from 'r/components/T/__generated__/M';
import { Shared_TicketFragmentDoc } from 'r/components/T/__generated__/T';
import { Shared_Ticket_ManageFragmentDoc } from 'r/components/T/__generated__/M';
import type { Shared_TicketFragment } from 'r/components/T/__generated__/T';

import type * as Types from '../../../../../generated/graphql';

// Step 2
import type * as ApolloReactCommon from '@apollo/react-common'
import * as ApolloReactHooks from '@apollo/react-hooks'
import gql from 'graphql-tag'
import type { Shared_Ticket_CustomerFragment } from 'r/components/T/__generated__/C'
import { Shared_Ticket_CustomerFragmentDoc } from 'r/components/T/__generated__/C'
import type { Shared_Ticket_DetailsFragment } from 'r/components/T/__generated__/D'
import { Shared_Ticket_DetailsFragmentDoc } from 'r/components/T/__generated__/D'
import type { Shared_Ticket_LogFragment } from 'r/components/T/__generated__/L'
import { Shared_Ticket_LogFragmentDoc } from 'r/components/T/__generated__/L'
import type { Shared_Ticket_ManageFragment } from 'r/components/T/__generated__/M'
import { Shared_Ticket_ManageFragmentDoc } from 'r/components/T/__generated__/M'
import { Shared_TicketFragmentDoc } from 'r/components/T/__generated__/T'
import type { Shared_TicketFragment } from 'r/components/T/__generated__/T'

import type * as Types from '../../../../../generated/graphql'
```
eslint config
```
{
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:@typescript-eslint/recommended-requiring-type-checking',
'plugin:react/recommended',
'airbnb',
'airbnb/hooks',
'prettier',
'prettier/@typescript-eslint',
'prettier/react',
],

parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'react', 'react-hooks', 'prettier', 'import'],
parserOptions: {
project: './tsconfig.json',
sourceType: 'module',
ecmaVersion: 2018,
ecmaFeatures: {
jsx: true,
},
},
ignorePatterns: ['*.json'],
settings: {
react: {
version: 'detect',
},
'import/resolver': {
typescript: {},
},
},
env: {
es6: true,
browser: true,
jest: true,
},
rules: {
curly: ['error'],
'eol-last': ['error', 'always'],
'dot-notation': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/explicit-module-boundary-types': 'off',
'@typescript-eslint/interface-name-prefix': 'off',
'react/display-name': 'off',
'react/prop-types': 'off',
'react-hooks/exhaustive-deps': 'warn',
'newline-before-return': 'warn',
'sort-imports': ['warn', { ignoreDeclarationSort: true, ignoreCase: true }],
'import/order': [
'error',
{
'newlines-between': 'always',
pathGroupsExcludedImportTypes: ['builtin'],
pathGroups: internalPaths.map((path) => ({ pattern: path, group: 'internal' })),
groups: ['builtin', 'external', ['internal'], ['parent', 'sibling'], 'index'],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
},
],
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
'react/jsx-filename-extension': [1, { extensions: ['.tsx', '.jsx'] }],
'import/prefer-default-export': 'off',
'react/jsx-props-no-spreading': 'warn',
'no-underscore-dangle': 'off',
'jsx-a11y/anchor-is-valid': 'warn',
'jsx-a11y/click-events-have-key-events': 'warn',
'jsx-a11y/no-static-element-interactions': 'warn',
'no-unused-expressions': ['error', { allowTaggedTemplates: true }],
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-return': 'warn',
'@typescript-eslint/no-unsafe-assignment': 'warn',
'@typescript-eslint/restrict-template-expressions': ['warn', { allowNumber: true }],
'@typescript-eslint/no-unsafe-call': 'warn',
'react/require-default-props': 'off',
'react/state-in-constructor': 'off',
},
globals: {
process: true,
},
overrides: [
{
files: ['**/generated/graphql.ts', '**/__generated__/*.ts'],
rules: {
'@typescript-eslint/no-explicit-any': 'off',
'@typescript-eslint/camelcase': 'off',
camelcase: 'off',
'import/no-duplicates': 'off',
},
},
],
```

Contributor guide

Open the contributing guide

Research direction

Start by reproducing the reported two-pass behavior with the shown import/order configuration, TypeScript imports, and generated-file examples. Trace the import/order rule's reported ordering and autofix behavior; done means the affected imports reach the intended order in a single eslint --fix run, with regression coverage for the example.

Written by the indexing model from the issue text.

Assessment

Tech stack
eslint, graphql, 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.