agentmap 0.8.0 → 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.
- package/CHANGELOG.md +96 -0
- package/README.md +24 -0
- package/dist/cli.js +37 -12
- package/dist/cli.js.map +1 -1
- package/dist/extract/definitions.js +12 -12
- package/dist/extract/definitions.js.map +1 -1
- package/dist/extract/definitions.test.js +30 -259
- package/dist/extract/definitions.test.js.map +1 -1
- package/dist/extract/git-status.d.ts +7 -2
- package/dist/extract/git-status.d.ts.map +1 -1
- package/dist/extract/git-status.js +12 -18
- package/dist/extract/git-status.js.map +1 -1
- package/dist/extract/markdown.js +1 -1
- package/dist/extract/markdown.test.js +3 -3
- package/dist/extract/markdown.test.js.map +1 -1
- package/dist/extract/marker.js +1 -1
- package/dist/extract/marker.test.js +4 -4
- package/dist/extract/marker.test.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/logger.d.ts +10 -0
- package/dist/logger.d.ts.map +1 -0
- package/dist/logger.js +41 -0
- package/dist/logger.js.map +1 -0
- package/dist/map/builder.d.ts.map +1 -1
- package/dist/map/builder.js +23 -12
- package/dist/map/builder.js.map +1 -1
- package/dist/map/builder.test.d.ts +2 -0
- package/dist/map/builder.test.d.ts.map +1 -0
- package/dist/map/builder.test.js +66 -0
- package/dist/map/builder.test.js.map +1 -0
- package/dist/map/truncate.d.ts +7 -3
- package/dist/map/truncate.d.ts.map +1 -1
- package/dist/map/truncate.js +80 -11
- package/dist/map/truncate.js.map +1 -1
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +164 -65
- package/dist/scanner.js.map +1 -1
- package/dist/scanner.test.d.ts +2 -0
- package/dist/scanner.test.d.ts.map +1 -0
- package/dist/scanner.test.js +84 -0
- package/dist/scanner.test.js.map +1 -0
- package/dist/test-helpers/git-test-helpers.d.ts +13 -0
- package/dist/test-helpers/git-test-helpers.d.ts.map +1 -0
- package/dist/test-helpers/git-test-helpers.js +48 -0
- package/dist/test-helpers/git-test-helpers.js.map +1 -0
- package/dist/types.d.ts +15 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -3
- package/src/cli.ts +164 -0
- package/src/extract/definitions.test.ts +2040 -0
- package/src/extract/definitions.ts +379 -0
- package/src/extract/git-status.test.ts +507 -0
- package/src/extract/git-status.ts +359 -0
- package/src/extract/markdown.test.ts +159 -0
- package/src/extract/markdown.ts +202 -0
- package/src/extract/marker.test.ts +566 -0
- package/src/extract/marker.ts +398 -0
- package/src/extract/submodules.test.ts +95 -0
- package/src/extract/submodules.ts +269 -0
- package/src/extract/utils.ts +27 -0
- package/src/index.ts +106 -0
- package/src/languages/cpp.ts +129 -0
- package/src/languages/go.ts +72 -0
- package/src/languages/index.ts +231 -0
- package/src/languages/javascript.ts +33 -0
- package/src/languages/python.ts +41 -0
- package/src/languages/rust.ts +72 -0
- package/src/languages/typescript.ts +74 -0
- package/src/languages/zig.ts +106 -0
- package/src/logger.ts +55 -0
- package/src/map/builder.test.ts +72 -0
- package/src/map/builder.ts +175 -0
- package/src/map/truncate.ts +188 -0
- package/src/map/yaml.ts +66 -0
- package/src/parser/index.ts +53 -0
- package/src/parser/languages.ts +64 -0
- package/src/scanner.test.ts +95 -0
- package/src/scanner.ts +364 -0
- package/src/test-helpers/git-test-helpers.ts +62 -0
- package/src/types.ts +191 -0
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
// Extract top-level definitions using tree-sitter.
|
|
2
|
+
|
|
3
|
+
import type { Definition, DefinitionType, Language, SyntaxNode } from '../types.js'
|
|
4
|
+
import {
|
|
5
|
+
FUNCTION_TYPES,
|
|
6
|
+
CLASS_TYPES,
|
|
7
|
+
STRUCT_TYPES,
|
|
8
|
+
TRAIT_TYPES,
|
|
9
|
+
INTERFACE_TYPES,
|
|
10
|
+
TYPE_TYPES,
|
|
11
|
+
ENUM_TYPES,
|
|
12
|
+
CONST_TYPES,
|
|
13
|
+
extractName,
|
|
14
|
+
extractConstName,
|
|
15
|
+
isExported,
|
|
16
|
+
unwrapExport,
|
|
17
|
+
isExtern,
|
|
18
|
+
isZigConst,
|
|
19
|
+
getZigTypeDeclaration,
|
|
20
|
+
typescript,
|
|
21
|
+
} from '../languages/index.js'
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Minimum body lines for a function/class to be included in defs
|
|
25
|
+
*/
|
|
26
|
+
const MIN_BODY_LINES = 5
|
|
27
|
+
|
|
28
|
+
// ============================================================================
|
|
29
|
+
// Main extraction logic
|
|
30
|
+
// ============================================================================
|
|
31
|
+
|
|
32
|
+
interface ExtractOptions {
|
|
33
|
+
node: SyntaxNode
|
|
34
|
+
language: Language
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface ExtractInternalOptions extends ExtractOptions {
|
|
38
|
+
/** Override: node is inside extern "C" block */
|
|
39
|
+
forceExtern?: boolean
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Extract top-level definitions from a syntax tree
|
|
44
|
+
*/
|
|
45
|
+
export function extractDefinitions(
|
|
46
|
+
rootNode: SyntaxNode,
|
|
47
|
+
language: Language
|
|
48
|
+
): Definition[] {
|
|
49
|
+
const definitions: Definition[] = []
|
|
50
|
+
const seenNames = new Set<string>()
|
|
51
|
+
|
|
52
|
+
for (let i = 0; i < rootNode.childCount; i++) {
|
|
53
|
+
const node = rootNode.child(i)
|
|
54
|
+
if (!node) continue
|
|
55
|
+
|
|
56
|
+
// Handle C++ linkage_specification (extern "C" { ... })
|
|
57
|
+
if (language === 'cpp' && node.type === 'linkage_specification') {
|
|
58
|
+
for (let j = 0; j < node.childCount; j++) {
|
|
59
|
+
const inner = node.child(j)
|
|
60
|
+
if (!inner) continue
|
|
61
|
+
if (inner.type === 'extern' || inner.type === 'string_literal') continue
|
|
62
|
+
|
|
63
|
+
const defs = extractDefinition({ node: inner, language, forceExtern: true })
|
|
64
|
+
for (const def of defs) {
|
|
65
|
+
if (!seenNames.has(def.name)) {
|
|
66
|
+
definitions.push(def)
|
|
67
|
+
seenNames.add(def.name)
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
continue
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const defs = extractDefinition({ node, language })
|
|
75
|
+
for (const def of defs) {
|
|
76
|
+
if (!seenNames.has(def.name)) {
|
|
77
|
+
definitions.push(def)
|
|
78
|
+
seenNames.add(def.name)
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return definitions
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Extract definition(s) from a single node.
|
|
88
|
+
* Handles export detection, unwrapping, and multiple declarations internally.
|
|
89
|
+
*/
|
|
90
|
+
function extractDefinition(opts: ExtractInternalOptions): Definition[] {
|
|
91
|
+
const { node, language, forceExtern = false } = opts
|
|
92
|
+
|
|
93
|
+
// Determine exported status and get actual node to process
|
|
94
|
+
let exported: boolean
|
|
95
|
+
let actualNode: SyntaxNode
|
|
96
|
+
let nodeIsExtern = forceExtern
|
|
97
|
+
|
|
98
|
+
switch (language) {
|
|
99
|
+
case 'typescript':
|
|
100
|
+
case 'javascript':
|
|
101
|
+
exported = isExported(node, language)
|
|
102
|
+
actualNode = unwrapExport(node, language)
|
|
103
|
+
break
|
|
104
|
+
case 'zig':
|
|
105
|
+
exported = isExported(node, language)
|
|
106
|
+
actualNode = node
|
|
107
|
+
nodeIsExtern = nodeIsExtern || isExtern(node, language)
|
|
108
|
+
break
|
|
109
|
+
case 'rust':
|
|
110
|
+
exported = isExported(node, language)
|
|
111
|
+
actualNode = node
|
|
112
|
+
break
|
|
113
|
+
case 'go':
|
|
114
|
+
// Go: exported determined per-name (uppercase = exported)
|
|
115
|
+
// We'll handle this in createDefinition
|
|
116
|
+
exported = false // placeholder, resolved per-name
|
|
117
|
+
actualNode = node
|
|
118
|
+
break
|
|
119
|
+
case 'cpp':
|
|
120
|
+
exported = false // C++ doesn't have module exports in this sense
|
|
121
|
+
actualNode = node
|
|
122
|
+
nodeIsExtern = nodeIsExtern || isExtern(node, language)
|
|
123
|
+
break
|
|
124
|
+
case 'python':
|
|
125
|
+
default:
|
|
126
|
+
exported = false
|
|
127
|
+
actualNode = node
|
|
128
|
+
break
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const results: Definition[] = []
|
|
132
|
+
|
|
133
|
+
// Helper to resolve export status (Go uses name-based exports)
|
|
134
|
+
const resolveExported = (name: string): boolean => {
|
|
135
|
+
if (language === 'go') return isExported(node, language, name)
|
|
136
|
+
return exported
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Helper to create a definition
|
|
140
|
+
const createDef = (
|
|
141
|
+
name: string,
|
|
142
|
+
type: DefinitionType,
|
|
143
|
+
startLine: number,
|
|
144
|
+
endLine: number
|
|
145
|
+
): Definition => ({
|
|
146
|
+
name,
|
|
147
|
+
line: startLine,
|
|
148
|
+
endLine,
|
|
149
|
+
type,
|
|
150
|
+
exported: resolveExported(name),
|
|
151
|
+
...(nodeIsExtern ? { extern: true } : {})
|
|
152
|
+
})
|
|
153
|
+
|
|
154
|
+
const functionTypes = FUNCTION_TYPES[language]
|
|
155
|
+
const classTypes = CLASS_TYPES[language]
|
|
156
|
+
const structTypes = STRUCT_TYPES[language]
|
|
157
|
+
const traitTypes = TRAIT_TYPES[language]
|
|
158
|
+
const interfaceTypes = INTERFACE_TYPES[language]
|
|
159
|
+
const typeTypes = TYPE_TYPES[language]
|
|
160
|
+
const enumTypes = ENUM_TYPES[language]
|
|
161
|
+
const constTypes = CONST_TYPES[language]
|
|
162
|
+
|
|
163
|
+
// Functions
|
|
164
|
+
if (functionTypes.includes(actualNode.type)) {
|
|
165
|
+
const name = extractName(actualNode, language)
|
|
166
|
+
if (name && getBodyLineCount(actualNode) > MIN_BODY_LINES) {
|
|
167
|
+
results.push(createDef(name, 'function', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
168
|
+
}
|
|
169
|
+
return results
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Classes
|
|
173
|
+
if (classTypes.includes(actualNode.type)) {
|
|
174
|
+
const name = extractName(actualNode, language)
|
|
175
|
+
if (name && getBodyLineCount(actualNode) > MIN_BODY_LINES) {
|
|
176
|
+
results.push(createDef(name, 'class', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
177
|
+
}
|
|
178
|
+
return results
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
// Structs - only if exported
|
|
182
|
+
if (structTypes.includes(actualNode.type)) {
|
|
183
|
+
const name = extractName(actualNode, language)
|
|
184
|
+
if (name && getBodyLineCount(actualNode) > MIN_BODY_LINES && resolveExported(name)) {
|
|
185
|
+
results.push(createDef(name, 'struct', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
186
|
+
}
|
|
187
|
+
return results
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Traits - only if exported
|
|
191
|
+
if (traitTypes.includes(actualNode.type)) {
|
|
192
|
+
const name = extractName(actualNode, language)
|
|
193
|
+
if (name && getBodyLineCount(actualNode) > MIN_BODY_LINES && resolveExported(name)) {
|
|
194
|
+
results.push(createDef(name, 'trait', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
195
|
+
}
|
|
196
|
+
return results
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Interfaces - only if exported
|
|
200
|
+
if (interfaceTypes.includes(actualNode.type)) {
|
|
201
|
+
const name = extractName(actualNode, language)
|
|
202
|
+
if (name && resolveExported(name)) {
|
|
203
|
+
results.push(createDef(name, 'interface', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
204
|
+
}
|
|
205
|
+
return results
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// Type aliases - only if exported
|
|
209
|
+
if (typeTypes.includes(actualNode.type)) {
|
|
210
|
+
const name = extractName(actualNode, language)
|
|
211
|
+
if (name && resolveExported(name)) {
|
|
212
|
+
results.push(createDef(name, 'type', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
213
|
+
}
|
|
214
|
+
return results
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// Enums - only if exported
|
|
218
|
+
if (enumTypes.includes(actualNode.type)) {
|
|
219
|
+
const name = extractName(actualNode, language)
|
|
220
|
+
if (name && resolveExported(name)) {
|
|
221
|
+
results.push(createDef(name, 'enum', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
222
|
+
}
|
|
223
|
+
return results
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Constants/variables
|
|
227
|
+
if (constTypes.includes(actualNode.type)) {
|
|
228
|
+
// Zig: pub const (may be struct/enum/union or plain const)
|
|
229
|
+
if (language === 'zig') {
|
|
230
|
+
if (!exported || !isZigConst(actualNode)) {
|
|
231
|
+
return results
|
|
232
|
+
}
|
|
233
|
+
const name = extractName(actualNode, language)
|
|
234
|
+
if (name) {
|
|
235
|
+
// Use specific type if struct/enum/union, otherwise const
|
|
236
|
+
const zigType = getZigTypeDeclaration(actualNode)
|
|
237
|
+
const type = zigType ?? 'const'
|
|
238
|
+
results.push(createDef(name, type, actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
239
|
+
}
|
|
240
|
+
return results
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// TS/JS: handle arrow functions and multiple declarations
|
|
244
|
+
if (language === 'typescript' || language === 'javascript') {
|
|
245
|
+
// Non-exported: only include large arrow functions
|
|
246
|
+
if (!exported) {
|
|
247
|
+
const arrowFn = extractArrowFunction(actualNode)
|
|
248
|
+
if (arrowFn && arrowFn.bodyLines > MIN_BODY_LINES) {
|
|
249
|
+
results.push({
|
|
250
|
+
name: arrowFn.name,
|
|
251
|
+
line: arrowFn.line,
|
|
252
|
+
endLine: arrowFn.endLine,
|
|
253
|
+
type: 'function',
|
|
254
|
+
exported: false
|
|
255
|
+
})
|
|
256
|
+
}
|
|
257
|
+
return results
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Exported: extract all declarations
|
|
261
|
+
return extractJSDeclarations({ node: actualNode, language, exported, isExtern: nodeIsExtern })
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Other languages: simple const extraction - only if exported
|
|
265
|
+
const name = extractConstName(actualNode, language)
|
|
266
|
+
if (name && resolveExported(name)) {
|
|
267
|
+
results.push(createDef(name, 'const', actualNode.startPosition.row + 1, actualNode.endPosition.row + 1))
|
|
268
|
+
}
|
|
269
|
+
return results
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return results
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Extract all declarations from a TS/JS lexical_declaration
|
|
277
|
+
* Handles: const a = 1, const b = () => {}, const c = 1, d = 2
|
|
278
|
+
*/
|
|
279
|
+
function extractJSDeclarations(opts: {
|
|
280
|
+
node: SyntaxNode
|
|
281
|
+
language: Language
|
|
282
|
+
exported: boolean
|
|
283
|
+
isExtern: boolean
|
|
284
|
+
}): Definition[] {
|
|
285
|
+
const { node, exported, isExtern: nodeIsExtern } = opts
|
|
286
|
+
const results: Definition[] = []
|
|
287
|
+
|
|
288
|
+
if (node.type !== 'lexical_declaration') {
|
|
289
|
+
// Single const extraction fallback
|
|
290
|
+
const name = extractConstName(node, opts.language)
|
|
291
|
+
if (name) {
|
|
292
|
+
results.push({
|
|
293
|
+
name,
|
|
294
|
+
line: node.startPosition.row + 1,
|
|
295
|
+
endLine: node.endPosition.row + 1,
|
|
296
|
+
type: 'const',
|
|
297
|
+
exported,
|
|
298
|
+
...(nodeIsExtern ? { extern: true } : {})
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
return results
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
305
|
+
const child = node.child(i)
|
|
306
|
+
if (child?.type !== 'variable_declarator') continue
|
|
307
|
+
|
|
308
|
+
const nameNode = child.childForFieldName('name')
|
|
309
|
+
const valueNode = child.childForFieldName('value')
|
|
310
|
+
if (!nameNode) continue
|
|
311
|
+
|
|
312
|
+
const isArrowFn = valueNode?.type === 'arrow_function'
|
|
313
|
+
const type: DefinitionType = isArrowFn ? 'function' : 'const'
|
|
314
|
+
|
|
315
|
+
// Skip small arrow functions
|
|
316
|
+
if (isArrowFn && valueNode && getBodyLineCount(valueNode) <= MIN_BODY_LINES) {
|
|
317
|
+
continue
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
results.push({
|
|
321
|
+
name: nameNode.text,
|
|
322
|
+
line: child.startPosition.row + 1,
|
|
323
|
+
endLine: child.endPosition.row + 1,
|
|
324
|
+
type,
|
|
325
|
+
exported,
|
|
326
|
+
...(nodeIsExtern ? { extern: true } : {})
|
|
327
|
+
})
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return results
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// ============================================================================
|
|
334
|
+
// Utility functions
|
|
335
|
+
// ============================================================================
|
|
336
|
+
|
|
337
|
+
/**
|
|
338
|
+
* Extract arrow function assigned to const/let
|
|
339
|
+
*/
|
|
340
|
+
function extractArrowFunction(node: SyntaxNode): { name: string; line: number; endLine: number; bodyLines: number } | null {
|
|
341
|
+
if (node.type !== 'lexical_declaration') return null
|
|
342
|
+
|
|
343
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
344
|
+
const declarator = node.child(i)
|
|
345
|
+
if (declarator?.type !== 'variable_declarator') continue
|
|
346
|
+
|
|
347
|
+
const nameNode = declarator.childForFieldName('name')
|
|
348
|
+
const valueNode = declarator.childForFieldName('value')
|
|
349
|
+
|
|
350
|
+
if (nameNode && valueNode?.type === 'arrow_function') {
|
|
351
|
+
return {
|
|
352
|
+
name: nameNode.text,
|
|
353
|
+
line: node.startPosition.row + 1,
|
|
354
|
+
endLine: node.endPosition.row + 1,
|
|
355
|
+
bodyLines: getBodyLineCount(valueNode),
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
return null
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Find a child node by type
|
|
365
|
+
*/
|
|
366
|
+
function findChild(node: SyntaxNode, type: string): SyntaxNode | null {
|
|
367
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
368
|
+
const child = node.child(i)
|
|
369
|
+
if (child?.type === type) return child
|
|
370
|
+
}
|
|
371
|
+
return null
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Get the number of lines in a node's body
|
|
376
|
+
*/
|
|
377
|
+
function getBodyLineCount(node: SyntaxNode): number {
|
|
378
|
+
return node.endPosition.row - node.startPosition.row + 1
|
|
379
|
+
}
|