Coder Social home page Coder Social logo

eslint-plugin-simple-import-sort's Introduction

eslint-plugin-simple-import-sort

Easy autofixable import sorting.

This is for those who use eslint --fix (autofix) a lot and want to completely forget about sorting imports!

Example

import React from "react";
import Button from "../Button";

import styles from "./styles.css";
import type { User } from "../../types";
import { getUser } from "../../api";

import PropTypes from "prop-types";
import classnames from "classnames";
import { truncate, formatNumber } from "../../utils";

⬇️

import classnames from "classnames";
import PropTypes from "prop-types";
import React from "react";

import { getUser } from "../../api";
import type { User } from "../../types";
import { formatNumber, truncate } from "../../utils";
import Button from "../Button";
import styles from "./styles.css";

More examples

Installation

npm install --save-dev eslint-plugin-simple-import-sort

ℹ️ This is an ESLint plugin. 👉 Getting Started with ESLint

Usage

  • eslintrc: Add "simple-import-sort" to the "plugins" array in your .eslintrc.* file, and add the rules for sorting imports and exports. By default ESLint doesn’t parse import syntax – the "parserOptions" is an example of how to enable that.

    {
      "plugins": ["simple-import-sort"],
      "rules": {
        "simple-import-sort/imports": "error",
        "simple-import-sort/exports": "error"
      },
      "parserOptions": {
        "sourceType": "module",
        "ecmaVersion": "latest"
      }
    }
  • eslint.config.js (flat config): Import eslint-plugin-simple-import-sort, put it in the plugins object, and add the rules for sorting imports and exports. With flat config, import syntax is enabled by default.

    import simpleImportSort from "eslint-plugin-simple-import-sort";
    
    export default [
      {
        plugins: {
          "simple-import-sort": simpleImportSort,
        },
        rules: {
          "simple-import-sort/imports": "error",
          "simple-import-sort/exports": "error",
        },
      },
    ];

Make sure not to use other sorting rules at the same time:

ℹ️ Note: There used to be a rule called "simple-import-sort/sort". Since version 6.0.0 it’s called "simple-import-sort/imports".

Example configuration

This example uses eslint-plugin-import, which is optional.

It is recommended to also set up Prettier, to help formatting your imports (and all other code) nicely.

{
  "parserOptions": {
    "sourceType": "module",
    "ecmaVersion": "latest"
  },
  "plugins": ["simple-import-sort", "import"],
  "rules": {
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
    "import/first": "error",
    "import/newline-after-import": "error",
    "import/no-duplicates": "error"
  }
}
  • "sourceType": "module" and "ecmaVersion": "latest" are needed so ESLint doesn’t report import and export as syntax errors.
  • simple-import-sort/imports and simple-import-sort/exports are turned on for all files.
  • import/first makes sure all imports are at the top of the file. (autofixable)
  • import/newline-after-import makes sure there’s a newline after the imports. (autofixable)
  • import/no-duplicates merges import statements of the same file. (autofixable, mostly)

Not for everyone

This plugin is not for everyone. Let me explain.

For a long time, this plugin used to have no options, which helped keeping it simple.

While the human alphabetical sorting and comment handling seems to work for a lot of people, grouping of imports is more difficult. Projects differ too much to have a one-size-fits-all grouping.

I’ve decided to have this single option but nothing more. Here are some things you can’t configure:

  • The sorting within each group. It is what it is. See Sorting.
  • Sorting of side effect imports (they always stay in the original order).

If you want more options, I recommend using the import/order rule (from eslint-plugin-import) instead. It has plenty of options, and the maintainers seem interested in expanding the feature where it makes sense.

Then why does this plugin exist? See How is this rule different from import/order?.

If we start adding more options to this plugin, it won’t be eslint-plugin-simple-import-sort anymore. Eventually it would have no reason to exist – effort would be better spent contributing to import/order.

I made this plugin for myself. I use it in many little projects and I like it. If you like it too – I’m very glad to hear! But everyone won’t like it. And that’s ok.

Sort order

This plugin is supposed to be used with autofix, ideally directly in your editor via an ESLint extension, or with eslint --fix otherwise.

This section is for learning how the sorting works, not for how to manually fix errors. Use autofix!

TL;DR: First group, then sort alphabetically.

Grouping

imports

First, the plugin finds all chunks of imports. A “chunk” is a sequence of import statements with only comments and whitespace between. Each chunk is sorted separately. Use import/first if you want to make sure that all imports end up in the same chunk.

Then, each chunk is grouped into sections with a blank line between each.

  1. import "./setup": Side effect imports. (These are not sorted internally.)
  2. import * as fs from "node:fs": Node.js builtin modules prefixed with node:.
  3. import react from "react": Packages (npm packages and Node.js builtins without node:).
  4. import a from "/a": Absolute imports and other imports such as Vue-style @/foo.
  5. import a from "./a": Relative imports.

Note: The above groups are very loosely defined. See Custom grouping for more information.

exports

Sequences of re-exports (exports with from) are sorted. Other types of exports are not reordered.

Unlike imports, there’s no automatic grouping of exports. Instead a comment on its own line starts a group. This leaves the grouping up to you to do manually.

The following example has 3 groups (one with “x” and “y”, one with “a” and “b” and one with “./”):

export * from "x";
export * from "y";

// This comment starts a new group.
/* This one does not. */ export * from "a"; // Neither does this one.
/* Nor this
one */ export * from "b";
/* But this one does. */
export * from "./";

Each group is sorted separately, and the groups themselves aren’t sorted – they stay where you wrote them.

Without the grouping comments the above example would end up like this:

export * from "./";
/* This one does not. */ export * from "a"; // Neither does this one.
/* Nor this
one */ export * from "b";
export * from "x";
export * from "y";

Sorting

Within each section, the imports/exports are sorted alphabetically on the from string (see also “Why sort on from?”). Keep it simple! It helps looking at the code here:

const collator = new Intl.Collator("en", {
  sensitivity: "base",
  numeric: true,
});

function compare(a, b) {
  return collator.compare(a, b) || (a < b ? -1 : a > b ? 1 : 0);
}

In other words, the imports/exports within groups are sorted alphabetically, case-insensitively and treating numbers like a human would, falling back to good old character code sorting in case of ties. See Intl.Collator for more information. Note: Intl.Collator sorts punctuation in some defined order. I have no idea what order punctuation sorts in, and I don’t care. There’s no ordered “alphabet” for punctuation that I know of.

There’s one addition to the alphabetical rule: Directory structure. Relative imports/exports of files higher up in the directory structure come before closer ones – "../../utils" comes before "../utils", which comes before ".". (In short, . and / sort before any other (non-whitespace, non-control) character. ".." and similar sort like "../," (to avoid the “shorter prefix comes first” sorting concept).)

If both import type and regular imports are used for the same source, the type imports come first. Same thing for export type. (You can move type imports to their own group, as mentioned in custom grouping.)

Example

