diff --git a/src/harness/fourslashImpl.ts b/src/harness/fourslashImpl.ts
index 640e0e0b822..7f0d385b796 100644
--- a/src/harness/fourslashImpl.ts
+++ b/src/harness/fourslashImpl.ts
@@ -771,7 +771,9 @@ namespace FourSlash {
}
if (endMarkers.length !== definitions.length) {
- this.raiseError(`${testName} failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}`);
+ const markers = definitions.map(d => ({ text: "HERE", fileName: d.fileName, position: d.textSpan.start }));
+ const actual = this.renderMarkers(markers);
+ this.raiseError(`${testName} failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}\n\n${actual}`);
}
ts.zipWith(endMarkers, definitions, (endMarkerOrFileResult, definition, i) => {
@@ -781,17 +783,8 @@ namespace FourSlash {
ts.Debug.assert(typeof expectedFileName === "string");
const expectedPosition = marker?.position || 0;
if (ts.comparePaths(expectedFileName, definition.fileName, /*ignoreCase*/ true) !== ts.Comparison.EqualTo || expectedPosition !== definition.textSpan.start) {
- const filesToDisplay = ts.deduplicate([expectedFileName, definition.fileName], ts.equateValues);
const markers = [{ text: "EXPECTED", fileName: expectedFileName, position: expectedPosition }, { text: "ACTUAL", fileName: definition.fileName, position: definition.textSpan.start }];
- const text = filesToDisplay.map(fileName => {
- const markersToRender = markers.filter(m => m.fileName === fileName).sort((a, b) => b.position - a.position);
- let fileContent = this.tryGetFileContent(fileName) || "";
- for (const marker of markersToRender) {
- fileContent = fileContent.slice(0, marker.position) + `\x1b[1;4m/*${marker.text}*/\x1b[0;31m` + fileContent.slice(marker.position);
- }
- return `// @Filename: ${fileName}\n${fileContent}`;
- }).join("\n\n");
-
+ const text = this.renderMarkers(markers);
this.raiseError(`${testName} failed for definition ${markerName || expectedFileName} (${i}): expected ${expectedFileName} at ${expectedPosition}, got ${definition.fileName} at ${definition.textSpan.start}\n\n${text}\n`);
}
if (definition.unverified && (typeof endMarkerOrFileResult === "string" || !endMarkerOrFileResult.unverified)) {
@@ -805,6 +798,18 @@ namespace FourSlash {
});
}
+ private renderMarkers(markers: { text: string, fileName: string, position: number }[]) {
+ const filesToDisplay = ts.deduplicate(markers.map(m => m.fileName), ts.equateValues);
+ return filesToDisplay.map(fileName => {
+ const markersToRender = markers.filter(m => m.fileName === fileName).sort((a, b) => b.position - a.position);
+ let fileContent = this.tryGetFileContent(fileName) || "";
+ for (const marker of markersToRender) {
+ fileContent = fileContent.slice(0, marker.position) + `\x1b[1;4m/*${marker.text}*/\x1b[0;31m` + fileContent.slice(marker.position);
+ }
+ return `// @Filename: ${fileName}\n${fileContent}`;
+ }).join("\n\n");
+ }
+
private verifyDefinitionTextSpan(defs: ts.DefinitionInfoAndBoundSpan, startMarkerName: string) {
const range = this.testData.ranges.find(range => this.markerName(range.marker!) === startMarkerName);
diff --git a/tests/cases/fourslash/server/goToSource1.ts b/tests/cases/fourslash/server/goToSource1_localJsBesideDts.ts
similarity index 100%
rename from tests/cases/fourslash/server/goToSource1.ts
rename to tests/cases/fourslash/server/goToSource1_localJsBesideDts.ts
diff --git a/tests/cases/fourslash/server/goToSource2_nodeModulesWithTypes.ts b/tests/cases/fourslash/server/goToSource2_nodeModulesWithTypes.ts
new file mode 100644
index 00000000000..a2166786c54
--- /dev/null
+++ b/tests/cases/fourslash/server/goToSource2_nodeModulesWithTypes.ts
@@ -0,0 +1,18 @@
+///
+
+// @moduleResolution: node
+
+// @Filename: /node_modules/foo/package.json
+//// { "name": "foo", "version": "1.0.0", "main": "./lib/main.js", "types": "./types/main.d.ts" }
+
+// @Filename: /node_modules/foo/lib/main.js
+//// export const /*end*/a = "a";
+
+// @Filename: /node_modules/foo/types/main.d.ts
+//// export declare const a: string;
+
+// @Filename: /index.ts
+//// import { a } from "foo";
+//// [|a/*start*/|]
+
+verify.goToSourceDefinition("start", "end");
diff --git a/tests/cases/fourslash/server/goToSource3_nodeModulesAtTypes.ts b/tests/cases/fourslash/server/goToSource3_nodeModulesAtTypes.ts
new file mode 100644
index 00000000000..152d411040a
--- /dev/null
+++ b/tests/cases/fourslash/server/goToSource3_nodeModulesAtTypes.ts
@@ -0,0 +1,21 @@
+///
+
+// @moduleResolution: node
+
+// @Filename: /node_modules/foo/package.json
+//// { "name": "foo", "version": "1.0.0", "main": "./lib/main.js" }
+
+// @Filename: /node_modules/foo/lib/main.js
+//// export const /*end*/a = "a";
+
+// @Filename: /node_modules/@types/foo/package.json
+//// { "name": "@types/foo", "version": "1.0.0", "types": "./index.d.ts" }
+
+// @Filename: /node_modules/@types/foo/index.d.ts
+//// export declare const a: string;
+
+// @Filename: /index.ts
+//// import { a } from "foo";
+//// [|a/*start*/|]
+
+verify.goToSourceDefinition("start", "end");
diff --git a/tests/cases/fourslash/server/goToSource4_sameAsGoToDef1.ts b/tests/cases/fourslash/server/goToSource4_sameAsGoToDef1.ts
new file mode 100644
index 00000000000..dc8f9a47abc
--- /dev/null
+++ b/tests/cases/fourslash/server/goToSource4_sameAsGoToDef1.ts
@@ -0,0 +1,8 @@
+///
+
+// @Filename: /index.ts
+//// import { a/*end*/ } from "./a";
+//// [|a/*start*/|]
+
+verify.goToDefinition("start", "end");
+verify.goToSourceDefinition("start", "end");
diff --git a/tests/cases/fourslash/server/goToSource5_sameAsGoToDef2.ts b/tests/cases/fourslash/server/goToSource5_sameAsGoToDef2.ts
new file mode 100644
index 00000000000..f2b7e2b7345
--- /dev/null
+++ b/tests/cases/fourslash/server/goToSource5_sameAsGoToDef2.ts
@@ -0,0 +1,17 @@
+///
+
+// @Filename: /a.ts
+//// export const /*end*/a = 'a';
+
+// @Filename: /a.d.ts
+//// export declare const a: string;
+
+// @Filename: /a.js
+//// export const a = 'a';
+
+// @Filename: /b.ts
+//// import { a } from './a';
+//// [|a/*start*/|]
+
+verify.goToDefinition("start", "end");
+verify.goToSourceDefinition("start", "end");
diff --git a/tests/cases/fourslash/server/goToSource6_sameAsGoToDef3.ts b/tests/cases/fourslash/server/goToSource6_sameAsGoToDef3.ts
new file mode 100644
index 00000000000..87b7065a17b
--- /dev/null
+++ b/tests/cases/fourslash/server/goToSource6_sameAsGoToDef3.ts
@@ -0,0 +1,24 @@
+///
+
+// @Filename: /node_modules/foo/package.json
+//// { "name": "foo", "version": "1.2.3", "typesVersions": { "*": { "*": ["./types/*"] } } }
+
+// @Filename: /node_modules/foo/src/a.ts
+//// export const /*end*/a = 'a';
+
+// @Filename: /node_modules/foo/types/a.d.ts
+//// export declare const a: string;
+//// //# sourceMappingURL=a.d.ts.map
+
+// @Filename: /node_modules/foo/types/a.d.ts.map
+//// {"version":3,"file":"a.d.ts","sourceRoot":"","sources":["../src/a.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,EAAE,OAAO,CAAC;;AACvB,wBAAsB"}
+
+// @Filename: /node_modules/foo/dist/a.js
+//// export const a = 'a';
+
+// @Filename: /b.ts
+//// import { a } from 'foo/a';
+//// [|a/*start*/|]
+
+verify.goToDefinition("start", "end");
+verify.goToSourceDefinition("start", "end");