@optave/codegraph 3.13.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 +35 -34
- 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/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +137 -134
- package/dist/cli/commands/config.js.map +1 -1
- 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/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 +68 -0
- 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 +17 -5
- package/dist/domain/graph/builder/call-resolver.d.ts.map +1 -1
- package/dist/domain/graph/builder/call-resolver.js +85 -220
- package/dist/domain/graph/builder/call-resolver.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 +16 -1
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +162 -72
- 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 +10 -4
- 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 +496 -250
- 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 +2 -1
- package/dist/domain/graph/builder/stages/detect-changes.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 +895 -545
- package/dist/domain/graph/builder/stages/native-orchestrator.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 +12 -0
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +12 -2
- 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 +3 -0
- 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 +24 -5
- package/dist/domain/wasm-worker-pool.js.map +1 -1
- package/dist/domain/wasm-worker-protocol.d.ts +7 -0
- package/dist/domain/wasm-worker-protocol.d.ts.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 +4 -2
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +5 -1
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.js +77 -1
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +549 -163
- 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.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/infrastructure/config.d.ts +10 -0
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +31 -3
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -7
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +29 -13
- 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/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 +76 -1
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-erlang.wasm +0 -0
- package/package.json +7 -7
- 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/config.ts +184 -184
- package/src/cli/commands/roles.ts +6 -1
- 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 +68 -0
- 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 +112 -232
- package/src/domain/graph/builder/context.ts +1 -0
- package/src/domain/graph/builder/helpers.ts +190 -72
- package/src/domain/graph/builder/incremental.ts +249 -120
- package/src/domain/graph/builder/pipeline.ts +11 -5
- package/src/domain/graph/builder/stages/build-edges.ts +696 -296
- package/src/domain/graph/builder/stages/collect-files.ts +12 -6
- package/src/domain/graph/builder/stages/detect-changes.ts +3 -1
- package/src/domain/graph/builder/stages/native-orchestrator.ts +1102 -590
- 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 +12 -2
- package/src/domain/queries.ts +1 -1
- package/src/domain/wasm-worker-entry.ts +3 -0
- package/src/domain/wasm-worker-pool.ts +28 -4
- package/src/domain/wasm-worker-protocol.ts +4 -0
- package/src/extractors/dart.ts +48 -3
- package/src/extractors/groovy.ts +62 -2
- package/src/extractors/helpers.ts +5 -2
- package/src/extractors/java.ts +80 -1
- package/src/extractors/javascript.ts +566 -161
- 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.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/infrastructure/config.ts +32 -3
- package/src/infrastructure/registry.ts +44 -20
- 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/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 +86 -1
package/src/extractors/kotlin.ts
CHANGED
|
@@ -44,6 +44,9 @@ function walkKotlinNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
44
44
|
case 'navigation_expression':
|
|
45
45
|
handleKotlinNavExpression(node, ctx);
|
|
46
46
|
break;
|
|
47
|
+
case 'callable_reference':
|
|
48
|
+
handleKotlinCallableRef(node, ctx);
|
|
49
|
+
break;
|
|
47
50
|
}
|
|
48
51
|
|
|
49
52
|
for (let i = 0; i < node.childCount; i++) {
|
|
@@ -270,7 +273,10 @@ function handleKotlinCallExpression(node: TreeSitterNode, ctx: ExtractorOutput):
|
|
|
270
273
|
const funcNode = node.child(0);
|
|
271
274
|
if (!funcNode) return;
|
|
272
275
|
if (funcNode.type === 'simple_identifier') {
|
|
273
|
-
|
|
276
|
+
const name = funcNode.text;
|
|
277
|
+
// Bare invoke() with no receiver is a resolvable operator fun invoke() self-call —
|
|
278
|
+
// only flag as unresolved-dynamic when called on a receiver (handled in handleKotlinNavExpression).
|
|
279
|
+
ctx.calls.push({ name, line: node.startPosition.row + 1 });
|
|
274
280
|
}
|
|
275
281
|
}
|
|
276
282
|
|
|
@@ -280,12 +286,60 @@ function handleKotlinNavExpression(node: TreeSitterNode, ctx: ExtractorOutput):
|
|
|
280
286
|
const lastChild = node.child(node.childCount - 1);
|
|
281
287
|
const firstChild = node.child(0);
|
|
282
288
|
if (lastChild && lastChild.type === 'simple_identifier' && firstChild) {
|
|
283
|
-
const
|
|
284
|
-
|
|
289
|
+
const methodName = lastChild.text;
|
|
290
|
+
const receiver = firstChild.text;
|
|
291
|
+
// fn.invoke(args) on a Kotlin callable — unresolvable without type info
|
|
292
|
+
if (methodName === 'invoke') {
|
|
293
|
+
ctx.calls.push({
|
|
294
|
+
name: '<dynamic:unresolved>',
|
|
295
|
+
line: node.startPosition.row + 1,
|
|
296
|
+
dynamic: true,
|
|
297
|
+
dynamicKind: 'unresolved-dynamic',
|
|
298
|
+
receiver,
|
|
299
|
+
});
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const call: Call = { name: methodName, line: node.startPosition.row + 1 };
|
|
303
|
+
call.receiver = receiver;
|
|
285
304
|
ctx.calls.push(call);
|
|
286
305
|
}
|
|
287
306
|
}
|
|
288
307
|
|
|
308
|
+
/**
|
|
309
|
+
* Handle Kotlin callable references: `::greet` and `obj::method`.
|
|
310
|
+
* Emits a reflection-kind call with the referenced member name.
|
|
311
|
+
*/
|
|
312
|
+
function handleKotlinCallableRef(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
313
|
+
// callable_reference: [qualifier '::'] simple_identifier
|
|
314
|
+
// Find the simple_identifier after '::'
|
|
315
|
+
let foundDoubleColon = false;
|
|
316
|
+
let qualifier: string | undefined;
|
|
317
|
+
for (let i = 0; i < node.childCount; i++) {
|
|
318
|
+
const child = node.child(i);
|
|
319
|
+
if (!child) continue;
|
|
320
|
+
if (child.type === '::') {
|
|
321
|
+
foundDoubleColon = true;
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
if (!foundDoubleColon) {
|
|
325
|
+
// Everything before '::' is the qualifier
|
|
326
|
+
if (child.type === 'simple_identifier' || child.type === 'type_identifier') {
|
|
327
|
+
qualifier = child.text;
|
|
328
|
+
}
|
|
329
|
+
} else if (child.type === 'simple_identifier') {
|
|
330
|
+
// The member name
|
|
331
|
+
ctx.calls.push({
|
|
332
|
+
name: child.text,
|
|
333
|
+
line: node.startPosition.row + 1,
|
|
334
|
+
dynamic: true,
|
|
335
|
+
dynamicKind: 'reflection',
|
|
336
|
+
receiver: qualifier,
|
|
337
|
+
});
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
289
343
|
// ── Child extraction helpers ────────────────────────────────────────────────
|
|
290
344
|
|
|
291
345
|
function extractKotlinParameters(funcNode: TreeSitterNode): SubDeclaration[] {
|
package/src/extractors/objc.ts
CHANGED
|
@@ -336,7 +336,19 @@ function handleCCallExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
336
336
|
} else {
|
|
337
337
|
call.name = funcNode.text;
|
|
338
338
|
}
|
|
339
|
-
if (call.name)
|
|
339
|
+
if (!call.name) return;
|
|
340
|
+
// objc_msgSend(obj, sel, ...) — raw ObjC runtime call; selector is a SEL value
|
|
341
|
+
if (call.name === 'objc_msgSend') {
|
|
342
|
+
ctx.calls.push({
|
|
343
|
+
name: '<dynamic:unresolved>',
|
|
344
|
+
line: call.line,
|
|
345
|
+
dynamic: true,
|
|
346
|
+
dynamicKind: 'unresolved-dynamic',
|
|
347
|
+
receiver: call.receiver,
|
|
348
|
+
});
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
ctx.calls.push(call);
|
|
340
352
|
}
|
|
341
353
|
|
|
342
354
|
function handleMessageExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
@@ -368,6 +380,18 @@ function handleMessageExpr(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
368
380
|
name = selector.text;
|
|
369
381
|
}
|
|
370
382
|
|
|
383
|
+
// performSelector: / performSelector:withObject: — SEL dispatch; not statically resolvable
|
|
384
|
+
if (name === 'performSelector:' || name.startsWith('performSelector:withObject')) {
|
|
385
|
+
ctx.calls.push({
|
|
386
|
+
name: '<dynamic:unresolved>',
|
|
387
|
+
line: node.startPosition.row + 1,
|
|
388
|
+
dynamic: true,
|
|
389
|
+
dynamicKind: 'unresolved-dynamic',
|
|
390
|
+
receiver: receiver?.text,
|
|
391
|
+
});
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
|
|
371
395
|
const call: Call = { name, line: node.startPosition.row + 1 };
|
|
372
396
|
if (receiver) call.receiver = receiver.text;
|
|
373
397
|
ctx.calls.push(call);
|
package/src/extractors/scala.ts
CHANGED
|
@@ -142,6 +142,23 @@ function handleScalaImportDecl(node: TreeSitterNode, ctx: ExtractorOutput): void
|
|
|
142
142
|
});
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
/** Extract the first string literal argument from a Scala call_expression. */
|
|
146
|
+
function getFirstStringArgScala(node: TreeSitterNode): string | null {
|
|
147
|
+
const args = node.childForFieldName('arguments') || findChild(node, 'arguments');
|
|
148
|
+
if (!args) return null;
|
|
149
|
+
for (let i = 0; i < args.childCount; i++) {
|
|
150
|
+
const child = args.child(i);
|
|
151
|
+
if (!child) continue;
|
|
152
|
+
const t = child.type;
|
|
153
|
+
if (t === '(' || t === ')' || t === ',') continue;
|
|
154
|
+
if (t === 'string' || t === 'string_literal') {
|
|
155
|
+
return child.text.replace(/^["']|["']$/g, '');
|
|
156
|
+
}
|
|
157
|
+
break;
|
|
158
|
+
}
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
|
|
145
162
|
function handleScalaCallExpression(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
146
163
|
const funcNode = node.childForFieldName('function');
|
|
147
164
|
if (!funcNode) return;
|
|
@@ -154,7 +171,52 @@ function handleScalaCallExpression(node: TreeSitterNode, ctx: ExtractorOutput):
|
|
|
154
171
|
} else {
|
|
155
172
|
call.name = funcNode.text;
|
|
156
173
|
}
|
|
157
|
-
if (call.name)
|
|
174
|
+
if (!call.name) return;
|
|
175
|
+
|
|
176
|
+
// method.invoke(target, args) — Java/Scala reflection; target unknown statically.
|
|
177
|
+
// Require a non-null receiver to avoid false positives on user-defined `invoke` methods.
|
|
178
|
+
if (call.name === 'invoke' && call.receiver !== undefined) {
|
|
179
|
+
ctx.calls.push({
|
|
180
|
+
name: '<dynamic:unresolved>',
|
|
181
|
+
line: call.line,
|
|
182
|
+
dynamic: true,
|
|
183
|
+
dynamicKind: 'unresolved-dynamic',
|
|
184
|
+
receiver: call.receiver,
|
|
185
|
+
});
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// clazz.getMethod("name") / getDeclaredMethod("name") — resolvable if literal.
|
|
190
|
+
// Require a non-null receiver to avoid false positives on gRPC ServiceDescriptor.getMethod(),
|
|
191
|
+
// Spring AnnotationUtils.getDeclaredMethod(), proto-generated descriptors, and any other API
|
|
192
|
+
// that exposes a method by this name unrelated to java.lang.Class reflection.
|
|
193
|
+
if (
|
|
194
|
+
(call.name === 'getMethod' || call.name === 'getDeclaredMethod') &&
|
|
195
|
+
call.receiver !== undefined
|
|
196
|
+
) {
|
|
197
|
+
const literal = getFirstStringArgScala(node);
|
|
198
|
+
if (literal) {
|
|
199
|
+
ctx.calls.push({
|
|
200
|
+
name: literal,
|
|
201
|
+
line: call.line,
|
|
202
|
+
dynamic: true,
|
|
203
|
+
dynamicKind: 'reflection',
|
|
204
|
+
keyExpr: literal,
|
|
205
|
+
receiver: call.receiver,
|
|
206
|
+
});
|
|
207
|
+
} else {
|
|
208
|
+
ctx.calls.push({
|
|
209
|
+
name: '<dynamic:computed-key>',
|
|
210
|
+
line: call.line,
|
|
211
|
+
dynamic: true,
|
|
212
|
+
dynamicKind: 'computed-key',
|
|
213
|
+
receiver: call.receiver,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
ctx.calls.push(call);
|
|
158
220
|
}
|
|
159
221
|
|
|
160
222
|
function handleScalaValVarDef(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
package/src/extractors/swift.ts
CHANGED
|
@@ -42,6 +42,7 @@ function walkSwiftNode(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
|
42
42
|
handleSwiftCallExpression(node, ctx);
|
|
43
43
|
break;
|
|
44
44
|
case 'property_declaration':
|
|
45
|
+
seedSwiftPropertyTypeMap(node, ctx);
|
|
45
46
|
handleSwiftPropertyDecl(node, ctx);
|
|
46
47
|
break;
|
|
47
48
|
}
|
|
@@ -250,11 +251,26 @@ function handleSwiftCallExpression(node: TreeSitterNode, ctx: ExtractorOutput):
|
|
|
250
251
|
if (!funcNode) return;
|
|
251
252
|
const call: Call = { name: '', line: node.startPosition.row + 1 };
|
|
252
253
|
if (funcNode.type === 'navigation_expression') {
|
|
253
|
-
// obj.method(...)
|
|
254
|
+
// obj.method(...) — Swift's tree-sitter grammar wraps the suffix in a
|
|
255
|
+
// `navigation_suffix` node: navigation_expression > [simple_identifier, navigation_suffix].
|
|
256
|
+
// We must descend into navigation_suffix to get the bare method name (e.g. "save" not ".save").
|
|
257
|
+
// Mirrors Rust match_swift_node which also descends into navigation_suffix via find_child
|
|
258
|
+
// to extract the inner simple_identifier, with a trim_start_matches('.') fallback.
|
|
254
259
|
const lastChild = funcNode.child(funcNode.childCount - 1);
|
|
255
260
|
const firstChild = funcNode.child(0);
|
|
256
|
-
if (lastChild &&
|
|
257
|
-
|
|
261
|
+
if (lastChild && firstChild) {
|
|
262
|
+
// Resolve the method name: descend into navigation_suffix to find the
|
|
263
|
+
// simple_identifier, or fall back to stripping the leading dot from the text.
|
|
264
|
+
let methodName: string;
|
|
265
|
+
if (lastChild.type === 'simple_identifier') {
|
|
266
|
+
methodName = lastChild.text;
|
|
267
|
+
} else if (lastChild.type === 'navigation_suffix') {
|
|
268
|
+
const inner = findChild(lastChild, 'simple_identifier');
|
|
269
|
+
methodName = inner ? inner.text : lastChild.text.replace(/^\./, '');
|
|
270
|
+
} else {
|
|
271
|
+
methodName = lastChild.text;
|
|
272
|
+
}
|
|
273
|
+
call.name = methodName;
|
|
258
274
|
call.receiver = firstChild.text;
|
|
259
275
|
}
|
|
260
276
|
} else if (funcNode.type === 'simple_identifier') {
|
|
@@ -265,6 +281,33 @@ function handleSwiftCallExpression(node: TreeSitterNode, ctx: ExtractorOutput):
|
|
|
265
281
|
if (call.name) ctx.calls.push(call);
|
|
266
282
|
}
|
|
267
283
|
|
|
284
|
+
/**
|
|
285
|
+
* Seed the typeMap for a property_declaration with a type annotation.
|
|
286
|
+
* This runs for ALL property_declaration nodes (including class-body ones)
|
|
287
|
+
* so that `repo.method()` calls can be resolved to the correct class.
|
|
288
|
+
* Mirrors Rust match_swift_type_map which walks all nodes unconditionally.
|
|
289
|
+
*/
|
|
290
|
+
function seedSwiftPropertyTypeMap(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
291
|
+
const typeAnn = findChild(node, 'type_annotation');
|
|
292
|
+
if (!typeAnn) return;
|
|
293
|
+
// type_annotation: ":" <user_type | simple_identifier | ...>
|
|
294
|
+
// The last child is the actual type node.
|
|
295
|
+
const lastChild = typeAnn.child(typeAnn.childCount - 1);
|
|
296
|
+
if (!lastChild) return;
|
|
297
|
+
// For "user_type > type_identifier", grab the inner identifier text;
|
|
298
|
+
// for a plain simple_identifier, use it directly.
|
|
299
|
+
const typeNode =
|
|
300
|
+
lastChild.type === 'user_type' ? findChild(lastChild, 'type_identifier') : lastChild;
|
|
301
|
+
if (!typeNode) return;
|
|
302
|
+
const typeName = typeNode.text;
|
|
303
|
+
if (!typeName) return;
|
|
304
|
+
const pattern = findChild(node, 'pattern');
|
|
305
|
+
if (!pattern) return;
|
|
306
|
+
const varName = findChild(pattern, 'simple_identifier')?.text ?? pattern.text;
|
|
307
|
+
if (!varName) return;
|
|
308
|
+
ctx.typeMap.set(varName, { type: typeName, confidence: 0.9 });
|
|
309
|
+
}
|
|
310
|
+
|
|
268
311
|
function handleSwiftPropertyDecl(node: TreeSitterNode, ctx: ExtractorOutput): void {
|
|
269
312
|
// Only handle top-level properties (class properties are handled inline)
|
|
270
313
|
if (
|
package/src/features/audit.ts
CHANGED
|
@@ -289,6 +289,46 @@ interface FileSymbol {
|
|
|
289
289
|
signature?: string | null;
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
/** Query callees, callers, and related test files for a node. */
|
|
293
|
+
function querySymbolEdges(
|
|
294
|
+
db: BetterSqlite3Database,
|
|
295
|
+
nodeId: number,
|
|
296
|
+
noTests: boolean,
|
|
297
|
+
): { callees: SymbolRef[]; callers: SymbolRef[]; relatedTests: { file: string }[] } {
|
|
298
|
+
const callees = (
|
|
299
|
+
db
|
|
300
|
+
.prepare(
|
|
301
|
+
`SELECT n.name, n.kind, n.file, n.line
|
|
302
|
+
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
303
|
+
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
304
|
+
)
|
|
305
|
+
.all(nodeId) as SymbolRef[]
|
|
306
|
+
).map(toSymbolRef);
|
|
307
|
+
|
|
308
|
+
let callers = (
|
|
309
|
+
db
|
|
310
|
+
.prepare(
|
|
311
|
+
`SELECT n.name, n.kind, n.file, n.line
|
|
312
|
+
FROM edges e JOIN nodes n ON e.source_id = n.id
|
|
313
|
+
WHERE e.target_id = ? AND e.kind = 'calls'`,
|
|
314
|
+
)
|
|
315
|
+
.all(nodeId) as SymbolRef[]
|
|
316
|
+
).map(toSymbolRef);
|
|
317
|
+
if (noTests) callers = callers.filter((c) => !isTestFile(c.file));
|
|
318
|
+
|
|
319
|
+
const testCallerRows = db
|
|
320
|
+
.prepare(
|
|
321
|
+
`SELECT DISTINCT n.file FROM edges e JOIN nodes n ON e.source_id = n.id
|
|
322
|
+
WHERE e.target_id = ? AND e.kind = 'calls'`,
|
|
323
|
+
)
|
|
324
|
+
.all(nodeId) as { file: string }[];
|
|
325
|
+
const relatedTests = testCallerRows
|
|
326
|
+
.filter((r) => isTestFile(r.file))
|
|
327
|
+
.map((r) => ({ file: r.file }));
|
|
328
|
+
|
|
329
|
+
return { callees, callers, relatedTests };
|
|
330
|
+
}
|
|
331
|
+
|
|
292
332
|
function enrichSymbol(
|
|
293
333
|
db: BetterSqlite3Database,
|
|
294
334
|
sym: FileSymbol,
|
|
@@ -305,40 +345,9 @@ function enrichSymbol(
|
|
|
305
345
|
const endLine = nodeRow?.end_line || null;
|
|
306
346
|
const lineCount = endLine ? endLine - sym.line + 1 : null;
|
|
307
347
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
let relatedTests: { file: string }[] = [];
|
|
312
|
-
if (nodeId) {
|
|
313
|
-
callees = (
|
|
314
|
-
db
|
|
315
|
-
.prepare(
|
|
316
|
-
`SELECT n.name, n.kind, n.file, n.line
|
|
317
|
-
FROM edges e JOIN nodes n ON e.target_id = n.id
|
|
318
|
-
WHERE e.source_id = ? AND e.kind = 'calls'`,
|
|
319
|
-
)
|
|
320
|
-
.all(nodeId) as SymbolRef[]
|
|
321
|
-
).map(toSymbolRef);
|
|
322
|
-
|
|
323
|
-
callers = (
|
|
324
|
-
db
|
|
325
|
-
.prepare(
|
|
326
|
-
`SELECT n.name, n.kind, n.file, n.line
|
|
327
|
-
FROM edges e JOIN nodes n ON e.source_id = n.id
|
|
328
|
-
WHERE e.target_id = ? AND e.kind = 'calls'`,
|
|
329
|
-
)
|
|
330
|
-
.all(nodeId) as SymbolRef[]
|
|
331
|
-
).map(toSymbolRef);
|
|
332
|
-
if (noTests) callers = callers.filter((c) => !isTestFile(c.file));
|
|
333
|
-
|
|
334
|
-
const testCallerRows = db
|
|
335
|
-
.prepare(
|
|
336
|
-
`SELECT DISTINCT n.file FROM edges e JOIN nodes n ON e.source_id = n.id
|
|
337
|
-
WHERE e.target_id = ? AND e.kind = 'calls'`,
|
|
338
|
-
)
|
|
339
|
-
.all(nodeId) as { file: string }[];
|
|
340
|
-
relatedTests = testCallerRows.filter((r) => isTestFile(r.file)).map((r) => ({ file: r.file }));
|
|
341
|
-
}
|
|
348
|
+
const { callees, callers, relatedTests } = nodeId
|
|
349
|
+
? querySymbolEdges(db, nodeId, noTests)
|
|
350
|
+
: { callees: [], callers: [], relatedTests: [] };
|
|
342
351
|
|
|
343
352
|
const health = nodeId ? buildHealth(db, nodeId, thresholds) : defaultHealth();
|
|
344
353
|
const impact = nodeId
|
|
@@ -174,6 +174,21 @@ export function validateBoundaryConfig(config: unknown): { valid: boolean; error
|
|
|
174
174
|
|
|
175
175
|
// ─── Preset Rule Generation ─────────────────────────────────────────
|
|
176
176
|
|
|
177
|
+
/** Collect the names of all modules assigned to layers outer than `layerIdx`. */
|
|
178
|
+
function collectOuterModules(
|
|
179
|
+
modulesByLayer: Map<string, string[]>,
|
|
180
|
+
layerIndex: Map<string, number>,
|
|
181
|
+
layerIdx: number,
|
|
182
|
+
): string[] {
|
|
183
|
+
const outer: string[] = [];
|
|
184
|
+
for (const [otherLayer, otherModNames] of modulesByLayer) {
|
|
185
|
+
if (layerIndex.get(otherLayer)! > layerIdx) {
|
|
186
|
+
outer.push(...otherModNames);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
return outer;
|
|
190
|
+
}
|
|
191
|
+
|
|
177
192
|
function generatePresetRules(
|
|
178
193
|
modules: Map<string, ResolvedModule>,
|
|
179
194
|
presetName: string,
|
|
@@ -181,8 +196,7 @@ function generatePresetRules(
|
|
|
181
196
|
const preset = PRESETS[presetName];
|
|
182
197
|
if (!preset) return [];
|
|
183
198
|
|
|
184
|
-
const
|
|
185
|
-
const layerIndex = new Map<string, number>(layers.map((l, i) => [l, i]));
|
|
199
|
+
const layerIndex = new Map<string, number>(preset.layers.map((l, i) => [l, i]));
|
|
186
200
|
|
|
187
201
|
const modulesByLayer = new Map<string, string[]>();
|
|
188
202
|
for (const [name, mod] of modules) {
|
|
@@ -194,13 +208,7 @@ function generatePresetRules(
|
|
|
194
208
|
|
|
195
209
|
const rules: BoundaryRule[] = [];
|
|
196
210
|
for (const [layer, modNames] of modulesByLayer) {
|
|
197
|
-
const
|
|
198
|
-
const outerModules: string[] = [];
|
|
199
|
-
for (const [otherLayer, otherModNames] of modulesByLayer) {
|
|
200
|
-
if (layerIndex.get(otherLayer)! > idx) {
|
|
201
|
-
outerModules.push(...otherModNames);
|
|
202
|
-
}
|
|
203
|
-
}
|
|
211
|
+
const outerModules = collectOuterModules(modulesByLayer, layerIndex, layerIndex.get(layer)!);
|
|
204
212
|
if (outerModules.length > 0) {
|
|
205
213
|
for (const from of modNames) {
|
|
206
214
|
rules.push({ from, notTo: outerModules });
|
package/src/features/cfg.ts
CHANGED
|
@@ -136,6 +136,35 @@ async function initCfgParsers(
|
|
|
136
136
|
return { parsers, getParserFn };
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/** Parse source via WASM when no native CFG data is available.
|
|
140
|
+
* Returns the parsed tree or undefined on any read/parse failure. */
|
|
141
|
+
function parseTreeForCfg(
|
|
142
|
+
relPath: string,
|
|
143
|
+
rootDir: string,
|
|
144
|
+
_langId: string,
|
|
145
|
+
parsers: unknown,
|
|
146
|
+
getParserFn: unknown,
|
|
147
|
+
): { rootNode: TreeSitterNode } | undefined {
|
|
148
|
+
const absPath = path.join(rootDir, relPath);
|
|
149
|
+
let code: string;
|
|
150
|
+
try {
|
|
151
|
+
code = fs.readFileSync(absPath, 'utf-8');
|
|
152
|
+
} catch (e) {
|
|
153
|
+
debug(`cfg: cannot read ${relPath}: ${(e as Error).message}`);
|
|
154
|
+
return undefined;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const parser = (getParserFn as (parsers: unknown, absPath: string) => unknown)(parsers, absPath);
|
|
158
|
+
if (!parser) return undefined;
|
|
159
|
+
|
|
160
|
+
try {
|
|
161
|
+
return (parser as { parse: (code: string) => { rootNode: TreeSitterNode } }).parse(code);
|
|
162
|
+
} catch (e) {
|
|
163
|
+
debug(`cfg: parse failed for ${relPath}: ${(e as Error).message}`);
|
|
164
|
+
return undefined;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
139
168
|
function getTreeAndLang(
|
|
140
169
|
symbols: FileSymbols,
|
|
141
170
|
relPath: string,
|
|
@@ -152,28 +181,8 @@ function getTreeAndLang(
|
|
|
152
181
|
if (!getParserFn) return null;
|
|
153
182
|
langId = extToLang.get(ext);
|
|
154
183
|
if (!langId || !CFG_RULES.has(langId)) return null;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
let code: string;
|
|
158
|
-
try {
|
|
159
|
-
code = fs.readFileSync(absPath, 'utf-8');
|
|
160
|
-
} catch (e) {
|
|
161
|
-
debug(`cfg: cannot read ${relPath}: ${(e as Error).message}`);
|
|
162
|
-
return null;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const parser = (getParserFn as (parsers: unknown, absPath: string) => unknown)(
|
|
166
|
-
parsers,
|
|
167
|
-
absPath,
|
|
168
|
-
);
|
|
169
|
-
if (!parser) return null;
|
|
170
|
-
|
|
171
|
-
try {
|
|
172
|
-
tree = (parser as { parse: (code: string) => { rootNode: TreeSitterNode } }).parse(code);
|
|
173
|
-
} catch (e) {
|
|
174
|
-
debug(`cfg: parse failed for ${relPath}: ${(e as Error).message}`);
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
184
|
+
tree = parseTreeForCfg(relPath, rootDir, langId, parsers, getParserFn);
|
|
185
|
+
if (!tree) return null;
|
|
177
186
|
}
|
|
178
187
|
|
|
179
188
|
if (!langId) {
|
package/src/features/check.ts
CHANGED
|
@@ -25,6 +25,22 @@ interface ParsedDiff {
|
|
|
25
25
|
const HUNK_RE = /^@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/;
|
|
26
26
|
const NEW_FILE_RE = /^\+\+\+ b\/(.+)/;
|
|
27
27
|
|
|
28
|
+
/** Returns true if the diff line marks the old file as /dev/null (new-file creation). */
|
|
29
|
+
function isDevNullSourceLine(line: string): boolean {
|
|
30
|
+
return line.startsWith('--- /dev/null');
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** Returns true if the diff line is a `---` source file header (not /dev/null). */
|
|
34
|
+
function isSourceFileHeaderLine(line: string): boolean {
|
|
35
|
+
return line.startsWith('--- ');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Extracts the new filename from a `+++ b/<file>` diff header, or null. */
|
|
39
|
+
function extractNewFileName(line: string): string | null {
|
|
40
|
+
const m = line.match(NEW_FILE_RE);
|
|
41
|
+
return m ? m[1]! : null;
|
|
42
|
+
}
|
|
43
|
+
|
|
28
44
|
function pushHunkRanges(
|
|
29
45
|
line: string,
|
|
30
46
|
currentFile: string,
|
|
@@ -53,17 +69,17 @@ export function parseDiffOutput(diffOutput: string): ParsedDiff {
|
|
|
53
69
|
let prevIsDevNull = false;
|
|
54
70
|
|
|
55
71
|
for (const line of diffOutput.split('\n')) {
|
|
56
|
-
if (line
|
|
72
|
+
if (isDevNullSourceLine(line)) {
|
|
57
73
|
prevIsDevNull = true;
|
|
58
74
|
continue;
|
|
59
75
|
}
|
|
60
|
-
if (line
|
|
76
|
+
if (isSourceFileHeaderLine(line)) {
|
|
61
77
|
prevIsDevNull = false;
|
|
62
78
|
continue;
|
|
63
79
|
}
|
|
64
|
-
const
|
|
65
|
-
if (
|
|
66
|
-
currentFile =
|
|
80
|
+
const newFile = extractNewFileName(line);
|
|
81
|
+
if (newFile) {
|
|
82
|
+
currentFile = newFile;
|
|
67
83
|
if (!changedRanges.has(currentFile)) changedRanges.set(currentFile, []);
|
|
68
84
|
if (!oldRanges.has(currentFile)) oldRanges.set(currentFile, []);
|
|
69
85
|
if (prevIsDevNull) newFiles.add(currentFile);
|
|
@@ -146,33 +146,42 @@ function analyzeDrift(
|
|
|
146
146
|
|
|
147
147
|
// ─── Core Analysis ────────────────────────────────────────────────────
|
|
148
148
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
149
|
+
type CommunitiesDataOpts = {
|
|
150
|
+
functions?: boolean;
|
|
151
|
+
resolution?: number;
|
|
152
|
+
noTests?: boolean;
|
|
153
|
+
drift?: boolean;
|
|
154
|
+
json?: boolean;
|
|
155
|
+
config?: CodegraphConfig;
|
|
156
|
+
maxLevels?: number;
|
|
157
|
+
maxLocalPasses?: number;
|
|
158
|
+
refinementTheta?: number;
|
|
159
|
+
limit?: number;
|
|
160
|
+
offset?: number;
|
|
161
|
+
repo?: Repository;
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
/** Load dependency graph from the repo, then close the DB connection. */
|
|
165
|
+
function loadCommunityGraph(
|
|
166
|
+
customDbPath: string | undefined,
|
|
167
|
+
opts: CommunitiesDataOpts,
|
|
168
|
+
): CodeGraph {
|
|
166
169
|
const { repo, close } = openRepo(customDbPath, opts);
|
|
167
|
-
let graph: CodeGraph;
|
|
168
170
|
try {
|
|
169
|
-
|
|
171
|
+
return buildDependencyGraph(repo, {
|
|
170
172
|
fileLevel: !opts.functions,
|
|
171
173
|
noTests: opts.noTests,
|
|
172
174
|
});
|
|
173
175
|
} finally {
|
|
174
176
|
close();
|
|
175
177
|
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export function communitiesData(
|
|
181
|
+
customDbPath?: string,
|
|
182
|
+
opts: CommunitiesDataOpts = {},
|
|
183
|
+
): Record<string, unknown> {
|
|
184
|
+
const graph = loadCommunityGraph(customDbPath, opts);
|
|
176
185
|
|
|
177
186
|
if (graph.nodeCount === 0 || graph.edgeCount === 0) {
|
|
178
187
|
return {
|