Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/platform/parser/test/node/getStructure.ts.spec.ts
13405 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
import { outdent } from 'outdent';
7
import { afterAll, describe, expect, it } from 'vitest';
8
import { resolve } from '../../../../util/vs/base/common/path';
9
import { _dispose } from '../../node/parserImpl';
10
import { WASMLanguage } from '../../node/treeSitterLanguages';
11
import { fromFixture, srcWithAnnotatedStructure } from './getStructure.util';
12
13
describe('getStructure - typescript', () => {
14
15
afterAll(() => _dispose());
16
17
function tsSrcWithStructure(source: string) {
18
return srcWithAnnotatedStructure(WASMLanguage.TypeScript, source);
19
}
20
21
it('`export` keyword should not be visible', async () => {
22
const source = outdent`
23
export function add(a, b) {
24
return a + b;
25
}
26
27
function subtract(a, b) {
28
return a - b;
29
}
30
`;
31
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
32
"<FUNCTION_DECLARATION>export function add(a, b) {
33
<RETURN_STATEMENT> return a + b;
34
</RETURN_STATEMENT>}
35
</FUNCTION_DECLARATION><FUNCTION_DECLARATION-1>
36
function subtract(a, b) {
37
<RETURN_STATEMENT-1> return a - b;
38
</RETURN_STATEMENT-1>}</FUNCTION_DECLARATION-1>"
39
`);
40
});
41
42
it('declarations with comments', async () => {
43
const source = outdent`
44
class C {
45
foo: string; // my comment
46
}`;
47
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
48
"<CLASS_DECLARATION>class C {
49
<PUBLIC_FIELD_DEFINITION> foo: string; // my comment
50
</PUBLIC_FIELD_DEFINITION>}</CLASS_DECLARATION>"
51
`);
52
});
53
54
it('handling line comments', async () => {
55
const source = outdent`
56
// Example usage
57
console.log(farewell("Alice")); // Output: Hello, Alice!
58
console.log(farewell("Bob", "Hi")); // Output: Hi, Bob!
59
console.log(multiply(5, 1, 3)); // Output: 15
60
// Updated identity function to accept only string type
61
console.log(identityString("Hello")); // Output: Hello
62
// Removed the previous identity function call for number type
63
// console.log(identity<number>(42)); // Output: 42
64
console.log(identityString("TypeScript")); // Output: TypeScript
65
`;
66
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
67
"<COMMENT>// Example usage
68
</COMMENT><EXPRESSION_STATEMENT>console.log(farewell("Alice")); // Output: Hello, Alice!
69
</EXPRESSION_STATEMENT><EXPRESSION_STATEMENT-1>console.log(farewell("Bob", "Hi")); // Output: Hi, Bob!
70
</EXPRESSION_STATEMENT-1><EXPRESSION_STATEMENT-2>console.log(multiply(5, 1, 3)); // Output: 15
71
</EXPRESSION_STATEMENT-2><COMMENT-1>// Updated identity function to accept only string type
72
</COMMENT-1><EXPRESSION_STATEMENT-3>console.log(identityString("Hello")); // Output: Hello
73
</EXPRESSION_STATEMENT-3><COMMENT-2>// Removed the previous identity function call for number type
74
</COMMENT-2><COMMENT-3>// console.log(identity<number>(42)); // Output: 42
75
</COMMENT-3><EXPRESSION_STATEMENT-4>console.log(identityString("TypeScript")); // Output: TypeScript</EXPRESSION_STATEMENT-4>"
76
`);
77
});
78
79
80
describe('if-else statements', () => {
81
82
it(`capture within statement blocks`, async () => {
83
const source = outdent`
84
if (true) {
85
foo;
86
} else {
87
bar;
88
}
89
`;
90
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
91
"<IF_STATEMENT>if (true) {
92
<EXPRESSION_STATEMENT> foo;
93
</EXPRESSION_STATEMENT>} else {
94
<EXPRESSION_STATEMENT-1> bar;
95
</EXPRESSION_STATEMENT-1>}</IF_STATEMENT>"
96
`);
97
});
98
99
it(`don't capture consequence in: if (cond) statement`, async () => {
100
const source = outdent`
101
if (true)
102
foo;
103
else
104
bar;
105
`;
106
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
107
"<IF_STATEMENT>if (true)
108
foo;
109
else
110
bar;</IF_STATEMENT>"
111
`);
112
});
113
});
114
115
it('class declarations', async () => {
116
const source = outdent`
117
abstract class Animal {
118
abstract makeSound(): void;
119
move(): void {
120
console.log("roaming the earth...");
121
}
122
}
123
class Bear extends Animal {
124
constructor(){
125
super();
126
}
127
override makeSound(): void {
128
console.log("roar");
129
}
130
}
131
`;
132
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
133
"<ABSTRACT_CLASS_DECLARATION>abstract class Animal {
134
<ABSTRACT_METHOD_SIGNATURE> abstract makeSound(): void;
135
</ABSTRACT_METHOD_SIGNATURE><METHOD_DEFINITION> move(): void {
136
<EXPRESSION_STATEMENT> console.log("roaming the earth...");
137
</EXPRESSION_STATEMENT> }
138
</METHOD_DEFINITION>}
139
</ABSTRACT_CLASS_DECLARATION><CLASS_DECLARATION>class Bear extends Animal {
140
<CONSTRUCTOR> constructor(){
141
<EXPRESSION_STATEMENT-1> super();
142
</EXPRESSION_STATEMENT-1> }
143
</CONSTRUCTOR><METHOD_DEFINITION-1> override makeSound(): void {
144
<EXPRESSION_STATEMENT-2> console.log("roar");
145
</EXPRESSION_STATEMENT-2> }
146
</METHOD_DEFINITION-1>}</CLASS_DECLARATION>"
147
`);
148
});
149
150
it('from tree-sitter repo', async () => {
151
const source = outdent`
152
declare module Foo {
153
break;
154
continue;
155
debugger;
156
do { } while (true);
157
for (x in null) { }
158
for (;;) { }
159
if (true) { } else { }
160
1;
161
return;
162
switch (x) {
163
case 1:
164
break;
165
default:
166
break;
167
}
168
throw "hello";
169
try { }
170
catch (e) { }
171
finally { }
172
}
173
`;
174
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
175
"<MODULE>declare module Foo {
176
<BREAK_STATEMENT> break;
177
</BREAK_STATEMENT><CONTINUE_STATEMENT> continue;
178
</CONTINUE_STATEMENT><DEBUGGER_STATEMENT> debugger;
179
</DEBUGGER_STATEMENT><DO_STATEMENT> do { } while (true);
180
</DO_STATEMENT><FOR_IN_STATEMENT> for (x in null) { }
181
</FOR_IN_STATEMENT><FOR_STATEMENT> for (;;) { }
182
</FOR_STATEMENT><IF_STATEMENT> if (true) { } else { }
183
</IF_STATEMENT><EXPRESSION_STATEMENT> 1;
184
</EXPRESSION_STATEMENT><RETURN_STATEMENT> return;
185
</RETURN_STATEMENT><SWITCH_STATEMENT> switch (x) {
186
<SWITCH_CASE> case 1:
187
<BREAK_STATEMENT-1> break;</BREAK_STATEMENT-1>
188
</SWITCH_CASE> default:
189
<BREAK_STATEMENT-2> break;</BREAK_STATEMENT-2>
190
}
191
</SWITCH_STATEMENT><THROW_STATEMENT> throw "hello";
192
</THROW_STATEMENT><TRY_STATEMENT> try { }
193
catch (e) { }
194
finally { }
195
</TRY_STATEMENT>}</MODULE>"
196
`);
197
});
198
199
it('issue #5755: inline edits go outside the selection', async () => {
200
const source = await fromFixture('vscode.proposed.chatParticipantAdditions.d.ts');
201
const fileSnapshot = resolve(__dirname, 'fixtures', `vscode.proposed.chatParticipantAdditions-annotated.d.ts.txt`);
202
await expect(await tsSrcWithStructure(source)).toMatchFileSnapshot(fileSnapshot);
203
});
204
205
it('issue #5755: inline interfaces', async () => {
206
const source = outdent`
207
interface X {
208
doIt(): { x: boolean };
209
y: { make(): void };
210
}
211
`;
212
expect(await tsSrcWithStructure(source)).toMatchInlineSnapshot(`
213
"<INTERFACE_DECLARATION>interface X {
214
<METHOD_SIGNATURE> doIt(): { x: boolean };
215
</METHOD_SIGNATURE><PROPERTY_SIGNATURE> y: { make(): void };
216
</PROPERTY_SIGNATURE>}</INTERFACE_DECLARATION>"
217
`);
218
});
219
220
describe('handling braces correctly', () => {
221
it('if-else chain', async () => {
222
const source = outdent`
223
function getFirstBracketBefore(node: AstNode, nodeOffsetStart: Length, nodeOffsetEnd: Length, position: Length): IFoundBracket | null {
224
if (node.kind === AstNodeKind.List || node.kind === AstNodeKind.Pair) {
225
const lengths: { nodeOffsetStart: Length; nodeOffsetEnd: Length }[] = [];
226
for (const child of node.children) {
227
nodeOffsetEnd = lengthAdd(nodeOffsetStart, child.length);
228
lengths.push({ nodeOffsetStart, nodeOffsetEnd });
229
nodeOffsetStart = nodeOffsetEnd;
230
}
231
for (let i = lengths.length - 1; i >= 0; i--) {
232
const { nodeOffsetStart, nodeOffsetEnd } = lengths[i];
233
if (lengthLessThan(nodeOffsetStart, position)) {
234
const result = getFirstBracketBefore(node.children[i], nodeOffsetStart, nodeOffsetEnd, position);
235
if (result) {
236
return result;
237
}
238
}
239
}
240
return null;
241
} else if (node.kind === AstNodeKind.UnexpectedClosingBracket) {
242
return null;
243
} else if (node.kind === AstNodeKind.Bracket) {
244
const range = lengthsToRange(nodeOffsetStart, nodeOffsetEnd);
245
return {
246
bracketInfo: node.bracketInfo,
247
range
248
};
249
}
250
return null;
251
}
252
`;
253
expect(await tsSrcWithStructure(source)).toMatchSnapshot();
254
});
255
});
256
});
257
258