Eslint-plugin-import: Use same alphabetize props as ESLint sort-imports

Created on 27 Feb 2020  路  16Comments  路  Source: benmosher/eslint-plugin-import

ESLint's native sort-imports does the sorting I want, but doesn't care about the grouping of imports. On the other hand, import/order gives me the ordering I want, but not the powerful alphabetization sort from sort-imports.

For sort-imports, this is the config I use:

{
  'sort-imports': [
    'warn',
    {
      ignoreCase: true,
      memberSyntaxSortOrder: [
        'single',
        'all',
        'multiple',
        'none',
      ],
    },
  ],
}

I'd like to do something similar with import/order:

{
  alphabetize: {
    caseInsensitive: true,
    memberSyntaxSortOrder: [
      'single',
      'all',
      'multiple',
      'none',
    ],
    order: 'asc',
  },
}

I would like this functionality because I'm grouping them differently than the default:

{
  groups: [
    [
      'builtin',
      'external',
    ],
    [
      'index',
      'parent',
      'sibling',
    ],
  ],
}

Here's an example I'd expect to see:

import PropTypes from 'prop-types'
import React from 'react'

import useMediaQuery from './useMediaQuery'
import useMediaQueryState from './useMediaQueryState'
import { * as actions } from './actions'
import { breakpointsList } from './breakpoints'
import './styles.css'
imporexport ordering

Most helpful comment

I'd also like to have the imports inside the group sorted.

All 16 comments

import/order has alphabetize, does that not do what you want?

It does alphabetize, but the ordering is based on the from string (from what I can tell), not the characters of the variables you're importing.

