Skip to content

Conversation

@cakoose
Copy link

@cakoose cakoose commented Jan 12, 2026

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
Copy link
Owner

lydell commented Jan 17, 2026

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
Copy link
Author

cakoose commented Jan 18, 2026

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
Copy link
Owner

lydell commented Jan 18, 2026

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.

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