// Side effect imports. (These are not sorted internally.)
import "./setup";
import "some-polyfill";
import "./global.css";

// Node.js builtins prefixed with `node:`.
import * as fs from "node:fs";

// Packages.
import type A from "an-npm-package";
import a from "an-npm-package";
import fs2 from "fs";
import b from "https://example.com/script.js";

// Absolute imports and other imports.
import c from "/";
import d from "/home/user/foo";
import Error from "@/components/error.vue";

// Relative imports.
import e from "../..";
import type { B } from "../types";
import f from "../Utils"; // Case insensitive.
import g from ".";
import h from "./constants";
import i from "./styles";

// Different types of exports:
export { a } from "../..";
export { b } from "/";
export { Error } from "@/components/error.vue";
export * from "an-npm-package";
export { readFile } from "fs";
export * as ns from "https://example.com/script.js";

// This comment groups some more exports:
export { e } from "../..";
export { f } from "../Utils";
export { g } from ".";
export { h } from "./constants";
export { i } from "./styles";

// Other exports – the plugin does not touch these, other than sorting named
// exports inside braces.
export var one = 1;
export let two = 2;
export const three = 3;
export function func() {}
export class Class {}
export type Type = string;
export { named, other as renamed };
export type { T, U as V };
export default whatever;

Regardless of group, imported items are sorted like this:

import {
  // Numbers are sorted by their numeric value:
  img1,
  img2,
  img10,
  // Then everything else, alphabetically:
  k,
  L, // Case insensitive.
  m as anotherName, // Sorted by the “external interface” name “m”, not “anotherName”.
  m as tie, // But do use the file-local name in case of a tie.
  // Types are sorted as if the `type` keyword wasn’t there.
  type x,
  y,
} from "./x";

Exported items are sorted even for exports without from (even though the whole export statement itself isn’t sorted in relation to other exports):

export {
  k,
  L, // Case insensitive.
  anotherName as m, // Sorted by the “external interface” name “m”, not “anotherName”.
  // tie as m, // For exports there can’t be ties – all exports must be unique.
  // Types are sorted as if the `type` keyword wasn’t there.
  type x,
  y,
};
export type { A, B, A as C };

At first it might sound counter-intuitive that a as b is sorted by a for imports, but by b for exports. The reason for doing it this way is to pick the most “stable” name. In import { a as b } from "./some-file.js", the as b part is there to avoid a name collision in the file without having to change some-file.js. In export { b as a }, the b as part is there to avoid a name collision in the file without having to change the exported interface of the file.

Custom grouping

There is one option (see Not for everyone) called groups that is useful for a bunch of different use cases.

groups is an array of arrays of strings:

type Options = {
  groups: Array<Array<string>>;
};

Each string is a regex (with the u flag). The regexes decide which imports go where. (Remember to escape backslashes – it’s "\\w", not "\w", for example.)

The inner arrays are joined with one newline; the outer arrays are joined with two – creating a blank line. That’s why there are two levels of arrays – it lets you choose where to have blank lines.

Here are some things you can do:

  • Move non-standard import paths like src/Button and @company/Button out of the (third party) “packages” group, into their own group.
  • Move react first.
  • Avoid blank lines between imports by using a single inner array.
  • Make a separate group for style imports.
  • Separate ./ and ../ imports.
  • Not use groups at all and only sort alphabetically.

If you’re looking at custom grouping because you want to move non-standard import paths like src/Button (with no leading ./ or ../) and @company/Button – consider instead using names that do not look like npm packages, such as @/Button and ~company/Button. Then you won’t need to customize the grouping at all, and as a bonus things might be less confusing for other people working on the code base.

See issue #31 for some tips on what you can do if you have very complex requirements.

Note: For exports the grouping is manual using comments – see exports.

Each import is matched against all regexes on the from string. The import ends up at the regex with the longest match. In case of a tie, the first matching regex wins.

If an import ends up in the wrong place – try making the desired regex match more of the from string, or use negative lookahead ((?!x)) to exclude things from other groups.

Imports that don’t match any regex are put together last.

Side effect imports have \u0000 prepended to their from string (starts with \u0000). You can match them with "^\\u0000".

Type imports have \u0000 appended to their from string (ends with \u0000). You can match them with "\\u0000$" – but you probably need more than that to avoid them also being matched by other regexes.

All imports that match the same regex are sorted internally as mentioned in Sort order.

This is the default value for the groups option:

[
  // Side effect imports.
  ["^\\u0000"],
  // Node.js builtins prefixed with `node:`.
  ["^node:"],
  // Packages.
  // Things that start with a letter (or digit or underscore), or `@` followed by a letter.
  ["^@?\\w"],
  // Absolute imports and other imports such as Vue-style `@/foo`.
  // Anything not matched in another group.
  ["^"],
  // Relative imports.
  // Anything that starts with a dot.
  ["^\\."],
];

The astute reader might notice that the above regexes match more than their comments say. For example, "@config" and "_internal" are matched as packages, but none of them are valid npm package names. ".foo" is matched as a relative import, but what does ".foo" even mean? There’s little gain in having more specific rules, though. So keep it simple!

See the examples for inspiration.

Comment and whitespace handling

When an import/export is moved through sorting, its comments are moved with it. Comments can be placed above an import/export (except the first one – more on that later), or at the start or end of its line.

Example:

// comment before import chunk
/* c1 */ import c from "c"; // c2
// b1
import b from "b"; // b2
// a1

/* a2
 */ import a /* a3 */ from "a"; /* a4 */ /* not-a
*/ // comment after import chunk

⬇️

// comment before import chunk
// a1
/* a2
 */ import a /* a3 */ from "a"; /* a4 */ 
// b1
import b from "b"; // b2
/* c1 */ import c from "c"; // c2
/* not-a
*/ // comment after import chunk

Now compare these two examples:

// @flow
import b from "b";
// a
import a from "a";
// eslint-disable-next-line import/no-extraneous-dependencies
import b from "b";
// a
import a from "a";

The // @flow comment is supposed to be at the top of the file (it enables Flow type checking for the file), and isn’t related to the "b" import. On the other hand, the // eslint-disable-next-line comment is related to the "b" import. Even a documentation comment could be either for the whole file, or the first import. So this plugin can’t know if it should move comments above the first import or not (but it knows that the //a comment belongs to the "a" import).

For this reason, comments above and below chunks of imports/exports are never moved. You need to do so yourself, if needed.

Comments around imported/exported items follow similar rules – they can be placed above an item, or at the start or end of its line. Comments before the first item or newline stay at the start, and comments after the last item stay at the end.

import { // comment at start
  /* c1 */ c /* c2 */, // c3
  // b1

  b as /* b2 */ renamed
  , /* b3 */ /* a1
  */ a /* not-a
  */ // comment at end
} from "wherever";
import {
  e,
  d, /* d */ /* not-d
  */ // comment at end after trailing comma
} from "wherever2";
import {/* comment at start */ g, /* g */ f /* f */} from "wherever3";

⬇️

