agentmap 0.7.1 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +24 -0
  3. package/dist/cli.js +44 -12
  4. package/dist/cli.js.map +1 -1
  5. package/dist/extract/definitions.js +12 -12
  6. package/dist/extract/definitions.js.map +1 -1
  7. package/dist/extract/definitions.test.js +30 -259
  8. package/dist/extract/definitions.test.js.map +1 -1
  9. package/dist/extract/git-status.d.ts +11 -4
  10. package/dist/extract/git-status.d.ts.map +1 -1
  11. package/dist/extract/git-status.js +21 -16
  12. package/dist/extract/git-status.js.map +1 -1
  13. package/dist/extract/markdown.js +1 -1
  14. package/dist/extract/markdown.test.js +3 -3
  15. package/dist/extract/markdown.test.js.map +1 -1
  16. package/dist/extract/marker.js +1 -1
  17. package/dist/extract/marker.test.js +4 -4
  18. package/dist/extract/marker.test.js.map +1 -1
  19. package/dist/extract/submodules.d.ts +12 -0
  20. package/dist/extract/submodules.d.ts.map +1 -0
  21. package/dist/extract/submodules.js +234 -0
  22. package/dist/extract/submodules.js.map +1 -0
  23. package/dist/extract/submodules.test.d.ts +2 -0
  24. package/dist/extract/submodules.test.d.ts.map +1 -0
  25. package/dist/extract/submodules.test.js +84 -0
  26. package/dist/extract/submodules.test.js.map +1 -0
  27. package/dist/index.d.ts +4 -1
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +10 -9
  30. package/dist/index.js.map +1 -1
  31. package/dist/logger.d.ts +10 -0
  32. package/dist/logger.d.ts.map +1 -0
  33. package/dist/logger.js +41 -0
  34. package/dist/logger.js.map +1 -0
  35. package/dist/map/builder.d.ts +3 -3
  36. package/dist/map/builder.d.ts.map +1 -1
  37. package/dist/map/builder.js +59 -9
  38. package/dist/map/builder.js.map +1 -1
  39. package/dist/map/builder.test.d.ts +2 -0
  40. package/dist/map/builder.test.d.ts.map +1 -0
  41. package/dist/map/builder.test.js +66 -0
  42. package/dist/map/builder.test.js.map +1 -0
  43. package/dist/map/truncate.d.ts +7 -3
  44. package/dist/map/truncate.d.ts.map +1 -1
  45. package/dist/map/truncate.js +90 -9
  46. package/dist/map/truncate.js.map +1 -1
  47. package/dist/map/yaml.d.ts.map +1 -1
  48. package/dist/map/yaml.js +13 -3
  49. package/dist/map/yaml.js.map +1 -1
  50. package/dist/scanner.d.ts +9 -2
  51. package/dist/scanner.d.ts.map +1 -1
  52. package/dist/scanner.js +172 -49
  53. package/dist/scanner.js.map +1 -1
  54. package/dist/scanner.test.d.ts +2 -0
  55. package/dist/scanner.test.d.ts.map +1 -0
  56. package/dist/scanner.test.js +84 -0
  57. package/dist/scanner.test.js.map +1 -0
  58. package/dist/test-helpers/git-test-helpers.d.ts +13 -0
  59. package/dist/test-helpers/git-test-helpers.d.ts.map +1 -0
  60. package/dist/test-helpers/git-test-helpers.js +48 -0
  61. package/dist/test-helpers/git-test-helpers.js.map +1 -0
  62. package/dist/types.d.ts +42 -2
  63. package/dist/types.d.ts.map +1 -1
  64. package/package.json +15 -3
  65. package/src/cli.ts +164 -0
  66. package/src/extract/definitions.test.ts +2040 -0
  67. package/src/extract/definitions.ts +379 -0
  68. package/src/extract/git-status.test.ts +507 -0
  69. package/src/extract/git-status.ts +359 -0
  70. package/src/extract/markdown.test.ts +159 -0
  71. package/src/extract/markdown.ts +202 -0
  72. package/src/extract/marker.test.ts +566 -0
  73. package/src/extract/marker.ts +398 -0
  74. package/src/extract/submodules.test.ts +95 -0
  75. package/src/extract/submodules.ts +269 -0
  76. package/src/extract/utils.ts +27 -0
  77. package/src/index.ts +106 -0
  78. package/src/languages/cpp.ts +129 -0
  79. package/src/languages/go.ts +72 -0
  80. package/src/languages/index.ts +231 -0
  81. package/src/languages/javascript.ts +33 -0
  82. package/src/languages/python.ts +41 -0
  83. package/src/languages/rust.ts +72 -0
  84. package/src/languages/typescript.ts +74 -0
  85. package/src/languages/zig.ts +106 -0
  86. package/src/logger.ts +55 -0
  87. package/src/map/builder.test.ts +72 -0
  88. package/src/map/builder.ts +175 -0
  89. package/src/map/truncate.ts +188 -0
  90. package/src/map/yaml.ts +66 -0
  91. package/src/parser/index.ts +53 -0
  92. package/src/parser/languages.ts +64 -0
  93. package/src/scanner.test.ts +95 -0
  94. package/src/scanner.ts +364 -0
  95. package/src/test-helpers/git-test-helpers.ts +62 -0
  96. package/src/types.ts +191 -0
