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,106 @@
|
|
|
1
|
+
/** C# extraction spec. */
|
|
2
|
+
|
|
3
|
+
const T = (cap) => `[(identifier) @${cap} (generic_name (identifier) @${cap}) (qualified_name name: (identifier) @${cap}) (qualified_name name: (generic_name (identifier) @${cap})) (nullable_type (identifier) @${cap})]`;
|
|
4
|
+
|
|
5
|
+
const QUERY = `
|
|
6
|
+
(class_declaration name: (identifier) @name) @def.class
|
|
7
|
+
(interface_declaration name: (identifier) @name) @def.interface
|
|
8
|
+
(struct_declaration name: (identifier) @name) @def.struct
|
|
9
|
+
(enum_declaration name: (identifier) @name) @def.enum
|
|
10
|
+
(record_declaration name: (identifier) @name) @def.class
|
|
11
|
+
(delegate_declaration name: (identifier) @name) @def.type
|
|
12
|
+
(method_declaration returns: (_) @type name: (identifier) @name) @def.method
|
|
13
|
+
(method_declaration name: (identifier) @name) @def.method
|
|
14
|
+
(constructor_declaration name: (identifier) @name) @def.constructor
|
|
15
|
+
(property_declaration type: (_) @type name: (identifier) @name) @def.property
|
|
16
|
+
(property_declaration name: (identifier) @name) @def.property
|
|
17
|
+
(field_declaration (variable_declaration type: (_) @type (variable_declarator name: (identifier) @name))) @def.field
|
|
18
|
+
(field_declaration (variable_declaration (variable_declarator name: (identifier) @name))) @def.field
|
|
19
|
+
(enum_member_declaration name: (identifier) @name) @def.constant
|
|
20
|
+
|
|
21
|
+
(invocation_expression function: (identifier) @name) @ref.call
|
|
22
|
+
(invocation_expression function: (generic_name (identifier) @name)) @ref.call
|
|
23
|
+
(invocation_expression function: (member_access_expression expression: (_) @recv name: [(identifier) @name (generic_name (identifier) @name)])) @ref.call
|
|
24
|
+
(object_creation_expression type: ${T('name')}) @ref.new
|
|
25
|
+
(base_list ${T('name')}) @ref.inherit
|
|
26
|
+
(base_list (primary_constructor_base_type type: ${T('name')})) @ref.inherit
|
|
27
|
+
(attribute name: ${T('name')}) @ref.decorator
|
|
28
|
+
(variable_declaration type: ${T('name')}) @ref.type
|
|
29
|
+
(parameter type: ${T('name')}) @ref.type
|
|
30
|
+
(method_declaration returns: ${T('name')}) @ref.type
|
|
31
|
+
(property_declaration type: ${T('name')}) @ref.type
|
|
32
|
+
(type_argument_list ${T('name')}) @ref.type
|
|
33
|
+
(typeof_expression type: ${T('name')}) @ref.type
|
|
34
|
+
(argument (identifier) @name) @ref.value
|
|
35
|
+
|
|
36
|
+
[(lambda_expression) (anonymous_method_expression)] @scope
|
|
37
|
+
(return_statement (_) @ret)
|
|
38
|
+
(using_directive) @import
|
|
39
|
+
|
|
40
|
+
(variable_declaration type: (_) @bind.type (variable_declarator name: (identifier) @bind.name)) @bind
|
|
41
|
+
(variable_declaration (variable_declarator name: (identifier) @bind.name (object_creation_expression type: ${T('bind.new')}))) @bind
|
|
42
|
+
(variable_declaration (variable_declarator name: (identifier) @bind.name (_) @bind.expr)) @bind
|
|
43
|
+
(parameter type: (_) @bind.type name: (identifier) @bind.name) @bind
|
|
44
|
+
(foreach_statement type: (_) @bind.type left: (identifier) @bind.name right: (_) @bind.elem) @bind
|
|
45
|
+
(field_declaration (variable_declaration type: (_) @field.type (variable_declarator name: (identifier) @field.name))) @field
|
|
46
|
+
(property_declaration type: (_) @field.type name: (identifier) @field.name) @field
|
|
47
|
+
`;
|
|
48
|
+
|
|
49
|
+
const BUILTIN = new Set(['string', 'String', 'int', 'long', 'bool', 'double', 'float', 'decimal', 'object', 'Object',
|
|
50
|
+
'void', 'dynamic', 'List', 'Dictionary', 'IEnumerable', 'IList', 'ICollection', 'Task', 'Guid', 'DateTime',
|
|
51
|
+
'TimeSpan', 'Exception', 'Func', 'Action', 'IReadOnlyList', 'IReadOnlyCollection', 'HashSet', 'Nullable',
|
|
52
|
+
'CancellationToken', 'Array', 'Type', 'byte', 'char', 'short', 'uint', 'ulong']);
|
|
53
|
+
|
|
54
|
+
function usingImport(node) {
|
|
55
|
+
const text = node.text.replace(/^global\s+/, '').replace(/^using\s+(static\s+)?/, '').replace(/;\s*$/, '').trim();
|
|
56
|
+
const alias = /^(\w+)\s*=\s*(.+)$/.exec(text);
|
|
57
|
+
if (alias) return [{ source: alias[2].trim(), imported: '*', local: alias[1] }];
|
|
58
|
+
return [{ source: text, imported: '*', local: null, wildcard: true }];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function modifiers(node) { return node.namedChildren.filter(c => c.type === 'modifier').map(c => c.text).join(' '); }
|
|
62
|
+
|
|
63
|
+
function fileInfo(root) {
|
|
64
|
+
const ns = [];
|
|
65
|
+
(function walk(n, depth) {
|
|
66
|
+
if (depth > 3) return;
|
|
67
|
+
for (const c of n.namedChildren) {
|
|
68
|
+
if (c.type === 'namespace_declaration' || c.type === 'file_scoped_namespace_declaration') ns.push(c.childForFieldName('name')?.text);
|
|
69
|
+
else if (c.type === 'declaration_list') walk(c, depth + 1);
|
|
70
|
+
}
|
|
71
|
+
})(root, 0);
|
|
72
|
+
return { package: ns.filter(Boolean)[0] ?? null };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export const csharp = {
|
|
76
|
+
id: 'csharp',
|
|
77
|
+
grammar: 'c_sharp',
|
|
78
|
+
extensions: ['.cs'],
|
|
79
|
+
family: 'dotnet',
|
|
80
|
+
query: QUERY,
|
|
81
|
+
implicitThis: true,
|
|
82
|
+
selfNames: ['this'],
|
|
83
|
+
externalReceivers: new Set(['Console', 'Math', 'String', 'Task', 'Enumerable', 'Guid', 'DateTime', 'Convert',
|
|
84
|
+
'Assert', 'Mock', 'JsonSerializer', 'File', 'Path', 'Directory', 'Environment', 'Debug', 'Trace', '_logger', 'logger', 'Logger']),
|
|
85
|
+
builtinCalls: new Set(['nameof', 'typeof', 'ToString', 'Equals', 'GetHashCode', 'GetType']),
|
|
86
|
+
testFile: /(^|\/)(tests?|Tests?|[\w.]*\.Tests?)\/|Tests?\.cs$/,
|
|
87
|
+
commentTypes: ['comment'],
|
|
88
|
+
parseImport: usingImport,
|
|
89
|
+
isExported: (node) => /\b(public|internal)\b/.test(modifiers(node)) || node.parent?.parent?.type === 'interface_declaration',
|
|
90
|
+
visibility: (node) => { const m = modifiers(node); return /\bprivate\b/.test(m) ? 'private' : /\bprotected\b/.test(m) ? 'protected' : /\bpublic\b/.test(m) ? 'public' : null; },
|
|
91
|
+
isPrimitiveType: (t) => BUILTIN.has(t),
|
|
92
|
+
transparentTypes: new Set(['Task', 'ValueTask', 'Nullable']),
|
|
93
|
+
elementTypes: new Set(['List', 'IList', 'IEnumerable', 'ICollection', 'IReadOnlyList', 'IReadOnlyCollection', 'HashSet', 'ISet', 'Queue', 'Stack',
|
|
94
|
+
'LinkedList', 'Collection', 'ObservableCollection', 'ImmutableList', 'ImmutableArray', 'IAsyncEnumerable', 'IQueryable', 'Span', 'ReadOnlySpan', 'Memory']),
|
|
95
|
+
elementMethods: new Set(['First', 'FirstOrDefault', 'Last', 'LastOrDefault', 'Single', 'SingleOrDefault', 'ElementAt', 'ElementAtOrDefault', 'Find', 'Dequeue', 'Peek', 'Pop']),
|
|
96
|
+
mapTypes: new Set(['Dictionary', 'IDictionary', 'IReadOnlyDictionary', 'ConcurrentDictionary', 'SortedDictionary', 'ImmutableDictionary']),
|
|
97
|
+
mapMethods: new Set(['GetValueOrDefault', 'GetOrAdd']),
|
|
98
|
+
mapValueMethods: new Set(['Values']),
|
|
99
|
+
decoratorsOf(node) {
|
|
100
|
+
return node.namedChildren.filter(c => c.type === 'attribute_list')
|
|
101
|
+
.flatMap(l => l.namedChildren.filter(a => a.type === 'attribute').map(a => a.childForFieldName('name')?.text))
|
|
102
|
+
.filter(Boolean).slice(0, 8);
|
|
103
|
+
},
|
|
104
|
+
fileInfo,
|
|
105
|
+
bodyField: 'body',
|
|
106
|
+
};
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JavaScript / TypeScript / TSX extraction specs.
|
|
3
|
+
*
|
|
4
|
+
* Captures follow the engine convention (see ../extract.mjs):
|
|
5
|
+
* @def.<kind> + @name [+ @owner] a definition
|
|
6
|
+
* @ref.<kind> + @name [+ @recv] a reference (call/new/type/inherit/decorator/value)
|
|
7
|
+
* @import an import/export-from statement (parsed by the hook)
|
|
8
|
+
* @import.require + @src a CommonJS require() call
|
|
9
|
+
* @bind + @bind.name + @bind.(type|new|call|expr|elem) local variable → type evidence
|
|
10
|
+
* @field + @field.name + @field.(type|new|expr) class field → type evidence
|
|
11
|
+
* (`expr` = the initialiser expression, `elem` = a collection whose element the name is bound to)
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
const DEFS_COMMON = `
|
|
15
|
+
(function_declaration name: (identifier) @name) @def.function
|
|
16
|
+
(generator_function_declaration name: (identifier) @name) @def.function
|
|
17
|
+
(class_declaration name: (_) @name) @def.class
|
|
18
|
+
(class name: (_) @name) @def.class
|
|
19
|
+
(class "class" @name !name) @def.class
|
|
20
|
+
(method_definition name: (_) @name) @def.method
|
|
21
|
+
(lexical_declaration (variable_declarator name: (identifier) @name value: [(arrow_function) (function_expression) (generator_function)]) @def.function)
|
|
22
|
+
(variable_declaration (variable_declarator name: (identifier) @name value: [(arrow_function) (function_expression) (generator_function)]) @def.function)
|
|
23
|
+
(variable_declarator name: (identifier) @name value: (class)) @def.class
|
|
24
|
+
(lexical_declaration (variable_declarator name: (identifier) @name value: (_) @_v) @def.variable (#not-match? @_v "^(async\\\\s*)?(function|\\\\(|[A-Za-z_$][A-Za-z0-9_$]*\\\\s*=>)"))
|
|
25
|
+
(variable_declaration (variable_declarator name: (identifier) @name value: (_) @_v) @def.variable (#not-match? @_v "^(async\\\\s*)?(function|\\\\(|[A-Za-z_$][A-Za-z0-9_$]*\\\\s*=>)"))
|
|
26
|
+
(assignment_expression
|
|
27
|
+
left: (member_expression
|
|
28
|
+
object: (member_expression object: (identifier) @owner property: (property_identifier) @_proto)
|
|
29
|
+
property: (property_identifier) @name)
|
|
30
|
+
right: [(function_expression) (arrow_function)]
|
|
31
|
+
(#eq? @_proto "prototype")) @def.method
|
|
32
|
+
(expression_statement (assignment_expression
|
|
33
|
+
left: (member_expression object: (identifier) @owner property: (property_identifier) @name)
|
|
34
|
+
right: [(function_expression) (arrow_function)])) @def.function
|
|
35
|
+
(expression_statement (assignment_expression
|
|
36
|
+
left: (member_expression object: (member_expression object: (identifier) @_m property: (property_identifier) @_e) property: (property_identifier) @name)
|
|
37
|
+
right: [(function_expression) (arrow_function)]
|
|
38
|
+
(#eq? @_m "module") (#eq? @_e "exports"))) @def.function
|
|
39
|
+
(pair key: (property_identifier) @name value: [(function_expression) (arrow_function)]) @def.method
|
|
40
|
+
(export_statement "default" value: [(function_expression) (arrow_function) (object) (call_expression) (binary_expression) (class)] @name) @def.function
|
|
41
|
+
(export_statement "default" declaration: [(function_declaration !name) (class_declaration !name)] @name) @def.function
|
|
42
|
+
`;
|
|
43
|
+
|
|
44
|
+
const DEFS_JS = `
|
|
45
|
+
(field_definition property: (_) @name value: [(arrow_function) (function_expression)]) @def.method
|
|
46
|
+
(field_definition property: (_) @name value: (class)) @def.class
|
|
47
|
+
(field_definition property: (_) @name) @def.field
|
|
48
|
+
`;
|
|
49
|
+
|
|
50
|
+
const DEFS_TS = `
|
|
51
|
+
(function_signature name: (identifier) @name) @def.function
|
|
52
|
+
(abstract_class_declaration name: (type_identifier) @name) @def.class
|
|
53
|
+
(interface_declaration name: (type_identifier) @name) @def.interface
|
|
54
|
+
(type_alias_declaration name: (type_identifier) @name) @def.type
|
|
55
|
+
(enum_declaration name: (identifier) @name) @def.enum
|
|
56
|
+
(internal_module name: (_) @name) @def.module
|
|
57
|
+
(module name: (_) @name) @def.module
|
|
58
|
+
(method_signature name: (_) @name) @def.method
|
|
59
|
+
(abstract_method_signature name: (_) @name) @def.method
|
|
60
|
+
(public_field_definition name: (_) @name value: [(arrow_function) (function_expression)]) @def.method
|
|
61
|
+
(public_field_definition name: (_) @name value: (class)) @def.class
|
|
62
|
+
(public_field_definition name: (_) @name) @def.field
|
|
63
|
+
(required_parameter (accessibility_modifier) pattern: (identifier) @name) @def.field
|
|
64
|
+
(required_parameter "readonly" pattern: (identifier) @name) @def.field
|
|
65
|
+
(optional_parameter (accessibility_modifier) pattern: (identifier) @name) @def.field
|
|
66
|
+
(property_signature name: (_) @name) @def.field
|
|
67
|
+
(function_declaration name: (identifier) @name return_type: (type_annotation (_) @type)) @def.function
|
|
68
|
+
(function_signature name: (identifier) @name return_type: (type_annotation (_) @type)) @def.function
|
|
69
|
+
(method_definition name: (_) @name return_type: (type_annotation (_) @type)) @def.method
|
|
70
|
+
(method_signature name: (_) @name return_type: (type_annotation (_) @type)) @def.method
|
|
71
|
+
(abstract_method_signature name: (_) @name return_type: (type_annotation (_) @type)) @def.method
|
|
72
|
+
(lexical_declaration (variable_declarator name: (identifier) @name value: (arrow_function return_type: (type_annotation (_) @type))) @def.function)
|
|
73
|
+
(public_field_definition name: (_) @name type: (type_annotation (_) @type)) @def.field
|
|
74
|
+
(property_signature name: (_) @name type: (type_annotation (_) @type)) @def.field
|
|
75
|
+
(class_declaration name: (_) @name (class_heritage (extends_clause) @type)) @def.class
|
|
76
|
+
(abstract_class_declaration name: (_) @name (class_heritage (extends_clause) @type)) @def.class
|
|
77
|
+
(class name: (_) @name (class_heritage (extends_clause) @type)) @def.class
|
|
78
|
+
(class "class" @name !name (class_heritage (extends_clause) @type)) @def.class
|
|
79
|
+
(variable_declarator name: (identifier) @name value: (class (class_heritage (extends_clause) @type))) @def.class
|
|
80
|
+
(required_parameter (accessibility_modifier) pattern: (identifier) @name type: (type_annotation (_) @type)) @def.field
|
|
81
|
+
(required_parameter "readonly" pattern: (identifier) @name type: (type_annotation (_) @type)) @def.field
|
|
82
|
+
(optional_parameter (accessibility_modifier) pattern: (identifier) @name type: (type_annotation (_) @type)) @def.field
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
const REFS_COMMON = `
|
|
86
|
+
(call_expression function: (identifier) @name) @ref.call
|
|
87
|
+
(call_expression function: (member_expression object: (_) @recv property: (_) @name)) @ref.call
|
|
88
|
+
(call_expression function: (await_expression (identifier) @name)) @ref.call
|
|
89
|
+
(call_expression function: (await_expression (member_expression object: (_) @recv property: (_) @name))) @ref.call
|
|
90
|
+
(new_expression constructor: (identifier) @name) @ref.new
|
|
91
|
+
(new_expression constructor: (member_expression object: (_) @recv property: (_) @name)) @ref.new
|
|
92
|
+
(decorator (identifier) @name) @ref.decorator
|
|
93
|
+
(decorator (call_expression function: (identifier) @name)) @ref.decorator
|
|
94
|
+
(decorator (call_expression function: (member_expression object: (_) @recv property: (_) @name))) @ref.decorator
|
|
95
|
+
(arguments (identifier) @name) @ref.value
|
|
96
|
+
(pair value: (identifier) @name) @ref.value
|
|
97
|
+
(array (identifier) @name) @ref.value
|
|
98
|
+
(shorthand_property_identifier) @name @ref.value
|
|
99
|
+
(member_expression object: (_) @recv property: (property_identifier) @name) @ref.read
|
|
100
|
+
(member_expression object: (identifier) @name) @ref.value
|
|
101
|
+
(binary_expression operator: "instanceof" right: (identifier) @name) @ref.type
|
|
102
|
+
(computed_property_name (identifier) @name) @ref.value
|
|
103
|
+
(computed_property_name (member_expression object: (_) @recv property: (property_identifier) @name)) @ref.read
|
|
104
|
+
(unary_expression operator: "typeof" argument: (identifier) @name) @ref.value
|
|
105
|
+
(arrow_function body: (identifier) @name) @ref.value
|
|
106
|
+
(ternary_expression consequence: (identifier) @name) @ref.value
|
|
107
|
+
(ternary_expression alternative: (identifier) @name) @ref.value
|
|
108
|
+
(return_statement (identifier) @name) @ref.value
|
|
109
|
+
(variable_declarator value: (identifier) @name) @ref.value
|
|
110
|
+
(assignment_expression right: (identifier) @name) @ref.value
|
|
111
|
+
`;
|
|
112
|
+
|
|
113
|
+
const REFS_JSX = `
|
|
114
|
+
(jsx_opening_element name: (identifier) @name) @ref.call
|
|
115
|
+
(jsx_self_closing_element name: (identifier) @name) @ref.call
|
|
116
|
+
(jsx_opening_element name: (member_expression object: (_) @recv property: (_) @name)) @ref.call
|
|
117
|
+
(jsx_self_closing_element name: (member_expression object: (_) @recv property: (_) @name)) @ref.call
|
|
118
|
+
`;
|
|
119
|
+
|
|
120
|
+
const REFS_JS = `
|
|
121
|
+
(class_heritage (identifier) @name) @ref.inherit
|
|
122
|
+
(class_heritage (member_expression object: (_) @recv property: (_) @name)) @ref.inherit
|
|
123
|
+
`;
|
|
124
|
+
|
|
125
|
+
const REFS_TS = `
|
|
126
|
+
(extends_clause value: (identifier) @name) @ref.inherit
|
|
127
|
+
(extends_clause value: (member_expression object: (_) @recv property: (_) @name)) @ref.inherit
|
|
128
|
+
(implements_clause (type_identifier) @name) @ref.inherit
|
|
129
|
+
(implements_clause (generic_type name: (type_identifier) @name)) @ref.inherit
|
|
130
|
+
(extends_type_clause type: (type_identifier) @name) @ref.inherit
|
|
131
|
+
(extends_type_clause type: (generic_type name: (type_identifier) @name)) @ref.inherit
|
|
132
|
+
(type_identifier) @name @ref.type
|
|
133
|
+
(nested_type_identifier module: (_) @recv name: (type_identifier) @name) @ref.type
|
|
134
|
+
(type_query (identifier) @name) @ref.value
|
|
135
|
+
(type_query (member_expression object: (_) @recv property: (property_identifier) @name)) @ref.type
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
const IMPORTS_COMMON = `
|
|
139
|
+
(import_statement) @import
|
|
140
|
+
(export_statement source: (string)) @import
|
|
141
|
+
(call_expression function: (identifier) @_req arguments: (arguments . (string) @src) (#eq? @_req "require")) @import.require
|
|
142
|
+
|
|
143
|
+
[(arrow_function) (function_expression) (generator_function)] @scope
|
|
144
|
+
(return_statement (_) @ret)
|
|
145
|
+
(arrow_function body: [(call_expression) (new_expression) (member_expression) (identifier) (await_expression) (parenthesized_expression) (this) (subscript_expression)] @ret)
|
|
146
|
+
`;
|
|
147
|
+
|
|
148
|
+
// `xs.forEach(x => …)`: the first callback parameter of an element-wise method is an element (a
|
|
149
|
+
// map's value for `m.forEach(v => …)`).
|
|
150
|
+
const callbackParam = (param) => `(call_expression
|
|
151
|
+
function: (member_expression object: (_) @bind.each property: (property_identifier) @_m)
|
|
152
|
+
arguments: (arguments . (arrow_function ${param}))
|
|
153
|
+
(#match? @_m "^(forEach|map|filter|find|findLast|findIndex|findLastIndex|some|every|flatMap)$")) @bind`;
|
|
154
|
+
|
|
155
|
+
const BINDINGS_COMMON = `
|
|
156
|
+
(variable_declarator name: (identifier) @bind.name value: (_) @bind.expr) @bind
|
|
157
|
+
(for_in_statement left: (identifier) @bind.name "of" right: (_) @bind.elem) @bind
|
|
158
|
+
${callbackParam('parameter: (identifier) @bind.name')}
|
|
159
|
+
(assignment_expression left: (member_expression object: (this) property: (property_identifier) @field.name) right: (_) @field.expr) @field
|
|
160
|
+
`;
|
|
161
|
+
|
|
162
|
+
const BINDINGS_TS = `
|
|
163
|
+
${callbackParam('parameters: (formal_parameters . (required_parameter pattern: (identifier) @bind.name))')}
|
|
164
|
+
(call_expression function: [(identifier) (member_expression)] @cb.fn arguments: (arguments [(arrow_function) (function_expression)] @cb.arg)) @cb
|
|
165
|
+
(variable_declarator name: (identifier) @bind.name type: (type_annotation (_) @bind.type)) @bind
|
|
166
|
+
(required_parameter pattern: (identifier) @bind.name type: (type_annotation (_) @bind.type)) @bind
|
|
167
|
+
(optional_parameter pattern: (identifier) @bind.name type: (type_annotation (_) @bind.type)) @bind
|
|
168
|
+
(variable_declarator name: (object_pattern (pair_pattern key: (property_identifier) @bind.key value: (identifier) @bind.name)) value: (_) @bind.expr) @bind
|
|
169
|
+
(variable_declarator name: (object_pattern (shorthand_property_identifier_pattern) @bind.name @bind.key) value: (_) @bind.expr) @bind
|
|
170
|
+
(required_parameter pattern: (object_pattern (pair_pattern key: (property_identifier) @bind.key value: (identifier) @bind.name)) type: (type_annotation (_) @bind.of)) @bind
|
|
171
|
+
(required_parameter pattern: (object_pattern (shorthand_property_identifier_pattern) @bind.name @bind.key) type: (type_annotation (_) @bind.of)) @bind
|
|
172
|
+
(public_field_definition name: (property_identifier) @field.name type: (type_annotation (_) @field.type)) @field
|
|
173
|
+
(public_field_definition name: (property_identifier) @field.name value: (_) @field.expr) @field
|
|
174
|
+
(required_parameter (accessibility_modifier) pattern: (identifier) @field.name type: (type_annotation (_) @field.type)) @field
|
|
175
|
+
(required_parameter "readonly" pattern: (identifier) @field.name type: (type_annotation (_) @field.type)) @field
|
|
176
|
+
(optional_parameter (accessibility_modifier) pattern: (identifier) @field.name type: (type_annotation (_) @field.type)) @field
|
|
177
|
+
`;
|
|
178
|
+
|
|
179
|
+
const BINDINGS_JS = `
|
|
180
|
+
${callbackParam('parameters: (formal_parameters . (identifier) @bind.name)')}
|
|
181
|
+
(field_definition property: (property_identifier) @field.name value: (_) @field.expr) @field
|
|
182
|
+
`;
|
|
183
|
+
|
|
184
|
+
// Wrappers whose members are reached through the wrapped type (after await / by convention).
|
|
185
|
+
const TRANSPARENT_TYPES = new Set(['Promise', 'PromiseLike', 'Awaited', 'Readonly', 'Partial', 'Required', 'NonNullable', 'DeepPartial', 'DeepReadonly', 'Mutable', 'Pick', 'Omit']);
|
|
186
|
+
/**
|
|
187
|
+
* What a type alias has the members of: `type E = Pick<Entry, 'a'>`, `type E = Entry & { b: B }`,
|
|
188
|
+
* `type E = Readonly<Entry>` — each named type it is made of (through the wrappers above).
|
|
189
|
+
*/
|
|
190
|
+
function aliasBases(node) {
|
|
191
|
+
if (node.type !== 'type_alias_declaration') return [];
|
|
192
|
+
const value = node.childForFieldName('value');
|
|
193
|
+
const out = [];
|
|
194
|
+
const visit = (n, depth = 0) => {
|
|
195
|
+
if (!n || depth > 4) return;
|
|
196
|
+
if (n.type === 'intersection_type' || n.type === 'parenthesized_type') { for (const c of n.namedChildren) visit(c, depth + 1); return; }
|
|
197
|
+
if (n.type === 'type_identifier') { out.push(n.text); return; }
|
|
198
|
+
if (n.type === 'nested_type_identifier') { out.push(n.childForFieldName('name')?.text); return; }
|
|
199
|
+
if (n.type === 'generic_type') {
|
|
200
|
+
const head = n.childForFieldName('name');
|
|
201
|
+
const name = head?.type === 'nested_type_identifier' ? head.childForFieldName('name')?.text : head?.text;
|
|
202
|
+
if (TRANSPARENT_TYPES.has(name)) visit(n.childForFieldName('type_arguments')?.namedChildren[0], depth + 1);
|
|
203
|
+
else if (name) out.push(name);
|
|
204
|
+
}
|
|
205
|
+
};
|
|
206
|
+
visit(value);
|
|
207
|
+
return out.filter(Boolean);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Collections: `x[i]`, `for (const e of x)` and `x.forEach(e => …)` see the element type.
|
|
211
|
+
const ELEMENT_TYPES = new Set(['Array', 'ReadonlyArray', 'Set', 'ReadonlySet', 'Iterable', 'IterableIterator', 'Iterator', 'AsyncIterable', 'AsyncIterableIterator', 'Generator', 'AsyncGenerator']);
|
|
212
|
+
// Types whose members never live in the repository.
|
|
213
|
+
// (`any` / `unknown` are not here: a value of that type may well be an instance of a repository class)
|
|
214
|
+
const PRIMITIVE_TYPES = new Set(['string', 'number', 'boolean', 'bigint', 'symbol', 'object', 'void', 'never', 'undefined', 'null',
|
|
215
|
+
'String', 'Number', 'Boolean', 'Object', 'Function', 'Date', 'RegExp', 'Map', 'WeakMap', 'WeakSet', 'Record', 'Error', 'Buffer',
|
|
216
|
+
'ArrayBuffer', 'Uint8Array', 'DataView', 'URL', 'URLSearchParams', 'Headers', 'Request', 'Response', 'AbortController', 'AbortSignal']);
|
|
217
|
+
|
|
218
|
+
// Ubiquitous globals whose members never resolve into the repository.
|
|
219
|
+
const EXTERNAL_RECEIVERS = new Set([
|
|
220
|
+
'console', 'JSON', 'Math', 'Object', 'Array', 'Promise', 'Reflect', 'Number', 'String', 'Symbol',
|
|
221
|
+
'Date', 'process', 'window', 'document', 'globalThis', 'Buffer', 'Intl', 'navigator', 'performance',
|
|
222
|
+
'localStorage', 'sessionStorage', 'location', 'history', 'Error', 'Map', 'Set', 'WeakMap', 'RegExp',
|
|
223
|
+
'module', 'exports', 'require', 'jest', 'vi', 'expect', 'assert', 'chai', 'sinon',
|
|
224
|
+
]);
|
|
225
|
+
const BUILTIN_CALLS = new Set([
|
|
226
|
+
'require', 'setTimeout', 'setInterval', 'clearTimeout', 'clearInterval', 'setImmediate', 'parseInt',
|
|
227
|
+
'parseFloat', 'isNaN', 'isFinite', 'encodeURIComponent', 'decodeURIComponent', 'encodeURI', 'decodeURI',
|
|
228
|
+
'String', 'Number', 'Boolean', 'Symbol', 'BigInt', 'queueMicrotask', 'structuredClone', 'fetch', 'eval',
|
|
229
|
+
'describe', 'it', 'test', 'expect', 'beforeEach', 'afterEach', 'beforeAll', 'afterAll', 'suite', 'context',
|
|
230
|
+
]);
|
|
231
|
+
|
|
232
|
+
// a top-level integration/ directory holds integration-test apps (nestjs, many monorepos)
|
|
233
|
+
const TEST_FILE_RE = /(^|\/)(__tests__|__mocks__|tests?|spec|e2e)\/|^integration\/|\.(test|spec|e2e-spec|cy)\.[cm]?[jt]sx?$/;
|
|
234
|
+
|
|
235
|
+
function stripQuotes(s) { return s.replace(/^['"`]|['"`]$/g, ''); }
|
|
236
|
+
|
|
237
|
+
/** Parse an ES import / export-from statement node into import records. */
|
|
238
|
+
function parseImportNode(node) {
|
|
239
|
+
const out = [];
|
|
240
|
+
const srcNode = node.childForFieldName('source');
|
|
241
|
+
if (!srcNode) return out;
|
|
242
|
+
const source = stripQuotes(srcNode.text);
|
|
243
|
+
if (node.type === 'import_statement') {
|
|
244
|
+
let any = false;
|
|
245
|
+
for (const child of node.namedChildren) {
|
|
246
|
+
if (child.type === 'import_clause') {
|
|
247
|
+
for (const c of child.namedChildren) {
|
|
248
|
+
if (c.type === 'identifier') { out.push({ source, imported: 'default', local: c.text }); any = true; }
|
|
249
|
+
else if (c.type === 'namespace_import') {
|
|
250
|
+
const id = c.namedChildren.find(n => n.type === 'identifier');
|
|
251
|
+
if (id) { out.push({ source, imported: '*', local: id.text }); any = true; }
|
|
252
|
+
} else if (c.type === 'named_imports') {
|
|
253
|
+
for (const spec of c.namedChildren) {
|
|
254
|
+
if (spec.type !== 'import_specifier') continue;
|
|
255
|
+
const name = spec.childForFieldName('name')?.text;
|
|
256
|
+
const alias = spec.childForFieldName('alias')?.text;
|
|
257
|
+
if (name) { out.push({ source, imported: stripQuotes(name), local: alias || stripQuotes(name) }); any = true; }
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
} else if (child.type === 'import_require_clause') {
|
|
262
|
+
const id = child.namedChildren.find(n => n.type === 'identifier');
|
|
263
|
+
if (id) { out.push({ source, imported: '*', local: id.text }); any = true; }
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
if (!any) out.push({ source, imported: null, local: null }); // side-effect import
|
|
267
|
+
} else if (node.type === 'export_statement') {
|
|
268
|
+
const clause = node.namedChildren.find(n => n.type === 'export_clause');
|
|
269
|
+
const nsExport = node.namedChildren.find(n => n.type === 'namespace_export');
|
|
270
|
+
if (clause) {
|
|
271
|
+
for (const spec of clause.namedChildren) {
|
|
272
|
+
if (spec.type !== 'export_specifier') continue;
|
|
273
|
+
const name = spec.childForFieldName('name')?.text;
|
|
274
|
+
const alias = spec.childForFieldName('alias')?.text;
|
|
275
|
+
if (name) out.push({ source, imported: stripQuotes(name), local: null, reexport: stripQuotes(alias || name) });
|
|
276
|
+
}
|
|
277
|
+
} else if (nsExport) {
|
|
278
|
+
const id = nsExport.namedChildren[0];
|
|
279
|
+
out.push({ source, imported: '*', local: null, reexport: id ? stripQuotes(id.text) : '*' });
|
|
280
|
+
} else {
|
|
281
|
+
out.push({ source, imported: '*', local: null, reexport: '*' });
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
return out;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/** const x = require('m') / const { a, b: c } = require('m') / require('m') */
|
|
288
|
+
function parseRequire(callNode, srcNode) {
|
|
289
|
+
const source = stripQuotes(srcNode.text);
|
|
290
|
+
let p = callNode.parent;
|
|
291
|
+
if (p?.type === 'await_expression') p = p.parent;
|
|
292
|
+
if (p?.type === 'variable_declarator') {
|
|
293
|
+
const nameNode = p.childForFieldName('name');
|
|
294
|
+
if (nameNode?.type === 'identifier') return [{ source, imported: '*', local: nameNode.text }];
|
|
295
|
+
if (nameNode?.type === 'object_pattern') {
|
|
296
|
+
const out = [];
|
|
297
|
+
for (const c of nameNode.namedChildren) {
|
|
298
|
+
if (c.type === 'shorthand_property_identifier_pattern') out.push({ source, imported: c.text, local: c.text });
|
|
299
|
+
else if (c.type === 'pair_pattern') {
|
|
300
|
+
const k = c.childForFieldName('key')?.text, v = c.childForFieldName('value');
|
|
301
|
+
if (k && v?.type === 'identifier') out.push({ source, imported: k, local: v.text });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (out.length) return out;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return [{ source, imported: null, local: null }];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
// what names a class expression (`const X = class {}`, a field, a default export) is the definition
|
|
311
|
+
const CLASS_HOLDERS = new Set(['variable_declarator', 'public_field_definition', 'field_definition', 'export_statement']);
|
|
312
|
+
const isAnonymousClass = (node) => node.type === 'class' && !node.childForFieldName('name');
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* The name of an anonymous class expression: what importers call it when it is a CommonJS export
|
|
316
|
+
* (`module.exports = class …`, `exports.Foo = class …`), else `<anonymous>` (`return class extends
|
|
317
|
+
* ModuleRef {…}`, `{ useClass: class {…} }`), a name no code can refer to. It is a symbol of its
|
|
318
|
+
* own so that `this` in its methods is an instance of it and its bases.
|
|
319
|
+
*/
|
|
320
|
+
function anonymousClassName(node, relPath) {
|
|
321
|
+
const p = node.parent;
|
|
322
|
+
const left = p?.type === 'assignment_expression' && p.childForFieldName('right')?.id === node.id ? p.childForFieldName('left') : null;
|
|
323
|
+
const target = left?.type === 'member_expression' ? left.text.replace(/\s+/g, '') : '';
|
|
324
|
+
if (target === 'module.exports') return fileStem(relPath) || '<anonymous>';
|
|
325
|
+
if (/^(module\.)?exports\.[A-Za-z_$][\w$]*$/.test(target)) return target.slice(target.lastIndexOf('.') + 1);
|
|
326
|
+
return '<anonymous>';
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/** What importers call a module's default export: its file name in camel case (`index` → its directory). */
|
|
330
|
+
function fileStem(relPath) {
|
|
331
|
+
const base = String(relPath ?? '').split('/').pop().replace(/\.[^.]+$/, '');
|
|
332
|
+
const stem = base === 'index' ? String(relPath).split('/').slice(-2, -1)[0] ?? base : base;
|
|
333
|
+
return stem.replace(/[-_.](\w)/g, (_, c) => c.toUpperCase()) || null;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/** `Array.from(xs)` and `[...xs]` hold the elements of xs: the node of xs, else null. */
|
|
337
|
+
function collectionSource(node) {
|
|
338
|
+
const only = (list) => { const kids = list?.namedChildren.filter(n => n.type !== 'comment') ?? []; return kids.length === 1 ? kids[0] : null; };
|
|
339
|
+
if (node.type === 'call_expression' && node.childForFieldName('function')?.text.replace(/\s+/g, '') === 'Array.from') {
|
|
340
|
+
const arg = only(node.childForFieldName('arguments')); // a second argument maps the elements
|
|
341
|
+
return arg && arg.type !== 'spread_element' ? arg : null;
|
|
342
|
+
}
|
|
343
|
+
if (node.type === 'array') {
|
|
344
|
+
const el = only(node);
|
|
345
|
+
return el?.type === 'spread_element' ? el.namedChildren[0] ?? null : null;
|
|
346
|
+
}
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** `const x = require('y')` / `const x = require('y').z` / `const {a} = require('y')` are imports, not definitions. */
|
|
351
|
+
function isRequireBinding(node) {
|
|
352
|
+
const decl = node.type === 'variable_declarator' ? node : node.namedChildren?.find(c => c.type === 'variable_declarator');
|
|
353
|
+
const v = decl?.childForFieldName('value');
|
|
354
|
+
return !!v && /^(await\s+)?require\s*\(/.test(v.text);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function isModuleLevel(node) {
|
|
358
|
+
// a variable declarator is module-level if its declaration sits in program / export_statement
|
|
359
|
+
let decl = node.type === 'variable_declarator' ? node.parent : node;
|
|
360
|
+
const p = decl?.parent;
|
|
361
|
+
return p?.type === 'program' || (p?.type === 'export_statement' && p.parent?.type === 'program');
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
function isExported(defNode) {
|
|
365
|
+
let n = defNode;
|
|
366
|
+
if (n.type === 'variable_declarator') n = n.parent;
|
|
367
|
+
const p = n.parent;
|
|
368
|
+
if (p?.type === 'export_statement') return true;
|
|
369
|
+
// `module.exports.x = ...`, `exports.x = ...`
|
|
370
|
+
if (defNode.type === 'expression_statement') return /^(module\.)?exports\./.test(defNode.text);
|
|
371
|
+
return false;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function visibility(defNode) {
|
|
375
|
+
for (const c of defNode.children) {
|
|
376
|
+
if (c.type === 'accessibility_modifier') return c.text; // public/private/protected
|
|
377
|
+
}
|
|
378
|
+
const name = defNode.childForFieldName('name');
|
|
379
|
+
if (name?.type === 'private_property_identifier') return 'private';
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function makeSpec(id, grammar, extensions, { ts, jsx }) {
|
|
384
|
+
return {
|
|
385
|
+
id,
|
|
386
|
+
grammar,
|
|
387
|
+
extensions,
|
|
388
|
+
family: 'ecma',
|
|
389
|
+
query: [
|
|
390
|
+
DEFS_COMMON, ts ? DEFS_TS : DEFS_JS,
|
|
391
|
+
REFS_COMMON, ts ? REFS_TS : REFS_JS, jsx ? REFS_JSX : '',
|
|
392
|
+
IMPORTS_COMMON, BINDINGS_COMMON, ts ? BINDINGS_TS : BINDINGS_JS,
|
|
393
|
+
].join('\n'),
|
|
394
|
+
implicitThis: false,
|
|
395
|
+
implicitBases: aliasBases,
|
|
396
|
+
selfNames: ['this'],
|
|
397
|
+
externalReceivers: EXTERNAL_RECEIVERS,
|
|
398
|
+
builtinCalls: BUILTIN_CALLS,
|
|
399
|
+
transparentTypes: TRANSPARENT_TYPES,
|
|
400
|
+
elementTypes: ELEMENT_TYPES,
|
|
401
|
+
isPrimitiveType: (t) => PRIMITIVE_TYPES.has(t),
|
|
402
|
+
elementMethods: new Set(['at', 'find', 'findLast', 'pop', 'shift']),
|
|
403
|
+
mapTypes: new Set(['Map', 'ReadonlyMap', 'WeakMap', 'Record']),
|
|
404
|
+
mapMethods: new Set(['get']),
|
|
405
|
+
mapValueMethods: new Set(['values']),
|
|
406
|
+
cleanType: (t) => t.replace(/^extends\s+/, ''),
|
|
407
|
+
testFile: TEST_FILE_RE,
|
|
408
|
+
commentTypes: ['comment'],
|
|
409
|
+
containerKinds: new Set(['class', 'interface', 'module', 'enum', 'function', 'method']),
|
|
410
|
+
parseImport: parseImportNode,
|
|
411
|
+
collectionSource,
|
|
412
|
+
filterDef: (d) => !((d.kind === 'variable') && isRequireBinding(d.node))
|
|
413
|
+
&& !(isAnonymousClass(d.node) && CLASS_HOLDERS.has(d.node.parent?.type)), // named by its holder
|
|
414
|
+
// `export default class extends Base {…}` is a class (its methods' `this`), not a function
|
|
415
|
+
refineKind: (kind, d) => (d.node.type === 'export_statement' && (d.nameNode.type === 'class' || d.nameNode.type === 'class_declaration') ? 'class' : kind),
|
|
416
|
+
normalizeName: (name, d, relPath) => {
|
|
417
|
+
if (d.node.type === 'export_statement') {
|
|
418
|
+
// default export → its own name, else named after its file (what importers call it)
|
|
419
|
+
d.isDefault = true;
|
|
420
|
+
const inner = d.nameNode;
|
|
421
|
+
let own = inner.childForFieldName?.('name')?.text;
|
|
422
|
+
if (!own && inner.type === 'binary_expression') own = inner.childForFieldName('right')?.childForFieldName?.('name')?.text;
|
|
423
|
+
return own || fileStem(relPath);
|
|
424
|
+
}
|
|
425
|
+
if (isAnonymousClass(d.node)) return anonymousClassName(d.node, relPath);
|
|
426
|
+
return name;
|
|
427
|
+
},
|
|
428
|
+
parseRequire,
|
|
429
|
+
isModuleLevel,
|
|
430
|
+
isExported,
|
|
431
|
+
visibility,
|
|
432
|
+
bodyField: 'body',
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export const javascript = makeSpec('javascript', 'javascript', ['.js', '.jsx', '.mjs', '.cjs'], { ts: false, jsx: true });
|
|
437
|
+
export const typescript = makeSpec('typescript', 'typescript', ['.ts', '.mts', '.cts'], { ts: true, jsx: false });
|
|
438
|
+
export const tsx = makeSpec('tsx', 'tsx', ['.tsx'], { ts: true, jsx: true });
|