@danielblomma/cortex-mcp 1.3.1 → 1.4.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 (154) hide show
  1. package/README.md +62 -14
  2. package/package.json +2 -2
  3. package/scaffold/mcp/package-lock.json +3 -7
  4. package/scaffold/mcp/package.json +1 -1
  5. package/scaffold/scripts/dashboard.mjs +15 -1
  6. package/scaffold/scripts/doctor.sh +64 -10
  7. package/scaffold/scripts/ingest.mjs +323 -50
  8. package/scaffold/scripts/parsers/bash-treesitter.mjs +229 -0
  9. package/scaffold/scripts/parsers/cpp-dispatch.mjs +56 -0
  10. package/scaffold/scripts/parsers/cpp-treesitter.mjs +333 -0
  11. package/scaffold/scripts/parsers/csharp.mjs +197 -10
  12. package/scaffold/scripts/parsers/dotnet/CSharpParser/CSharpParser.csproj +1 -0
  13. package/scaffold/scripts/parsers/dotnet/CSharpParser/Program.cs +126 -21
  14. package/scaffold/scripts/parsers/go-treesitter.mjs +283 -0
  15. package/scaffold/scripts/parsers/java-treesitter.mjs +250 -0
  16. package/scaffold/scripts/parsers/javascript/ast.mjs +118 -12
  17. package/scaffold/scripts/parsers/javascript/chunks.mjs +4 -0
  18. package/scaffold/scripts/parsers/javascript/patterns.mjs +6 -0
  19. package/scaffold/scripts/parsers/javascript.mjs +4 -19
  20. package/scaffold/scripts/parsers/node_modules/.package-lock.json +57 -0
  21. package/scaffold/scripts/parsers/node_modules/acorn/CHANGELOG.md +972 -0
  22. package/scaffold/scripts/parsers/node_modules/acorn/LICENSE +21 -0
  23. package/scaffold/scripts/parsers/node_modules/acorn/README.md +301 -0
  24. package/scaffold/scripts/parsers/node_modules/acorn/bin/acorn +4 -0
  25. package/scaffold/scripts/parsers/node_modules/acorn/dist/acorn.d.mts +883 -0
  26. package/scaffold/scripts/parsers/node_modules/acorn/dist/acorn.d.ts +883 -0
  27. package/scaffold/scripts/parsers/node_modules/acorn/dist/acorn.js +6295 -0
  28. package/scaffold/scripts/parsers/node_modules/acorn/dist/acorn.mjs +6266 -0
  29. package/scaffold/scripts/parsers/node_modules/acorn/dist/bin.js +90 -0
  30. package/scaffold/scripts/parsers/node_modules/acorn/package.json +50 -0
  31. package/scaffold/scripts/parsers/node_modules/acorn-typescript/CHANGELOG.md +421 -0
  32. package/scaffold/scripts/parsers/node_modules/acorn-typescript/LICENSE +21 -0
  33. package/scaffold/scripts/parsers/node_modules/acorn-typescript/README.md +81 -0
  34. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/error.d.ts +103 -0
  35. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/error.js +78 -0
  36. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/error.js.map +1 -0
  37. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/decorators.d.ts +167 -0
  38. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/decorators.js +75 -0
  39. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/decorators.js.map +1 -0
  40. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/import-assertions.d.ts +177 -0
  41. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/import-assertions.js +56 -0
  42. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/import-assertions.js.map +1 -0
  43. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/jsx/index.d.ts +198 -0
  44. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/jsx/index.js +327 -0
  45. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/jsx/index.js.map +1 -0
  46. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/jsx/xhtml.d.ts +256 -0
  47. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/jsx/xhtml.js +256 -0
  48. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/extentions/jsx/xhtml.js.map +1 -0
  49. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/index.d.ts +472 -0
  50. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/index.js +1 -0
  51. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/index.js.map +1 -0
  52. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/index.mjs +1 -0
  53. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/middleware.d.ts +159 -0
  54. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/middleware.js +2 -0
  55. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/middleware.js.map +1 -0
  56. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/parseutil.d.ts +10 -0
  57. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/parseutil.js +38 -0
  58. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/parseutil.js.map +1 -0
  59. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/scopeflags.d.ts +12 -0
  60. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/scopeflags.js +29 -0
  61. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/scopeflags.js.map +1 -0
  62. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/tokenType.d.ts +2 -0
  63. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/tokenType.js +118 -0
  64. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/tokenType.js.map +1 -0
  65. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/types.d.ts +60 -0
  66. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/types.js +2 -0
  67. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/types.js.map +1 -0
  68. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/whitespace.d.ts +2 -0
  69. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/whitespace.js +19 -0
  70. package/scaffold/scripts/parsers/node_modules/acorn-typescript/lib/whitespace.js.map +1 -0
  71. package/scaffold/scripts/parsers/node_modules/acorn-typescript/package.json +53 -0
  72. package/scaffold/scripts/parsers/node_modules/acorn-typescript/tsconfig.json +19 -0
  73. package/scaffold/scripts/parsers/node_modules/acorn-walk/CHANGELOG.md +209 -0
  74. package/scaffold/scripts/parsers/node_modules/acorn-walk/LICENSE +21 -0
  75. package/scaffold/scripts/parsers/node_modules/acorn-walk/README.md +124 -0
  76. package/scaffold/scripts/parsers/node_modules/acorn-walk/dist/walk.d.mts +152 -0
  77. package/scaffold/scripts/parsers/node_modules/acorn-walk/dist/walk.d.ts +152 -0
  78. package/scaffold/scripts/parsers/node_modules/acorn-walk/dist/walk.js +485 -0
  79. package/scaffold/scripts/parsers/node_modules/acorn-walk/dist/walk.mjs +467 -0
  80. package/scaffold/scripts/parsers/node_modules/acorn-walk/package.json +50 -0
  81. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/LICENSE +24 -0
  82. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/README.md +23 -0
  83. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-bash.wasm +0 -0
  84. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-c.wasm +0 -0
  85. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-c_sharp.wasm +0 -0
  86. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-cpp.wasm +0 -0
  87. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-css.wasm +0 -0
  88. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-dart.wasm +0 -0
  89. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-elisp.wasm +0 -0
  90. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-elixir.wasm +0 -0
  91. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-elm.wasm +0 -0
  92. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-embedded_template.wasm +0 -0
  93. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-go.wasm +0 -0
  94. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-html.wasm +0 -0
  95. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-java.wasm +0 -0
  96. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-javascript.wasm +0 -0
  97. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-json.wasm +0 -0
  98. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-kotlin.wasm +0 -0
  99. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-lua.wasm +0 -0
  100. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-objc.wasm +0 -0
  101. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-ocaml.wasm +0 -0
  102. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-php.wasm +0 -0
  103. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-python.wasm +0 -0
  104. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-ql.wasm +0 -0
  105. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-rescript.wasm +0 -0
  106. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-ruby.wasm +0 -0
  107. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-rust.wasm +0 -0
  108. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-scala.wasm +0 -0
  109. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-solidity.wasm +0 -0
  110. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-swift.wasm +0 -0
  111. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-systemrdl.wasm +0 -0
  112. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-tlaplus.wasm +0 -0
  113. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-toml.wasm +0 -0
  114. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-tsx.wasm +0 -0
  115. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-typescript.wasm +0 -0
  116. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-vue.wasm +0 -0
  117. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-yaml.wasm +0 -0
  118. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/out/tree-sitter-zig.wasm +0 -0
  119. package/scaffold/scripts/parsers/node_modules/tree-sitter-wasms/package.json +64 -0
  120. package/scaffold/scripts/parsers/node_modules/web-tree-sitter/LICENSE +21 -0
  121. package/scaffold/scripts/parsers/node_modules/web-tree-sitter/README.md +198 -0
  122. package/scaffold/scripts/parsers/node_modules/web-tree-sitter/package.json +37 -0
  123. package/scaffold/scripts/parsers/node_modules/web-tree-sitter/tree-sitter-web.d.ts +242 -0
  124. package/scaffold/scripts/parsers/node_modules/web-tree-sitter/tree-sitter.js +1 -0
  125. package/scaffold/scripts/parsers/node_modules/web-tree-sitter/tree-sitter.wasm +0 -0
  126. package/scaffold/scripts/parsers/package-lock.json +19 -1
  127. package/scaffold/scripts/parsers/package.json +3 -1
  128. package/scaffold/scripts/parsers/python-treesitter.mjs +271 -0
  129. package/scaffold/scripts/parsers/ruby-treesitter.mjs +271 -0
  130. package/scaffold/scripts/parsers/rust-dispatch.mjs +43 -0
  131. package/scaffold/scripts/parsers/rust-treesitter.mjs +291 -0
  132. package/scaffold/scripts/parsers/tree-sitter/base.mjs +163 -0
  133. package/scaffold/scripts/parsers/tree-sitter/queries/bash.calls.scm +7 -0
  134. package/scaffold/scripts/parsers/tree-sitter/queries/bash.chunks.scm +6 -0
  135. package/scaffold/scripts/parsers/tree-sitter/queries/bash.imports.scm +5 -0
  136. package/scaffold/scripts/parsers/tree-sitter/queries/cpp.calls.scm +17 -0
  137. package/scaffold/scripts/parsers/tree-sitter/queries/cpp.chunks.scm +30 -0
  138. package/scaffold/scripts/parsers/tree-sitter/queries/cpp.imports.scm +6 -0
  139. package/scaffold/scripts/parsers/tree-sitter/queries/go.calls.scm +11 -0
  140. package/scaffold/scripts/parsers/tree-sitter/queries/go.chunks.scm +19 -0
  141. package/scaffold/scripts/parsers/tree-sitter/queries/go.imports.scm +6 -0
  142. package/scaffold/scripts/parsers/tree-sitter/queries/java.calls.scm +6 -0
  143. package/scaffold/scripts/parsers/tree-sitter/queries/java.chunks.scm +23 -0
  144. package/scaffold/scripts/parsers/tree-sitter/queries/java.imports.scm +6 -0
  145. package/scaffold/scripts/parsers/tree-sitter/queries/python.calls.scm +11 -0
  146. package/scaffold/scripts/parsers/tree-sitter/queries/python.chunks.scm +11 -0
  147. package/scaffold/scripts/parsers/tree-sitter/queries/python.imports.scm +13 -0
  148. package/scaffold/scripts/parsers/tree-sitter/queries/ruby.calls.scm +6 -0
  149. package/scaffold/scripts/parsers/tree-sitter/queries/ruby.chunks.scm +16 -0
  150. package/scaffold/scripts/parsers/tree-sitter/queries/ruby.imports.scm +8 -0
  151. package/scaffold/scripts/parsers/tree-sitter/queries/rust.calls.scm +31 -0
  152. package/scaffold/scripts/parsers/tree-sitter/queries/rust.chunks.scm +29 -0
  153. package/scaffold/scripts/parsers/tree-sitter/queries/rust.imports.scm +5 -0
  154. package/scaffold/scripts/parsers/vb6.mjs +395 -0
