From 96df8d602783f8c3712b63db0733eee9d29d34ca Mon Sep 17 00:00:00 2001 From: Viraj <77448246+virajsabhaya23@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:16:02 -0500 Subject: [PATCH 1/5] fix: prioritize local imports over node_modules in auto-import suggestions(#62667) --- src/services/codefixes/importFixes.ts | 21 ++++++++ .../fourslash/importFixesPrioritizeLocal.ts | 54 +++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 tests/cases/fourslash/importFixesPrioritizeLocal.ts diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 6034c9dfc3de1..9f921696b8319 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1414,6 +1414,21 @@ function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile: } /** @returns `Comparison.LessThan` if `a` is better than `b`. */ + +/** Heuristic approach: Prioritize local/relative imports over node_modules imports. */ +function compareLocalVsExternal( + a: ImportFixWithModuleSpecifier, + b: ImportFixWithModuleSpecifier +): Comparison { + const aIsExternal = a.moduleSpecifierKind === "node_modules"; + const bIsExternal = b.moduleSpecifierKind === "node_modules"; + if (!aIsExternal && bIsExternal) return Comparison.LessThan; + if (aIsExternal && !bIsExternal) return Comparison.GreaterThan; + return Comparison.EqualTo; +} + +/** @returns `Comparison.LessThan` if `a` is better than `b`. */ + function compareModuleSpecifiers( a: ImportFixWithModuleSpecifier, b: ImportFixWithModuleSpecifier, @@ -1424,6 +1439,12 @@ function compareModuleSpecifiers( toPath: (fileName: string) => Path, ): Comparison { if (a.kind !== ImportFixKind.UseNamespace && b.kind !== ImportFixKind.UseNamespace) { + // STEP 2: ADD THE COMPARISON LOGIC HERE (INSIDE THE FUNCTION) ✅ + const localVsExternalComparison = compareLocalVsExternal(a, b); + if (localVsExternalComparison !== Comparison.EqualTo) { + return localVsExternalComparison; + } + return compareBooleans( b.moduleSpecifierKind !== "node_modules" || allowsImportingSpecifier(b.moduleSpecifier), a.moduleSpecifierKind !== "node_modules" || allowsImportingSpecifier(a.moduleSpecifier), diff --git a/tests/cases/fourslash/importFixesPrioritizeLocal.ts b/tests/cases/fourslash/importFixesPrioritizeLocal.ts new file mode 100644 index 0000000000000..9f88eb53c99e6 --- /dev/null +++ b/tests/cases/fourslash/importFixesPrioritizeLocal.ts @@ -0,0 +1,54 @@ +/// + +// Test that local imports are prioritized over external node_modules imports +// when the same symbol is exported from both + +// @Filename: /node_modules/@mui/material/index.d.ts +//// export function useTheme(): { palette: string }; + +// @Filename: /node_modules/@mui/material/package.json +//// { "name": "@mui/material", "version": "5.0.0", "types": "index.d.ts" } + +// @Filename: /node_modules/zustand/index.d.ts +//// export function useStore(): any; + +// @Filename: /node_modules/zustand/package.json +//// { "name": "zustand", "version": "4.0.0", "types": "index.d.ts" } + +// @Filename: /utils/store.ts +//// export function useTheme() { +//// return { palette: 'light' }; +//// } +//// export function useStore() { +//// return {}; +//// } + +// @Filename: /components/Button.tsx +//// // Local useTheme should be suggested first +//// const theme = useTheme/*1*/(); + +// @Filename: /components/Header.tsx +//// // Local useStore should be suggested first +//// const store = useStore/*2*/(); + +// Test 1: useTheme - should prioritize local import over @mui/material +goTo.marker("1"); +verify.importFixAtPosition([ +`import { useTheme } from "../utils/store"; +// Local useTheme should be suggested first +const theme = useTheme();`, +`import { useTheme } from "@mui/material"; +// Local useTheme should be suggested first +const theme = useTheme();` +]); + +// Test 2: useStore - should prioritize local import over zustand +goTo.marker("2"); +verify.importFixAtPosition([ +`import { useStore } from "../utils/store"; +// Local useStore should be suggested first +const store = useStore();`, +`import { useStore } from "zustand"; +// Local useStore should be suggested first +const store = useStore();` +]); \ No newline at end of file From 3835b4ab10c72e882db5fb18d89b88788f860322 Mon Sep 17 00:00:00 2001 From: Viraj <77448246+virajsabhaya23@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:19:03 -0500 Subject: [PATCH 2/5] Update src/services/codefixes/importFixes.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/services/codefixes/importFixes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 9f921696b8319..8252474556088 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1439,7 +1439,7 @@ function compareModuleSpecifiers( toPath: (fileName: string) => Path, ): Comparison { if (a.kind !== ImportFixKind.UseNamespace && b.kind !== ImportFixKind.UseNamespace) { - // STEP 2: ADD THE COMPARISON LOGIC HERE (INSIDE THE FUNCTION) ✅ + const localVsExternalComparison = compareLocalVsExternal(a, b); if (localVsExternalComparison !== Comparison.EqualTo) { return localVsExternalComparison; From 8989ebdf2aabd7ddf09617c2dd9e9dd7778372ed Mon Sep 17 00:00:00 2001 From: Viraj <77448246+virajsabhaya23@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:19:25 -0500 Subject: [PATCH 3/5] Update src/services/codefixes/importFixes.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/services/codefixes/importFixes.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 8252474556088..f095824e2104a 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1427,8 +1427,6 @@ function compareLocalVsExternal( return Comparison.EqualTo; } -/** @returns `Comparison.LessThan` if `a` is better than `b`. */ - function compareModuleSpecifiers( a: ImportFixWithModuleSpecifier, b: ImportFixWithModuleSpecifier, From bbcc694de4250a5302799f28d53167d99a639905 Mon Sep 17 00:00:00 2001 From: Viraj <77448246+virajsabhaya23@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:19:39 -0500 Subject: [PATCH 4/5] Update src/services/codefixes/importFixes.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/services/codefixes/importFixes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index f095824e2104a..85f8527b5eff5 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1442,7 +1442,6 @@ function compareModuleSpecifiers( if (localVsExternalComparison !== Comparison.EqualTo) { return localVsExternalComparison; } - return compareBooleans( b.moduleSpecifierKind !== "node_modules" || allowsImportingSpecifier(b.moduleSpecifier), a.moduleSpecifierKind !== "node_modules" || allowsImportingSpecifier(a.moduleSpecifier), From 657ee8f7c74fb7384c159ca737bc024987ffb915 Mon Sep 17 00:00:00 2001 From: Viraj <77448246+virajsabhaya23@users.noreply.github.com> Date: Mon, 27 Oct 2025 19:19:47 -0500 Subject: [PATCH 5/5] Update src/services/codefixes/importFixes.ts Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/services/codefixes/importFixes.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts index 85f8527b5eff5..4404665c94d6e 100644 --- a/src/services/codefixes/importFixes.ts +++ b/src/services/codefixes/importFixes.ts @@ -1414,7 +1414,6 @@ function getBestFix(fixes: readonly ImportFixWithModuleSpecifier[], sourceFile: } /** @returns `Comparison.LessThan` if `a` is better than `b`. */ - /** Heuristic approach: Prioritize local/relative imports over node_modules imports. */ function compareLocalVsExternal( a: ImportFixWithModuleSpecifier,