Skip to content

Commit 33a6509

Browse files
sisisinrbuckton
authored andcommitted
Fixes export destructured variables reference (#32007)
* Add basic test for current behavior * Fixes getting destructured variables references(#31922) * Add test case that renames destructured property * Fixes missing nested object destrucuturing variable references
1 parent c1e0db7 commit 33a6509

File tree

5 files changed

+206
-24
lines changed

5 files changed

+206
-24
lines changed

src/services/importTracker.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -577,10 +577,10 @@ namespace ts.FindAllReferences {
577577
// If a reference is a class expression, the exported node would be its parent.
578578
// If a reference is a variable declaration, the exported node would be the variable statement.
579579
function getExportNode(parent: Node, node: Node): Node | undefined {
580-
if (parent.kind === SyntaxKind.VariableDeclaration) {
581-
const p = parent as VariableDeclaration;
582-
return p.name !== node ? undefined :
583-
p.parent.kind === SyntaxKind.CatchClause ? undefined : p.parent.parent.kind === SyntaxKind.VariableStatement ? p.parent.parent : undefined;
580+
const declaration = isVariableDeclaration(parent) ? parent : isBindingElement(parent) ? walkUpBindingElementsAndPatterns(parent) : undefined;
581+
if (declaration) {
582+
return (parent as VariableDeclaration | BindingElement).name !== node ? undefined :
583+
isCatchClause(declaration.parent) ? undefined : isVariableStatement(declaration.parent.parent) ? declaration.parent.parent : undefined;
584584
}
585585
else {
586586
return parent;

src/testRunner/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
"unittests/tsserver/formatSettings.ts",
132132
"unittests/tsserver/getApplicableRefactors.ts",
133133
"unittests/tsserver/getEditsForFileRename.ts",
134+
"unittests/tsserver/getExportReferences.ts",
134135
"unittests/tsserver/importHelpers.ts",
135136
"unittests/tsserver/inferredProjects.ts",
136137
"unittests/tsserver/languageService.ts",

src/testRunner/unittests/tsserver/declarationFileMaps.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
namespace ts.projectSystem {
2-
interface DocumentSpanFromSubstring {
3-
file: File;
4-
text: string;
5-
options?: SpanFromSubstringOptions;
6-
contextText?: string;
7-
contextOptions?: SpanFromSubstringOptions;
8-
}
92
function documentSpanFromSubstring({ file, text, contextText, options, contextOptions }: DocumentSpanFromSubstring): DocumentSpan {
103
const contextSpan = contextText !== undefined ? documentSpanFromSubstring({ file, text: contextText, options: contextOptions }) : undefined;
114
return {
@@ -19,19 +12,6 @@ namespace ts.projectSystem {
1912
return documentSpanFromSubstring(input);
2013
}
2114

22-
interface MakeReferenceItem extends DocumentSpanFromSubstring {
23-
isDefinition: boolean;
24-
lineText: string;
25-
}
26-
function makeReferenceItem({ isDefinition, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
27-
return {
28-
...protocolFileSpanWithContextFromSubstring(rest),
29-
isDefinition,
30-
isWriteAccess: isDefinition,
31-
lineText,
32-
};
33-
}
34-
3515
interface MakeReferenceEntry extends DocumentSpanFromSubstring {
3616
isDefinition: boolean;
3717
}
Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
namespace ts.projectSystem {
2+
describe("unittests:: tsserver:: getExportReferences", () => {
3+
const exportVariable = "export const value = 0;";
4+
const exportArrayDestructured = "export const [valueA, valueB] = [0, 1];";
5+
const exportObjectDestructured = "export const { valueC, valueD: renamedD } = { valueC: 0, valueD: 1 };";
6+
const exportNestedObject = "export const { nest: [valueE, { valueF }] } = { nest: [0, { valueF: 1 }] };";
7+
8+
const mainTs: File = {
9+
path: "/main.ts",
10+
content: 'import { value, valueA, valueB, valueC, renamedD, valueE, valueF } from "./mod";',
11+
};
12+
const modTs: File = {
13+
path: "/mod.ts",
14+
content: `${exportVariable}
15+
${exportArrayDestructured}
16+
${exportObjectDestructured}
17+
${exportNestedObject}
18+
`,
19+
};
20+
const tsconfig: File = {
21+
path: "/tsconfig.json",
22+
content: "{}",
23+
};
24+
25+
function makeSampleSession() {
26+
const host = createServerHost([mainTs, modTs, tsconfig]);
27+
const session = createSession(host);
28+
openFilesForSession([mainTs, modTs], session);
29+
return session;
30+
}
31+
32+
const referenceMainTs = (mainTs: File, text: string): protocol.ReferencesResponseItem =>
33+
makeReferenceItem({
34+
file: mainTs,
35+
isDefinition: true,
36+
lineText: mainTs.content,
37+
contextText: mainTs.content,
38+
text,
39+
});
40+
41+
const referenceModTs = (
42+
texts: { text: string; lineText: string; contextText?: string },
43+
override: Partial<MakeReferenceItem> = {},
44+
): protocol.ReferencesResponseItem =>
45+
makeReferenceItem({
46+
file: modTs,
47+
isDefinition: true,
48+
...texts,
49+
...override,
50+
});
51+
52+
it("should get const variable declaration references", () => {
53+
const session = makeSampleSession();
54+
55+
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
56+
session,
57+
protocol.CommandTypes.References,
58+
protocolFileLocationFromSubstring(modTs, "value"),
59+
);
60+
61+
const expectResponse = {
62+
refs: [
63+
referenceModTs({ text: "value", lineText: exportVariable, contextText: exportVariable }),
64+
referenceMainTs(mainTs, "value"),
65+
],
66+
symbolDisplayString: "const value: 0",
67+
symbolName: "value",
68+
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "value").offset,
69+
};
70+
71+
assert.deepEqual(response, expectResponse);
72+
});
73+
74+
it("should get array destructuring declaration references", () => {
75+
const session = makeSampleSession();
76+
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
77+
session,
78+
protocol.CommandTypes.References,
79+
protocolFileLocationFromSubstring(modTs, "valueA"),
80+
);
81+
82+
const expectResponse = {
83+
refs: [
84+
referenceModTs({
85+
text: "valueA",
86+
lineText: exportArrayDestructured,
87+
contextText: exportArrayDestructured,
88+
}),
89+
referenceMainTs(mainTs, "valueA"),
90+
],
91+
symbolDisplayString: "const valueA: number",
92+
symbolName: "valueA",
93+
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueA").offset,
94+
};
95+
96+
assert.deepEqual(response, expectResponse);
97+
});
98+
99+
it("should get object destructuring declaration references", () => {
100+
const session = makeSampleSession();
101+
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
102+
session,
103+
protocol.CommandTypes.References,
104+
protocolFileLocationFromSubstring(modTs, "valueC"),
105+
);
106+
const expectResponse = {
107+
refs: [
108+
referenceModTs({
109+
text: "valueC",
110+
lineText: exportObjectDestructured,
111+
contextText: exportObjectDestructured,
112+
}),
113+
referenceMainTs(mainTs, "valueC"),
114+
referenceModTs(
115+
{ text: "valueC", lineText: exportObjectDestructured, contextText: "valueC: 0" },
116+
{ options: { index: 1 } },
117+
),
118+
],
119+
symbolDisplayString: "const valueC: number",
120+
symbolName: "valueC",
121+
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueC").offset,
122+
};
123+
124+
assert.deepEqual(response, expectResponse);
125+
});
126+
127+
it("should get object declaration references that renames destructured property", () => {
128+
const session = makeSampleSession();
129+
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
130+
session,
131+
protocol.CommandTypes.References,
132+
protocolFileLocationFromSubstring(modTs, "renamedD"),
133+
);
134+
135+
const expectResponse = {
136+
refs: [
137+
referenceModTs({
138+
text: "renamedD",
139+
lineText: exportObjectDestructured,
140+
contextText: exportObjectDestructured,
141+
}),
142+
referenceMainTs(mainTs, "renamedD"),
143+
],
144+
symbolDisplayString: "const renamedD: number",
145+
symbolName: "renamedD",
146+
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "renamedD").offset,
147+
};
148+
149+
assert.deepEqual(response, expectResponse);
150+
});
151+
152+
it("should get nested object declaration references", () => {
153+
const session = makeSampleSession();
154+
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(
155+
session,
156+
protocol.CommandTypes.References,
157+
protocolFileLocationFromSubstring(modTs, "valueF"),
158+
);
159+
160+
const expectResponse = {
161+
refs: [
162+
referenceModTs({
163+
text: "valueF",
164+
lineText: exportNestedObject,
165+
contextText: exportNestedObject,
166+
}),
167+
referenceMainTs(mainTs, "valueF"),
168+
referenceModTs(
169+
{
170+
text: "valueF",
171+
lineText: exportNestedObject,
172+
contextText: "valueF: 1",
173+
},
174+
{ options: { index: 1 } },
175+
),
176+
],
177+
symbolDisplayString: "const valueF: number",
178+
symbolName: "valueF",
179+
symbolStartOffset: protocolLocationFromSubstring(modTs.content, "valueF").offset,
180+
};
181+
182+
assert.deepEqual(response, expectResponse);
183+
});
184+
});
185+
}

src/testRunner/unittests/tsserver/helpers.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,8 @@ namespace ts.projectSystem {
519519
file: File;
520520
text: string;
521521
options?: SpanFromSubstringOptions;
522+
contextText?: string;
523+
contextOptions?: SpanFromSubstringOptions;
522524
}
523525
export function protocolFileSpanFromSubstring({ file, text, options }: DocumentSpanFromSubstring): protocol.FileSpan {
524526
return { file: file.path, ...protocolTextSpanFromSubstring(file.content, text, options) };
@@ -727,4 +729,18 @@ namespace ts.projectSystem {
727729
assert.strictEqual(outputs.length, index + 1, JSON.stringify(outputs));
728730
}
729731
}
732+
733+
export interface MakeReferenceItem extends DocumentSpanFromSubstring {
734+
isDefinition: boolean;
735+
lineText: string;
736+
}
737+
738+
export function makeReferenceItem({ isDefinition, lineText, ...rest }: MakeReferenceItem): protocol.ReferencesResponseItem {
739+
return {
740+
...protocolFileSpanWithContextFromSubstring(rest),
741+
isDefinition,
742+
isWriteAccess: isDefinition,
743+
lineText,
744+
};
745+
}
730746
}

0 commit comments

Comments
 (0)