@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
|
@@ -306,11 +306,18 @@ const LANGUAGE_REGISTRY: LanguageRegistryEntry[] = [
|
|
|
306
306
|
},
|
|
307
307
|
{
|
|
308
308
|
id: 'fsharp',
|
|
309
|
-
extensions: ['.fs', '.fsx'
|
|
309
|
+
extensions: ['.fs', '.fsx'],
|
|
310
310
|
grammarFile: 'tree-sitter-fsharp.wasm',
|
|
311
311
|
extractor: extractFSharpSymbols,
|
|
312
312
|
required: false,
|
|
313
313
|
},
|
|
314
|
+
{
|
|
315
|
+
id: 'fsharp-signature',
|
|
316
|
+
extensions: ['.fsi'],
|
|
317
|
+
grammarFile: 'tree-sitter-fsharp_signature.wasm',
|
|
318
|
+
extractor: extractFSharpSymbols,
|
|
319
|
+
required: false,
|
|
320
|
+
},
|
|
314
321
|
{
|
|
315
322
|
id: 'gleam',
|
|
316
323
|
extensions: ['.gleam'],
|
|
@@ -566,6 +573,90 @@ interface SetupResult {
|
|
|
566
573
|
dataflowVisitor: Visitor | null;
|
|
567
574
|
}
|
|
568
575
|
|
|
576
|
+
/**
|
|
577
|
+
* Build the AST-store visitor for `langId`. Returns `null` when AST is
|
|
578
|
+
* disabled or the language has no AST type map. db-free — passes an empty
|
|
579
|
+
* nodeIdMap. The main thread re-resolves parent node IDs in
|
|
580
|
+
* `features/ast.ts::collectFileAstRows`.
|
|
581
|
+
*/
|
|
582
|
+
function buildAstVisitor(
|
|
583
|
+
langId: string,
|
|
584
|
+
defs: ExtractorOutput['definitions'],
|
|
585
|
+
relPath: string,
|
|
586
|
+
enabled: boolean,
|
|
587
|
+
): Visitor | null {
|
|
588
|
+
if (!enabled) return null;
|
|
589
|
+
const astTypeMap = AST_TYPE_MAPS.get(langId);
|
|
590
|
+
if (!astTypeMap) return null;
|
|
591
|
+
const stringConfig = AST_STRING_CONFIGS.get(langId);
|
|
592
|
+
return createAstStoreVisitor(
|
|
593
|
+
astTypeMap,
|
|
594
|
+
defs,
|
|
595
|
+
relPath,
|
|
596
|
+
new Map<string, number>(),
|
|
597
|
+
stringConfig,
|
|
598
|
+
astStopRecurseKinds(langId),
|
|
599
|
+
);
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
/**
|
|
603
|
+
* Build the complexity visitor when enabled, the language has complexity
|
|
604
|
+
* rules, and at least one definition still lacks a `complexity` payload.
|
|
605
|
+
* Side-effect: extends `walkerOpts` with nesting-node types and a
|
|
606
|
+
* `getFunctionName` resolver suitable for this language.
|
|
607
|
+
*/
|
|
608
|
+
function buildComplexityVisitor(
|
|
609
|
+
langId: string,
|
|
610
|
+
defs: ExtractorOutput['definitions'],
|
|
611
|
+
enabled: boolean,
|
|
612
|
+
walkerOpts: WalkOptions,
|
|
613
|
+
): Visitor | null {
|
|
614
|
+
if (!enabled) return null;
|
|
615
|
+
const cRules = COMPLEXITY_RULES.get(langId);
|
|
616
|
+
if (!cRules || !defs.some((d) => hasFuncBody(d) && !d.complexity)) return null;
|
|
617
|
+
|
|
618
|
+
const hRules = HALSTEAD_RULES.get(langId);
|
|
619
|
+
const visitor = createComplexityVisitor(cRules, hRules, { fileLevelWalk: true, langId });
|
|
620
|
+
for (const t of cRules.nestingNodes) walkerOpts.nestingNodeTypes?.add(t);
|
|
621
|
+
const dfRules = DATAFLOW_RULES.get(langId);
|
|
622
|
+
walkerOpts.getFunctionName = (node: TreeSitterNode): string | null => {
|
|
623
|
+
const nameNode = node.childForFieldName('name');
|
|
624
|
+
if (nameNode) return nameNode.text;
|
|
625
|
+
// dfRules shape varies per language; visitor-utils accepts any shape
|
|
626
|
+
if (dfRules) return getFuncName(node, dfRules as any);
|
|
627
|
+
return null;
|
|
628
|
+
};
|
|
629
|
+
return visitor;
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/** Build the CFG visitor when enabled and at least one definition still lacks blocks. */
|
|
633
|
+
function buildCfgVisitor(
|
|
634
|
+
langId: string,
|
|
635
|
+
defs: ExtractorOutput['definitions'],
|
|
636
|
+
enabled: boolean,
|
|
637
|
+
): Visitor | null {
|
|
638
|
+
if (!enabled) return null;
|
|
639
|
+
const cfgRulesForLang = CFG_RULES.get(langId);
|
|
640
|
+
if (!cfgRulesForLang) return null;
|
|
641
|
+
const needsCfg = defs.some(
|
|
642
|
+
(d) => hasFuncBody(d) && d.cfg !== null && !Array.isArray(d.cfg?.blocks),
|
|
643
|
+
);
|
|
644
|
+
if (!needsCfg) return null;
|
|
645
|
+
return createCfgVisitor(cfgRulesForLang);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
/** Build the dataflow visitor when enabled and `symbols.dataflow` is not yet populated. */
|
|
649
|
+
function buildDataflowVisitor(
|
|
650
|
+
langId: string,
|
|
651
|
+
symbols: ExtractorOutput,
|
|
652
|
+
enabled: boolean,
|
|
653
|
+
): Visitor | null {
|
|
654
|
+
if (!enabled) return null;
|
|
655
|
+
const dfRules = DATAFLOW_RULES.get(langId);
|
|
656
|
+
if (!dfRules || symbols.dataflow) return null;
|
|
657
|
+
return createDataflowVisitor(dfRules);
|
|
658
|
+
}
|
|
659
|
+
|
|
569
660
|
function setupVisitorsLocal(
|
|
570
661
|
symbols: ExtractorOutput,
|
|
571
662
|
relPath: string,
|
|
@@ -573,82 +664,161 @@ function setupVisitorsLocal(
|
|
|
573
664
|
opts: WorkerParseRequest['opts'],
|
|
574
665
|
): SetupResult {
|
|
575
666
|
const defs = symbols.definitions || [];
|
|
576
|
-
const visitors: Visitor[] = [];
|
|
577
667
|
const walkerOpts: WalkOptions = {
|
|
578
668
|
functionNodeTypes: new Set<string>(),
|
|
579
669
|
nestingNodeTypes: new Set<string>(),
|
|
580
670
|
getFunctionName: (_node: TreeSitterNode) => null,
|
|
581
671
|
};
|
|
582
672
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
const astTypeMap = AST_TYPE_MAPS.get(langId);
|
|
588
|
-
if (astTypeMap) {
|
|
589
|
-
const stringConfig = AST_STRING_CONFIGS.get(langId);
|
|
590
|
-
astVisitor = createAstStoreVisitor(
|
|
591
|
-
astTypeMap,
|
|
592
|
-
defs,
|
|
593
|
-
relPath,
|
|
594
|
-
new Map<string, number>(),
|
|
595
|
-
stringConfig,
|
|
596
|
-
astStopRecurseKinds(langId),
|
|
597
|
-
);
|
|
598
|
-
visitors.push(astVisitor);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
673
|
+
const astVisitor = buildAstVisitor(langId, defs, relPath, !!opts.ast);
|
|
674
|
+
const complexityVisitor = buildComplexityVisitor(langId, defs, !!opts.complexity, walkerOpts);
|
|
675
|
+
const cfgVisitor = buildCfgVisitor(langId, defs, !!opts.cfg);
|
|
676
|
+
const dataflowVisitor = buildDataflowVisitor(langId, symbols, !!opts.dataflow);
|
|
601
677
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if (
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
const hRules = HALSTEAD_RULES.get(langId);
|
|
608
|
-
complexityVisitor = createComplexityVisitor(cRules, hRules, {
|
|
609
|
-
fileLevelWalk: true,
|
|
610
|
-
langId,
|
|
611
|
-
});
|
|
612
|
-
for (const t of cRules.nestingNodes) walkerOpts.nestingNodeTypes?.add(t);
|
|
613
|
-
const dfRules = DATAFLOW_RULES.get(langId);
|
|
614
|
-
walkerOpts.getFunctionName = (node: TreeSitterNode): string | null => {
|
|
615
|
-
const nameNode = node.childForFieldName('name');
|
|
616
|
-
if (nameNode) return nameNode.text;
|
|
617
|
-
// dfRules shape varies per language; visitor-utils accepts any shape
|
|
618
|
-
if (dfRules) return getFuncName(node, dfRules as any);
|
|
619
|
-
return null;
|
|
620
|
-
};
|
|
621
|
-
visitors.push(complexityVisitor);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
678
|
+
const visitors: Visitor[] = [];
|
|
679
|
+
if (astVisitor) visitors.push(astVisitor);
|
|
680
|
+
if (complexityVisitor) visitors.push(complexityVisitor);
|
|
681
|
+
if (cfgVisitor) visitors.push(cfgVisitor);
|
|
682
|
+
if (dataflowVisitor) visitors.push(dataflowVisitor);
|
|
624
683
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
684
|
+
return { visitors, walkerOpts, astVisitor, complexityVisitor, cfgVisitor, dataflowVisitor };
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
// ── Main parse handler ──────────────────────────────────────────────────────
|
|
688
|
+
|
|
689
|
+
/**
|
|
690
|
+
* Run tree-sitter parse + extractor on `code`. Returns `null` when either
|
|
691
|
+
* step yields no usable output. Throws (for the caller to report back to the
|
|
692
|
+
* pool) only on a hard tree-sitter parse error.
|
|
693
|
+
*/
|
|
694
|
+
function parseAndExtract(
|
|
695
|
+
parser: Parser,
|
|
696
|
+
entry: LanguageRegistryEntry,
|
|
697
|
+
filePath: string,
|
|
698
|
+
code: string,
|
|
699
|
+
): { tree: Tree; symbols: ExtractorOutput } | null {
|
|
700
|
+
let tree: Tree | null;
|
|
701
|
+
try {
|
|
702
|
+
tree = parser.parse(code);
|
|
703
|
+
} catch (e: unknown) {
|
|
704
|
+
// Parse error — report back but keep worker alive.
|
|
705
|
+
throw new Error(`parse failed: ${(e as Error).message}`);
|
|
636
706
|
}
|
|
707
|
+
if (!tree) return null;
|
|
637
708
|
|
|
638
|
-
//
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
709
|
+
// Extractor — on failure, skip file (ok:true, null) to match parser.ts
|
|
710
|
+
// behavior where extractor issues don't crash the build. Dispose the tree
|
|
711
|
+
// before returning null so WASM linear memory doesn't accumulate in the worker.
|
|
712
|
+
let symbols: ExtractorOutput | null;
|
|
713
|
+
try {
|
|
714
|
+
const query = _queries.get(entry.id);
|
|
715
|
+
// tree-sitter's Tree/Query are structurally compatible with
|
|
716
|
+
// TreeSitterTree/TreeSitterQuery at runtime — same cast style as
|
|
717
|
+
// parser.ts::wasmExtractSymbols (parser.ts:789).
|
|
718
|
+
symbols = entry.extractor(tree as any, filePath, query as any) ?? null;
|
|
719
|
+
} catch {
|
|
720
|
+
disposeTree(tree);
|
|
721
|
+
return null;
|
|
646
722
|
}
|
|
723
|
+
if (!symbols) {
|
|
724
|
+
disposeTree(tree);
|
|
725
|
+
return null;
|
|
726
|
+
}
|
|
727
|
+
return { tree, symbols };
|
|
728
|
+
}
|
|
647
729
|
|
|
648
|
-
|
|
730
|
+
/**
|
|
731
|
+
* Project the visitor `ast-store` rows into the wire-safe shape returned to
|
|
732
|
+
* the main thread. Strips `file` and `parentNodeId` — both are re-resolved in
|
|
733
|
+
* `features/ast.ts::collectFileAstRows`. Always returns an array (even empty)
|
|
734
|
+
* so `engine.ts::fileNeedsWasmTree` doesn't treat the file as un-walked and
|
|
735
|
+
* trigger a full ensureWasmTrees re-parse (#1036).
|
|
736
|
+
*/
|
|
737
|
+
function projectAstNodes(results: WalkResults): SerializedExtractorOutput['astNodes'] {
|
|
738
|
+
const astRows = (results['ast-store'] || []) as Array<{
|
|
739
|
+
line: number;
|
|
740
|
+
kind: string;
|
|
741
|
+
name: string | null | undefined;
|
|
742
|
+
text: string | null;
|
|
743
|
+
receiver: string | null;
|
|
744
|
+
file?: string;
|
|
745
|
+
parentNodeId?: number | null;
|
|
746
|
+
}>;
|
|
747
|
+
return astRows.map((n) => ({
|
|
748
|
+
line: n.line,
|
|
749
|
+
kind: n.kind,
|
|
750
|
+
name: n.name ?? '',
|
|
751
|
+
text: n.text ?? undefined,
|
|
752
|
+
receiver: n.receiver ?? undefined,
|
|
753
|
+
}));
|
|
649
754
|
}
|
|
650
755
|
|
|
651
|
-
|
|
756
|
+
/**
|
|
757
|
+
* Run the configured visitor walk over `tree.rootNode` and apply each
|
|
758
|
+
* visitor's results back onto `symbols`. Returns the serialized astNodes
|
|
759
|
+
* (or `undefined` when AST is disabled / no rows produced).
|
|
760
|
+
*
|
|
761
|
+
* Mirrors engine.ts:791-829. Runs BEFORE `tree.delete()` because
|
|
762
|
+
* storeComplexityResults / storeCfgResults read `funcNode` off live nodes.
|
|
763
|
+
*/
|
|
764
|
+
function runVisitorWalk(
|
|
765
|
+
tree: Tree,
|
|
766
|
+
symbols: ExtractorOutput,
|
|
767
|
+
langId: string,
|
|
768
|
+
setup: SetupResult,
|
|
769
|
+
): SerializedExtractorOutput['astNodes'] {
|
|
770
|
+
if (setup.visitors.length === 0) return undefined;
|
|
771
|
+
// rootNode shape matches TreeSitterNode at runtime — same cast as parser.ts:789.
|
|
772
|
+
const results = walkWithVisitors(tree.rootNode as any, setup.visitors, langId, setup.walkerOpts);
|
|
773
|
+
const defs = symbols.definitions || [];
|
|
774
|
+
let serializedAstNodes: SerializedExtractorOutput['astNodes'];
|
|
775
|
+
if (setup.astVisitor) serializedAstNodes = projectAstNodes(results);
|
|
776
|
+
if (setup.complexityVisitor) storeComplexityResults(results, defs, langId);
|
|
777
|
+
if (setup.cfgVisitor) storeCfgResults(results, defs);
|
|
778
|
+
if (setup.dataflowVisitor) symbols.dataflow = results.dataflow as DataflowResult;
|
|
779
|
+
return serializedAstNodes;
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
/**
|
|
783
|
+
* Pack the in-memory ExtractorOutput into the structured-clone-safe shape
|
|
784
|
+
* sent back across the worker boundary. Converts the typeMap into a tuple
|
|
785
|
+
* array and intentionally omits `_tree` (cannot cross the boundary).
|
|
786
|
+
*/
|
|
787
|
+
function serializeExtractorOutput(
|
|
788
|
+
symbols: ExtractorOutput,
|
|
789
|
+
langId: LanguageId,
|
|
790
|
+
code: string,
|
|
791
|
+
astNodes: SerializedExtractorOutput['astNodes'],
|
|
792
|
+
): SerializedExtractorOutput {
|
|
793
|
+
return {
|
|
794
|
+
definitions: symbols.definitions,
|
|
795
|
+
calls: symbols.calls,
|
|
796
|
+
imports: symbols.imports,
|
|
797
|
+
classes: symbols.classes,
|
|
798
|
+
exports: symbols.exports,
|
|
799
|
+
typeMap: Array.from(symbols.typeMap.entries()),
|
|
800
|
+
_langId: langId,
|
|
801
|
+
_lineCount: code.split('\n').length,
|
|
802
|
+
dataflow: symbols.dataflow,
|
|
803
|
+
astNodes,
|
|
804
|
+
};
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
/**
|
|
808
|
+
* Release WASM linear memory backing a tree. Best-effort — swallows errors so
|
|
809
|
+
* the worker keeps serving requests. Deferring this would let trees accumulate
|
|
810
|
+
* in the worker's WASM heap and defeat the point of isolating parse calls.
|
|
811
|
+
*/
|
|
812
|
+
function disposeTree(tree: Tree | null): void {
|
|
813
|
+
if (!tree) return;
|
|
814
|
+
const deletable = tree as unknown as { delete?: () => void };
|
|
815
|
+
if (typeof deletable.delete !== 'function') return;
|
|
816
|
+
try {
|
|
817
|
+
deletable.delete();
|
|
818
|
+
} catch {
|
|
819
|
+
// best-effort cleanup — swallow; worker continues.
|
|
820
|
+
}
|
|
821
|
+
}
|
|
652
822
|
|
|
653
823
|
async function handleParse(msg: WorkerParseRequest): Promise<SerializedExtractorOutput | null> {
|
|
654
824
|
const ext = path.extname(msg.filePath).toLowerCase();
|
|
@@ -659,100 +829,20 @@ async function handleParse(msg: WorkerParseRequest): Promise<SerializedExtractor
|
|
|
659
829
|
const parser = await loadLanguageLazy(entry);
|
|
660
830
|
if (!parser) return null;
|
|
661
831
|
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
tree = parser.parse(msg.code);
|
|
666
|
-
} catch (e: unknown) {
|
|
667
|
-
// Parse error — report back but keep worker alive.
|
|
668
|
-
throw new Error(`parse failed: ${(e as Error).message}`);
|
|
669
|
-
}
|
|
670
|
-
if (!tree) return null;
|
|
671
|
-
|
|
672
|
-
// Extractor — on failure, skip file (ok:true, null) to match parser.ts
|
|
673
|
-
// behavior where extractor issues don't crash the build.
|
|
674
|
-
let symbols: ExtractorOutput | null;
|
|
675
|
-
try {
|
|
676
|
-
const query = _queries.get(entry.id);
|
|
677
|
-
// tree-sitter's Tree/Query are structurally compatible with
|
|
678
|
-
// TreeSitterTree/TreeSitterQuery at runtime — same cast style as
|
|
679
|
-
// parser.ts::wasmExtractSymbols (parser.ts:789).
|
|
680
|
-
symbols = entry.extractor(tree as any, msg.filePath, query as any) ?? null;
|
|
681
|
-
} catch {
|
|
682
|
-
return null;
|
|
683
|
-
}
|
|
684
|
-
if (!symbols) return null;
|
|
685
|
-
|
|
686
|
-
// Unified visitor walk — mirrors engine.ts:791-829. Runs BEFORE tree.delete()
|
|
687
|
-
// because storeComplexityResults/storeCfgResults read funcNode off live nodes.
|
|
688
|
-
const { visitors, walkerOpts, astVisitor, complexityVisitor, cfgVisitor, dataflowVisitor } =
|
|
689
|
-
setupVisitorsLocal(symbols, msg.filePath, entry.id, msg.opts);
|
|
832
|
+
const parsed = parseAndExtract(parser, entry, msg.filePath, msg.code);
|
|
833
|
+
if (!parsed) return null;
|
|
834
|
+
const { tree, symbols } = parsed;
|
|
690
835
|
|
|
691
|
-
|
|
836
|
+
try {
|
|
837
|
+
const setup = setupVisitorsLocal(symbols, msg.filePath, entry.id, msg.opts);
|
|
838
|
+
// astNodes kept in the serialized shape (without `file`/`parentNodeId`),
|
|
692
839
|
// not assigned back to symbols.astNodes — ExtractorOutput.astNodes is
|
|
693
840
|
// ASTNodeRow[] (DB row shape with node_id), which is a different type.
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
if (visitors.length > 0) {
|
|
697
|
-
// rootNode shape matches TreeSitterNode at runtime — same cast as parser.ts:789.
|
|
698
|
-
const results = walkWithVisitors(tree.rootNode as any, visitors, entry.id, walkerOpts);
|
|
699
|
-
|
|
700
|
-
const defs = symbols.definitions || [];
|
|
701
|
-
if (astVisitor) {
|
|
702
|
-
const astRows = (results['ast-store'] || []) as Array<{
|
|
703
|
-
line: number;
|
|
704
|
-
kind: string;
|
|
705
|
-
name: string | null | undefined;
|
|
706
|
-
text: string | null;
|
|
707
|
-
receiver: string | null;
|
|
708
|
-
file?: string;
|
|
709
|
-
parentNodeId?: number | null;
|
|
710
|
-
}>;
|
|
711
|
-
// Always set an array (even empty) — leaving astNodes undefined makes
|
|
712
|
-
// engine.ts::fileNeedsWasmTree treat the file as un-walked and trigger
|
|
713
|
-
// a full ensureWasmTrees re-parse of every WASM-parseable file (#1036).
|
|
714
|
-
// Strip `file` and `parentNodeId` — main thread re-resolves both in
|
|
715
|
-
// features/ast.ts::collectFileAstRows.
|
|
716
|
-
serializedAstNodes = astRows.map((n) => ({
|
|
717
|
-
line: n.line,
|
|
718
|
-
kind: n.kind,
|
|
719
|
-
name: n.name ?? '',
|
|
720
|
-
text: n.text ?? undefined,
|
|
721
|
-
receiver: n.receiver ?? undefined,
|
|
722
|
-
}));
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
if (complexityVisitor) storeComplexityResults(results, defs, entry.id);
|
|
726
|
-
if (cfgVisitor) storeCfgResults(results, defs);
|
|
727
|
-
if (dataflowVisitor) symbols.dataflow = results.dataflow as DataflowResult;
|
|
728
|
-
}
|
|
729
|
-
|
|
730
|
-
// Serialize — convert Map<string, TypeMapEntry> to tuple array for the wire.
|
|
731
|
-
const serialized: SerializedExtractorOutput = {
|
|
732
|
-
definitions: symbols.definitions,
|
|
733
|
-
calls: symbols.calls,
|
|
734
|
-
imports: symbols.imports,
|
|
735
|
-
classes: symbols.classes,
|
|
736
|
-
exports: symbols.exports,
|
|
737
|
-
typeMap: Array.from(symbols.typeMap.entries()),
|
|
738
|
-
_langId: entry.id as LanguageId,
|
|
739
|
-
_lineCount: msg.code.split('\n').length,
|
|
740
|
-
dataflow: symbols.dataflow,
|
|
741
|
-
astNodes: serializedAstNodes,
|
|
742
|
-
};
|
|
743
|
-
// _tree is deliberately not serialized — it cannot cross the worker boundary.
|
|
744
|
-
return serialized;
|
|
841
|
+
const serializedAstNodes = runVisitorWalk(tree, symbols, entry.id, setup);
|
|
842
|
+
return serializeExtractorOutput(symbols, entry.id as LanguageId, msg.code, serializedAstNodes);
|
|
745
843
|
} finally {
|
|
746
|
-
// ALWAYS release WASM memory before responding
|
|
747
|
-
|
|
748
|
-
// the point of isolating parse calls.
|
|
749
|
-
if (tree && typeof (tree as unknown as { delete?: () => void }).delete === 'function') {
|
|
750
|
-
try {
|
|
751
|
-
(tree as unknown as { delete: () => void }).delete();
|
|
752
|
-
} catch {
|
|
753
|
-
// best-effort cleanup — swallow; worker continues.
|
|
754
|
-
}
|
|
755
|
-
}
|
|
844
|
+
// ALWAYS release WASM memory before responding (see disposeTree note).
|
|
845
|
+
disposeTree(tree);
|
|
756
846
|
}
|
|
757
847
|
}
|
|
758
848
|
|
package/src/extractors/c.ts
CHANGED
|
@@ -159,6 +159,31 @@ function handleCCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
159
159
|
|
|
160
160
|
// ── Child extraction helpers ────────────────────────────────────────────────
|
|
161
161
|
|
|
162
|
+
const C_DECLARATOR_WRAPPERS = new Set([
|
|
163
|
+
'pointer_declarator',
|
|
164
|
+
'array_declarator',
|
|
165
|
+
'parenthesized_declarator',
|
|
166
|
+
'function_declarator',
|
|
167
|
+
]);
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Drill through pointer/array/parenthesized/function declarator wrappers to
|
|
171
|
+
* recover the bare identifier. Mirrors `unwrap_declarator` in the native C
|
|
172
|
+
* extractor so both engines agree on the name for parameters such as
|
|
173
|
+
* `void process(int callback(int))` (function-type parameter → `callback`) or
|
|
174
|
+
* `int *func(int)` (pointer-returning function → `func`).
|
|
175
|
+
*/
|
|
176
|
+
function unwrapCDeclaratorName(node: TreeSitterNode): string {
|
|
177
|
+
let current: TreeSitterNode | null = node;
|
|
178
|
+
while (current && C_DECLARATOR_WRAPPERS.has(current.type)) {
|
|
179
|
+
current = current.childForFieldName('declarator');
|
|
180
|
+
}
|
|
181
|
+
if (current?.type === 'identifier' || current?.type === 'field_identifier') {
|
|
182
|
+
return current.text;
|
|
183
|
+
}
|
|
184
|
+
return current?.text ?? node.text;
|
|
185
|
+
}
|
|
186
|
+
|
|
162
187
|
function extractCParameters(paramListNode: TreeSitterNode | null): SubDeclaration[] {
|
|
163
188
|
const params: SubDeclaration[] = [];
|
|
164
189
|
if (!paramListNode) return params;
|
|
@@ -167,10 +192,7 @@ function extractCParameters(paramListNode: TreeSitterNode | null): SubDeclaratio
|
|
|
167
192
|
if (!param || param.type !== 'parameter_declaration') continue;
|
|
168
193
|
const nameNode = param.childForFieldName('declarator');
|
|
169
194
|
if (nameNode) {
|
|
170
|
-
const name =
|
|
171
|
-
nameNode.type === 'identifier'
|
|
172
|
-
? nameNode.text
|
|
173
|
-
: (findChild(nameNode, 'identifier')?.text ?? nameNode.text);
|
|
195
|
+
const name = unwrapCDeclaratorName(nameNode);
|
|
174
196
|
params.push({ name, kind: 'parameter', line: param.startPosition.row + 1 });
|
|
175
197
|
}
|
|
176
198
|
}
|
|
@@ -186,10 +208,7 @@ function extractStructFields(structNode: TreeSitterNode): SubDeclaration[] {
|
|
|
186
208
|
if (!member || member.type !== 'field_declaration') continue;
|
|
187
209
|
const nameNode = member.childForFieldName('declarator');
|
|
188
210
|
if (nameNode) {
|
|
189
|
-
const name =
|
|
190
|
-
nameNode.type === 'identifier'
|
|
191
|
-
? nameNode.text
|
|
192
|
-
: (findChild(nameNode, 'identifier')?.text ?? nameNode.text);
|
|
211
|
+
const name = unwrapCDeclaratorName(nameNode);
|
|
193
212
|
fields.push({ name, kind: 'property', line: member.startPosition.row + 1 });
|
|
194
213
|
}
|
|
195
214
|
}
|
package/src/extractors/cpp.ts
CHANGED
|
@@ -239,6 +239,54 @@ function findCppParentClass(node: TreeSitterNode): string | null {
|
|
|
239
239
|
return null;
|
|
240
240
|
}
|
|
241
241
|
|
|
242
|
+
const CPP_DECLARATOR_WRAPPERS = new Set([
|
|
243
|
+
'pointer_declarator',
|
|
244
|
+
'reference_declarator',
|
|
245
|
+
'array_declarator',
|
|
246
|
+
'parenthesized_declarator',
|
|
247
|
+
'function_declarator',
|
|
248
|
+
]);
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Drill through pointer/reference/array/parenthesized/function declarator
|
|
252
|
+
* wrappers to recover the bare identifier. Mirrors `unwrap_cpp_declarator` in
|
|
253
|
+
* the native C++ extractor. tree-sitter-cpp's `reference_declarator` does not
|
|
254
|
+
* expose a `declarator` field, so the loop falls back to scanning children
|
|
255
|
+
* for the next nested declarator or identifier.
|
|
256
|
+
*/
|
|
257
|
+
function unwrapCppDeclaratorName(node: TreeSitterNode): string {
|
|
258
|
+
let current: TreeSitterNode | null = node;
|
|
259
|
+
while (current && CPP_DECLARATOR_WRAPPERS.has(current.type)) {
|
|
260
|
+
const named = current.childForFieldName('declarator');
|
|
261
|
+
if (named) {
|
|
262
|
+
current = named;
|
|
263
|
+
continue;
|
|
264
|
+
}
|
|
265
|
+
const fallback = nextCppDeclaratorChild(current);
|
|
266
|
+
if (!fallback) break;
|
|
267
|
+
current = fallback;
|
|
268
|
+
}
|
|
269
|
+
if (current?.type === 'identifier' || current?.type === 'field_identifier') {
|
|
270
|
+
return current.text;
|
|
271
|
+
}
|
|
272
|
+
return current?.text ?? node.text;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function nextCppDeclaratorChild(node: TreeSitterNode): TreeSitterNode | null {
|
|
276
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
277
|
+
const child = node.child(i);
|
|
278
|
+
if (!child) continue;
|
|
279
|
+
if (
|
|
280
|
+
child.type === 'identifier' ||
|
|
281
|
+
child.type === 'field_identifier' ||
|
|
282
|
+
CPP_DECLARATOR_WRAPPERS.has(child.type)
|
|
283
|
+
) {
|
|
284
|
+
return child;
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
|
|
242
290
|
function extractCppParameters(paramListNode: TreeSitterNode | null): SubDeclaration[] {
|
|
243
291
|
const params: SubDeclaration[] = [];
|
|
244
292
|
if (!paramListNode) return params;
|
|
@@ -247,10 +295,7 @@ function extractCppParameters(paramListNode: TreeSitterNode | null): SubDeclarat
|
|
|
247
295
|
if (!param || param.type !== 'parameter_declaration') continue;
|
|
248
296
|
const nameNode = param.childForFieldName('declarator');
|
|
249
297
|
if (nameNode) {
|
|
250
|
-
const name =
|
|
251
|
-
nameNode.type === 'identifier'
|
|
252
|
-
? nameNode.text
|
|
253
|
-
: (findChild(nameNode, 'identifier')?.text ?? nameNode.text);
|
|
298
|
+
const name = unwrapCppDeclaratorName(nameNode);
|
|
254
299
|
params.push({ name, kind: 'parameter', line: param.startPosition.row + 1 });
|
|
255
300
|
}
|
|
256
301
|
}
|
|
@@ -267,10 +312,7 @@ function extractCppClassFields(classNode: TreeSitterNode): SubDeclaration[] {
|
|
|
267
312
|
if (!member || member.type !== 'field_declaration') continue;
|
|
268
313
|
const nameNode = member.childForFieldName('declarator');
|
|
269
314
|
if (nameNode) {
|
|
270
|
-
const name =
|
|
271
|
-
nameNode.type === 'identifier'
|
|
272
|
-
? nameNode.text
|
|
273
|
-
: (findChild(nameNode, 'identifier')?.text ?? nameNode.text);
|
|
315
|
+
const name = unwrapCppDeclaratorName(nameNode);
|
|
274
316
|
fields.push({
|
|
275
317
|
name,
|
|
276
318
|
kind: 'property',
|