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