@optave/codegraph 3.4.0 → 3.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +3 -9
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/shared.d.ts.map +1 -1
- package/dist/ast-analysis/shared.js +0 -1
- package/dist/ast-analysis/shared.js.map +1 -1
- package/dist/ast-analysis/visitors/cfg-conditionals.d.ts +5 -0
- package/dist/ast-analysis/visitors/cfg-conditionals.d.ts.map +1 -0
- package/dist/ast-analysis/visitors/cfg-conditionals.js +166 -0
- package/dist/ast-analysis/visitors/cfg-conditionals.js.map +1 -0
- package/dist/ast-analysis/visitors/cfg-loops.d.ts +7 -0
- package/dist/ast-analysis/visitors/cfg-loops.d.ts.map +1 -0
- package/dist/ast-analysis/visitors/cfg-loops.js +73 -0
- package/dist/ast-analysis/visitors/cfg-loops.js.map +1 -0
- package/dist/ast-analysis/visitors/cfg-shared.d.ts +56 -0
- package/dist/ast-analysis/visitors/cfg-shared.d.ts.map +1 -0
- package/dist/ast-analysis/visitors/cfg-shared.js +107 -0
- package/dist/ast-analysis/visitors/cfg-shared.js.map +1 -0
- package/dist/ast-analysis/visitors/cfg-try-catch.d.ts +4 -0
- package/dist/ast-analysis/visitors/cfg-try-catch.d.ts.map +1 -0
- package/dist/ast-analysis/visitors/cfg-try-catch.js +100 -0
- package/dist/ast-analysis/visitors/cfg-try-catch.js.map +1 -0
- package/dist/ast-analysis/visitors/cfg-visitor.d.ts +2 -2
- package/dist/ast-analysis/visitors/cfg-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/cfg-visitor.js +11 -445
- 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.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
- package/dist/cli/commands/batch.d.ts.map +1 -1
- package/dist/cli/commands/batch.js +4 -3
- package/dist/cli/commands/batch.js.map +1 -1
- package/dist/cli/commands/branch-compare.js +1 -1
- package/dist/cli/commands/branch-compare.js.map +1 -1
- package/dist/cli/commands/build.js +1 -1
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/info.d.ts.map +1 -1
- package/dist/cli/commands/info.js +1 -2
- package/dist/cli/commands/info.js.map +1 -1
- package/dist/cli/commands/path.d.ts.map +1 -1
- package/dist/cli/commands/path.js +7 -2
- package/dist/cli/commands/path.js.map +1 -1
- package/dist/cli/commands/plot.d.ts.map +1 -1
- package/dist/cli/commands/plot.js +2 -2
- package/dist/cli/commands/plot.js.map +1 -1
- package/dist/cli/commands/watch.js +1 -1
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/cli/index.js +2 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/shared/open-graph.d.ts +2 -2
- package/dist/cli/shared/open-graph.d.ts.map +1 -1
- package/dist/cli/shared/open-graph.js.map +1 -1
- package/dist/cli/types.d.ts +1 -1
- package/dist/cli/types.d.ts.map +1 -1
- package/dist/cli.js +2 -3
- package/dist/cli.js.map +1 -1
- package/dist/db/connection.d.ts +17 -0
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +91 -2
- 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 +7 -0
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/analysis/brief.d.ts.map +1 -1
- package/dist/domain/analysis/brief.js +1 -3
- package/dist/domain/analysis/brief.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +2 -4
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts +49 -0
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +145 -0
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +76 -0
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -0
- package/dist/domain/analysis/diff-impact.js +282 -0
- package/dist/domain/analysis/diff-impact.js.map +1 -0
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +0 -1
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +66 -0
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -0
- package/dist/domain/analysis/fn-impact.js +189 -0
- package/dist/domain/analysis/fn-impact.js.map +1 -0
- package/dist/domain/analysis/impact.d.ts +8 -148
- package/dist/domain/analysis/impact.d.ts.map +1 -1
- package/dist/domain/analysis/impact.js +8 -568
- package/dist/domain/analysis/impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +1 -3
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/graph/builder/context.d.ts +2 -3
- 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 +4 -5
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +1 -2
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts +2 -3
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- 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 +6 -0
- 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 +12 -2
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +155 -59
- package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +6 -6
- 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 +85 -61
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +58 -11
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/cycles.js +2 -2
- package/dist/domain/graph/cycles.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +10 -8
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +1 -3
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +11 -12
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/queries.d.ts +3 -2
- package/dist/domain/queries.d.ts.map +1 -1
- package/dist/domain/queries.js +3 -2
- package/dist/domain/queries.js.map +1 -1
- package/dist/domain/search/generator.d.ts.map +1 -1
- package/dist/domain/search/generator.js.map +1 -1
- package/dist/extractors/csharp.js +2 -2
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/go.js +2 -2
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/helpers.d.ts +5 -0
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +5 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/javascript.js +58 -60
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/php.js +2 -2
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.js +2 -2
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/rust.js +2 -2
- package/dist/extractors/rust.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +1 -2
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +2 -3
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +2 -4
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/cochange.js +4 -4
- package/dist/features/cochange.js.map +1 -1
- package/dist/features/communities.js +4 -4
- package/dist/features/communities.js.map +1 -1
- package/dist/features/complexity-query.d.ts +37 -0
- package/dist/features/complexity-query.d.ts.map +1 -0
- package/dist/features/complexity-query.js +263 -0
- package/dist/features/complexity-query.js.map +1 -0
- package/dist/features/complexity.d.ts +2 -30
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +7 -261
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +8 -24
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/export.d.ts +7 -8
- package/dist/features/export.d.ts.map +1 -1
- package/dist/features/export.js.map +1 -1
- package/dist/features/flow.d.ts.map +1 -1
- package/dist/features/flow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +1 -3
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/manifesto.js +8 -8
- package/dist/features/manifesto.js.map +1 -1
- package/dist/features/snapshot.d.ts.map +1 -1
- package/dist/features/snapshot.js +0 -1
- package/dist/features/snapshot.js.map +1 -1
- package/dist/features/structure-query.d.ts +76 -0
- package/dist/features/structure-query.d.ts.map +1 -0
- package/dist/features/structure-query.js +245 -0
- package/dist/features/structure-query.js.map +1 -0
- package/dist/features/structure.d.ts +12 -67
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +188 -244
- package/dist/features/structure.js.map +1 -1
- package/dist/features/triage.js +2 -2
- package/dist/features/triage.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +2 -9
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/classifiers/roles.d.ts +5 -1
- package/dist/graph/classifiers/roles.d.ts.map +1 -1
- package/dist/graph/classifiers/roles.js +20 -12
- package/dist/graph/classifiers/roles.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +12 -11
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/native.d.ts.map +1 -1
- package/dist/infrastructure/native.js +7 -3
- package/dist/infrastructure/native.js.map +1 -1
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +1 -1
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/infrastructure/update-check.js +3 -3
- package/dist/infrastructure/update-check.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +2 -8
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +9 -4
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/mcp/tools/audit.js +1 -1
- package/dist/mcp/tools/audit.js.map +1 -1
- package/dist/mcp/tools/cfg.js +1 -1
- package/dist/mcp/tools/cfg.js.map +1 -1
- package/dist/mcp/tools/check.js +2 -2
- package/dist/mcp/tools/check.js.map +1 -1
- package/dist/mcp/tools/dataflow.js +2 -2
- package/dist/mcp/tools/dataflow.js.map +1 -1
- package/dist/mcp/tools/export-graph.js +1 -1
- package/dist/mcp/tools/export-graph.js.map +1 -1
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/index.js.map +1 -1
- package/dist/mcp/tools/path.d.ts +1 -0
- package/dist/mcp/tools/path.d.ts.map +1 -1
- package/dist/mcp/tools/path.js +9 -0
- package/dist/mcp/tools/path.js.map +1 -1
- package/dist/mcp/tools/query.js +1 -1
- package/dist/mcp/tools/query.js.map +1 -1
- package/dist/mcp/tools/semantic-search.js +1 -1
- package/dist/mcp/tools/semantic-search.js.map +1 -1
- package/dist/mcp/tools/sequence.js +1 -1
- package/dist/mcp/tools/sequence.js.map +1 -1
- package/dist/mcp/tools/symbol-children.js +1 -1
- package/dist/mcp/tools/symbol-children.js.map +1 -1
- package/dist/mcp/tools/triage.js +1 -1
- package/dist/mcp/tools/triage.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +0 -1
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/diff-impact-mermaid.d.ts +11 -0
- package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -0
- package/dist/presentation/diff-impact-mermaid.js +105 -0
- package/dist/presentation/diff-impact-mermaid.js.map +1 -0
- package/dist/presentation/flow.d.ts.map +1 -1
- package/dist/presentation/flow.js +0 -2
- package/dist/presentation/flow.js.map +1 -1
- package/dist/presentation/manifesto.d.ts.map +1 -1
- package/dist/presentation/manifesto.js +0 -1
- package/dist/presentation/manifesto.js.map +1 -1
- package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
- package/dist/presentation/queries-cli/inspect.js.map +1 -1
- package/dist/presentation/queries-cli/path.d.ts.map +1 -1
- package/dist/presentation/queries-cli/path.js +45 -1
- package/dist/presentation/queries-cli/path.js.map +1 -1
- package/dist/presentation/result-formatter.d.ts.map +1 -1
- package/dist/presentation/result-formatter.js +1 -3
- package/dist/presentation/result-formatter.js.map +1 -1
- package/dist/presentation/sequence.d.ts.map +1 -1
- package/dist/presentation/sequence.js +0 -1
- package/dist/presentation/sequence.js.map +1 -1
- package/dist/presentation/structure.d.ts.map +1 -1
- package/dist/presentation/structure.js.map +1 -1
- package/dist/presentation/triage.d.ts.map +1 -1
- package/dist/presentation/triage.js +0 -1
- package/dist/presentation/triage.js.map +1 -1
- package/dist/shared/constants.d.ts +9 -3
- package/dist/shared/constants.d.ts.map +1 -1
- package/dist/shared/constants.js +6 -3
- package/dist/shared/constants.js.map +1 -1
- package/dist/shared/errors.d.ts +2 -0
- package/dist/shared/errors.d.ts.map +1 -1
- package/dist/shared/errors.js +4 -0
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/version.d.ts +2 -0
- package/dist/shared/version.d.ts.map +1 -0
- package/dist/shared/version.js +5 -0
- package/dist/shared/version.js.map +1 -0
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +8 -7
- package/src/ast-analysis/engine.ts +3 -9
- package/src/ast-analysis/shared.ts +0 -1
- package/src/ast-analysis/visitors/cfg-conditionals.ts +227 -0
- package/src/ast-analysis/visitors/cfg-loops.ts +136 -0
- package/src/ast-analysis/visitors/cfg-shared.ts +196 -0
- package/src/ast-analysis/visitors/cfg-try-catch.ts +142 -0
- package/src/ast-analysis/visitors/cfg-visitor.ts +34 -655
- package/src/ast-analysis/visitors/complexity-visitor.ts +0 -1
- package/src/ast-analysis/visitors/dataflow-visitor.ts +0 -1
- package/src/cli/commands/batch.ts +4 -3
- package/src/cli/commands/branch-compare.ts +1 -1
- package/src/cli/commands/build.ts +1 -1
- package/src/cli/commands/info.ts +1 -2
- package/src/cli/commands/path.ts +7 -2
- package/src/cli/commands/plot.ts +2 -2
- package/src/cli/commands/watch.ts +1 -1
- package/src/cli/index.ts +2 -2
- package/src/cli/shared/open-graph.ts +2 -2
- package/src/cli/types.ts +1 -1
- package/src/cli.ts +2 -3
- package/src/db/connection.ts +97 -13
- package/src/db/index.ts +2 -0
- package/src/db/migrations.ts +7 -0
- package/src/domain/analysis/brief.ts +0 -1
- package/src/domain/analysis/context.ts +2 -6
- package/src/domain/analysis/dependencies.ts +165 -0
- package/src/domain/analysis/diff-impact.ts +354 -0
- package/src/domain/analysis/exports.ts +0 -2
- package/src/domain/analysis/fn-impact.ts +241 -0
- package/src/domain/analysis/impact.ts +8 -718
- package/src/domain/analysis/module-map.ts +1 -5
- package/src/domain/graph/builder/context.ts +2 -2
- package/src/domain/graph/builder/helpers.ts +14 -11
- package/src/domain/graph/builder/incremental.ts +33 -28
- package/src/domain/graph/builder/pipeline.ts +8 -0
- package/src/domain/graph/builder/stages/build-edges.ts +17 -4
- package/src/domain/graph/builder/stages/build-structure.ts +205 -76
- package/src/domain/graph/builder/stages/detect-changes.ts +11 -12
- package/src/domain/graph/builder/stages/finalize.ts +100 -81
- package/src/domain/graph/builder/stages/insert-nodes.ts +12 -8
- package/src/domain/graph/builder/stages/resolve-imports.ts +75 -10
- package/src/domain/graph/cycles.ts +2 -2
- package/src/domain/graph/resolve.ts +14 -8
- package/src/domain/graph/watcher.ts +2 -4
- package/src/domain/parser.ts +11 -13
- package/src/domain/queries.ts +2 -2
- package/src/domain/search/generator.ts +3 -4
- package/src/extractors/csharp.ts +2 -2
- package/src/extractors/go.ts +2 -2
- package/src/extractors/helpers.ts +6 -0
- package/src/extractors/javascript.ts +58 -61
- package/src/extractors/php.ts +2 -2
- package/src/extractors/python.ts +2 -2
- package/src/extractors/rust.ts +2 -2
- package/src/features/audit.ts +1 -2
- package/src/features/branch-compare.ts +3 -9
- package/src/features/cfg.ts +2 -4
- package/src/features/cochange.ts +4 -4
- package/src/features/communities.ts +4 -4
- package/src/features/complexity-query.ts +370 -0
- package/src/features/complexity.ts +6 -365
- package/src/features/dataflow.ts +48 -70
- package/src/features/export.ts +12 -16
- package/src/features/flow.ts +0 -1
- package/src/features/graph-enrichment.ts +1 -3
- package/src/features/manifesto.ts +8 -8
- package/src/features/snapshot.ts +1 -2
- package/src/features/structure-query.ts +387 -0
- package/src/features/structure.ts +231 -376
- package/src/features/triage.ts +2 -2
- package/src/graph/algorithms/leiden/adapter.ts +2 -9
- package/src/graph/classifiers/roles.ts +22 -13
- package/src/index.ts +1 -0
- package/src/infrastructure/config.ts +12 -13
- package/src/infrastructure/native.ts +7 -3
- package/src/infrastructure/registry.ts +1 -1
- package/src/infrastructure/update-check.ts +3 -3
- package/src/mcp/server.ts +2 -10
- package/src/mcp/tool-registry.ts +11 -4
- package/src/mcp/tools/audit.ts +1 -1
- package/src/mcp/tools/cfg.ts +1 -1
- package/src/mcp/tools/check.ts +2 -2
- package/src/mcp/tools/dataflow.ts +2 -2
- package/src/mcp/tools/export-graph.ts +1 -1
- package/src/mcp/tools/index.ts +0 -1
- package/src/mcp/tools/path.ts +10 -0
- 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/symbol-children.ts +1 -1
- package/src/mcp/tools/triage.ts +1 -1
- package/src/presentation/audit.ts +0 -1
- package/src/presentation/diff-impact-mermaid.ts +127 -0
- package/src/presentation/flow.ts +0 -2
- package/src/presentation/manifesto.ts +0 -1
- package/src/presentation/queries-cli/inspect.ts +0 -1
- package/src/presentation/queries-cli/path.ts +71 -1
- package/src/presentation/result-formatter.ts +0 -1
- package/src/presentation/sequence.ts +0 -1
- package/src/presentation/structure.ts +0 -12
- package/src/presentation/triage.ts +0 -1
- package/src/shared/constants.ts +33 -19
- package/src/shared/errors.ts +5 -0
- package/src/shared/version.ts +10 -0
- package/src/types.ts +4 -10
- package/src/vendor.d.ts +0 -39
|
@@ -3,7 +3,7 @@ import { collectFile } from '../../db/query-builder.js';
|
|
|
3
3
|
import { EVERY_SYMBOL_KIND } from '../../domain/queries.js';
|
|
4
4
|
import { BATCH_COMMANDS, multiBatchData, splitTargets } from '../../features/batch.js';
|
|
5
5
|
import { batch } from '../../presentation/batch.js';
|
|
6
|
-
import { ConfigError } from '../../shared/errors.js';
|
|
6
|
+
import { ConfigError, toErrorMessage } from '../../shared/errors.js';
|
|
7
7
|
import type { CommandDefinition } from '../types.js';
|
|
8
8
|
|
|
9
9
|
interface MultiBatchItem {
|
|
@@ -58,8 +58,9 @@ export const command: CommandDefinition = {
|
|
|
58
58
|
targets = splitTargets(positionalTargets as unknown as string[]);
|
|
59
59
|
}
|
|
60
60
|
} catch (err: unknown) {
|
|
61
|
-
|
|
62
|
-
|
|
61
|
+
throw new ConfigError(`Failed to parse targets: ${toErrorMessage(err)}`, {
|
|
62
|
+
cause: err as Error,
|
|
63
|
+
});
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
if (!targets || targets.length === 0) {
|
|
@@ -13,7 +13,7 @@ export const command: CommandDefinition = {
|
|
|
13
13
|
async execute([base, target], opts, ctx) {
|
|
14
14
|
const { branchCompare } = await import('../../presentation/branch-compare.js');
|
|
15
15
|
await branchCompare(base!, target!, {
|
|
16
|
-
engine: ctx.program.opts()
|
|
16
|
+
engine: ctx.program.opts().engine,
|
|
17
17
|
depth: parseInt(opts.depth as string, 10),
|
|
18
18
|
noTests: ctx.resolveNoTests(opts),
|
|
19
19
|
json: opts.json,
|
|
@@ -15,7 +15,7 @@ export const command: CommandDefinition = {
|
|
|
15
15
|
],
|
|
16
16
|
async execute([dir], opts, ctx) {
|
|
17
17
|
const root = path.resolve(dir || '.');
|
|
18
|
-
const engine = ctx.program.opts()
|
|
18
|
+
const engine = ctx.program.opts().engine;
|
|
19
19
|
await buildGraph(root, {
|
|
20
20
|
incremental: opts.incremental as boolean,
|
|
21
21
|
ast: opts.ast as boolean,
|
package/src/cli/commands/info.ts
CHANGED
|
@@ -9,7 +9,7 @@ export const command: CommandDefinition = {
|
|
|
9
9
|
);
|
|
10
10
|
const { getActiveEngine } = await import('../../domain/parser.js');
|
|
11
11
|
|
|
12
|
-
const engine = ctx.program.opts()
|
|
12
|
+
const engine = ctx.program.opts().engine;
|
|
13
13
|
const { name: activeName, version: activeVersion } = getActiveEngine({ engine });
|
|
14
14
|
const nativeAvailable = isNativeAvailable();
|
|
15
15
|
|
|
@@ -43,7 +43,6 @@ export const command: CommandDefinition = {
|
|
|
43
43
|
const dbPath = findDbPath();
|
|
44
44
|
const fs = await import('node:fs');
|
|
45
45
|
if (fs.existsSync(dbPath)) {
|
|
46
|
-
// @ts-expect-error -- better-sqlite3 default export typing
|
|
47
46
|
const db = new Database(dbPath, { readonly: true });
|
|
48
47
|
const buildEngine = getBuildMeta(db, 'engine');
|
|
49
48
|
const buildVersion = getBuildMeta(db, 'codegraph_version');
|
package/src/cli/commands/path.ts
CHANGED
|
@@ -4,11 +4,15 @@ import type { CommandDefinition } from '../types.js';
|
|
|
4
4
|
|
|
5
5
|
export const command: CommandDefinition = {
|
|
6
6
|
name: 'path <from> <to>',
|
|
7
|
-
description: 'Find shortest path between two symbols',
|
|
7
|
+
description: 'Find shortest path between two symbols (or files with --file)',
|
|
8
8
|
options: [
|
|
9
9
|
['-d, --db <path>', 'Path to graph.db'],
|
|
10
|
+
['-f, --file', 'Treat <from> and <to> as file paths instead of symbol names'],
|
|
10
11
|
['--reverse', 'Follow edges backward'],
|
|
11
|
-
[
|
|
12
|
+
[
|
|
13
|
+
'--kinds <kinds>',
|
|
14
|
+
'Comma-separated edge kinds to follow (default: calls; file mode: imports,imports-type)',
|
|
15
|
+
],
|
|
12
16
|
['--from-file <path>', 'Disambiguate source symbol by file'],
|
|
13
17
|
['--to-file <path>', 'Disambiguate target symbol by file'],
|
|
14
18
|
['--depth <n>', 'Max traversal depth', '10'],
|
|
@@ -32,6 +36,7 @@ export const command: CommandDefinition = {
|
|
|
32
36
|
kind: opts.kind,
|
|
33
37
|
noTests: ctx.resolveNoTests(opts),
|
|
34
38
|
json: opts.json,
|
|
39
|
+
file: opts.file,
|
|
35
40
|
});
|
|
36
41
|
},
|
|
37
42
|
};
|
package/src/cli/commands/plot.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { toErrorMessage } from '../../shared/errors.js';
|
|
3
4
|
import { openGraph } from '../shared/open-graph.js';
|
|
4
5
|
import type { CommandDefinition } from '../types.js';
|
|
5
6
|
|
|
@@ -51,8 +52,7 @@ export const command: CommandDefinition = {
|
|
|
51
52
|
try {
|
|
52
53
|
plotCfg = JSON.parse(fs.readFileSync(opts.config as string, 'utf-8')) as PlotConfig;
|
|
53
54
|
} catch (e: unknown) {
|
|
54
|
-
|
|
55
|
-
console.error(`Failed to load config: ${message}`);
|
|
55
|
+
console.error(`Failed to load config: ${toErrorMessage(e)}`);
|
|
56
56
|
process.exitCode = 1;
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
@@ -7,7 +7,7 @@ export const command: CommandDefinition = {
|
|
|
7
7
|
description: 'Watch project for file changes and incrementally update the graph',
|
|
8
8
|
async execute([dir], _opts, ctx) {
|
|
9
9
|
const root = path.resolve(dir || '.');
|
|
10
|
-
const engine = ctx.program.opts()
|
|
10
|
+
const engine = ctx.program.opts().engine;
|
|
11
11
|
await watchProject(root, { engine });
|
|
12
12
|
},
|
|
13
13
|
};
|
package/src/cli/index.ts
CHANGED
|
@@ -27,12 +27,12 @@ program
|
|
|
27
27
|
.option('--engine <engine>', 'Parser engine: native, wasm, or auto (default: auto)', 'auto')
|
|
28
28
|
.hook('preAction', (thisCommand) => {
|
|
29
29
|
const opts = thisCommand.opts();
|
|
30
|
-
if (opts
|
|
30
|
+
if (opts.verbose) setVerbose(true);
|
|
31
31
|
})
|
|
32
32
|
.hook('postAction', async (_thisCommand, actionCommand) => {
|
|
33
33
|
const name = actionCommand.name();
|
|
34
34
|
if (name === 'mcp' || name === 'watch') return;
|
|
35
|
-
if (actionCommand.opts()
|
|
35
|
+
if (actionCommand.opts().json) return;
|
|
36
36
|
try {
|
|
37
37
|
const result = await checkForUpdates(pkg.version);
|
|
38
38
|
if (result) printUpdateNotification(result.current, result.latest);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import type Database from 'better-sqlite3';
|
|
2
1
|
import { openReadonlyOrFail } from '../../db/index.js';
|
|
2
|
+
import type { BetterSqlite3Database } from '../../types.js';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Open the graph database in readonly mode with a clean close() handle.
|
|
6
6
|
*/
|
|
7
7
|
export function openGraph(opts: { db?: string } = {}): {
|
|
8
|
-
db:
|
|
8
|
+
db: BetterSqlite3Database;
|
|
9
9
|
close: () => void;
|
|
10
10
|
} {
|
|
11
11
|
const db = openReadonlyOrFail(opts.db);
|
package/src/cli/types.ts
CHANGED
|
@@ -27,7 +27,7 @@ export interface CommandDefinition {
|
|
|
27
27
|
description: string;
|
|
28
28
|
queryOpts?: boolean;
|
|
29
29
|
options?: Array<[string, string, ...unknown[]]>;
|
|
30
|
-
validate?(args: string[], opts: CommandOpts, ctx: CliContext): string |
|
|
30
|
+
validate?(args: string[], opts: CommandOpts, ctx: CliContext): string | undefined;
|
|
31
31
|
execute?(args: string[], opts: CommandOpts, ctx: CliContext): void | Promise<void>;
|
|
32
32
|
subcommands?: CommandDefinition[];
|
|
33
33
|
}
|
package/src/cli.ts
CHANGED
|
@@ -1,15 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { run } from './cli/index.js';
|
|
4
|
-
import { CodegraphError } from './shared/errors.js';
|
|
4
|
+
import { CodegraphError, toErrorMessage } from './shared/errors.js';
|
|
5
5
|
|
|
6
6
|
run().catch((err: unknown) => {
|
|
7
7
|
if (err instanceof CodegraphError) {
|
|
8
8
|
console.error(`codegraph [${err.code}]: ${err.message}`);
|
|
9
9
|
if (err.file) console.error(` file: ${err.file}`);
|
|
10
10
|
} else {
|
|
11
|
-
|
|
12
|
-
console.error(`codegraph: fatal error — ${message}`);
|
|
11
|
+
console.error(`codegraph: fatal error — ${toErrorMessage(err)}`);
|
|
13
12
|
}
|
|
14
13
|
process.exit(1);
|
|
15
14
|
});
|
package/src/db/connection.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { execFileSync } from 'node:child_process';
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
4
5
|
import Database from 'better-sqlite3';
|
|
5
6
|
import { debug, warn } from '../infrastructure/logger.js';
|
|
6
7
|
import { DbError } from '../shared/errors.js';
|
|
@@ -8,6 +9,24 @@ import type { BetterSqlite3Database } from '../types.js';
|
|
|
8
9
|
import { Repository } from './repository/base.js';
|
|
9
10
|
import { SqliteRepository } from './repository/sqlite-repository.js';
|
|
10
11
|
|
|
12
|
+
/** Lazy-loaded package version (read once from package.json). */
|
|
13
|
+
let _packageVersion: string | undefined;
|
|
14
|
+
function getPackageVersion(): string {
|
|
15
|
+
if (_packageVersion !== undefined) return _packageVersion;
|
|
16
|
+
try {
|
|
17
|
+
const connDir = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
+
const pkgPath = path.join(connDir, '..', '..', 'package.json');
|
|
19
|
+
_packageVersion = (JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { version: string })
|
|
20
|
+
.version;
|
|
21
|
+
} catch {
|
|
22
|
+
_packageVersion = '';
|
|
23
|
+
}
|
|
24
|
+
return _packageVersion;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Warn once per process when DB version mismatches the running codegraph version. */
|
|
28
|
+
let _versionWarned = false;
|
|
29
|
+
|
|
11
30
|
/** DB instance with optional advisory lock path. */
|
|
12
31
|
export type LockedDatabase = BetterSqlite3Database & { __lockPath?: string };
|
|
13
32
|
|
|
@@ -60,6 +79,11 @@ export function _resetRepoRootCache(): void {
|
|
|
60
79
|
_cachedRepoRootCwd = undefined;
|
|
61
80
|
}
|
|
62
81
|
|
|
82
|
+
/** Reset the version warning flag (for testing). */
|
|
83
|
+
export function _resetVersionWarning(): void {
|
|
84
|
+
_versionWarned = false;
|
|
85
|
+
}
|
|
86
|
+
|
|
63
87
|
function isProcessAlive(pid: number): boolean {
|
|
64
88
|
try {
|
|
65
89
|
process.kill(pid, 0);
|
|
@@ -119,16 +143,12 @@ function isSameDirectory(a: string, b: string): boolean {
|
|
|
119
143
|
}
|
|
120
144
|
|
|
121
145
|
export function openDb(dbPath: string): LockedDatabase {
|
|
146
|
+
// Flush any deferred DB close from a previous build (avoids WAL contention)
|
|
147
|
+
flushDeferredClose();
|
|
122
148
|
const dir = path.dirname(dbPath);
|
|
123
149
|
if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
|
|
124
150
|
acquireAdvisoryLock(dbPath);
|
|
125
|
-
|
|
126
|
-
const db = new (
|
|
127
|
-
Database as unknown as new (
|
|
128
|
-
path: string,
|
|
129
|
-
opts?: Record<string, unknown>,
|
|
130
|
-
) => LockedDatabase
|
|
131
|
-
)(dbPath);
|
|
151
|
+
const db = new Database(dbPath) as unknown as LockedDatabase;
|
|
132
152
|
db.pragma('journal_mode = WAL');
|
|
133
153
|
db.pragma('busy_timeout = 5000');
|
|
134
154
|
db.__lockPath = `${dbPath}.lock`;
|
|
@@ -140,6 +160,54 @@ export function closeDb(db: LockedDatabase): void {
|
|
|
140
160
|
if (db.__lockPath) releaseAdvisoryLock(db.__lockPath);
|
|
141
161
|
}
|
|
142
162
|
|
|
163
|
+
/** Pending deferred-close DB handles (not yet closed). */
|
|
164
|
+
const _deferredDbs: LockedDatabase[] = [];
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Synchronously close any DB handles queued by `closeDbDeferred()`.
|
|
168
|
+
* Call before deleting DB files or in test teardown to avoid EBUSY on Windows.
|
|
169
|
+
*/
|
|
170
|
+
export function flushDeferredClose(): void {
|
|
171
|
+
while (_deferredDbs.length > 0) {
|
|
172
|
+
const db = _deferredDbs.pop()!;
|
|
173
|
+
try {
|
|
174
|
+
db.close();
|
|
175
|
+
} catch {
|
|
176
|
+
/* ignore — handle may already be closed */
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Schedule DB close on the next event loop tick. Useful for incremental
|
|
183
|
+
* builds where the WAL checkpoint in db.close() is expensive (~250ms on
|
|
184
|
+
* Windows) and doesn't need to block the caller.
|
|
185
|
+
*
|
|
186
|
+
* The advisory lock is released immediately so subsequent opens succeed.
|
|
187
|
+
* The actual handle close (+ WAL checkpoint) happens asynchronously.
|
|
188
|
+
* Call `flushDeferredClose()` before deleting the DB file.
|
|
189
|
+
*/
|
|
190
|
+
export function closeDbDeferred(db: LockedDatabase): void {
|
|
191
|
+
// Release the advisory lock immediately so the next open can proceed
|
|
192
|
+
if (db.__lockPath) {
|
|
193
|
+
releaseAdvisoryLock(db.__lockPath);
|
|
194
|
+
db.__lockPath = undefined;
|
|
195
|
+
}
|
|
196
|
+
_deferredDbs.push(db);
|
|
197
|
+
// Defer the expensive WAL checkpoint to after the caller returns
|
|
198
|
+
setImmediate(() => {
|
|
199
|
+
const idx = _deferredDbs.indexOf(db);
|
|
200
|
+
if (idx !== -1) {
|
|
201
|
+
_deferredDbs.splice(idx, 1);
|
|
202
|
+
try {
|
|
203
|
+
db.close();
|
|
204
|
+
} catch {
|
|
205
|
+
/* ignore — handle may already be closed by flush */
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
|
|
143
211
|
export function findDbPath(customPath?: string): string {
|
|
144
212
|
if (customPath) return path.resolve(customPath);
|
|
145
213
|
const rawCeiling = findRepoRoot();
|
|
@@ -190,12 +258,28 @@ export function openReadonlyOrFail(customPath?: string): BetterSqlite3Database {
|
|
|
190
258
|
{ file: dbPath },
|
|
191
259
|
);
|
|
192
260
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
261
|
+
const db = new Database(dbPath, { readonly: true }) as unknown as BetterSqlite3Database;
|
|
262
|
+
|
|
263
|
+
// Warn once per process if the DB was built with a different codegraph version
|
|
264
|
+
if (!_versionWarned) {
|
|
265
|
+
try {
|
|
266
|
+
const row = db
|
|
267
|
+
.prepare<{ value: string }>('SELECT value FROM build_meta WHERE key = ?')
|
|
268
|
+
.get('codegraph_version');
|
|
269
|
+
const buildVersion = row?.value;
|
|
270
|
+
const currentVersion = getPackageVersion();
|
|
271
|
+
if (buildVersion && currentVersion && buildVersion !== currentVersion) {
|
|
272
|
+
warn(
|
|
273
|
+
`DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
} catch {
|
|
277
|
+
// build_meta table may not exist in older DBs — silently ignore
|
|
278
|
+
}
|
|
279
|
+
_versionWarned = true;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
return db;
|
|
199
283
|
}
|
|
200
284
|
|
|
201
285
|
/**
|
package/src/db/index.ts
CHANGED
package/src/db/migrations.ts
CHANGED
|
@@ -247,6 +247,13 @@ export const MIGRATIONS: Migration[] = [
|
|
|
247
247
|
CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope);
|
|
248
248
|
`,
|
|
249
249
|
},
|
|
250
|
+
{
|
|
251
|
+
version: 16,
|
|
252
|
+
up: `
|
|
253
|
+
CREATE INDEX IF NOT EXISTS idx_edges_kind_target ON edges(kind, target_id);
|
|
254
|
+
CREATE INDEX IF NOT EXISTS idx_edges_kind_source ON edges(kind, source_id);
|
|
255
|
+
`,
|
|
256
|
+
},
|
|
250
257
|
];
|
|
251
258
|
|
|
252
259
|
interface PragmaColumnInfo {
|
|
@@ -113,7 +113,6 @@ function countTransitiveImporters(
|
|
|
113
113
|
export function briefData(
|
|
114
114
|
file: string,
|
|
115
115
|
customDbPath: string,
|
|
116
|
-
// biome-ignore lint/suspicious/noExplicitAny: config shape is dynamic
|
|
117
116
|
opts: { noTests?: boolean; config?: any } = {},
|
|
118
117
|
) {
|
|
119
118
|
const db = openReadonlyOrFail(customDbPath);
|
|
@@ -379,7 +379,6 @@ function explainFunctionImpl(
|
|
|
379
379
|
});
|
|
380
380
|
}
|
|
381
381
|
|
|
382
|
-
// biome-ignore lint/suspicious/noExplicitAny: explainFunctionImpl results have dynamic shape with _depth
|
|
383
382
|
function explainCallees(
|
|
384
383
|
parentResults: any[],
|
|
385
384
|
currentDepth: number,
|
|
@@ -405,8 +404,8 @@ function explainCallees(
|
|
|
405
404
|
);
|
|
406
405
|
const exact = calleeResults.find((cr) => cr.file === callee.file && cr.line === callee.line);
|
|
407
406
|
if (exact) {
|
|
408
|
-
(exact as Record<string, unknown>)
|
|
409
|
-
(((r as Record<string, unknown>)
|
|
407
|
+
(exact as Record<string, unknown>)._depth =
|
|
408
|
+
(((r as Record<string, unknown>)._depth as number) || 0) + 1;
|
|
410
409
|
newCallees.push(exact);
|
|
411
410
|
}
|
|
412
411
|
}
|
|
@@ -431,7 +430,6 @@ export function contextData(
|
|
|
431
430
|
kind?: string;
|
|
432
431
|
limit?: number;
|
|
433
432
|
offset?: number;
|
|
434
|
-
// biome-ignore lint/suspicious/noExplicitAny: config shape is dynamic
|
|
435
433
|
config?: any;
|
|
436
434
|
} = {},
|
|
437
435
|
) {
|
|
@@ -509,7 +507,6 @@ export function explainData(
|
|
|
509
507
|
depth?: number;
|
|
510
508
|
limit?: number;
|
|
511
509
|
offset?: number;
|
|
512
|
-
// biome-ignore lint/suspicious/noExplicitAny: config shape is dynamic
|
|
513
510
|
config?: any;
|
|
514
511
|
} = {},
|
|
515
512
|
) {
|
|
@@ -533,7 +530,6 @@ export function explainData(
|
|
|
533
530
|
: explainFunctionImpl(db, target, noTests, getFileLines, displayOpts);
|
|
534
531
|
|
|
535
532
|
if (kind === 'function' && depth > 0 && results.length > 0) {
|
|
536
|
-
// biome-ignore lint/suspicious/noExplicitAny: results are function results when kind === 'function'
|
|
537
533
|
const visited = new Set(results.map((r: any) => `${r.name}:${r.file}:${r.line ?? ''}`));
|
|
538
534
|
explainCallees(results, depth, visited, db, noTests, getFileLines, displayOpts);
|
|
539
535
|
}
|
|
@@ -481,3 +481,168 @@ export function pathData(
|
|
|
481
481
|
db.close();
|
|
482
482
|
}
|
|
483
483
|
}
|
|
484
|
+
|
|
485
|
+
// ── File-level shortest path ────────────────────────────────────────────
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* BFS at the file level: find shortest import/edge path between two files.
|
|
489
|
+
* Adjacency: file A → file B if any symbol in A has an edge to any symbol in B.
|
|
490
|
+
*/
|
|
491
|
+
export function filePathData(
|
|
492
|
+
from: string,
|
|
493
|
+
to: string,
|
|
494
|
+
customDbPath: string,
|
|
495
|
+
opts: {
|
|
496
|
+
noTests?: boolean;
|
|
497
|
+
maxDepth?: number;
|
|
498
|
+
edgeKinds?: string[];
|
|
499
|
+
reverse?: boolean;
|
|
500
|
+
} = {},
|
|
501
|
+
) {
|
|
502
|
+
const db = openReadonlyOrFail(customDbPath);
|
|
503
|
+
try {
|
|
504
|
+
const noTests = opts.noTests || false;
|
|
505
|
+
const maxDepth = opts.maxDepth || 10;
|
|
506
|
+
const edgeKinds = opts.edgeKinds || ['imports', 'imports-type'];
|
|
507
|
+
const reverse = opts.reverse || false;
|
|
508
|
+
|
|
509
|
+
// Resolve from/to as file paths (LIKE match)
|
|
510
|
+
const fromFiles = findFileNodes(db, `%${from}%`) as NodeRow[];
|
|
511
|
+
if (fromFiles.length === 0) {
|
|
512
|
+
return {
|
|
513
|
+
from,
|
|
514
|
+
to,
|
|
515
|
+
found: false,
|
|
516
|
+
error: `No file matching "${from}"`,
|
|
517
|
+
path: [],
|
|
518
|
+
fromCandidates: [],
|
|
519
|
+
toCandidates: [],
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
const toFiles = findFileNodes(db, `%${to}%`) as NodeRow[];
|
|
523
|
+
if (toFiles.length === 0) {
|
|
524
|
+
return {
|
|
525
|
+
from,
|
|
526
|
+
to,
|
|
527
|
+
found: false,
|
|
528
|
+
error: `No file matching "${to}"`,
|
|
529
|
+
path: [],
|
|
530
|
+
fromCandidates: fromFiles.slice(0, 5).map((f) => f.file),
|
|
531
|
+
toCandidates: [],
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
const sourceFile = fromFiles[0]!.file;
|
|
536
|
+
const targetFile = toFiles[0]!.file;
|
|
537
|
+
|
|
538
|
+
const fromCandidates = fromFiles.slice(0, 5).map((f) => f.file);
|
|
539
|
+
const toCandidates = toFiles.slice(0, 5).map((f) => f.file);
|
|
540
|
+
|
|
541
|
+
if (sourceFile === targetFile) {
|
|
542
|
+
return {
|
|
543
|
+
from,
|
|
544
|
+
to,
|
|
545
|
+
fromCandidates,
|
|
546
|
+
toCandidates,
|
|
547
|
+
found: true,
|
|
548
|
+
hops: 0,
|
|
549
|
+
path: [sourceFile],
|
|
550
|
+
alternateCount: 0,
|
|
551
|
+
edgeKinds,
|
|
552
|
+
reverse,
|
|
553
|
+
maxDepth,
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
// Build neighbor query: find all distinct files adjacent to a given file via edges
|
|
558
|
+
const kindPlaceholders = edgeKinds.map(() => '?').join(', ');
|
|
559
|
+
const neighborQuery = reverse
|
|
560
|
+
? `SELECT DISTINCT n_src.file AS neighbor_file
|
|
561
|
+
FROM nodes n_tgt
|
|
562
|
+
JOIN edges e ON e.target_id = n_tgt.id
|
|
563
|
+
JOIN nodes n_src ON e.source_id = n_src.id
|
|
564
|
+
WHERE n_tgt.file = ? AND e.kind IN (${kindPlaceholders}) AND n_src.file != n_tgt.file`
|
|
565
|
+
: `SELECT DISTINCT n_tgt.file AS neighbor_file
|
|
566
|
+
FROM nodes n_src
|
|
567
|
+
JOIN edges e ON e.source_id = n_src.id
|
|
568
|
+
JOIN nodes n_tgt ON e.target_id = n_tgt.id
|
|
569
|
+
WHERE n_src.file = ? AND e.kind IN (${kindPlaceholders}) AND n_tgt.file != n_src.file`;
|
|
570
|
+
const neighborStmt = db.prepare(neighborQuery);
|
|
571
|
+
|
|
572
|
+
// BFS
|
|
573
|
+
const visited = new Set([sourceFile]);
|
|
574
|
+
const parentMap = new Map<string, string>();
|
|
575
|
+
let queue = [sourceFile];
|
|
576
|
+
let found = false;
|
|
577
|
+
let alternateCount = 0;
|
|
578
|
+
|
|
579
|
+
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
580
|
+
const nextQueue: string[] = [];
|
|
581
|
+
for (const currentFile of queue) {
|
|
582
|
+
const neighbors = neighborStmt.all(currentFile, ...edgeKinds) as Array<{
|
|
583
|
+
neighbor_file: string;
|
|
584
|
+
}>;
|
|
585
|
+
for (const n of neighbors) {
|
|
586
|
+
if (noTests && isTestFile(n.neighbor_file)) continue;
|
|
587
|
+
if (n.neighbor_file === targetFile) {
|
|
588
|
+
if (!found) {
|
|
589
|
+
found = true;
|
|
590
|
+
parentMap.set(n.neighbor_file, currentFile);
|
|
591
|
+
}
|
|
592
|
+
alternateCount++;
|
|
593
|
+
continue;
|
|
594
|
+
}
|
|
595
|
+
if (!visited.has(n.neighbor_file)) {
|
|
596
|
+
visited.add(n.neighbor_file);
|
|
597
|
+
parentMap.set(n.neighbor_file, currentFile);
|
|
598
|
+
nextQueue.push(n.neighbor_file);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
if (found) break;
|
|
603
|
+
queue = nextQueue;
|
|
604
|
+
if (queue.length === 0) break;
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
if (!found) {
|
|
608
|
+
return {
|
|
609
|
+
from,
|
|
610
|
+
to,
|
|
611
|
+
fromCandidates,
|
|
612
|
+
toCandidates,
|
|
613
|
+
found: false,
|
|
614
|
+
hops: null,
|
|
615
|
+
path: [],
|
|
616
|
+
alternateCount: 0,
|
|
617
|
+
edgeKinds,
|
|
618
|
+
reverse,
|
|
619
|
+
maxDepth,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// Reconstruct path
|
|
624
|
+
const filePath: string[] = [targetFile];
|
|
625
|
+
let cur = targetFile;
|
|
626
|
+
while (cur !== sourceFile) {
|
|
627
|
+
cur = parentMap.get(cur)!;
|
|
628
|
+
filePath.push(cur);
|
|
629
|
+
}
|
|
630
|
+
filePath.reverse();
|
|
631
|
+
|
|
632
|
+
return {
|
|
633
|
+
from,
|
|
634
|
+
to,
|
|
635
|
+
fromCandidates,
|
|
636
|
+
toCandidates,
|
|
637
|
+
found: true,
|
|
638
|
+
hops: filePath.length - 1,
|
|
639
|
+
path: filePath,
|
|
640
|
+
alternateCount: Math.max(0, alternateCount - 1),
|
|
641
|
+
edgeKinds,
|
|
642
|
+
reverse,
|
|
643
|
+
maxDepth,
|
|
644
|
+
};
|
|
645
|
+
} finally {
|
|
646
|
+
db.close();
|
|
647
|
+
}
|
|
648
|
+
}
|