diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index 103200600b2..4f04c6f8e82 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -28100,6 +28100,9 @@ namespace ts {
case SyntaxKind.ImportType:
return isLiteralImportTypeNode(node) ? getSymbolAtLocation(node.argument.literal) : undefined;
+ case SyntaxKind.ExportKeyword:
+ return isExportAssignment(node.parent) ? Debug.assertDefined(node.parent.symbol) : undefined;
+
default:
return undefined;
}
diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts
index 30b69c7ce19..16e34565b7e 100644
--- a/src/services/findAllReferences.ts
+++ b/src/services/findAllReferences.ts
@@ -368,6 +368,10 @@ namespace ts.FindAllReferences.Core {
return !options.implementations && isStringLiteral(node) ? getReferencesForStringLiteral(node, sourceFiles, cancellationToken) : undefined;
}
+ if (symbol.escapedName === InternalSymbolName.ExportEquals) {
+ return getReferencedSymbolsForModule(program, symbol.parent!, /*excludeImportTypeOfExportEquals*/ false, sourceFiles, sourceFilesSet);
+ }
+
let moduleReferences: SymbolAndEntries[] = emptyArray;
const moduleSourceFile = isModuleSymbol(symbol);
let referencedNode: Node | undefined = node;
@@ -427,6 +431,22 @@ namespace ts.FindAllReferences.Core {
}
}
+ const exported = symbol.exports!.get(InternalSymbolName.ExportEquals);
+ if (exported) {
+ for (const decl of exported.declarations) {
+ const sourceFile = decl.getSourceFile();
+ if (sourceFilesSet.has(sourceFile.fileName)) {
+ // At `module.exports = ...`, reference node is `module`
+ const node = isBinaryExpression(decl) && isPropertyAccessExpression(decl.left)
+ ? decl.left.expression
+ : isExportAssignment(decl)
+ ? Debug.assertDefined(findChildOfKind(decl, SyntaxKind.ExportKeyword, sourceFile))
+ : getNameOfDeclaration(decl) || decl;
+ references.push(nodeEntry(node));
+ }
+ }
+ }
+
return references.length ? [{ definition: { type: DefinitionKind.Symbol, symbol }, references }] : emptyArray;
}
diff --git a/tests/cases/fourslash/findAllRefsExportEquals.ts b/tests/cases/fourslash/findAllRefsExportEquals.ts
index 6bbdc613554..3580c8fe4ee 100644
--- a/tests/cases/fourslash/findAllRefsExportEquals.ts
+++ b/tests/cases/fourslash/findAllRefsExportEquals.ts
@@ -2,15 +2,16 @@
// @Filename: /a.ts
////type [|{| "isWriteAccess": true, "isDefinition": true |}T|] = number;
-////export = [|T|];
+////[|export|] = [|T|];
// @Filename: /b.ts
////import [|{| "isWriteAccess": true, "isDefinition": true |}T|] = require("[|./a|]");
-const [r0, r1, r2, r3] = test.ranges();
-const mod = { definition: 'module "/a"', ranges: [r3] };
-const a = { definition: "type T = number", ranges: [r0, r1] };
-const b = { definition: '(alias) type T = number\nimport T = require("./a")', ranges: [r2] };
-verify.referenceGroups([r0, r1], [a, b]);
-verify.referenceGroups(r2, [b, a]);
-verify.referenceGroups(r3, [mod, a, b]);
+const [r0, r1, r2, r3, r4] = test.ranges();
+const mod = { definition: 'module "/a"', ranges: [r4, r1] };
+const a = { definition: "type T = number", ranges: [r0, r2] };
+const b = { definition: '(alias) type T = number\nimport T = require("./a")', ranges: [r3] };
+verify.referenceGroups([r0, r2], [a, b]);
+verify.referenceGroups(r3, [b, a]);
+verify.referenceGroups(r4, [mod, a, b]);
+verify.referenceGroups(r1, [mod]);
diff --git a/tests/cases/fourslash/findAllRefsImportEqualsJsonFile.ts b/tests/cases/fourslash/findAllRefsImportEqualsJsonFile.ts
new file mode 100644
index 00000000000..3c3c0dbb2e4
--- /dev/null
+++ b/tests/cases/fourslash/findAllRefsImportEqualsJsonFile.ts
@@ -0,0 +1,24 @@
+///
+
+// @allowJs: true
+// @checkJs: true
+// @resolveJsonModule: true
+
+// @Filename: /a.ts
+////import [|{| "isWriteAccess": true, "isDefinition": true |}j|] = require("[|./j.json|]");
+////[|j|];
+
+// @Filename: /b.js
+////const [|{| "isWriteAccess": true, "isDefinition": true |}j|] = require("[|./j.json|]");
+////[|j|];
+
+// @Filename: /j.json
+////[|{ "x": 0 }|]
+
+verify.noErrors();
+
+const [r0, r1, r2, r3, r4, r5, r6] = test.ranges();
+verify.singleReferenceGroup('import j = require("./j.json")', [r0, r2]);
+verify.referenceGroups([r1, r4], [{ definition: 'module "/j"', ranges: [r1, r4, r6] }]);
+verify.singleReferenceGroup('const j: {\n "x": number;\n}', [r3, r5]);
+verify.referenceGroups(r6, undefined);
diff --git a/tests/cases/fourslash/findAllRefsModuleDotExports.ts b/tests/cases/fourslash/findAllRefsModuleDotExports.ts
new file mode 100644
index 00000000000..bc1bd705c2f
--- /dev/null
+++ b/tests/cases/fourslash/findAllRefsModuleDotExports.ts
@@ -0,0 +1,11 @@
+///
+
+// @allowJs: true
+
+// @Filename: /a.js
+////const b = require("[|./b|]");
+
+// @Filename: /b.js
+////[|module|].exports = 0;
+
+verify.singleReferenceGroup('module "/b"')
diff --git a/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts b/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts
index 7fe0696f952..496fa8a9d3b 100644
--- a/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts
+++ b/tests/cases/fourslash/findAllRefs_importType_exportEquals.ts
@@ -5,7 +5,7 @@
////namespace [|{| "isWriteAccess": true, "isDefinition": true |}T|] {
//// export type U = string;
////}
-////export = [|T|];
+////[|export|] = [|T|];
// @Filename: /b.ts
////const x: import("[|./[|a|]|]") = 0;
@@ -13,14 +13,13 @@
verify.noErrors();
-const [r0, r1, r2, r3, r3b, r4, r4b] = test.ranges();
+const [r0, r1, rExport, r2, r3, r3b, r4, r4b] = test.ranges();
verify.referenceGroups(r0, [{ definition: "type T = number\nnamespace T", ranges: [r0, r2, r3] }]);
verify.referenceGroups(r1, [{ definition: "namespace T", ranges: [r1, r2] }]);
-verify.referenceGroups(r2, [{ definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] }]);
-verify.referenceGroups([r3, r4], [
- { definition: 'module "/a"', ranges: [r4] },
- { definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] },
-]);
+const t: FourSlashInterface.ReferenceGroup = { definition: "type T = number\nnamespace T", ranges: [r0, r1, r2, r3] };
+verify.referenceGroups(r2, [t]);
+verify.referenceGroups([r3, r4], [{ definition: 'module "/a"', ranges: [r4, rExport] }, t]);
+verify.referenceGroups(rExport, [{ definition: 'module "/a"', ranges: [r3, r4, rExport] }]);
verify.renameLocations(r0, [r0, r2]);
verify.renameLocations(r1, [r1, r2]);
diff --git a/tests/cases/fourslash/findAllRefs_importType_js.ts b/tests/cases/fourslash/findAllRefs_importType_js.ts
index 863ee05b12f..b1f612c8e45 100644
--- a/tests/cases/fourslash/findAllRefs_importType_js.ts
+++ b/tests/cases/fourslash/findAllRefs_importType_js.ts
@@ -4,7 +4,7 @@
// @checkJs: true
// @Filename: /a.js
-////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}C|] {};
+////[|module|].exports = class [|{| "isWriteAccess": true, "isDefinition": true |}C|] {};
////module.exports.[|{| "isWriteAccess": true, "isDefinition": true |}D|] = class [|{| "isWriteAccess": true, "isDefinition": true |}D|] {};
// @Filename: /b.js
@@ -17,7 +17,8 @@ verify.noErrors();
// TODO: GH#24025
-const [r0, r1, r2, r3, r4, r5] = test.ranges();
+const [rModule, r0, r1, r2, r3, r4, r5] = test.ranges();
+verify.referenceGroups(rModule, [{ definition: 'module "/a"', ranges: [r3, r4, rModule] }]);
verify.referenceGroups(r0, [
{ definition: "(local class) C", ranges: [r0] },
// TODO: This definition is really ugly
@@ -31,7 +32,7 @@ verify.referenceGroups(r2, [
{ definition: "class D\n(property) D: typeof D", ranges: [r5] },
]);
verify.referenceGroups([r3, r4], [
- { definition: 'module "/a"', ranges: [r4] },
+ { definition: 'module "/a"', ranges: [r4, rModule] },
{ definition: "(local class) C", ranges: [r0] },
{ definition: "(alias) (local class) export=\nimport export=", ranges: [r3] },
]);
diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts
index ddf55fb41b5..b6df330b85c 100644
--- a/tests/cases/fourslash/fourslash.ts
+++ b/tests/cases/fourslash/fourslash.ts
@@ -231,7 +231,7 @@ declare namespace FourSlashInterface {
* For each of starts, asserts the ranges that are referenced from there.
* This uses the 'findReferences' command instead of 'getReferencesAtPosition', so references are grouped by their definition.
*/
- referenceGroups(starts: ArrayOrSingle | ArrayOrSingle, parts: Array<{ definition: ReferencesDefinition, ranges: Range[] }>): void;
+ referenceGroups(starts: ArrayOrSingle | ArrayOrSingle, parts: ReadonlyArray): void;
singleReferenceGroup(definition: ReferencesDefinition, ranges?: Range[]): void;
rangesAreOccurrences(isWriteAccess?: boolean): void;
rangesWithSameTextAreRenameLocations(): void;
@@ -487,6 +487,10 @@ declare namespace FourSlashInterface {
};
}
+ interface ReferenceGroup {
+ readonly definition: ReferencesDefinition;
+ readonly ranges: ReadonlyArray;
+ }
type ReferencesDefinition = string | {
text: string;
range: Range;