fix(typescript): respect resolveHiddenExtensions when a host pre-installs resolveModuleNameLiterals#309
Open
NullVoxPopuli wants to merge 1 commit into
Conversation
…hen a plugin sets resolveHiddenExtensions When any registered language plugin uses `resolveHiddenExtensions: true`, the wrapped `moduleResolutionHost.fileExists` in resolveModuleName.ts is what makes extensionless imports of plugin-extension files resolvable (it answers `Foo.d.ts` as true when `Foo.<ext>` exists on disk). The fast-path in proxyCreateProgram delegates a module-resolution batch back to the original host whenever none of the import literals end in a plugin extension. In one-shot `tsc` the original host has no resolver installed, so the fast-path is a no-op and volar's wrapper runs. But `tsc --watch` installs `resolutionCache.resolveModuleNameLiterals` on the compiler host before volar's proxy runs. With that resolver defined, extensionless imports take the fast-path and bypass the wrapper, so e.g. glint's `import Foo from './Foo'` (where `Foo.gts` exists) fails with TS2307 in watch mode while succeeding in one-shot mode. Skip the fast-path when any plugin opts in to `resolveHiddenExtensions`, matching the existing pluginExtensions check. Reported by https://github.com/typed-ember/glint
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When any registered language plugin sets
typescript.resolveHiddenExtensions: true, the wrappedmoduleResolutionHost.fileExistsinresolveModuleName.tsis what makes extensionless imports of plugin-extension files resolvable (it answersFoo.d.tsastruewhenFoo.<ext>exists on disk, so tsc's hard-codedtryAddingExtensionsaccepts the lookup).The fast-path in
proxyCreateProgramshort-circuits a resolution batch back to the original host whenever no import literal ends in a plugin extension. In one-shottscthe original host has noresolveModuleNameLiteralsinstalled, so the condition is false and volar's wrapper runs.But
tsc --watchinstalls a cached resolver on the compiler host before volar's proxy runs:With that resolver defined, extensionless imports now take the fast-path and bypass the wrapper. The host's plain
fileExistsdoesn't know about the.<ext>↔.d.tsshim, so the import fails with TS2307 in watch mode while succeeding in one-shot mode.This was hit by glint for
.gtsfiles:import Foo from './Foo'(whereFoo.gtsexists) works underember-tscbut errors underember-tsc --watch. Same shape as the TS Plugin mode limitation already tracked at typed-ember/glint#806.Change
Skip the fast-path when any plugin opts in to
resolveHiddenExtensions, matching the existing pluginExtensions check. Applied to bothresolveModuleNameLiteralsandresolveModuleNames.Test plan
packages/typescript/tests/proxyCreateProgram.spec.tswith two cases:resolveHiddenExtensions: true, extensionless imports must not be delegated to the host'sresolveModuleNameLiterals.resolveHiddenExtensions, the existing fast-path is preserved — extensionless imports still delegate to the host.pnpm buildcleanpnpm test— 72 passed (10 files), including the two new cases. Reverting the production change makes the first case fail, confirming it catches the regression.glint: with this patch applied to the@volar/typescriptsource and rebuilt,ember-tsc --watchagainst a project with extensionless.gtsimports reportsFound 0 errors(wasTS2307: Cannot find module './Foo').