@@ -0,0 +1,283 @@
1
+ /**
2
+ * Tree-sitter Go parser for Cortex.
3
+ *
4
+ * Extracts function_declaration, method_declaration (with receiver),
5
+ * and type_declaration (struct/interface/type alias) as chunks.
6
+ *
7
+ * Naming:
8
+ * top-level function: name = "Parse"
9
+ * method on T: name = "T.Method"
10
+ * method on *T: name = "T.Method" (pointer vs value unified)
11
+ * struct type: name = "Config" (kind = "struct")
12
+ * interface type: name = "Handler" (kind = "interface")
13
+ * other type: name = "UserID" (kind = "type")
14
+ *
15
+ * Exported: true when the name starts with an upper-case letter (Go convention).
16
+ *
17
+ * parseCode is async; the WASM grammar is lazily loaded on first call
18
+ * and cached for subsequent calls.
19
+ */
20
+
21
+ import path from "node:path";
22
+ import fs from "node:fs";
23
+ import { fileURLToPath } from "node:url";
24
+ import {
25
+ dedupe,
26
+ initTreeSitter,
27
+ lineRangeOf,
28
+ loadGrammar,
29
+ parseSource,
30
+ runQuery
31
+ } from "./tree-sitter/base.mjs";
32
+
33
+ const __filename = fileURLToPath(import.meta.url);
34
+ const __dirname = path.dirname(__filename);
35
+ const QUERY_DIR = path.join(__dirname, "tree-sitter", "queries");
36
+
37
+ let GO_LANG = null;
38
+ let langPromise = null;
39
+
40
+ async function ensureLanguage() {
41
+ if (GO_LANG) return GO_LANG;
42
+ if (!langPromise) {
43
+ langPromise = (async () => {
44
+ await initTreeSitter();
45
+ GO_LANG = await loadGrammar("go");
46
+ return GO_LANG;
47
+ })();
48
+ }
49
+ await langPromise;
50
+ return GO_LANG;
51
+ }
52
+
53
+ export async function isAvailable() {
54
+ try {
55
+ await ensureLanguage();
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ }
61
+
62
+ const CHUNK_QUERY = fs.readFileSync(path.join(QUERY_DIR, "go.chunks.scm"), "utf8");
63
+ const CALL_QUERY = fs.readFileSync(path.join(QUERY_DIR, "go.calls.scm"), "utf8");
64
+ const IMPORT_QUERY = fs.readFileSync(path.join(QUERY_DIR, "go.imports.scm"), "utf8");
65
+
66
+ const CALL_FILTER = new Set([
67
+ "make", "new", "len", "cap", "append", "copy", "delete",
68
+ "panic", "recover", "print", "println", "close",
69
+ "int", "int32", "int64", "float32", "float64", "string",
70
+ "byte", "rune", "bool", "complex", "real", "imag"
71
+ ]);
72
+
73
+ function normalizeWhitespace(value) {
74
+ return String(value).replace(/\s+/g, " ").trim();
75
+ }
76
+
77
+ function signatureOfDecl(node) {
78
+ const braceIndex = node.text.indexOf("{");
79
+ if (braceIndex === -1) return normalizeWhitespace(node.text);
80
+ return normalizeWhitespace(node.text.slice(0, braceIndex));
81
+ }
82
+
83
+ function unquoteStringLiteral(text) {
84
+ if (text.length >= 2 && (text.startsWith('"') || text.startsWith("`"))) {
85
+ return text.slice(1, -1);
86
+ }
87
+ return text;
88
+ }
89
+
90
+ function isExported(name) {
91
+ if (!name || name.length === 0) return false;
92
+ const first = name[0];
93
+ return first >= "A" && first <= "Z";
94
+ }
95
+
96
+ function collectImports(rootNode) {
97
+ const captures = runQuery(GO_LANG, IMPORT_QUERY, rootNode);
98
+ const imports = captures
99
+ .filter((c) => c.name === "import.path")
100
+ .map((c) => unquoteStringLiteral(c.node.text));
101
+ return dedupe(imports);
102
+ }
103
+
104
+ function collectCallsInNode(node) {
105
+ const captures = runQuery(GO_LANG, CALL_QUERY, node);
106
+ const names = captures
107
+ .filter((c) => c.name === "call.name")
108
+ .map((c) => c.node.text)
109
+ .filter((name) => name && !CALL_FILTER.has(name));
110
+ return dedupe(names);
111
+ }
112
+
113
+ /**
114
+ * Return the receiver type name for a method_declaration, ignoring
115
+ * pointer-vs-value distinction. `func (r *Foo) M()` and `func (r Foo) M()`
116
+ * both return "Foo".
117
+ */
118
+ function receiverTypeOf(methodNode) {
119
+ // First parameter_list is the receiver — walk for pointer_type or type_identifier.
120
+ for (let i = 0; i < methodNode.namedChildCount; i += 1) {
121
+ const child = methodNode.namedChild(i);
122
+ if (child.type !== "parameter_list") continue;
123
+ for (let j = 0; j < child.namedChildCount; j += 1) {
124
+ const param = child.namedChild(j);
125
+ if (param.type !== "parameter_declaration") continue;
126
+ for (let k = 0; k < param.namedChildCount; k += 1) {
127
+ const typeNode = param.namedChild(k);
128
+ if (typeNode.type === "pointer_type") {
129
+ for (let m = 0; m < typeNode.namedChildCount; m += 1) {
130
+ const inner = typeNode.namedChild(m);
131
+ if (inner.type === "type_identifier") return inner.text;
132
+ }
133
+ }
134
+ if (typeNode.type === "type_identifier") return typeNode.text;
135
+ // generic receivers look like generic_type with inner type_identifier
136
+ if (typeNode.type === "generic_type") {
137
+ for (let m = 0; m < typeNode.namedChildCount; m += 1) {
138
+ const inner = typeNode.namedChild(m);
139
+ if (inner.type === "type_identifier") return inner.text;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ break;
145
+ }
146
+ return "";
147
+ }
148
+
149
+ /**
150
+ * Classify a type_declaration's kind. Inspects the body of the type_spec
151
+ * (or type_alias) child to decide: struct, interface, or generic "type".
152
+ */
153
+ function typeKindOf(declNode) {
154
+ for (let i = 0; i < declNode.namedChildCount; i += 1) {
155
+ const spec = declNode.namedChild(i);
156
+ if (spec.type !== "type_spec" && spec.type !== "type_alias") continue;
157
+ for (let j = 0; j < spec.namedChildCount; j += 1) {
158
+ const child = spec.namedChild(j);
159
+ if (child.type === "struct_type") return "struct";
160
+ if (child.type === "interface_type") return "interface";
161
+ }
162
+ }
163
+ return "type";
164
+ }
165
+
166
+ function buildFunctionChunk(node, imports, language) {
167
+ const nameNode = node.childForFieldName("name");
168
+ if (!nameNode) return null;
169
+ const name = nameNode.text;
170
+ const { startLine, endLine } = lineRangeOf(node);
171
+ return {
172
+ name,
173
+ kind: "function",
174
+ signature: signatureOfDecl(node),
175
+ body: node.text,
176
+ startLine,
177
+ endLine,
178
+ language,
179
+ exported: isExported(name),
180
+ calls: collectCallsInNode(node),
181
+ imports
182
+ };
183
+ }
184
+
185
+ function buildMethodChunk(node, imports, language) {
186
+ const nameNode = node.childForFieldName("name");
187
+ if (!nameNode) return null;
188
+ const methodName = nameNode.text;
189
+ const receiver = receiverTypeOf(node);
190
+ const qualifiedName = receiver ? `${receiver}.${methodName}` : methodName;
191
+ const { startLine, endLine } = lineRangeOf(node);
192
+ return {
193
+ name: qualifiedName,
194
+ kind: "method",
195
+ signature: signatureOfDecl(node),
196
+ body: node.text,
197
+ startLine,
198
+ endLine,
199
+ language,
200
+ exported: isExported(methodName),
201
+ calls: collectCallsInNode(node),
202
+ imports
203
+ };
204
+ }
205
+
206
+ function buildTypeChunk(node, nameNode, language) {
207
+ const name = nameNode.text;
208
+ const kind = typeKindOf(node);
209
+ const { startLine, endLine } = lineRangeOf(node);
210
+ return {
211
+ name,
212
+ kind,
213
+ signature: signatureOfDecl(node),
214
+ body: node.text,
215
+ startLine,
216
+ endLine,
217
+ language,
218
+ exported: isExported(name),
219
+ calls: [],
220
+ imports: []
221
+ };
222
+ }
223
+
224
+ export async function parseCode(code, filePath, language = "go") {
225
+ await ensureLanguage();
226
+ const { tree } = parseSource(GO_LANG, code);
227
+ const root = tree.rootNode;
228
+ const imports = collectImports(root);
229
+
230
+ const captures = runQuery(GO_LANG, CHUNK_QUERY, root);
231
+ const declCaptures = captures.filter((c) => c.name.endsWith(".decl"));
232
+
233
+ const nameCaptures = captures.filter((c) => c.name.endsWith(".name"));
234
+
235
+ const chunks = [];
236
+ for (const cap of declCaptures) {
237
+ const kind = cap.name.split(".")[0];
238
+ if (kind === "fn") {
239
+ const chunk = buildFunctionChunk(cap.node, imports, language);
240
+ if (chunk) chunks.push(chunk);
241
+ } else if (kind === "method") {
242
+ const chunk = buildMethodChunk(cap.node, imports, language);
243
+ if (chunk) chunks.push(chunk);
244
+ } else if (kind === "type") {
245
+ let nameNode = null;
246
+ let smallest = Infinity;
247
+ for (const nc of nameCaptures) {
248
+ if (nc.name !== "type.name") continue;
249
+ if (nc.node.startIndex < cap.node.startIndex) continue;
250
+ if (nc.node.endIndex > cap.node.endIndex) continue;
251
+ const size = nc.node.endIndex - nc.node.startIndex;
252
+ if (size < smallest) {
253
+ smallest = size;
254
+ nameNode = nc.node;
255
+ }
256
+ }
257
+ if (!nameNode) continue;
258
+ const chunk = buildTypeChunk(cap.node, nameNode, language);
259
+ if (chunk) chunks.push(chunk);
260
+ }
261
+ }
262
+
263
+ const seen = new Set();
264
+ const deduped = chunks.filter((chunk) => {
265
+ const key = `${chunk.kind}|${chunk.name}|${chunk.startLine}|${chunk.endLine}`;
266
+ if (seen.has(key)) return false;
267
+ seen.add(key);
268
+ return true;
269
+ });
270
+
271
+ return { chunks: deduped, errors: [] };
272
+ }
273
+
274
+ if (import.meta.url === `file://${process.argv[1]}`) {
275
+ const target = process.argv[2];
276
+ if (!target) {
277
+ console.error("Usage: go-treesitter.mjs <file.go>");
278
+ process.exit(1);
279
+ }
280
+ const code = fs.readFileSync(target, "utf8");
281
+ const result = await parseCode(code, target, "go");
282
+ console.log(JSON.stringify(result, null, 2));
283
+ }
@@ -0,0 +1,250 @@
1
+ /**
2
+ * Tree-sitter Java parser for Cortex.
3
+ *
4
+ * Extracts class/interface/enum/record declarations, methods, and
5
+ * constructors as chunks. Methods and constructors are qualified by
6
+ * the enclosing type path, so `Outer.Inner.deep()` becomes
7
+ * "Outer.Inner.deep" and `Svc(int n)` becomes "Svc.ctor".
8
+ *
9
+ * Naming conventions (match other Cortex parsers):
10
+ * class/interface/enum/record: name = "Foo"
11
+ * nested type: name = "Outer.Inner"
12
+ * method: name = "Class.method"
13
+ * method in nested: name = "Outer.Inner.method"
14
+ * constructor: name = "Class.ctor" (matches C# style)
15
+ *
16
+ * exported: true when modifiers include `public`. Package-private and
17
+ * protected count as not-exported for Cortex's find-callers purposes.
18
+ *
19
+ * parseCode is async; the WASM grammar is lazily loaded on first call
20
+ * and cached for subsequent calls.
21
+ */
22
+
23
+ import path from "node:path";
24
+ import fs from "node:fs";
25
+ import { fileURLToPath } from "node:url";
26
+ import {
27
+ dedupe,
28
+ initTreeSitter,
29
+ lineRangeOf,
30
+ loadGrammar,
31
+ parseSource,
32
+ runQuery
33
+ } from "./tree-sitter/base.mjs";
34
+
35
+ const __filename = fileURLToPath(import.meta.url);
36
+ const __dirname = path.dirname(__filename);
37
+ const QUERY_DIR = path.join(__dirname, "tree-sitter", "queries");
38
+
39
+ let JAVA_LANG = null;
40
+ let langPromise = null;
41
+
42
+ async function ensureLanguage() {
43
+ if (JAVA_LANG) return JAVA_LANG;
44
+ if (!langPromise) {
45
+ langPromise = (async () => {
46
+ await initTreeSitter();
47
+ JAVA_LANG = await loadGrammar("java");
48
+ return JAVA_LANG;
49
+ })();
50
+ }
51
+ await langPromise;
52
+ return JAVA_LANG;
53
+ }
54
+
55
+ export async function isAvailable() {
56
+ try {
57
+ await ensureLanguage();
58
+ return true;
59
+ } catch {
60
+ return false;
61
+ }
62
+ }
63
+
64
+ const CHUNK_QUERY = fs.readFileSync(path.join(QUERY_DIR, "java.chunks.scm"), "utf8");
65
+ const CALL_QUERY = fs.readFileSync(path.join(QUERY_DIR, "java.calls.scm"), "utf8");
66
+ const IMPORT_QUERY = fs.readFileSync(path.join(QUERY_DIR, "java.imports.scm"), "utf8");
67
+
68
+ // Keywords that parse as method_invocation in some grammars but
69
+ // aren't real call edges for our purposes.
70
+ const CALL_FILTER = new Set([
71
+ "super", "this"
72
+ ]);
73
+
74
+ function normalizeWhitespace(value) {
75
+ return String(value).replace(/\s+/g, " ").trim();
76
+ }
77
+
78
+ function signatureOfDecl(node) {
79
+ const braceIndex = node.text.indexOf("{");
80
+ const semiIndex = node.text.indexOf(";");
81
+ const end = braceIndex === -1 ? semiIndex : (semiIndex === -1 ? braceIndex : Math.min(braceIndex, semiIndex));
82
+ if (end === -1) return normalizeWhitespace(node.text);
83
+ return normalizeWhitespace(node.text.slice(0, end));
84
+ }
85
+
86
+ function hasPublicModifier(node) {
87
+ for (let i = 0; i < node.namedChildCount; i += 1) {
88
+ const child = node.namedChild(i);
89
+ if (child.type !== "modifiers") continue;
90
+ if (child.text.includes("public")) return true;
91
+ return false;
92
+ }
93
+ return false;
94
+ }
95
+
96
+ function enclosingTypePath(node) {
97
+ const path = [];
98
+ let cur = node.parent;
99
+ while (cur && cur.type !== "program") {
100
+ if (
101
+ cur.type === "class_declaration" ||
102
+ cur.type === "interface_declaration" ||
103
+ cur.type === "enum_declaration" ||
104
+ cur.type === "record_declaration"
105
+ ) {
106
+ const nameNode = cur.childForFieldName("name");
107
+ if (nameNode) path.unshift(nameNode.text);
108
+ }
109
+ cur = cur.parent;
110
+ }
111
+ return path;
112
+ }
113
+
114
+ function collectCallsInNode(node) {
115
+ const captures = runQuery(JAVA_LANG, CALL_QUERY, node);
116
+ const names = captures
117
+ .filter((c) => c.name === "call.name")
118
+ .map((c) => c.node.text)
119
+ .filter((name) => name && !CALL_FILTER.has(name));
120
+ return dedupe(names);
121
+ }
122
+
123
+ function collectImports(rootNode) {
124
+ const captures = runQuery(JAVA_LANG, IMPORT_QUERY, rootNode);
125
+ const imports = [];
126
+ for (const cap of captures) {
127
+ if (cap.name !== "import.decl") continue;
128
+ const decl = cap.node;
129
+ // decl.text looks like `import java.util.List;` or
130
+ // `import static java.lang.Math.PI;` or `import java.util.*;`.
131
+ // Strip `import`, optional `static`, and trailing semicolon.
132
+ let text = decl.text.trim();
133
+ if (text.endsWith(";")) text = text.slice(0, -1).trim();
134
+ if (text.startsWith("import")) text = text.slice("import".length).trim();
135
+ if (text.startsWith("static ")) text = text.slice("static".length).trim();
136
+ imports.push(text);
137
+ }
138
+ return dedupe(imports);
139
+ }
140
+
141
+ function buildTypeChunk(node, kind, imports, language) {
142
+ const nameNode = node.childForFieldName("name");
143
+ if (!nameNode) return null;
144
+ const baseName = nameNode.text;
145
+ const parentPath = enclosingTypePath(node);
146
+ const qualifiedName = parentPath.length > 0
147
+ ? `${parentPath.join(".")}.${baseName}`
148
+ : baseName;
149
+ const { startLine, endLine } = lineRangeOf(node);
150
+ return {
151
+ name: qualifiedName,
152
+ kind,
153
+ signature: signatureOfDecl(node),
154
+ body: node.text,
155
+ startLine,
156
+ endLine,
157
+ language,
158
+ exported: hasPublicModifier(node),
159
+ calls: [],
160
+ imports: []
161
+ };
162
+ }
163
+
164
+ function buildMethodChunk(node, imports, language) {
165
+ const nameNode = node.childForFieldName("name");
166
+ if (!nameNode) return null;
167
+ const methodName = nameNode.text;
168
+ const parentPath = enclosingTypePath(node);
169
+ const qualifiedName = parentPath.length > 0
170
+ ? `${parentPath.join(".")}.${methodName}`
171
+ : methodName;
172
+ const { startLine, endLine } = lineRangeOf(node);
173
+ return {
174
+ name: qualifiedName,
175
+ kind: "method",
176
+ signature: signatureOfDecl(node),
177
+ body: node.text,
178
+ startLine,
179
+ endLine,
180
+ language,
181
+ exported: hasPublicModifier(node),
182
+ calls: collectCallsInNode(node),
183
+ imports
184
+ };
185
+ }
186
+
187
+ function buildConstructorChunk(node, imports, language) {
188
+ const nameNode = node.childForFieldName("name");
189
+ if (!nameNode) return null;
190
+ const parentPath = enclosingTypePath(node);
191
+ const classPath = parentPath.length > 0 ? parentPath.join(".") : nameNode.text;
192
+ const qualifiedName = `${classPath}.ctor`;
193
+ const { startLine, endLine } = lineRangeOf(node);
194
+ return {
195
+ name: qualifiedName,
196
+ kind: "constructor",
197
+ signature: signatureOfDecl(node),
198
+ body: node.text,
199
+ startLine,
200
+ endLine,
201
+ language,
202
+ exported: hasPublicModifier(node),
203
+ calls: collectCallsInNode(node),
204
+ imports
205
+ };
206
+ }
207
+
208
+ export async function parseCode(code, filePath, language = "java") {
209
+ await ensureLanguage();
210
+ const { tree } = parseSource(JAVA_LANG, code);
211
+ const root = tree.rootNode;
212
+ const imports = collectImports(root);
213
+
214
+ const captures = runQuery(JAVA_LANG, CHUNK_QUERY, root);
215
+ const declCaptures = captures.filter((c) => c.name.endsWith(".decl"));
216
+
217
+ const chunks = [];
218
+ for (const cap of declCaptures) {
219
+ const kind = cap.name.split(".")[0];
220
+ let chunk = null;
221
+ if (kind === "class") chunk = buildTypeChunk(cap.node, "class", imports, language);
222
+ else if (kind === "interface") chunk = buildTypeChunk(cap.node, "interface", imports, language);
223
+ else if (kind === "enum") chunk = buildTypeChunk(cap.node, "enum", imports, language);
224
+ else if (kind === "record") chunk = buildTypeChunk(cap.node, "record", imports, language);
225
+ else if (kind === "method") chunk = buildMethodChunk(cap.node, imports, language);
226
+ else if (kind === "ctor") chunk = buildConstructorChunk(cap.node, imports, language);
227
+ if (chunk) chunks.push(chunk);
228
+ }
229
+
230
+ const seen = new Set();
231
+ const deduped = chunks.filter((chunk) => {
232
+ const key = `${chunk.kind}|${chunk.name}|${chunk.startLine}|${chunk.endLine}`;
233
+ if (seen.has(key)) return false;
234
+ seen.add(key);
235
+ return true;
236
+ });
237
+
238
+ return { chunks: deduped, errors: [] };
239
+ }
240
+
241
+ if (import.meta.url === `file://${process.argv[1]}`) {
242
+ const target = process.argv[2];
243
+ if (!target) {
244
+ console.error("Usage: java-treesitter.mjs <file.java>");
245
+ process.exit(1);
246
+ }
247
+ const code = fs.readFileSync(target, "utf8");
248
+ const result = await parseCode(code, target, "java");
249
+ console.log(JSON.stringify(result, null, 2));
250
+ }
@@ -2,12 +2,67 @@ import { Parser } from "acorn";
2
2
  import tsPlugin from "acorn-typescript";
3
3
  import { base } from "acorn-walk";
4
4
 
5
+ const baseIdentifier = base.Identifier;
6
+ const baseFunction = base.Function;
7
+ const baseClass = base.Class;
8
+
9
+ base.Identifier = (node, st, visit) => {
10
+ baseIdentifier(node, st, visit);
11
+ if (node.typeAnnotation) {
12
+ visit(node.typeAnnotation, st);
13
+ }
14
+ };
15
+
16
+ base.Function = (node, st, visit) => {
17
+ baseFunction(node, st, visit);
18
+ if (node.returnType) {
19
+ visit(node.returnType, st);
20
+ }
21
+ if (node.typeParameters) {
22
+ visit(node.typeParameters, st);
23
+ }
24
+ };
25
+
26
+ base.Class = (node, st, visit) => {
27
+ baseClass(node, st, visit);
28
+ for (const implementedType of node.implements || []) {
29
+ visit(implementedType, st);
30
+ }
31
+ if (node.typeParameters) {
32
+ visit(node.typeParameters, st);
33
+ }
34
+ };
35
+
5
36
  const tsNodeHandlers = {
6
37
  TSAsExpression(node, st, visit) { visit(node.expression, st); },
7
- TSTypeAnnotation() {},
8
- TSTypeParameterInstantiation() {},
9
- TSTypeParameterDeclaration() {},
10
- TSTypeReference() {},
38
+ TSTypeAnnotation(node, st, visit) {
39
+ if (node.typeAnnotation) {
40
+ visit(node.typeAnnotation, st);
41
+ }
42
+ },
43
+ TSTypeParameterInstantiation(node, st, visit) {
44
+ for (const param of node.params || []) {
45
+ visit(param, st);
46
+ }
47
+ },
48
+ TSTypeParameterDeclaration(node, st, visit) {
49
+ for (const param of node.params || []) {
50
+ if (param.constraint) {
51
+ visit(param.constraint, st);
52
+ }
53
+ if (param.default) {
54
+ visit(param.default, st);
55
+ }
56
+ }
57
+ },
58
+ TSTypeReference(node, st, visit) {
59
+ if (node.typeName) {
60
+ visit(node.typeName, st);
61
+ }
62
+ if (node.typeParameters) {
63
+ visit(node.typeParameters, st);
64
+ }
65
+ },
11
66
  TSInterfaceDeclaration() {},
12
67
  TSTypeAliasDeclaration() {},
13
68
  TSEnumDeclaration() {},
@@ -17,14 +72,65 @@ const tsNodeHandlers = {
17
72
  TSMethodSignature() {},
18
73
  TSIndexSignature() {},
19
74
  TSTypeLiteral() {},
20
- TSUnionType() {},
21
- TSIntersectionType() {},
22
- TSArrayType() {},
23
- TSTupleType() {},
24
- TSOptionalType() {},
25
- TSRestType() {},
26
- TSFunctionType() {},
27
- TSConstructorType() {},
75
+ TSUnionType(node, st, visit) {
76
+ for (const typeNode of node.types || []) {
77
+ visit(typeNode, st);
78
+ }
79
+ },
80
+ TSIntersectionType(node, st, visit) {
81
+ for (const typeNode of node.types || []) {
82
+ visit(typeNode, st);
83
+ }
84
+ },
85
+ TSArrayType(node, st, visit) {
86
+ if (node.elementType) {
87
+ visit(node.elementType, st);
88
+ }
89
+ },
90
+ TSTupleType(node, st, visit) {
91
+ for (const elementType of node.elementTypes || []) {
92
+ visit(elementType, st);
93
+ }
94
+ },
95
+ TSOptionalType(node, st, visit) {
96
+ if (node.typeAnnotation) {
97
+ visit(node.typeAnnotation, st);
98
+ }
99
+ },
100
+ TSRestType(node, st, visit) {
101
+ if (node.typeAnnotation) {
102
+ visit(node.typeAnnotation, st);
103
+ }
104
+ },
105
+ TSFunctionType(node, st, visit) {
106
+ for (const param of node.params || []) {
107
+ visit(param, st);
108
+ }
109
+ if (node.returnType) {
110
+ visit(node.returnType, st);
111
+ }
112
+ },
113
+ TSConstructorType(node, st, visit) {
114
+ for (const param of node.params || []) {
115
+ visit(param, st);
116
+ }
117
+ if (node.returnType) {
118
+ visit(node.returnType, st);
119
+ }
120
+ },
121
+ TSExpressionWithTypeArguments(node, st, visit) {
122
+ if (node.expression) {
123
+ visit(node.expression, st);
124
+ }
125
+ if (node.typeParameters) {
126
+ visit(node.typeParameters, st);
127
+ }
128
+ },
129
+ TSParameterProperty(node, st, visit) {
130
+ if (node.parameter) {
131
+ visit(node.parameter, st);
132
+ }
133
+ },
28
134
  TSNonNullExpression(node, st, visit) { visit(node.expression, st); },
29
135
  TSInstantiationExpression(node, st, visit) { visit(node.expression, st); }
30
136
  };
@@ -376,6 +376,10 @@ function findLeadingCommentStart(code, node) {
376
376
  }
377
377
 
378
378
  function formatParameterName(param) {
379
+ if (param.type === "TSParameterProperty") {
380
+ return formatParameterName(param.parameter);
381
+ }
382
+
379
383
  if (param.type === "Identifier") {
380
384
  return param.name;
381
385
  }
@@ -4,6 +4,9 @@ export function collectPatternIdentifiers(pattern, visit) {
4
4
  }
5
5
 
6
6
  switch (pattern.type) {
7
+ case "TSParameterProperty":
8
+ collectPatternIdentifiers(pattern.parameter, visit);
9
+ break;
7
10
  case "Identifier":
8
11
  visit(pattern.name);
9
12
  break;
@@ -44,6 +47,9 @@ export function walkPatternExpressions(pattern, visit) {
44
47
  }
45
48
 
46
49
  switch (pattern.type) {
50
+ case "TSParameterProperty":
51
+ walkPatternExpressions(pattern.parameter, visit);
52
+ break;
47
53
  case "AssignmentPattern":
48
54
  walkPatternExpressions(pattern.left, visit);
49
55
  if (pattern.right) {