import { // comment at start
/* a1
  */ a, 
  // b1
  b as /* b2 */ renamed
  , /* b3 */ 
  /* c1 */ c /* c2 */// c3
/* not-a
  */ // comment at end
} from "wherever";
import {
  d, /* d */   e,
/* not-d
  */ // comment at end after trailing comma
} from "wherever2";
import {/* comment at start */ f, /* f */g/* g */ } from "wherever3";

If you wonder what’s up with the strange whitespace – see “The sorting autofix causes some odd whitespace!”

Speaking of whitespace – what about blank lines? Just like comments, it’s difficult to know where blank lines should go after sorting. This plugin went with a simple approach – all blank lines in chunks of imports/exports are removed, except in /**/ comments and the blank lines added between the groups mentioned in Sort order. (Note: For exports, blank lines between groups are completely up to you – if you have blank lines around the grouping comments they are preserved.)

(Since blank lines are removed, you might get slight incompatibilities with the lines-around-comment and padding-line-between-statements rules – I don’t use those myself, but I think there should be workarounds.)

The final whitespace rule is that this plugin puts one import/export per line. I’ve never seen real projects that intentionally puts several imports/exports on the same line.

FAQ

Does it support require?

No. This is intentional to keep things simple. Use some other sorting rule, such as import/order, for sorting require. Or consider migrating your code using require to import. import is well supported these days.

Why sort on from?

Some other import sorting rules sort based on the first name after import, rather than the string after from. This plugin intentionally sorts on the from string to be git diff friendly.

Have a look at this example:

import { productType } from "./constants";
import { truncate } from "./utils";

Now let’s say you need the arraySplit util as well:

import { productType } from "./constants";
import { arraySplit, truncate } from "./utils";

If the imports were sorted based on the first name after import (“productType” and “arraySplit” in this case), the two imports would now swap order:

import { arraySplit, truncate } from "./utils";
import { productType } from "./constants";

On the other hand, if sorting based on the from string (like this plugin does), the imports stay in the same order. This prevents the imports from jumping around as you add and remove things, keeping your git history clean and reducing the risk of merge conflicts.

Is sorting imports/exports safe?

Mostly.

Imports and re-exports can have side effects in JavaScript, so changing the order of them can change the order that those side effects execute in. It is best practice to either import a module for its side effects or for the things it exports (and never rely on side effects from re-exports).

// An `import` that runs side effects:
import "some-polyfill";

// An `import` that gets `someUtil`:
import { someUtil } from "some-library";

Imports that are only used for side effects stay in the input order. These won’t be sorted:

import "b";
import "a";

Imports that both export stuff and run side effects are rare. If you run into such a situation – try to fix it, since it will confuse everyone working with the code. If that’s not possible, it’s possible to ignore (parts of) sorting.

Another small caveat is that you sometimes need to move comments manually – see Comment and whitespace handling.

For completeness, sorting the imported/exported items of an import is always safe:

import { c, b, a } from "wherever";
// Equivalent to:
import { a, b, c } from "wherever";

Note: import {} from "wherever" is not treated as a side effect import.

Finally, there’s one more thing to know about exports. Consider this case:

one.js:

export const title = "One";
export const one = 1;

two.js:

export const title = "Two";
export const two = 2;

reexport.js:

export * from "./one.js";
export * from "./two.js";

main.js:

import * as reexport from "./rexport.js";
console.log(reexport);

What happens if you run main.js? In Node.js and browsers the result is:

{
  one: 1,
  two: 2,
}

Note how title is not even present in the object! This is good for sorting, because it means that it’s safe to reorder the two export * from exports in reexport.js – it’s not like the last import “wins” and you’d accidentally change the value of title by sorting.

However, this might still cause issues depending on which bundler you use. Here’s how a few bundlers handled the duplicate name title the time of this writing:

  • ✅ Webpack: Compile time error – safe.
  • ✅ Parcel: Run time error – safe.
  • ⚠️ Rollup: Compile time warning, but uses the first one of them so it’s potentially unsafe. It’s possible to configure Rollup to treat warnings as errors, though.
  • ✅ TypeScript: Compile time error – safe.

The sorting autofix causes some odd whitespace!

You might end up with slightly weird spacing, for example a missing space after a comma:

import {bar, baz,foo} from "example";

Sorting is the easy part of this plugin. Handling whitespace and comments is the hard part. The autofix might end up with a little odd spacing around an import/export sometimes. Rather than fixing those spaces by hand, I recommend using Prettier or enabling other autofixable ESLint whitespace rules. See examples for more information.

The reason the whitespace can end up weird is because this plugin re-uses and moves around already existing whitespace rather than removing and adding new whitespace. This is to stay compatible with other ESLint rules that deal with whitespace.

Can I use this without autofix?

Not really. The error message for this rule is literally “Run autofix to sort these imports!” Why? To actively encourage you to use eslint --fix (autofix), and not waste time on manually doing something that the computer does a lot better. I’ve seen people painstakingly fixing cryptic (and annoying!) sorting errors from other rules one by one, not realizing they could have been autofixed. Finally, not trying to make more detailed messages makes the code of this plugin much easier to work with.

How do I use eslint-ignore for this rule?

Looking for /* eslint-disable */ for this rule? Read all about ignoring (parts of) sorting.

How is this rule different from import/order?

The import/order rule used to not support alphabetical sorting but now it does. So what does eslint-plugin-simple-import-sort bring to the table?

Some other differences:

  • This plugin gives you a single error for each chunk of imports/exports, while import/order can give multiple (see Can I use this without autofix? for details). In other words, this plugin is noisier in terms of underlined lines in your editor, while import/order is noisier in terms of error count.
  • This plugin has a single (though very powerful) option that is a bunch of regexes, while import/order has bunch of different options. It’s unclear which is easier to configure. But eslint-plugin-simple-import-sort tries to do the maximum out of the box.

How do I use this with dprint?

dprint also sorts imports and exports – but does not group them. Instead, it preserves your own grouping.

The first question to ask yourself is if dprint is good enough. If so, you’ve got one tool less to worry about!

If you’d like to enforce grouping, though, you could still use eslint-plugin-simple-import-sort. However, the two might disagree slightly on some sorting edge cases. So it’s better to turn off sorting in your dprint config file:

{
  "typescript": {
    "module.sortImportDeclarations": "maintain"
  }
}

Source: https://dprint.dev/plugins/typescript/config/

How do I remove all blank lines between imports?

Use custom grouping, setting the groups option to only have a single inner array.

For example, here’s the default value but changed to a single inner array:

[["^\\u0000", "^node:", "^@?\\w", "^", "^\\."]];

(By default, each string is in its own array (that’s 5 inner arrays) – causing a blank line between each.)

License

MIT

eslint-plugin-simple-import-sort's People

Contributors

dependabot[bot] avatar gableroux avatar logicer16 avatar lydell avatar millersvt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

eslint-plugin-simple-import-sort's Issues