@@ -0,0 +1,2040 @@
1
+ import { beforeAll, describe, expect, test } from 'bun:test'
2
+ import { parseCode, initParser } from '../parser/index.js'
3
+ import { extractDefinitions } from './definitions.js'
4
+ import type { Language, Definition } from '../types.js'
5
+
6
+ // ============================================================================
7
+ // Setup
8
+ // ============================================================================
9
+
10
+ beforeAll(async () => {
11
+ await initParser()
12
+ })
13
+
14
+ /**
15
+ * Helper to extract definitions from code string
16
+ */
17
+ async function getDefinitions(code: string, language: Language): Promise<Definition[]> {
18
+ const tree = await parseCode(code, language)
19
+ return extractDefinitions(tree.rootNode, language)
20
+ }
21
+
22
+ // ============================================================================
23
+ // TypeScript Tests
24
+ // ============================================================================
25
+
26
+ describe('TypeScript', () => {
27
+ test('large function (>7 lines) is included', async () => {
28
+ const code = `function processData(input: string): string {
29
+ const trimmed = input.trim()
30
+ const upper = trimmed.toUpperCase()
31
+ const parts = upper.split(',')
32
+ const filtered = parts.filter(Boolean)
33
+ const joined = filtered.join('-')
34
+ const result = joined + '!'
35
+ return result
36
+ }`
37
+ const defs = await getDefinitions(code, 'typescript')
38
+ expect(defs).toMatchInlineSnapshot(`
39
+ [
40
+ {
41
+ "endLine": 9,
42
+ "exported": false,
43
+ "line": 1,
44
+ "name": "processData",
45
+ "type": "function",
46
+ },
47
+ ]
48
+ `)
49
+ })
50
+
51
+ test('small function (<=7 lines) is excluded', async () => {
52
+ const code = `function add(a: number, b: number): number {
53
+ return a + b
54
+ }`
55
+ const defs = await getDefinitions(code, 'typescript')
56
+ expect(defs).toMatchInlineSnapshot(`[]`)
57
+ })
58
+
59
+ test('large class is included', async () => {
60
+ const code = `class Calculator {
61
+ private value: number = 0
62
+
63
+ add(n: number): this {
64
+ this.value += n
65
+ return this
66
+ }
67
+
68
+ subtract(n: number): this {
69
+ this.value -= n
70
+ return this
71
+ }
72
+ }`
73
+ const defs = await getDefinitions(code, 'typescript')
74
+ expect(defs).toMatchInlineSnapshot(`
75
+ [
76
+ {
77
+ "endLine": 13,
78
+ "exported": false,
79
+ "line": 1,
80
+ "name": "Calculator",
81
+ "type": "class",
82
+ },
83
+ ]
84
+ `)
85
+ })
86
+
87
+ test('small class is excluded', async () => {
88
+ const code = `class Point {
89
+ x: number
90
+ y: number
91
+ }`
92
+ const defs = await getDefinitions(code, 'typescript')
93
+ expect(defs).toMatchInlineSnapshot(`[]`)
94
+ })
95
+
96
+ test('large arrow function is included', async () => {
97
+ const code = `const processItems = (items: string[]) => {
98
+ const result: string[] = []
99
+ for (const item of items) {
100
+ const processed = item.trim()
101
+ const upper = processed.toUpperCase()
102
+ result.push(upper)
103
+ }
104
+ return result
105
+ }`
106
+ const defs = await getDefinitions(code, 'typescript')
107
+ expect(defs).toMatchInlineSnapshot(`
108
+ [
109
+ {
110
+ "endLine": 9,
111
+ "exported": false,
112
+ "line": 1,
113
+ "name": "processItems",
114
+ "type": "function",
115
+ },
116
+ ]
117
+ `)
118
+ })
119
+
120
+ test('small arrow function is excluded', async () => {
121
+ const code = `const double = (n: number) => n * 2`
122
+ const defs = await getDefinitions(code, 'typescript')
123
+ expect(defs).toMatchInlineSnapshot(`[]`)
124
+ })
125
+
126
+ test('exported const is included', async () => {
127
+ const code = `export const CONFIG = {
128
+ apiUrl: 'https://api.example.com',
129
+ timeout: 5000,
130
+ }`
131
+ const defs = await getDefinitions(code, 'typescript')
132
+ expect(defs).toMatchInlineSnapshot(`
133
+ [
134
+ {
135
+ "endLine": 4,
136
+ "exported": true,
137
+ "line": 1,
138
+ "name": "CONFIG",
139
+ "type": "const",
140
+ },
141
+ ]
142
+ `)
143
+ })
144
+
145
+ test('non-exported const is excluded', async () => {
146
+ const code = `const CONFIG = { timeout: 5000 }`
147
+ const defs = await getDefinitions(code, 'typescript')
148
+ expect(defs).toMatchInlineSnapshot(`[]`)
149
+ })
150
+
151
+ test('interface is included (any size)', async () => {
152
+ const code = `interface User {
153
+ name: string
154
+ age: number
155
+ }`
156
+ const defs = await getDefinitions(code, 'typescript')
157
+ expect(defs).toMatchInlineSnapshot(`[]`)
158
+ })
159
+
160
+ test('type alias is included (any size)', async () => {
161
+ const code = `type Status = 'pending' | 'active' | 'done'`
162
+ const defs = await getDefinitions(code, 'typescript')
163
+ expect(defs).toMatchInlineSnapshot(`[]`)
164
+ })
165
+
166
+ test('enum is included (any size)', async () => {
167
+ const code = `enum Color {
168
+ Red,
169
+ Green,
170
+ Blue,
171
+ }`
172
+ const defs = await getDefinitions(code, 'typescript')
173
+ expect(defs).toMatchInlineSnapshot(`[]`)
174
+ })
175
+
176
+ test('exported function', async () => {
177
+ const code = `export function fetchData(url: string): Promise<Response> {
178
+ const headers = new Headers()
179
+ headers.set('Content-Type', 'application/json')
180
+ const options = { method: 'GET', headers }
181
+ const response = fetch(url, options)
182
+ return response
183
+ }`
184
+ const defs = await getDefinitions(code, 'typescript')
185
+ expect(defs).toMatchInlineSnapshot(`
186
+ [
187
+ {
188
+ "endLine": 7,
189
+ "exported": true,
190
+ "line": 1,
191
+ "name": "fetchData",
192
+ "type": "function",
193
+ },
194
+ ]
195
+ `)
196
+ })
197
+
198
+ test('exported large function', async () => {
199
+ const code = `export function fetchData(url: string): Promise<Response> {
200
+ const headers = new Headers()
201
+ headers.set('Content-Type', 'application/json')
202
+ headers.set('Accept', 'application/json')
203
+ const options = { method: 'GET', headers }
204
+ const response = fetch(url, options)
205
+ return response
206
+ }`
207
+ const defs = await getDefinitions(code, 'typescript')
208
+ expect(defs).toMatchInlineSnapshot(`
209
+ [
210
+ {
211
+ "endLine": 8,
212
+ "exported": true,
213
+ "line": 1,
214
+ "name": "fetchData",
215
+ "type": "function",
216
+ },
217
+ ]
218
+ `)
219
+ })
220
+
221
+ test('async function', async () => {
222
+ const code = `async function loadData(id: string): Promise<Data> {
223
+ const url = buildUrl(id)
224
+ const response = await fetch(url)
225
+ const json = await response.json()
226
+ const validated = validate(json)
227
+ const transformed = transform(validated)
228
+ return transformed
229
+ }`
230
+ const defs = await getDefinitions(code, 'typescript')
231
+ expect(defs).toMatchInlineSnapshot(`
232
+ [
233
+ {
234
+ "endLine": 8,
235
+ "exported": false,
236
+ "line": 1,
237
+ "name": "loadData",
238
+ "type": "function",
239
+ },
240
+ ]
241
+ `)
242
+ })
243
+
244
+ test('generator function', async () => {
245
+ const code = `function* generateSequence(start: number, end: number) {
246
+ let current = start
247
+ while (current <= end) {
248
+ const value = current
249
+ current++
250
+ yield value
251
+ console.log('yielded', value)
252
+ }
253
+ }`
254
+ const defs = await getDefinitions(code, 'typescript')
255
+ expect(defs).toMatchInlineSnapshot(`[]`)
256
+ })
257
+
258
+ test('abstract class', async () => {
259
+ const code = `abstract class BaseProcessor {
260
+ abstract process(input: string): string
261
+
262
+ protected validate(input: string): boolean {
263
+ return input.length > 0
264
+ }
265
+
266
+ protected transform(input: string): string {
267
+ return input.trim()
268
+ }
269
+ }`
270
+ const defs = await getDefinitions(code, 'typescript')
271
+ expect(defs).toMatchInlineSnapshot(`
272
+ [
273
+ {
274
+ "endLine": 11,
275
+ "exported": false,
276
+ "line": 1,
277
+ "name": "BaseProcessor",
278
+ "type": "class",
279
+ },
280
+ ]
281
+ `)
282
+ })
283
+
284
+ test('generic function', async () => {
285
+ const code = `function identity<T>(value: T): T {
286
+ const result = value
287
+ console.log('identity called')
288
+ console.log('value:', result)
289
+ console.log('type:', typeof result)
290
+ console.log('returning...')
291
+ return result
292
+ }`
293
+ const defs = await getDefinitions(code, 'typescript')
294
+ expect(defs).toMatchInlineSnapshot(`
295
+ [
296
+ {
297
+ "endLine": 8,
298
+ "exported": false,
299
+ "line": 1,
300
+ "name": "identity",
301
+ "type": "function",
302
+ },
303
+ ]
304
+ `)
305
+ })
306
+
307
+ test('generic class', async () => {
308
+ const code = `class Container<T> {
309
+ private items: T[] = []
310
+
311
+ add(item: T): void {
312
+ this.items.push(item)
313
+ }
314
+
315
+ get(index: number): T {
316
+ return this.items[index]
317
+ }
318
+
319
+ size(): number {
320
+ return this.items.length
321
+ }
322
+ }`
323
+ const defs = await getDefinitions(code, 'typescript')
324
+ expect(defs).toMatchInlineSnapshot(`
325
+ [
326
+ {
327
+ "endLine": 15,
328
+ "exported": false,
329
+ "line": 1,
330
+ "name": "Container",
331
+ "type": "class",
332
+ },
333
+ ]
334
+ `)
335
+ })
336
+
337
+ test('multiple exports in one line', async () => {
338
+ const code = `export const a = 1, b = 2, c = 3`
339
+ const defs = await getDefinitions(code, 'typescript')
340
+ expect(defs).toMatchInlineSnapshot(`
341
+ [
342
+ {
343
+ "endLine": 1,
344
+ "exported": true,
345
+ "line": 1,
346
+ "name": "a",
347
+ "type": "const",
348
+ },
349
+ {
350
+ "endLine": 1,
351
+ "exported": true,
352
+ "line": 1,
353
+ "name": "b",
354
+ "type": "const",
355
+ },
356
+ {
357
+ "endLine": 1,
358
+ "exported": true,
359
+ "line": 1,
360
+ "name": "c",
361
+ "type": "const",
362
+ },
363
+ ]
364
+ `)
365
+ })
366
+
367
+ test('export default function', async () => {
368
+ const code = `export default function handler(req: Request): Response {
369
+ const body = req.body
370
+ const parsed = JSON.parse(body)
371
+ const validated = validate(parsed)
372
+ const processed = processData(validated)
373
+ const formatted = format(processed)
374
+ const response = JSON.stringify(formatted)
375
+ return new Response(response)
376
+ }`
377
+ const defs = await getDefinitions(code, 'typescript')
378
+ expect(defs).toMatchInlineSnapshot(`
379
+ [
380
+ {
381
+ "endLine": 9,
382
+ "exported": true,
383
+ "line": 1,
384
+ "name": "handler",
385
+ "type": "function",
386
+ },
387
+ ]
388
+ `)
389
+ })
390
+
391
+ test('class with decorators', async () => {
392
+ const code = `@Injectable()
393
+ @Singleton()
394
+ class UserService {
395
+ constructor(private db: Database) {}
396
+
397
+ async findUser(id: string): Promise<User> {
398
+ return this.db.users.find(id)
399
+ }
400
+
401
+ async createUser(data: UserData): Promise<User> {
402
+ return this.db.users.create(data)
403
+ }
404
+ }`
405
+ const defs = await getDefinitions(code, 'typescript')
406
+ expect(defs).toMatchInlineSnapshot(`
407
+ [
408
+ {
409
+ "endLine": 13,
410
+ "exported": false,
411
+ "line": 1,
412
+ "name": "UserService",
413
+ "type": "class",
414
+ },
415
+ ]
416
+ `)
417
+ })
418
+
419
+ test('mixed definitions - filters correctly', async () => {
420
+ const code = `// Small function - excluded
421
+ function util(x: number) {
422
+ return x * 2
423
+ }
424
+
425
+ // Large function - included
426
+ export function processData(input: string): string {
427
+ const step1 = input.trim()
428
+ const step2 = step1.toUpperCase()
429
+ const step3 = step2.split('')
430
+ const step4 = step3.reverse()
431
+ const step5 = step4.join('')
432
+ return step5
433
+ }
434
+
435
+ // Interface - included
436
+ interface Config {
437
+ name: string
438
+ }
439
+
440
+ // Small class - excluded
441
+ class Tiny {
442
+ x = 1
443
+ }
444
+
445
+ // Exported const - included
446
+ export const VERSION = '1.0.0'
447
+
448
+ // Type alias - included
449
+ type ID = string | number`
450
+ const defs = await getDefinitions(code, 'typescript')
451
+ expect(defs).toMatchInlineSnapshot(`
452
+ [
453
+ {
454
+ "endLine": 14,
455
+ "exported": true,
456
+ "line": 7,
457
+ "name": "processData",
458
+ "type": "function",
459
+ },
460
+ {
461
+ "endLine": 27,
462
+ "exported": true,
463
+ "line": 27,
464
+ "name": "VERSION",
465
+ "type": "const",
466
+ },
467
+ ]
468
+ `)
469
+ })
470
+ })
471
+
472
+ // ============================================================================
473
+ // JavaScript Tests
474
+ // ============================================================================
475
+
476
+ describe('JavaScript', () => {
477
+ test('large function', async () => {
478
+ const code = `function buildResponse(data) {
479
+ const headers = { 'Content-Type': 'application/json' }
480
+ const body = JSON.stringify(data)
481
+ const status = 200
482
+ const statusText = 'OK'
483
+ const response = { headers, body, status, statusText }
484
+ return response
485
+ }`
486
+ const defs = await getDefinitions(code, 'javascript')
487
+ expect(defs).toMatchInlineSnapshot(`
488
+ [
489
+ {
490
+ "endLine": 8,
491
+ "exported": false,
492
+ "line": 1,
493
+ "name": "buildResponse",
494
+ "type": "function",
495
+ },
496
+ ]
497
+ `)
498
+ })
499
+
500
+ test('small function', async () => {
501
+ const code = `function add(a, b) {
502
+ return a + b
503
+ }`
504
+ const defs = await getDefinitions(code, 'javascript')
505
+ expect(defs).toMatchInlineSnapshot(`[]`)
506
+ })
507
+
508
+ test('large class', async () => {
509
+ const code = `class EventEmitter {
510
+ constructor() {
511
+ this.events = {}
512
+ }
513
+
514
+ on(event, callback) {
515
+ if (!this.events[event]) {
516
+ this.events[event] = []
517
+ }
518
+ this.events[event].push(callback)
519
+ }
520
+
521
+ emit(event, data) {
522
+ const callbacks = this.events[event]
523
+ if (callbacks) {
524
+ callbacks.forEach(cb => cb(data))
525
+ }
526
+ }
527
+ }`
528
+ const defs = await getDefinitions(code, 'javascript')
529
+ expect(defs).toMatchInlineSnapshot(`
530
+ [
531
+ {
532
+ "endLine": 19,
533
+ "exported": false,
534
+ "line": 1,
535
+ "name": "EventEmitter",
536
+ "type": "class",
537
+ },
538
+ ]
539
+ `)
540
+ })
541
+
542
+ test('IIFE is not extracted', async () => {
543
+ const code = `(function() {
544
+ console.log('init')
545
+ const x = 1
546
+ const y = 2
547
+ const z = 3
548
+ console.log(x, y, z)
549
+ return { x, y, z }
550
+ })()`
551
+ const defs = await getDefinitions(code, 'javascript')
552
+ expect(defs).toMatchInlineSnapshot(`[]`)
553
+ })
554
+
555
+ test('function expression assigned to var', async () => {
556
+ const code = `var processItems = function(items) {
557
+ const result = []
558
+ for (const item of items) {
559
+ const processed = item.trim()
560
+ const upper = processed.toUpperCase()
561
+ result.push(upper)
562
+ }
563
+ return result
564
+ }`
565
+ const defs = await getDefinitions(code, 'javascript')
566
+ expect(defs).toMatchInlineSnapshot(`[]`)
567
+ })
568
+ })
569
+
570
+ // ============================================================================
571
+ // Python Tests
572
+ // ============================================================================
573
+
574
+ describe('Python', () => {
575
+ test('large function', async () => {
576
+ const code = `def process_data(items):
577
+ result = []
578
+ for item in items:
579
+ cleaned = item.strip()
580
+ upper = cleaned.upper()
581
+ parts = upper.split(',')
582
+ result.extend(parts)
583
+ return result`
584
+ const defs = await getDefinitions(code, 'python')
585
+ expect(defs).toMatchInlineSnapshot(`
586
+ [
587
+ {
588
+ "endLine": 8,
589
+ "exported": false,
590
+ "line": 1,
591
+ "name": "process_data",
592
+ "type": "function",
593
+ },
594
+ ]
595
+ `)
596
+ })
597
+
598
+ test('small function', async () => {
599
+ const code = `def add(a, b):
600
+ return a + b`
601
+ const defs = await getDefinitions(code, 'python')
602
+ expect(defs).toMatchInlineSnapshot(`[]`)
603
+ })
604
+
605
+ test('large class', async () => {
606
+ const code = `class DataProcessor:
607
+ def __init__(self, data):
608
+ self.data = data
609
+ self.processed = False
610
+
611
+ def process(self):
612
+ self.data = [x.strip() for x in self.data]
613
+ self.processed = True
614
+ return self
615
+
616
+ def get_result(self):
617
+ if not self.processed:
618
+ raise ValueError("Not processed")
619
+ return self.data`
620
+ const defs = await getDefinitions(code, 'python')
621
+ expect(defs).toMatchInlineSnapshot(`
622
+ [
623
+ {
624
+ "endLine": 14,
625
+ "exported": false,
626
+ "line": 1,
627
+ "name": "DataProcessor",
628
+ "type": "class",
629
+ },
630
+ ]
631
+ `)
632
+ })
633
+
634
+ test('small class', async () => {
635
+ const code = `class Point:
636
+ x: int
637
+ y: int`
638
+ const defs = await getDefinitions(code, 'python')
639
+ expect(defs).toMatchInlineSnapshot(`[]`)
640
+ })
641
+
642
+ test('async function', async () => {
643
+ const code = `async def fetch_data(url):
644
+ async with aiohttp.ClientSession() as session:
645
+ async with session.get(url) as response:
646
+ data = await response.json()
647
+ validated = validate(data)
648
+ processed = process(validated)
649
+ return processed`
650
+ const defs = await getDefinitions(code, 'python')
651
+ expect(defs).toMatchInlineSnapshot(`
652
+ [
653
+ {
654
+ "endLine": 7,
655
+ "exported": false,
656
+ "line": 1,
657
+ "name": "fetch_data",
658
+ "type": "function",
659
+ },
660
+ ]
661
+ `)
662
+ })
663
+
664
+ test('decorated function', async () => {
665
+ const code = `@app.route('/api/users')
666
+ @require_auth
667
+ def get_users():
668
+ users = db.query(User).all()
669
+ serialized = [u.to_dict() for u in users]
670
+ filtered = filter_active(serialized)
671
+ sorted_users = sort_by_name(filtered)
672
+ return jsonify(sorted_users)`
673
+ const defs = await getDefinitions(code, 'python')
674
+ expect(defs).toMatchInlineSnapshot(`[]`)
675
+ })
676
+
677
+ test('class with inheritance', async () => {
678
+ const code = `class AdminUser(User, PermissionMixin):
679
+ def __init__(self, name, permissions):
680
+ super().__init__(name)
681
+ self.permissions = permissions
682
+
683
+ def has_permission(self, perm):
684
+ return perm in self.permissions
685
+
686
+ def grant(self, perm):
687
+ self.permissions.add(perm)`
688
+ const defs = await getDefinitions(code, 'python')
689
+ expect(defs).toMatchInlineSnapshot(`
690
+ [
691
+ {
692
+ "endLine": 10,
693
+ "exported": false,
694
+ "line": 1,
695
+ "name": "AdminUser",
696
+ "type": "class",
697
+ },
698
+ ]
699
+ `)
700
+ })
701
+
702
+ test('lambda is not extracted', async () => {
703
+ const code = `double = lambda x: x * 2
704
+ triple = lambda x: x * 3`
705
+ const defs = await getDefinitions(code, 'python')
706
+ expect(defs).toMatchInlineSnapshot(`[]`)
707
+ })
708
+ })
709
+
710
+ // ============================================================================
711
+ // Rust Tests
712
+ // ============================================================================
713
+
714
+ describe('Rust', () => {
715
+ test('large function', async () => {
716
+ const code = `fn process_items(items: Vec<String>) -> Vec<String> {
717
+ let mut result = Vec::new();
718
+ for item in items {
719
+ let trimmed = item.trim();
720
+ let upper = trimmed.to_uppercase();
721
+ let parts: Vec<&str> = upper.split(',').collect();
722
+ result.extend(parts.iter().map(|s| s.to_string()));
723
+ }
724
+ result
725
+ }`
726
+ const defs = await getDefinitions(code, 'rust')
727
+ expect(defs).toMatchInlineSnapshot(`
728
+ [
729
+ {
730
+ "endLine": 10,
731
+ "exported": false,
732
+ "line": 1,
733
+ "name": "process_items",
734
+ "type": "function",
735
+ },
736
+ ]
737
+ `)
738
+ })
739
+
740
+ test('small function', async () => {
741
+ const code = `fn add(a: i32, b: i32) -> i32 {
742
+ a + b
743
+ }`
744
+ const defs = await getDefinitions(code, 'rust')
745
+ expect(defs).toMatchInlineSnapshot(`[]`)
746
+ })
747
+
748
+ test('large struct', async () => {
749
+ const code = `struct Config {
750
+ api_url: String,
751
+ timeout: u64,
752
+ retries: u32,
753
+ headers: HashMap<String, String>,
754
+ auth_token: Option<String>,
755
+ debug_mode: bool,
756
+ log_level: String,
757
+ max_connections: usize,
758
+ }`
759
+ const defs = await getDefinitions(code, 'rust')
760
+ expect(defs).toMatchInlineSnapshot(`[]`)
761
+ })
762
+
763
+ test('small struct', async () => {
764
+ const code = `struct Point {
765
+ x: i32,
766
+ y: i32,
767
+ }`
768
+ const defs = await getDefinitions(code, 'rust')
769
+ expect(defs).toMatchInlineSnapshot(`[]`)
770
+ })
771
+
772
+ test('large impl block', async () => {
773
+ const code = `impl Calculator {
774
+ fn new() -> Self {
775
+ Calculator { value: 0 }
776
+ }
777
+
778
+ fn add(&mut self, n: i32) -> &mut Self {
779
+ self.value += n;
780
+ self
781
+ }
782
+
783
+ fn result(&self) -> i32 {
784
+ self.value
785
+ }
786
+ }`
787
+ const defs = await getDefinitions(code, 'rust')
788
+ expect(defs).toMatchInlineSnapshot(`[]`)
789
+ })
790
+
791
+ test('large trait', async () => {
792
+ const code = `trait Processor {
793
+ fn process(&self, input: &str) -> String;
794
+ fn validate(&self, input: &str) -> bool;
795
+ fn transform(&self, input: &str) -> Vec<String>;
796
+ fn cleanup(&self);
797
+ fn reset(&mut self);
798
+ fn get_status(&self) -> Status;
799
+ fn set_config(&mut self, config: Config);
800
+ fn run(&self) -> Result<(), Error>;
801
+ }`
802
+ const defs = await getDefinitions(code, 'rust')
803
+ expect(defs).toMatchInlineSnapshot(`[]`)
804
+ })
805
+
806
+ test('enum', async () => {
807
+ const code = `enum Status {
808
+ Pending,
809
+ Active,
810
+ Done,
811
+ }`
812
+ const defs = await getDefinitions(code, 'rust')
813
+ expect(defs).toMatchInlineSnapshot(`[]`)
814
+ })
815
+
816
+ test('type alias', async () => {
817
+ const code = `type Result<T> = std::result::Result<T, Error>;`
818
+ const defs = await getDefinitions(code, 'rust')
819
+ expect(defs).toMatchInlineSnapshot(`[]`)
820
+ })
821
+
822
+ test('const item', async () => {
823
+ const code = `const MAX_SIZE: usize = 1024;`
824
+ const defs = await getDefinitions(code, 'rust')
825
+ expect(defs).toMatchInlineSnapshot(`[]`)
826
+ })
827
+
828
+ test('static item', async () => {
829
+ const code = `static COUNTER: AtomicUsize = AtomicUsize::new(0);`
830
+ const defs = await getDefinitions(code, 'rust')
831
+ expect(defs).toMatchInlineSnapshot(`[]`)
832
+ })
833
+
834
+ test('pub function', async () => {
835
+ const code = `pub fn public_handler(request: Request) -> Response {
836
+ let body = request.body();
837
+ let parsed = parse_body(body);
838
+ let validated = validate(parsed);
839
+ let processed = process(validated);
840
+ let serialized = serialize(processed);
841
+ Response::new(serialized)
842
+ }`
843
+ const defs = await getDefinitions(code, 'rust')
844
+ expect(defs).toMatchInlineSnapshot(`
845
+ [
846
+ {
847
+ "endLine": 8,
848
+ "exported": true,
849
+ "line": 1,
850
+ "name": "public_handler",
851
+ "type": "function",
852
+ },
853
+ ]
854
+ `)
855
+ })
856
+
857
+ test('async function', async () => {
858
+ const code = `async fn fetch_data(url: &str) -> Result<Data, Error> {
859
+ let client = reqwest::Client::new();
860
+ let response = client.get(url).send().await?;
861
+ let body = response.text().await?;
862
+ let parsed = serde_json::from_str(&body)?;
863
+ let validated = validate(parsed)?;
864
+ Ok(validated)
865
+ }`
866
+ const defs = await getDefinitions(code, 'rust')
867
+ expect(defs).toMatchInlineSnapshot(`
868
+ [
869
+ {
870
+ "endLine": 8,
871
+ "exported": false,
872
+ "line": 1,
873
+ "name": "fetch_data",
874
+ "type": "function",
875
+ },
876
+ ]
877
+ `)
878
+ })
879
+
880
+ test('macro definition is not extracted', async () => {
881
+ const code = `macro_rules! create_function {
882
+ ($name:ident) => {
883
+ fn $name() {
884
+ println!("Called {}", stringify!($name));
885
+ }
886
+ };
887
+ }`
888
+ const defs = await getDefinitions(code, 'rust')
889
+ expect(defs).toMatchInlineSnapshot(`[]`)
890
+ })
891
+ })
892
+
893
+ // ============================================================================
894
+ // Go Tests
895
+ // ============================================================================
896
+
897
+ describe('Go', () => {
898
+ test('large function', async () => {
899
+ const code = `func processItems(items []string) []string {
900
+ result := make([]string, 0)
901
+ for _, item := range items {
902
+ trimmed := strings.TrimSpace(item)
903
+ upper := strings.ToUpper(trimmed)
904
+ parts := strings.Split(upper, ",")
905
+ result = append(result, parts...)
906
+ }
907
+ return result
908
+ }`
909
+ const defs = await getDefinitions(code, 'go')
910
+ expect(defs).toMatchInlineSnapshot(`
911
+ [
912
+ {
913
+ "endLine": 10,
914
+ "exported": false,
915
+ "line": 1,
916
+ "name": "processItems",
917
+ "type": "function",
918
+ },
919
+ ]
920
+ `)
921
+ })
922
+
923
+ test('small function', async () => {
924
+ const code = `func add(a, b int) int {
925
+ return a + b
926
+ }`
927
+ const defs = await getDefinitions(code, 'go')
928
+ expect(defs).toMatchInlineSnapshot(`[]`)
929
+ })
930
+
931
+ test('large method', async () => {
932
+ const code = `func (c *Calculator) Process(input string) string {
933
+ step1 := strings.TrimSpace(input)
934
+ step2 := strings.ToUpper(step1)
935
+ step3 := strings.Split(step2, ",")
936
+ step4 := strings.Join(step3, "-")
937
+ step5 := step4 + "!"
938
+ return step5
939
+ }`
940
+ const defs = await getDefinitions(code, 'go')
941
+ expect(defs).toMatchInlineSnapshot(`
942
+ [
943
+ {
944
+ "endLine": 8,
945
+ "exported": true,
946
+ "line": 1,
947
+ "name": "Process",
948
+ "type": "function",
949
+ },
950
+ ]
951
+ `)
952
+ })
953
+
954
+ test('type struct', async () => {
955
+ const code = `type Config struct {
956
+ APIUrl string
957
+ Timeout int
958
+ }`
959
+ const defs = await getDefinitions(code, 'go')
960
+ expect(defs).toMatchInlineSnapshot(`
961
+ [
962
+ {
963
+ "endLine": 4,
964
+ "exported": true,
965
+ "line": 1,
966
+ "name": "Config",
967
+ "type": "type",
968
+ },
969
+ ]
970
+ `)
971
+ })
972
+
973
+ test('type interface', async () => {
974
+ const code = `type Reader interface {
975
+ Read(p []byte) (n int, err error)
976
+ }`
977
+ const defs = await getDefinitions(code, 'go')
978
+ expect(defs).toMatchInlineSnapshot(`
979
+ [
980
+ {
981
+ "endLine": 3,
982
+ "exported": true,
983
+ "line": 1,
984
+ "name": "Reader",
985
+ "type": "type",
986
+ },
987
+ ]
988
+ `)
989
+ })
990
+
991
+ test('const declaration', async () => {
992
+ const code = `const MaxRetries = 3`
993
+ const defs = await getDefinitions(code, 'go')
994
+ expect(defs).toMatchInlineSnapshot(`
995
+ [
996
+ {
997
+ "endLine": 1,
998
+ "exported": true,
999
+ "line": 1,
1000
+ "name": "MaxRetries",
1001
+ "type": "const",
1002
+ },
1003
+ ]
1004
+ `)
1005
+ })
1006
+
1007
+ test('var declaration', async () => {
1008
+ const code = `var DefaultTimeout = time.Second * 30`
1009
+ const defs = await getDefinitions(code, 'go')
1010
+ expect(defs).toMatchInlineSnapshot(`
1011
+ [
1012
+ {
1013
+ "endLine": 1,
1014
+ "exported": true,
1015
+ "line": 1,
1016
+ "name": "DefaultTimeout",
1017
+ "type": "const",
1018
+ },
1019
+ ]
1020
+ `)
1021
+ })
1022
+
1023
+ test('exported function (capitalized)', async () => {
1024
+ const code = `func ProcessData(input string) (string, error) {
1025
+ if input == "" {
1026
+ return "", errors.New("empty input")
1027
+ }
1028
+ trimmed := strings.TrimSpace(input)
1029
+ upper := strings.ToUpper(trimmed)
1030
+ validated := validate(upper)
1031
+ return validated, nil
1032
+ }`
1033
+ const defs = await getDefinitions(code, 'go')
1034
+ expect(defs).toMatchInlineSnapshot(`
1035
+ [
1036
+ {
1037
+ "endLine": 9,
1038
+ "exported": true,
1039
+ "line": 1,
1040
+ "name": "ProcessData",
1041
+ "type": "function",
1042
+ },
1043
+ ]
1044
+ `)
1045
+ })
1046
+
1047
+ test('init function is extracted if large', async () => {
1048
+ const code = `func init() {
1049
+ config = loadConfig()
1050
+ db = connectDB()
1051
+ cache = initCache()
1052
+ logger = setupLogger()
1053
+ metrics = initMetrics()
1054
+ validator = newValidator()
1055
+ handlers = registerHandlers()
1056
+ }`
1057
+ const defs = await getDefinitions(code, 'go')
1058
+ expect(defs).toMatchInlineSnapshot(`
1059
+ [
1060
+ {
1061
+ "endLine": 9,
1062
+ "exported": false,
1063
+ "line": 1,
1064
+ "name": "init",
1065
+ "type": "function",
1066
+ },
1067
+ ]
1068
+ `)
1069
+ })
1070
+
1071
+ test('type alias', async () => {
1072
+ const code = `type UserID = int64`
1073
+ const defs = await getDefinitions(code, 'go')
1074
+ expect(defs).toMatchInlineSnapshot(`[]`)
1075
+ })
1076
+ })
1077
+
1078
+ // ============================================================================
1079
+ // Edge Cases
1080
+ // ============================================================================
1081
+
1082
+ describe('edge cases', () => {
1083
+ test('empty file', async () => {
1084
+ const defs = await getDefinitions('', 'typescript')
1085
+ expect(defs).toMatchInlineSnapshot(`[]`)
1086
+ })
1087
+
1088
+ test('only comments', async () => {
1089
+ const code = `// This is a comment
1090
+ // Another comment
1091
+ /* Block comment */`
1092
+ const defs = await getDefinitions(code, 'typescript')
1093
+ expect(defs).toMatchInlineSnapshot(`[]`)
1094
+ })
1095
+
1096
+ test('only imports', async () => {
1097
+ const code = `import { foo } from 'bar'
1098
+ import * as baz from 'qux'`
1099
+ const defs = await getDefinitions(code, 'typescript')
1100
+ expect(defs).toMatchInlineSnapshot(`[]`)
1101
+ })
1102
+
1103
+ test('nested functions - only top level', async () => {
1104
+ const code = `function outer(x: number): number {
1105
+ function inner(y: number): number {
1106
+ return y * 2
1107
+ }
1108
+ const result = inner(x)
1109
+ const doubled = result * 2
1110
+ const tripled = result * 3
1111
+ return doubled + tripled
1112
+ }`
1113
+ const defs = await getDefinitions(code, 'typescript')
1114
+ expect(defs).toMatchInlineSnapshot(`
1115
+ [
1116
+ {
1117
+ "endLine": 9,
1118
+ "exported": false,
1119
+ "line": 1,
1120
+ "name": "outer",
1121
+ "type": "function",
1122
+ },
1123
+ ]
1124
+ `)
1125
+ })
1126
+
1127
+ test('boundary: exactly 8 lines included', async () => {
1128
+ const code = `function eightLines(): void {
1129
+ const a = 1
1130
+ const b = 2
1131
+ const c = 3
1132
+ const d = 4
1133
+ const e = 5
1134
+ console.log(a, b, c, d, e)
1135
+ }`
1136
+ const defs = await getDefinitions(code, 'typescript')
1137
+ expect(defs).toMatchInlineSnapshot(`
1138
+ [
1139
+ {
1140
+ "endLine": 8,
1141
+ "exported": false,
1142
+ "line": 1,
1143
+ "name": "eightLines",
1144
+ "type": "function",
1145
+ },
1146
+ ]
1147
+ `)
1148
+ })
1149
+
1150
+ test('boundary: exactly 7 lines excluded', async () => {
1151
+ const code = `function sevenLines(): void {
1152
+ const a = 1
1153
+ const b = 2
1154
+ const c = 3
1155
+ const d = 4
1156
+ console.log(a, b, c, d)
1157
+ }`
1158
+ const defs = await getDefinitions(code, 'typescript')
1159
+ expect(defs).toMatchInlineSnapshot(`
1160
+ [
1161
+ {
1162
+ "endLine": 7,
1163
+ "exported": false,
1164
+ "line": 1,
1165
+ "name": "sevenLines",
1166
+ "type": "function",
1167
+ },
1168
+ ]
1169
+ `)
1170
+ })
1171
+
1172
+ test('function with multiline signature', async () => {
1173
+ const code = `function complexSignature(
1174
+ param1: string,
1175
+ param2: number,
1176
+ param3: boolean,
1177
+ param4: object
1178
+ ): Result {
1179
+ const combined = combine(param1, param2)
1180
+ const processed = process(combined, param3)
1181
+ return finalize(processed, param4)
1182
+ }`
1183
+ const defs = await getDefinitions(code, 'typescript')
1184
+ expect(defs).toMatchInlineSnapshot(`
1185
+ [
1186
+ {
1187
+ "endLine": 10,
1188
+ "exported": false,
1189
+ "line": 1,
1190
+ "name": "complexSignature",
1191
+ "type": "function",
1192
+ },
1193
+ ]
1194
+ `)
1195
+ })
1196
+
1197
+ test('class with static members', async () => {
1198
+ const code = `class Singleton {
1199
+ private static instance: Singleton
1200
+
1201
+ private constructor() {}
1202
+
1203
+ static getInstance(): Singleton {
1204
+ if (!Singleton.instance) {
1205
+ Singleton.instance = new Singleton()
1206
+ }
1207
+ return Singleton.instance
1208
+ }
1209
+ }`
1210
+ const defs = await getDefinitions(code, 'typescript')
1211
+ expect(defs).toMatchInlineSnapshot(`
1212
+ [
1213
+ {
1214
+ "endLine": 12,
1215
+ "exported": false,
1216
+ "line": 1,
1217
+ "name": "Singleton",
1218
+ "type": "class",
1219
+ },
1220
+ ]
1221
+ `)
1222
+ })
1223
+
1224
+ test('re-export statement', async () => {
1225
+ const code = `export { foo, bar } from './module'
1226
+ export * from './other'`
1227
+ const defs = await getDefinitions(code, 'typescript')
1228
+ expect(defs).toMatchInlineSnapshot(`[]`)
1229
+ })
1230
+
1231
+ test('interface with generics', async () => {
1232
+ const code = `interface Repository<T, ID> {
1233
+ find(id: ID): Promise<T | null>
1234
+ findAll(): Promise<T[]>
1235
+ save(entity: T): Promise<T>
1236
+ delete(id: ID): Promise<void>
1237
+ }`
1238
+ const defs = await getDefinitions(code, 'typescript')
1239
+ expect(defs).toMatchInlineSnapshot(`[]`)
1240
+ })
1241
+
1242
+ test('mapped type', async () => {
1243
+ const code = `type Readonly<T> = {
1244
+ readonly [P in keyof T]: T[P]
1245
+ }`
1246
+ const defs = await getDefinitions(code, 'typescript')
1247
+ expect(defs).toMatchInlineSnapshot(`[]`)
1248
+ })
1249
+
1250
+ test('conditional type', async () => {
1251
+ const code = `type NonNullable<T> = T extends null | undefined ? never : T`
1252
+ const defs = await getDefinitions(code, 'typescript')
1253
+ expect(defs).toMatchInlineSnapshot(`[]`)
1254
+ })
1255
+
1256
+ test('overloaded function signatures', async () => {
1257
+ const code = `function process(input: string): string
1258
+ function process(input: number): number
1259
+ function process(input: string | number): string | number {
1260
+ if (typeof input === 'string') {
1261
+ return input.toUpperCase()
1262
+ }
1263
+ return input * 2
1264
+ }`
1265
+ const defs = await getDefinitions(code, 'typescript')
1266
+ expect(defs).toMatchInlineSnapshot(`
1267
+ [
1268
+ {
1269
+ "endLine": 8,
1270
+ "exported": false,
1271
+ "line": 3,
1272
+ "name": "process",
1273
+ "type": "function",
1274
+ },
1275
+ ]
1276
+ `)
1277
+ })
1278
+
1279
+ test('namespace', async () => {
1280
+ const code = `namespace Utils {
1281
+ export function helper(x: number): number {
1282
+ return x * 2
1283
+ }
1284
+
1285
+ export const VERSION = '1.0.0'
1286
+ }`
1287
+ const defs = await getDefinitions(code, 'typescript')
1288
+ expect(defs).toMatchInlineSnapshot(`[]`)
1289
+ })
1290
+
1291
+ test('declare statements', async () => {
1292
+ const code = `declare function external(x: string): void
1293
+ declare class ExternalClass {
1294
+ method(): void
1295
+ }
1296
+ declare const CONFIG: { url: string }`
1297
+ const defs = await getDefinitions(code, 'typescript')
1298
+ expect(defs).toMatchInlineSnapshot(`[]`)
1299
+ })
1300
+
1301
+ test('unicode identifiers', async () => {
1302
+ const code = `function 计算(输入: number): number {
1303
+ const 结果 = 输入 * 2
1304
+ const 验证 = validate(结果)
1305
+ const 处理 = process(验证)
1306
+ const 格式化 = format(处理)
1307
+ const 输出 = finalize(格式化)
1308
+ return 输出
1309
+ }`
1310
+ const defs = await getDefinitions(code, 'typescript')
1311
+ expect(defs).toMatchInlineSnapshot(`
1312
+ [
1313
+ {
1314
+ "endLine": 8,
1315
+ "exported": false,
1316
+ "line": 1,
1317
+ "name": "计算",
1318
+ "type": "function",
1319
+ },
1320
+ ]
1321
+ `)
1322
+ })
1323
+
1324
+ test('private class fields', async () => {
1325
+ const code = `class SecureStorage {
1326
+ #data: Map<string, string> = new Map()
1327
+ #key: string
1328
+
1329
+ constructor(key: string) {
1330
+ this.#key = key
1331
+ }
1332
+
1333
+ #encrypt(value: string): string {
1334
+ return btoa(value + this.#key)
1335
+ }
1336
+
1337
+ set(key: string, value: string): void {
1338
+ this.#data.set(key, this.#encrypt(value))
1339
+ }
1340
+ }`
1341
+ const defs = await getDefinitions(code, 'typescript')
1342
+ expect(defs).toMatchInlineSnapshot(`
1343
+ [
1344
+ {
1345
+ "endLine": 16,
1346
+ "exported": false,
1347
+ "line": 1,
1348
+ "name": "SecureStorage",
1349
+ "type": "class",
1350
+ },
1351
+ ]
1352
+ `)
1353
+ })
1354
+ })
1355
+
1356
+ // ============================================================================
1357
+ // Zig Tests
1358
+ // ============================================================================
1359
+
1360
+ describe('Zig', () => {
1361
+ test('pub function is exported', async () => {
1362
+ const code = `pub fn calculate(a: i32, b: i32) i32 {
1363
+ const sum = a + b;
1364
+ const product = a * b;
1365
+ const diff = a - b;
1366
+ const result = sum + product;
1367
+ return result + diff;
1368
+ }`
1369
+ const defs = await getDefinitions(code, 'zig')
1370
+ expect(defs).toMatchInlineSnapshot(`
1371
+ [
1372
+ {
1373
+ "endLine": 7,
1374
+ "exported": true,
1375
+ "line": 1,
1376
+ "name": "calculate",
1377
+ "type": "function",
1378
+ },
1379
+ ]
1380
+ `)
1381
+ })
1382
+
1383
+ test('private function not exported', async () => {
1384
+ const code = `fn helper(x: i32) i32 {
1385
+ const a = x * 2;
1386
+ const b = a + 1;
1387
+ const c = b - 3;
1388
+ const d = c * 4;
1389
+ return d;
1390
+ }`
1391
+ const defs = await getDefinitions(code, 'zig')
1392
+ expect(defs).toMatchInlineSnapshot(`
1393
+ [
1394
+ {
1395
+ "endLine": 7,
1396
+ "exported": false,
1397
+ "line": 1,
1398
+ "name": "helper",
1399
+ "type": "function",
1400
+ },
1401
+ ]
1402
+ `)
1403
+ })
1404
+
1405
+ test('pub const is exported', async () => {
1406
+ const code = `pub const MAX_SIZE: usize = 1024;`
1407
+ const defs = await getDefinitions(code, 'zig')
1408
+ expect(defs).toMatchInlineSnapshot(`
1409
+ [
1410
+ {
1411
+ "endLine": 1,
1412
+ "exported": true,
1413
+ "line": 1,
1414
+ "name": "MAX_SIZE",
1415
+ "type": "const",
1416
+ },
1417
+ ]
1418
+ `)
1419
+ })
1420
+
1421
+ test('private const not included', async () => {
1422
+ const code = `const internal_value: i32 = 42;`
1423
+ const defs = await getDefinitions(code, 'zig')
1424
+ expect(defs).toMatchInlineSnapshot(`[]`)
1425
+ })
1426
+
1427
+ test('pub var not included (only const)', async () => {
1428
+ const code = `pub var mutable_value: i32 = 42;`
1429
+ const defs = await getDefinitions(code, 'zig')
1430
+ expect(defs).toMatchInlineSnapshot(`[]`)
1431
+ })
1432
+
1433
+ test('struct declaration is class', async () => {
1434
+ const code = `pub const Config = struct {
1435
+ name: []const u8,
1436
+ value: i32,
1437
+ enabled: bool,
1438
+ };`
1439
+ const defs = await getDefinitions(code, 'zig')
1440
+ expect(defs).toMatchInlineSnapshot(`
1441
+ [
1442
+ {
1443
+ "endLine": 5,
1444
+ "exported": true,
1445
+ "line": 1,
1446
+ "name": "Config",
1447
+ "type": "struct",
1448
+ },
1449
+ ]
1450
+ `)
1451
+ })
1452
+
1453
+ test('enum declaration', async () => {
1454
+ const code = `pub const Status = enum {
1455
+ pending,
1456
+ running,
1457
+ completed,
1458
+ failed,
1459
+ };`
1460
+ const defs = await getDefinitions(code, 'zig')
1461
+ expect(defs).toMatchInlineSnapshot(`
1462
+ [
1463
+ {
1464
+ "endLine": 6,
1465
+ "exported": true,
1466
+ "line": 1,
1467
+ "name": "Status",
1468
+ "type": "enum",
1469
+ },
1470
+ ]
1471
+ `)
1472
+ })
1473
+
1474
+ test('union declaration is class', async () => {
1475
+ const code = `pub const Result = union(enum) {
1476
+ ok: i32,
1477
+ err: []const u8,
1478
+ };`
1479
+ const defs = await getDefinitions(code, 'zig')
1480
+ expect(defs).toMatchInlineSnapshot(`
1481
+ [
1482
+ {
1483
+ "endLine": 4,
1484
+ "exported": true,
1485
+ "line": 1,
1486
+ "name": "Result",
1487
+ "type": "union",
1488
+ },
1489
+ ]
1490
+ `)
1491
+ })
1492
+
1493
+ test('test declaration with string name', async () => {
1494
+ const code = `test "add function" {
1495
+ const result = add(2, 3);
1496
+ const expected = 5;
1497
+ const check = result == expected;
1498
+ const msg = "test failed";
1499
+ try std.testing.expect(check);
1500
+ }`
1501
+ const defs = await getDefinitions(code, 'zig')
1502
+ expect(defs).toMatchInlineSnapshot(`
1503
+ [
1504
+ {
1505
+ "endLine": 7,
1506
+ "exported": false,
1507
+ "line": 1,
1508
+ "name": "add function",
1509
+ "type": "function",
1510
+ },
1511
+ ]
1512
+ `)
1513
+ })
1514
+
1515
+ test('small function excluded', async () => {
1516
+ const code = `pub fn add(a: i32, b: i32) i32 {
1517
+ return a + b;
1518
+ }`
1519
+ const defs = await getDefinitions(code, 'zig')
1520
+ expect(defs).toMatchInlineSnapshot(`[]`)
1521
+ })
1522
+
1523
+ test('comptime function', async () => {
1524
+ const code = `pub fn comptimeFunc(comptime T: type) type {
1525
+ return struct {
1526
+ value: T,
1527
+ count: usize,
1528
+ flag: bool,
1529
+ };
1530
+ }`
1531
+ const defs = await getDefinitions(code, 'zig')
1532
+ expect(defs).toMatchInlineSnapshot(`
1533
+ [
1534
+ {
1535
+ "endLine": 7,
1536
+ "exported": true,
1537
+ "line": 1,
1538
+ "name": "comptimeFunc",
1539
+ "type": "function",
1540
+ },
1541
+ ]
1542
+ `)
1543
+ })
1544
+
1545
+ test('extern function', async () => {
1546
+ const code = `pub extern "c" fn printf(format: [*:0]const u8, ...) c_int;`
1547
+ const defs = await getDefinitions(code, 'zig')
1548
+ expect(defs).toMatchInlineSnapshot(`[]`)
1549
+ })
1550
+
1551
+ test('error set', async () => {
1552
+ const code = `pub const FileError = error{
1553
+ NotFound,
1554
+ AccessDenied,
1555
+ OutOfMemory,
1556
+ InvalidPath,
1557
+ };`
1558
+ const defs = await getDefinitions(code, 'zig')
1559
+ expect(defs).toMatchInlineSnapshot(`
1560
+ [
1561
+ {
1562
+ "endLine": 6,
1563
+ "exported": true,
1564
+ "line": 1,
1565
+ "name": "FileError",
1566
+ "type": "const",
1567
+ },
1568
+ ]
1569
+ `)
1570
+ })
1571
+
1572
+ test('packed struct', async () => {
1573
+ const code = `pub const PackedData = packed struct {
1574
+ flags: u4,
1575
+ count: u4,
1576
+ value: u8,
1577
+ extra: u16,
1578
+ };`
1579
+ const defs = await getDefinitions(code, 'zig')
1580
+ expect(defs).toMatchInlineSnapshot(`
1581
+ [
1582
+ {
1583
+ "endLine": 6,
1584
+ "exported": true,
1585
+ "line": 1,
1586
+ "name": "PackedData",
1587
+ "type": "struct",
1588
+ },
1589
+ ]
1590
+ `)
1591
+ })
1592
+
1593
+ test('multiple definitions in file', async () => {
1594
+ const code = `pub const MAX_SIZE: usize = 1024;
1595
+ pub const Config = struct {
1596
+ name: []const u8,
1597
+ value: i32,
1598
+ };
1599
+ pub fn process(cfg: Config) void {
1600
+ const x = cfg.value;
1601
+ const y = x * 2;
1602
+ const z = y + 1;
1603
+ _ = z;
1604
+ return;
1605
+ }`
1606
+ const defs = await getDefinitions(code, 'zig')
1607
+ expect(defs).toMatchInlineSnapshot(`
1608
+ [
1609
+ {
1610
+ "endLine": 1,
1611
+ "exported": true,
1612
+ "line": 1,
1613
+ "name": "MAX_SIZE",
1614
+ "type": "const",
1615
+ },
1616
+ {
1617
+ "endLine": 5,
1618
+ "exported": true,
1619
+ "line": 2,
1620
+ "name": "Config",
1621
+ "type": "struct",
1622
+ },
1623
+ {
1624
+ "endLine": 12,
1625
+ "exported": true,
1626
+ "line": 6,
1627
+ "name": "process",
1628
+ "type": "function",
1629
+ },
1630
+ ]
1631
+ `)
1632
+ })
1633
+
1634
+ test('extern function has extern flag', async () => {
1635
+ const code = `pub extern "c" fn processData(data: [*]u8, len: usize) callconv(.C) void {
1636
+ var i: usize = 0;
1637
+ while (i < len) : (i += 1) {
1638
+ data[i] = 0;
1639
+ }
1640
+ return;
1641
+ }`
1642
+ const defs = await getDefinitions(code, 'zig')
1643
+ expect(defs).toMatchInlineSnapshot(`
1644
+ [
1645
+ {
1646
+ "endLine": 7,
1647
+ "exported": true,
1648
+ "extern": true,
1649
+ "line": 1,
1650
+ "name": "processData",
1651
+ "type": "function",
1652
+ },
1653
+ ]
1654
+ `)
1655
+ })
1656
+
1657
+ test('non-extern function has no extern flag', async () => {
1658
+ const code = `pub fn normalFunction(x: i32) i32 {
1659
+ const a = x * 2;
1660
+ const b = a + 1;
1661
+ const c = b - 3;
1662
+ const d = c * 4;
1663
+ return d;
1664
+ }`
1665
+ const defs = await getDefinitions(code, 'zig')
1666
+ expect(defs).toMatchInlineSnapshot(`
1667
+ [
1668
+ {
1669
+ "endLine": 7,
1670
+ "exported": true,
1671
+ "line": 1,
1672
+ "name": "normalFunction",
1673
+ "type": "function",
1674
+ },
1675
+ ]
1676
+ `)
1677
+ })
1678
+ })
1679
+
1680
+ // C/C++ Tests
1681
+ // ============================================================================
1682
+
1683
+ describe('C++', () => {
1684
+ test('large function', async () => {
1685
+ const code = `int calculateSum(int arr[], int size) {
1686
+ int sum = 0;
1687
+ for (int i = 0; i < size; i++) {
1688
+ sum += arr[i];
1689
+ }
1690
+ return sum;
1691
+ }`
1692
+ const defs = await getDefinitions(code, 'cpp')
1693
+ expect(defs).toMatchInlineSnapshot(`
1694
+ [
1695
+ {
1696
+ "endLine": 7,
1697
+ "exported": false,
1698
+ "line": 1,
1699
+ "name": "calculateSum",
1700
+ "type": "function",
1701
+ },
1702
+ ]
1703
+ `)
1704
+ })
1705
+
1706
+ test('small function excluded', async () => {
1707
+ const code = `int add(int a, int b) {
1708
+ return a + b;
1709
+ }`
1710
+ const defs = await getDefinitions(code, 'cpp')
1711
+ expect(defs).toMatchInlineSnapshot(`[]`)
1712
+ })
1713
+
1714
+ test('class definition', async () => {
1715
+ const code = `class Calculator {
1716
+ public:
1717
+ int add(int a, int b) {
1718
+ return a + b;
1719
+ }
1720
+ private:
1721
+ int result;
1722
+ };`
1723
+ const defs = await getDefinitions(code, 'cpp')
1724
+ expect(defs).toMatchInlineSnapshot(`
1725
+ [
1726
+ {
1727
+ "endLine": 8,
1728
+ "exported": false,
1729
+ "line": 1,
1730
+ "name": "Calculator",
1731
+ "type": "class",
1732
+ },
1733
+ ]
1734
+ `)
1735
+ })
1736
+
1737
+ test('struct definition', async () => {
1738
+ const code = `struct Point {
1739
+ int x;
1740
+ int y;
1741
+ int z;
1742
+ int w;
1743
+ int v;
1744
+ };`
1745
+ const defs = await getDefinitions(code, 'cpp')
1746
+ expect(defs).toMatchInlineSnapshot(`[]`)
1747
+ })
1748
+
1749
+ test('enum definition', async () => {
1750
+ const code = `enum Color {
1751
+ RED,
1752
+ GREEN,
1753
+ BLUE,
1754
+ ALPHA
1755
+ };`
1756
+ const defs = await getDefinitions(code, 'cpp')
1757
+ expect(defs).toMatchInlineSnapshot(`[]`)
1758
+ })
1759
+
1760
+ test('enum class (C++11)', async () => {
1761
+ const code = `enum class Status {
1762
+ Pending,
1763
+ Running,
1764
+ Complete,
1765
+ Failed
1766
+ };`
1767
+ const defs = await getDefinitions(code, 'cpp')
1768
+ expect(defs).toMatchInlineSnapshot(`[]`)
1769
+ })
1770
+
1771
+ test('typedef', async () => {
1772
+ const code = `typedef unsigned long ulong;`
1773
+ const defs = await getDefinitions(code, 'cpp')
1774
+ expect(defs).toMatchInlineSnapshot(`[]`)
1775
+ })
1776
+
1777
+ test('using alias (C++11)', async () => {
1778
+ const code = `using StringList = std::vector<std::string>;`
1779
+ const defs = await getDefinitions(code, 'cpp')
1780
+ expect(defs).toMatchInlineSnapshot(`[]`)
1781
+ })
1782
+
1783
+ test('template function', async () => {
1784
+ const code = `template<typename T>
1785
+ T maximum(T a, T b) {
1786
+ if (a > b) {
1787
+ return a;
1788
+ } else {
1789
+ return b;
1790
+ }
1791
+ }`
1792
+ const defs = await getDefinitions(code, 'cpp')
1793
+ expect(defs).toMatchInlineSnapshot(`[]`)
1794
+ })
1795
+
1796
+ test('template class', async () => {
1797
+ const code = `template<typename T>
1798
+ class Container {
1799
+ public:
1800
+ T value;
1801
+ void set(T v) { value = v; }
1802
+ T get() { return value; }
1803
+ };`
1804
+ const defs = await getDefinitions(code, 'cpp')
1805
+ expect(defs).toMatchInlineSnapshot(`[]`)
1806
+ })
1807
+
1808
+ test('namespace function', async () => {
1809
+ const code = `namespace utils {
1810
+ int helper(int x) {
1811
+ int a = x * 2;
1812
+ int b = a + 1;
1813
+ int c = b - 3;
1814
+ return c;
1815
+ }
1816
+ }`
1817
+ const defs = await getDefinitions(code, 'cpp')
1818
+ expect(defs).toMatchInlineSnapshot(`[]`)
1819
+ })
1820
+
1821
+ test('static function', async () => {
1822
+ const code = `static int internalFunc(int x) {
1823
+ int result = x;
1824
+ result *= 2;
1825
+ result += 10;
1826
+ result -= 5;
1827
+ return result;
1828
+ }`
1829
+ const defs = await getDefinitions(code, 'cpp')
1830
+ expect(defs).toMatchInlineSnapshot(`
1831
+ [
1832
+ {
1833
+ "endLine": 7,
1834
+ "exported": false,
1835
+ "line": 1,
1836
+ "name": "internalFunc",
1837
+ "type": "function",
1838
+ },
1839
+ ]
1840
+ `)
1841
+ })
1842
+
1843
+ test('const global', async () => {
1844
+ const code = `const int MAX_SIZE = 1024;`
1845
+ const defs = await getDefinitions(code, 'cpp')
1846
+ expect(defs).toMatchInlineSnapshot(`[]`)
1847
+ })
1848
+
1849
+ test('multiple definitions', async () => {
1850
+ const code = `struct Point {
1851
+ int x;
1852
+ int y;
1853
+ int z;
1854
+ int w;
1855
+ };
1856
+
1857
+ enum Color { RED, GREEN, BLUE };
1858
+
1859
+ int distance(Point a, Point b) {
1860
+ int dx = a.x - b.x;
1861
+ int dy = a.y - b.y;
1862
+ int dz = a.z - b.z;
1863
+ return dx + dy + dz;
1864
+ }`
1865
+ const defs = await getDefinitions(code, 'cpp')
1866
+ expect(defs).toMatchInlineSnapshot(`
1867
+ [
1868
+ {
1869
+ "endLine": 15,
1870
+ "exported": false,
1871
+ "line": 10,
1872
+ "name": "distance",
1873
+ "type": "function",
1874
+ },
1875
+ ]
1876
+ `)
1877
+ })
1878
+
1879
+ test('forward declaration ignored', async () => {
1880
+ const code = `class ForwardDeclared;
1881
+ struct AnotherForward;`
1882
+ const defs = await getDefinitions(code, 'cpp')
1883
+ expect(defs).toMatchInlineSnapshot(`[]`)
1884
+ })
1885
+
1886
+ test('function with pointer return', async () => {
1887
+ const code = `int* createArray(int size) {
1888
+ int* arr = new int[size];
1889
+ for (int i = 0; i < size; i++) {
1890
+ arr[i] = 0;
1891
+ }
1892
+ return arr;
1893
+ }`
1894
+ const defs = await getDefinitions(code, 'cpp')
1895
+ expect(defs).toMatchInlineSnapshot(`
1896
+ [
1897
+ {
1898
+ "endLine": 7,
1899
+ "exported": false,
1900
+ "line": 1,
1901
+ "name": "createArray",
1902
+ "type": "function",
1903
+ },
1904
+ ]
1905
+ `)
1906
+ })
1907
+
1908
+ test('virtual method in class', async () => {
1909
+ const code = `class Base {
1910
+ public:
1911
+ virtual void process() {
1912
+ int x = 1;
1913
+ int y = 2;
1914
+ int z = x + y;
1915
+ }
1916
+ virtual ~Base() {}
1917
+ };`
1918
+ const defs = await getDefinitions(code, 'cpp')
1919
+ expect(defs).toMatchInlineSnapshot(`
1920
+ [
1921
+ {
1922
+ "endLine": 9,
1923
+ "exported": false,
1924
+ "line": 1,
1925
+ "name": "Base",
1926
+ "type": "class",
1927
+ },
1928
+ ]
1929
+ `)
1930
+ })
1931
+
1932
+ test('C-style header declarations', async () => {
1933
+ const code = `#ifndef HEADER_H
1934
+ #define HEADER_H
1935
+
1936
+ typedef struct {
1937
+ int x;
1938
+ int y;
1939
+ int z;
1940
+ int w;
1941
+ } Point;
1942
+
1943
+ int add(int a, int b);
1944
+ void process(Point* p);
1945
+
1946
+ #endif`
1947
+ const defs = await getDefinitions(code, 'cpp')
1948
+ expect(defs).toMatchInlineSnapshot(`[]`)
1949
+ })
1950
+
1951
+ test('lambda not captured as function', async () => {
1952
+ const code = `auto lambda = [](int x) {
1953
+ return x * 2;
1954
+ };`
1955
+ const defs = await getDefinitions(code, 'cpp')
1956
+ expect(defs).toMatchInlineSnapshot(`[]`)
1957
+ })
1958
+
1959
+ test('constructor and destructor', async () => {
1960
+ const code = `class Resource {
1961
+ public:
1962
+ Resource() {
1963
+ data = new int[100];
1964
+ size = 100;
1965
+ count = 0;
1966
+ }
1967
+ ~Resource() {
1968
+ delete[] data;
1969
+ data = nullptr;
1970
+ size = 0;
1971
+ }
1972
+ private:
1973
+ int* data;
1974
+ int size;
1975
+ int count;
1976
+ };`
1977
+ const defs = await getDefinitions(code, 'cpp')
1978
+ expect(defs).toMatchInlineSnapshot(`
1979
+ [
1980
+ {
1981
+ "endLine": 17,
1982
+ "exported": false,
1983
+ "line": 1,
1984
+ "name": "Resource",
1985
+ "type": "class",
1986
+ },
1987
+ ]
1988
+ `)
1989
+ })
1990
+
1991
+ test('extern "C" function has extern flag', async () => {
1992
+ const code = `extern "C" void c_callback(int code) {
1993
+ int result = code;
1994
+ result *= 2;
1995
+ result += 10;
1996
+ result -= 5;
1997
+ printf("%d", result);
1998
+ }`
1999
+ const defs = await getDefinitions(code, 'cpp')
2000
+ expect(defs).toMatchInlineSnapshot(`
2001
+ [
2002
+ {
2003
+ "endLine": 7,
2004
+ "exported": false,
2005
+ "extern": true,
2006
+ "line": 1,
2007
+ "name": "c_callback",
2008
+ "type": "function",
2009
+ },
2010
+ ]
2011
+ `)
2012
+ })
2013
+
2014
+ test('extern variable has extern flag', async () => {
2015
+ const code = `extern int global_counter;`
2016
+ const defs = await getDefinitions(code, 'cpp')
2017
+ expect(defs).toMatchInlineSnapshot(`[]`)
2018
+ })
2019
+
2020
+ test('non-extern function has no extern flag', async () => {
2021
+ const code = `void regularFunc(int x) {
2022
+ int a = x * 2;
2023
+ int b = a + 1;
2024
+ int c = b - 3;
2025
+ printf("%d", c);
2026
+ }`
2027
+ const defs = await getDefinitions(code, 'cpp')
2028
+ expect(defs).toMatchInlineSnapshot(`
2029
+ [
2030
+ {
2031
+ "endLine": 6,
2032
+ "exported": false,
2033
+ "line": 1,
2034
+ "name": "regularFunc",
2035
+ "type": "function",
2036
+ },
2037
+ ]
2038
+ `)
2039
+ })
2040
+ })