Repository: un-ts/eslint-plugin-import-x
Pull request #163 (2024-09-29 13:19:44)

perf(utils): faster ImportDeclaration detect

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: afad23e30a5179fda5529c5f01fbdf77c31dde43

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/SukkaW/eslint-plugin-import-x/new/minor-performance-improvement?filename=.changeset/purple-hounds-try.md&value=---%0A%22eslint-plugin-import-x%22%3A%20patch%0A---%0A%0Aperf(utils)%3A%20faster%20ImportDeclaration%20detect%0A)


codesandbox-ci[bot]: This pull request is automatically built and testable in [CodeSandbox](https://codesandbox.io).

  To see build info of the built libraries, click [here](https://ci.codesandbox.io/status/un-ts/eslint-plugin-import-x/pr/163/builds/546080) or the icon next to each commit SHA.

Patch:
diff --git a/.changeset/mighty-ladybugs-agree.md b/.changeset/mighty-ladybugs-agree.md
new file mode 100644
index 00000000..552ec821
--- /dev/null
+++ b/.changeset/mighty-ladybugs-agree.md
@@ -0,0 +1,5 @@
+---
+'eslint-plugin-import-x': patch
+---
+
+Fix issue where `no-duplicates` rule with `prefer-inline` incorrectly marks default type and named type imports as duplicates
diff --git a/src/rules/namespace.ts b/src/rules/namespace.ts
index 0d880a96..c1e29c6b 100644
--- a/src/rules/namespace.ts
+++ b/src/rules/namespace.ts
@@ -151,7 +151,10 @@ export = createRule<[Options], MessageId>({
 
       // same as above, but does not add names to local map
       ExportNamespaceSpecifier(namespace) {
-        const declaration = importDeclaration(context, namespace)
+        const declaration = importDeclaration(
+          context,
+          namespace as TSESTree.ImportDefaultSpecifier,
+        )
 
         const imports = ExportMap.get(declaration.source.value, context)
         if (imports == null) {
diff --git a/src/rules/no-duplicates.ts b/src/rules/no-duplicates.ts
index b706541a..334b2071 100644
--- a/src/rules/no-duplicates.ts
+++ b/src/rules/no-duplicates.ts
@@ -463,12 +463,19 @@ export = createRule<[Options?], MessageId>({
         moduleMaps.set(parent, map)
       }
 
-      if (!preferInline && n.importKind === 'type') {
-        return n.specifiers.length > 0 &&
+      if (n.importKind === 'type') {
+        if (
+          n.specifiers.length > 0 &&
           n.specifiers[0].type === 'ImportDefaultSpecifier'
-          ? map.defaultTypesImported
-          : map.namedTypesImported
+        ) {
+          return map.defaultTypesImported
+        }
+
+        if (!preferInline) {
+          return map.namedTypesImported
+        }
       }
+
       if (
         !preferInline &&
         n.specifiers.some(
diff --git a/src/utils/import-declaration.ts b/src/utils/import-declaration.ts
index f2fda55c..40cc3eda 100644
--- a/src/utils/import-declaration.ts
+++ b/src/utils/import-declaration.ts
@@ -1,11 +1,15 @@
+import { AST_NODE_TYPES } from '@typescript-eslint/utils'
 import type { TSESTree } from '@typescript-eslint/utils'
 
 import type { RuleContext } from '../types'
 
 export const importDeclaration = (
   context: RuleContext,
-  node: TSESTree.Node,
+  node: TSESTree.ImportDefaultSpecifier,
 ) => {
+  if (node.parent && node.parent.type === AST_NODE_TYPES.ImportDeclaration) {
+    return node.parent
+  }
   const ancestors = context.sourceCode.getAncestors(node)
   return ancestors[ancestors.length - 1] as TSESTree.ImportDeclaration
 }
diff --git a/src/utils/resolve.ts b/src/utils/resolve.ts
index 805bd775..3401e3be 100644
--- a/src/utils/resolve.ts
+++ b/src/utils/resolve.ts
@@ -125,10 +125,6 @@ function fullResolve(
     return { found: true, path: cachedPath }
   }
 
-  function cache(resolvedPath: string | null) {
-    fileExistsCache.set(cacheKey, resolvedPath)
-  }
-
   function withResolver(resolver: Resolver, config: unknown) {
     if (resolver.interfaceVersion === 2) {
       return resolver.resolve(modulePath, sourceFile, config)
@@ -170,7 +166,7 @@ function fullResolve(
     }
 
     // else, counts
-    cache(resolved.path as string | null)
+    fileExistsCache.set(cacheKey, resolved.path as string | null)
     return resolved
   }
 


Test patch:
diff --git a/test/rules/no-duplicates.spec.ts b/test/rules/no-duplicates.spec.ts
index 3be9b76d..1fb645d5 100644
--- a/test/rules/no-duplicates.spec.ts
+++ b/test/rules/no-duplicates.spec.ts
@@ -682,6 +682,21 @@ describe('TypeScript', () => {
             ...parserConfig,
           }),
         ]),
+    test({
+      code: "import type { A } from 'foo';import type B from 'foo';",
+      ...parserConfig,
+      options: [{ 'prefer-inline': true }],
+    }),
+    test({
+      code: "import { type A } from 'foo';import type B from 'foo';",
+      ...parserConfig,
+      options: [{ 'prefer-inline': true }],
+    }),
+    test({
+      code: "import type A from 'foo';import { B } from 'foo';",
+      ...parserConfig,
+      options: [{ 'prefer-inline': true }],
+    }),
   ]
 
   const invalid = [