TypeScript: Broken autofix for functions with `async` name

I have noticed a strange behaviour that occurs with Angular testing library.
Before autofix:

import { TestBed, async } from '@angular/core/testing';

After autofix:

import { ,asyncTestBed } from '@angular/core/testing';

Package versions:
eslint-plugin-simple-import-sort -> 4.0.0
@typescript-eslint/eslint-plugin -> 1.10.2
@typescript-eslint/parser -> 1.10.2

async is not a reserved keyword - see https://www.ecma-international.org/ecma-262/10.0/index.html#sec-keywords

Support tsconfig.json paths and baseUrl automatically

It would be cool if the plugin could automatically detect tsconfig.json to see which first party imports you have, such as web/components/foo. Then those could be moved into the “absolute imports” group, instead of ending up in the (third party) “packages” group.

One idea is to use https://github.com/dividab/tsconfig-paths. Need to check that it actually supports baseUrl, though.

Another idea is to try to require("typescript"). If it’s there, use it to resolve the config.

The initial idea comes from: #18 (comment)

Edit: This is a light-weight package that can do the hard work for us: https://github.com/privatenumber/get-tsconfig

Merge regular and type imports

It’s possible to import types and values in a single file. If so, these can be safely merged.

Input:

import type { ReactNode } from 'react';
import React from 'react';

export default function Foo(): ReactNode {
  return <div>Hello</div>
}

Expected output:

import React, { ReactNode } from 'react';

export default function Foo(): ReactNode {
  return <div>Hello</div>
}

The only case where this is questionable, is if the type is re-exported.

import type { ReactNode } from 'react';
import React from 'react';

export { ReactNode };

When the imports are merged, this becomes the following, where some tools can’t determine if ReactNode is a type or value.

import React, { ReactNode } from 'react';

export { ReactNode };

I think this is ok though. When properly written, a type export is used for this instead.

import React, { ReactNode } from 'react';

export type { ReactNode };

TypeScript doesn’t verify this (yet), but I think this makes it ok for this ESLint plugin to fully ignore that situation.

Option to ignore filename or pattern

@lydell hi, this is a great plugin!
...but I missing an option to ignore some files.
I always put typings (TypeScript) in a separate block:

import React from 'react'
import { Button } from './Button'

// typings
import { MyType } from '../types'

But with this plugin (and others) there's no way to preserve the order. Even with /* eslint-disable-next-line */ in some cases.

Any plans for such option?

Case-insensitive sort of named imports

👋 @lydell!

After switching from TSLint to ESLint and your plugin, I've noticed that named imports are sorted differently. Your approach is case-sensitive, while TSLint's ordered-imports is not by default.

// tslint
import { a, B, c } from "somethiing";

// eslint-plugin-simple-import-sort
import { B, a, c } from "somethiing";

The former notation feels more natural to me. WDYT?

Group for first party packages

We have a module alias called web for our local code (like @ in #4) and I'd like it to be sorted into it's own group like this:

import React from "react"

import { Foo } from "web/components/foo"

import { Bar } from "./bar"

import/order supports this by doing a bunch of magic with Webpack parsing, but just having a list of first party packages as a config variable would be a lot easier.
Thanks

Add support for adding comments in top of defined groups

It'd be great if we could set up a flag to enable/disable adding a comment above each defined group (if a custom definition is provided):

  // ...
  'groups': [
    {
      match: '^\\u0000',
      comment: 'side effects',
    },
    {
      match: '^@?\\w',
      comment: 'package imports,
    },
    // ...
  ],
  // ...

I can take care of this feature if you see it fit for your package. Thoughts?

Spacing issue when fixing unsorted imports

First of all -- great plugin. I'm a huge fan of sorting my imports and I've managed to convince my team to include this plugin in our application.

That being said, I'm running into a weird issue where the spacing isn't right after sorting.

Before fix:

Screen Shot 2020-05-26 at 1 32 47 PM

After fix:

Screen Shot 2020-05-26 at 1 33 03 PM

See how there is no space between alias and oneWay or between computed and get?

Is this an issue perhaps with another eslint rule?

Thanks!

Fix position of a side-effect import

I'd like to be able to fix position of a side-effect import. Here's the use-case:

// main.ts, entrypoint of a Vue app

import Vue from 'vue'
import VueBlahBlah from 'vue-blah-blah'
import VueBootstrap from 'vue-bootstrap' // imaginary library with CSS

// Import local assets, including local CSS files.
// This should really go **after** global imports, because those
// may have imported some initial CSS, and local assets should
// follow to be able to override the rules.
import './assets'

import '@/store'
import '@/other/local/module'

What if eslint-plugin-simple-import-sort supported some kind of magic comment, similar to // eslint-disable-next-line? Like: // simple-import-sort: keep-group

Support comments above import group

It would be nice to have an option to add comments above custom groups.

import code

// node modules
import React, { useCallback, useState } from 'react';
import { View } from 'react-native';
// components
import { CustomButton } from 'src/components';
// screens
import CurrentTimezoneClock from 'src/screens/Clock/CurrentTimezoneClock';
// store
import { StoreState } from 'src/store/rootReducer';
// services
import { NavigationService } from 'src/services';
// utils
import { DateUtils, HooksUtils } from 'src/utils';
import { clockFormat, dateFormat } from 'src/utils/DateUtils';
// types
import { eIcons } from 'src/types/enums';
import { iSavedTimezoneEntry } from 'src/types/interfaces';
// styles
import styles from 'src/screens/Clock/styles';
import { appStyles, dimensions } from 'src/styles';

eslint config

{
  ...

   rules: {
     "simple-import-sort/sort":  [
        "error",
        {
          groups: [
                        { comment:"node modules", ['^react', '^@?\\w'] },
                        { comment:"components", ['^src/components'] },
                        { comment:"screens", ['^src/screens'] },
                        { comment:"strore", ['^src/store'] },
                        { comment:"services", ['^src/services'] },
                        { comment:"utils", ['^src/utils'] },
                        { comment:"types", ['^src/types'] },
        ],
        },
      ],
    },

  ...
}

import './foo' should be after import './foo/bar'

TLDR, order should be:

import './foo/bar/baz';
import './foo/bar';
import './foo';
  • Example 1:
import React from 'react';

import { App, QueryParams } from './App';
import { flushPromises } from './utils/flushPromises';
import { mockRouteComponentProps } from './utils/mockRouteComponentProps';

should be:

import React from 'react';

import { flushPromises } from './utils/flushPromises';
import { mockRouteComponentProps } from './utils/mockRouteComponentProps';
import { App, QueryParams } from './App';
  • Example 2:
import { config } from '../config';
import { UUID } from '../utils/UUID';

should be:

import { UUID } from '../utils/UUID';
import { config } from '../config';
  • Also noticed that
import 'core-js';
import 'regenerator-runtime/runtime';
import 'whatwg-fetch';

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';

import { Router } from './Router';
import { Layout } from './layout/Layout';
import './index.scss';

becomes:

import 'core-js';
import 'regenerator-runtime/runtime';
import 'whatwg-fetch';
import './index.scss';

import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter } from 'react-router-dom';

