@optave/codegraph 3.4.1 → 3.6.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/README.md +50 -28
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +119 -127
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
- package/dist/ast-analysis/rules/javascript.js +1 -0
- package/dist/ast-analysis/rules/javascript.js.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js +116 -35
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/db/better-sqlite3.d.ts +3 -0
- package/dist/db/better-sqlite3.d.ts.map +1 -0
- package/dist/db/better-sqlite3.js +19 -0
- package/dist/db/better-sqlite3.js.map +1 -0
- package/dist/db/connection.d.ts +25 -4
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +125 -23
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +40 -32
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/query-builder.d.ts +5 -5
- package/dist/db/query-builder.d.ts.map +1 -1
- package/dist/db/query-builder.js +20 -4
- package/dist/db/query-builder.js.map +1 -1
- package/dist/db/repository/index.d.ts +1 -0
- package/dist/db/repository/index.d.ts.map +1 -1
- package/dist/db/repository/index.js +1 -0
- package/dist/db/repository/index.js.map +1 -1
- package/dist/db/repository/native-repository.d.ts +58 -0
- package/dist/db/repository/native-repository.d.ts.map +1 -0
- package/dist/db/repository/native-repository.js +261 -0
- package/dist/db/repository/native-repository.js.map +1 -0
- package/dist/db/repository/nodes.d.ts +4 -4
- package/dist/db/repository/nodes.d.ts.map +1 -1
- package/dist/db/repository/nodes.js +6 -6
- package/dist/db/repository/nodes.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +51 -66
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +62 -70
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +9 -7
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +29 -33
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +15 -17
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +35 -65
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +91 -6
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +20 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
- package/dist/domain/analysis/query-helpers.js +27 -0
- package/dist/domain/analysis/query-helpers.js.map +1 -0
- package/dist/domain/graph/builder/context.d.ts +2 -1
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js +1 -0
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +15 -9
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +3 -2
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +95 -7
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +101 -57
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +33 -3
- package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +70 -6
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +36 -14
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +130 -88
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +124 -16
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts +0 -4
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +32 -48
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +12 -12
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +165 -101
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
- package/dist/domain/search/search/cli-formatter.js +88 -83
- package/dist/domain/search/search/cli-formatter.js.map +1 -1
- package/dist/extractors/bash.d.ts +6 -0
- package/dist/extractors/bash.d.ts.map +1 -0
- package/dist/extractors/bash.js +91 -0
- package/dist/extractors/bash.js.map +1 -0
- package/dist/extractors/c.d.ts +6 -0
- package/dist/extractors/c.d.ts.map +1 -0
- package/dist/extractors/c.js +204 -0
- package/dist/extractors/c.js.map +1 -0
- package/dist/extractors/cpp.d.ts +6 -0
- package/dist/extractors/cpp.d.ts.map +1 -0
- package/dist/extractors/cpp.js +283 -0
- package/dist/extractors/cpp.js.map +1 -0
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +42 -54
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/go.d.ts.map +1 -1
- package/dist/extractors/go.js +126 -130
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/hcl.js +6 -6
- package/dist/extractors/hcl.js.map +1 -1
- package/dist/extractors/helpers.d.ts +32 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +74 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/index.d.ts +6 -0
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +6 -0
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +32 -47
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +359 -330
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.d.ts +6 -0
- package/dist/extractors/kotlin.d.ts.map +1 -0
- package/dist/extractors/kotlin.js +275 -0
- package/dist/extractors/kotlin.js.map +1 -0
- package/dist/extractors/php.d.ts.map +1 -1
- package/dist/extractors/php.js +39 -44
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.d.ts.map +1 -1
- package/dist/extractors/python.js +75 -93
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +6 -13
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/rust.d.ts.map +1 -1
- package/dist/extractors/rust.js +58 -82
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/scala.d.ts +6 -0
- package/dist/extractors/scala.d.ts.map +1 -0
- package/dist/extractors/scala.js +269 -0
- package/dist/extractors/scala.js.map +1 -0
- package/dist/extractors/swift.d.ts +6 -0
- package/dist/extractors/swift.d.ts.map +1 -0
- package/dist/extractors/swift.js +275 -0
- package/dist/extractors/swift.js.map +1 -0
- package/dist/features/ast.d.ts +16 -1
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +45 -23
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +17 -21
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +50 -4
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +7 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +118 -62
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +79 -62
- package/dist/features/check.js.map +1 -1
- package/dist/features/complexity-query.d.ts.map +1 -1
- package/dist/features/complexity-query.js +142 -137
- package/dist/features/complexity-query.js.map +1 -1
- package/dist/features/complexity.d.ts +7 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +62 -1
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts +7 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +356 -188
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +117 -104
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +25 -4
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/snapshot.d.ts.map +1 -1
- package/dist/features/snapshot.js +2 -1
- package/dist/features/snapshot.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +29 -4
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +35 -15
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +88 -73
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/algorithms/leiden/index.js +43 -28
- package/dist/graph/algorithms/leiden/index.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +90 -104
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/partition.js +89 -106
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts +2 -0
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +20 -8
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts +0 -8
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +73 -62
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -8
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +12 -14
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +47 -45
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +61 -57
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/branch-compare.d.ts.map +1 -1
- package/dist/presentation/branch-compare.js +56 -38
- package/dist/presentation/branch-compare.js.map +1 -1
- package/dist/presentation/check.d.ts.map +1 -1
- package/dist/presentation/check.js +30 -32
- package/dist/presentation/check.js.map +1 -1
- package/dist/presentation/colors.d.ts.map +1 -1
- package/dist/presentation/colors.js +2 -0
- package/dist/presentation/colors.js.map +1 -1
- package/dist/presentation/complexity.d.ts.map +1 -1
- package/dist/presentation/complexity.js +25 -19
- package/dist/presentation/complexity.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +15 -15
- package/dist/presentation/queries-cli/exports.js.map +1 -1
- package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
- package/dist/presentation/queries-cli/impact.js +29 -19
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/types.d.ts +406 -3
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/package.json +67 -11
- package/src/ast-analysis/engine.ts +147 -138
- package/src/ast-analysis/rules/javascript.ts +1 -0
- package/src/ast-analysis/visitors/ast-store-visitor.ts +116 -34
- package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
- package/src/db/better-sqlite3.ts +20 -0
- package/src/db/connection.ts +148 -26
- package/src/db/index.ts +4 -1
- package/src/db/migrations.ts +38 -32
- package/src/db/query-builder.ts +30 -5
- package/src/db/repository/index.ts +1 -0
- package/src/db/repository/native-repository.ts +361 -0
- package/src/db/repository/nodes.ts +7 -3
- package/src/domain/analysis/context.ts +73 -75
- package/src/domain/analysis/dependencies.ts +78 -68
- package/src/domain/analysis/exports.ts +45 -34
- package/src/domain/analysis/fn-impact.ts +67 -64
- package/src/domain/analysis/module-map.ts +103 -8
- package/src/domain/analysis/query-helpers.ts +35 -0
- package/src/domain/graph/builder/context.ts +2 -0
- package/src/domain/graph/builder/helpers.ts +12 -6
- package/src/domain/graph/builder/incremental.ts +3 -2
- package/src/domain/graph/builder/pipeline.ts +98 -6
- package/src/domain/graph/builder/stages/build-edges.ts +116 -83
- package/src/domain/graph/builder/stages/build-structure.ts +46 -8
- package/src/domain/graph/builder/stages/collect-files.ts +83 -6
- package/src/domain/graph/builder/stages/detect-changes.ts +44 -21
- package/src/domain/graph/builder/stages/finalize.ts +172 -109
- package/src/domain/graph/builder/stages/insert-nodes.ts +147 -17
- package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
- package/src/domain/graph/resolve.ts +34 -46
- package/src/domain/graph/watcher.ts +12 -14
- package/src/domain/parser.ts +169 -97
- package/src/domain/search/search/cli-formatter.ts +121 -94
- package/src/extractors/bash.ts +97 -0
- package/src/extractors/c.ts +212 -0
- package/src/extractors/cpp.ts +298 -0
- package/src/extractors/csharp.ts +53 -56
- package/src/extractors/go.ts +152 -134
- package/src/extractors/hcl.ts +6 -6
- package/src/extractors/helpers.ts +93 -1
- package/src/extractors/index.ts +6 -0
- package/src/extractors/java.ts +43 -48
- package/src/extractors/javascript.ts +382 -317
- package/src/extractors/kotlin.ts +293 -0
- package/src/extractors/php.ts +46 -40
- package/src/extractors/python.ts +81 -104
- package/src/extractors/ruby.ts +6 -13
- package/src/extractors/rust.ts +65 -84
- package/src/extractors/scala.ts +285 -0
- package/src/extractors/swift.ts +293 -0
- package/src/features/ast.ts +74 -24
- package/src/features/audit.ts +24 -20
- package/src/features/branch-compare.ts +54 -5
- package/src/features/cfg.ts +158 -65
- package/src/features/check.ts +90 -74
- package/src/features/complexity-query.ts +181 -163
- package/src/features/complexity.ts +64 -1
- package/src/features/dataflow.ts +462 -217
- package/src/features/graph-enrichment.ts +161 -117
- package/src/features/sequence.ts +27 -4
- package/src/features/snapshot.ts +2 -1
- package/src/features/structure-query.ts +43 -4
- package/src/features/structure.ts +50 -22
- package/src/graph/algorithms/leiden/adapter.ts +126 -71
- package/src/graph/algorithms/leiden/index.ts +67 -28
- package/src/graph/algorithms/leiden/optimiser.ts +114 -105
- package/src/graph/algorithms/leiden/partition.ts +131 -98
- package/src/graph/model.ts +19 -7
- package/src/infrastructure/config.ts +60 -58
- package/src/infrastructure/registry.ts +17 -14
- package/src/mcp/server.ts +48 -47
- package/src/presentation/audit.ts +72 -67
- package/src/presentation/branch-compare.ts +54 -50
- package/src/presentation/check.ts +34 -34
- package/src/presentation/colors.ts +2 -0
- package/src/presentation/complexity.ts +39 -33
- package/src/presentation/queries-cli/exports.ts +17 -17
- package/src/presentation/queries-cli/impact.ts +30 -22
- package/src/types.ts +458 -3
|
@@ -12,7 +12,13 @@ import type {
|
|
|
12
12
|
TreeSitterTree,
|
|
13
13
|
TypeMapEntry,
|
|
14
14
|
} from '../types.js';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
findChild,
|
|
17
|
+
findParentNode,
|
|
18
|
+
MAX_WALK_DEPTH,
|
|
19
|
+
nodeEndLine,
|
|
20
|
+
setTypeMapEntry,
|
|
21
|
+
} from './helpers.js';
|
|
16
22
|
|
|
17
23
|
/** Built-in globals that start with uppercase but are not user-defined types. */
|
|
18
24
|
const BUILTIN_GLOBALS: Set<string> = new Set([
|
|
@@ -87,6 +93,182 @@ export function extractSymbols(
|
|
|
87
93
|
|
|
88
94
|
// ── Query-based extraction (fast path) ──────────────────────────────────────
|
|
89
95
|
|
|
96
|
+
/** Handle function_declaration capture. */
|
|
97
|
+
function handleFnCapture(c: Record<string, TreeSitterNode>, definitions: Definition[]): void {
|
|
98
|
+
const fnChildren = extractParameters(c.fn_node!);
|
|
99
|
+
definitions.push({
|
|
100
|
+
name: c.fn_name!.text,
|
|
101
|
+
kind: 'function',
|
|
102
|
+
line: c.fn_node!.startPosition.row + 1,
|
|
103
|
+
endLine: nodeEndLine(c.fn_node!),
|
|
104
|
+
children: fnChildren.length > 0 ? fnChildren : undefined,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Handle variable_declarator with arrow_function / function_expression capture. */
|
|
109
|
+
function handleVarFnCapture(c: Record<string, TreeSitterNode>, definitions: Definition[]): void {
|
|
110
|
+
const declNode = c.varfn_name!.parent?.parent;
|
|
111
|
+
const line = declNode ? declNode.startPosition.row + 1 : c.varfn_name!.startPosition.row + 1;
|
|
112
|
+
const varFnChildren = extractParameters(c.varfn_value!);
|
|
113
|
+
definitions.push({
|
|
114
|
+
name: c.varfn_name!.text,
|
|
115
|
+
kind: 'function',
|
|
116
|
+
line,
|
|
117
|
+
endLine: nodeEndLine(c.varfn_value!),
|
|
118
|
+
children: varFnChildren.length > 0 ? varFnChildren : undefined,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Handle class_declaration capture. */
|
|
123
|
+
function handleClassCapture(
|
|
124
|
+
c: Record<string, TreeSitterNode>,
|
|
125
|
+
definitions: Definition[],
|
|
126
|
+
classes: ClassRelation[],
|
|
127
|
+
): void {
|
|
128
|
+
const className = c.cls_name!.text;
|
|
129
|
+
const startLine = c.cls_node!.startPosition.row + 1;
|
|
130
|
+
const clsChildren = extractClassProperties(c.cls_node!);
|
|
131
|
+
definitions.push({
|
|
132
|
+
name: className,
|
|
133
|
+
kind: 'class',
|
|
134
|
+
line: startLine,
|
|
135
|
+
endLine: nodeEndLine(c.cls_node!),
|
|
136
|
+
children: clsChildren.length > 0 ? clsChildren : undefined,
|
|
137
|
+
});
|
|
138
|
+
const heritage =
|
|
139
|
+
c.cls_node!.childForFieldName('heritage') || findChild(c.cls_node!, 'class_heritage');
|
|
140
|
+
if (heritage) {
|
|
141
|
+
const superName = extractSuperclass(heritage);
|
|
142
|
+
if (superName) classes.push({ name: className, extends: superName, line: startLine });
|
|
143
|
+
const implementsList = extractImplements(heritage);
|
|
144
|
+
for (const iface of implementsList) {
|
|
145
|
+
classes.push({ name: className, implements: iface, line: startLine });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/** Handle method_definition capture. */
|
|
151
|
+
function handleMethodCapture(c: Record<string, TreeSitterNode>, definitions: Definition[]): void {
|
|
152
|
+
const methName = c.meth_name!.text;
|
|
153
|
+
const parentClass = findParentClass(c.meth_node!);
|
|
154
|
+
const fullName = parentClass ? `${parentClass}.${methName}` : methName;
|
|
155
|
+
const methChildren = extractParameters(c.meth_node!);
|
|
156
|
+
const methVis = extractVisibility(c.meth_node!);
|
|
157
|
+
definitions.push({
|
|
158
|
+
name: fullName,
|
|
159
|
+
kind: 'method',
|
|
160
|
+
line: c.meth_node!.startPosition.row + 1,
|
|
161
|
+
endLine: nodeEndLine(c.meth_node!),
|
|
162
|
+
children: methChildren.length > 0 ? methChildren : undefined,
|
|
163
|
+
visibility: methVis,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Handle export_statement capture. */
|
|
168
|
+
function handleExportCapture(
|
|
169
|
+
c: Record<string, TreeSitterNode>,
|
|
170
|
+
exps: Export[],
|
|
171
|
+
imports: Import[],
|
|
172
|
+
): void {
|
|
173
|
+
const exportLine = c.exp_node!.startPosition.row + 1;
|
|
174
|
+
const decl = c.exp_node!.childForFieldName('declaration');
|
|
175
|
+
if (decl) {
|
|
176
|
+
const declType = decl.type;
|
|
177
|
+
const kindMap: Record<string, string> = {
|
|
178
|
+
function_declaration: 'function',
|
|
179
|
+
class_declaration: 'class',
|
|
180
|
+
interface_declaration: 'interface',
|
|
181
|
+
type_alias_declaration: 'type',
|
|
182
|
+
};
|
|
183
|
+
const kind = kindMap[declType];
|
|
184
|
+
if (kind) {
|
|
185
|
+
const n = decl.childForFieldName('name');
|
|
186
|
+
if (n) exps.push({ name: n.text, kind: kind as Export['kind'], line: exportLine });
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const source = c.exp_node!.childForFieldName('source') || findChild(c.exp_node!, 'string');
|
|
190
|
+
if (source && !decl) {
|
|
191
|
+
const modPath = source.text.replace(/['"]/g, '');
|
|
192
|
+
const reexportNames = extractImportNames(c.exp_node!);
|
|
193
|
+
const nodeText = c.exp_node!.text;
|
|
194
|
+
const isWildcard = nodeText.includes('export *') || nodeText.includes('export*');
|
|
195
|
+
imports.push({
|
|
196
|
+
source: modPath,
|
|
197
|
+
names: reexportNames,
|
|
198
|
+
line: exportLine,
|
|
199
|
+
reexport: true,
|
|
200
|
+
wildcardReexport: isWildcard && reexportNames.length === 0,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Dispatch a single query match to the appropriate handler. */
|
|
206
|
+
function dispatchQueryMatch(
|
|
207
|
+
c: Record<string, TreeSitterNode>,
|
|
208
|
+
definitions: Definition[],
|
|
209
|
+
calls: Call[],
|
|
210
|
+
imports: Import[],
|
|
211
|
+
classes: ClassRelation[],
|
|
212
|
+
exps: Export[],
|
|
213
|
+
): void {
|
|
214
|
+
if (c.fn_node) {
|
|
215
|
+
handleFnCapture(c, definitions);
|
|
216
|
+
} else if (c.varfn_name) {
|
|
217
|
+
handleVarFnCapture(c, definitions);
|
|
218
|
+
} else if (c.cls_node) {
|
|
219
|
+
handleClassCapture(c, definitions, classes);
|
|
220
|
+
} else if (c.meth_node) {
|
|
221
|
+
handleMethodCapture(c, definitions);
|
|
222
|
+
} else if (c.iface_node) {
|
|
223
|
+
const ifaceName = c.iface_name!.text;
|
|
224
|
+
definitions.push({
|
|
225
|
+
name: ifaceName,
|
|
226
|
+
kind: 'interface',
|
|
227
|
+
line: c.iface_node.startPosition.row + 1,
|
|
228
|
+
endLine: nodeEndLine(c.iface_node),
|
|
229
|
+
});
|
|
230
|
+
const body =
|
|
231
|
+
c.iface_node.childForFieldName('body') ||
|
|
232
|
+
findChild(c.iface_node, 'interface_body') ||
|
|
233
|
+
findChild(c.iface_node, 'object_type');
|
|
234
|
+
if (body) extractInterfaceMethods(body, ifaceName, definitions);
|
|
235
|
+
} else if (c.type_node) {
|
|
236
|
+
definitions.push({
|
|
237
|
+
name: c.type_name!.text,
|
|
238
|
+
kind: 'type',
|
|
239
|
+
line: c.type_node.startPosition.row + 1,
|
|
240
|
+
endLine: nodeEndLine(c.type_node),
|
|
241
|
+
});
|
|
242
|
+
} else if (c.imp_node) {
|
|
243
|
+
const isTypeOnly = c.imp_node.text.startsWith('import type');
|
|
244
|
+
const modPath = c.imp_source!.text.replace(/['"]/g, '');
|
|
245
|
+
const names = extractImportNames(c.imp_node);
|
|
246
|
+
imports.push({
|
|
247
|
+
source: modPath,
|
|
248
|
+
names,
|
|
249
|
+
line: c.imp_node.startPosition.row + 1,
|
|
250
|
+
typeOnly: isTypeOnly,
|
|
251
|
+
});
|
|
252
|
+
} else if (c.exp_node) {
|
|
253
|
+
handleExportCapture(c, exps, imports);
|
|
254
|
+
} else if (c.callfn_node) {
|
|
255
|
+
calls.push({
|
|
256
|
+
name: c.callfn_name!.text,
|
|
257
|
+
line: c.callfn_node.startPosition.row + 1,
|
|
258
|
+
});
|
|
259
|
+
} else if (c.callmem_node) {
|
|
260
|
+
const callInfo = extractCallInfo(c.callmem_fn!, c.callmem_node);
|
|
261
|
+
if (callInfo) calls.push(callInfo);
|
|
262
|
+
const cbDef = extractCallbackDefinition(c.callmem_node, c.callmem_fn);
|
|
263
|
+
if (cbDef) definitions.push(cbDef);
|
|
264
|
+
} else if (c.callsub_node) {
|
|
265
|
+
const callInfo = extractCallInfo(c.callsub_fn!, c.callsub_node);
|
|
266
|
+
if (callInfo) calls.push(callInfo);
|
|
267
|
+
} else if (c.assign_node) {
|
|
268
|
+
handleCommonJSAssignment(c.assign_left!, c.assign_right!, c.assign_node, imports);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
90
272
|
function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): ExtractorOutput {
|
|
91
273
|
const definitions: Definition[] = [];
|
|
92
274
|
const calls: Call[] = [];
|
|
@@ -101,151 +283,7 @@ function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): Extr
|
|
|
101
283
|
// Build capture lookup for this match (1-3 captures each, very fast)
|
|
102
284
|
const c: Record<string, TreeSitterNode> = Object.create(null);
|
|
103
285
|
for (const cap of match.captures) c[cap.name] = cap.node;
|
|
104
|
-
|
|
105
|
-
if (c.fn_node) {
|
|
106
|
-
// function_declaration
|
|
107
|
-
const fnChildren = extractParameters(c.fn_node);
|
|
108
|
-
definitions.push({
|
|
109
|
-
name: c.fn_name!.text,
|
|
110
|
-
kind: 'function',
|
|
111
|
-
line: c.fn_node.startPosition.row + 1,
|
|
112
|
-
endLine: nodeEndLine(c.fn_node),
|
|
113
|
-
children: fnChildren.length > 0 ? fnChildren : undefined,
|
|
114
|
-
});
|
|
115
|
-
} else if (c.varfn_name) {
|
|
116
|
-
// variable_declarator with arrow_function / function_expression
|
|
117
|
-
const declNode = c.varfn_name.parent?.parent;
|
|
118
|
-
const line = declNode ? declNode.startPosition.row + 1 : c.varfn_name.startPosition.row + 1;
|
|
119
|
-
const varFnChildren = extractParameters(c.varfn_value!);
|
|
120
|
-
definitions.push({
|
|
121
|
-
name: c.varfn_name.text,
|
|
122
|
-
kind: 'function',
|
|
123
|
-
line,
|
|
124
|
-
endLine: nodeEndLine(c.varfn_value!),
|
|
125
|
-
children: varFnChildren.length > 0 ? varFnChildren : undefined,
|
|
126
|
-
});
|
|
127
|
-
} else if (c.cls_node) {
|
|
128
|
-
// class_declaration
|
|
129
|
-
const className = c.cls_name!.text;
|
|
130
|
-
const startLine = c.cls_node.startPosition.row + 1;
|
|
131
|
-
const clsChildren = extractClassProperties(c.cls_node);
|
|
132
|
-
definitions.push({
|
|
133
|
-
name: className,
|
|
134
|
-
kind: 'class',
|
|
135
|
-
line: startLine,
|
|
136
|
-
endLine: nodeEndLine(c.cls_node),
|
|
137
|
-
children: clsChildren.length > 0 ? clsChildren : undefined,
|
|
138
|
-
});
|
|
139
|
-
const heritage =
|
|
140
|
-
c.cls_node.childForFieldName('heritage') || findChild(c.cls_node, 'class_heritage');
|
|
141
|
-
if (heritage) {
|
|
142
|
-
const superName = extractSuperclass(heritage);
|
|
143
|
-
if (superName) classes.push({ name: className, extends: superName, line: startLine });
|
|
144
|
-
const implementsList = extractImplements(heritage);
|
|
145
|
-
for (const iface of implementsList) {
|
|
146
|
-
classes.push({ name: className, implements: iface, line: startLine });
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
} else if (c.meth_node) {
|
|
150
|
-
// method_definition
|
|
151
|
-
const methName = c.meth_name!.text;
|
|
152
|
-
const parentClass = findParentClass(c.meth_node);
|
|
153
|
-
const fullName = parentClass ? `${parentClass}.${methName}` : methName;
|
|
154
|
-
const methChildren = extractParameters(c.meth_node);
|
|
155
|
-
const methVis = extractVisibility(c.meth_node);
|
|
156
|
-
definitions.push({
|
|
157
|
-
name: fullName,
|
|
158
|
-
kind: 'method',
|
|
159
|
-
line: c.meth_node.startPosition.row + 1,
|
|
160
|
-
endLine: nodeEndLine(c.meth_node),
|
|
161
|
-
children: methChildren.length > 0 ? methChildren : undefined,
|
|
162
|
-
visibility: methVis,
|
|
163
|
-
});
|
|
164
|
-
} else if (c.iface_node) {
|
|
165
|
-
// interface_declaration (TS/TSX only)
|
|
166
|
-
const ifaceName = c.iface_name!.text;
|
|
167
|
-
definitions.push({
|
|
168
|
-
name: ifaceName,
|
|
169
|
-
kind: 'interface',
|
|
170
|
-
line: c.iface_node.startPosition.row + 1,
|
|
171
|
-
endLine: nodeEndLine(c.iface_node),
|
|
172
|
-
});
|
|
173
|
-
const body =
|
|
174
|
-
c.iface_node.childForFieldName('body') ||
|
|
175
|
-
findChild(c.iface_node, 'interface_body') ||
|
|
176
|
-
findChild(c.iface_node, 'object_type');
|
|
177
|
-
if (body) extractInterfaceMethods(body, ifaceName, definitions);
|
|
178
|
-
} else if (c.type_node) {
|
|
179
|
-
// type_alias_declaration (TS/TSX only)
|
|
180
|
-
definitions.push({
|
|
181
|
-
name: c.type_name!.text,
|
|
182
|
-
kind: 'type',
|
|
183
|
-
line: c.type_node.startPosition.row + 1,
|
|
184
|
-
endLine: nodeEndLine(c.type_node),
|
|
185
|
-
});
|
|
186
|
-
} else if (c.imp_node) {
|
|
187
|
-
// import_statement
|
|
188
|
-
const isTypeOnly = c.imp_node.text.startsWith('import type');
|
|
189
|
-
const modPath = c.imp_source!.text.replace(/['"]/g, '');
|
|
190
|
-
const names = extractImportNames(c.imp_node);
|
|
191
|
-
imports.push({
|
|
192
|
-
source: modPath,
|
|
193
|
-
names,
|
|
194
|
-
line: c.imp_node.startPosition.row + 1,
|
|
195
|
-
typeOnly: isTypeOnly,
|
|
196
|
-
});
|
|
197
|
-
} else if (c.exp_node) {
|
|
198
|
-
// export_statement
|
|
199
|
-
const exportLine = c.exp_node.startPosition.row + 1;
|
|
200
|
-
const decl = c.exp_node.childForFieldName('declaration');
|
|
201
|
-
if (decl) {
|
|
202
|
-
const declType = decl.type;
|
|
203
|
-
const kindMap: Record<string, string> = {
|
|
204
|
-
function_declaration: 'function',
|
|
205
|
-
class_declaration: 'class',
|
|
206
|
-
interface_declaration: 'interface',
|
|
207
|
-
type_alias_declaration: 'type',
|
|
208
|
-
};
|
|
209
|
-
const kind = kindMap[declType];
|
|
210
|
-
if (kind) {
|
|
211
|
-
const n = decl.childForFieldName('name');
|
|
212
|
-
if (n) exps.push({ name: n.text, kind: kind as Export['kind'], line: exportLine });
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
const source = c.exp_node.childForFieldName('source') || findChild(c.exp_node, 'string');
|
|
216
|
-
if (source && !decl) {
|
|
217
|
-
const modPath = source.text.replace(/['"]/g, '');
|
|
218
|
-
const reexportNames = extractImportNames(c.exp_node);
|
|
219
|
-
const nodeText = c.exp_node.text;
|
|
220
|
-
const isWildcard = nodeText.includes('export *') || nodeText.includes('export*');
|
|
221
|
-
imports.push({
|
|
222
|
-
source: modPath,
|
|
223
|
-
names: reexportNames,
|
|
224
|
-
line: exportLine,
|
|
225
|
-
reexport: true,
|
|
226
|
-
wildcardReexport: isWildcard && reexportNames.length === 0,
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
|
-
} else if (c.callfn_node) {
|
|
230
|
-
// call_expression with identifier function
|
|
231
|
-
calls.push({
|
|
232
|
-
name: c.callfn_name!.text,
|
|
233
|
-
line: c.callfn_node.startPosition.row + 1,
|
|
234
|
-
});
|
|
235
|
-
} else if (c.callmem_node) {
|
|
236
|
-
// call_expression with member_expression function
|
|
237
|
-
const callInfo = extractCallInfo(c.callmem_fn!, c.callmem_node);
|
|
238
|
-
if (callInfo) calls.push(callInfo);
|
|
239
|
-
const cbDef = extractCallbackDefinition(c.callmem_node, c.callmem_fn);
|
|
240
|
-
if (cbDef) definitions.push(cbDef);
|
|
241
|
-
} else if (c.callsub_node) {
|
|
242
|
-
// call_expression with subscript_expression function
|
|
243
|
-
const callInfo = extractCallInfo(c.callsub_fn!, c.callsub_node);
|
|
244
|
-
if (callInfo) calls.push(callInfo);
|
|
245
|
-
} else if (c.assign_node) {
|
|
246
|
-
// CommonJS: module.exports = require(...) / module.exports = { ...require(...) }
|
|
247
|
-
handleCommonJSAssignment(c.assign_left!, c.assign_right!, c.assign_node, imports);
|
|
248
|
-
}
|
|
286
|
+
dispatchQueryMatch(c, definitions, calls, imports, classes, exps);
|
|
249
287
|
}
|
|
250
288
|
|
|
251
289
|
// Extract top-level constants via targeted walk (query patterns don't cover these)
|
|
@@ -260,51 +298,69 @@ function extractSymbolsQuery(tree: TreeSitterTree, query: TreeSitterQuery): Extr
|
|
|
260
298
|
return { definitions, calls, imports, classes, exports: exps, typeMap };
|
|
261
299
|
}
|
|
262
300
|
|
|
301
|
+
/** Node types that define a function scope — constants inside these are skipped. */
|
|
302
|
+
const FUNCTION_SCOPE_TYPES = new Set([
|
|
303
|
+
'function_declaration',
|
|
304
|
+
'arrow_function',
|
|
305
|
+
'function_expression',
|
|
306
|
+
'method_definition',
|
|
307
|
+
'generator_function_declaration',
|
|
308
|
+
'generator_function',
|
|
309
|
+
]);
|
|
310
|
+
|
|
263
311
|
/**
|
|
264
|
-
*
|
|
265
|
-
*
|
|
266
|
-
*
|
|
312
|
+
* Recursively walk the AST to extract `const x = <literal>` as constants.
|
|
313
|
+
* Skips nodes inside function scopes so only file-level / block-level constants
|
|
314
|
+
* are captured — matching the native engine's behaviour.
|
|
267
315
|
*/
|
|
268
|
-
function extractConstantsWalk(
|
|
269
|
-
for (let i = 0; i <
|
|
270
|
-
const
|
|
271
|
-
if (!
|
|
316
|
+
function extractConstantsWalk(node: TreeSitterNode, definitions: Definition[]): void {
|
|
317
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
318
|
+
const child = node.child(i);
|
|
319
|
+
if (!child) continue;
|
|
320
|
+
|
|
321
|
+
// Don't descend into function scopes
|
|
322
|
+
if (FUNCTION_SCOPE_TYPES.has(child.type)) continue;
|
|
272
323
|
|
|
273
|
-
let declNode =
|
|
324
|
+
let declNode = child;
|
|
274
325
|
// Handle `export const …` — unwrap the export_statement to its declaration child
|
|
275
|
-
if (
|
|
276
|
-
const inner =
|
|
277
|
-
if (
|
|
278
|
-
declNode = inner;
|
|
326
|
+
if (child.type === 'export_statement') {
|
|
327
|
+
const inner = child.childForFieldName('declaration');
|
|
328
|
+
if (inner) declNode = inner;
|
|
279
329
|
}
|
|
280
330
|
|
|
281
331
|
const t = declNode.type;
|
|
282
|
-
if (t
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
332
|
+
if (t === 'lexical_declaration' || t === 'variable_declaration') {
|
|
333
|
+
if (declNode.text.startsWith('const ')) {
|
|
334
|
+
for (let j = 0; j < declNode.childCount; j++) {
|
|
335
|
+
const declarator = declNode.child(j);
|
|
336
|
+
if (!declarator || declarator.type !== 'variable_declarator') continue;
|
|
337
|
+
const nameN = declarator.childForFieldName('name');
|
|
338
|
+
const valueN = declarator.childForFieldName('value');
|
|
339
|
+
if (!nameN || nameN.type !== 'identifier' || !valueN) continue;
|
|
340
|
+
// Skip functions — already captured by query patterns
|
|
341
|
+
const valType = valueN.type;
|
|
342
|
+
if (
|
|
343
|
+
valType === 'arrow_function' ||
|
|
344
|
+
valType === 'function_expression' ||
|
|
345
|
+
valType === 'function'
|
|
346
|
+
)
|
|
347
|
+
continue;
|
|
348
|
+
if (isConstantValue(valueN)) {
|
|
349
|
+
definitions.push({
|
|
350
|
+
name: nameN.text,
|
|
351
|
+
kind: 'constant',
|
|
352
|
+
line: declNode.startPosition.row + 1,
|
|
353
|
+
endLine: nodeEndLine(declNode),
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
}
|
|
306
357
|
}
|
|
307
358
|
}
|
|
359
|
+
|
|
360
|
+
// Recurse into non-function, non-export-statement children (blocks, if-statements, etc.)
|
|
361
|
+
if (child.type !== 'export_statement') {
|
|
362
|
+
extractConstantsWalk(child, definitions);
|
|
363
|
+
}
|
|
308
364
|
}
|
|
309
365
|
}
|
|
310
366
|
|
|
@@ -353,48 +409,49 @@ function handleCommonJSAssignment(
|
|
|
353
409
|
const leftText = left.text;
|
|
354
410
|
if (!leftText.startsWith('module.exports') && leftText !== 'exports') return;
|
|
355
411
|
|
|
356
|
-
const rightType = right.type;
|
|
357
412
|
const assignLine = node.startPosition.row + 1;
|
|
358
413
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
414
|
+
// module.exports = require("…") — direct re-export
|
|
415
|
+
if (right.type === 'call_expression') {
|
|
416
|
+
extractRequireReexport(right, assignLine, imports);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
// module.exports = { ...require("…") } — spread re-export
|
|
420
|
+
if (right.type === 'object') {
|
|
421
|
+
extractSpreadRequireReexports(right, assignLine, imports);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Extract a direct `require()` re-export from a call_expression. */
|
|
426
|
+
function extractRequireReexport(callExpr: TreeSitterNode, line: number, imports: Import[]): void {
|
|
427
|
+
const fn = callExpr.childForFieldName('function');
|
|
428
|
+
const args = callExpr.childForFieldName('arguments') || findChild(callExpr, 'arguments');
|
|
429
|
+
if (fn && fn.text === 'require' && args) {
|
|
430
|
+
const strArg = findChild(args, 'string');
|
|
431
|
+
if (strArg) {
|
|
432
|
+
imports.push({
|
|
433
|
+
source: strArg.text.replace(/['"]/g, ''),
|
|
434
|
+
names: [],
|
|
435
|
+
line,
|
|
436
|
+
reexport: true,
|
|
437
|
+
wildcardReexport: true,
|
|
438
|
+
});
|
|
373
439
|
}
|
|
374
440
|
}
|
|
441
|
+
}
|
|
375
442
|
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
imports.push({
|
|
389
|
-
source: strArg2.text.replace(/['"]/g, ''),
|
|
390
|
-
names: [],
|
|
391
|
-
line: assignLine,
|
|
392
|
-
reexport: true,
|
|
393
|
-
wildcardReexport: true,
|
|
394
|
-
});
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
443
|
+
/** Extract `...require()` re-exports from spread elements inside an object literal. */
|
|
444
|
+
function extractSpreadRequireReexports(
|
|
445
|
+
objectNode: TreeSitterNode,
|
|
446
|
+
line: number,
|
|
447
|
+
imports: Import[],
|
|
448
|
+
): void {
|
|
449
|
+
for (let ci = 0; ci < objectNode.childCount; ci++) {
|
|
450
|
+
const child = objectNode.child(ci);
|
|
451
|
+
if (child && child.type === 'spread_element') {
|
|
452
|
+
const spreadExpr = child.child(1) || child.childForFieldName('value');
|
|
453
|
+
if (spreadExpr && spreadExpr.type === 'call_expression') {
|
|
454
|
+
extractRequireReexport(spreadExpr, line, imports);
|
|
398
455
|
}
|
|
399
456
|
}
|
|
400
457
|
}
|
|
@@ -918,56 +975,13 @@ function extractNewExprTypeName(newExprNode: TreeSitterNode): string | null {
|
|
|
918
975
|
* Higher-confidence entries take priority when the same variable is seen twice.
|
|
919
976
|
*/
|
|
920
977
|
function extractTypeMapWalk(rootNode: TreeSitterNode, typeMap: Map<string, TypeMapEntry>): void {
|
|
921
|
-
function setIfHigher(name: string, type: string, confidence: number): void {
|
|
922
|
-
const existing = typeMap.get(name);
|
|
923
|
-
if (!existing || confidence > existing.confidence) {
|
|
924
|
-
typeMap.set(name, { type, confidence });
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
978
|
function walk(node: TreeSitterNode, depth: number): void {
|
|
929
979
|
if (depth >= MAX_WALK_DEPTH) return;
|
|
930
980
|
const t = node.type;
|
|
931
981
|
if (t === 'variable_declarator') {
|
|
932
|
-
|
|
933
|
-
if (nameN && nameN.type === 'identifier') {
|
|
934
|
-
const typeAnno = findChild(node, 'type_annotation');
|
|
935
|
-
if (typeAnno) {
|
|
936
|
-
const typeName = extractSimpleTypeName(typeAnno);
|
|
937
|
-
if (typeName) setIfHigher(nameN.text, typeName, 0.9);
|
|
938
|
-
}
|
|
939
|
-
const valueN = node.childForFieldName('value');
|
|
940
|
-
if (valueN) {
|
|
941
|
-
// Constructor: const x = new Foo() → confidence 1.0
|
|
942
|
-
if (valueN.type === 'new_expression') {
|
|
943
|
-
const ctorType = extractNewExprTypeName(valueN);
|
|
944
|
-
if (ctorType) setIfHigher(nameN.text, ctorType, 1.0);
|
|
945
|
-
}
|
|
946
|
-
// Factory method: const x = Foo.create() → confidence 0.7
|
|
947
|
-
else if (valueN.type === 'call_expression') {
|
|
948
|
-
const fn = valueN.childForFieldName('function');
|
|
949
|
-
if (fn && fn.type === 'member_expression') {
|
|
950
|
-
const obj = fn.childForFieldName('object');
|
|
951
|
-
if (obj && obj.type === 'identifier') {
|
|
952
|
-
const objName = obj.text;
|
|
953
|
-
if (objName[0]! !== objName[0]!.toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
|
|
954
|
-
setIfHigher(nameN.text, objName, 0.7);
|
|
955
|
-
}
|
|
956
|
-
}
|
|
957
|
-
}
|
|
958
|
-
}
|
|
959
|
-
}
|
|
960
|
-
}
|
|
982
|
+
handleVarDeclaratorTypeMap(node, typeMap);
|
|
961
983
|
} else if (t === 'required_parameter' || t === 'optional_parameter') {
|
|
962
|
-
|
|
963
|
-
node.childForFieldName('pattern') || node.childForFieldName('left') || node.child(0);
|
|
964
|
-
if (nameNode && nameNode.type === 'identifier') {
|
|
965
|
-
const typeAnno = findChild(node, 'type_annotation');
|
|
966
|
-
if (typeAnno) {
|
|
967
|
-
const typeName = extractSimpleTypeName(typeAnno);
|
|
968
|
-
if (typeName) setIfHigher(nameNode.text, typeName, 0.9);
|
|
969
|
-
}
|
|
970
|
-
}
|
|
984
|
+
handleParamTypeMap(node, typeMap);
|
|
971
985
|
}
|
|
972
986
|
for (let i = 0; i < node.childCount; i++) {
|
|
973
987
|
walk(node.child(i)!, depth + 1);
|
|
@@ -976,6 +990,56 @@ function extractTypeMapWalk(rootNode: TreeSitterNode, typeMap: Map<string, TypeM
|
|
|
976
990
|
walk(rootNode, 0);
|
|
977
991
|
}
|
|
978
992
|
|
|
993
|
+
/** Extract type info from a variable_declarator: type annotation, constructor, or factory. */
|
|
994
|
+
function handleVarDeclaratorTypeMap(
|
|
995
|
+
node: TreeSitterNode,
|
|
996
|
+
typeMap: Map<string, TypeMapEntry>,
|
|
997
|
+
): void {
|
|
998
|
+
const nameN = node.childForFieldName('name');
|
|
999
|
+
if (!nameN || nameN.type !== 'identifier') return;
|
|
1000
|
+
|
|
1001
|
+
// Type annotation: const x: Foo = …
|
|
1002
|
+
const typeAnno = findChild(node, 'type_annotation');
|
|
1003
|
+
if (typeAnno) {
|
|
1004
|
+
const typeName = extractSimpleTypeName(typeAnno);
|
|
1005
|
+
if (typeName) setTypeMapEntry(typeMap, nameN.text, typeName, 0.9);
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
const valueN = node.childForFieldName('value');
|
|
1009
|
+
if (!valueN) return;
|
|
1010
|
+
|
|
1011
|
+
// Constructor: const x = new Foo() → confidence 1.0
|
|
1012
|
+
if (valueN.type === 'new_expression') {
|
|
1013
|
+
const ctorType = extractNewExprTypeName(valueN);
|
|
1014
|
+
if (ctorType) setTypeMapEntry(typeMap, nameN.text, ctorType, 1.0);
|
|
1015
|
+
}
|
|
1016
|
+
// Factory method: const x = Foo.create() → confidence 0.7
|
|
1017
|
+
else if (valueN.type === 'call_expression') {
|
|
1018
|
+
const fn = valueN.childForFieldName('function');
|
|
1019
|
+
if (fn && fn.type === 'member_expression') {
|
|
1020
|
+
const obj = fn.childForFieldName('object');
|
|
1021
|
+
if (obj && obj.type === 'identifier') {
|
|
1022
|
+
const objName = obj.text;
|
|
1023
|
+
if (objName[0]! !== objName[0]!.toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
|
|
1024
|
+
setTypeMapEntry(typeMap, nameN.text, objName, 0.7);
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
|
|
1031
|
+
/** Extract type info from a required_parameter or optional_parameter. */
|
|
1032
|
+
function handleParamTypeMap(node: TreeSitterNode, typeMap: Map<string, TypeMapEntry>): void {
|
|
1033
|
+
const nameNode =
|
|
1034
|
+
node.childForFieldName('pattern') || node.childForFieldName('left') || node.child(0);
|
|
1035
|
+
if (!nameNode || nameNode.type !== 'identifier') return;
|
|
1036
|
+
const typeAnno = findChild(node, 'type_annotation');
|
|
1037
|
+
if (typeAnno) {
|
|
1038
|
+
const typeName = extractSimpleTypeName(typeAnno);
|
|
1039
|
+
if (typeName) setTypeMapEntry(typeMap, nameNode.text, typeName, 0.9);
|
|
1040
|
+
}
|
|
1041
|
+
}
|
|
1042
|
+
|
|
979
1043
|
function extractReceiverName(objNode: TreeSitterNode | null): string | undefined {
|
|
980
1044
|
if (!objNode) return undefined;
|
|
981
1045
|
const t = objNode.type;
|
|
@@ -988,57 +1052,66 @@ function extractCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | n
|
|
|
988
1052
|
if (fnType === 'identifier') {
|
|
989
1053
|
return { name: fn.text, line: callNode.startPosition.row + 1 };
|
|
990
1054
|
}
|
|
991
|
-
|
|
992
1055
|
if (fnType === 'member_expression') {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
if (propText === 'call' || propText === 'apply' || propText === 'bind') {
|
|
1001
|
-
if (obj && obj.type === 'identifier')
|
|
1002
|
-
return { name: obj.text, line: callLine, dynamic: true };
|
|
1003
|
-
if (obj && obj.type === 'member_expression') {
|
|
1004
|
-
const innerProp = obj.childForFieldName('property');
|
|
1005
|
-
if (innerProp) return { name: innerProp.text, line: callLine, dynamic: true };
|
|
1006
|
-
}
|
|
1007
|
-
}
|
|
1056
|
+
return extractMemberExprCallInfo(fn, callNode);
|
|
1057
|
+
}
|
|
1058
|
+
if (fnType === 'subscript_expression') {
|
|
1059
|
+
return extractSubscriptCallInfo(fn, callNode);
|
|
1060
|
+
}
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1008
1063
|
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1064
|
+
/** Extract call info from a member_expression function node (obj.method()). */
|
|
1065
|
+
function extractMemberExprCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | null {
|
|
1066
|
+
const obj = fn.childForFieldName('object');
|
|
1067
|
+
const prop = fn.childForFieldName('property');
|
|
1068
|
+
if (!prop) return null;
|
|
1069
|
+
|
|
1070
|
+
const callLine = callNode.startPosition.row + 1;
|
|
1071
|
+
const propText = prop.text;
|
|
1017
1072
|
|
|
1018
|
-
|
|
1019
|
-
|
|
1073
|
+
// .call()/.apply()/.bind() — dynamic invocation
|
|
1074
|
+
if (propText === 'call' || propText === 'apply' || propText === 'bind') {
|
|
1075
|
+
if (obj && obj.type === 'identifier') return { name: obj.text, line: callLine, dynamic: true };
|
|
1076
|
+
if (obj && obj.type === 'member_expression') {
|
|
1077
|
+
const innerProp = obj.childForFieldName('property');
|
|
1078
|
+
if (innerProp) return { name: innerProp.text, line: callLine, dynamic: true };
|
|
1079
|
+
}
|
|
1020
1080
|
}
|
|
1021
1081
|
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
if (methodName && !methodName.includes('$')) {
|
|
1030
|
-
const receiver = extractReceiverName(obj);
|
|
1031
|
-
return {
|
|
1032
|
-
name: methodName,
|
|
1033
|
-
line: callNode.startPosition.row + 1,
|
|
1034
|
-
dynamic: true,
|
|
1035
|
-
receiver,
|
|
1036
|
-
};
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1082
|
+
// Computed property: obj["method"]()
|
|
1083
|
+
const propType = prop.type;
|
|
1084
|
+
if (propType === 'string' || propType === 'string_fragment') {
|
|
1085
|
+
const methodName = propText.replace(/['"]/g, '');
|
|
1086
|
+
if (methodName) {
|
|
1087
|
+
const receiver = extractReceiverName(obj);
|
|
1088
|
+
return { name: methodName, line: callLine, dynamic: true, receiver };
|
|
1039
1089
|
}
|
|
1040
1090
|
}
|
|
1041
1091
|
|
|
1092
|
+
const receiver = extractReceiverName(obj);
|
|
1093
|
+
return { name: propText, line: callLine, receiver };
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
/** Extract call info from a subscript_expression function node (obj["method"]()). */
|
|
1097
|
+
function extractSubscriptCallInfo(fn: TreeSitterNode, callNode: TreeSitterNode): Call | null {
|
|
1098
|
+
const obj = fn.childForFieldName('object');
|
|
1099
|
+
const index = fn.childForFieldName('index');
|
|
1100
|
+
if (!index) return null;
|
|
1101
|
+
|
|
1102
|
+
const indexType = index.type;
|
|
1103
|
+
if (indexType === 'string' || indexType === 'template_string') {
|
|
1104
|
+
const methodName = index.text.replace(/['"`]/g, '');
|
|
1105
|
+
if (methodName && !methodName.includes('$')) {
|
|
1106
|
+
const receiver = extractReceiverName(obj);
|
|
1107
|
+
return {
|
|
1108
|
+
name: methodName,
|
|
1109
|
+
line: callNode.startPosition.row + 1,
|
|
1110
|
+
dynamic: true,
|
|
1111
|
+
receiver,
|
|
1112
|
+
};
|
|
1113
|
+
}
|
|
1114
|
+
}
|
|
1042
1115
|
return null;
|
|
1043
1116
|
}
|
|
1044
1117
|
|
|
@@ -1173,17 +1246,9 @@ function extractSuperclass(heritage: TreeSitterNode): string | null {
|
|
|
1173
1246
|
return null;
|
|
1174
1247
|
}
|
|
1175
1248
|
|
|
1249
|
+
const JS_CLASS_TYPES = ['class_declaration', 'class'] as const;
|
|
1176
1250
|
function findParentClass(node: TreeSitterNode): string | null {
|
|
1177
|
-
|
|
1178
|
-
while (current) {
|
|
1179
|
-
const t = current.type;
|
|
1180
|
-
if (t === 'class_declaration' || t === 'class') {
|
|
1181
|
-
const nameNode = current.childForFieldName('name');
|
|
1182
|
-
return nameNode ? nameNode.text : null;
|
|
1183
|
-
}
|
|
1184
|
-
current = current.parent;
|
|
1185
|
-
}
|
|
1186
|
-
return null;
|
|
1251
|
+
return findParentNode(node, JS_CLASS_TYPES);
|
|
1187
1252
|
}
|
|
1188
1253
|
|
|
1189
1254
|
function extractImportNames(node: TreeSitterNode): string[] {
|