Skip to content

Commit 9472a40

Browse files
committed
Add logic for python and go
1 parent 74deaa6 commit 9472a40

File tree

6 files changed

+4758
-2176
lines changed

6 files changed

+4758
-2176
lines changed

package-lock.json

Lines changed: 3602 additions & 2174 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,10 @@
7777
"openai": "^4.73.1",
7878
"ora": "^8.2.0",
7979
"prettier": "3.3.3",
80-
"tree-sitter": "^0.21.1",
81-
"tree-sitter-typescript": "^0.23.2",
80+
"tree-sitter": "^0.21.0",
81+
"tree-sitter-go": "^0.21.2",
82+
"tree-sitter-python": "^0.21.0",
83+
"tree-sitter-typescript": "^0.21.2",
8284
"typescript": "~5.6.2",
8385
"vitest": "^3.0.9",
8486
"ws": "^8.18.0",
Lines changed: 301 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,301 @@
1+
import { describe, it, expect } from "vitest";
2+
import { GoSymbolExtractor } from "./go-symbol-extractor";
3+
import { FunctionSymbol, TypeSymbol } from "./types";
4+
5+
const extractor = new GoSymbolExtractor();
6+
7+
function extractFunctionSymbols(code: string): FunctionSymbol[] {
8+
const symbols = extractor["extractFromFile"]("test.go", code);
9+
return symbols.filter((s) => s.type === "function") as FunctionSymbol[];
10+
}
11+
12+
function extractTypeSymbols(code: string): TypeSymbol[] {
13+
const symbols = extractor["extractFromFile"]("test.go", code);
14+
return symbols.filter((s) => s.type === "type") as TypeSymbol[];
15+
}
16+
17+
describe("go-symbol-extractor", () => {
18+
describe("FunctionSymbol", () => {
19+
it("should extract a simple function", () => {
20+
const code = `
21+
package main
22+
23+
func Hello() {
24+
}
25+
`;
26+
const [symbol] = extractFunctionSymbols(code);
27+
expect(symbol).toBeDefined();
28+
expect(symbol?.name).toBe("Hello");
29+
expect(symbol?.type).toBe("function");
30+
expect(symbol?.meta.returnType).toBe("void");
31+
expect(symbol?.meta.parameters).toHaveLength(0);
32+
expect(symbol?.meta.isAsync).toBe(false);
33+
expect(symbol?.meta.isStatic).toBe(true);
34+
});
35+
36+
it("should extract a function with parameters", () => {
37+
const code = `
38+
package main
39+
40+
func Add(a int, b int) int {
41+
return a + b
42+
}
43+
`;
44+
const [symbol] = extractFunctionSymbols(code);
45+
expect(symbol).toBeDefined();
46+
expect(symbol?.name).toBe("Add");
47+
expect(symbol?.type).toBe("function");
48+
expect(symbol?.meta.returnType).toBe("int");
49+
expect(symbol?.meta.parameters).toHaveLength(2);
50+
expect(symbol?.meta.parameters).toEqual([
51+
{
52+
name: "a",
53+
type: "int",
54+
optional: false,
55+
},
56+
{
57+
name: "b",
58+
type: "int",
59+
optional: false,
60+
},
61+
]);
62+
});
63+
64+
it("should extract a function with multiple return types", () => {
65+
const code = `
66+
package main
67+
68+
func Divide(a int, b int) (int, error) {
69+
if b == 0 {
70+
return 0, errors.New("division by zero")
71+
}
72+
return a / b, nil
73+
}
74+
`;
75+
const [symbol] = extractFunctionSymbols(code);
76+
expect(symbol).toBeDefined();
77+
expect(symbol?.name).toBe("Divide");
78+
expect(symbol?.type).toBe("function");
79+
expect(symbol?.meta.returnType).toBe("(int, error)");
80+
expect(symbol?.meta.parameters).toHaveLength(2);
81+
});
82+
83+
it("should extract a function with pointer parameters", () => {
84+
const code = `
85+
package main
86+
87+
func Process(data *string) *int {
88+
return nil
89+
}
90+
`;
91+
const [symbol] = extractFunctionSymbols(code);
92+
expect(symbol).toBeDefined();
93+
expect(symbol?.name).toBe("Process");
94+
expect(symbol?.type).toBe("function");
95+
expect(symbol?.meta.returnType).toBe("*int");
96+
expect(symbol?.meta.parameters).toHaveLength(1);
97+
expect(symbol?.meta.parameters[0]).toEqual({
98+
name: "data",
99+
type: "*string",
100+
optional: false,
101+
});
102+
});
103+
104+
it("should extract a method declaration", () => {
105+
const code = `
106+
package main
107+
108+
type Person struct {
109+
Name string
110+
}
111+
112+
func (p *Person) GetName() string {
113+
return p.Name
114+
}
115+
`;
116+
const [symbol] = extractFunctionSymbols(code);
117+
expect(symbol).toBeDefined();
118+
expect(symbol?.name).toBe("GetName");
119+
expect(symbol?.type).toBe("function");
120+
expect(symbol?.meta.returnType).toBe("string");
121+
expect(symbol?.meta.isStatic).toBe(false); // methods are not static
122+
});
123+
124+
it("should not extract unexported functions", () => {
125+
const code = `
126+
package main
127+
128+
func hello() {
129+
}
130+
131+
func Hello() {
132+
}
133+
`;
134+
const symbols = extractFunctionSymbols(code);
135+
expect(symbols).toHaveLength(1);
136+
expect(symbols[0]?.name).toBe("Hello");
137+
});
138+
139+
it("should extract multiple functions", () => {
140+
const code = `
141+
package main
142+
143+
func First() {
144+
}
145+
146+
func Second() {
147+
}
148+
149+
func Third() {
150+
}
151+
`;
152+
const symbols = extractFunctionSymbols(code);
153+
expect(symbols).toHaveLength(3);
154+
expect(symbols[0]?.name).toBe("First");
155+
expect(symbols[1]?.name).toBe("Second");
156+
expect(symbols[2]?.name).toBe("Third");
157+
});
158+
});
159+
160+
describe("TypeSymbol", () => {
161+
it("should extract a simple type alias", () => {
162+
const code = `
163+
package main
164+
165+
type UserID string
166+
`;
167+
const [symbol] = extractTypeSymbols(code);
168+
expect(symbol).toBeDefined();
169+
expect(symbol?.name).toBe("UserID");
170+
expect(symbol?.type).toBe("type");
171+
expect(symbol?.meta.kind).toBe("alias");
172+
});
173+
174+
it("should extract a struct type", () => {
175+
const code = `
176+
package main
177+
178+
type User struct {
179+
ID int
180+
Name string
181+
}
182+
`;
183+
const [symbol] = extractTypeSymbols(code);
184+
expect(symbol).toBeDefined();
185+
expect(symbol?.name).toBe("User");
186+
expect(symbol?.type).toBe("type");
187+
expect(symbol?.meta.kind).toBe("type");
188+
});
189+
190+
it("should extract an interface type", () => {
191+
const code = `
192+
package main
193+
194+
type Writer interface {
195+
Write([]byte) (int, error)
196+
}
197+
`;
198+
const [symbol] = extractTypeSymbols(code);
199+
expect(symbol).toBeDefined();
200+
expect(symbol?.name).toBe("Writer");
201+
expect(symbol?.type).toBe("type");
202+
expect(symbol?.meta.kind).toBe("interface");
203+
});
204+
205+
it("should extract multiple types", () => {
206+
const code = `
207+
package main
208+
209+
type UserID string
210+
211+
type User struct {
212+
ID UserID
213+
Name string
214+
}
215+
216+
type UserRepo interface {
217+
GetUser(id UserID) (*User, error)
218+
}
219+
`;
220+
const symbols = extractTypeSymbols(code);
221+
expect(symbols).toHaveLength(3);
222+
expect(symbols[0]?.name).toBe("UserID");
223+
expect(symbols[0]?.meta.kind).toBe("alias");
224+
expect(symbols[1]?.name).toBe("User");
225+
expect(symbols[1]?.meta.kind).toBe("type");
226+
expect(symbols[2]?.name).toBe("UserRepo");
227+
expect(symbols[2]?.meta.kind).toBe("interface");
228+
});
229+
230+
it("should not extract unexported types", () => {
231+
const code = `
232+
package main
233+
234+
type userID string
235+
236+
type User struct {
237+
ID userID
238+
Name string
239+
}
240+
`;
241+
const symbols = extractTypeSymbols(code);
242+
expect(symbols).toHaveLength(1);
243+
expect(symbols[0]?.name).toBe("User");
244+
});
245+
246+
it("should extract a type with definition", () => {
247+
const code = `
248+
package main
249+
250+
type Status int
251+
252+
const (
253+
Active Status = iota
254+
Inactive
255+
)
256+
`;
257+
const [symbol] = extractTypeSymbols(code);
258+
expect(symbol).toBeDefined();
259+
expect(symbol?.name).toBe("Status");
260+
expect(symbol?.type).toBe("type");
261+
expect(symbol?.meta.kind).toBe("alias");
262+
expect(symbol?.meta.definition).toContain("type Status int");
263+
});
264+
});
265+
266+
describe("Combined extraction", () => {
267+
it("should extract both functions and types from the same code", () => {
268+
const code = `
269+
package main
270+
271+
type User struct {
272+
ID int
273+
Name string
274+
}
275+
276+
func NewUser(id int, name string) *User {
277+
return &User{ID: id, Name: name}
278+
}
279+
280+
func (u *User) GetName() string {
281+
return u.Name
282+
}
283+
284+
type UserRepo interface {
285+
GetUser(id int) (*User, error)
286+
}
287+
`;
288+
const allSymbols = extractor["extractFromFile"]("test.go", code);
289+
const functions = allSymbols.filter((s) => s.type === "function");
290+
const types = allSymbols.filter((s) => s.type === "type");
291+
292+
expect(functions).toHaveLength(2);
293+
expect(types).toHaveLength(2);
294+
295+
expect(functions[0]?.name).toBe("NewUser");
296+
expect(functions[1]?.name).toBe("GetName");
297+
expect(types[0]?.name).toBe("User");
298+
expect(types[1]?.name).toBe("UserRepo");
299+
});
300+
});
301+
});

0 commit comments

Comments
 (0)