graph-indexer 2.1.1 → 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.
- package/CHANGELOG.md +260 -1
- package/README.md +232 -312
- package/SECURITY.md +37 -59
- package/bin/graph-indexer.mjs +251 -0
- package/integrations/claude-code/.claude-plugin/plugin.json +8 -0
- package/integrations/claude-code/.mcp.json +8 -0
- package/integrations/claude-code/agents/code-structure.md +22 -0
- package/integrations/claude-code/hooks/gi-hook.mjs +99 -0
- package/integrations/claude-code/hooks/hooks.json +16 -0
- package/integrations/opencode/graph-indexer.js +124 -0
- package/package.json +32 -109
- package/src/cli/helper.mjs +67 -0
- package/src/cli/hook.mjs +356 -0
- package/src/cli/init.mjs +255 -0
- package/src/cli/resident.mjs +175 -0
- package/src/index/discover.mjs +130 -0
- package/src/index/fingerprint.mjs +30 -0
- package/src/index/graph.mjs +61 -0
- package/src/index/indexer.mjs +476 -0
- package/src/index/modules.mjs +331 -0
- package/src/index/resolver.mjs +954 -0
- package/src/mcp/render.mjs +60 -0
- package/src/mcp/server.mjs +147 -0
- package/src/mcp/tools.mjs +973 -0
- package/src/parse/arity.mjs +152 -0
- package/src/parse/extract.mjs +1031 -0
- package/src/parse/lang/csharp.mjs +106 -0
- package/src/parse/lang/ecma.mjs +438 -0
- package/src/parse/lang/go.mjs +194 -0
- package/src/parse/lang/jvm.mjs +118 -0
- package/src/parse/lang/kotlin.mjs +97 -0
- package/src/parse/lang/misc.mjs +115 -0
- package/src/parse/lang/native.mjs +126 -0
- package/src/parse/lang/python.mjs +153 -0
- package/src/parse/lang/rust.mjs +157 -0
- package/src/parse/lang/scripting.mjs +219 -0
- package/src/parse/languages.mjs +48 -0
- package/src/parse/runtime.mjs +56 -0
- package/src/query/check.mjs +343 -0
- package/src/query/facts.mjs +323 -0
- package/src/query/intel.mjs +680 -0
- package/src/query/read.mjs +81 -0
- package/src/query/testcmd.mjs +119 -0
- package/src/query/textsearch.mjs +160 -0
- package/src/search/search.mjs +210 -0
- package/src/search/tokenize.mjs +188 -0
- package/src/store/db.mjs +169 -0
- package/src/util/paths.mjs +24 -0
- package/vendor/grammars/bash.wasm.gz +0 -0
- package/vendor/grammars/c.wasm.gz +0 -0
- package/vendor/grammars/c_sharp.wasm.gz +0 -0
- package/vendor/grammars/cpp.wasm.gz +0 -0
- package/vendor/grammars/css.wasm.gz +0 -0
- package/vendor/grammars/go.wasm.gz +0 -0
- package/vendor/grammars/java.wasm.gz +0 -0
- package/vendor/grammars/javascript.wasm.gz +0 -0
- package/vendor/grammars/kotlin.wasm.gz +0 -0
- package/vendor/grammars/manifest.json +148 -0
- package/vendor/grammars/php.wasm.gz +0 -0
- package/vendor/grammars/python.wasm.gz +0 -0
- package/vendor/grammars/ruby.wasm.gz +0 -0
- package/vendor/grammars/rust.wasm.gz +0 -0
- package/vendor/grammars/scala.wasm.gz +0 -0
- package/vendor/grammars/tsx.wasm.gz +0 -0
- package/vendor/grammars/typescript.wasm.gz +0 -0
- package/vendor/web-tree-sitter/web-tree-sitter.js +3980 -0
- package/vendor/web-tree-sitter/web-tree-sitter.wasm +0 -0
- package/cli-ui.mjs +0 -78
- package/colbert.mjs +0 -168
- package/config.mjs +0 -494
- package/daemon-ctl.mjs +0 -175
- package/daemon-lock.mjs +0 -69
- package/embedders/python/mlx_embed_server.py +0 -61
- package/embedders/python/requirements-mlx.txt +0 -5
- package/embedders/setup-mlx.mjs +0 -110
- package/embeddings.mjs +0 -571
- package/engine/binary.mjs +0 -437
- package/engine/memory.mjs +0 -1003
- package/engine/sqlite.mjs +0 -1136
- package/enrichment.mjs +0 -521
- package/git-signals.mjs +0 -248
- package/indexer.mjs +0 -546
- package/init.mjs +0 -1809
- package/layout.mjs +0 -123
- package/mcp/centrality.mjs +0 -117
- package/mcp/format.mjs +0 -61
- package/mcp/resolver.mjs +0 -116
- package/mcp/symbolgraph.mjs +0 -137
- package/mcp/taint.mjs +0 -225
- package/mcp/tools.mjs +0 -1582
- package/mcp/topology.mjs +0 -676
- package/mcp-server.mjs +0 -197
- package/parse/extractor.mjs +0 -628
- package/parse/imports.mjs +0 -365
- package/parse/interprocedural.mjs +0 -134
- package/parse/languages.mjs +0 -253
- package/parse/metadata.mjs +0 -701
- package/parse/routes.mjs +0 -327
- package/parse/scip.mjs +0 -391
- package/parse/taint-patterns.mjs +0 -119
- package/prompts/CORE.md +0 -91
- package/prompts/DOMAIN_TEMPLATE.md +0 -46
- package/prompts/INTEGRATION.md +0 -123
- package/prompts/frameworks/ANDROID.md +0 -17
- package/prompts/frameworks/ASPNET_CORE.md +0 -19
- package/prompts/frameworks/FASTAPI_DJANGO.md +0 -20
- package/prompts/frameworks/LARAVEL_SYMFONY.md +0 -22
- package/prompts/frameworks/NODE_EXPRESS_NESTJS.md +0 -19
- package/prompts/frameworks/RAILS.md +0 -20
- package/prompts/frameworks/REACT.md +0 -20
- package/prompts/frameworks/SPRING_BOOT.md +0 -20
- package/prompts/languages/BASH.md +0 -22
- package/prompts/languages/C.md +0 -21
- package/prompts/languages/CSHARP.md +0 -24
- package/prompts/languages/CSS_SCSS.md +0 -22
- package/prompts/languages/GO.md +0 -24
- package/prompts/languages/JAVA.md +0 -23
- package/prompts/languages/JAVASCRIPT_TYPESCRIPT.md +0 -24
- package/prompts/languages/KOTLIN.md +0 -24
- package/prompts/languages/PHP.md +0 -23
- package/prompts/languages/PYTHON.md +0 -23
- package/prompts/languages/RUBY.md +0 -23
- package/prompts/languages/RUST.md +0 -21
- package/prompts/languages/SWIFT.md +0 -21
- package/seal.mjs +0 -400
- package/search-core.mjs +0 -777
- package/search-sparse.mjs +0 -183
- package/storage.mjs +0 -73
- 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
|
+
};
|