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.
- package/CHANGELOG.md +96 -0
- package/README.md +24 -0
- package/dist/cli.js +44 -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 +11 -4
- package/dist/extract/git-status.d.ts.map +1 -1
- package/dist/extract/git-status.js +21 -16
- 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/extract/submodules.d.ts +12 -0
- package/dist/extract/submodules.d.ts.map +1 -0
- package/dist/extract/submodules.js +234 -0
- package/dist/extract/submodules.js.map +1 -0
- package/dist/extract/submodules.test.d.ts +2 -0
- package/dist/extract/submodules.test.d.ts.map +1 -0
- package/dist/extract/submodules.test.js +84 -0
- package/dist/extract/submodules.test.js.map +1 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -9
- 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 +3 -3
- package/dist/map/builder.d.ts.map +1 -1
- package/dist/map/builder.js +59 -9
- 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 +90 -9
- package/dist/map/truncate.js.map +1 -1
- package/dist/map/yaml.d.ts.map +1 -1
- package/dist/map/yaml.js +13 -3
- package/dist/map/yaml.js.map +1 -1
- package/dist/scanner.d.ts +9 -2
- package/dist/scanner.d.ts.map +1 -1
- package/dist/scanner.js +172 -49
- 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 +42 -2
- 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,231 @@
|
|
|
1
|
+
// Language registry for agentmap.
|
|
2
|
+
// Aggregates all language-specific implementations.
|
|
3
|
+
|
|
4
|
+
import type { Language, SyntaxNode, DefinitionType } from '../types.js'
|
|
5
|
+
|
|
6
|
+
import * as typescript from './typescript.js'
|
|
7
|
+
import * as javascript from './javascript.js'
|
|
8
|
+
import * as python from './python.js'
|
|
9
|
+
import * as rust from './rust.js'
|
|
10
|
+
import * as go from './go.js'
|
|
11
|
+
import * as zig from './zig.js'
|
|
12
|
+
import * as cpp from './cpp.js'
|
|
13
|
+
|
|
14
|
+
// Re-export language modules for direct access
|
|
15
|
+
export { typescript, javascript, python, rust, go, zig, cpp }
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* All registered languages
|
|
19
|
+
*/
|
|
20
|
+
export const languages = {
|
|
21
|
+
typescript,
|
|
22
|
+
javascript,
|
|
23
|
+
python,
|
|
24
|
+
rust,
|
|
25
|
+
go,
|
|
26
|
+
zig,
|
|
27
|
+
cpp,
|
|
28
|
+
} as const
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* File extension to language mapping
|
|
32
|
+
*/
|
|
33
|
+
export const LANGUAGE_EXTENSIONS: Record<string, Language> = {
|
|
34
|
+
...Object.fromEntries(typescript.extensions.map(e => [e, 'typescript' as const])),
|
|
35
|
+
...Object.fromEntries(javascript.extensions.map(e => [e, 'javascript' as const])),
|
|
36
|
+
...Object.fromEntries(python.extensions.map(e => [e, 'python' as const])),
|
|
37
|
+
...Object.fromEntries(rust.extensions.map(e => [e, 'rust' as const])),
|
|
38
|
+
...Object.fromEntries(go.extensions.map(e => [e, 'go' as const])),
|
|
39
|
+
...Object.fromEntries(zig.extensions.map(e => [e, 'zig' as const])),
|
|
40
|
+
...Object.fromEntries(cpp.extensions.map(e => [e, 'cpp' as const])),
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Grammar paths per language
|
|
45
|
+
*/
|
|
46
|
+
export const GRAMMAR_PATHS: Record<Language, string> = {
|
|
47
|
+
typescript: typescript.grammar,
|
|
48
|
+
javascript: javascript.grammar,
|
|
49
|
+
python: python.grammar,
|
|
50
|
+
rust: rust.grammar,
|
|
51
|
+
go: go.grammar,
|
|
52
|
+
zig: zig.grammar,
|
|
53
|
+
cpp: cpp.grammar,
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Node types that represent functions per language
|
|
58
|
+
*/
|
|
59
|
+
export const FUNCTION_TYPES: Record<Language, string[]> = {
|
|
60
|
+
typescript: typescript.FUNCTION_TYPES,
|
|
61
|
+
javascript: javascript.FUNCTION_TYPES,
|
|
62
|
+
python: python.FUNCTION_TYPES,
|
|
63
|
+
rust: rust.FUNCTION_TYPES,
|
|
64
|
+
go: go.FUNCTION_TYPES,
|
|
65
|
+
zig: zig.FUNCTION_TYPES,
|
|
66
|
+
cpp: cpp.FUNCTION_TYPES,
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Node types that represent classes per language
|
|
71
|
+
*/
|
|
72
|
+
export const CLASS_TYPES: Record<Language, string[]> = {
|
|
73
|
+
typescript: typescript.CLASS_TYPES,
|
|
74
|
+
javascript: javascript.CLASS_TYPES,
|
|
75
|
+
python: python.CLASS_TYPES,
|
|
76
|
+
rust: rust.CLASS_TYPES,
|
|
77
|
+
go: go.CLASS_TYPES,
|
|
78
|
+
zig: zig.CLASS_TYPES,
|
|
79
|
+
cpp: cpp.CLASS_TYPES,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Node types that represent structs per language
|
|
84
|
+
*/
|
|
85
|
+
export const STRUCT_TYPES: Record<Language, string[]> = {
|
|
86
|
+
typescript: typescript.STRUCT_TYPES,
|
|
87
|
+
javascript: javascript.STRUCT_TYPES,
|
|
88
|
+
python: python.STRUCT_TYPES,
|
|
89
|
+
rust: rust.STRUCT_TYPES,
|
|
90
|
+
go: go.STRUCT_TYPES,
|
|
91
|
+
zig: zig.STRUCT_TYPES,
|
|
92
|
+
cpp: cpp.STRUCT_TYPES,
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Node types that represent traits per language
|
|
97
|
+
*/
|
|
98
|
+
export const TRAIT_TYPES: Record<Language, string[]> = {
|
|
99
|
+
typescript: typescript.TRAIT_TYPES,
|
|
100
|
+
javascript: javascript.TRAIT_TYPES,
|
|
101
|
+
python: python.TRAIT_TYPES,
|
|
102
|
+
rust: rust.TRAIT_TYPES,
|
|
103
|
+
go: go.TRAIT_TYPES,
|
|
104
|
+
zig: zig.TRAIT_TYPES,
|
|
105
|
+
cpp: cpp.TRAIT_TYPES,
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Node types that represent interfaces per language
|
|
110
|
+
*/
|
|
111
|
+
export const INTERFACE_TYPES: Record<Language, string[]> = {
|
|
112
|
+
typescript: typescript.INTERFACE_TYPES,
|
|
113
|
+
javascript: javascript.INTERFACE_TYPES,
|
|
114
|
+
python: python.INTERFACE_TYPES,
|
|
115
|
+
rust: rust.INTERFACE_TYPES,
|
|
116
|
+
go: go.INTERFACE_TYPES,
|
|
117
|
+
zig: zig.INTERFACE_TYPES,
|
|
118
|
+
cpp: cpp.INTERFACE_TYPES,
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Node types that represent type aliases per language
|
|
123
|
+
*/
|
|
124
|
+
export const TYPE_TYPES: Record<Language, string[]> = {
|
|
125
|
+
typescript: typescript.TYPE_TYPES,
|
|
126
|
+
javascript: javascript.TYPE_TYPES,
|
|
127
|
+
python: python.TYPE_TYPES,
|
|
128
|
+
rust: rust.TYPE_TYPES,
|
|
129
|
+
go: go.TYPE_TYPES,
|
|
130
|
+
zig: zig.TYPE_TYPES,
|
|
131
|
+
cpp: cpp.TYPE_TYPES,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Node types that represent enums per language
|
|
136
|
+
*/
|
|
137
|
+
export const ENUM_TYPES: Record<Language, string[]> = {
|
|
138
|
+
typescript: typescript.ENUM_TYPES,
|
|
139
|
+
javascript: javascript.ENUM_TYPES,
|
|
140
|
+
python: python.ENUM_TYPES,
|
|
141
|
+
rust: rust.ENUM_TYPES,
|
|
142
|
+
go: go.ENUM_TYPES,
|
|
143
|
+
zig: zig.ENUM_TYPES,
|
|
144
|
+
cpp: cpp.ENUM_TYPES,
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Node types that represent constants per language
|
|
149
|
+
*/
|
|
150
|
+
export const CONST_TYPES: Record<Language, string[]> = {
|
|
151
|
+
typescript: typescript.CONST_TYPES,
|
|
152
|
+
javascript: javascript.CONST_TYPES,
|
|
153
|
+
python: python.CONST_TYPES,
|
|
154
|
+
rust: rust.CONST_TYPES,
|
|
155
|
+
go: go.CONST_TYPES,
|
|
156
|
+
zig: zig.CONST_TYPES,
|
|
157
|
+
cpp: cpp.CONST_TYPES,
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Extract name from a node using language-specific logic
|
|
162
|
+
*/
|
|
163
|
+
export function extractName(node: SyntaxNode, language: Language): string | null {
|
|
164
|
+
// Try 'name' field first (common across languages)
|
|
165
|
+
const nameNode = node.childForFieldName('name')
|
|
166
|
+
if (nameNode) {
|
|
167
|
+
return nameNode.text
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
return languages[language].extractName(node)
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Extract name from a const/let/var declaration
|
|
175
|
+
*/
|
|
176
|
+
export function extractConstName(node: SyntaxNode, language: Language): string | null {
|
|
177
|
+
const lang = languages[language]
|
|
178
|
+
if ('extractConstName' in lang && typeof lang.extractConstName === 'function') {
|
|
179
|
+
return lang.extractConstName(node)
|
|
180
|
+
}
|
|
181
|
+
return extractName(node, language)
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Check if a node is exported (language-specific)
|
|
186
|
+
*/
|
|
187
|
+
export function isExported(node: SyntaxNode, language: Language, name?: string): boolean {
|
|
188
|
+
const lang = languages[language]
|
|
189
|
+
// Go uses name-based exports
|
|
190
|
+
if (language === 'go') {
|
|
191
|
+
return (lang as typeof go).isExported(node, name)
|
|
192
|
+
}
|
|
193
|
+
return lang.isExported(node)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Unwrap export statement to get the actual declaration (TS/JS only)
|
|
198
|
+
*/
|
|
199
|
+
export function unwrapExport(node: SyntaxNode, language: Language): SyntaxNode {
|
|
200
|
+
if (language === 'typescript' || language === 'javascript') {
|
|
201
|
+
return typescript.unwrapExport(node)
|
|
202
|
+
}
|
|
203
|
+
return node
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Check if a node has extern modifier (Zig/C++ only)
|
|
208
|
+
*/
|
|
209
|
+
export function isExtern(node: SyntaxNode, language: Language): boolean {
|
|
210
|
+
if (language === 'zig') {
|
|
211
|
+
return zig.isExtern(node)
|
|
212
|
+
}
|
|
213
|
+
if (language === 'cpp') {
|
|
214
|
+
return cpp.isExtern(node)
|
|
215
|
+
}
|
|
216
|
+
return false
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* Zig-specific: check if variable_declaration uses 'const'
|
|
221
|
+
*/
|
|
222
|
+
export function isZigConst(node: SyntaxNode): boolean {
|
|
223
|
+
return zig.isConst(node)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Zig-specific: get type declaration (struct/enum/union) from variable_declaration
|
|
228
|
+
*/
|
|
229
|
+
export function getZigTypeDeclaration(node: SyntaxNode): DefinitionType | null {
|
|
230
|
+
return zig.getTypeDeclaration(node)
|
|
231
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
// JavaScript language support for agentmap.
|
|
2
|
+
// Shares most implementation with TypeScript.
|
|
3
|
+
|
|
4
|
+
import type { SyntaxNode } from '../types.js'
|
|
5
|
+
import {
|
|
6
|
+
extractName as tsExtractName,
|
|
7
|
+
extractConstName as tsExtractConstName,
|
|
8
|
+
isExported as tsIsExported,
|
|
9
|
+
unwrapExport as tsUnwrapExport,
|
|
10
|
+
} from './typescript.js'
|
|
11
|
+
|
|
12
|
+
export const id = 'javascript' as const
|
|
13
|
+
export const extensions = ['.js', '.jsx', '.mjs', '.cjs']
|
|
14
|
+
export const grammar = 'tree-sitter-javascript/tree-sitter-javascript.wasm'
|
|
15
|
+
|
|
16
|
+
// AST node types
|
|
17
|
+
export const FUNCTION_TYPES = ['function_declaration', 'method_definition']
|
|
18
|
+
export const CLASS_TYPES = ['class_declaration']
|
|
19
|
+
export const STRUCT_TYPES: string[] = []
|
|
20
|
+
export const TRAIT_TYPES: string[] = []
|
|
21
|
+
export const INTERFACE_TYPES: string[] = []
|
|
22
|
+
export const TYPE_TYPES: string[] = []
|
|
23
|
+
export const ENUM_TYPES: string[] = []
|
|
24
|
+
export const CONST_TYPES = ['lexical_declaration']
|
|
25
|
+
|
|
26
|
+
// Reuse TypeScript implementations
|
|
27
|
+
export const isExported = tsIsExported
|
|
28
|
+
export const unwrapExport = tsUnwrapExport
|
|
29
|
+
export const extractName = tsExtractName
|
|
30
|
+
export const extractConstName = tsExtractConstName
|
|
31
|
+
|
|
32
|
+
// Comment handling
|
|
33
|
+
export const commentPrefixes = ['//', '/*']
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Python language support for agentmap.
|
|
2
|
+
|
|
3
|
+
import type { SyntaxNode } from '../types.js'
|
|
4
|
+
|
|
5
|
+
export const id = 'python' as const
|
|
6
|
+
export const extensions = ['.py', '.pyi']
|
|
7
|
+
export const grammar = 'tree-sitter-python/tree-sitter-python.wasm'
|
|
8
|
+
|
|
9
|
+
// AST node types
|
|
10
|
+
export const FUNCTION_TYPES = ['function_definition']
|
|
11
|
+
export const CLASS_TYPES = ['class_definition']
|
|
12
|
+
export const STRUCT_TYPES: string[] = []
|
|
13
|
+
export const TRAIT_TYPES: string[] = []
|
|
14
|
+
export const INTERFACE_TYPES: string[] = []
|
|
15
|
+
export const TYPE_TYPES: string[] = []
|
|
16
|
+
export const ENUM_TYPES: string[] = []
|
|
17
|
+
export const CONST_TYPES: string[] = [] // Python constants handled separately
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Python doesn't have explicit exports - everything is importable
|
|
21
|
+
*/
|
|
22
|
+
export function isExported(_node: SyntaxNode): boolean {
|
|
23
|
+
return false
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Extract name from a Python node
|
|
28
|
+
*/
|
|
29
|
+
export function extractName(node: SyntaxNode): string | null {
|
|
30
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
31
|
+
const child = node.child(i)
|
|
32
|
+
if (child?.type === 'identifier') {
|
|
33
|
+
return child.text
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Comment handling
|
|
40
|
+
export const commentPrefixes = ['#']
|
|
41
|
+
export const docstringType = 'string' // Python uses docstrings
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Rust language support for agentmap.
|
|
2
|
+
|
|
3
|
+
import type { SyntaxNode } from '../types.js'
|
|
4
|
+
|
|
5
|
+
export const id = 'rust' as const
|
|
6
|
+
export const extensions = ['.rs']
|
|
7
|
+
export const grammar = 'tree-sitter-rust/tree-sitter-rust.wasm'
|
|
8
|
+
|
|
9
|
+
// AST node types
|
|
10
|
+
export const FUNCTION_TYPES = ['function_item']
|
|
11
|
+
export const CLASS_TYPES: string[] = [] // Rust has structs/traits, not classes
|
|
12
|
+
export const STRUCT_TYPES = ['struct_item']
|
|
13
|
+
export const TRAIT_TYPES = ['trait_item']
|
|
14
|
+
export const INTERFACE_TYPES: string[] = [] // Rust traits handled in TRAIT_TYPES
|
|
15
|
+
export const TYPE_TYPES = ['type_item']
|
|
16
|
+
export const ENUM_TYPES = ['enum_item']
|
|
17
|
+
export const CONST_TYPES = ['const_item', 'static_item']
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Check if a Rust node has 'pub' visibility modifier
|
|
21
|
+
*/
|
|
22
|
+
export function isExported(node: SyntaxNode): boolean {
|
|
23
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
24
|
+
const child = node.child(i)
|
|
25
|
+
if (child?.type === 'visibility_modifier') {
|
|
26
|
+
return child.text.startsWith('pub')
|
|
27
|
+
}
|
|
28
|
+
if (child?.type === 'identifier' || child?.type === 'type_identifier') break
|
|
29
|
+
}
|
|
30
|
+
return false
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Extract name from a Rust node
|
|
35
|
+
*/
|
|
36
|
+
export function extractName(node: SyntaxNode): string | null {
|
|
37
|
+
if (node.type === 'impl_item') {
|
|
38
|
+
const typeNode = node.childForFieldName('type')
|
|
39
|
+
if (typeNode) {
|
|
40
|
+
const ident = typeNode.type === 'type_identifier'
|
|
41
|
+
? typeNode
|
|
42
|
+
: findChild(typeNode, 'type_identifier')
|
|
43
|
+
return ident?.text ?? null
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
48
|
+
const child = node.child(i)
|
|
49
|
+
if (child?.type === 'identifier' || child?.type === 'type_identifier') {
|
|
50
|
+
return child.text
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Extract name from const/static declaration
|
|
58
|
+
*/
|
|
59
|
+
export function extractConstName(node: SyntaxNode): string | null {
|
|
60
|
+
return extractName(node)
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function findChild(node: SyntaxNode, type: string): SyntaxNode | null {
|
|
64
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
65
|
+
const child = node.child(i)
|
|
66
|
+
if (child?.type === type) return child
|
|
67
|
+
}
|
|
68
|
+
return null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Comment handling
|
|
72
|
+
export const commentPrefixes = ['//', '/*', '//!', '///']
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// TypeScript language support for agentmap.
|
|
2
|
+
|
|
3
|
+
import type { SyntaxNode } from '../types.js'
|
|
4
|
+
|
|
5
|
+
export const id = 'typescript' as const
|
|
6
|
+
export const extensions = ['.ts', '.tsx', '.mts', '.cts']
|
|
7
|
+
export const grammar = 'tree-sitter-typescript/tree-sitter-tsx.wasm'
|
|
8
|
+
|
|
9
|
+
// AST node types
|
|
10
|
+
export const FUNCTION_TYPES = ['function_declaration', 'method_definition']
|
|
11
|
+
export const CLASS_TYPES = ['class_declaration', 'abstract_class_declaration']
|
|
12
|
+
export const STRUCT_TYPES: string[] = []
|
|
13
|
+
export const TRAIT_TYPES: string[] = []
|
|
14
|
+
export const INTERFACE_TYPES = ['interface_declaration']
|
|
15
|
+
export const TYPE_TYPES = ['type_alias_declaration']
|
|
16
|
+
export const ENUM_TYPES = ['enum_declaration']
|
|
17
|
+
export const CONST_TYPES = ['lexical_declaration']
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Check if a node is an export statement
|
|
21
|
+
*/
|
|
22
|
+
export function isExported(node: SyntaxNode): boolean {
|
|
23
|
+
return node.type === 'export_statement'
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Unwrap export statement to get the actual declaration
|
|
28
|
+
*/
|
|
29
|
+
export function unwrapExport(node: SyntaxNode): SyntaxNode {
|
|
30
|
+
if (node.type === 'export_statement') {
|
|
31
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
32
|
+
const child = node.child(i)
|
|
33
|
+
if (!child) continue
|
|
34
|
+
if (child.type !== 'export' && !child.type.includes('comment') && child.type !== 'default') {
|
|
35
|
+
return child
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return node
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Extract name from a TypeScript/JavaScript node
|
|
44
|
+
*/
|
|
45
|
+
export function extractName(node: SyntaxNode): string | null {
|
|
46
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
47
|
+
const child = node.child(i)
|
|
48
|
+
if (!child) continue
|
|
49
|
+
if (child.type === 'identifier' || child.type === 'type_identifier') {
|
|
50
|
+
return child.text
|
|
51
|
+
}
|
|
52
|
+
if (child.type === 'property_identifier') {
|
|
53
|
+
return child.text
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return null
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extract name from const/let declaration
|
|
61
|
+
*/
|
|
62
|
+
export function extractConstName(node: SyntaxNode): string | null {
|
|
63
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
64
|
+
const child = node.child(i)
|
|
65
|
+
if (child?.type === 'variable_declarator') {
|
|
66
|
+
const nameNode = child.childForFieldName('name')
|
|
67
|
+
return nameNode?.text ?? null
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return null
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Comment handling
|
|
74
|
+
export const commentPrefixes = ['//', '/*']
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Zig language support for agentmap.
|
|
2
|
+
|
|
3
|
+
import type { SyntaxNode, DefinitionType } from '../types.js'
|
|
4
|
+
|
|
5
|
+
export const id = 'zig' as const
|
|
6
|
+
export const extensions = ['.zig']
|
|
7
|
+
export const grammar = '@tree-sitter-grammars/tree-sitter-zig/tree-sitter-zig.wasm'
|
|
8
|
+
|
|
9
|
+
// AST node types
|
|
10
|
+
export const FUNCTION_TYPES = ['function_declaration', 'test_declaration']
|
|
11
|
+
export const CLASS_TYPES: string[] = [] // Zig has structs/unions, not classes
|
|
12
|
+
export const STRUCT_TYPES: string[] = [] // Handled via variable_declaration with struct value
|
|
13
|
+
export const TRAIT_TYPES: string[] = []
|
|
14
|
+
export const INTERFACE_TYPES: string[] = []
|
|
15
|
+
export const TYPE_TYPES: string[] = []
|
|
16
|
+
export const ENUM_TYPES: string[] = [] // Handled via variable_declaration with enum value
|
|
17
|
+
export const CONST_TYPES = ['variable_declaration']
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Check if a Zig node has 'pub' modifier
|
|
21
|
+
*/
|
|
22
|
+
export function isExported(node: SyntaxNode): boolean {
|
|
23
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
24
|
+
const child = node.child(i)
|
|
25
|
+
if (child?.type === 'pub') return true
|
|
26
|
+
if (child?.type === 'identifier' || child?.type === 'block') break
|
|
27
|
+
}
|
|
28
|
+
return false
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Check if a Zig variable_declaration uses 'const' (not 'var')
|
|
33
|
+
*/
|
|
34
|
+
export function isConst(node: SyntaxNode): boolean {
|
|
35
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
36
|
+
const child = node.child(i)
|
|
37
|
+
if (child?.type === 'const') return true
|
|
38
|
+
if (child?.type === 'var') return false
|
|
39
|
+
}
|
|
40
|
+
return false
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Check if a Zig variable_declaration contains a struct/enum/union declaration
|
|
45
|
+
*/
|
|
46
|
+
export function getTypeDeclaration(node: SyntaxNode): DefinitionType | null {
|
|
47
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
48
|
+
const child = node.child(i)
|
|
49
|
+
if (child?.type === 'struct_declaration') return 'struct'
|
|
50
|
+
if (child?.type === 'union_declaration') return 'union'
|
|
51
|
+
if (child?.type === 'enum_declaration') return 'enum'
|
|
52
|
+
}
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Check if a Zig function has 'extern' modifier
|
|
58
|
+
*/
|
|
59
|
+
export function isExtern(node: SyntaxNode): boolean {
|
|
60
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
61
|
+
const child = node.child(i)
|
|
62
|
+
if (child?.type === 'extern') return true
|
|
63
|
+
if (child?.type === 'block' || child?.type === 'fn') break
|
|
64
|
+
}
|
|
65
|
+
return false
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Extract name from a Zig node
|
|
70
|
+
*/
|
|
71
|
+
export function extractName(node: SyntaxNode): string | null {
|
|
72
|
+
if (node.type === 'test_declaration') {
|
|
73
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
74
|
+
const child = node.child(i)
|
|
75
|
+
if (child?.type === 'string') {
|
|
76
|
+
const text = child.text
|
|
77
|
+
if (text.startsWith('"') && text.endsWith('"')) {
|
|
78
|
+
return text.slice(1, -1)
|
|
79
|
+
}
|
|
80
|
+
return text
|
|
81
|
+
}
|
|
82
|
+
if (child?.type === 'identifier') {
|
|
83
|
+
return child.text
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return null
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
90
|
+
const child = node.child(i)
|
|
91
|
+
if (child?.type === 'identifier') {
|
|
92
|
+
return child.text
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return null
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Extract name from const/var declaration
|
|
100
|
+
*/
|
|
101
|
+
export function extractConstName(node: SyntaxNode): string | null {
|
|
102
|
+
return extractName(node)
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Comment handling
|
|
106
|
+
export const commentPrefixes = ['//', '/*']
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// Shared logger abstraction used by CLI and integrations.
|
|
2
|
+
|
|
3
|
+
export interface Logger {
|
|
4
|
+
debug: (...args: unknown[]) => void
|
|
5
|
+
info: (...args: unknown[]) => void
|
|
6
|
+
warn: (...args: unknown[]) => void
|
|
7
|
+
error: (...args: unknown[]) => void
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const NOOP = () => {}
|
|
11
|
+
|
|
12
|
+
const NOOP_LOGGER: Logger = {
|
|
13
|
+
debug: NOOP,
|
|
14
|
+
info: NOOP,
|
|
15
|
+
warn: NOOP,
|
|
16
|
+
error: NOOP,
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function createNoopLogger(): Logger {
|
|
20
|
+
return NOOP_LOGGER
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function formatArg(value: unknown): string {
|
|
24
|
+
if (typeof value === 'string') {
|
|
25
|
+
return value
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (value instanceof Error) {
|
|
29
|
+
return value.stack ?? value.message
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
return JSON.stringify(value)
|
|
34
|
+
} catch {
|
|
35
|
+
return String(value)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function formatLogMessage(args: unknown[]): string {
|
|
40
|
+
return args.map(formatArg).join(' ')
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function writeLine(stream: Pick<NodeJS.WriteStream, 'write'>, args: unknown[]): void {
|
|
44
|
+
const message = formatLogMessage(args)
|
|
45
|
+
stream.write(message.endsWith('\n') ? message : `${message}\n`)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function createConsoleLogger(): Logger {
|
|
49
|
+
return {
|
|
50
|
+
debug: (...args) => writeLine(process.stderr, args),
|
|
51
|
+
info: (...args) => writeLine(process.stderr, args),
|
|
52
|
+
warn: (...args) => writeLine(process.stderr, args),
|
|
53
|
+
error: (...args) => writeLine(process.stderr, args),
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Tests for building nested map nodes for recursive submodule trees.
|
|
2
|
+
|
|
3
|
+
import { describe, expect, test } from 'bun:test'
|
|
4
|
+
import { buildMap } from './builder.js'
|
|
5
|
+
|
|
6
|
+
describe('buildMap with recursive submodules', () => {
|
|
7
|
+
test('renders submodule metadata and nested files under the same node', () => {
|
|
8
|
+
const map = buildMap(
|
|
9
|
+
[
|
|
10
|
+
{
|
|
11
|
+
relativePath: 'README.md',
|
|
12
|
+
description: 'Root repo\nRoot README.',
|
|
13
|
+
definitions: [],
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
relativePath: 'vendor/child-lib/README.md',
|
|
17
|
+
description: 'Child repo\nChild README.',
|
|
18
|
+
definitions: [],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
relativePath: 'vendor/child-lib/deps/nested-lib/README.md',
|
|
22
|
+
description: 'Nested repo\nNested README.',
|
|
23
|
+
definitions: [],
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
'repo',
|
|
27
|
+
[
|
|
28
|
+
{
|
|
29
|
+
path: 'vendor/child-lib',
|
|
30
|
+
commit: 'abc1234',
|
|
31
|
+
branch: undefined,
|
|
32
|
+
dirty: false,
|
|
33
|
+
initialized: true,
|
|
34
|
+
url: undefined,
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
path: 'vendor/child-lib/deps/nested-lib',
|
|
38
|
+
commit: 'def5678',
|
|
39
|
+
branch: undefined,
|
|
40
|
+
dirty: true,
|
|
41
|
+
initialized: true,
|
|
42
|
+
url: undefined,
|
|
43
|
+
},
|
|
44
|
+
]
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
expect(map).toEqual({
|
|
48
|
+
repo: {
|
|
49
|
+
'README.md': {
|
|
50
|
+
description: 'Root repo\nRoot README.',
|
|
51
|
+
},
|
|
52
|
+
vendor: {
|
|
53
|
+
'child-lib': {
|
|
54
|
+
'README.md': {
|
|
55
|
+
description: 'Child repo\nChild README.',
|
|
56
|
+
},
|
|
57
|
+
deps: {
|
|
58
|
+
'nested-lib': {
|
|
59
|
+
'README.md': {
|
|
60
|
+
description: 'Nested repo\nNested README.',
|
|
61
|
+
},
|
|
62
|
+
dirty: 'modified',
|
|
63
|
+
submodule: 'detached @ def5678',
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
submodule: 'detached @ abc1234',
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
})
|
|
71
|
+
})
|
|
72
|
+
})
|