graph-indexer 2.1.0 → 3.0.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 (129) hide show
  1. package/CHANGELOG.md +260 -1
  2. package/README.md +232 -312
  3. package/SECURITY.md +37 -59
  4. package/bin/graph-indexer.mjs +251 -0
  5. package/integrations/claude-code/.claude-plugin/plugin.json +8 -0
  6. package/integrations/claude-code/.mcp.json +8 -0
  7. package/integrations/claude-code/agents/code-structure.md +22 -0
  8. package/integrations/claude-code/hooks/gi-hook.mjs +99 -0
  9. package/integrations/claude-code/hooks/hooks.json +16 -0
  10. package/integrations/opencode/graph-indexer.js +124 -0
  11. package/package.json +31 -105
  12. package/src/cli/helper.mjs +67 -0
  13. package/src/cli/hook.mjs +356 -0
  14. package/src/cli/init.mjs +255 -0
  15. package/src/cli/resident.mjs +175 -0
  16. package/src/index/discover.mjs +130 -0
  17. package/src/index/fingerprint.mjs +30 -0
  18. package/src/index/graph.mjs +61 -0
  19. package/src/index/indexer.mjs +476 -0
  20. package/src/index/modules.mjs +331 -0
  21. package/src/index/resolver.mjs +954 -0
  22. package/src/mcp/render.mjs +60 -0
  23. package/src/mcp/server.mjs +147 -0
  24. package/src/mcp/tools.mjs +973 -0
  25. package/src/parse/arity.mjs +152 -0
  26. package/src/parse/extract.mjs +1031 -0
  27. package/src/parse/lang/csharp.mjs +106 -0
  28. package/src/parse/lang/ecma.mjs +438 -0
  29. package/src/parse/lang/go.mjs +194 -0
  30. package/src/parse/lang/jvm.mjs +118 -0
  31. package/src/parse/lang/kotlin.mjs +97 -0
  32. package/src/parse/lang/misc.mjs +115 -0
  33. package/src/parse/lang/native.mjs +126 -0
  34. package/src/parse/lang/python.mjs +153 -0
  35. package/src/parse/lang/rust.mjs +157 -0
  36. package/src/parse/lang/scripting.mjs +219 -0
  37. package/src/parse/languages.mjs +48 -0
  38. package/src/parse/runtime.mjs +56 -0
  39. package/src/query/check.mjs +343 -0
  40. package/src/query/facts.mjs +323 -0
  41. package/src/query/intel.mjs +680 -0
  42. package/src/query/read.mjs +81 -0
  43. package/src/query/testcmd.mjs +119 -0
  44. package/src/query/textsearch.mjs +160 -0
  45. package/src/search/search.mjs +210 -0
  46. package/src/search/tokenize.mjs +188 -0
  47. package/src/store/db.mjs +169 -0
  48. package/src/util/paths.mjs +24 -0
  49. package/vendor/grammars/bash.wasm.gz +0 -0
  50. package/vendor/grammars/c.wasm.gz +0 -0
  51. package/vendor/grammars/c_sharp.wasm.gz +0 -0
  52. package/vendor/grammars/cpp.wasm.gz +0 -0
  53. package/vendor/grammars/css.wasm.gz +0 -0
  54. package/vendor/grammars/go.wasm.gz +0 -0
  55. package/vendor/grammars/java.wasm.gz +0 -0
  56. package/vendor/grammars/javascript.wasm.gz +0 -0
  57. package/vendor/grammars/kotlin.wasm.gz +0 -0
  58. package/vendor/grammars/manifest.json +148 -0
  59. package/vendor/grammars/php.wasm.gz +0 -0
  60. package/vendor/grammars/python.wasm.gz +0 -0
  61. package/vendor/grammars/ruby.wasm.gz +0 -0
  62. package/vendor/grammars/rust.wasm.gz +0 -0
  63. package/vendor/grammars/scala.wasm.gz +0 -0
  64. package/vendor/grammars/tsx.wasm.gz +0 -0
  65. package/vendor/grammars/typescript.wasm.gz +0 -0
  66. package/vendor/web-tree-sitter/web-tree-sitter.js +3980 -0
  67. package/vendor/web-tree-sitter/web-tree-sitter.wasm +0 -0
  68. package/cli-ui.mjs +0 -78
  69. package/colbert.mjs +0 -168
  70. package/config.mjs +0 -494
  71. package/daemon-ctl.mjs +0 -175
  72. package/daemon-lock.mjs +0 -69
  73. package/embedders/python/mlx_embed_server.py +0 -61
  74. package/embedders/python/requirements-mlx.txt +0 -5
  75. package/embedders/setup-mlx.mjs +0 -110
  76. package/embeddings.mjs +0 -571
  77. package/engine/binary.mjs +0 -437
  78. package/engine/memory.mjs +0 -1003
  79. package/engine/sqlite.mjs +0 -1136
  80. package/enrichment.mjs +0 -521
  81. package/git-signals.mjs +0 -248
  82. package/indexer.mjs +0 -546
  83. package/init.mjs +0 -1809
  84. package/layout.mjs +0 -123
  85. package/mcp/centrality.mjs +0 -117
  86. package/mcp/format.mjs +0 -61
  87. package/mcp/resolver.mjs +0 -116
  88. package/mcp/symbolgraph.mjs +0 -137
  89. package/mcp/taint.mjs +0 -225
  90. package/mcp/tools.mjs +0 -1582
  91. package/mcp/topology.mjs +0 -676
  92. package/mcp-server.mjs +0 -197
  93. package/parse/extractor.mjs +0 -628
  94. package/parse/imports.mjs +0 -365
  95. package/parse/interprocedural.mjs +0 -134
  96. package/parse/languages.mjs +0 -253
  97. package/parse/metadata.mjs +0 -701
  98. package/parse/routes.mjs +0 -327
  99. package/parse/scip.mjs +0 -391
  100. package/parse/taint-patterns.mjs +0 -119
  101. package/prompts/CORE.md +0 -91
  102. package/prompts/DOMAIN_TEMPLATE.md +0 -46
  103. package/prompts/INTEGRATION.md +0 -123
  104. package/prompts/frameworks/ANDROID.md +0 -17
  105. package/prompts/frameworks/ASPNET_CORE.md +0 -19
  106. package/prompts/frameworks/FASTAPI_DJANGO.md +0 -20
  107. package/prompts/frameworks/LARAVEL_SYMFONY.md +0 -22
  108. package/prompts/frameworks/NODE_EXPRESS_NESTJS.md +0 -19
  109. package/prompts/frameworks/RAILS.md +0 -20
  110. package/prompts/frameworks/REACT.md +0 -20
  111. package/prompts/frameworks/SPRING_BOOT.md +0 -20
  112. package/prompts/languages/BASH.md +0 -22
  113. package/prompts/languages/C.md +0 -21
  114. package/prompts/languages/CSHARP.md +0 -24
  115. package/prompts/languages/CSS_SCSS.md +0 -22
  116. package/prompts/languages/GO.md +0 -24
  117. package/prompts/languages/JAVA.md +0 -23
  118. package/prompts/languages/JAVASCRIPT_TYPESCRIPT.md +0 -24
  119. package/prompts/languages/KOTLIN.md +0 -24
  120. package/prompts/languages/PHP.md +0 -23
  121. package/prompts/languages/PYTHON.md +0 -23
  122. package/prompts/languages/RUBY.md +0 -23
  123. package/prompts/languages/RUST.md +0 -21
  124. package/prompts/languages/SWIFT.md +0 -21
  125. package/seal.mjs +0 -400
  126. package/search-core.mjs +0 -777
  127. package/search-sparse.mjs +0 -183
  128. package/storage.mjs +0 -73
  129. package/watch-daemon.mjs +0 -289
