@optave/codegraph 3.12.0 → 3.15.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 +83 -46
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +38 -40
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/b2.d.ts +7 -0
- package/dist/ast-analysis/rules/b2.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b2.js +240 -0
- package/dist/ast-analysis/rules/b2.js.map +1 -0
- package/dist/ast-analysis/rules/b3.d.ts +6 -0
- package/dist/ast-analysis/rules/b3.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b3.js +105 -0
- package/dist/ast-analysis/rules/b3.js.map +1 -0
- package/dist/ast-analysis/rules/b4.d.ts +9 -0
- package/dist/ast-analysis/rules/b4.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b4.js +361 -0
- package/dist/ast-analysis/rules/b4.js.map +1 -0
- package/dist/ast-analysis/rules/b5.d.ts +4 -0
- package/dist/ast-analysis/rules/b5.d.ts.map +1 -0
- package/dist/ast-analysis/rules/b5.js +52 -0
- package/dist/ast-analysis/rules/b5.js.map +1 -0
- package/dist/ast-analysis/rules/c.d.ts +4 -0
- package/dist/ast-analysis/rules/c.d.ts.map +1 -0
- package/dist/ast-analysis/rules/c.js +143 -0
- package/dist/ast-analysis/rules/c.js.map +1 -0
- package/dist/ast-analysis/rules/index.d.ts.map +1 -1
- package/dist/ast-analysis/rules/index.js +34 -0
- package/dist/ast-analysis/rules/index.js.map +1 -1
- package/dist/ast-analysis/rules/javascript.d.ts.map +1 -1
- package/dist/ast-analysis/rules/javascript.js +3 -0
- package/dist/ast-analysis/rules/javascript.js.map +1 -1
- package/dist/ast-analysis/shared.d.ts.map +1 -1
- package/dist/ast-analysis/shared.js +2 -0
- package/dist/ast-analysis/shared.js.map +1 -1
- package/dist/ast-analysis/visitor-utils.d.ts +1 -0
- package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
- package/dist/ast-analysis/visitor-utils.js +5 -0
- package/dist/ast-analysis/visitor-utils.js.map +1 -1
- package/dist/ast-analysis/visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitor.js +60 -47
- package/dist/ast-analysis/visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/cfg-visitor.js +126 -76
- package/dist/ast-analysis/visitors/cfg-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 +27 -15
- package/dist/ast-analysis/visitors/complexity-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 +54 -21
- package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
- package/dist/cli/commands/audit.d.ts.map +1 -1
- package/dist/cli/commands/audit.js +2 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +1 -0
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +6 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/config.d.ts +3 -0
- package/dist/cli/commands/config.d.ts.map +1 -0
- package/dist/cli/commands/config.js +275 -0
- package/dist/cli/commands/config.js.map +1 -0
- package/dist/cli/commands/roles.d.ts.map +1 -1
- package/dist/cli/commands/roles.js +6 -1
- package/dist/cli/commands/roles.js.map +1 -1
- package/dist/cli/commands/triage.js +1 -1
- package/dist/cli/commands/triage.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +10 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/shared/options.d.ts +2 -1
- package/dist/cli/shared/options.d.ts.map +1 -1
- package/dist/cli/shared/options.js +11 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/cli/types.d.ts +2 -0
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/db/better-sqlite3.d.ts +2 -1
- package/dist/db/better-sqlite3.d.ts.map +1 -1
- package/dist/db/better-sqlite3.js.map +1 -1
- package/dist/db/connection.d.ts +7 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +20 -5
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- 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 +69 -1
- package/dist/db/migrations.js.map +1 -1
- package/dist/db/repository/build-stmts.d.ts.map +1 -1
- package/dist/db/repository/build-stmts.js +18 -0
- package/dist/db/repository/build-stmts.js.map +1 -1
- package/dist/db/repository/dataflow.d.ts +5 -0
- package/dist/db/repository/dataflow.d.ts.map +1 -1
- package/dist/db/repository/dataflow.js +14 -0
- package/dist/db/repository/dataflow.js.map +1 -1
- package/dist/db/repository/index.d.ts +1 -1
- package/dist/db/repository/index.d.ts.map +1 -1
- package/dist/db/repository/index.js +1 -1
- package/dist/db/repository/index.js.map +1 -1
- package/dist/db/repository/native-repository.d.ts.map +1 -1
- package/dist/db/repository/native-repository.js +47 -34
- package/dist/db/repository/native-repository.js.map +1 -1
- package/dist/domain/analysis/context.d.ts +2 -2
- package/dist/domain/analysis/dependencies.d.ts +2 -2
- package/dist/domain/analysis/diff-impact.d.ts +2 -2
- package/dist/domain/analysis/fn-impact.d.ts +3 -1
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +4 -0
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/implementations.d.ts +2 -2
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +32 -5
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/roles.d.ts +7 -1
- package/dist/domain/analysis/roles.d.ts.map +1 -1
- package/dist/domain/analysis/roles.js +16 -0
- package/dist/domain/analysis/roles.js.map +1 -1
- package/dist/domain/analysis/symbol-lookup.d.ts +4 -4
- package/dist/domain/graph/builder/call-resolver.d.ts +29 -13
- package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
- package/dist/domain/graph/builder/call-resolver.js +125 -205
- package/dist/domain/graph/builder/call-resolver.js.map +1 -1
- package/dist/domain/graph/builder/cha.d.ts +9 -1
- package/dist/domain/graph/builder/cha.d.ts.map +1 -1
- package/dist/domain/graph/builder/cha.js +17 -2
- package/dist/domain/graph/builder/cha.js.map +1 -1
- package/dist/domain/graph/builder/context.d.ts +1 -0
- package/dist/domain/graph/builder/context.d.ts.map +1 -1
- package/dist/domain/graph/builder/context.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +24 -1
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +174 -65
- 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 +166 -97
- 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 +46 -5
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts +0 -2
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +554 -538
- package/dist/domain/graph/builder/stages/build-edges.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 +10 -7
- 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 +3 -2
- 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 +4 -0
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/native-orchestrator.js +952 -343
- package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolver/points-to.d.ts.map +1 -1
- package/dist/domain/graph/resolver/points-to.js +105 -57
- package/dist/domain/graph/resolver/points-to.js.map +1 -1
- package/dist/domain/graph/resolver/strategy.d.ts +61 -0
- package/dist/domain/graph/resolver/strategy.d.ts.map +1 -0
- package/dist/domain/graph/resolver/strategy.js +222 -0
- package/dist/domain/graph/resolver/strategy.js.map +1 -0
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +16 -9
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +16 -5
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +58 -17
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/queries.d.ts +1 -1
- package/dist/domain/queries.d.ts.map +1 -1
- package/dist/domain/queries.js +1 -1
- package/dist/domain/queries.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +13 -2
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/domain/wasm-worker-pool.d.ts.map +1 -1
- package/dist/domain/wasm-worker-pool.js +26 -5
- package/dist/domain/wasm-worker-pool.js.map +1 -1
- package/dist/domain/wasm-worker-protocol.d.ts +8 -0
- package/dist/domain/wasm-worker-protocol.d.ts.map +1 -1
- package/dist/extractors/cpp.d.ts.map +1 -1
- package/dist/extractors/cpp.js +42 -1
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/cuda.d.ts.map +1 -1
- package/dist/extractors/cuda.js +42 -1
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/dart.js +48 -3
- package/dist/extractors/dart.js.map +1 -1
- package/dist/extractors/groovy.js +62 -3
- package/dist/extractors/groovy.js.map +1 -1
- package/dist/extractors/helpers.d.ts +15 -2
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +45 -1
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +85 -8
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +686 -169
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.js +58 -3
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/objc.js +25 -2
- package/dist/extractors/objc.js.map +1 -1
- package/dist/extractors/scala.js +62 -2
- package/dist/extractors/scala.js.map +1 -1
- package/dist/extractors/swift.js +52 -3
- package/dist/extractors/swift.js.map +1 -1
- package/dist/features/audit.js +26 -23
- package/dist/features/audit.js.map +1 -1
- package/dist/features/boundaries.d.ts.map +1 -1
- package/dist/features/boundaries.js +12 -9
- package/dist/features/boundaries.js.map +1 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +25 -18
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +18 -5
- package/dist/features/check.js.map +1 -1
- package/dist/features/communities.d.ts +4 -2
- package/dist/features/communities.d.ts.map +1 -1
- package/dist/features/communities.js +6 -4
- package/dist/features/communities.js.map +1 -1
- package/dist/features/dataflow.d.ts +60 -0
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +530 -6
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/manifesto.d.ts.map +1 -1
- package/dist/features/manifesto.js +59 -72
- package/dist/features/manifesto.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +27 -22
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/snapshot.d.ts.map +1 -1
- package/dist/features/snapshot.js +36 -28
- package/dist/features/snapshot.js.map +1 -1
- package/dist/features/structure-query.d.ts +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +6 -6
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +150 -62
- package/dist/features/structure.js.map +1 -1
- package/dist/features/triage.d.ts.map +1 -1
- package/dist/features/triage.js +18 -11
- package/dist/features/triage.js.map +1 -1
- package/dist/graph/algorithms/bfs.d.ts +1 -1
- package/dist/graph/algorithms/bfs.d.ts.map +1 -1
- package/dist/graph/algorithms/bfs.js +14 -13
- package/dist/graph/algorithms/bfs.js.map +1 -1
- package/dist/graph/algorithms/tarjan.d.ts.map +1 -1
- package/dist/graph/algorithms/tarjan.js +5 -0
- package/dist/graph/algorithms/tarjan.js.map +1 -1
- package/dist/graph/builders/dependency.js +28 -22
- package/dist/graph/builders/dependency.js.map +1 -1
- package/dist/graph/classifiers/roles.d.ts +10 -1
- package/dist/graph/classifiers/roles.d.ts.map +1 -1
- package/dist/graph/classifiers/roles.js +60 -6
- package/dist/graph/classifiers/roles.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/config.d.ts +87 -4
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +424 -22
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +27 -7
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +79 -5
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/infrastructure/update-check.d.ts.map +1 -1
- package/dist/infrastructure/update-check.js +49 -31
- package/dist/infrastructure/update-check.js.map +1 -1
- package/dist/mcp/server.d.ts +2 -10
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/ast-query.d.ts +1 -1
- package/dist/mcp/tools/ast-query.d.ts.map +1 -1
- package/dist/mcp/tools/audit.d.ts +1 -1
- package/dist/mcp/tools/audit.d.ts.map +1 -1
- package/dist/mcp/tools/batch-query.d.ts +1 -1
- package/dist/mcp/tools/batch-query.d.ts.map +1 -1
- package/dist/mcp/tools/branch-compare.d.ts +1 -1
- package/dist/mcp/tools/branch-compare.d.ts.map +1 -1
- package/dist/mcp/tools/brief.d.ts +1 -1
- package/dist/mcp/tools/brief.d.ts.map +1 -1
- package/dist/mcp/tools/cfg.d.ts +1 -1
- package/dist/mcp/tools/cfg.d.ts.map +1 -1
- package/dist/mcp/tools/check.d.ts +1 -1
- package/dist/mcp/tools/check.d.ts.map +1 -1
- package/dist/mcp/tools/co-changes.d.ts +1 -1
- package/dist/mcp/tools/co-changes.d.ts.map +1 -1
- package/dist/mcp/tools/code-owners.d.ts +1 -1
- package/dist/mcp/tools/code-owners.d.ts.map +1 -1
- package/dist/mcp/tools/communities.d.ts +1 -1
- package/dist/mcp/tools/communities.d.ts.map +1 -1
- package/dist/mcp/tools/complexity.d.ts +1 -1
- package/dist/mcp/tools/complexity.d.ts.map +1 -1
- package/dist/mcp/tools/context.d.ts +1 -1
- package/dist/mcp/tools/context.d.ts.map +1 -1
- package/dist/mcp/tools/dataflow.d.ts +1 -1
- package/dist/mcp/tools/dataflow.d.ts.map +1 -1
- package/dist/mcp/tools/diff-impact.d.ts +1 -1
- package/dist/mcp/tools/diff-impact.d.ts.map +1 -1
- package/dist/mcp/tools/execution-flow.d.ts +1 -1
- package/dist/mcp/tools/execution-flow.d.ts.map +1 -1
- package/dist/mcp/tools/export-graph.d.ts +1 -1
- package/dist/mcp/tools/export-graph.d.ts.map +1 -1
- package/dist/mcp/tools/file-deps.d.ts +1 -1
- package/dist/mcp/tools/file-deps.d.ts.map +1 -1
- package/dist/mcp/tools/file-exports.d.ts +1 -1
- package/dist/mcp/tools/file-exports.d.ts.map +1 -1
- package/dist/mcp/tools/find-cycles.d.ts +1 -1
- package/dist/mcp/tools/find-cycles.d.ts.map +1 -1
- package/dist/mcp/tools/fn-impact.d.ts +1 -1
- package/dist/mcp/tools/fn-impact.d.ts.map +1 -1
- package/dist/mcp/tools/impact-analysis.d.ts +1 -1
- package/dist/mcp/tools/impact-analysis.d.ts.map +1 -1
- package/dist/mcp/tools/implementations.d.ts +1 -1
- package/dist/mcp/tools/implementations.d.ts.map +1 -1
- package/dist/mcp/tools/index.d.ts +2 -5
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/interfaces.d.ts +1 -1
- package/dist/mcp/tools/interfaces.d.ts.map +1 -1
- package/dist/mcp/tools/list-functions.d.ts +1 -1
- package/dist/mcp/tools/list-functions.d.ts.map +1 -1
- package/dist/mcp/tools/list-repos.d.ts +1 -1
- package/dist/mcp/tools/list-repos.d.ts.map +1 -1
- package/dist/mcp/tools/module-map.d.ts +1 -1
- package/dist/mcp/tools/module-map.d.ts.map +1 -1
- package/dist/mcp/tools/node-roles.d.ts +1 -1
- package/dist/mcp/tools/node-roles.d.ts.map +1 -1
- package/dist/mcp/tools/path.d.ts +1 -1
- package/dist/mcp/tools/path.d.ts.map +1 -1
- package/dist/mcp/tools/query.d.ts +1 -1
- package/dist/mcp/tools/query.d.ts.map +1 -1
- package/dist/mcp/tools/semantic-search.d.ts +1 -1
- package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
- package/dist/mcp/tools/sequence.d.ts +1 -1
- package/dist/mcp/tools/sequence.d.ts.map +1 -1
- package/dist/mcp/tools/structure.d.ts +1 -1
- package/dist/mcp/tools/structure.d.ts.map +1 -1
- package/dist/mcp/tools/symbol-children.d.ts +1 -1
- package/dist/mcp/tools/symbol-children.d.ts.map +1 -1
- package/dist/mcp/tools/triage.d.ts +1 -1
- package/dist/mcp/tools/triage.d.ts.map +1 -1
- package/dist/mcp/tools/where.d.ts +1 -1
- package/dist/mcp/tools/where.d.ts.map +1 -1
- package/dist/mcp/types.d.ts +19 -0
- package/dist/mcp/types.d.ts.map +1 -0
- package/dist/mcp/types.js +6 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/presentation/queries-cli/index.d.ts +1 -1
- package/dist/presentation/queries-cli/index.d.ts.map +1 -1
- package/dist/presentation/queries-cli/index.js +1 -1
- package/dist/presentation/queries-cli/index.js.map +1 -1
- package/dist/presentation/queries-cli/overview.d.ts +1 -0
- package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
- package/dist/presentation/queries-cli/overview.js +20 -1
- package/dist/presentation/queries-cli/overview.js.map +1 -1
- package/dist/presentation/queries-cli.d.ts +1 -1
- package/dist/presentation/queries-cli.d.ts.map +1 -1
- package/dist/presentation/queries-cli.js +1 -1
- package/dist/presentation/queries-cli.js.map +1 -1
- package/dist/presentation/structure.d.ts +1 -1
- package/dist/presentation/structure.d.ts.map +1 -1
- package/dist/presentation/structure.js +2 -2
- package/dist/presentation/structure.js.map +1 -1
- package/dist/presentation/viewer.d.ts.map +1 -1
- package/dist/presentation/viewer.js +45 -32
- package/dist/presentation/viewer.js.map +1 -1
- package/dist/shared/constants.d.ts +21 -0
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +25 -0
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/normalize.d.ts.map +1 -1
- package/dist/shared/normalize.js +12 -22
- package/dist/shared/normalize.js.map +1 -1
- package/dist/shared/paginate.d.ts +4 -17
- package/dist/shared/paginate.d.ts.map +1 -1
- package/dist/shared/paginate.js.map +1 -1
- package/dist/types.d.ts +113 -1
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-erlang.wasm +0 -0
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +7 -8
- package/src/ast-analysis/engine.ts +43 -63
- package/src/ast-analysis/rules/b2.ts +263 -0
- package/src/ast-analysis/rules/b3.ts +127 -0
- package/src/ast-analysis/rules/b4.ts +378 -0
- package/src/ast-analysis/rules/b5.ts +65 -0
- package/src/ast-analysis/rules/c.ts +157 -0
- package/src/ast-analysis/rules/index.ts +34 -0
- package/src/ast-analysis/rules/javascript.ts +3 -0
- package/src/ast-analysis/shared.ts +2 -0
- package/src/ast-analysis/visitor-utils.ts +5 -0
- package/src/ast-analysis/visitor.ts +82 -52
- package/src/ast-analysis/visitors/cfg-visitor.ts +198 -84
- package/src/ast-analysis/visitors/complexity-visitor.ts +44 -16
- package/src/ast-analysis/visitors/dataflow-visitor.ts +68 -29
- package/src/cli/commands/audit.ts +2 -1
- package/src/cli/commands/batch.ts +1 -0
- package/src/cli/commands/build.ts +6 -1
- package/src/cli/commands/config.ts +353 -0
- package/src/cli/commands/roles.ts +6 -1
- package/src/cli/commands/triage.ts +1 -1
- package/src/cli/index.ts +10 -0
- package/src/cli/shared/options.ts +11 -1
- package/src/cli/types.ts +2 -0
- package/src/db/better-sqlite3.ts +5 -4
- package/src/db/connection.ts +23 -5
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +69 -1
- package/src/db/repository/build-stmts.ts +30 -0
- package/src/db/repository/dataflow.ts +16 -0
- package/src/db/repository/index.ts +1 -1
- package/src/db/repository/native-repository.ts +56 -40
- package/src/domain/analysis/fn-impact.ts +4 -0
- package/src/domain/analysis/module-map.ts +38 -6
- package/src/domain/analysis/roles.ts +23 -0
- package/src/domain/graph/builder/call-resolver.ts +156 -218
- package/src/domain/graph/builder/cha.ts +18 -1
- package/src/domain/graph/builder/context.ts +1 -0
- package/src/domain/graph/builder/helpers.ts +205 -67
- package/src/domain/graph/builder/incremental.ts +249 -119
- package/src/domain/graph/builder/pipeline.ts +59 -6
- package/src/domain/graph/builder/stages/build-edges.ts +783 -652
- package/src/domain/graph/builder/stages/collect-files.ts +12 -6
- package/src/domain/graph/builder/stages/detect-changes.ts +4 -2
- package/src/domain/graph/builder/stages/finalize.ts +4 -0
- package/src/domain/graph/builder/stages/native-orchestrator.ts +1214 -398
- package/src/domain/graph/builder/stages/resolve-imports.ts +1 -1
- package/src/domain/graph/resolver/points-to.ts +182 -59
- package/src/domain/graph/resolver/strategy.ts +265 -0
- package/src/domain/graph/watcher.ts +19 -9
- package/src/domain/parser.ts +57 -16
- package/src/domain/queries.ts +1 -1
- package/src/domain/wasm-worker-entry.ts +13 -2
- package/src/domain/wasm-worker-pool.ts +29 -4
- package/src/domain/wasm-worker-protocol.ts +5 -0
- package/src/extractors/cpp.ts +44 -1
- package/src/extractors/cuda.ts +44 -1
- package/src/extractors/dart.ts +48 -3
- package/src/extractors/groovy.ts +62 -2
- package/src/extractors/helpers.ts +48 -2
- package/src/extractors/java.ts +88 -8
- package/src/extractors/javascript.ts +693 -167
- package/src/extractors/kotlin.ts +57 -3
- package/src/extractors/objc.ts +25 -1
- package/src/extractors/scala.ts +63 -1
- package/src/extractors/swift.ts +46 -3
- package/src/features/audit.ts +43 -34
- package/src/features/boundaries.ts +17 -9
- package/src/features/cfg.ts +31 -22
- package/src/features/check.ts +21 -5
- package/src/features/communities.ts +28 -19
- package/src/features/dataflow.ts +755 -6
- package/src/features/manifesto.ts +76 -75
- package/src/features/sequence.ts +29 -23
- package/src/features/snapshot.ts +36 -25
- package/src/features/structure-query.ts +7 -7
- package/src/features/structure.ts +185 -55
- package/src/features/triage.ts +28 -15
- package/src/graph/algorithms/bfs.ts +13 -12
- package/src/graph/algorithms/tarjan.ts +5 -0
- package/src/graph/builders/dependency.ts +35 -23
- package/src/graph/classifiers/roles.ts +74 -7
- package/src/index.ts +5 -1
- package/src/infrastructure/config.ts +511 -23
- package/src/infrastructure/registry.ts +117 -12
- package/src/infrastructure/update-check.ts +55 -33
- package/src/mcp/server.ts +2 -8
- package/src/mcp/tools/ast-query.ts +1 -1
- package/src/mcp/tools/audit.ts +1 -1
- package/src/mcp/tools/batch-query.ts +1 -1
- package/src/mcp/tools/branch-compare.ts +1 -1
- package/src/mcp/tools/brief.ts +1 -1
- package/src/mcp/tools/cfg.ts +1 -1
- package/src/mcp/tools/check.ts +1 -1
- package/src/mcp/tools/co-changes.ts +1 -1
- package/src/mcp/tools/code-owners.ts +1 -1
- package/src/mcp/tools/communities.ts +1 -1
- package/src/mcp/tools/complexity.ts +1 -1
- package/src/mcp/tools/context.ts +1 -1
- package/src/mcp/tools/dataflow.ts +1 -1
- package/src/mcp/tools/diff-impact.ts +1 -1
- package/src/mcp/tools/execution-flow.ts +1 -1
- package/src/mcp/tools/export-graph.ts +1 -1
- package/src/mcp/tools/file-deps.ts +1 -1
- package/src/mcp/tools/file-exports.ts +1 -1
- package/src/mcp/tools/find-cycles.ts +1 -1
- package/src/mcp/tools/fn-impact.ts +1 -1
- package/src/mcp/tools/impact-analysis.ts +1 -1
- package/src/mcp/tools/implementations.ts +1 -1
- package/src/mcp/tools/index.ts +2 -5
- package/src/mcp/tools/interfaces.ts +1 -1
- package/src/mcp/tools/list-functions.ts +1 -1
- package/src/mcp/tools/list-repos.ts +1 -1
- package/src/mcp/tools/module-map.ts +1 -1
- package/src/mcp/tools/node-roles.ts +1 -1
- package/src/mcp/tools/path.ts +1 -1
- package/src/mcp/tools/query.ts +1 -1
- package/src/mcp/tools/semantic-search.ts +1 -1
- package/src/mcp/tools/sequence.ts +1 -1
- package/src/mcp/tools/structure.ts +1 -1
- package/src/mcp/tools/symbol-children.ts +1 -1
- package/src/mcp/tools/triage.ts +1 -1
- package/src/mcp/tools/where.ts +1 -1
- package/src/mcp/types.ts +21 -0
- package/src/presentation/queries-cli/index.ts +1 -1
- package/src/presentation/queries-cli/overview.ts +35 -1
- package/src/presentation/queries-cli.ts +1 -0
- package/src/presentation/structure.ts +3 -3
- package/src/presentation/viewer.ts +98 -87
- package/src/shared/constants.ts +26 -0
- package/src/shared/normalize.ts +13 -22
- package/src/shared/paginate.ts +4 -18
- package/src/types.ts +127 -1
|
@@ -13,6 +13,7 @@ interface ParamInfo {
|
|
|
13
13
|
|
|
14
14
|
interface LanguageRules {
|
|
15
15
|
nameField: string;
|
|
16
|
+
nameExtractor?: ((node: TreeSitterNode) => string | null) | null;
|
|
16
17
|
varAssignedFnParent?: string;
|
|
17
18
|
pairFnParent?: string;
|
|
18
19
|
assignmentFnParent?: string;
|
|
@@ -47,6 +48,10 @@ export function truncate(str: string, max = 120): string {
|
|
|
47
48
|
*/
|
|
48
49
|
export function functionName(fnNode: TreeSitterNode | null, rules: LanguageRules): string | null {
|
|
49
50
|
if (!fnNode) return null;
|
|
51
|
+
if (rules.nameExtractor) {
|
|
52
|
+
const extracted = rules.nameExtractor(fnNode);
|
|
53
|
+
if (extracted) return extracted;
|
|
54
|
+
}
|
|
50
55
|
const nameNode = fnNode.childForFieldName(rules.nameField);
|
|
51
56
|
if (nameNode) return nameNode.text;
|
|
52
57
|
|
|
@@ -152,24 +152,18 @@ function collectResults(visitors: Visitor[]): WalkResults {
|
|
|
152
152
|
return results;
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
export function walkWithVisitors(
|
|
168
|
-
rootNode: TreeSitterNode,
|
|
169
|
-
visitors: Visitor[],
|
|
170
|
-
langId: string,
|
|
171
|
-
options: WalkOptions = {},
|
|
172
|
-
): WalkResults {
|
|
155
|
+
interface WalkState {
|
|
156
|
+
visitors: Visitor[];
|
|
157
|
+
allFuncTypes: Set<string>;
|
|
158
|
+
nestingNodeTypes: Set<string>;
|
|
159
|
+
getFunctionName: (node: TreeSitterNode) => string | null;
|
|
160
|
+
context: VisitorContext;
|
|
161
|
+
scopeStack: ScopeEntry[];
|
|
162
|
+
skipDepths: Map<number, number>;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** Build walk state from options: resolve function types, init visitors, create shared context. */
|
|
166
|
+
function buildWalkState(visitors: Visitor[], langId: string, options: WalkOptions): WalkState {
|
|
173
167
|
const {
|
|
174
168
|
functionNodeTypes = new Set<string>(),
|
|
175
169
|
nestingNodeTypes = new Set<string>(),
|
|
@@ -179,7 +173,6 @@ export function walkWithVisitors(
|
|
|
179
173
|
const allFuncTypes = mergeFunctionNodeTypes(visitors, functionNodeTypes);
|
|
180
174
|
initVisitors(visitors, langId);
|
|
181
175
|
|
|
182
|
-
// Shared context object (mutated during walk)
|
|
183
176
|
const scopeStack: ScopeEntry[] = [];
|
|
184
177
|
const context: VisitorContext = {
|
|
185
178
|
nestingLevel: 0,
|
|
@@ -188,49 +181,86 @@ export function walkWithVisitors(
|
|
|
188
181
|
scopeStack,
|
|
189
182
|
};
|
|
190
183
|
|
|
191
|
-
|
|
184
|
+
return {
|
|
185
|
+
visitors,
|
|
186
|
+
allFuncTypes,
|
|
187
|
+
nestingNodeTypes,
|
|
188
|
+
getFunctionName,
|
|
189
|
+
context,
|
|
190
|
+
scopeStack,
|
|
191
|
+
skipDepths: new Map<number, number>(),
|
|
192
|
+
};
|
|
193
|
+
}
|
|
192
194
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
195
|
+
/** Single DFS step: dispatch enter/exit hooks and recurse into children. */
|
|
196
|
+
function walkNode(state: WalkState, node: TreeSitterNode | null, depth: number): void {
|
|
197
|
+
if (!node) return;
|
|
198
|
+
if (depth > MAX_WALK_DEPTH) {
|
|
199
|
+
debug(`walkWithVisitors: AST depth limit (${MAX_WALK_DEPTH}) hit — subtree truncated`);
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
199
202
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
+
const {
|
|
204
|
+
visitors,
|
|
205
|
+
allFuncTypes,
|
|
206
|
+
nestingNodeTypes,
|
|
207
|
+
getFunctionName,
|
|
208
|
+
context,
|
|
209
|
+
scopeStack,
|
|
210
|
+
skipDepths,
|
|
211
|
+
} = state;
|
|
212
|
+
const type = node.type;
|
|
213
|
+
const isFuncBoundary = allFuncTypes.has(type);
|
|
214
|
+
let funcName: string | null = null;
|
|
203
215
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
216
|
+
if (isFuncBoundary) {
|
|
217
|
+
funcName = getFunctionName(node);
|
|
218
|
+
context.currentFunction = node;
|
|
219
|
+
scopeStack.push({ funcName, funcNode: node, params: new Map(), locals: new Map() });
|
|
220
|
+
dispatchEnterFunction(visitors, skipDepths, node, funcName, context, depth);
|
|
221
|
+
}
|
|
210
222
|
|
|
211
|
-
|
|
223
|
+
dispatchEnterNode(visitors, skipDepths, node, context, depth);
|
|
212
224
|
|
|
213
|
-
|
|
214
|
-
|
|
225
|
+
const addsNesting = nestingNodeTypes.has(type);
|
|
226
|
+
if (addsNesting) context.nestingLevel++;
|
|
215
227
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
228
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
229
|
+
walkNode(state, node.child(i), depth + 1);
|
|
230
|
+
}
|
|
219
231
|
|
|
220
|
-
|
|
232
|
+
if (addsNesting) context.nestingLevel--;
|
|
221
233
|
|
|
222
|
-
|
|
223
|
-
|
|
234
|
+
dispatchExitNode(visitors, skipDepths, node, context, depth);
|
|
235
|
+
clearSkipFlags(skipDepths, visitors.length, depth);
|
|
224
236
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
237
|
+
if (isFuncBoundary) {
|
|
238
|
+
dispatchExitFunction(visitors, skipDepths, node, funcName, context, depth);
|
|
239
|
+
scopeStack.pop();
|
|
240
|
+
context.currentFunction =
|
|
241
|
+
scopeStack.length > 0 ? scopeStack[scopeStack.length - 1]!.funcNode : null;
|
|
231
242
|
}
|
|
243
|
+
}
|
|
232
244
|
|
|
233
|
-
|
|
234
|
-
|
|
245
|
+
/**
|
|
246
|
+
* Walk an AST root with multiple visitors in a single DFS pass.
|
|
247
|
+
*
|
|
248
|
+
* @param {object} rootNode - tree-sitter root node to walk
|
|
249
|
+
* @param {Visitor[]} visitors - array of visitor objects
|
|
250
|
+
* @param {string} langId - language identifier
|
|
251
|
+
* @param {object} [options]
|
|
252
|
+
* @param {Set} [options.functionNodeTypes] - set of node types that are function boundaries
|
|
253
|
+
* @param {Set} [options.nestingNodeTypes] - set of node types that increase nesting depth
|
|
254
|
+
* @param {function} [options.getFunctionName] - (funcNode) => string|null
|
|
255
|
+
* @returns {object} Map of visitor.name → finish() result
|
|
256
|
+
*/
|
|
257
|
+
export function walkWithVisitors(
|
|
258
|
+
rootNode: TreeSitterNode,
|
|
259
|
+
visitors: Visitor[],
|
|
260
|
+
langId: string,
|
|
261
|
+
options: WalkOptions = {},
|
|
262
|
+
): WalkResults {
|
|
263
|
+
const state = buildWalkState(visitors, langId, options);
|
|
264
|
+
walkNode(state, rootNode, 0);
|
|
235
265
|
return collectResults(visitors);
|
|
236
266
|
}
|
|
@@ -27,97 +27,28 @@ import { processTryCatch } from './cfg-try-catch.js';
|
|
|
27
27
|
|
|
28
28
|
export type { CfgBlockInternal } from './cfg-shared.js';
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
// ─── Statement handler dispatch ─────────────────────────────────────────
|
|
31
|
+
|
|
32
|
+
type BoundProcessStatements = (
|
|
31
33
|
stmts: TreeSitterNode[],
|
|
32
34
|
currentBlock: CfgBlockInternal,
|
|
33
35
|
S: FuncState,
|
|
34
|
-
|
|
35
|
-
): CfgBlockInternal | null {
|
|
36
|
-
let cur: CfgBlockInternal | null = currentBlock;
|
|
37
|
-
for (const stmt of stmts) {
|
|
38
|
-
if (!cur) break;
|
|
39
|
-
cur = processStatement(stmt, cur, S, cfgRules);
|
|
40
|
-
}
|
|
41
|
-
return cur;
|
|
42
|
-
}
|
|
36
|
+
) => CfgBlockInternal | null;
|
|
43
37
|
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
type StatementHandler = (
|
|
39
|
+
node: TreeSitterNode,
|
|
46
40
|
currentBlock: CfgBlockInternal,
|
|
47
41
|
S: FuncState,
|
|
48
42
|
cfgRules: AnyRules,
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const effNode = effectiveNode(stmt, cfgRules);
|
|
53
|
-
const type = effNode.type;
|
|
43
|
+
processStmts: BoundProcessStatements,
|
|
44
|
+
) => CfgBlockInternal | null;
|
|
54
45
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
if (isIfNode(type, cfgRules) || (cfgRules.unlessNode && type === cfgRules.unlessNode)) {
|
|
59
|
-
return processIf(effNode, currentBlock, S, cfgRules, processStatements);
|
|
60
|
-
}
|
|
61
|
-
if (isForNode(type, cfgRules)) {
|
|
62
|
-
return processForLoop(effNode, currentBlock, S, cfgRules, processStatements);
|
|
63
|
-
}
|
|
64
|
-
if (isWhileNode(type, cfgRules) || (cfgRules.untilNode && type === cfgRules.untilNode)) {
|
|
65
|
-
return processWhileLoop(effNode, currentBlock, S, cfgRules, processStatements);
|
|
66
|
-
}
|
|
67
|
-
if (cfgRules.doNode && type === cfgRules.doNode) {
|
|
68
|
-
return processDoWhileLoop(effNode, currentBlock, S, cfgRules, processStatements);
|
|
69
|
-
}
|
|
70
|
-
if (cfgRules.infiniteLoopNode && type === cfgRules.infiniteLoopNode) {
|
|
71
|
-
return processInfiniteLoop(effNode, currentBlock, S, cfgRules, processStatements);
|
|
72
|
-
}
|
|
73
|
-
if (isSwitchNode(type, cfgRules)) {
|
|
74
|
-
return processSwitch(effNode, currentBlock, S, cfgRules, processStatements);
|
|
75
|
-
}
|
|
76
|
-
if (cfgRules.tryNode && type === cfgRules.tryNode) {
|
|
77
|
-
return processTryCatch(effNode, currentBlock, S, cfgRules, processStatements);
|
|
78
|
-
}
|
|
79
|
-
if (type === cfgRules.returnNode) {
|
|
80
|
-
currentBlock.endLine = effNode.startPosition.row + 1;
|
|
81
|
-
S.addEdge(currentBlock, S.exitBlock, 'return');
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
if (type === cfgRules.throwNode) {
|
|
85
|
-
currentBlock.endLine = effNode.startPosition.row + 1;
|
|
86
|
-
S.addEdge(currentBlock, S.exitBlock, 'exception');
|
|
87
|
-
return null;
|
|
88
|
-
}
|
|
89
|
-
if (type === cfgRules.breakNode) {
|
|
90
|
-
return processBreak(effNode, currentBlock, S);
|
|
91
|
-
}
|
|
92
|
-
if (type === cfgRules.continueNode) {
|
|
93
|
-
return processContinue(effNode, currentBlock, S);
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
if (!currentBlock.startLine) {
|
|
97
|
-
currentBlock.startLine = stmt.startPosition.row + 1;
|
|
98
|
-
}
|
|
99
|
-
currentBlock.endLine = stmt.endPosition.row + 1;
|
|
100
|
-
return currentBlock;
|
|
46
|
+
interface StatementEntry {
|
|
47
|
+
match: (type: string) => boolean;
|
|
48
|
+
handle: StatementHandler;
|
|
101
49
|
}
|
|
102
50
|
|
|
103
|
-
|
|
104
|
-
node: TreeSitterNode,
|
|
105
|
-
currentBlock: CfgBlockInternal,
|
|
106
|
-
S: FuncState,
|
|
107
|
-
cfgRules: AnyRules,
|
|
108
|
-
): CfgBlockInternal | null {
|
|
109
|
-
const labelNode = node.childForFieldName('label');
|
|
110
|
-
const labelName = labelNode ? labelNode.text : null;
|
|
111
|
-
const body = node.childForFieldName('body');
|
|
112
|
-
if (body && labelName) {
|
|
113
|
-
const labelCtx: LabelCtx = { headerBlock: null, exitBlock: null };
|
|
114
|
-
S.labelMap.set(labelName, labelCtx);
|
|
115
|
-
const result = processStatement(body, currentBlock, S, cfgRules);
|
|
116
|
-
S.labelMap.delete(labelName);
|
|
117
|
-
return result;
|
|
118
|
-
}
|
|
119
|
-
return currentBlock;
|
|
120
|
-
}
|
|
51
|
+
// ─── Helpers that do not depend on the dispatch closure ─────────────────
|
|
121
52
|
|
|
122
53
|
function processBreak(
|
|
123
54
|
node: TreeSitterNode,
|
|
@@ -165,7 +96,186 @@ function processContinue(
|
|
|
165
96
|
return currentBlock;
|
|
166
97
|
}
|
|
167
98
|
|
|
168
|
-
|
|
99
|
+
// ─── Dispatch table builder ──────────────────────────────────────────────
|
|
100
|
+
|
|
101
|
+
// ─── Terminal statement handlers (no processStatements dependency) ───────
|
|
102
|
+
|
|
103
|
+
function handleReturn(n: TreeSitterNode, b: CfgBlockInternal, S: FuncState): null {
|
|
104
|
+
b.endLine = n.startPosition.row + 1;
|
|
105
|
+
S.addEdge(b, S.exitBlock, 'return');
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function handleThrow(n: TreeSitterNode, b: CfgBlockInternal, S: FuncState): null {
|
|
110
|
+
b.endLine = n.startPosition.row + 1;
|
|
111
|
+
S.addEdge(b, S.exitBlock, 'exception');
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Lookup structure for statement dispatch.
|
|
117
|
+
* - `map`: O(1) lookup for single-type matchers (one concrete node-type string per handler).
|
|
118
|
+
* - `fallback`: short linear scan for multi-predicate entries (if/for/while/switch rules that
|
|
119
|
+
* match multiple concrete type strings depending on the language).
|
|
120
|
+
*/
|
|
121
|
+
interface StatementDispatch {
|
|
122
|
+
map: Map<string, StatementHandler>;
|
|
123
|
+
fallback: StatementEntry[];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Build a dispatch table for statement node types from cfgRules.
|
|
128
|
+
* Built once per createCfgVisitor call; optional entries (doNode, infiniteLoopNode,
|
|
129
|
+
* tryNode) are included only when the language rules define them.
|
|
130
|
+
*
|
|
131
|
+
* Single-type matchers go into a Map for O(1) lookup; multi-predicate entries
|
|
132
|
+
* (isIfNode, isForNode, isWhileNode, isSwitchNode) stay in a short fallback array
|
|
133
|
+
* scanned only on a map miss.
|
|
134
|
+
*/
|
|
135
|
+
function buildStatementDispatch(
|
|
136
|
+
cfgRules: AnyRules,
|
|
137
|
+
processLabeledFn: (
|
|
138
|
+
n: TreeSitterNode,
|
|
139
|
+
b: CfgBlockInternal,
|
|
140
|
+
S: FuncState,
|
|
141
|
+
) => CfgBlockInternal | null,
|
|
142
|
+
): StatementDispatch {
|
|
143
|
+
const map = new Map<string, StatementHandler>();
|
|
144
|
+
|
|
145
|
+
// Single-type required matchers
|
|
146
|
+
if (cfgRules.labeledNode) map.set(cfgRules.labeledNode, (n, b, S) => processLabeledFn(n, b, S));
|
|
147
|
+
if (cfgRules.returnNode) map.set(cfgRules.returnNode, handleReturn);
|
|
148
|
+
if (cfgRules.throwNode) map.set(cfgRules.throwNode, handleThrow);
|
|
149
|
+
if (cfgRules.breakNode) map.set(cfgRules.breakNode, (n, b, S) => processBreak(n, b, S));
|
|
150
|
+
if (cfgRules.continueNode) map.set(cfgRules.continueNode, (n, b, S) => processContinue(n, b, S));
|
|
151
|
+
|
|
152
|
+
// Single-type optional matchers
|
|
153
|
+
if (cfgRules.doNode)
|
|
154
|
+
map.set(cfgRules.doNode, (n, b, S, r, ps) => processDoWhileLoop(n, b, S, r, ps));
|
|
155
|
+
if (cfgRules.infiniteLoopNode)
|
|
156
|
+
map.set(cfgRules.infiniteLoopNode, (n, b, S, r, ps) => processInfiniteLoop(n, b, S, r, ps));
|
|
157
|
+
if (cfgRules.tryNode)
|
|
158
|
+
map.set(cfgRules.tryNode, (n, b, S, r, ps) => processTryCatch(n, b, S, r, ps));
|
|
159
|
+
|
|
160
|
+
// Multi-predicate entries that can match several concrete type strings per language;
|
|
161
|
+
// also handles unlessNode/untilNode aliases for if/while which may collide with other
|
|
162
|
+
// single-type map keys.
|
|
163
|
+
const fallback: StatementEntry[] = [
|
|
164
|
+
{
|
|
165
|
+
match: (t) => isIfNode(t, cfgRules) || (!!cfgRules.unlessNode && t === cfgRules.unlessNode),
|
|
166
|
+
handle: (n, b, S, r, ps) => processIf(n, b, S, r, ps),
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
match: (t) => isForNode(t, cfgRules),
|
|
170
|
+
handle: (n, b, S, r, ps) => processForLoop(n, b, S, r, ps),
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
match: (t) => isWhileNode(t, cfgRules) || (!!cfgRules.untilNode && t === cfgRules.untilNode),
|
|
174
|
+
handle: (n, b, S, r, ps) => processWhileLoop(n, b, S, r, ps),
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
match: (t) => isSwitchNode(t, cfgRules),
|
|
178
|
+
handle: (n, b, S, r, ps) => processSwitch(n, b, S, r, ps),
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
|
|
182
|
+
return { map, fallback };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ─── Bound statement processors ──────────────────────────────────────────
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Build {processStatement, processStatements} bound to cfgRules and a
|
|
189
|
+
* pre-built dispatch table. The two functions are mutually recursive via
|
|
190
|
+
* the closure — no cfgRules arguments needed at call sites inside the visitor.
|
|
191
|
+
*/
|
|
192
|
+
function buildStatementProcessors(cfgRules: AnyRules): {
|
|
193
|
+
processStatement: (
|
|
194
|
+
stmt: TreeSitterNode,
|
|
195
|
+
currentBlock: CfgBlockInternal,
|
|
196
|
+
S: FuncState,
|
|
197
|
+
) => CfgBlockInternal | null;
|
|
198
|
+
processStatements: BoundProcessStatements;
|
|
199
|
+
} {
|
|
200
|
+
// processLabeled needs processStatement from this closure, so we forward-declare
|
|
201
|
+
// it and patch it in after processStatement is defined.
|
|
202
|
+
let processStatementRef: (
|
|
203
|
+
stmt: TreeSitterNode,
|
|
204
|
+
block: CfgBlockInternal,
|
|
205
|
+
S: FuncState,
|
|
206
|
+
) => CfgBlockInternal | null;
|
|
207
|
+
|
|
208
|
+
function processLabeled(
|
|
209
|
+
node: TreeSitterNode,
|
|
210
|
+
currentBlock: CfgBlockInternal,
|
|
211
|
+
S: FuncState,
|
|
212
|
+
): CfgBlockInternal | null {
|
|
213
|
+
const labelNode = node.childForFieldName('label');
|
|
214
|
+
const labelName = labelNode ? labelNode.text : null;
|
|
215
|
+
const body = node.childForFieldName('body');
|
|
216
|
+
if (body && labelName) {
|
|
217
|
+
const labelCtx: LabelCtx = { headerBlock: null, exitBlock: null };
|
|
218
|
+
S.labelMap.set(labelName, labelCtx);
|
|
219
|
+
const result = processStatementRef(body, currentBlock, S);
|
|
220
|
+
S.labelMap.delete(labelName);
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
return currentBlock;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
const dispatch = buildStatementDispatch(cfgRules, processLabeled);
|
|
227
|
+
|
|
228
|
+
function processStatement(
|
|
229
|
+
stmt: TreeSitterNode,
|
|
230
|
+
currentBlock: CfgBlockInternal,
|
|
231
|
+
S: FuncState,
|
|
232
|
+
): CfgBlockInternal | null {
|
|
233
|
+
if (!stmt || !currentBlock) return currentBlock;
|
|
234
|
+
|
|
235
|
+
const effNode = effectiveNode(stmt, cfgRules);
|
|
236
|
+
const type = effNode.type;
|
|
237
|
+
|
|
238
|
+
// O(1) map lookup first; fall back to the short multi-predicate array on a miss
|
|
239
|
+
const mapHandler = dispatch.map.get(type);
|
|
240
|
+
if (mapHandler) return mapHandler(effNode, currentBlock, S, cfgRules, processStatements);
|
|
241
|
+
const fallbackEntry = dispatch.fallback.find((e) => e.match(type));
|
|
242
|
+
if (fallbackEntry)
|
|
243
|
+
return fallbackEntry.handle(effNode, currentBlock, S, cfgRules, processStatements);
|
|
244
|
+
|
|
245
|
+
if (!currentBlock.startLine) {
|
|
246
|
+
currentBlock.startLine = stmt.startPosition.row + 1;
|
|
247
|
+
}
|
|
248
|
+
currentBlock.endLine = stmt.endPosition.row + 1;
|
|
249
|
+
return currentBlock;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Wire the forward reference so processLabeled can call processStatement
|
|
253
|
+
processStatementRef = processStatement;
|
|
254
|
+
|
|
255
|
+
function processStatements(
|
|
256
|
+
stmts: TreeSitterNode[],
|
|
257
|
+
currentBlock: CfgBlockInternal,
|
|
258
|
+
S: FuncState,
|
|
259
|
+
): CfgBlockInternal | null {
|
|
260
|
+
let cur: CfgBlockInternal | null = currentBlock;
|
|
261
|
+
for (const stmt of stmts) {
|
|
262
|
+
if (!cur) break;
|
|
263
|
+
cur = processStatement(stmt, cur, S);
|
|
264
|
+
}
|
|
265
|
+
return cur;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return { processStatement, processStatements };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ─── Function body walker ────────────────────────────────────────────────
|
|
272
|
+
|
|
273
|
+
function processFunctionBody(
|
|
274
|
+
funcNode: TreeSitterNode,
|
|
275
|
+
S: FuncState,
|
|
276
|
+
cfgRules: AnyRules,
|
|
277
|
+
processStatements: BoundProcessStatements,
|
|
278
|
+
): void {
|
|
169
279
|
const body = funcNode.childForFieldName('body');
|
|
170
280
|
if (!body) {
|
|
171
281
|
S.blocks.length = 2;
|
|
@@ -194,18 +304,22 @@ function processFunctionBody(funcNode: TreeSitterNode, S: FuncState, cfgRules: A
|
|
|
194
304
|
}
|
|
195
305
|
|
|
196
306
|
const firstBody = S.blocks[2]!;
|
|
197
|
-
const lastBlock = processStatements(stmts, firstBody, S
|
|
307
|
+
const lastBlock = processStatements(stmts, firstBody, S);
|
|
198
308
|
if (lastBlock) {
|
|
199
309
|
S.addEdge(lastBlock, S.exitBlock, 'fallthrough');
|
|
200
310
|
}
|
|
201
311
|
S.currentBlock = null;
|
|
202
312
|
}
|
|
203
313
|
|
|
314
|
+
// ─── Public visitor factory ───────────────────────────────────────────────
|
|
315
|
+
|
|
204
316
|
export function createCfgVisitor(cfgRules: AnyRules): Visitor {
|
|
205
317
|
const funcStateStack: FuncState[] = [];
|
|
206
318
|
let S: FuncState | null = null;
|
|
207
319
|
const results: CFGResultInternal[] = [];
|
|
208
320
|
|
|
321
|
+
const { processStatements } = buildStatementProcessors(cfgRules);
|
|
322
|
+
|
|
209
323
|
return {
|
|
210
324
|
name: 'cfg',
|
|
211
325
|
functionNodeTypes: cfgRules.functionNodes,
|
|
@@ -218,7 +332,7 @@ export function createCfgVisitor(cfgRules: AnyRules): Visitor {
|
|
|
218
332
|
if (S) funcStateStack.push(S);
|
|
219
333
|
S = makeFuncState();
|
|
220
334
|
S.funcNode = funcNode;
|
|
221
|
-
processFunctionBody(funcNode, S, cfgRules);
|
|
335
|
+
processFunctionBody(funcNode, S, cfgRules, processStatements);
|
|
222
336
|
},
|
|
223
337
|
|
|
224
338
|
exitFunction(
|
|
@@ -203,6 +203,43 @@ function classifyNode(
|
|
|
203
203
|
if (cRules.caseNodes.has(type) && node.childCount > 0) acc.cyclomatic++;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
+
/**
|
|
207
|
+
* Compute the effective nesting level for complexity classification.
|
|
208
|
+
*
|
|
209
|
+
* In file-level mode, funcDepth starts at 0 for the active function.
|
|
210
|
+
* In function-level mode, funcDepth starts at 1 for the root function
|
|
211
|
+
* (since enterFunction always increments it). Subtract 1 so the root
|
|
212
|
+
* function contributes 0 nesting and each nested level adds +1, matching
|
|
213
|
+
* the Rust engine's behavior.
|
|
214
|
+
*/
|
|
215
|
+
function computeEffectiveNesting(
|
|
216
|
+
contextNesting: number,
|
|
217
|
+
funcDepth: number,
|
|
218
|
+
nestingAdjust: number,
|
|
219
|
+
fileLevelWalk: boolean,
|
|
220
|
+
): number {
|
|
221
|
+
const funcNesting = fileLevelWalk ? funcDepth : Math.max(0, funcDepth - 1);
|
|
222
|
+
return contextNesting + funcNesting - nestingAdjust;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* If this node is an else-if that the walker treats as a nesting node but
|
|
227
|
+
* the DFS engine would NOT increment nesting for, track it so children see
|
|
228
|
+
* the correct (non-inflated) nesting level.
|
|
229
|
+
*/
|
|
230
|
+
function trackElseIfNestingAdjust(
|
|
231
|
+
node: TreeSitterNode,
|
|
232
|
+
cRules: AnyRules,
|
|
233
|
+
nestingAdjust: number,
|
|
234
|
+
adjustNodeIds: Set<number>,
|
|
235
|
+
): number {
|
|
236
|
+
if (cRules.nestingNodes.has(node.type) && isElseIfNonNesting(node, node.type, cRules)) {
|
|
237
|
+
adjustNodeIds.add(node.id);
|
|
238
|
+
return nestingAdjust + 1;
|
|
239
|
+
}
|
|
240
|
+
return nestingAdjust;
|
|
241
|
+
}
|
|
242
|
+
|
|
206
243
|
export function createComplexityVisitor(
|
|
207
244
|
cRules: AnyRules,
|
|
208
245
|
hRules?: AnyRules | null,
|
|
@@ -265,23 +302,14 @@ export function createComplexityVisitor(
|
|
|
265
302
|
enterNode(node: TreeSitterNode, context: VisitorContext): EnterNodeResult | undefined {
|
|
266
303
|
if (fileLevelWalk && !activeFuncNode) return;
|
|
267
304
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
const nestingLevel = context.nestingLevel + funcNesting - nestingAdjust;
|
|
305
|
+
const nestingLevel = computeEffectiveNesting(
|
|
306
|
+
context.nestingLevel,
|
|
307
|
+
funcDepth,
|
|
308
|
+
nestingAdjust,
|
|
309
|
+
fileLevelWalk,
|
|
310
|
+
);
|
|
275
311
|
classifyNode(node, nestingLevel, cRules, hRules, acc);
|
|
276
|
-
|
|
277
|
-
// If this is an else-if if_statement that the walker will treat as a
|
|
278
|
-
// nesting node (incrementing context.nestingLevel for children), but
|
|
279
|
-
// the DFS walk would NOT increment nesting for, compensate by bumping
|
|
280
|
-
// nestingAdjust so children see the correct level.
|
|
281
|
-
if (cRules.nestingNodes.has(node.type) && isElseIfNonNesting(node, node.type, cRules)) {
|
|
282
|
-
nestingAdjust++;
|
|
283
|
-
adjustNodeIds.add(node.id);
|
|
284
|
-
}
|
|
312
|
+
nestingAdjust = trackElseIfNestingAdjust(node, cRules, nestingAdjust, adjustNodeIds);
|
|
285
313
|
},
|
|
286
314
|
|
|
287
315
|
exitNode(node: TreeSitterNode): void {
|