Skip to content

fix(auto-import): don't suggest # imports that only resolve via condition fallback - #64177

Open
Marwan (marwan562) wants to merge 3 commits into
microsoft:mainfrom
marwan562:fix/64171-autoimport-invalid-specifier
Open

fix(auto-import): don't suggest # imports that only resolve via condition fallback#64177
Marwan (marwan562) wants to merge 3 commits into
microsoft:mainfrom
marwan562:fix/64171-autoimport-invalid-specifier

Conversation

@marwan562

Copy link
Copy Markdown

With imports": { "#*": { "node": "./dist/*/index.js", "default": "./dist/*.js" } } and nodenext, auto-import offered both #utils/summarize and #utils/summarize/summarize. The second only resolves in TS by falling back from node to default after the node target misses. Node picks the first matching condition and throws ERR_MODULE_NOT_FOUND instead, so picking that suggestion crashes at runtime.

Reverse mapping in tryGetModuleNameFromExportsOrImports did the same fallback as the resolver. It now mirrors Node first-match: when a runtime-active condition misses, later conditions aren't tried. types/types@ don't block since Node ignores them, nested objects with no active runtime key still fall through, and array fallback still works.

Added cases alongside the existing ones in tsc/internal/modulespecifiers/specifiers_test.go.

Fixes #64171
Related #62439, #50762

Disclosure: I used AI assistance to draft this patch and reviewed and tested it myself.

…tion fallback

Reverse mapping in tryGetModuleNameFromExportsOrImports mirrored TS resolver fallback across conditions, suggesting specifiers like #utils/summarize/summarize that resolve via default only after node misses. Node picks first matching condition and throws on miss, so such suggestions crash at runtime with ERR_MODULE_NOT_FOUND.

Mirror Node first-match semantics: when a runtime-active condition misses, block later conditions. Types-only conditions are ignored at runtime and don't block. Handles nested conditionals without active runtime keys and preserves array fallback.

Closes microsoft#64171
Copilot AI balanced review requested due to automatic review settings September 5, 2026 04:41
@github-project-automation github-project-automation Bot moved this to Not started in PR Backlog Sep 5, 2026
@typescript-automation typescript-automation Bot added the For Backlog Bug PRs that fix a backlog bug label Sep 5, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Two moderate resolution-semantics issues could still produce incorrect auto-import behavior.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Updates auto-import reverse mapping to better match Node.js conditional import resolution.

Changes:

  • Stops fallback after matching runtime conditions.
  • Adds conditional, nested, types-only, and array mapping tests.
File summaries
File Review
tsc/internal/modulespecifiers/specifiers.go Requires fixes for deeper conditional objects and Node array-target semantics.
tsc/internal/modulespecifiers/specifiers_test.go Adds regression coverage, but incorrectly expects file-existence fallback for arrays.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Balanced

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread tsc/internal/modulespecifiers/specifiers.go
Comment thread tsc/internal/modulespecifiers/specifiers.go Outdated
@marwan562

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

…rays

Address Copilot review: arrays select first valid string target at runtime (no file-existence fallback), and deeper nested conditionals with inactive keys return undefined and should fallback. Switch reverse mapping to tri-state (matched/blocked/skipped) so terminal misses block later fallback while undefined continues.
@marwan562

Copy link
Copy Markdown
Author

Addressed both Copilot comments:

  • Arrays now treat first valid string as terminal (no file-existence fallback). Second-element match test corrected to expect blocked, first-element still valid. Undefined array entries (inactive conditional) still fall through.
  • Nested conditionals now track terminal vs undefined via tri-state return, so { node: { import: { browser: ... } }, default } with inactive browser correctly falls back to default.

Added deeper-nesting + array-undefined-first cases. All modulespecifiers tests pass.

Copilot review

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The critical and moderate fallback-handling issues must be resolved before approval.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Review details

Suppressed comments (2)

tsc/internal/modulespecifiers/specifiers.go:1337

  • An exhausted array is not always equivalent to an undefined nested conditional. Node treats an empty array as null (terminal), and throws the last invalid-target error when all entries are invalid; only an array whose entries all resolve to undefined may fall through. Returning blocked=false here makes maps such as { "node": [], "default": "./dist/index.js" } suggest the default even though Node rejects that specifier. Track these outcomes separately and propagate a terminal result for empty/all-invalid arrays.
		return "", false

tsc/internal/modulespecifiers/specifiers_test.go:393

  • These cases only invoke the private reverse-mapping helper, but the regression is specifically the LSP auto-import/Quick Fix result. Add a Fourslash regression using the issue's package.json/project layout and assert the exact list with VerifyImportFixModuleSpecifiers; existing package-import auto-import coverage uses that path (for example, tsc/internal/fourslash/tests/autoImportPackageJsonImportsConditions_test.go:10-29). This ensures the invalid suggestion is actually filtered through the full language-server flow.
				result := tryGetModuleNameFromExportsOrImports(
  • Files reviewed: 2/2 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread tsc/internal/modulespecifiers/specifiers.go Outdated
Comment thread tsc/internal/modulespecifiers/specifiers.go Outdated
…s fallback, handle empty/all-invalid arrays

Address Copilot review on PR 64177:
- String misses now check target validity (same rules as forward
  resolver): invalid targets skipped in arrays, terminal in
  conditionals; valid misses stay terminal.
- Thread inTypesOnly through conditional/array recursion so
  types-only subtrees never block, preserving TS declaration
  fallback that Node ignores at runtime.
- Empty and all-invalid arrays are terminal at runtime; only
  all-undefined arrays fall through.
- Add unit cases and Fourslash regression for issue 64171.
@marwan562

Marwan (marwan562) commented Sep 8, 2026

Copy link
Copy Markdown
Author

Addressed the two Sep 8 Copilot threads:

  • String validity (specifiers.go:1322 + 1337): string misses now check isValidPackageTarget (same rules as forward resolver: ./ prefix, bare-specifier allowance for imports, .././node_modules segments). Invalid targets return statusInvalid (skipped in arrays, terminal in conditionals); valid misses stay terminal. ["invalid", "./dist/index.js"] now falls through to the valid entry.
  • Types-only arrays (specifiers.go:1334): threaded inTypesOnly through conditional/array recursion, so "types": ["./missing.d.ts", "./index.d.ts"] preserves TS declaration fallback and never blocks outer default (Node ignores the subtree at runtime).

Also handled suppressed feedback: empty and all-invalid arrays are terminal at runtime (only all-undefined falls through), and added Fourslash regression TestAutoImportPackageJsonImportsInvalidSpecifier using the issue layout with VerifyImportFixModuleSpecifiers.

All modulespecifiers + TestAutoImportPackageJson* Fourslash tests pass.

Copilot review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

For Backlog Bug PRs that fix a backlog bug

Projects

Status: Not started

Development

Successfully merging this pull request may close these issues.

[Auto-import] Quick Fix suggests invalid module specifiers that fail to resolve at runtime

2 participants