import { Router } from './Router';
import { Layout } from './layout/Layout';

=> './index.scss' should be last

How to remove newline between import groups?

Thanks for nice plugin!

I tried to use this and had one question.
How to remove newline between import groups?
(Or is there no option to remove line breaks?)

import fetch from 'cross-fetch'
import { NextPage } from 'next'
import Link from 'next/link'
import React from 'react'

// I want to delete ↑ line...
import { Head } from '~/components/abstracts/head'

The config file used is shown below.

My ESLint config

{
  "root": true,
  "env": {
    "es6": true,
    "node": true,
    "browser": true
  },
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": { "jsx": true },
    "sourceType": "module"
  },
  "plugins": [
    "react",
    "import",
    "unicorn",
    "security",
    "prettier",
    "react-hooks",
    "simple-import-sort",
    "@typescript-eslint"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:import/errors",
    "plugin:import/warnings",
    "plugin:import/typescript",
    "plugin:react/recommended",
    "plugin:unicorn/recommended",
    "plugin:security/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:prettier/recommended",
    "prettier/@typescript-eslint",
    "prettier/unicorn",
    "prettier/react"
  ],
  "rules": {
    "prefer-const": "error",
    "react/prop-types": "off",
    "simple-import-sort/sort": "error",
    "react-hooks/rules-of-hooks": "error",
    "react-hooks/exhaustive-deps": "warn",
    "import/newline-after-import": "error",
    "unicorn/prevent-abbreviations": "off",
    "unicorn/consistent-function-scoping": "off",
    "@typescript-eslint/ban-ts-ignore": "off",
    "@typescript-eslint/explicit-function-return-type": "off",
    "@typescript-eslint/explicit-member-accessibility": "off",
    "@typescript-eslint/consistent-type-definitions": ["error", "type"]
  },
  "settings": {
    "react": {
      "version": "detect"
    },
    "import/resolver": {
      "babel-module": {}
    },
    "import/parsers": {
      "@typescript-eslint/parser": [".ts", ".tsx"]
    }
  }
}

Support Typescript

Currently the plugin crashes with typescript-eslint-parser:

TypeError: Expected `index` to be a number.
    at SourceCode.getLocFromIndex (/Users/semenov/tmp/ts-rule/node_modules/eslint/lib/util/source-code.js:436:19)
    at maybeReportSorting (/Users/semenov/tmp/ts-rule/node_modules/eslint-plugin-simple-import-sort/src/sort.js:62:27)
    at Program (/Users/semenov/tmp/ts-rule/node_modules/eslint-plugin-simple-import-sort/src/sort.js:20:11)
    at listeners.(anonymous function).forEach.listener (/Users/semenov/tmp/ts-rule/node_modules/eslint/lib/util/safe-emitter.js:45:58)
    at Array.forEach (<anonymous>)
    at Object.emit (/Users/semenov/tmp/ts-rule/node_modules/eslint/lib/util/safe-emitter.js:45:38)
    at NodeEventGenerator.applySelector (/Users/semenov/tmp/ts-rule/node_modules/eslint/lib/util/node-event-generator.js:251:26)
    at NodeEventGenerator.applySelectors (/Users/semenov/tmp/ts-rule/node_modules/eslint/lib/util/node-event-generator.js:280:22)
    at NodeEventGenerator.enterNode (/Users/semenov/tmp/ts-rule/node_modules/eslint/lib/util/node-event-generator.js:294:14)
    at CodePathAnalyzer.enterNode (/Users/semenov/tmp/ts-rule/node_modules/eslint/lib/code-path-analysis/code-path-analyzer.js:632:23)

I created the reproduction repo: https://github.com/IlyaSemenov/eslint-plugin-simple-import-sort-typescript-repro

Please implement better error messages.

/home/asday/code/src/app/containers/Navigation.js
  1:1  error  Run autofix to sort these imports!  simple-import-sort/sort

Is this complaining about the gap between the parent imports and the sibling imports? The fact I have react-navigation after react-navigation-redux-helpers? Who knows!

It's lovely that you can autofix it, but I don't want you to. I want to be told what I wrote that was wrong, so I can learn to write the right thing, first time, in future. That way, when I come to other code on the project that's compliant, I already know what I'm expecting to see, because that's how I've taught myself to write.

Sorting "../../.." is broken

The readme says:

Since “.” sorts before “/”, relative imports of files higher up in the directory structure come before closer ones – "../../utils" comes before "../utils". Perhaps surprisingly though, ".." would come before "../../utils" (since shorter substrings sort before longer strings). For that reason there’s one addition to the alphabetical rule: "." and ".." are treated as "./" and "../".

That is pretty broken, though:

import {} from "../";
import {} from "../../";
import {} from "../../a";
import {} from "../a";
import {} from "./";
import {} from "./a";

Expected:

import {} from "../../";
import {} from "../../a";
import {} from "../";
import {} from "../a";
import {} from "./";
import {} from "./a";

I have some ideas around this that I’d like to play with this fall.

Wrong grouping of imports?

Hi I have these imports:

import moment, { Moment } from 'moment'
import React, { Component } from 'react'
import { Text, View } from 'react-native'

import * as GQL from '@gql-schema'
import { Texts } from '@styles/common/Texts'
import { ToggleItem } from '@ui/Section'
import { amountWithCurrency } from '@util/amountFormatter'

import { GraphColumns } from './GraphColumns'
import { styles } from './styles'

Sort plugin reports them as wrong and it will correct them to the:

import { Texts } from '@styles/common/Texts'
import moment, { Moment } from 'moment'
import React, { Component } from 'react'
import { Text, View } from 'react-native'

import * as GQL from '@gql-schema'
import { ToggleItem } from '@ui/Section'
import { amountWithCurrency } from '@util/amountFormatter'

import { GraphColumns } from './GraphColumns'
import { styles } from './styles'

i would expect all imports starting with @ to be in same group. Could you provide explanation how this was sorted?
Thank you

Update installation instructions for ESLint 6.0

https://eslint.org/docs/6.0.0/user-guide/migrating-to-6.0.0#-plugin-authors-may-need-to-update-installation-instructions

If you maintain a plugin and provide installation instructions, you should ensure that the installation instructions are up to date with the user-facing changes to how plugins are loaded. In particular, if your plugin was generated with the generator-eslint package, it likely contains outdated instructions for how to use the plugin with global ESLint installations.

Handle custom groups

Nowadays, absolute imports is a very popular thing, as well as monorepos with different features "stored" as a separate packages. However they are not packages.

Webpack aliases and yarn workspaces are breaking original idea behind the "groups" feature.

import React from 'react';              // 1. "external" package
import Button from 'components/Button'; // 2. "internal" package (or just an absolute URL)
import style from './style';            // 3. "relative" module
import "./messages";                    // 4. side effect

