Skip to content

Commit 2995a71

Browse files
authored
Fix specifiers for declaration files (#3351)
1 parent c0703e6 commit 2995a71

12 files changed

Lines changed: 82 additions & 82 deletions

internal/ls/string_completions.go

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1813,7 +1813,7 @@ func getFilenameWithExtensionOption(
18131813
extensionOptions *extensionOptions,
18141814
isExportsOrImportsWildcard bool,
18151815
) (string, string) {
1816-
nonJSResult := tryGetRealFileNameForNonJSDeclarationFileName(name)
1816+
nonJSResult := modulespecifiers.TryGetRealFileNameForNonJSDeclarationFileName(name)
18171817
if nonJSResult != "" {
18181818
return nonJSResult, tspath.TryGetExtensionFromPath(nonJSResult)
18191819
}
@@ -1863,22 +1863,6 @@ func getFilenameWithExtensionOption(
18631863
return name, tspath.TryGetExtensionFromPath(name)
18641864
}
18651865

1866-
// Remaps files like `foo.d.json.ts` back to `foo.json`.
1867-
func tryGetRealFileNameForNonJSDeclarationFileName(fileName string) string {
1868-
baseName := tspath.GetBaseFileName(fileName)
1869-
// Ends with .ts, contains ".d.", and is NOT a standard .d.ts file
1870-
if !strings.HasSuffix(fileName, tspath.ExtensionTs) ||
1871-
!strings.Contains(baseName, ".d.") ||
1872-
strings.HasSuffix(baseName, tspath.ExtensionDts) {
1873-
return ""
1874-
}
1875-
noExtension := tspath.RemoveExtension(fileName, tspath.ExtensionTs)
1876-
lastDotIndex := strings.LastIndex(noExtension, ".")
1877-
ext := noExtension[lastDotIndex:]
1878-
before, _, _ := strings.Cut(noExtension, ".d.")
1879-
return before + ext
1880-
}
1881-
18821866
func walkUpParentheses(node *ast.Node) *ast.Node {
18831867
switch node.Kind {
18841868
case ast.KindParenthesizedType:

internal/modulespecifiers/specifiers.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -661,6 +661,12 @@ func processEnding(
661661
if tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionMts, tspath.ExtensionCts}) {
662662
return noExtension + getJSExtensionForFile(fileName, options)
663663
}
664+
if !tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionDts}) && tspath.FileExtensionIsOneOf(fileName, []string{tspath.ExtensionTs}) && strings.Contains(fileName, ".d.") {
665+
// `foo.d.json.ts` and the like - remap back to `foo.json`
666+
if result := TryGetRealFileNameForNonJSDeclarationFileName(fileName); result != "" {
667+
return result
668+
}
669+
}
664670

665671
switch allowedEndings[0] {
666672
case ModuleSpecifierEndingMinimal:
@@ -676,10 +682,21 @@ func processEnding(
676682
case ModuleSpecifierEndingJsExtension:
677683
return noExtension + getJSExtensionForFile(fileName, options)
678684
case ModuleSpecifierEndingTsExtension:
679-
// declaration files are already handled first with a remap back to input js paths,
680-
// and mjs/cjs/json are already singled out,
681-
// so we know fileName has to be either an input .js or .ts path already
682-
// TODO: possible dead code in strada in this branch to do with declaration file name handling
685+
// For now, we don't know if this import is going to be type-only, which means we don't
686+
// know if a .d.ts extension is valid, so use no extension or a .js extension
687+
if tspath.IsDeclarationFileName(fileName) {
688+
extensionlessPriority := -1
689+
for i, e := range allowedEndings {
690+
if e == ModuleSpecifierEndingMinimal || e == ModuleSpecifierEndingIndex {
691+
extensionlessPriority = i
692+
break
693+
}
694+
}
695+
if extensionlessPriority != -1 && extensionlessPriority < jsPriority {
696+
return noExtension
697+
}
698+
return noExtension + getJSExtensionForFile(fileName, options)
699+
}
683700
return fileName
684701
default:
685702
debug.AssertNever(allowedEndings[0])

internal/modulespecifiers/specifiers_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,40 @@ func TestContainsIgnoredPath(t *testing.T) {
257257
}
258258
}
259259

260+
func TestTryGetRealFileNameForNonJSDeclarationFileName(t *testing.T) {
261+
t.Parallel()
262+
tests := []struct {
263+
name string
264+
fileName string
265+
expected string
266+
}{
267+
{
268+
name: "json declaration file",
269+
fileName: "/project/foo.d.json.ts",
270+
expected: "/project/foo.json",
271+
},
272+
{
273+
name: "multi-dot source extension declaration file",
274+
fileName: "/project/foo.module.d.css.ts",
275+
expected: "/project/foo.module.css",
276+
},
277+
{
278+
name: "plain dts file ignored",
279+
fileName: "/project/foo.d.ts",
280+
expected: "",
281+
},
282+
}
283+
284+
for _, tt := range tests {
285+
t.Run(tt.name, func(t *testing.T) {
286+
t.Parallel()
287+
if got := TryGetRealFileNameForNonJSDeclarationFileName(tt.fileName); got != tt.expected {
288+
t.Errorf("TryGetRealFileNameForNonJSDeclarationFileName(%q) = %q, expected %q", tt.fileName, got, tt.expected)
289+
}
290+
})
291+
}
292+
}
293+
260294
func TestTryGetModuleNameFromExportsOrImports(t *testing.T) {
261295
t.Parallel()
262296
t.Run("with exports pattern", func(t *testing.T) {

internal/modulespecifiers/util.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ func GetJSExtensionForDeclarationFileExtension(ext string) string {
151151
}
152152
}
153153

154+
// TryGetRealFileNameForNonJSDeclarationFileName remaps files like `foo.d.json.ts` or
155+
// `foo.module.d.css.ts` back to their real non-JS names.
156+
func TryGetRealFileNameForNonJSDeclarationFileName(fileName string) string {
157+
baseName := tspath.GetBaseFileName(fileName)
158+
// Ends with .ts, contains ".d.", and is NOT a standard .d.ts file
159+
if !strings.HasSuffix(fileName, tspath.ExtensionTs) ||
160+
!strings.Contains(baseName, ".d.") ||
161+
strings.HasSuffix(baseName, tspath.ExtensionDts) {
162+
return ""
163+
}
164+
noExtension := tspath.RemoveExtension(fileName, tspath.ExtensionTs)
165+
lastDotIndex := strings.LastIndex(noExtension, ".")
166+
ext := noExtension[lastDotIndex:]
167+
before, _, _ := strings.Cut(noExtension, ".d.")
168+
return before + ext
169+
}
170+
154171
func getJSExtensionForFile(fileName string, options *core.CompilerOptions) string {
155172
result := module.TryGetJSExtensionForFile(fileName, options)
156173
if len(result) == 0 {

testdata/baselines/reference/submodule/compiler/declarationEmitNoInvalidCommentReuse2.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export type Id<T> = T;
2222

2323
//// [a.d.ts]
2424
export declare const _: {
25-
foo: import("./id.d.ts").Id<{}>;
25+
foo: import("./id").Id<{}>;
2626
};
2727
/**
2828
* huh

testdata/baselines/reference/submodule/compiler/declarationEmitNoInvalidCommentReuse2.js.diff

Lines changed: 0 additions & 11 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/declarationEmitNoInvalidCommentReuse2.types

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
=== a.ts ===
44
import { object } from "./obj.ts";
5-
>object : { foo: import("./id.d.ts").Id<{}>; }
5+
>object : { foo: import("./id").Id<{}>; }
66

77
export const _ = object;
8-
>_ : { foo: import("./id.d.ts").Id<{}>; }
9-
>object : { foo: import("./id.d.ts").Id<{}>; }
8+
>_ : { foo: import("./id").Id<{}>; }
9+
>object : { foo: import("./id").Id<{}>; }
1010

1111
///////////
1212
/**

testdata/baselines/reference/submodule/compiler/declarationEmitNoInvalidCommentReuse2.types.diff

Lines changed: 0 additions & 17 deletions
This file was deleted.

testdata/baselines/reference/submodule/compiler/declarationEmitTransitiveImportOfHtmlDeclarationItem.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,4 +34,4 @@ exports.c = (0, reexporter_1.func)();
3434
import { CustomHtmlRepresentationThing } from "./foo.html";
3535
export declare function func(): CustomHtmlRepresentationThing;
3636
//// [index.d.ts]
37-
export declare const c: import("./foo.d.html").CustomHtmlRepresentationThing;
37+
export declare const c: import("./foo.html").CustomHtmlRepresentationThing;

testdata/baselines/reference/submodule/compiler/declarationEmitTransitiveImportOfHtmlDeclarationItem.js.diff

Lines changed: 0 additions & 8 deletions
This file was deleted.

0 commit comments

Comments
 (0)