@optave/codegraph 3.10.0 → 3.11.1
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 +40 -33
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +91 -60
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/index.d.ts.map +1 -1
- package/dist/ast-analysis/rules/index.js +77 -0
- package/dist/ast-analysis/rules/index.js.map +1 -1
- package/dist/ast-analysis/visitor-utils.d.ts +3 -0
- package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
- package/dist/ast-analysis/visitor-utils.js +83 -49
- package/dist/ast-analysis/visitor-utils.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 +78 -62
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.js +61 -42
- package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
- package/dist/cli/commands/audit.js +1 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +2 -0
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/check.js +1 -1
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/children.js +1 -1
- package/dist/cli/commands/children.js.map +1 -1
- package/dist/cli/commands/diff-impact.js +1 -1
- package/dist/cli/commands/diff-impact.js.map +1 -1
- package/dist/cli/commands/embed.d.ts.map +1 -1
- package/dist/cli/commands/embed.js +49 -4
- package/dist/cli/commands/embed.js.map +1 -1
- package/dist/cli/commands/roles.js +1 -1
- package/dist/cli/commands/roles.js.map +1 -1
- package/dist/cli/commands/structure.js +1 -1
- package/dist/cli/commands/structure.js.map +1 -1
- package/dist/cli/shared/options.js +1 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +8 -0
- package/dist/db/connection.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +106 -80
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +77 -52
- 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 +132 -121
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +4 -4
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +47 -33
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts +6 -6
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +148 -99
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts +1 -0
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +23 -637
- 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 +141 -98
- 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 +82 -65
- package/dist/domain/graph/builder/stages/build-structure.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 +84 -56
- 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 +60 -51
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts +8 -6
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +107 -122
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts +14 -0
- package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts.map +1 -0
- package/dist/domain/graph/builder/stages/native-db-lifecycle.js +77 -0
- package/dist/domain/graph/builder/stages/native-db-lifecycle.js.map +1 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts +62 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.js +747 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -0
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +73 -22
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/cycles.d.ts +6 -4
- package/dist/domain/graph/cycles.d.ts.map +1 -1
- package/dist/domain/graph/cycles.js +50 -55
- package/dist/domain/graph/cycles.js.map +1 -1
- package/dist/domain/graph/journal.d.ts.map +1 -1
- package/dist/domain/graph/journal.js +89 -70
- package/dist/domain/graph/journal.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +28 -20
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +12 -23
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +153 -80
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/generator.d.ts +3 -1
- package/dist/domain/search/generator.d.ts.map +1 -1
- package/dist/domain/search/generator.js +68 -45
- package/dist/domain/search/generator.js.map +1 -1
- package/dist/domain/search/models.d.ts +18 -0
- package/dist/domain/search/models.d.ts.map +1 -1
- package/dist/domain/search/models.js +72 -4
- package/dist/domain/search/models.js.map +1 -1
- package/dist/domain/search/search/hybrid.d.ts.map +1 -1
- package/dist/domain/search/search/hybrid.js +49 -40
- package/dist/domain/search/search/hybrid.js.map +1 -1
- package/dist/domain/search/search/semantic.d.ts.map +1 -1
- package/dist/domain/search/search/semantic.js +69 -49
- package/dist/domain/search/search/semantic.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +209 -137
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/extractors/c.js +25 -6
- package/dist/extractors/c.js.map +1 -1
- package/dist/extractors/cpp.js +47 -6
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/cuda.js +90 -14
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/elixir.js +108 -4
- package/dist/extractors/elixir.js.map +1 -1
- package/dist/extractors/erlang.js +56 -20
- package/dist/extractors/erlang.js.map +1 -1
- package/dist/extractors/fsharp.d.ts +7 -0
- package/dist/extractors/fsharp.d.ts.map +1 -1
- package/dist/extractors/fsharp.js +94 -0
- package/dist/extractors/fsharp.js.map +1 -1
- package/dist/extractors/gleam.d.ts.map +1 -1
- package/dist/extractors/gleam.js +29 -33
- package/dist/extractors/gleam.js.map +1 -1
- package/dist/extractors/groovy.js +41 -1
- package/dist/extractors/groovy.js.map +1 -1
- package/dist/extractors/haskell.js +48 -4
- package/dist/extractors/haskell.js.map +1 -1
- package/dist/extractors/helpers.d.ts +79 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +137 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +37 -49
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +44 -44
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/julia.js +198 -74
- package/dist/extractors/julia.js.map +1 -1
- package/dist/extractors/kotlin.js +4 -0
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/objc.js +184 -47
- package/dist/extractors/objc.js.map +1 -1
- package/dist/extractors/python.js +7 -4
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/r.d.ts.map +1 -1
- package/dist/extractors/r.js +103 -87
- package/dist/extractors/r.js.map +1 -1
- package/dist/extractors/scala.d.ts.map +1 -1
- package/dist/extractors/scala.js +18 -32
- package/dist/extractors/scala.js.map +1 -1
- package/dist/extractors/solidity.d.ts.map +1 -1
- package/dist/extractors/solidity.js +55 -69
- package/dist/extractors/solidity.js.map +1 -1
- package/dist/extractors/verilog.js +80 -15
- package/dist/extractors/verilog.js.map +1 -1
- package/dist/features/boundaries.d.ts.map +1 -1
- package/dist/features/boundaries.js +49 -39
- package/dist/features/boundaries.js.map +1 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +90 -63
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +43 -34
- package/dist/features/check.js.map +1 -1
- package/dist/features/cochange.d.ts.map +1 -1
- package/dist/features/cochange.js +68 -56
- package/dist/features/cochange.js.map +1 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +105 -75
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +37 -29
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/flow.d.ts.map +1 -1
- package/dist/features/flow.js +31 -22
- package/dist/features/flow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +77 -70
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/owners.d.ts +17 -26
- package/dist/features/owners.d.ts.map +1 -1
- package/dist/features/owners.js +120 -109
- package/dist/features/owners.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +59 -54
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +60 -60
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.js +28 -36
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +100 -69
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/classifiers/roles.d.ts.map +1 -1
- package/dist/graph/classifiers/roles.js +63 -59
- package/dist/graph/classifiers/roles.js.map +1 -1
- package/dist/infrastructure/config.d.ts +1 -1
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +1 -1
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +4 -0
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/mcp/tools/semantic-search.d.ts +1 -0
- package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
- package/dist/mcp/tools/semantic-search.js +1 -0
- package/dist/mcp/tools/semantic-search.js.map +1 -1
- package/dist/presentation/cfg.d.ts.map +1 -1
- package/dist/presentation/cfg.js +44 -29
- package/dist/presentation/cfg.js.map +1 -1
- package/dist/presentation/flow.d.ts.map +1 -1
- package/dist/presentation/flow.js +58 -38
- package/dist/presentation/flow.js.map +1 -1
- package/dist/types.d.ts +16 -2
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-erlang.wasm +0 -0
- package/grammars/tree-sitter-fsharp.wasm +0 -0
- package/grammars/tree-sitter-fsharp_signature.wasm +0 -0
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +10 -10
- package/src/ast-analysis/engine.ts +145 -61
- package/src/ast-analysis/rules/index.ts +87 -0
- package/src/ast-analysis/visitor-utils.ts +86 -46
- package/src/ast-analysis/visitors/ast-store-visitor.ts +104 -69
- package/src/ast-analysis/visitors/dataflow-visitor.ts +86 -47
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/build.ts +2 -0
- package/src/cli/commands/check.ts +1 -1
- package/src/cli/commands/children.ts +1 -1
- package/src/cli/commands/diff-impact.ts +1 -1
- package/src/cli/commands/embed.ts +54 -4
- package/src/cli/commands/roles.ts +1 -1
- package/src/cli/commands/structure.ts +1 -1
- package/src/cli/shared/options.ts +1 -1
- package/src/db/connection.ts +8 -0
- package/src/domain/analysis/dependencies.ts +166 -85
- package/src/domain/analysis/fn-impact.ts +120 -50
- package/src/domain/analysis/module-map.ts +175 -140
- package/src/domain/graph/builder/helpers.ts +85 -76
- package/src/domain/graph/builder/incremental.ts +223 -131
- package/src/domain/graph/builder/pipeline.ts +32 -785
- package/src/domain/graph/builder/stages/build-edges.ts +207 -142
- package/src/domain/graph/builder/stages/build-structure.ts +115 -82
- package/src/domain/graph/builder/stages/detect-changes.ts +107 -64
- package/src/domain/graph/builder/stages/finalize.ts +72 -70
- package/src/domain/graph/builder/stages/insert-nodes.ts +154 -120
- package/src/domain/graph/builder/stages/native-db-lifecycle.ts +74 -0
- package/src/domain/graph/builder/stages/native-orchestrator.ts +942 -0
- package/src/domain/graph/builder/stages/resolve-imports.ts +79 -25
- package/src/domain/graph/cycles.ts +51 -49
- package/src/domain/graph/journal.ts +84 -69
- package/src/domain/graph/watcher.ts +29 -25
- package/src/domain/parser.ts +170 -67
- package/src/domain/search/generator.ts +132 -74
- package/src/domain/search/models.ts +75 -4
- package/src/domain/search/search/hybrid.ts +53 -42
- package/src/domain/search/search/semantic.ts +105 -65
- package/src/domain/wasm-worker-entry.ts +243 -153
- package/src/extractors/c.ts +27 -8
- package/src/extractors/cpp.ts +50 -8
- package/src/extractors/cuda.ts +90 -16
- package/src/extractors/elixir.ts +103 -4
- package/src/extractors/erlang.ts +63 -20
- package/src/extractors/fsharp.ts +104 -0
- package/src/extractors/gleam.ts +40 -39
- package/src/extractors/groovy.ts +45 -1
- package/src/extractors/haskell.ts +45 -4
- package/src/extractors/helpers.ts +205 -1
- package/src/extractors/java.ts +42 -45
- package/src/extractors/javascript.ts +44 -43
- package/src/extractors/julia.ts +191 -77
- package/src/extractors/kotlin.ts +4 -0
- package/src/extractors/objc.ts +171 -47
- package/src/extractors/python.ts +5 -3
- package/src/extractors/r.ts +104 -82
- package/src/extractors/scala.ts +24 -36
- package/src/extractors/solidity.ts +59 -78
- package/src/extractors/verilog.ts +83 -15
- package/src/features/boundaries.ts +64 -46
- package/src/features/cfg.ts +145 -74
- package/src/features/check.ts +60 -43
- package/src/features/cochange.ts +95 -72
- package/src/features/complexity.ts +134 -79
- package/src/features/dataflow.ts +57 -34
- package/src/features/flow.ts +48 -24
- package/src/features/graph-enrichment.ts +105 -70
- package/src/features/owners.ts +186 -146
- package/src/features/sequence.ts +99 -69
- package/src/features/structure-query.ts +94 -79
- package/src/features/structure.ts +56 -56
- package/src/graph/algorithms/leiden/optimiser.ts +142 -87
- package/src/graph/classifiers/roles.ts +64 -54
- package/src/infrastructure/config.ts +1 -1
- package/src/mcp/tool-registry.ts +5 -0
- package/src/mcp/tools/semantic-search.ts +2 -0
- package/src/presentation/cfg.ts +48 -32
- package/src/presentation/flow.ts +100 -52
- package/src/types.ts +16 -1
package/src/extractors/objc.ts
CHANGED
|
@@ -55,6 +55,11 @@ function walkObjCNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
55
55
|
case 'preproc_import':
|
|
56
56
|
handleImport(node, ctx);
|
|
57
57
|
break;
|
|
58
|
+
// tree-sitter-objc v3 emits `module_import` for `@import Foundation;`
|
|
59
|
+
// statements. Older grammar revisions used `import_declaration`, so we
|
|
60
|
+
// accept both for forward/backward compatibility and keep behaviour
|
|
61
|
+
// aligned with `handle_at_import` on the Rust side.
|
|
62
|
+
case 'module_import':
|
|
58
63
|
case 'import_declaration':
|
|
59
64
|
handleAtImport(node, ctx);
|
|
60
65
|
break;
|
|
@@ -87,29 +92,46 @@ function handleClassInterface(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
87
92
|
const nameNode = node.childForFieldName('name') || findObjCDeclName(node);
|
|
88
93
|
if (!nameNode) return;
|
|
89
94
|
const name = nameNode.text;
|
|
95
|
+
// Categories declared as `@interface Foo (Cat)` arrive as `class_interface`
|
|
96
|
+
// with a `category` field (rather than the `category_interface` node type).
|
|
97
|
+
// Qualify the display name with `(Cat)` so symbols stay grouped per category
|
|
98
|
+
// and match the Rust extractor.
|
|
99
|
+
const category = node.childForFieldName('category');
|
|
100
|
+
const displayName = category ? `${name}(${category.text})` : name;
|
|
90
101
|
|
|
91
102
|
const members = collectClassMembers(node);
|
|
92
103
|
ctx.definitions.push({
|
|
93
|
-
name,
|
|
104
|
+
name: displayName,
|
|
94
105
|
kind: 'class',
|
|
95
106
|
line: node.startPosition.row + 1,
|
|
96
107
|
endLine: nodeEndLine(node),
|
|
97
108
|
children: members.length > 0 ? members : undefined,
|
|
98
109
|
});
|
|
99
110
|
|
|
100
|
-
// Superclass
|
|
111
|
+
// Superclass — keyed on the bare class name (categories don't have a superclass).
|
|
101
112
|
const superclass = node.childForFieldName('superclass');
|
|
102
113
|
if (superclass) {
|
|
103
114
|
ctx.classes.push({ name, extends: superclass.text, line: node.startPosition.row + 1 });
|
|
104
115
|
}
|
|
105
116
|
|
|
106
|
-
//
|
|
107
|
-
|
|
117
|
+
// Adopted protocols. tree-sitter-objc v3 wraps the adopted-protocol list in
|
|
118
|
+
// `parameterized_arguments` (not `protocol_qualifiers`, which was the v2
|
|
119
|
+
// grammar shape). Each child is wrapped in `type_name > type_identifier`;
|
|
120
|
+
// fall back to a bare `identifier`/`type_identifier` for older grammars.
|
|
121
|
+
const protocols = findChild(node, 'parameterized_arguments');
|
|
108
122
|
if (protocols) {
|
|
109
123
|
for (let i = 0; i < protocols.childCount; i++) {
|
|
110
124
|
const proto = protocols.child(i);
|
|
111
|
-
if (proto
|
|
112
|
-
|
|
125
|
+
if (!proto) continue;
|
|
126
|
+
let protoName: string | null = null;
|
|
127
|
+
if (proto.type === 'type_name') {
|
|
128
|
+
const inner = findChild(proto, 'type_identifier') || findChild(proto, 'identifier');
|
|
129
|
+
if (inner) protoName = inner.text;
|
|
130
|
+
} else if (proto.type === 'identifier' || proto.type === 'type_identifier') {
|
|
131
|
+
protoName = proto.text;
|
|
132
|
+
}
|
|
133
|
+
if (protoName) {
|
|
134
|
+
ctx.classes.push({ name, implements: protoName, line: node.startPosition.row + 1 });
|
|
113
135
|
}
|
|
114
136
|
}
|
|
115
137
|
}
|
|
@@ -118,9 +140,14 @@ function handleClassInterface(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
118
140
|
function handleClassImplementation(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
119
141
|
const nameNode = node.childForFieldName('name') || findObjCDeclName(node);
|
|
120
142
|
if (!nameNode) return;
|
|
143
|
+
// Categories declared as `@implementation Foo (Cat)` arrive as
|
|
144
|
+
// `class_implementation` with a `category` field. Mirror the Rust extractor
|
|
145
|
+
// and qualify the display name with `(Cat)`.
|
|
146
|
+
const category = node.childForFieldName('category');
|
|
147
|
+
const displayName = category ? `${nameNode.text}(${category.text})` : nameNode.text;
|
|
121
148
|
|
|
122
149
|
ctx.definitions.push({
|
|
123
|
-
name:
|
|
150
|
+
name: displayName,
|
|
124
151
|
kind: 'class',
|
|
125
152
|
line: node.startPosition.row + 1,
|
|
126
153
|
endLine: nodeEndLine(node),
|
|
@@ -285,7 +312,20 @@ function handleTypedef(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
285
312
|
// ── Call handlers ─────────────────────────────────────────────────────────
|
|
286
313
|
|
|
287
314
|
function handleCCallExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
288
|
-
|
|
315
|
+
// tree-sitter-objc does not expose a `function` field on `call_expression`,
|
|
316
|
+
// so the named-field lookup almost always misses. Fall back to the first
|
|
317
|
+
// `identifier` / `field_expression` child to mirror `handle_c_call_expr` in
|
|
318
|
+
// `crates/codegraph-core/src/extractors/objc.rs` and keep engine parity.
|
|
319
|
+
let funcNode = node.childForFieldName('function');
|
|
320
|
+
if (!funcNode) {
|
|
321
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
322
|
+
const child = node.child(i);
|
|
323
|
+
if (child && (child.type === 'identifier' || child.type === 'field_expression')) {
|
|
324
|
+
funcNode = child;
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
}
|
|
289
329
|
if (!funcNode) return;
|
|
290
330
|
const call: Call = { name: '', line: node.startPosition.row + 1 };
|
|
291
331
|
if (funcNode.type === 'field_expression') {
|
|
@@ -302,10 +342,33 @@ function handleCCallExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
302
342
|
function handleMessageExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
303
343
|
// [receiver selector:arg ...]
|
|
304
344
|
const receiver = node.childForFieldName('receiver');
|
|
305
|
-
const selector = node.childForFieldName('selector');
|
|
306
|
-
if (!selector) return;
|
|
307
345
|
|
|
308
|
-
|
|
346
|
+
// tree-sitter-objc v3 does not expose a `selector` field on
|
|
347
|
+
// `message_expression`; instead every keyword identifier has the `method`
|
|
348
|
+
// field. Assemble the selector by joining `method` children with `:`,
|
|
349
|
+
// appending a trailing `:` when the message has at least one colon
|
|
350
|
+
// (keyword form). Mirrors `build_message_selector` in
|
|
351
|
+
// `crates/codegraph-core/src/extractors/objc.rs`.
|
|
352
|
+
const parts: string[] = [];
|
|
353
|
+
let hasColon = false;
|
|
354
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
355
|
+
const child = node.child(i);
|
|
356
|
+
if (!child) continue;
|
|
357
|
+
const fieldName = node.fieldNameForChild(i);
|
|
358
|
+
if (fieldName === 'method') parts.push(child.text);
|
|
359
|
+
if (child.type === ':') hasColon = true;
|
|
360
|
+
}
|
|
361
|
+
let name: string;
|
|
362
|
+
if (parts.length > 0) {
|
|
363
|
+
name = hasColon ? `${parts.join(':')}:` : parts.join(':');
|
|
364
|
+
} else {
|
|
365
|
+
// Fallback: some grammar revisions expose a `selector` field.
|
|
366
|
+
const selector = node.childForFieldName('selector');
|
|
367
|
+
if (!selector) return;
|
|
368
|
+
name = selector.text;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const call: Call = { name, line: node.startPosition.row + 1 };
|
|
309
372
|
if (receiver) call.receiver = receiver.text;
|
|
310
373
|
ctx.calls.push(call);
|
|
311
374
|
}
|
|
@@ -313,29 +376,25 @@ function handleMessageExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
313
376
|
// ── Helpers ───────────────────────────────────────────────────────────────
|
|
314
377
|
|
|
315
378
|
function buildSelector(methodNode: TreeSitterNode): string | null {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
//
|
|
379
|
+
// tree-sitter-objc v3 does not expose a `selector` field; the selector is
|
|
380
|
+
// assembled from the leading `identifier` keywords. Multi-keyword forms
|
|
381
|
+
// look like `setName:(...)x age:(...)y` and appear as flat
|
|
382
|
+
// `identifier` + `method_parameter` children directly under the method
|
|
383
|
+
// node (not wrapped in `keyword_selector`). Mirrors `build_selector` in
|
|
384
|
+
// `crates/codegraph-core/src/extractors/objc.rs`.
|
|
320
385
|
const parts: string[] = [];
|
|
386
|
+
let hasParams = false;
|
|
321
387
|
for (let i = 0; i < methodNode.childCount; i++) {
|
|
322
388
|
const child = methodNode.child(i);
|
|
323
389
|
if (!child) continue;
|
|
324
|
-
if (child.type === '
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
const kwName = kw.childForFieldName('keyword');
|
|
329
|
-
if (kwName) parts.push(kwName.text);
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
if (child.type === 'identifier' && i === 1) {
|
|
334
|
-
// Simple unary selector
|
|
335
|
-
return child.text;
|
|
390
|
+
if (child.type === 'identifier') {
|
|
391
|
+
parts.push(child.text);
|
|
392
|
+
} else if (child.type === 'method_parameter') {
|
|
393
|
+
hasParams = true;
|
|
336
394
|
}
|
|
337
395
|
}
|
|
338
|
-
|
|
396
|
+
if (parts.length === 0) return null;
|
|
397
|
+
return hasParams ? `${parts.join(':')}:` : parts.join(':');
|
|
339
398
|
}
|
|
340
399
|
|
|
341
400
|
function findObjCParentClass(node: TreeSitterNode): string | null {
|
|
@@ -349,7 +408,14 @@ function findObjCParentClass(node: TreeSitterNode): string | null {
|
|
|
349
408
|
current.type === 'category_implementation'
|
|
350
409
|
) {
|
|
351
410
|
const nameNode = current.childForFieldName('name') || findObjCDeclName(current);
|
|
352
|
-
|
|
411
|
+
if (!nameNode) return null;
|
|
412
|
+
// Categories: include `(Cat)` so methods are grouped per category.
|
|
413
|
+
// Two categories on the same class can declare same-named methods, so
|
|
414
|
+
// qualifying the parent name keeps the symbols disambiguated. Mirrors
|
|
415
|
+
// `find_objc_parent_class` in `crates/codegraph-core/src/extractors/objc.rs`.
|
|
416
|
+
const category = current.childForFieldName('category');
|
|
417
|
+
if (category) return `${nameNode.text}(${category.text})`;
|
|
418
|
+
return nameNode.text;
|
|
353
419
|
}
|
|
354
420
|
current = current.parent;
|
|
355
421
|
}
|
|
@@ -381,32 +447,65 @@ function collectClassMembers(classNode: TreeSitterNode): SubDeclaration[] {
|
|
|
381
447
|
}
|
|
382
448
|
}
|
|
383
449
|
if (child.type === 'property_declaration') {
|
|
384
|
-
const propName = child
|
|
450
|
+
const propName = extractPropertyName(child);
|
|
385
451
|
if (propName) {
|
|
386
|
-
members.push({ name: propName
|
|
452
|
+
members.push({ name: propName, kind: 'property', line: child.startPosition.row + 1 });
|
|
387
453
|
}
|
|
388
454
|
}
|
|
389
455
|
}
|
|
390
456
|
return members;
|
|
391
457
|
}
|
|
392
458
|
|
|
459
|
+
/**
|
|
460
|
+
* Extract the property name from `@property (...) Type *foo;`. The v3 grammar
|
|
461
|
+
* does not expose `name` as a named field on `property_declaration`; instead
|
|
462
|
+
* the identifier nests under `struct_declaration > struct_declarator >
|
|
463
|
+
* [pointer_declarator >] identifier`. Mirrors `extract_property_name` in
|
|
464
|
+
* `crates/codegraph-core/src/extractors/objc.rs`.
|
|
465
|
+
*/
|
|
466
|
+
function extractPropertyName(propNode: TreeSitterNode): string | null {
|
|
467
|
+
const structDecl = findChild(propNode, 'struct_declaration');
|
|
468
|
+
if (!structDecl) return null;
|
|
469
|
+
for (let i = 0; i < structDecl.childCount; i++) {
|
|
470
|
+
const child = structDecl.child(i);
|
|
471
|
+
if (!child || child.type !== 'struct_declarator') continue;
|
|
472
|
+
const id = findIdentifierDeep(child);
|
|
473
|
+
if (id) return id.text;
|
|
474
|
+
}
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function findIdentifierDeep(node: TreeSitterNode): TreeSitterNode | null {
|
|
479
|
+
if (node.type === 'identifier') return node;
|
|
480
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
481
|
+
const child = node.child(i);
|
|
482
|
+
if (!child) continue;
|
|
483
|
+
const found = findIdentifierDeep(child);
|
|
484
|
+
if (found) return found;
|
|
485
|
+
}
|
|
486
|
+
return null;
|
|
487
|
+
}
|
|
488
|
+
|
|
393
489
|
function extractMethodParams(methodNode: TreeSitterNode): SubDeclaration[] {
|
|
490
|
+
// The v3 grammar emits flat `method_parameter` children under the method
|
|
491
|
+
// node; the parameter name is the last `identifier` inside each
|
|
492
|
+
// `method_parameter`. Mirrors `extract_method_params` in
|
|
493
|
+
// `crates/codegraph-core/src/extractors/objc.rs`.
|
|
394
494
|
const params: SubDeclaration[] = [];
|
|
395
495
|
for (let i = 0; i < methodNode.childCount; i++) {
|
|
396
496
|
const child = methodNode.child(i);
|
|
397
|
-
if (!child || child.type !== '
|
|
497
|
+
if (!child || child.type !== 'method_parameter') continue;
|
|
498
|
+
let nameNode: TreeSitterNode | null = null;
|
|
398
499
|
for (let j = 0; j < child.childCount; j++) {
|
|
399
|
-
const
|
|
400
|
-
if (
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
}
|
|
500
|
+
const inner = child.child(j);
|
|
501
|
+
if (inner && inner.type === 'identifier') nameNode = inner;
|
|
502
|
+
}
|
|
503
|
+
if (nameNode) {
|
|
504
|
+
params.push({
|
|
505
|
+
name: nameNode.text,
|
|
506
|
+
kind: 'parameter',
|
|
507
|
+
line: nameNode.startPosition.row + 1,
|
|
508
|
+
});
|
|
410
509
|
}
|
|
411
510
|
}
|
|
412
511
|
return params;
|
|
@@ -420,12 +519,37 @@ function extractCParams(paramListNode: TreeSitterNode | null): SubDeclaration[]
|
|
|
420
519
|
if (!param || param.type !== 'parameter_declaration') continue;
|
|
421
520
|
const nameNode = param.childForFieldName('declarator');
|
|
422
521
|
if (nameNode) {
|
|
423
|
-
const name =
|
|
424
|
-
nameNode.type === 'identifier'
|
|
425
|
-
? nameNode.text
|
|
426
|
-
: (findChild(nameNode, 'identifier')?.text ?? nameNode.text);
|
|
522
|
+
const name = unwrapObjCDeclaratorName(nameNode);
|
|
427
523
|
params.push({ name, kind: 'parameter', line: param.startPosition.row + 1 });
|
|
428
524
|
}
|
|
429
525
|
}
|
|
430
526
|
return params;
|
|
431
527
|
}
|
|
528
|
+
|
|
529
|
+
const OBJC_DECLARATOR_WRAPPERS = new Set([
|
|
530
|
+
'pointer_declarator',
|
|
531
|
+
'reference_declarator',
|
|
532
|
+
'array_declarator',
|
|
533
|
+
'parenthesized_declarator',
|
|
534
|
+
'function_declarator',
|
|
535
|
+
]);
|
|
536
|
+
|
|
537
|
+
/**
|
|
538
|
+
* Drill through pointer/array/reference/parenthesized/function declarator
|
|
539
|
+
* wrappers to recover the bare parameter identifier. Without this the WASM
|
|
540
|
+
* extractor emitted raw declarator text (e.g. `*argv[]` or `callback(int x)`)
|
|
541
|
+
* while native unwrapped to `argv` / `callback`, producing cross-engine
|
|
542
|
+
* `contains` divergence on C-style parameters such as
|
|
543
|
+
* `int main(int argc, const char *argv[])` and function-type parameters such
|
|
544
|
+
* as `void process(int callback(int))`.
|
|
545
|
+
*/
|
|
546
|
+
function unwrapObjCDeclaratorName(node: TreeSitterNode): string {
|
|
547
|
+
let current: TreeSitterNode | null = node;
|
|
548
|
+
while (current && OBJC_DECLARATOR_WRAPPERS.has(current.type)) {
|
|
549
|
+
current = current.childForFieldName('declarator');
|
|
550
|
+
}
|
|
551
|
+
if (current?.type === 'identifier' || current?.type === 'field_identifier') {
|
|
552
|
+
return current.text;
|
|
553
|
+
}
|
|
554
|
+
return current?.text ?? node.text;
|
|
555
|
+
}
|
package/src/extractors/python.ts
CHANGED
|
@@ -122,7 +122,7 @@ function handlePyFunctionDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
122
122
|
const parentClass = findPythonParentClass(node);
|
|
123
123
|
const fullName = parentClass ? `${parentClass}.${nameNode.text}` : nameNode.text;
|
|
124
124
|
const kind = parentClass ? 'method' : 'function';
|
|
125
|
-
const fnChildren = extractPythonParameters(node);
|
|
125
|
+
const fnChildren = extractPythonParameters(node, parentClass !== null);
|
|
126
126
|
ctx.definitions.push({
|
|
127
127
|
name: fullName,
|
|
128
128
|
kind,
|
|
@@ -238,7 +238,7 @@ function handlePyImportFrom(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
238
238
|
|
|
239
239
|
// ── Python-specific helpers ─────────────────────────────────────────────────
|
|
240
240
|
|
|
241
|
-
function extractPythonParameters(fnNode: TreeSitterNode): SubDeclaration[] {
|
|
241
|
+
function extractPythonParameters(fnNode: TreeSitterNode, isMethod: boolean): SubDeclaration[] {
|
|
242
242
|
const params: SubDeclaration[] = [];
|
|
243
243
|
const paramsNode = fnNode.childForFieldName('parameters') || findChild(fnNode, 'parameters');
|
|
244
244
|
if (!paramsNode) return params;
|
|
@@ -246,7 +246,9 @@ function extractPythonParameters(fnNode: TreeSitterNode): SubDeclaration[] {
|
|
|
246
246
|
const child = paramsNode.child(i);
|
|
247
247
|
if (!child) continue;
|
|
248
248
|
const param = extractSinglePyParam(child);
|
|
249
|
-
if (param)
|
|
249
|
+
if (!param) continue;
|
|
250
|
+
if (isMethod && (param.name === 'self' || param.name === 'cls')) continue;
|
|
251
|
+
params.push(param);
|
|
250
252
|
}
|
|
251
253
|
return params;
|
|
252
254
|
}
|
package/src/extractors/r.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import type { ExtractorOutput, SubDeclaration, TreeSitterNode, TreeSitterTree } from '../types.js';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
findChild,
|
|
4
|
+
findFirstChildOfTypes,
|
|
5
|
+
nodeEndLine,
|
|
6
|
+
nodeStartLine,
|
|
7
|
+
pushCall,
|
|
8
|
+
pushImport,
|
|
9
|
+
stripQuotes,
|
|
10
|
+
} from './helpers.js';
|
|
3
11
|
|
|
4
12
|
/**
|
|
5
13
|
* Extract symbols from R files.
|
|
@@ -58,7 +66,7 @@ function handleBinaryOp(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
58
66
|
ctx.definitions.push({
|
|
59
67
|
name: lhs.text,
|
|
60
68
|
kind: 'function',
|
|
61
|
-
line: node
|
|
69
|
+
line: nodeStartLine(node),
|
|
62
70
|
endLine: nodeEndLine(node),
|
|
63
71
|
children: params.length > 0 ? params : undefined,
|
|
64
72
|
});
|
|
@@ -68,7 +76,7 @@ function handleBinaryOp(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
68
76
|
ctx.definitions.push({
|
|
69
77
|
name: lhs.text,
|
|
70
78
|
kind: 'variable',
|
|
71
|
-
line: node
|
|
79
|
+
line: nodeStartLine(node),
|
|
72
80
|
endLine: nodeEndLine(node),
|
|
73
81
|
});
|
|
74
82
|
}
|
|
@@ -87,14 +95,14 @@ function extractRParams(funcDef: TreeSitterNode): SubDeclaration[] {
|
|
|
87
95
|
// parameter node has name and possibly default value
|
|
88
96
|
const nameNode = child.childForFieldName('name') || findChild(child, 'identifier');
|
|
89
97
|
if (nameNode) {
|
|
90
|
-
params.push({ name: nameNode.text, kind: 'parameter', line: child
|
|
98
|
+
params.push({ name: nameNode.text, kind: 'parameter', line: nodeStartLine(child) });
|
|
91
99
|
} else if (child.text && child.text !== ',' && child.text !== '(' && child.text !== ')') {
|
|
92
100
|
// Some grammars have the param as plain text
|
|
93
|
-
params.push({ name: child.text, kind: 'parameter', line: child
|
|
101
|
+
params.push({ name: child.text, kind: 'parameter', line: nodeStartLine(child) });
|
|
94
102
|
}
|
|
95
103
|
}
|
|
96
104
|
if (child.type === 'identifier') {
|
|
97
|
-
params.push({ name: child.text, kind: 'parameter', line: child
|
|
105
|
+
params.push({ name: child.text, kind: 'parameter', line: nodeStartLine(child) });
|
|
98
106
|
}
|
|
99
107
|
}
|
|
100
108
|
return params;
|
|
@@ -125,29 +133,35 @@ function handleCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
125
133
|
return;
|
|
126
134
|
}
|
|
127
135
|
|
|
128
|
-
if (funcName === 'setGeneric'
|
|
136
|
+
if (funcName === 'setGeneric') {
|
|
129
137
|
handleSetGeneric(node, ctx);
|
|
130
138
|
return;
|
|
131
139
|
}
|
|
132
140
|
|
|
141
|
+
if (funcName === 'setMethod') {
|
|
142
|
+
handleSetMethod(node, ctx);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
133
146
|
// Regular call
|
|
134
147
|
if (funcNode.type === 'identifier') {
|
|
135
|
-
ctx
|
|
148
|
+
pushCall(ctx, node, funcName);
|
|
136
149
|
} else if (funcNode.type === 'namespace_operator') {
|
|
137
150
|
// pkg::func
|
|
138
151
|
const parts = funcName.split('::');
|
|
139
152
|
if (parts.length >= 2) {
|
|
140
|
-
ctx.
|
|
141
|
-
name: parts[parts.length - 1]!,
|
|
153
|
+
pushCall(ctx, node, parts[parts.length - 1]!, {
|
|
142
154
|
receiver: parts.slice(0, -1).join('::'),
|
|
143
|
-
line: node.startPosition.row + 1,
|
|
144
155
|
});
|
|
145
156
|
}
|
|
146
157
|
}
|
|
147
158
|
}
|
|
148
159
|
|
|
149
160
|
function handleLibraryCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
150
|
-
// Find the package name in arguments
|
|
161
|
+
// Find the package name in arguments. For named arguments like
|
|
162
|
+
// `library(package = dplyr)`, prefer the field-named `value` child of the
|
|
163
|
+
// `argument` node so we extract `dplyr` (the value), not `package` (the
|
|
164
|
+
// parameter name). Keeps native (Rust) and WASM extractors in parity.
|
|
151
165
|
for (let i = 0; i < node.childCount; i++) {
|
|
152
166
|
const child = node.child(i);
|
|
153
167
|
if (!child) continue;
|
|
@@ -156,32 +170,38 @@ function handleLibraryCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
156
170
|
const arg = child.child(j);
|
|
157
171
|
if (!arg) continue;
|
|
158
172
|
if (arg.type === 'identifier') {
|
|
159
|
-
ctx.
|
|
160
|
-
source: arg.text,
|
|
161
|
-
names: [arg.text],
|
|
162
|
-
line: node.startPosition.row + 1,
|
|
163
|
-
});
|
|
173
|
+
pushImport(ctx, node, arg.text, [arg.text]);
|
|
164
174
|
return;
|
|
165
175
|
}
|
|
166
176
|
if (arg.type === 'string' || arg.type === 'string_content') {
|
|
167
|
-
const text = arg.text
|
|
168
|
-
ctx
|
|
169
|
-
source: text,
|
|
170
|
-
names: [text],
|
|
171
|
-
line: node.startPosition.row + 1,
|
|
172
|
-
});
|
|
177
|
+
const text = stripQuotes(arg.text);
|
|
178
|
+
pushImport(ctx, node, text, [text]);
|
|
173
179
|
return;
|
|
174
180
|
}
|
|
175
181
|
// Argument might be wrapped
|
|
176
182
|
if (arg.type === 'argument') {
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
183
|
+
// Prefer the `value` field (correct for named arguments).
|
|
184
|
+
const valueNode = arg.childForFieldName('value');
|
|
185
|
+
let pick: TreeSitterNode | null = null;
|
|
186
|
+
if (valueNode && (valueNode.type === 'string' || valueNode.type === 'identifier')) {
|
|
187
|
+
pick = valueNode;
|
|
188
|
+
} else {
|
|
189
|
+
// Fallback: skip the parameter-name child if the grammar exposes
|
|
190
|
+
// it via the `name` field, then pick the first string/identifier.
|
|
191
|
+
const nameNode = arg.childForFieldName('name');
|
|
192
|
+
for (let k = 0; k < arg.childCount; k++) {
|
|
193
|
+
const inner = arg.child(k);
|
|
194
|
+
if (!inner) continue;
|
|
195
|
+
if (nameNode && inner.id === nameNode.id) continue;
|
|
196
|
+
if (inner.type === 'string' || inner.type === 'identifier') {
|
|
197
|
+
pick = inner;
|
|
198
|
+
break;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
if (pick) {
|
|
203
|
+
const text = stripQuotes(pick.text);
|
|
204
|
+
pushImport(ctx, node, text, [text]);
|
|
185
205
|
return;
|
|
186
206
|
}
|
|
187
207
|
}
|
|
@@ -191,63 +211,65 @@ function handleLibraryCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
191
211
|
}
|
|
192
212
|
|
|
193
213
|
function handleSourceCall(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const arg = child.child(j);
|
|
199
|
-
if (!arg) continue;
|
|
200
|
-
if (arg.type === 'string') {
|
|
201
|
-
const text = arg.text.replace(/^["']|["']$/g, '');
|
|
202
|
-
ctx.imports.push({
|
|
203
|
-
source: text,
|
|
204
|
-
names: ['source'],
|
|
205
|
-
line: node.startPosition.row + 1,
|
|
206
|
-
});
|
|
207
|
-
return;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
214
|
+
// source() only accepts string literals — `source(varname)` is not an import.
|
|
215
|
+
const path = firstStringArgument(node);
|
|
216
|
+
if (path === null) return;
|
|
217
|
+
pushImport(ctx, node, path, ['source']);
|
|
211
218
|
}
|
|
212
219
|
|
|
213
220
|
function handleSetClass(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
ctx.definitions.push({
|
|
223
|
-
name,
|
|
224
|
-
kind: 'class',
|
|
225
|
-
line: node.startPosition.row + 1,
|
|
226
|
-
endLine: nodeEndLine(node),
|
|
227
|
-
});
|
|
228
|
-
return;
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
221
|
+
const name = firstStringArgument(node);
|
|
222
|
+
if (name === null) return;
|
|
223
|
+
ctx.definitions.push({
|
|
224
|
+
name,
|
|
225
|
+
kind: 'class',
|
|
226
|
+
line: nodeStartLine(node),
|
|
227
|
+
endLine: nodeEndLine(node),
|
|
228
|
+
});
|
|
232
229
|
}
|
|
233
230
|
|
|
234
231
|
function handleSetGeneric(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
232
|
+
const name = firstStringArgument(node);
|
|
233
|
+
if (name === null) return;
|
|
234
|
+
ctx.definitions.push({
|
|
235
|
+
name,
|
|
236
|
+
kind: 'function',
|
|
237
|
+
line: nodeStartLine(node),
|
|
238
|
+
endLine: nodeEndLine(node),
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// setMethod("greet", "Person", function(x) ...) registers an implementation of
|
|
243
|
+
// the generic `greet` — it is not a new top-level definition. Emitting a
|
|
244
|
+
// definition here produced two `function` nodes with the same name (one from
|
|
245
|
+
// setGeneric, one from setMethod) and broke resolution. Emit a call edge to
|
|
246
|
+
// the generic instead; the method body's calls are still picked up by the
|
|
247
|
+
// recursive walk of the anonymous function argument.
|
|
248
|
+
function handleSetMethod(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
249
|
+
const name = firstStringArgument(node);
|
|
250
|
+
if (name === null) return;
|
|
251
|
+
pushCall(ctx, node, name);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// tree-sitter-r wraps each positional argument in an `argument` node that
|
|
255
|
+
// contains the actual `string` (or `identifier`) child, so the inner string
|
|
256
|
+
// must be unwrapped — checking `child.type === 'string'` directly misses it.
|
|
257
|
+
// Mirrors `first_argument_value` in the Rust extractor for parity.
|
|
258
|
+
function firstStringArgument(node: TreeSitterNode): string | null {
|
|
259
|
+
const args = findFirstChildOfTypes(node, ['arguments']);
|
|
260
|
+
if (!args) return null;
|
|
261
|
+
for (let j = 0; j < args.childCount; j++) {
|
|
262
|
+
const arg = args.child(j);
|
|
263
|
+
if (!arg) continue;
|
|
264
|
+
if (arg.type === 'string') {
|
|
265
|
+
return stripQuotes(arg.text);
|
|
266
|
+
}
|
|
267
|
+
if (arg.type === 'argument') {
|
|
268
|
+
const valueNode = arg.childForFieldName('value');
|
|
269
|
+
if (valueNode && valueNode.type === 'string') return stripQuotes(valueNode.text);
|
|
270
|
+
const innerStr = findFirstChildOfTypes(arg, ['string']);
|
|
271
|
+
if (innerStr) return stripQuotes(innerStr.text);
|
|
251
272
|
}
|
|
252
273
|
}
|
|
274
|
+
return null;
|
|
253
275
|
}
|