Visitar URL original
Determinstic ordering between different import styles by cakoose · Pull Request #203 · lydell/eslint-plugin-simple-import-sort · GitHub
Skip to content

Determinstic ordering between different import styles - #203

Merged
lydell merged 3 commits into
lydell:mainfrom
cakoose:kannan/style-determinism
Apr 6, 2026
Merged

lydell merged 3 commits into
lydell:mainfrom
cakoose:kannan/style-determinism

Conversation

@cakoose

@cakoose cakoose commented Jan 12, 2026

Copy link
Copy Markdown
Contributor

Even after deduplicating, you may still have three different styles of imports of the same module.

For "import"

import * as b1 from 'blah';
import b2, { B2 } from 'blah';

For "import type":

import type * as b3 from 'blah';
import type b4 from 'blah';
import type { B5 } from 'blah';

Before, this rule wouldn't apply a deterministic ordering. Sometimes, different developers IDEs would end up swapping those back and forth. It would be nice if this rule had a deterministic order.

Fixes #200

Even after deduplicating, you may still have multiple imports of the
same module, since certain styles of imports can't be combined:

For "import"

    import * as b1 from 'blah';
    import b2, { B2 } from 'blah';

For "import type":

    import type * as b3 from 'blah';
    import type b4 from 'blah';
    import type { B5 } from 'blah';

Before, this rule wouldn't apply a deterministic ordering. Sometimes,
different developers IDEs would end up swapping those back and forth.
It would be nice if this rule had a deterministic order.
@lydell

lydell commented Jan 17, 2026 •

Copy link
Copy Markdown
Owner

Hi! Thanks for the pull request!

I think it makes sense to sort namespace imports before other imports. As shown in #200, there is a use case for that.

But I’m not convinced it’s useful to define rules for default, named and default+named. Even with those rules, we still don’t become fully deterministic, since for example import a from "foo"; import b from "foo" has no defined order. And I think it’s better to de-duplicate those.

So I think it’s better to only make changes for import * as a from "foo" until somebody asks for more. Oh, and exports should be handled the same: export * as a from "foo".

I think we should replace .isSideEffectImport : boolean with .type : "SideEffect" | "Namespace" | "Regular".

// Change `function isSideEffectImport(importNode, sourceCode) {` into:
function getImportType(importNode, sourceCode) {
  return (
    // import "setup"
    // But not: import {} from "setup"
    // And not: import type {} from "setup"
    importNode.specifiers.length === 0 &&
      (!importNode.importKind || importNode.importKind === "value") &&
      !shared.isPunctuator(
        sourceCode.getFirstToken(importNode, { skip: 1 }),
        "{",
      )
      ? "SideEffect"
      : // import * as ns from "package"
        importNode.specifiers.length === 1 &&
          importNode.specifiers[0].type === "ImportNamespaceSpecifier"
        ? "Namespace"
        : "Regular"
  );
}

@cakoose

cakoose commented Jan 18, 2026

Copy link
Copy Markdown
Contributor Author

But I’m not convinced it’s useful to define rules for default, named and default+named. Even with those rules, we still don’t become fully deterministic, since for example import a from "foo"; import b from "foo" has no defined order. And I think it’s better to de-duplicate those.

The reason I return different integers for default vs named is that import type doesn't allow you to mix them, e.g.

// Not allowed by TypeScript: "A type-only import can specify a default import or named bindings, but not both."
import type blah, {a, b} from 'blah';

// Must be split:
import type blah from 'blah';
import type {a, b} from 'blah';

And since I'm making that distinction for import type, I figured I'd leave that in there for import for consistency.

But I'm not opposed to removing that distinction for non-type imports. Though maybe the cleanest way to do that is to have a single piece of code handle the import style distinction and the type vs value distinction?

BTW, I'm not too attached to this PR. If you have fix that you prefer, feel free to go with that and discard this PR. Would just be happy to get something that works.

@lydell

lydell commented Jan 18, 2026

Copy link
Copy Markdown
Owner

The reason I return different integers for default vs named is that import type doesn't allow you to mix them

Oh, I didn’t know that. Thanks for letting me know! Then, ignore my previous comment. I’ll review again with this restriction in mind.

@lydell
lydell merged commit 7794d14 into lydell:main Apr 6, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Order is not enforced between wildcard and non-wildcard imports of the same module

2 participants