Skip to content

Commit 5a039af

Browse files
committed
Support go-to-definition for imports of scripts and arbitrary files
1 parent 203a5ce commit 5a039af

File tree

4 files changed

+52
-7
lines changed

4 files changed

+52
-7
lines changed

src/services/findAllReferences.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -624,7 +624,7 @@ namespace ts.FindAllReferences {
624624
}
625625
if (isSourceFile(node)) {
626626
const resolvedRef = GoToDefinition.getReferenceAtPosition(node, position, program);
627-
if (!resolvedRef) {
627+
if (!resolvedRef?.file) {
628628
return undefined;
629629
}
630630
const moduleSymbol = program.getTypeChecker().getMergedSymbol(resolvedRef.file.symbol);
@@ -656,7 +656,7 @@ namespace ts.FindAllReferences {
656656
if (!symbol) {
657657
// String literal might be a property (and thus have a symbol), so do this here rather than in getReferencedSymbolsSpecial.
658658
if (!options.implementations && isStringLiteralLike(node)) {
659-
if (isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ true) || isExternalModuleReference(node.parent) || isImportDeclaration(node.parent) || isImportCall(node.parent)) {
659+
if (isModuleSpecifierLike(node)) {
660660
const fileIncludeReasons = program.getFileIncludeReasons();
661661
const referencedFileName = node.getSourceFile().resolvedModules?.get(node.text)?.resolvedFileName;
662662
const referencedFile = referencedFileName ? program.getSourceFile(referencedFileName) : undefined;

src/services/goToDefinition.ts

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ namespace ts.GoToDefinition {
33
export function getDefinitionAtPosition(program: Program, sourceFile: SourceFile, position: number): readonly DefinitionInfo[] | undefined {
44
const resolvedRef = getReferenceAtPosition(sourceFile, position, program);
55
if (resolvedRef) {
6-
return [getDefinitionInfoForFileReference(resolvedRef.reference.fileName, resolvedRef.file.fileName)];
6+
return [getDefinitionInfoForFileReference(resolvedRef.reference.fileName, resolvedRef.fileName)];
77
}
88

99
const node = getTouchingPropertyName(sourceFile, position);
@@ -108,24 +108,41 @@ namespace ts.GoToDefinition {
108108
|| (!isCallLikeExpression(calledDeclaration.parent) && s === calledDeclaration.parent.symbol);
109109
}
110110

111-
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { reference: FileReference, file: SourceFile } | undefined {
111+
export function getReferenceAtPosition(sourceFile: SourceFile, position: number, program: Program): { reference: FileReference, fileName: string, file?: SourceFile } | undefined {
112112
const referencePath = findReferenceInPosition(sourceFile.referencedFiles, position);
113113
if (referencePath) {
114114
const file = program.getSourceFileFromReference(sourceFile, referencePath);
115-
return file && { reference: referencePath, file };
115+
return file && { reference: referencePath, fileName: file.fileName };
116116
}
117117

118118
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
119119
if (typeReferenceDirective) {
120120
const reference = program.getResolvedTypeReferenceDirectives().get(typeReferenceDirective.fileName);
121121
const file = reference && program.getSourceFile(reference.resolvedFileName!); // TODO:GH#18217
122-
return file && { reference: typeReferenceDirective, file };
122+
return file && { reference: typeReferenceDirective, fileName: file.fileName };
123123
}
124124

125125
const libReferenceDirective = findReferenceInPosition(sourceFile.libReferenceDirectives, position);
126126
if (libReferenceDirective) {
127127
const file = program.getLibFileFromReference(libReferenceDirective);
128-
return file && { reference: libReferenceDirective, file };
128+
return file && { reference: libReferenceDirective, fileName: file.fileName };
129+
}
130+
131+
if (sourceFile.resolvedModules?.size) {
132+
const node = getTokenAtPosition(sourceFile, position);
133+
if (isModuleSpecifierLike(node) && !pathIsBareSpecifier(node.text) && sourceFile.resolvedModules.has(node.text)) {
134+
const fileName = sourceFile.resolvedModules.get(node.text)?.resolvedFileName
135+
|| resolvePath(getDirectoryPath(sourceFile.fileName), node.text);
136+
return {
137+
file: program.getSourceFile(fileName),
138+
fileName,
139+
reference: {
140+
pos: node.getStart(),
141+
end: node.getEnd(),
142+
fileName: node.text
143+
}
144+
};
145+
}
129146
}
130147

131148
return undefined;

src/services/utilities.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1906,6 +1906,14 @@ namespace ts {
19061906
});
19071907
}
19081908

1909+
export function isModuleSpecifierLike(node: Node): node is StringLiteralLike {
1910+
return isStringLiteralLike(node) && (
1911+
isExternalModuleReference(node.parent) ||
1912+
isImportDeclaration(node.parent) ||
1913+
isRequireCall(node.parent, /*requireStringLiteralLikeArgument*/ false) && node.parent.arguments[0] === node ||
1914+
isImportCall(node.parent) && node.parent.arguments[0] === node);
1915+
}
1916+
19091917
export type ObjectBindingElementWithoutPropertyName = BindingElement & { name: Identifier };
19101918

19111919
export function isObjectBindingElementWithoutPropertyName(bindingElement: Node): bindingElement is ObjectBindingElementWithoutPropertyName {
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/// <reference path="fourslash.ts" />
2+
3+
// @filename: scriptThing.ts
4+
//// /*1d*/console.log("woooo side effects")
5+
6+
// @filename: stylez.css
7+
//// /*2d*/div {
8+
//// color: magenta;
9+
//// }
10+
11+
// @filename: moduleThing.ts
12+
13+
// not a module, but we should let you jump to it.
14+
//// import [|/*1*/"./scriptThing"|];
15+
16+
// not JS/TS, but if we can, you should be able to jump to it.
17+
//// import [|/*2*/"./stylez.css"|];
18+
19+
verify.goToDefinition("1", "1d");
20+
verify.goToDefinition("2", "2d");

0 commit comments

Comments
 (0)