Technically these are:

  1. packages in node_modules
  2. packages not in node_modules
  3. relative path
  4. no import
  • 2 could be distinguished from 1 by calling require.resolve and checking path to include node_modules (obvious)
  • 2 could be distinguished from 1 by having some configuration rules, but I reckon it's not feature proof and quite fragile.

I could work on PR if you'll accept the idea

Set sort order of imports without a specifier (side-effects)?

Description

Consider following import declarations:

import { PROPERTY } from './config'; // later refered as "import A"
import './style'; // later refered as "import B"

According to AST, the the import A has specifier, the import B has none. I would like to sort imports without specifier last.

Digging into the code, following function was discovered (so it looks like, my case is considered side-effect):

function isSideEffectImport(importNode, sourceCode) {

The behaviour described is proven by this comment:

: // If one of the items is a side effect import, move it first.

Verdict: the side-effect comes first. I would like it come last.

I am also suspecting the regex I pass is wrong, if that's the case, please let me know. The configs can be seen in examples bellow.

Motivation

The feature is specifically important for stylesheet imports, if imported as CSS - the order matters. So, I would like my imports in module to come last, this means if I extend a component which also imports style, mine module style will have a priority when resolving.

What I tried

Plugin options provided:

{
    "groups": [
        [
            "^\\u0000"
        ], // side effect imports
        [
            "^@?[a-z]"
        ], // anything that starts with @ and lowercase
        [
            "^[^.]"
        ], // anything but a dot
        [
            "^\\."
        ] // starting with dot
    ]
}

Gives me following output:

import './UrlResolver.style';

import PropTypes from 'prop-types';
import { PureComponent } from 'react';

import { CATEGORY, PRODUCT, UNKNOWN } from './UrlResolver.config';

The config as follows:

{
    "groups": [
        [
            "^@?[a-z]"
        ], // anything that starts with @ and lowercase
        [
            "^[^.]"
        ], // anything but a dot
        [
            "^\\."
        ], // starting with dot
        [
            "^\\u0000"
        ], // side effect imports
    ]
}

Gives me:

import PropTypes from 'prop-types';
import { PureComponent } from 'react';

import './UrlResolver.style';

import { CATEGORY, PRODUCT, UNKNOWN } from './UrlResolver.config';

Expected result:

An option to configuration is added, which allows to sort side-effects / importds without specifier last.

import PropTypes from 'prop-types';
import { PureComponent } from 'react';

import { CATEGORY, PRODUCT, UNKNOWN } from './UrlResolver.config';

import './UrlResolver.style';

Support indentation in script tags

I have <script> block in my vue component. For example:

<script lang="ts">
    import { Component, Vue, Watch } from 'vue-property-decorator';
    import { Location } from 'vue-router';

    ...
</script>

Indent is set to 4 spaces inside script block.
But when I run linter, I got this error:
image
As you can see, imports are sorted. And if I remove indentation, the error is gone.

eslint-disable is ignored

I'm not sure if I'm doing it wrong, but sorting happens even inside a eslint-disable / eslint-enable block.
e.g.

import React from 'react';
import { ToastContainer } from 'react-toastify';
import { useAccount, useUser } from 'src/state';

import mapboxgl from 'mapbox-gl';

/* eslint-disable */
import '@feathr/components/style/theme/index.css';
import '@feathr/components/style/global/index.css';
import './ReactApp.css';

// Load after theme/index.css.
import { ErrorBoundary } from '@feathr/components';
/* eslint-enable */

import Routes from './Routes';

I would expect anything outside the disable/enable block to get sorted, but inside to be left alone.

Is there a way to sort default imports aboved named imports?

in a group, I have:

import Component from '@glimmer/component';
import { action } from '@ember/object';
import { inject as service } from '@ember/service';

all of those are in my custom "framework" group.

but, when apply the auto-fix, @glimmer/component moves to the bottom, because g comes after e.

Is there a way to keep it at the top, because it's a default import?

For example, previously, I had:

  'sort-imports-es6-autofix/sort-imports-es6': [2, {
    'ignoreCase': false,
    'ignoreMemberSort': false,
    'memberSyntaxSortOrder': ['single', 'all', 'multiple', 'none'],
  }],

which looks like:

import single from 'a';
import * from 'b';
import { foo, bar } from 'c';
import from 'd';

i'd like to maintain that to reduce impact to the (very large) codebase (and people's workflows)

Improve default group regexps to make them easier to copy-paste and re-order, and improve grouping docs

Hi, I have some problems sorting by groups.

First problem

Eslint Config

{
  ...

   rules: {
     "simple-import-sort/sort":  [
        "error",
        {
          groups: [["^\\u0000"], ["^[^.]"], ["^@?\\w"], ["^\\."]],
        },
      ],
    },

  ...
}

import code

    import react from "react";
    import test from "@/components/test";
    import "./style.less";
    import {sort} from "../src"

Expected behavior

    import "./style.less";

    import test from "@/components/test";

    import react from "react";

    import {sort} from "../src"

Actual behavior

    import "./style.less";

    import test from "@/components/test";
    import react from "react";

    import {sort} from "../src"

So I think the defaultGroups need to be changed, The user should be able to change the import order directly by changing the defaultGroups, but this is not possible now, as this will mislead the user。for example, change it like below:

const defaultGroups = [
   // Side effect imports.
   ["^\\u0000"],
   // Packages.
   // Things that start with a letter (or digit or underscore), or `@` followed by a letter.
   ["^@?\\w"],
   // Absolute imports and other imports such as Vue-style `@/foo`.
   // Anything that does not start with a dot.
   ["(^@/[^.])|(^/[^.])"],
   // Relative imports.
   // Anything that starts with a dot.
   ["^\\."],
];

Second problem

if ["^\u0000"] is at the end of the groups

Eslint Config

{
  ...

   rules: {
     "simple-import-sort/sort":  [
        "error",
        {
          groups: [  ["^@?\\w"], ["^\\."],["^[^.]"],["^\\u0000"]],
        },
      ],
    },

  ...
}

** import code **

    import react from "react";
    import test from "@/components/test";
    import "./style.less";
    import {sort} from "../src"

Expected behavior

    import react from "react";

    import {sort} from "../src";

    import test from "@/components/test";

    import "./style.less";

Actual behavior

    import react from "react";

    import {sort} from "../src";

    import "./style.less";
    import test from "@/components/test";

The reason for this problem is that the 【"^[^.]"】 rules and 【["^\u0000"]】 rules coincide

Solution One: change group

       groups: [  ["^@?\\w"], ["^\\."],["^[^.]"],["^\\u0000"]]   =>  groups: [  ["^@?\\w"], ["^\\."],["(^@/[^.])|(^/[^.])"],["^\\u0000"]]

Solution Two: change flatMap function; such as:

         flatMap(itemGroups, (groups) =>
                groups.map((group) => [group, group.regex.exec(source)])
          )
