Support finding references at module in module.exports = or export in export = (#28221)

* Support finding references at `module` in `module.exports =` or `export` in `export =`

* Add json test
This commit is contained in:
Andy 2018-11-09 09:38:45 -08:00 committed by GitHub
parent 69c61cd166
commit aaf1d8055b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 82 additions and 19 deletions

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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]);

View file

@ -0,0 +1,24 @@
/// <reference path='fourslash.ts' />
// @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);

View file

@ -0,0 +1,11 @@
/// <reference path='fourslash.ts' />
// @allowJs: true
// @Filename: /a.js
////const b = require("[|./b|]");
// @Filename: /b.js
////[|module|].exports = 0;
verify.singleReferenceGroup('module "/b"')

View file

@ -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]);

View file

@ -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] },
]);

View file

@ -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<string> | ArrayOrSingle<Range>, parts: Array<{ definition: ReferencesDefinition, ranges: Range[] }>): void;
referenceGroups(starts: ArrayOrSingle<string> | ArrayOrSingle<Range>, parts: ReadonlyArray<ReferenceGroup>): 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<Range>;
}
type ReferencesDefinition = string | {
text: string;
range: Range;