That's why I was suggesting similar functionality to what's in the memberSyntaxSortOrder from the official ESLint import sorting. It allows you to say where the { should be ordered and where * and "no from" statements get ordered.

It also optionally has the ability to sort single-line imports as well so this would get alphabetically sorted in the deconstruction as well:

import { one, two } from './numbers'

Ah, thanks for clarifying.

I don't see value in sorting by the identifier names - especially since you can have multiples. What would you sort by in this:?

import { a as z, b, d }, c from 'e';

In your example, I'd keep c in front and sort the inside has you have it. I never even thought the default export could be after the deconstruction.

// Sorted deconstruction
import c, { a as z, b, d } from 'e';

Right, but then you're sorting by the exported names, but the importing default name. If the name the importer chooses is the primary bit, then i'd expect as z to win out over a.

That is a really good point!

My main concern is being able to quickly find things. If everything's alphabetical, it's in the same order each time no matter the component. It also needs to be something I could reasonably fix without

I have no opinion on sorting by a or z in a as z as long as it's easy to spot when skimming imports.

Are we in agreement on the other parts or is there more contention?

What's the use case tho? Like, what are you hoping to quickly find that you're not using grep ("find" in your editor), or "go to definition" jumping from a usage site?

Alphabetizing anything where order doesn't matter makes it easier to skim unimportant parts of PRs. There's also improved compression ratio because there are more situations where we have repeat code. And with code-consistency, it becomes easier to find and replace.

My main thing for me is having similar functionality to the official ESLint rule, but separating node_modules/ from local imports like eslint-plugin-import provides.

Would it help if I provided the PR myself? I completely understand if that's the determining factor here.

I appreciate that, and providing the PR certainly helps! While I strongly agree with the sentiment in making it easier to skip unimportant parts of PRs (reducing diff churn, eg), to me it's more important that the lint rule make sense on its own. Just sorting things for the sake of sorting them doesn't seem particularly compelling to me.

Just playing devil's advocate here, but couldn't you apply your rationale about "sorting things just for the sake of sorting" to the entire idea of grouping and sorting imports in general? If I'm looking to modify an existing import or looking over a PR that made such a modification, it seems just as nice to be able to find an import group as it is to find a imported member/identifier within a single statement.

There are rules to order object keys, vars, and as was pointed out here, rules in tslint or other eslint plugins to order the imported members. And this plugin orders and groups imports, so why would you not order the identifiers within? As for your example, I also don't particularly care about which way you choose to order, as long as it's consistent.

I'd also like to have the imports inside the group sorted.

just two cents from TypeScript world, in TSLint there was a rule ordered-imports and there was an option named-imports-order: "lowercase-first". As soon as TSLint is dead and everyone somehow migrates to eslint it would be nice to have similar option for compatibility.

I'd also like to have the imports inside the group sorted.

Same!

What I want:

  • imprts get grouped by path (the groups setting)
  • groups get sorted by syntax (the sort-imports memberSyntaxSortOrder setting)
  • syntax groups get sorted alphabetically by path
  • the variables inside a multiple import statement get sorted

I have the following config:

    'sort-imports': [
      'warn',
      {
        ignoreCase: true,
        memberSyntaxSortOrder: ['multiple', 'single', 'all', 'none']
      },
    ],
    'import/order': [
      'warn',
      {
        'groups': ['builtin', 'external', 'parent', 'sibling', 'index'],
        'pathGroups': [
          {
            pattern: 'react*',
            group: 'external',
            position: 'before',
          },
          {
            pattern: '@react*',
            group: 'external',
            position: 'before',
          },
        ],
        'pathGroupsExcludedImportTypes': ['builtin'],
        'newlines-between': 'never',
      },
    ],

example:

import React from 'react'
import anotherNodeModule from 'another-node-module'
import otherNodeModule from 'other-node-module'
import Something from '../something'
import {xSibling, ySibling, zSibling} from './lettered-siblings'
import sibling from './sibling'

This makes sort-imports complain anotherNodeModule should come before React. If memberSyntaxSortOrder would be included in this plugin, I could disable sort-imports.

It does not complain if I set 'newlines-between': 'always', and sort-imports allowSeparatedGroups: true, but then there would be quite a few import blocks that consist of a single import line and a newline, so I would like to avoid that if at all possible.

@ThaJay : this is pretty close to what I want. Fortunately in my case, the rules do work without conflict, but I lose auto fixing for the memberSyntaxSortOrder part.

Basically, I'm trying to emulate Python's isort. But isort has an easier time because you cannot combine default/namespace/named imports into one statement. It's all or nothing.

My platonic ideal:

import * as fs from "fs";

import * as reactivated from "reactivated";
import {Router, browserHistory} from "react-router";
import React from "react";

import * as typography from "@client/shared/typography";
import Login from "@client/scenes/Login";
import {useSceneSubmitHandler} from "@client/scenes/utils";

import * as constants from "./constants";
import * as style from "./style";
import {Thunk} from "./reducer";

First broken up by chunks (builtin, external, internal, relative). Then within that, grouped into import syntax. Then alphabetized.

Currently, this plugin can automate all but the last step. If I turn on alphabetize, I get this:

import * as fs from "fs";

import React from "react";
import {Router, browserHistory} from "react-router";
import * as reactivated from "reactivated";

import Login from "@client/scenes/Login";
import {useSceneSubmitHandler} from "@client/scenes/utils";
import * as typography from "@client/shared/typography";

import * as constants from "./constants";
import {Thunk} from "./reducer";
import * as style from "./style";

And that to be looks a lot worse. Moreover, I then need to disable memberSyntaxSortOrder otherwise I get a conflict.

So currently I can either: fully automate but lose grouping syntax, or almost fully automate but need to manually group syntax.

Compared to my previous config posted here, if I add ignoreDeclarationSort: true, to 'sort-imports' and add more pathGroups like so it works well enough:

'pathGroups': [
  {
    pattern: 'react',
    group: 'external',
    position: 'before',
  },
  {
    pattern: 'react-native',
    group: 'external',
    position: 'before',
  },
  {
    pattern: 'react*',
    group: 'external',
    position: 'before',
  },
  {
    pattern: '@react*',
    group: 'external',
    position: 'before',
  }
]
Was this page helpful?
0 / 5 - 0 ratings