----------------------------------------------------------------------------------
         flatMap(itemGroups, (groups) =>
               groups.map((group) =>  group.regex.source.includes("^\\u0000")
                  ? [group, group.regex.exec(source)]
                  : RegExp("^\\u0000", "u").exec(source)
                  ? [group, null]
                  : [group, group.regex.exec(source)];)
        )

I think it should be possible to change the import position by changing the parameter position in the default groups, but this is not possible now 🤡

Should change the default groups, and Readme documents 🤠🤠🤠

`require` support

I have to say, I love how this project works! It nails the developer experience, and just works without config, all the way down to the error messages.

Unfortunately I'm coming from a mixed project, https://github.com/badges/shields (the front end uses ESM and the back end uses require) so I'm using import/order.

It's really clear from the readme that require isn't supported, though wanted to say I would definitely use it if it were added!

Thanks so much for a great project!

Incorrect sort of exports with as

Hey 👋,

The new exports sort does not handle sorting exports that use the as keyword.

export { something, something as default } from './something'

will be sorted as:

export { something as, defaultsomething } from './something'

which obviously is incorrect.

V6.0 broken

Updating to 6.0 leads to errors:

Effect-TS/effect#392

Namely:

Definition for rule 'simple-import-sort/imports' was not found  simple-import-sort/imports

Are there any ways to ignore sorting for non-import lines ?

Is there a way to do something like this :

// eslint-disable-next-line simple-import-sort/sort
process.env.NODE_ENV = 'development';

import './some-import';
import './another import';

where I can set some environment variables before the imports ?

But what happens is process.env.NODE_ENV gets transferred to the bottom of the imports.

import './some-import';
import './another import';

process.env.NODE_ENV = 'development';

Running this rule has suddenly cause broken code to generate

import { format, parseISO } from 'date-fns';
import React from 'react';
import { createFragmentContainer, graphql } from 'react-relay';
import { FaqAuthor_author } from '~/__generated__/FaqAuthor_author.graphql';
import { FaqAuthor_faq } from '~/__generated__/FaqAuthor_faq.graphql';
import { AuthorInfo } from '~/components/AuthorInfo/AuthorInfo';

Is our import block when running 'simple-import-sort/sort': 'off',, and source code.

However, as soon as we go 'simple-import-sort/sort': 'error',

This produces:

import { format, parseISO } from 'date-fns';
import React from 'react';
import { createFragmentContainer, graphql } from 'react-relay';






import { FaqAuthor_author } from '~/__generated__/FaqAuthor_author.graph
q
l
'
;

import { FaqAuthor_faq } from '~/__generated__/FaqAuthor_faq.g
ra
ph
ql
';

import { AuthorInfo } from '~/components/AuthorInfo/AuthorInfo';

My eslintrc file:

module.exports = {
	extends: ['plugin:@autoguru/react'],
	env: {
		'shared-node-browser': true,
		browser: true,
	},
	parserOptions: {
		tsconfigRootDir: __dirname,
	},
	settings: {
		'import/resolver': {
			typescript: {
				directory: __dirname,
			},
		},
	},
};

and rule config @ https://github.com/autoguru-au/octane/blob/master/packages/eslint-plugin/configs/base/import.js#L7

Imports of the same package is not combined

Imports of the same package are to be combined to the one import.


Steps to reproduce:

Try to fix the following

import React from 'react'
import { Component } from 'react'

Actual result:

import React from 'react'
import { Component } from 'react'

Expected result:

import React, { Component } from 'react'

Steps to reproduce:

Try to fix the following

import './styles.scss'
import './styles.scss'

Actual result:

import './styles.scss'
import './styles.scss'

Expected result:

import './styles.scss'

Side-effect import not sorted properly with @typescript-eslint 2.23.0

This is with "eslint-plugin-simple-import-sort": "5.0.1".

Before (i.e. 2.22.0):

import "hard-rejection/register";

import chalk from "chalk";
import dotenv from "dotenv";
import ora from "ora";
import pluralize from "pluralize";

After:

import chalk from "chalk";
import dotenv from "dotenv";
import "hard-rejection/register";
import ora from "ora";
import pluralize from "pluralize";

Here's the changelog. Seems most likely to be caused by (completely uneducated guess) typescript-eslint/typescript-eslint#1697?

Error: "Definition for rule 'simple-import-sort/sort' was not found"

Hi, first time trying to use your lib. Facing that error, look at my eslintrc.js, what I does wrong?
eslintrc.js:

module.exports = {
  root: true,
  ignorePatterns: ["node_modules/**/*", "dist/**/*", "storybook-static/*"],
  overrides: [
    {
      files: ["*.ts"],
      parser: "@typescript-eslint/parser",
      parserOptions: {
        project: [
          "tsconfig.json"
        ],
        createDefaultProgram: true
      },
      extends: [
        'airbnb-typescript/base',
        'prettier/@typescript-eslint',
        'plugin:prettier/recommended'
      ],
      plugins: [
        "@typescript-eslint",
        "@angular-eslint",
        "simple-import-sort"
      ],
      rules: {
        "@angular-eslint/directive-selector": [
          "error",
          { "type": "attribute", "prefix": "app", "style": "camelCase" }
        ],
        "@angular-eslint/component-selector": [
          "error",
          { "type": "element", "prefix": "app", "style": "kebab-case" }
        ],
        "simple-import-sort/sort": [
          'error',
          {
            groups: [
              // Side effect imports.
              ['^\\u0000'],
              // Packages.
              ['^@?(?!mediu@nrwl/eslint-plugin-nxm\-stories)\\w'],
              ['^@medium\-stories?\\w'],
              ['^[^.]'],
              // Relative imports.
              // Anything that starts with a dot.
              ['^\\.'],
            ],
          },
        ],
        "sort-imports": "off",
        "import/first": "error",
        "import/newline-after-import": "error",
        "import/no-duplicates": "error"
      }
    },
    {
      files: ["*.html"],
      parser: "@angular-eslint/template-parser",

        extends: ["plugin:@angular-eslint/template/recommended"],
        rules: {
          "max-len": ["error", { "code": 140 }]
        }
      }
  ]
}

Handle re-exports

Some modules re-export members directly. This is also sort of an import.

I.e.

export { default as Foo, Fooz, Foob } from './Foo';
export { default, NonDefault } from './qwe';
export * from './asd';
export * as bar from './bar';

It would be nice if this would be sorted automatically as well following the same rules as imports.

I think this is mostly not combined with regular imports, but it could be. This means there should be rules for this.

Candidate rules I could come up with:

  1. re-exports before imports
  2. re-exports after imports
  3. re-exports mixed with imports

Personally I’d go with 2.

Some side-effect imports are not autofixable

Hi there - first off, thank you for creating this project!

We are having autofix issues when running eslint --fix on this particular set of side-effect imports:

import "codemirror/addon/fold/brace-fold"
import "codemirror/addon/edit/closebrackets"
import "codemirror/addon/fold/foldgutter"
import "codemirror/addon/fold/foldgutter.css"
import "codemirror/addon/lint/json-lint"
import "codemirror/addon/lint/lint"
import "codemirror/addon/lint/lint.css"
import "codemirror/addon/scroll/simplescrollbars"
import "codemirror/addon/scroll/simplescrollbars.css"
import "codemirror/lib/codemirror.css"
import "codemirror/mode/javascript/javascript"

Expected behavior:

  • no errors are emitted
  • side-effect imports are not reordered

Actual behavior:

  • error (Run autofix to sort...)
  • side-effect imports are reordered like below
import "codemirror/addon/lint/lint"
import "codemirror/addon/fold/brace-fold"
import "codemirror/addon/fold/foldgutter"
import "codemirror/addon/fold/foldgutter.css"
import "codemirror/addon/lint/json-lint"
import "codemirror/addon/edit/closebrackets"
import "codemirror/addon/lint/lint.css"
import "codemirror/addon/scroll/simplescrollbars"
import "codemirror/addon/scroll/simplescrollbars.css"
import "codemirror/lib/codemirror.css"
import "codemirror/mode/javascript/javascript"

If I find an easier repro, I'll include it. Happy to also help dig into this further when I have a chance. Cheers.

bug: import { ,ofSubject } from 'rxjs';

Thanks for this awesome plugin.

Ran into this bug...
Using version 5.0.0

Input:

import { Subject, of } from 'rxjs';

Output:

import { ,ofSubject } from 'rxjs';

Plugin insists on removing empty line between imports and a semicolon (;)

The plugin insists on removing the delimiting empty line between the imports and a semicolon. This affects, for example, inline function calls (which are prepended with a semicolon by prettier).

Example:

import { foo } from "bar"

;(async function() {
  await foo()
})()

See screenshots:

Screenshot 2019-05-09 at 13 13 03

Screenshot 2019-05-09 at 13 13 13

The "fixed" version:

Screenshot 2019-05-09 at 13 13 17

Expected behaviour

Allow empty line between imports and a block starting with a semicolon (as on screenshot 1).

If you need a reproduction repo I can create one. But I think the problem will repeat if you just copy/paste my example to any environment.

Treat @/path imports as absolute

Problem

In a project created with vue-cli, local components are sorted above global packages:

import Error from "@/components/error.vue"
import { Component, Vue } from "vue-property-decorator"

which is counter-intuitive, and may possibly suffer from missing side-effects coming from global imports.

The @ alias comes from here:
https://github.com/vuejs/vue-cli/blob/486a921e9fc782fe4a9b9dd1bdf82066b1522782/packages/%40vue/cli-service/lib/config/base.js#L49

I understand that the sort plugin treats this as a normal package import, and character code of @ (64) is smaller than of any letter—I agree that the current behaviour is correct as per documentation.

However, using @ is a wide spread use case (at least in Vue world) for referring to local modules, so this problem might have a solution provided by simple-import-sort without needing to update all imports.

Proposal

I think the simplest solution would be to allow to customize prefixes for "absolute imports" group. As I understand, currently an import is considered absolute if and only if it starts with /. What if user could add more prefixes? Something like { absolutePrefixes: ['/', '@/'] }.

Current workaround

For now I've changed @/absolute/import to ~/absolute/import (~ sorts after all alphanumeric characters so these imports come directly after all package imports). Granted, it even makes more sense, as ~ means home in Unix (and also ~ is a suggested default in e.g. babel-plugin-root-import).

However, it's breaking wide spread Vue conventions, so a solution in the sorter allowing to use the default alias @/ would be appreciated.

Also, logically even ~/package is an absolute import and belong to 'absolute imports' group, not a global package with weird name which just coincidentally happens to be sorted alphabetically after all other packages. This will also be useful for putting line breaks between groups.

Duplicate imports are not optimized

Duplicate imports are to be combined to the one import.

Discovered in release 2.0.0

Steps to reproduce:

Try to fix the following

import './styles.scss'
import './styles.scss'

Actual result:

import './styles.scss'
import './styles.scss'

Expected result:

import './styles.scss'

Sorting is broken?

I have this code:

import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';

with this config:

 // conflicts with the below
  'sort-imports-es6-autofix/sort-imports-es6': 'off',

  // combine imports
  'import/no-duplicates': 'error',

  // does not support sorting "require"
  'simple-import-sort/sort': ['error', {
    groups: [
      // Framework Packages
      // ['^@ember', '^@glimmer', 'ember-qunit', 'qunit'],

      // Side effect imports.
      ['^\\u0000'],

      // Parent imports. Put `..` last.
      ['^\\.\\.(?!/?$)', '^\\.\\./?$'],

      // Other relative imports. Put same-folder imports and `.` last.
      ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],

      // Style imports.
      ['^.+\\.s?css$'],
    ],
  }],

and the imports keep flip flopping and the broken state never settles.

import { setupTest } from 'ember-qunit';
import { module, test } from 'qunit';

only the bottom import errors, but autfixing goes to

import { module, test } from 'qunit';
import { setupTest } from 'ember-qunit';

but then both lines error, and autofix to the first

VsCode error

Failed to load plugin 'simple-import-sor' declared in '.eslintrc.js': Cannot find module 'eslint-plugin-simple-import-sor'

"extends": [ "eslint:recommended", "plugin:react/recommended", "plugin:import/errors", "plugin:import/warnings", "plugin:simple-import-sort" ],

I set to only simple-import-sort but no works

Custom groups not working with Prettier (format on save)

Hi!

Prettier formats my code just fine when adding the plugin as-is, but it's ignoring the custom groups rule while formatting.

Simple Import Sort rules:

rules: {
    "simple-import-sort/imports": [
      "error",
      {
        groups: [
          // Node.js builtins. You could also generate this regex if you use a `.js` config.
          // For example: `^(${require("module").builtinModules.join("|")})(/|$)`
          [
            "^(assert|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|https|module|net|os|path|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|tty|url|util|vm|zlib|freelist|v8|process|async_hooks|http2|perf_hooks)(/.*|$)",
          ],
          // Packages. `react` related packages come first.
          ["^react", "^@?\\w"],
          // Internal packages.
          ["^(@|@company|@ui|@src|components|utils|config|vendored-lib|src)(/.*|$)"],
          // Side effect imports.
          ["^\\u0000"],
          // Parent imports. Put `..` last.
          ["^\\.\\.(?!/?$)", "^\\.\\./?$"],
          // Other relative imports. Put same-folder imports and `.` last.
          ["^\\./(?=.*/)(?!/?$)", "^\\.(?!/?$)", "^\\./?$"],
          // Style imports.
          ["^.+\\.s?css$"]
        ]
      }
    ],
    "simple-import-sort/exports": "error",
    "sort-imports": "off",
    "import/order": "off"
  }

Expected:
image

Outcome (after saving the file):
image

Formatting works just fine if I run eslint --fix, but for some reason, Prettier is not taking this into account and formatting as if I had never written the groups option, even though ESLint clearly sees this as an error.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.