@@ -0,0 +1,194 @@
1
+ /** Go extraction spec. Methods are qualified by their receiver type (Engine.Run). */
2
+
3
+ const RECV_TYPE = `[(type_identifier) @owner (pointer_type (type_identifier) @owner) (generic_type type: (type_identifier) @owner) (pointer_type (generic_type type: (type_identifier) @owner))]`;
4
+ // a whole (single) type; normalizeType reduces it to what member lookup needs (`[]*pkg.T` → T[])
5
+ const TYPE_HEAD = `[(type_identifier) (pointer_type) (qualified_type) (generic_type) (slice_type) (array_type) (map_type) (channel_type)] @type`;
6
+
7
+ const QUERY = `
8
+ (function_declaration name: (identifier) @name result: ${TYPE_HEAD}) @def.function
9
+ (function_declaration name: (identifier) @name result: (parameter_list . (parameter_declaration type: ${TYPE_HEAD}))) @def.function
10
+ (function_declaration name: (identifier) @name) @def.function
11
+ (method_declaration receiver: (parameter_list (parameter_declaration type: ${RECV_TYPE})) name: (field_identifier) @name result: ${TYPE_HEAD}) @def.method
12
+ (method_declaration receiver: (parameter_list (parameter_declaration type: ${RECV_TYPE})) name: (field_identifier) @name result: (parameter_list . (parameter_declaration type: ${TYPE_HEAD}))) @def.method
13
+ (method_declaration receiver: (parameter_list (parameter_declaration type: ${RECV_TYPE})) name: (field_identifier) @name) @def.method
14
+ (type_spec name: (type_identifier) @name type: (struct_type)) @def.struct
15
+ (type_spec name: (type_identifier) @name type: (interface_type)) @def.interface
16
+ (type_spec name: (type_identifier) @name type: [(map_type) (slice_type) (array_type)] @type) @def.type
17
+ (type_spec name: (type_identifier) @name type: [(type_identifier) (qualified_type) (function_type) (map_type) (slice_type) (array_type) (pointer_type) (generic_type) (channel_type)]) @def.type
18
+ (type_alias name: (type_identifier) @name type: ${TYPE_HEAD}) @def.type
19
+ (type_alias name: (type_identifier) @name) @def.type
20
+ (method_elem name: (field_identifier) @name result: ${TYPE_HEAD}) @def.method
21
+ (method_elem name: (field_identifier) @name result: (parameter_list . (parameter_declaration type: ${TYPE_HEAD}))) @def.method
22
+ (method_elem name: (field_identifier) @name) @def.method
23
+ (field_declaration name: (field_identifier) @name type: ${TYPE_HEAD}) @def.field
24
+ (field_declaration name: (field_identifier) @name) @def.field
25
+ (const_spec name: (identifier) @name) @def.constant
26
+ (var_spec name: (identifier) @name) @def.variable
27
+
28
+ (call_expression function: (identifier) @name) @ref.call
29
+ (call_expression function: (selector_expression operand: (_) @recv field: (field_identifier) @name)) @ref.call
30
+ (type_identifier) @name @ref.type
31
+ (qualified_type package: (package_identifier) @recv name: (type_identifier) @name) @ref.type
32
+ (composite_literal type: (type_identifier) @name) @ref.new
33
+ (call_expression function: (parenthesized_expression (unary_expression operand: (identifier) @name))) @ref.type
34
+ (call_expression function: (parenthesized_expression (unary_expression operand: (selector_expression operand: (identifier) @recv field: (field_identifier) @name)))) @ref.type
35
+ (composite_literal type: (qualified_type package: (package_identifier) @recv name: (type_identifier) @name)) @ref.new
36
+ (field_declaration_list (field_declaration !name type: [(type_identifier) @name (pointer_type (type_identifier) @name)])) @ref.inherit
37
+ (field_declaration_list (field_declaration !name type: [(qualified_type package: (package_identifier) @recv name: (type_identifier) @name) (pointer_type (qualified_type package: (package_identifier) @recv name: (type_identifier) @name))])) @ref.inherit
38
+ (interface_type (type_elem (type_identifier) @name)) @ref.inherit
39
+ (argument_list (identifier) @name) @ref.value
40
+ (argument_list (selector_expression operand: (identifier) @recv field: (field_identifier) @name)) @ref.value
41
+ (keyed_element (literal_element) (literal_element (identifier) @name)) @ref.value
42
+ (composite_literal type: [(map_type) (slice_type) (array_type)] body: (literal_value (keyed_element . (literal_element (identifier) @name)))) @ref.value
43
+ (composite_literal type: [(type_identifier) (qualified_type) (generic_type)] body: (literal_value (keyed_element . (literal_element (identifier) @name)))) @recv @ref.read
44
+ (selector_expression operand: (_) @recv field: (field_identifier) @name) @ref.read
45
+
46
+ (func_literal) @scope
47
+ (return_statement (expression_list . (_) @ret))
48
+ (import_spec) @import
49
+
50
+ (short_var_declaration left: (expression_list . (identifier) @bind.name) right: (expression_list . (composite_literal type: (type_identifier) @bind.new))) @bind
51
+ (short_var_declaration left: (expression_list . (identifier) @bind.name) right: (expression_list . (unary_expression operand: (composite_literal type: (type_identifier) @bind.new)))) @bind
52
+ (short_var_declaration left: (expression_list . (identifier) @bind.name) right: (expression_list . (_) @bind.expr)) @bind
53
+ (var_spec name: (identifier) @bind.name value: (expression_list . (_) @bind.expr)) @bind
54
+ (for_statement (range_clause left: (expression_list . (_) . (identifier) @bind.name) right: (_) @bind.elem)) @bind
55
+ (var_spec name: (identifier) @bind.name type: ${TYPE_HEAD.replaceAll('@type', '@bind.type')}) @bind
56
+ (parameter_declaration name: (identifier) @bind.name type: ${TYPE_HEAD.replaceAll('@type', '@bind.type')}) @bind
57
+ `;
58
+
59
+ const BUILTIN_CALLS = new Set(['make', 'new', 'len', 'cap', 'append', 'copy', 'delete', 'panic', 'recover', 'print',
60
+ 'println', 'close', 'complex', 'real', 'imag', 'min', 'max', 'clear', 'string', 'int', 'int64', 'int32', 'uint',
61
+ 'uint64', 'uint32', 'float64', 'float32', 'byte', 'rune', 'bool', 'error', 'uintptr']);
62
+ const PRIMITIVES = new Set(['string', 'int', 'int8', 'int16', 'int32', 'int64', 'uint', 'uint8', 'uint16', 'uint32',
63
+ 'uint64', 'uintptr', 'float32', 'float64', 'complex64', 'complex128', 'byte', 'rune', 'bool', 'error', 'any',
64
+ 'interface', 'map', 'chan', 'func']);
65
+
66
+ function splitTop(s) {
67
+ const out = [];
68
+ let depth = 0, cur = '';
69
+ for (const ch of s) {
70
+ if ('([{'.includes(ch)) depth++;
71
+ else if (')]}'.includes(ch)) depth--;
72
+ if (ch === ',' && depth === 0) { out.push(cur.trim()); cur = ''; } else cur += ch;
73
+ }
74
+ if (cur.trim()) out.push(cur.trim());
75
+ return out;
76
+ }
77
+ function closeParen(s, open) {
78
+ for (let i = open, depth = 0; i < s.length; i++) {
79
+ if (s[i] === '(') depth++;
80
+ else if (s[i] === ')' && --depth === 0) return i;
81
+ }
82
+ return -1;
83
+ }
84
+ const KEYWORD_TYPES = new Set(['chan', 'func', 'map', 'struct', 'interface']);
85
+ /** The types of a parameter or result list, names dropped (`a, b string` is two strings). */
86
+ function listTypes(text) {
87
+ const entries = splitTop(text);
88
+ const named = entries.some(e => { const m = /^([A-Za-z_]\w*)\s+\S/.exec(e); return m && !KEYWORD_TYPES.has(m[1]); });
89
+ if (!named) return entries;
90
+ const out = [];
91
+ let type = null;
92
+ for (let i = entries.length - 1; i >= 0; i--) {
93
+ const m = /^[A-Za-z_]\w*\s+(.+)$/s.exec(entries[i]);
94
+ if (m) type = m[1];
95
+ out.unshift(type);
96
+ }
97
+ return out;
98
+ }
99
+ /** A type reduced to what tells two signatures apart without type checking: `*pkg.T` → T. */
100
+ function typeHead(t) {
101
+ let s = (t ?? '').trim();
102
+ for (let prev; prev !== s;) { prev = s; s = s.replace(/^(?:\*|\.\.\.|\[\d*\]|<-\s*|chan\s+)/, '').trim(); }
103
+ if (/^map\s*\[/.test(s)) return 'map';
104
+ if (/^func\b/.test(s)) return 'func';
105
+ if (/^(struct|interface)\s*\{/.test(s)) return s.startsWith('struct') ? 'struct' : 'interface';
106
+ s = s.replace(/\[.*$/s, '');
107
+ return s.split('.').pop();
108
+ }
109
+ /**
110
+ * The shape of a method's signature, for telling whether a type's method satisfies an interface's:
111
+ * parameter and result types reduced to their heads (`ServeHTTP(http.ResponseWriter, *http.Request)
112
+ * error` → `ResponseWriter,Request->error`). Null when the signature cannot be read.
113
+ */
114
+ function methodShape(sig, name) {
115
+ if (!sig) return null;
116
+ const m = new RegExp(`(?:^|[\\s)])${name}\\s*\\(`).exec(sig);
117
+ if (!m) return null;
118
+ const open = m.index + m[0].length - 1, close = closeParen(sig, open);
119
+ if (close < 0) return null;
120
+ const params = listTypes(sig.slice(open + 1, close));
121
+ let rest = sig.slice(close + 1).replace(/\{\s*$/, '').trim();
122
+ let results;
123
+ if (rest.startsWith('(')) {
124
+ const end = closeParen(rest, 0);
125
+ if (end < 0) return null;
126
+ results = listTypes(rest.slice(1, end));
127
+ } else results = rest ? [rest] : [];
128
+ return params.map(typeHead).join(',') + '->' + results.map(typeHead).join(',');
129
+ }
130
+
131
+ function parseImport(node) {
132
+ const pathNode = node.childForFieldName('path');
133
+ if (!pathNode) return [];
134
+ const source = pathNode.text.replace(/^["`]|["`]$/g, '');
135
+ const alias = node.childForFieldName('name')?.text;
136
+ // the package is named after the last path element, but not a major version: `…/caddy/v2` is
137
+ // package caddy, `gopkg.in/yaml.v3` package yaml
138
+ const parts = source.split('/');
139
+ const last = /^v\d+$/.test(parts[parts.length - 1]) && parts.length > 1 ? parts[parts.length - 2] : parts[parts.length - 1];
140
+ const local = alias && alias !== '_' && alias !== '.' ? alias : (alias === '.' ? null : last.replace(/\.v\d+$/, '').replace(/^go-|-go$/g, ''));
141
+ return [{ source, imported: '*', local, wildcard: alias === '.' }];
142
+ }
143
+
144
+ function isModuleLevel(node) {
145
+ // var_spec → var_declaration → source_file (or var_spec_list in between)
146
+ let p = node.parent;
147
+ if (p?.type === 'var_spec_list') p = p.parent;
148
+ return p?.type === 'var_declaration' ? p.parent?.type === 'source_file' : p?.type === 'const_declaration' ? p.parent?.type === 'source_file' : true;
149
+ }
150
+
151
+ function docOf(defNode) {
152
+ // type_spec lives inside a type_declaration; comments sit above the declaration
153
+ return null;
154
+ }
155
+
156
+ function fileInfo(root) {
157
+ const pkg = root.namedChildren.find(c => c.type === 'package_clause');
158
+ return { package: pkg?.namedChildren[0]?.text ?? null };
159
+ }
160
+
161
+ export const go = {
162
+ id: 'go',
163
+ grammar: 'go',
164
+ extensions: ['.go'],
165
+ family: 'go',
166
+ query: QUERY,
167
+ implicitThis: false,
168
+ selfNames: [],
169
+ externalReceivers: new Set(['fmt', 'os', 'strings', 'strconv', 'errors', 'io', 'bytes', 'sync', 'time', 'context',
170
+ 'log', 'math', 'sort', 'regexp', 'filepath', 'reflect', 'atomic', 'bufio', 'unicode', 'utf8', 'json', 'xml',
171
+ 'hex', 'base64', 'rand', 'runtime', 'testing', 'assert', 'require', 'ioutil', 'url', 'unsafe']),
172
+ builtinCalls: BUILTIN_CALLS,
173
+ testFile: /_test\.go$|(^|\/)testdata\//,
174
+ commentTypes: ['comment'],
175
+ docWrappers: new Set(['type_declaration', 'const_declaration', 'var_declaration']),
176
+ docOf,
177
+ parseImport,
178
+ isModuleLevel,
179
+ isExported: (node, name) => /^[A-Z]/.test(name),
180
+ visibility: (node, name) => (name && /^[a-z_]/.test(name) ? 'private' : null),
181
+ isPrimitiveType: (t) => PRIMITIVES.has(t),
182
+ // `(T, error)` results: the value is the first element
183
+ mapIterValues: true, // `for _, v := range m` binds values
184
+ packageValues: true, // a bare identifier that is not local is a package-level variable
185
+ qualifiedTypes: true, // types keep their package (`http.Request`)
186
+ methodShape, // interfaces are satisfied by name and signature
187
+ cleanType: (t) => t.replace(/^\(\s*(?:\w+\s+)?([^,()]+?)\s*,\s*(?:\w+\s+)?error\s*\)$/s, '$1'),
188
+ refineKind(kind, d, parent) {
189
+ if (d.node.type === 'method_elem') return 'method';
190
+ return kind;
191
+ },
192
+ fileInfo,
193
+ bodyField: 'body',
194
+ };
@@ -0,0 +1,118 @@
1
+ /** Java extraction spec (Kotlin/Scala live in their own modules). */
2
+
3
+ const T = (cap) => `[(type_identifier) @${cap} (generic_type (type_identifier) @${cap}) (scoped_type_identifier (type_identifier) @${cap} .) (generic_type (scoped_type_identifier (type_identifier) @${cap} .))]`;
4
+
5
+ const JAVA_QUERY = `
6
+ (class_declaration name: (identifier) @name) @def.class
7
+ (class_declaration name: (identifier) @name superclass: (superclass (_) @type)) @def.class
8
+ (interface_declaration name: (identifier) @name) @def.interface
9
+ (enum_declaration name: (identifier) @name) @def.enum
10
+ (record_declaration name: (identifier) @name) @def.class
11
+ (annotation_type_declaration name: (identifier) @name) @def.interface
12
+ (method_declaration type: (_) @type name: (identifier) @name) @def.method
13
+ (method_declaration name: (identifier) @name) @def.method
14
+ (constructor_declaration name: (identifier) @name) @def.constructor
15
+ (field_declaration type: (_) @type declarator: (variable_declarator name: (identifier) @name)) @def.field
16
+ (field_declaration declarator: (variable_declarator name: (identifier) @name)) @def.field
17
+ (enum_constant name: (identifier) @name body: (class_body)) @def.class
18
+ (enum_constant name: (identifier) @name) @def.constant
19
+ (object_creation_expression "new" @name (class_body)) @def.class
20
+
21
+ (method_invocation !object name: (identifier) @name) @ref.call
22
+ (method_invocation object: (_) @recv name: (identifier) @name) @ref.call
23
+ (object_creation_expression type: ${T('name')}) @ref.new
24
+ (superclass ${T('name')}) @ref.inherit
25
+ (super_interfaces (type_list ${T('name')})) @ref.inherit
26
+ (object_creation_expression type: ${T('name')} (class_body)) @ref.inherit
27
+ (extends_interfaces (type_list ${T('name')})) @ref.inherit
28
+ (type_identifier) @name @ref.type
29
+ (marker_annotation name: (identifier) @name) @ref.decorator
30
+ (annotation name: (identifier) @name) @ref.decorator
31
+ (method_reference . (identifier) @recv (identifier) @name) @ref.value
32
+ ; a class named on the left of a static access: StringUtil.join(…), Token.TokenType.EOF, Foo::bar
33
+ ; (a constant in capitals is not a class; a name that is no type of the repository resolves to nothing)
34
+ (method_invocation object: ((identifier) @name @ref.type (#match? @name "^[A-Z]\\w*[a-z]")))
35
+ (field_access object: ((identifier) @name @ref.type (#match? @name "^[A-Z]\\w*[a-z]")))
36
+ (method_reference . ((identifier) @name @ref.type (#match? @name "^[A-Z]\\w*[a-z]")))
37
+ (argument_list (identifier) @name) @ref.value
38
+
39
+ (lambda_expression) @scope
40
+ (return_statement (_) @ret)
41
+ (import_declaration) @import
42
+
43
+ (local_variable_declaration type: (_) @bind.type declarator: (variable_declarator name: (identifier) @bind.name)) @bind
44
+ (local_variable_declaration declarator: (variable_declarator name: (identifier) @bind.name value: (object_creation_expression type: ${T('bind.new')}))) @bind
45
+ (local_variable_declaration declarator: (variable_declarator name: (identifier) @bind.name value: (_) @bind.expr)) @bind
46
+ (formal_parameter type: (_) @bind.type name: (identifier) @bind.name) @bind
47
+ (enhanced_for_statement type: (_) @bind.type name: (identifier) @bind.name value: (_) @bind.elem) @bind
48
+ (field_declaration type: (_) @field.type declarator: (variable_declarator name: (identifier) @field.name)) @field
49
+ `;
50
+
51
+ const JAVA_BUILTIN_TYPES = new Set(['String', 'Object', 'Integer', 'Long', 'Double', 'Float', 'Boolean', 'Character',
52
+ 'Byte', 'Short', 'Void', 'List', 'Map', 'Set', 'Collection', 'Optional', 'Stream', 'Iterable', 'Iterator',
53
+ 'ArrayList', 'HashMap', 'HashSet', 'LinkedList', 'Arrays', 'Collections', 'Objects', 'Math', 'System',
54
+ 'StringBuilder', 'Exception', 'RuntimeException', 'Throwable', 'Class', 'Thread', 'Override', 'Deprecated',
55
+ 'SuppressWarnings', 'FunctionalInterface']);
56
+
57
+ function javaImport(node) {
58
+ const text = node.text.replace(/^import\s+(static\s+)?/, '').replace(/;\s*$/, '').trim();
59
+ const isStatic = /^import\s+static/.test(node.text);
60
+ if (text.endsWith('.*')) return [{ source: text.slice(0, -2), imported: '*', local: null, wildcard: true, static: isStatic }];
61
+ const parts = text.split('.');
62
+ const name = parts.pop();
63
+ return [{ source: parts.join('.'), imported: name, local: name, static: isStatic }];
64
+ }
65
+
66
+ function modifiersText(node) {
67
+ const m = node.namedChildren.find(c => c.type === 'modifiers');
68
+ return m ? m.text : '';
69
+ }
70
+
71
+ function javaFileInfo(root) {
72
+ const pkg = root.namedChildren.find(c => c.type === 'package_declaration');
73
+ return { package: pkg ? pkg.text.replace(/^package\s+/, '').replace(/;\s*$/, '').trim() : null };
74
+ }
75
+
76
+ export const java = {
77
+ id: 'java',
78
+ distinctOverloads: true, // each overload is a method of its own: calls bind by argument count
79
+ localValues: true, // an argument named like a local or parameter is that variable
80
+ nestedTypes: true, // `Token.Comment` names the class Comment nested in Token
81
+ // an anonymous class (`new Transformer<>() {…}`) is `<anonymous>`, a subclass of what it instantiates
82
+ normalizeName: (name, d) => (d.node.type === 'object_creation_expression' ? '<anonymous>' : name),
83
+ // an enum constant with a body (`AfterBody { boolean process(…) {…} }`) is a subclass of its enum
84
+ refineKind: (kind, d) => (d.node.type === 'enum_constant' && d.node.childForFieldName('body') ? 'class' : kind),
85
+ implicitBases: (node) => (node.type === 'enum_constant' && node.childForFieldName('body') ? [node.parent?.parent?.childForFieldName('name')?.text].filter(Boolean) : []),
86
+ grammar: 'java',
87
+ extensions: ['.java'],
88
+ family: 'jvm',
89
+ query: JAVA_QUERY,
90
+ implicitThis: true,
91
+ selfNames: ['this'],
92
+ externalReceivers: new Set(['System', 'Math', 'Arrays', 'Collections', 'Objects', 'String', 'Integer', 'Long',
93
+ 'Double', 'Boolean', 'Optional', 'Stream', 'Collectors', 'LoggerFactory', 'log', 'logger', 'LOG', 'LOGGER',
94
+ 'Assertions', 'Assert', 'Mockito', 'assertThat']),
95
+ builtinCalls: new Set(['assertEquals', 'assertTrue', 'assertFalse', 'assertNotNull', 'assertNull', 'assertThat',
96
+ 'when', 'verify', 'mock', 'any', 'eq', 'println', 'printf', 'format', 'valueOf', 'toString', 'equals',
97
+ 'hashCode', 'getClass', 'super', 'this']),
98
+ testFile: /(^|\/)src\/test\/|Tests?\.java$|IT\.java$/,
99
+ commentTypes: ['block_comment', 'line_comment'],
100
+ parseImport: javaImport,
101
+ isExported: (node) => /\bpublic\b/.test(modifiersText(node)) || node.parent?.type === 'interface_body',
102
+ visibility: (node) => { const m = modifiersText(node); return /\bprivate\b/.test(m) ? 'private' : /\bprotected\b/.test(m) ? 'protected' : /\bpublic\b/.test(m) ? 'public' : null; },
103
+ isPrimitiveType: (t) => JAVA_BUILTIN_TYPES.has(t) || /^(int|long|double|float|boolean|char|byte|short|void)$/.test(t),
104
+ elementTypes: new Set(['List', 'ArrayList', 'LinkedList', 'Collection', 'Set', 'HashSet', 'TreeSet', 'LinkedHashSet', 'SortedSet', 'NavigableSet',
105
+ 'Iterable', 'Iterator', 'Stream', 'Queue', 'Deque', 'ArrayDeque', 'PriorityQueue', 'Vector', 'CopyOnWriteArrayList', 'BlockingQueue']),
106
+ elementMethods: new Set(['get', 'getFirst', 'getLast', 'peek', 'poll', 'pop', 'element', 'first', 'last', 'next', 'remove', 'take']),
107
+ mapTypes: new Set(['Map', 'HashMap', 'TreeMap', 'LinkedHashMap', 'ConcurrentHashMap', 'SortedMap', 'NavigableMap', 'ConcurrentMap', 'EnumMap']),
108
+ mapMethods: new Set(['get', 'getOrDefault', 'remove', 'put', 'putIfAbsent', 'computeIfAbsent', 'compute', 'merge']),
109
+ mapValueMethods: new Set(['values']),
110
+ decoratorsOf(node) {
111
+ const m = node.namedChildren.find(c => c.type === 'modifiers');
112
+ if (!m) return [];
113
+ return m.namedChildren.filter(c => c.type === 'annotation' || c.type === 'marker_annotation')
114
+ .map(a => a.childForFieldName('name')?.text).filter(Boolean).slice(0, 8);
115
+ },
116
+ fileInfo: javaFileInfo,
117
+ bodyField: 'body',
118
+ };
@@ -0,0 +1,97 @@
1
+ /** Kotlin extraction spec (fwcd/tree-sitter-kotlin; the grammar has no field names, so patterns are positional). */
2
+
3
+ const QUERY = `
4
+ [(lambda_literal) (anonymous_function)] @scope
5
+ (class_declaration (type_identifier) @name) @def.class
6
+ (object_declaration (type_identifier) @name) @def.object
7
+ (function_declaration (simple_identifier) @name (user_type (type_identifier) @type)) @def.function
8
+ (function_declaration (simple_identifier) @name) @def.function
9
+ (class_body (property_declaration (variable_declaration (simple_identifier) @name (user_type (type_identifier) @type))) @def.property)
10
+ (class_body (property_declaration (variable_declaration (simple_identifier) @name)) @def.property)
11
+ (source_file (property_declaration (variable_declaration (simple_identifier) @name)) @def.variable)
12
+ (class_parameter (binding_pattern_kind) (simple_identifier) @name (user_type (type_identifier) @type)) @def.property
13
+ (class_parameter (binding_pattern_kind) (simple_identifier) @name) @def.property
14
+ (type_alias (type_identifier) @name) @def.type
15
+ (enum_entry (simple_identifier) @name) @def.constant
16
+
17
+ (call_expression . (simple_identifier) @name) @ref.call
18
+ (call_expression . (navigation_expression (_) @recv . (navigation_suffix (simple_identifier) @name))) @ref.call
19
+ (delegation_specifier (constructor_invocation (user_type (type_identifier) @name))) @ref.inherit
20
+ (delegation_specifier (user_type (type_identifier) @name)) @ref.inherit
21
+ (user_type (type_identifier) @name) @ref.type
22
+ (annotation (user_type (type_identifier) @name)) @ref.decorator
23
+ (annotation (constructor_invocation (user_type (type_identifier) @name))) @ref.decorator
24
+ (value_argument (simple_identifier) @name) @ref.value
25
+ (callable_reference (simple_identifier) @name) @ref.value
26
+
27
+ (import_header) @import
28
+
29
+ (property_declaration (variable_declaration (simple_identifier) @bind.name (user_type (type_identifier) @bind.type))) @bind
30
+ (property_declaration (variable_declaration (simple_identifier) @bind.name) (call_expression . (simple_identifier) @bind.call)) @bind
31
+ (parameter (simple_identifier) @bind.name (user_type (type_identifier) @bind.type)) @bind
32
+ (class_parameter (simple_identifier) @field.name (user_type (type_identifier) @field.type)) @field
33
+ (class_body (property_declaration (variable_declaration (simple_identifier) @field.name (user_type (type_identifier) @field.type))) @field)
34
+ (class_body (property_declaration (variable_declaration (simple_identifier) @field.name) (call_expression . (simple_identifier) @field.call)) @field)
35
+ `;
36
+
37
+ const PRIMITIVES = new Set(['String', 'Int', 'Long', 'Double', 'Float', 'Boolean', 'Char', 'Byte', 'Short', 'Unit',
38
+ 'Any', 'Nothing', 'List', 'MutableList', 'Map', 'MutableMap', 'Set', 'MutableSet', 'Array', 'Pair', 'Triple',
39
+ 'Flow', 'StateFlow', 'MutableStateFlow', 'LiveData', 'MutableLiveData', 'Sequence']);
40
+
41
+ function parseImport(node) {
42
+ const text = node.text.split('\n')[0].replace(/^import\s+/, '').replace(/;\s*$/, '').trim();
43
+ const alias = /\s+as\s+(\w+)$/.exec(text);
44
+ const path = text.replace(/\s+as\s+\w+$/, '').trim();
45
+ if (path.endsWith('.*')) return [{ source: path.slice(0, -2), imported: '*', local: null, wildcard: true }];
46
+ const parts = path.split('.');
47
+ const name = parts.pop();
48
+ return [{ source: parts.join('.'), imported: name, local: alias ? alias[1] : name }];
49
+ }
50
+
51
+ function modifiers(node) { return node.namedChildren.find(c => c.type === 'modifiers')?.text ?? ''; }
52
+
53
+ function fileInfo(root) {
54
+ const pkg = root.namedChildren.find(c => c.type === 'package_header');
55
+ return { package: pkg ? pkg.text.replace(/^package\s+/, '').trim() : null };
56
+ }
57
+
58
+ export const kotlin = {
59
+ id: 'kotlin',
60
+ grammar: 'kotlin',
61
+ extensions: ['.kt', '.kts'],
62
+ family: 'jvm',
63
+ query: QUERY,
64
+ implicitThis: true,
65
+ selfNames: ['this'],
66
+ externalReceivers: new Set(['Log', 'Timber', 'System', 'Math', 'println']),
67
+ builtinCalls: new Set(['println', 'print', 'listOf', 'mutableListOf', 'mapOf', 'mutableMapOf', 'setOf', 'mutableSetOf',
68
+ 'arrayOf', 'emptyList', 'emptyMap', 'emptySet', 'require', 'requireNotNull', 'check', 'checkNotNull', 'error',
69
+ 'lazy', 'let', 'also', 'apply', 'run', 'with', 'repeat', 'TODO', 'assert', 'assertEquals', 'assertTrue', 'launch',
70
+ 'async', 'runBlocking', 'withContext', 'remember', 'mutableStateOf']),
71
+ testFile: /(^|\/)src\/(test|androidTest)\/|Test\.kt$/,
72
+ commentTypes: ['comment', 'multiline_comment', 'line_comment'],
73
+ parseImport,
74
+ isExported: (node) => !/\b(private|internal)\b/.test(modifiers(node)),
75
+ visibility: (node) => { const m = modifiers(node); return /\bprivate\b/.test(m) ? 'private' : /\bprotected\b/.test(m) ? 'protected' : null; },
76
+ isPrimitiveType: (t) => PRIMITIVES.has(t),
77
+ elementTypes: new Set(['List', 'MutableList', 'ArrayList', 'Set', 'MutableSet', 'HashSet', 'LinkedHashSet', 'Collection', 'MutableCollection', 'Iterable', 'Sequence', 'Array']),
78
+ elementMethods: new Set(['get', 'first', 'last', 'firstOrNull', 'lastOrNull', 'single', 'singleOrNull', 'elementAt', 'getOrNull', 'find', 'random', 'removeFirst', 'removeLast']),
79
+ mapTypes: new Set(['Map', 'MutableMap', 'HashMap', 'LinkedHashMap']),
80
+ mapMethods: new Set(['get', 'getValue', 'getOrDefault', 'getOrElse', 'getOrPut', 'remove']),
81
+ mapValueMethods: new Set(['values']),
82
+ refineKind(kind, d) {
83
+ if (d.node.type === 'class_declaration') {
84
+ const head = d.node.text.slice(0, d.node.text.indexOf(d.nameNode.text));
85
+ if (/\binterface\b/.test(head)) return 'interface';
86
+ if (/\benum\b/.test(head)) return 'enum';
87
+ }
88
+ return kind;
89
+ },
90
+ decoratorsOf(node) {
91
+ const m = node.namedChildren.find(c => c.type === 'modifiers');
92
+ return m ? m.namedChildren.filter(c => c.type === 'annotation').map(a => a.text.replace(/^@/, '').split('(')[0]).slice(0, 8) : [];
93
+ },
94
+ fileInfo,
95
+ bodyField: null,
96
+ signatureCleanup: (text) => text.replace(/\s*[{=].*$/s, ''),
97
+ };
@@ -0,0 +1,115 @@
1
+ /** Scala and CSS extraction specs. */
2
+
3
+ const SCALA_QUERY = `
4
+ (class_definition name: (identifier) @name) @def.class
5
+ (object_definition name: (identifier) @name) @def.object
6
+ (trait_definition name: (identifier) @name) @def.trait
7
+ (enum_definition name: (identifier) @name) @def.enum
8
+ (function_definition name: (identifier) @name return_type: [(type_identifier) @type (generic_type type: (type_identifier) @type)]) @def.function
9
+ (function_definition name: (identifier) @name) @def.function
10
+ (function_declaration name: (identifier) @name) @def.function
11
+ (val_definition pattern: (identifier) @name type: [(type_identifier) @type (generic_type type: (type_identifier) @type)]) @def.variable
12
+ (val_definition pattern: (identifier) @name) @def.variable
13
+ (var_definition pattern: (identifier) @name) @def.variable
14
+ (type_definition name: (type_identifier) @name) @def.type
15
+
16
+ (call_expression function: (identifier) @name) @ref.call
17
+ (call_expression function: (field_expression value: (_) @recv field: (identifier) @name)) @ref.call
18
+ (call_expression function: (generic_function function: (identifier) @name)) @ref.call
19
+ (instance_expression (type_identifier) @name) @ref.new
20
+ (instance_expression (generic_type type: (type_identifier) @name)) @ref.new
21
+ (extends_clause type: (type_identifier) @name) @ref.inherit
22
+ (extends_clause type: (generic_type type: (type_identifier) @name)) @ref.inherit
23
+ (type_identifier) @name @ref.type
24
+ (arguments (identifier) @name) @ref.value
25
+
26
+ (import_declaration) @import
27
+
28
+ (val_definition pattern: (identifier) @bind.name type: [(type_identifier) @bind.type (generic_type type: (type_identifier) @bind.type)]) @bind
29
+ (val_definition pattern: (identifier) @bind.name value: (instance_expression (type_identifier) @bind.new)) @bind
30
+ (val_definition pattern: (identifier) @bind.name value: (call_expression function: (identifier) @bind.call)) @bind
31
+ (parameter name: (identifier) @bind.name type: [(type_identifier) @bind.type (generic_type type: (type_identifier) @bind.type)]) @bind
32
+ (class_parameter name: (identifier) @field.name type: [(type_identifier) @field.type (generic_type type: (type_identifier) @field.type)]) @field
33
+ `;
34
+
35
+ function scalaImport(node) {
36
+ const text = node.text.replace(/^import\s+/, '').trim();
37
+ const brace = /^(.*)\.\{(.*)\}$/.exec(text);
38
+ if (brace) {
39
+ return brace[2].split(',').map(s => s.trim()).filter(Boolean).map(s => {
40
+ const [n, a] = s.split(/\s*(?:=>|as)\s*/);
41
+ return n === '_' || n === '*' ? { source: brace[1], imported: '*', local: null, wildcard: true } : { source: brace[1], imported: n, local: a || n };
42
+ });
43
+ }
44
+ if (/\.(_|\*)$/.test(text)) return [{ source: text.replace(/\.(_|\*)$/, ''), imported: '*', local: null, wildcard: true }];
45
+ const parts = text.split('.');
46
+ const name = parts.pop();
47
+ return [{ source: parts.join('.'), imported: name, local: name }];
48
+ }
49
+
50
+ export const scala = {
51
+ id: 'scala',
52
+ grammar: 'scala',
53
+ extensions: ['.scala', '.sc'],
54
+ family: 'jvm',
55
+ query: SCALA_QUERY,
56
+ implicitThis: true,
57
+ selfNames: ['this'],
58
+ externalReceivers: new Set(['System', 'Math', 'Future', 'Option', 'Some', 'Seq', 'List', 'Map', 'Set', 'Vector', 'Array', 'println']),
59
+ builtinCalls: new Set(['println', 'print', 'require', 'assert', 'Some', 'None', 'Seq', 'List', 'Map', 'Set', 'Vector', 'Array', 'Option', 'Future']),
60
+ testFile: /(^|\/)src\/test\/|(Spec|Test|Suite)\.scala$/,
61
+ commentTypes: ['comment', 'block_comment'],
62
+ parseImport: scalaImport,
63
+ isExported: (node) => !/^\s*(private|protected)\b/.test(node.text),
64
+ visibility: (node) => (/^\s*private\b/.test(node.text) ? 'private' : null),
65
+ isPrimitiveType: (t) => /^(Int|Long|Double|Float|Boolean|Char|Byte|Short|Unit|String|Any|AnyRef|Nothing|Option|List|Seq|Map|Set|Vector|Array|Future)$/.test(t),
66
+ transparentTypes: new Set(['Option', 'Some']),
67
+ elementTypes: new Set(['List', 'Seq', 'IndexedSeq', 'Vector', 'Set', 'Array', 'Iterable', 'Iterator', 'ArrayBuffer', 'ListBuffer']),
68
+ elementMethods: new Set(['head', 'last', 'apply', 'find', 'headOption', 'lastOption']),
69
+ mapTypes: new Set(['Map', 'HashMap', 'TreeMap', 'mutable.Map']),
70
+ mapMethods: new Set(['apply', 'get', 'getOrElse']),
71
+ mapValueMethods: new Set(['values']),
72
+ refineKind(kind, d, parent) {
73
+ if (kind === 'variable' && parent && ['class', 'object', 'trait'].includes(parent.kind)) return 'field';
74
+ return kind;
75
+ },
76
+ isModuleLevel: (node) => ['compilation_unit', 'template_body', 'package_clause'].includes(node.parent?.type ?? '') || node.parent?.parent?.type === 'package_clause',
77
+ fileInfo(root) {
78
+ const pkg = root.namedChildren.find(c => c.type === 'package_clause');
79
+ return { package: pkg ? pkg.text.replace(/^package\s+/, '').split(/\s|\{/)[0] : null };
80
+ },
81
+ bodyField: 'body',
82
+ };
83
+
84
+ // CSS: selectors, custom properties and keyframes are the addressable units.
85
+ const CSS_QUERY = `
86
+ (stylesheet (rule_set (selectors) @name) @def.selector)
87
+ (keyframes_statement (keyframes_name) @name) @def.keyframes
88
+ (stylesheet (declaration (property_name) @name) @def.variable (#match? @name "^--"))
89
+ (rule_set (block (declaration (property_name) @name) @def.variable (#match? @name "^--")))
90
+ (call_expression (function_name) @_f (arguments (plain_value) @name) (#eq? @_f "var")) @ref.value
91
+ (import_statement) @import
92
+ `;
93
+
94
+ export const css = {
95
+ id: 'css',
96
+ grammar: 'css',
97
+ extensions: ['.css', '.scss', '.less'],
98
+ family: 'css',
99
+ query: CSS_QUERY,
100
+ implicitThis: false,
101
+ selfNames: [],
102
+ externalReceivers: new Set(),
103
+ builtinCalls: new Set(),
104
+ testFile: /$^/,
105
+ commentTypes: ['comment'],
106
+ parseImport(node) {
107
+ const m = /["']([^"']+)["']|url\(([^)]+)\)/.exec(node.text);
108
+ return m ? [{ source: (m[1] || m[2]).trim(), imported: '*', local: null }] : [];
109
+ },
110
+ isExported: () => true,
111
+ visibility: null,
112
+ isPrimitiveType: () => true,
113
+ normalizeName: (name) => name.replace(/\s+/g, ' ').trim().slice(0, 120),
114
+ bodyField: 'block',
115
+ };