diff --git a/packages/core/src/transform/template/rewrite-module.ts b/packages/core/src/transform/template/rewrite-module.ts index a44c8f14c..1039d2b01 100644 --- a/packages/core/src/transform/template/rewrite-module.ts +++ b/packages/core/src/transform/template/rewrite-module.ts @@ -21,36 +21,6 @@ import { calculateCompanionTemplateSpans } from './inlining/companion-file.js'; */ export type RewriteInput = { script: SourceFile; template?: SourceFile }; -// HACK: We prefix every transformed TS file with these non-existent imports -// because it causes TypeScript to consider `.gts` and `.gjs` as possible -// implied extensions when extensions are omitted from import module specifiers, -// i.e. it causes `import FooComponent from './foo';` to work given a `foo.gts` file. -// -// Origin of this hack: -// https://github.com/typed-ember/glint/issues/806#issuecomment-2758616327 -// -// This approach has the following desirable properties: -// -// 1. It doesn't break Organize Imports command -// 2. It doesn't introduce any keywords/variables that'll show up in auto-complete suggestions -const EXTENSION_FIXING_HEADER_HACK_GTS = ` -// @ts-expect-error -({} as typeof import('./__glint-hacky-nonexistent.gts')); - -// @ts-expect-error -({} as typeof import('./__glint-hacky-nonexistent.gjs')); - -`; - -const EXTENSION_FIXING_HEADER_HACK_GJS = ` -// @ts-expect-error -(/** @type {typeof import("./__glint-hacky-nonexistent.gts")} */ ({})) - -// @ts-expect-error -(/** @type {typeof import("./__glint-hacky-nonexistent.gjs")} */ ({})) - -`; - /** * Given the script and/or template that together comprise a component module, * returns a `TransformedModule` representing the combined result, with the @@ -97,17 +67,7 @@ function calculateCorrelatedSpans( ): CorrelatedSpansResult { let directives: Array = []; let errors: Array = []; - let partialSpans: Array = [ - { - originalFile: script, - originalStart: 0, - originalLength: 0, - insertionPoint: 0, - transformedSource: environment.isUntypedScript(script.filename) - ? EXTENSION_FIXING_HEADER_HACK_GJS - : EXTENSION_FIXING_HEADER_HACK_GTS, - }, - ]; + let partialSpans: Array = []; let { ast, emitMetadata, error } = parseScript(ts, script, environment); diff --git a/packages/tsserver-plugin/src/typescript-server-plugin.ts b/packages/tsserver-plugin/src/typescript-server-plugin.ts index 520f1b967..2e94386fa 100644 --- a/packages/tsserver-plugin/src/typescript-server-plugin.ts +++ b/packages/tsserver-plugin/src/typescript-server-plugin.ts @@ -61,6 +61,49 @@ const plugin = createLanguageServicePlugin( (fileName) => fileName, ); + const resolveModuleNameLiterals = + info.languageServiceHost.resolveModuleNameLiterals?.bind(info.languageServiceHost); + + if (resolveModuleNameLiterals) { + // TS isn't aware of our customer .gts/.gjs extensions by default which causes + // issues with resolving imports that omit extensions. We hackishly "teach" + // TS about these extensions by overriding `resolveModuleNameLiterals` to + // inject non-existent imports that cause TS to consider the extensions when + // resolving. + // + // Origin of this hack: + // https://github.com/typed-ember/glint/issues/806#issuecomment-2758616327 + info.languageServiceHost.resolveModuleNameLiterals = ( + moduleLiterals, + containingFile, + redirectedReference, + options, + ...rest + ) => { + let fakeImportNodes: any = []; + if (moduleLiterals.length > 0) { + fakeImportNodes.push({ + ...moduleLiterals[0], + text: './__NONEXISTENT_GLINT_HACK__.gts', + }); + fakeImportNodes.push({ + ...moduleLiterals[0], + text: './__NONEXISTENT_GLINT_HACK__.gjs', + }); + } + + const result = resolveModuleNameLiterals( + [...fakeImportNodes, ...moduleLiterals], + containingFile, + redirectedReference, + options, + ...rest, + ); + + return result.slice(fakeImportNodes.length); + }; + } + // #3963 // const timer = setInterval(() => { // if (info.project['program']) { diff --git a/packages/vscode/__fixtures__/ember-app-loose-and-gts/app/components/vanilla.ts b/packages/vscode/__fixtures__/ember-app-loose-and-gts/app/components/vanilla.ts new file mode 100644 index 000000000..d4c59ecab --- /dev/null +++ b/packages/vscode/__fixtures__/ember-app-loose-and-gts/app/components/vanilla.ts @@ -0,0 +1,3 @@ +import Greeting from './Greeting'; + +export default Greeting; diff --git a/packages/vscode/__fixtures__/template-imports-app-ts-plugin/src/index.gts b/packages/vscode/__fixtures__/template-imports-app-ts-plugin/src/index.gts index fae47f952..5594e2179 100644 --- a/packages/vscode/__fixtures__/template-imports-app-ts-plugin/src/index.gts +++ b/packages/vscode/__fixtures__/template-imports-app-ts-plugin/src/index.gts @@ -1,11 +1,7 @@ import '@glint/environment-ember-loose'; import '@glint/environment-ember-template-imports'; -// TS-PLUGIN: I had to add the .gts extension in order for this to work, otherwise -// Cannot find module './Greeting' or its corresponding type declarations. [ts-plugin(2307)] - -// import Greeting from './Greeting'; -import Greeting from './Greeting.gts'; +import Greeting from './Greeting';