import-js / eslint-plugin-import

ESLint plugin with rules that help validate proper imports.
MIT License
5.55k stars 1.56k forks source link

[import/order] Inconsistent ordering #1867

Open artursvonda opened 4 years ago

artursvonda commented 4 years ago

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',
      },
    },
  ],
ljharb commented 4 years ago

This is true, but the CLI usually does multiple passes.

Happy to accept a PR to improve things here.