@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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { debug } from '../infrastructure/logger.js';
|
|
2
|
-
import { findChild, MAX_WALK_DEPTH, nodeEndLine } from './helpers.js';
|
|
2
|
+
import { findChild, findParentNode, MAX_WALK_DEPTH, nodeEndLine, setTypeMapEntry, } from './helpers.js';
|
|
3
3
|
/** Built-in globals that start with uppercase but are not user-defined types. */
|
|
4
4
|
const BUILTIN_GLOBALS = new Set([
|
|
5
5
|
'Math',
|
|
@@ -67,6 +67,176 @@ export function extractSymbols(tree, _filePath, query) {
|
|
|
67
67
|
return extractSymbolsWalk(tree);
|
|
68
68
|
}
|
|
69
69
|
// ── Query-based extraction (fast path) ──────────────────────────────────────
|
|
70
|
+
/** Handle function_declaration capture. */
|
|
71
|
+
function handleFnCapture(c, definitions) {
|
|
72
|
+
const fnChildren = extractParameters(c.fn_node);
|
|
73
|
+
definitions.push({
|
|
74
|
+
name: c.fn_name.text,
|
|
75
|
+
kind: 'function',
|
|
76
|
+
line: c.fn_node.startPosition.row + 1,
|
|
77
|
+
endLine: nodeEndLine(c.fn_node),
|
|
78
|
+
children: fnChildren.length > 0 ? fnChildren : undefined,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
/** Handle variable_declarator with arrow_function / function_expression capture. */
|
|
82
|
+
function handleVarFnCapture(c, definitions) {
|
|
83
|
+
const declNode = c.varfn_name.parent?.parent;
|
|
84
|
+
const line = declNode ? declNode.startPosition.row + 1 : c.varfn_name.startPosition.row + 1;
|
|
85
|
+
const varFnChildren = extractParameters(c.varfn_value);
|
|
86
|
+
definitions.push({
|
|
87
|
+
name: c.varfn_name.text,
|
|
88
|
+
kind: 'function',
|
|
89
|
+
line,
|
|
90
|
+
endLine: nodeEndLine(c.varfn_value),
|
|
91
|
+
children: varFnChildren.length > 0 ? varFnChildren : undefined,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
/** Handle class_declaration capture. */
|
|
95
|
+
function handleClassCapture(c, definitions, classes) {
|
|
96
|
+
const className = c.cls_name.text;
|
|
97
|
+
const startLine = c.cls_node.startPosition.row + 1;
|
|
98
|
+
const clsChildren = extractClassProperties(c.cls_node);
|
|
99
|
+
definitions.push({
|
|
100
|
+
name: className,
|
|
101
|
+
kind: 'class',
|
|
102
|
+
line: startLine,
|
|
103
|
+
endLine: nodeEndLine(c.cls_node),
|
|
104
|
+
children: clsChildren.length > 0 ? clsChildren : undefined,
|
|
105
|
+
});
|
|
106
|
+
const heritage = c.cls_node.childForFieldName('heritage') || findChild(c.cls_node, 'class_heritage');
|
|
107
|
+
if (heritage) {
|
|
108
|
+
const superName = extractSuperclass(heritage);
|
|
109
|
+
if (superName)
|
|
110
|
+
classes.push({ name: className, extends: superName, line: startLine });
|
|
111
|
+
const implementsList = extractImplements(heritage);
|
|
112
|
+
for (const iface of implementsList) {
|
|
113
|
+
classes.push({ name: className, implements: iface, line: startLine });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** Handle method_definition capture. */
|
|
118
|
+
function handleMethodCapture(c, definitions) {
|
|
119
|
+
const methName = c.meth_name.text;
|
|
120
|
+
const parentClass = findParentClass(c.meth_node);
|
|
121
|
+
const fullName = parentClass ? `${parentClass}.${methName}` : methName;
|
|
122
|
+
const methChildren = extractParameters(c.meth_node);
|
|
123
|
+
const methVis = extractVisibility(c.meth_node);
|
|
124
|
+
definitions.push({
|
|
125
|
+
name: fullName,
|
|
126
|
+
kind: 'method',
|
|
127
|
+
line: c.meth_node.startPosition.row + 1,
|
|
128
|
+
endLine: nodeEndLine(c.meth_node),
|
|
129
|
+
children: methChildren.length > 0 ? methChildren : undefined,
|
|
130
|
+
visibility: methVis,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/** Handle export_statement capture. */
|
|
134
|
+
function handleExportCapture(c, exps, imports) {
|
|
135
|
+
const exportLine = c.exp_node.startPosition.row + 1;
|
|
136
|
+
const decl = c.exp_node.childForFieldName('declaration');
|
|
137
|
+
if (decl) {
|
|
138
|
+
const declType = decl.type;
|
|
139
|
+
const kindMap = {
|
|
140
|
+
function_declaration: 'function',
|
|
141
|
+
class_declaration: 'class',
|
|
142
|
+
interface_declaration: 'interface',
|
|
143
|
+
type_alias_declaration: 'type',
|
|
144
|
+
};
|
|
145
|
+
const kind = kindMap[declType];
|
|
146
|
+
if (kind) {
|
|
147
|
+
const n = decl.childForFieldName('name');
|
|
148
|
+
if (n)
|
|
149
|
+
exps.push({ name: n.text, kind: kind, line: exportLine });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const source = c.exp_node.childForFieldName('source') || findChild(c.exp_node, 'string');
|
|
153
|
+
if (source && !decl) {
|
|
154
|
+
const modPath = source.text.replace(/['"]/g, '');
|
|
155
|
+
const reexportNames = extractImportNames(c.exp_node);
|
|
156
|
+
const nodeText = c.exp_node.text;
|
|
157
|
+
const isWildcard = nodeText.includes('export *') || nodeText.includes('export*');
|
|
158
|
+
imports.push({
|
|
159
|
+
source: modPath,
|
|
160
|
+
names: reexportNames,
|
|
161
|
+
line: exportLine,
|
|
162
|
+
reexport: true,
|
|
163
|
+
wildcardReexport: isWildcard && reexportNames.length === 0,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/** Dispatch a single query match to the appropriate handler. */
|
|
168
|
+
function dispatchQueryMatch(c, definitions, calls, imports, classes, exps) {
|
|
169
|
+
if (c.fn_node) {
|
|
170
|
+
handleFnCapture(c, definitions);
|
|
171
|
+
}
|
|
172
|
+
else if (c.varfn_name) {
|
|
173
|
+
handleVarFnCapture(c, definitions);
|
|
174
|
+
}
|
|
175
|
+
else if (c.cls_node) {
|
|
176
|
+
handleClassCapture(c, definitions, classes);
|
|
177
|
+
}
|
|
178
|
+
else if (c.meth_node) {
|
|
179
|
+
handleMethodCapture(c, definitions);
|
|
180
|
+
}
|
|
181
|
+
else if (c.iface_node) {
|
|
182
|
+
const ifaceName = c.iface_name.text;
|
|
183
|
+
definitions.push({
|
|
184
|
+
name: ifaceName,
|
|
185
|
+
kind: 'interface',
|
|
186
|
+
line: c.iface_node.startPosition.row + 1,
|
|
187
|
+
endLine: nodeEndLine(c.iface_node),
|
|
188
|
+
});
|
|
189
|
+
const body = c.iface_node.childForFieldName('body') ||
|
|
190
|
+
findChild(c.iface_node, 'interface_body') ||
|
|
191
|
+
findChild(c.iface_node, 'object_type');
|
|
192
|
+
if (body)
|
|
193
|
+
extractInterfaceMethods(body, ifaceName, definitions);
|
|
194
|
+
}
|
|
195
|
+
else if (c.type_node) {
|
|
196
|
+
definitions.push({
|
|
197
|
+
name: c.type_name.text,
|
|
198
|
+
kind: 'type',
|
|
199
|
+
line: c.type_node.startPosition.row + 1,
|
|
200
|
+
endLine: nodeEndLine(c.type_node),
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
else if (c.imp_node) {
|
|
204
|
+
const isTypeOnly = c.imp_node.text.startsWith('import type');
|
|
205
|
+
const modPath = c.imp_source.text.replace(/['"]/g, '');
|
|
206
|
+
const names = extractImportNames(c.imp_node);
|
|
207
|
+
imports.push({
|
|
208
|
+
source: modPath,
|
|
209
|
+
names,
|
|
210
|
+
line: c.imp_node.startPosition.row + 1,
|
|
211
|
+
typeOnly: isTypeOnly,
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
else if (c.exp_node) {
|
|
215
|
+
handleExportCapture(c, exps, imports);
|
|
216
|
+
}
|
|
217
|
+
else if (c.callfn_node) {
|
|
218
|
+
calls.push({
|
|
219
|
+
name: c.callfn_name.text,
|
|
220
|
+
line: c.callfn_node.startPosition.row + 1,
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
else if (c.callmem_node) {
|
|
224
|
+
const callInfo = extractCallInfo(c.callmem_fn, c.callmem_node);
|
|
225
|
+
if (callInfo)
|
|
226
|
+
calls.push(callInfo);
|
|
227
|
+
const cbDef = extractCallbackDefinition(c.callmem_node, c.callmem_fn);
|
|
228
|
+
if (cbDef)
|
|
229
|
+
definitions.push(cbDef);
|
|
230
|
+
}
|
|
231
|
+
else if (c.callsub_node) {
|
|
232
|
+
const callInfo = extractCallInfo(c.callsub_fn, c.callsub_node);
|
|
233
|
+
if (callInfo)
|
|
234
|
+
calls.push(callInfo);
|
|
235
|
+
}
|
|
236
|
+
else if (c.assign_node) {
|
|
237
|
+
handleCommonJSAssignment(c.assign_left, c.assign_right, c.assign_node, imports);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
70
240
|
function extractSymbolsQuery(tree, query) {
|
|
71
241
|
const definitions = [];
|
|
72
242
|
const calls = [];
|
|
@@ -80,165 +250,7 @@ function extractSymbolsQuery(tree, query) {
|
|
|
80
250
|
const c = Object.create(null);
|
|
81
251
|
for (const cap of match.captures)
|
|
82
252
|
c[cap.name] = cap.node;
|
|
83
|
-
|
|
84
|
-
// function_declaration
|
|
85
|
-
const fnChildren = extractParameters(c.fn_node);
|
|
86
|
-
definitions.push({
|
|
87
|
-
name: c.fn_name.text,
|
|
88
|
-
kind: 'function',
|
|
89
|
-
line: c.fn_node.startPosition.row + 1,
|
|
90
|
-
endLine: nodeEndLine(c.fn_node),
|
|
91
|
-
children: fnChildren.length > 0 ? fnChildren : undefined,
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
else if (c.varfn_name) {
|
|
95
|
-
// variable_declarator with arrow_function / function_expression
|
|
96
|
-
const declNode = c.varfn_name.parent?.parent;
|
|
97
|
-
const line = declNode ? declNode.startPosition.row + 1 : c.varfn_name.startPosition.row + 1;
|
|
98
|
-
const varFnChildren = extractParameters(c.varfn_value);
|
|
99
|
-
definitions.push({
|
|
100
|
-
name: c.varfn_name.text,
|
|
101
|
-
kind: 'function',
|
|
102
|
-
line,
|
|
103
|
-
endLine: nodeEndLine(c.varfn_value),
|
|
104
|
-
children: varFnChildren.length > 0 ? varFnChildren : undefined,
|
|
105
|
-
});
|
|
106
|
-
}
|
|
107
|
-
else if (c.cls_node) {
|
|
108
|
-
// class_declaration
|
|
109
|
-
const className = c.cls_name.text;
|
|
110
|
-
const startLine = c.cls_node.startPosition.row + 1;
|
|
111
|
-
const clsChildren = extractClassProperties(c.cls_node);
|
|
112
|
-
definitions.push({
|
|
113
|
-
name: className,
|
|
114
|
-
kind: 'class',
|
|
115
|
-
line: startLine,
|
|
116
|
-
endLine: nodeEndLine(c.cls_node),
|
|
117
|
-
children: clsChildren.length > 0 ? clsChildren : undefined,
|
|
118
|
-
});
|
|
119
|
-
const heritage = c.cls_node.childForFieldName('heritage') || findChild(c.cls_node, 'class_heritage');
|
|
120
|
-
if (heritage) {
|
|
121
|
-
const superName = extractSuperclass(heritage);
|
|
122
|
-
if (superName)
|
|
123
|
-
classes.push({ name: className, extends: superName, line: startLine });
|
|
124
|
-
const implementsList = extractImplements(heritage);
|
|
125
|
-
for (const iface of implementsList) {
|
|
126
|
-
classes.push({ name: className, implements: iface, line: startLine });
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
else if (c.meth_node) {
|
|
131
|
-
// method_definition
|
|
132
|
-
const methName = c.meth_name.text;
|
|
133
|
-
const parentClass = findParentClass(c.meth_node);
|
|
134
|
-
const fullName = parentClass ? `${parentClass}.${methName}` : methName;
|
|
135
|
-
const methChildren = extractParameters(c.meth_node);
|
|
136
|
-
const methVis = extractVisibility(c.meth_node);
|
|
137
|
-
definitions.push({
|
|
138
|
-
name: fullName,
|
|
139
|
-
kind: 'method',
|
|
140
|
-
line: c.meth_node.startPosition.row + 1,
|
|
141
|
-
endLine: nodeEndLine(c.meth_node),
|
|
142
|
-
children: methChildren.length > 0 ? methChildren : undefined,
|
|
143
|
-
visibility: methVis,
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
else if (c.iface_node) {
|
|
147
|
-
// interface_declaration (TS/TSX only)
|
|
148
|
-
const ifaceName = c.iface_name.text;
|
|
149
|
-
definitions.push({
|
|
150
|
-
name: ifaceName,
|
|
151
|
-
kind: 'interface',
|
|
152
|
-
line: c.iface_node.startPosition.row + 1,
|
|
153
|
-
endLine: nodeEndLine(c.iface_node),
|
|
154
|
-
});
|
|
155
|
-
const body = c.iface_node.childForFieldName('body') ||
|
|
156
|
-
findChild(c.iface_node, 'interface_body') ||
|
|
157
|
-
findChild(c.iface_node, 'object_type');
|
|
158
|
-
if (body)
|
|
159
|
-
extractInterfaceMethods(body, ifaceName, definitions);
|
|
160
|
-
}
|
|
161
|
-
else if (c.type_node) {
|
|
162
|
-
// type_alias_declaration (TS/TSX only)
|
|
163
|
-
definitions.push({
|
|
164
|
-
name: c.type_name.text,
|
|
165
|
-
kind: 'type',
|
|
166
|
-
line: c.type_node.startPosition.row + 1,
|
|
167
|
-
endLine: nodeEndLine(c.type_node),
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
else if (c.imp_node) {
|
|
171
|
-
// import_statement
|
|
172
|
-
const isTypeOnly = c.imp_node.text.startsWith('import type');
|
|
173
|
-
const modPath = c.imp_source.text.replace(/['"]/g, '');
|
|
174
|
-
const names = extractImportNames(c.imp_node);
|
|
175
|
-
imports.push({
|
|
176
|
-
source: modPath,
|
|
177
|
-
names,
|
|
178
|
-
line: c.imp_node.startPosition.row + 1,
|
|
179
|
-
typeOnly: isTypeOnly,
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
else if (c.exp_node) {
|
|
183
|
-
// export_statement
|
|
184
|
-
const exportLine = c.exp_node.startPosition.row + 1;
|
|
185
|
-
const decl = c.exp_node.childForFieldName('declaration');
|
|
186
|
-
if (decl) {
|
|
187
|
-
const declType = decl.type;
|
|
188
|
-
const kindMap = {
|
|
189
|
-
function_declaration: 'function',
|
|
190
|
-
class_declaration: 'class',
|
|
191
|
-
interface_declaration: 'interface',
|
|
192
|
-
type_alias_declaration: 'type',
|
|
193
|
-
};
|
|
194
|
-
const kind = kindMap[declType];
|
|
195
|
-
if (kind) {
|
|
196
|
-
const n = decl.childForFieldName('name');
|
|
197
|
-
if (n)
|
|
198
|
-
exps.push({ name: n.text, kind: kind, line: exportLine });
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
|
-
const source = c.exp_node.childForFieldName('source') || findChild(c.exp_node, 'string');
|
|
202
|
-
if (source && !decl) {
|
|
203
|
-
const modPath = source.text.replace(/['"]/g, '');
|
|
204
|
-
const reexportNames = extractImportNames(c.exp_node);
|
|
205
|
-
const nodeText = c.exp_node.text;
|
|
206
|
-
const isWildcard = nodeText.includes('export *') || nodeText.includes('export*');
|
|
207
|
-
imports.push({
|
|
208
|
-
source: modPath,
|
|
209
|
-
names: reexportNames,
|
|
210
|
-
line: exportLine,
|
|
211
|
-
reexport: true,
|
|
212
|
-
wildcardReexport: isWildcard && reexportNames.length === 0,
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
else if (c.callfn_node) {
|
|
217
|
-
// call_expression with identifier function
|
|
218
|
-
calls.push({
|
|
219
|
-
name: c.callfn_name.text,
|
|
220
|
-
line: c.callfn_node.startPosition.row + 1,
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
else if (c.callmem_node) {
|
|
224
|
-
// call_expression with member_expression function
|
|
225
|
-
const callInfo = extractCallInfo(c.callmem_fn, c.callmem_node);
|
|
226
|
-
if (callInfo)
|
|
227
|
-
calls.push(callInfo);
|
|
228
|
-
const cbDef = extractCallbackDefinition(c.callmem_node, c.callmem_fn);
|
|
229
|
-
if (cbDef)
|
|
230
|
-
definitions.push(cbDef);
|
|
231
|
-
}
|
|
232
|
-
else if (c.callsub_node) {
|
|
233
|
-
// call_expression with subscript_expression function
|
|
234
|
-
const callInfo = extractCallInfo(c.callsub_fn, c.callsub_node);
|
|
235
|
-
if (callInfo)
|
|
236
|
-
calls.push(callInfo);
|
|
237
|
-
}
|
|
238
|
-
else if (c.assign_node) {
|
|
239
|
-
// CommonJS: module.exports = require(...) / module.exports = { ...require(...) }
|
|
240
|
-
handleCommonJSAssignment(c.assign_left, c.assign_right, c.assign_node, imports);
|
|
241
|
-
}
|
|
253
|
+
dispatchQueryMatch(c, definitions, calls, imports, classes, exps);
|
|
242
254
|
}
|
|
243
255
|
// Extract top-level constants via targeted walk (query patterns don't cover these)
|
|
244
256
|
extractConstantsWalk(tree.rootNode, definitions);
|
|
@@ -248,52 +260,67 @@ function extractSymbolsQuery(tree, query) {
|
|
|
248
260
|
extractTypeMapWalk(tree.rootNode, typeMap);
|
|
249
261
|
return { definitions, calls, imports, classes, exports: exps, typeMap };
|
|
250
262
|
}
|
|
263
|
+
/** Node types that define a function scope — constants inside these are skipped. */
|
|
264
|
+
const FUNCTION_SCOPE_TYPES = new Set([
|
|
265
|
+
'function_declaration',
|
|
266
|
+
'arrow_function',
|
|
267
|
+
'function_expression',
|
|
268
|
+
'method_definition',
|
|
269
|
+
'generator_function_declaration',
|
|
270
|
+
'generator_function',
|
|
271
|
+
]);
|
|
251
272
|
/**
|
|
252
|
-
*
|
|
253
|
-
*
|
|
254
|
-
*
|
|
273
|
+
* Recursively walk the AST to extract `const x = <literal>` as constants.
|
|
274
|
+
* Skips nodes inside function scopes so only file-level / block-level constants
|
|
275
|
+
* are captured — matching the native engine's behaviour.
|
|
255
276
|
*/
|
|
256
|
-
function extractConstantsWalk(
|
|
257
|
-
for (let i = 0; i <
|
|
258
|
-
const
|
|
259
|
-
if (!
|
|
277
|
+
function extractConstantsWalk(node, definitions) {
|
|
278
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
279
|
+
const child = node.child(i);
|
|
280
|
+
if (!child)
|
|
260
281
|
continue;
|
|
261
|
-
|
|
282
|
+
// Don't descend into function scopes
|
|
283
|
+
if (FUNCTION_SCOPE_TYPES.has(child.type))
|
|
284
|
+
continue;
|
|
285
|
+
let declNode = child;
|
|
262
286
|
// Handle `export const …` — unwrap the export_statement to its declaration child
|
|
263
|
-
if (
|
|
264
|
-
const inner =
|
|
265
|
-
if (
|
|
266
|
-
|
|
267
|
-
declNode = inner;
|
|
287
|
+
if (child.type === 'export_statement') {
|
|
288
|
+
const inner = child.childForFieldName('declaration');
|
|
289
|
+
if (inner)
|
|
290
|
+
declNode = inner;
|
|
268
291
|
}
|
|
269
292
|
const t = declNode.type;
|
|
270
|
-
if (t
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
}
|
|
293
|
+
if (t === 'lexical_declaration' || t === 'variable_declaration') {
|
|
294
|
+
if (declNode.text.startsWith('const ')) {
|
|
295
|
+
for (let j = 0; j < declNode.childCount; j++) {
|
|
296
|
+
const declarator = declNode.child(j);
|
|
297
|
+
if (!declarator || declarator.type !== 'variable_declarator')
|
|
298
|
+
continue;
|
|
299
|
+
const nameN = declarator.childForFieldName('name');
|
|
300
|
+
const valueN = declarator.childForFieldName('value');
|
|
301
|
+
if (!nameN || nameN.type !== 'identifier' || !valueN)
|
|
302
|
+
continue;
|
|
303
|
+
// Skip functions — already captured by query patterns
|
|
304
|
+
const valType = valueN.type;
|
|
305
|
+
if (valType === 'arrow_function' ||
|
|
306
|
+
valType === 'function_expression' ||
|
|
307
|
+
valType === 'function')
|
|
308
|
+
continue;
|
|
309
|
+
if (isConstantValue(valueN)) {
|
|
310
|
+
definitions.push({
|
|
311
|
+
name: nameN.text,
|
|
312
|
+
kind: 'constant',
|
|
313
|
+
line: declNode.startPosition.row + 1,
|
|
314
|
+
endLine: nodeEndLine(declNode),
|
|
315
|
+
});
|
|
316
|
+
}
|
|
317
|
+
}
|
|
295
318
|
}
|
|
296
319
|
}
|
|
320
|
+
// Recurse into non-function, non-export-statement children (blocks, if-statements, etc.)
|
|
321
|
+
if (child.type !== 'export_statement') {
|
|
322
|
+
extractConstantsWalk(child, definitions);
|
|
323
|
+
}
|
|
297
324
|
}
|
|
298
325
|
}
|
|
299
326
|
/**
|
|
@@ -335,45 +362,41 @@ function handleCommonJSAssignment(left, right, node, imports) {
|
|
|
335
362
|
const leftText = left.text;
|
|
336
363
|
if (!leftText.startsWith('module.exports') && leftText !== 'exports')
|
|
337
364
|
return;
|
|
338
|
-
const rightType = right.type;
|
|
339
365
|
const assignLine = node.startPosition.row + 1;
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
366
|
+
// module.exports = require("…") — direct re-export
|
|
367
|
+
if (right.type === 'call_expression') {
|
|
368
|
+
extractRequireReexport(right, assignLine, imports);
|
|
369
|
+
}
|
|
370
|
+
// module.exports = { ...require("…") } — spread re-export
|
|
371
|
+
if (right.type === 'object') {
|
|
372
|
+
extractSpreadRequireReexports(right, assignLine, imports);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
/** Extract a direct `require()` re-export from a call_expression. */
|
|
376
|
+
function extractRequireReexport(callExpr, line, imports) {
|
|
377
|
+
const fn = callExpr.childForFieldName('function');
|
|
378
|
+
const args = callExpr.childForFieldName('arguments') || findChild(callExpr, 'arguments');
|
|
379
|
+
if (fn && fn.text === 'require' && args) {
|
|
380
|
+
const strArg = findChild(args, 'string');
|
|
381
|
+
if (strArg) {
|
|
382
|
+
imports.push({
|
|
383
|
+
source: strArg.text.replace(/['"]/g, ''),
|
|
384
|
+
names: [],
|
|
385
|
+
line,
|
|
386
|
+
reexport: true,
|
|
387
|
+
wildcardReexport: true,
|
|
388
|
+
});
|
|
354
389
|
}
|
|
355
390
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
const strArg2 = findChild(args2, 'string');
|
|
366
|
-
if (strArg2) {
|
|
367
|
-
imports.push({
|
|
368
|
-
source: strArg2.text.replace(/['"]/g, ''),
|
|
369
|
-
names: [],
|
|
370
|
-
line: assignLine,
|
|
371
|
-
reexport: true,
|
|
372
|
-
wildcardReexport: true,
|
|
373
|
-
});
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
}
|
|
391
|
+
}
|
|
392
|
+
/** Extract `...require()` re-exports from spread elements inside an object literal. */
|
|
393
|
+
function extractSpreadRequireReexports(objectNode, line, imports) {
|
|
394
|
+
for (let ci = 0; ci < objectNode.childCount; ci++) {
|
|
395
|
+
const child = objectNode.child(ci);
|
|
396
|
+
if (child && child.type === 'spread_element') {
|
|
397
|
+
const spreadExpr = child.child(1) || child.childForFieldName('value');
|
|
398
|
+
if (spreadExpr && spreadExpr.type === 'call_expression') {
|
|
399
|
+
extractRequireReexport(spreadExpr, line, imports);
|
|
377
400
|
}
|
|
378
401
|
}
|
|
379
402
|
}
|
|
@@ -881,59 +904,15 @@ function extractNewExprTypeName(newExprNode) {
|
|
|
881
904
|
* Higher-confidence entries take priority when the same variable is seen twice.
|
|
882
905
|
*/
|
|
883
906
|
function extractTypeMapWalk(rootNode, typeMap) {
|
|
884
|
-
function setIfHigher(name, type, confidence) {
|
|
885
|
-
const existing = typeMap.get(name);
|
|
886
|
-
if (!existing || confidence > existing.confidence) {
|
|
887
|
-
typeMap.set(name, { type, confidence });
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
907
|
function walk(node, depth) {
|
|
891
908
|
if (depth >= MAX_WALK_DEPTH)
|
|
892
909
|
return;
|
|
893
910
|
const t = node.type;
|
|
894
911
|
if (t === 'variable_declarator') {
|
|
895
|
-
|
|
896
|
-
if (nameN && nameN.type === 'identifier') {
|
|
897
|
-
const typeAnno = findChild(node, 'type_annotation');
|
|
898
|
-
if (typeAnno) {
|
|
899
|
-
const typeName = extractSimpleTypeName(typeAnno);
|
|
900
|
-
if (typeName)
|
|
901
|
-
setIfHigher(nameN.text, typeName, 0.9);
|
|
902
|
-
}
|
|
903
|
-
const valueN = node.childForFieldName('value');
|
|
904
|
-
if (valueN) {
|
|
905
|
-
// Constructor: const x = new Foo() → confidence 1.0
|
|
906
|
-
if (valueN.type === 'new_expression') {
|
|
907
|
-
const ctorType = extractNewExprTypeName(valueN);
|
|
908
|
-
if (ctorType)
|
|
909
|
-
setIfHigher(nameN.text, ctorType, 1.0);
|
|
910
|
-
}
|
|
911
|
-
// Factory method: const x = Foo.create() → confidence 0.7
|
|
912
|
-
else if (valueN.type === 'call_expression') {
|
|
913
|
-
const fn = valueN.childForFieldName('function');
|
|
914
|
-
if (fn && fn.type === 'member_expression') {
|
|
915
|
-
const obj = fn.childForFieldName('object');
|
|
916
|
-
if (obj && obj.type === 'identifier') {
|
|
917
|
-
const objName = obj.text;
|
|
918
|
-
if (objName[0] !== objName[0].toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
|
|
919
|
-
setIfHigher(nameN.text, objName, 0.7);
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
}
|
|
912
|
+
handleVarDeclaratorTypeMap(node, typeMap);
|
|
926
913
|
}
|
|
927
914
|
else if (t === 'required_parameter' || t === 'optional_parameter') {
|
|
928
|
-
|
|
929
|
-
if (nameNode && nameNode.type === 'identifier') {
|
|
930
|
-
const typeAnno = findChild(node, 'type_annotation');
|
|
931
|
-
if (typeAnno) {
|
|
932
|
-
const typeName = extractSimpleTypeName(typeAnno);
|
|
933
|
-
if (typeName)
|
|
934
|
-
setIfHigher(nameNode.text, typeName, 0.9);
|
|
935
|
-
}
|
|
936
|
-
}
|
|
915
|
+
handleParamTypeMap(node, typeMap);
|
|
937
916
|
}
|
|
938
917
|
for (let i = 0; i < node.childCount; i++) {
|
|
939
918
|
walk(node.child(i), depth + 1);
|
|
@@ -941,6 +920,53 @@ function extractTypeMapWalk(rootNode, typeMap) {
|
|
|
941
920
|
}
|
|
942
921
|
walk(rootNode, 0);
|
|
943
922
|
}
|
|
923
|
+
/** Extract type info from a variable_declarator: type annotation, constructor, or factory. */
|
|
924
|
+
function handleVarDeclaratorTypeMap(node, typeMap) {
|
|
925
|
+
const nameN = node.childForFieldName('name');
|
|
926
|
+
if (!nameN || nameN.type !== 'identifier')
|
|
927
|
+
return;
|
|
928
|
+
// Type annotation: const x: Foo = …
|
|
929
|
+
const typeAnno = findChild(node, 'type_annotation');
|
|
930
|
+
if (typeAnno) {
|
|
931
|
+
const typeName = extractSimpleTypeName(typeAnno);
|
|
932
|
+
if (typeName)
|
|
933
|
+
setTypeMapEntry(typeMap, nameN.text, typeName, 0.9);
|
|
934
|
+
}
|
|
935
|
+
const valueN = node.childForFieldName('value');
|
|
936
|
+
if (!valueN)
|
|
937
|
+
return;
|
|
938
|
+
// Constructor: const x = new Foo() → confidence 1.0
|
|
939
|
+
if (valueN.type === 'new_expression') {
|
|
940
|
+
const ctorType = extractNewExprTypeName(valueN);
|
|
941
|
+
if (ctorType)
|
|
942
|
+
setTypeMapEntry(typeMap, nameN.text, ctorType, 1.0);
|
|
943
|
+
}
|
|
944
|
+
// Factory method: const x = Foo.create() → confidence 0.7
|
|
945
|
+
else if (valueN.type === 'call_expression') {
|
|
946
|
+
const fn = valueN.childForFieldName('function');
|
|
947
|
+
if (fn && fn.type === 'member_expression') {
|
|
948
|
+
const obj = fn.childForFieldName('object');
|
|
949
|
+
if (obj && obj.type === 'identifier') {
|
|
950
|
+
const objName = obj.text;
|
|
951
|
+
if (objName[0] !== objName[0].toLowerCase() && !BUILTIN_GLOBALS.has(objName)) {
|
|
952
|
+
setTypeMapEntry(typeMap, nameN.text, objName, 0.7);
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
/** Extract type info from a required_parameter or optional_parameter. */
|
|
959
|
+
function handleParamTypeMap(node, typeMap) {
|
|
960
|
+
const nameNode = node.childForFieldName('pattern') || node.childForFieldName('left') || node.child(0);
|
|
961
|
+
if (!nameNode || nameNode.type !== 'identifier')
|
|
962
|
+
return;
|
|
963
|
+
const typeAnno = findChild(node, 'type_annotation');
|
|
964
|
+
if (typeAnno) {
|
|
965
|
+
const typeName = extractSimpleTypeName(typeAnno);
|
|
966
|
+
if (typeName)
|
|
967
|
+
setTypeMapEntry(typeMap, nameNode.text, typeName, 0.9);
|
|
968
|
+
}
|
|
969
|
+
}
|
|
944
970
|
function extractReceiverName(objNode) {
|
|
945
971
|
if (!objNode)
|
|
946
972
|
return undefined;
|
|
@@ -955,49 +981,60 @@ function extractCallInfo(fn, callNode) {
|
|
|
955
981
|
return { name: fn.text, line: callNode.startPosition.row + 1 };
|
|
956
982
|
}
|
|
957
983
|
if (fnType === 'member_expression') {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
984
|
+
return extractMemberExprCallInfo(fn, callNode);
|
|
985
|
+
}
|
|
986
|
+
if (fnType === 'subscript_expression') {
|
|
987
|
+
return extractSubscriptCallInfo(fn, callNode);
|
|
988
|
+
}
|
|
989
|
+
return null;
|
|
990
|
+
}
|
|
991
|
+
/** Extract call info from a member_expression function node (obj.method()). */
|
|
992
|
+
function extractMemberExprCallInfo(fn, callNode) {
|
|
993
|
+
const obj = fn.childForFieldName('object');
|
|
994
|
+
const prop = fn.childForFieldName('property');
|
|
995
|
+
if (!prop)
|
|
996
|
+
return null;
|
|
997
|
+
const callLine = callNode.startPosition.row + 1;
|
|
998
|
+
const propText = prop.text;
|
|
999
|
+
// .call()/.apply()/.bind() — dynamic invocation
|
|
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)
|
|
1006
|
+
return { name: innerProp.text, line: callLine, dynamic: true };
|
|
972
1007
|
}
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
1008
|
+
}
|
|
1009
|
+
// Computed property: obj["method"]()
|
|
1010
|
+
const propType = prop.type;
|
|
1011
|
+
if (propType === 'string' || propType === 'string_fragment') {
|
|
1012
|
+
const methodName = propText.replace(/['"]/g, '');
|
|
1013
|
+
if (methodName) {
|
|
1014
|
+
const receiver = extractReceiverName(obj);
|
|
1015
|
+
return { name: methodName, line: callLine, dynamic: true, receiver };
|
|
980
1016
|
}
|
|
981
|
-
const receiver = extractReceiverName(obj);
|
|
982
|
-
return { name: propText, line: callLine, receiver };
|
|
983
1017
|
}
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1018
|
+
const receiver = extractReceiverName(obj);
|
|
1019
|
+
return { name: propText, line: callLine, receiver };
|
|
1020
|
+
}
|
|
1021
|
+
/** Extract call info from a subscript_expression function node (obj["method"]()). */
|
|
1022
|
+
function extractSubscriptCallInfo(fn, callNode) {
|
|
1023
|
+
const obj = fn.childForFieldName('object');
|
|
1024
|
+
const index = fn.childForFieldName('index');
|
|
1025
|
+
if (!index)
|
|
1026
|
+
return null;
|
|
1027
|
+
const indexType = index.type;
|
|
1028
|
+
if (indexType === 'string' || indexType === 'template_string') {
|
|
1029
|
+
const methodName = index.text.replace(/['"`]/g, '');
|
|
1030
|
+
if (methodName && !methodName.includes('$')) {
|
|
1031
|
+
const receiver = extractReceiverName(obj);
|
|
1032
|
+
return {
|
|
1033
|
+
name: methodName,
|
|
1034
|
+
line: callNode.startPosition.row + 1,
|
|
1035
|
+
dynamic: true,
|
|
1036
|
+
receiver,
|
|
1037
|
+
};
|
|
1001
1038
|
}
|
|
1002
1039
|
}
|
|
1003
1040
|
return null;
|
|
@@ -1134,17 +1171,9 @@ function extractSuperclass(heritage) {
|
|
|
1134
1171
|
}
|
|
1135
1172
|
return null;
|
|
1136
1173
|
}
|
|
1174
|
+
const JS_CLASS_TYPES = ['class_declaration', 'class'];
|
|
1137
1175
|
function findParentClass(node) {
|
|
1138
|
-
|
|
1139
|
-
while (current) {
|
|
1140
|
-
const t = current.type;
|
|
1141
|
-
if (t === 'class_declaration' || t === 'class') {
|
|
1142
|
-
const nameNode = current.childForFieldName('name');
|
|
1143
|
-
return nameNode ? nameNode.text : null;
|
|
1144
|
-
}
|
|
1145
|
-
current = current.parent;
|
|
1146
|
-
}
|
|
1147
|
-
return null;
|
|
1176
|
+
return findParentNode(node, JS_CLASS_TYPES);
|
|
1148
1177
|
}
|
|
1149
1178
|
function extractImportNames(node) {
|
|
1150
1179
|
const names = [];
|