@optave/codegraph 3.5.0 → 3.7.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 +47 -21
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +119 -127
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
- package/dist/ast-analysis/visitors/ast-store-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 +11 -13
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/db/connection.d.ts +12 -2
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +81 -53
- 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 +38 -32
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +51 -66
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +62 -70
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +9 -7
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +29 -33
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +15 -17
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +35 -65
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +91 -6
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +20 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
- package/dist/domain/analysis/query-helpers.js +27 -0
- package/dist/domain/analysis/query-helpers.js.map +1 -0
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +15 -9
- 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 +3 -2
- 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 +69 -3
- 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 +7 -51
- 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 +7 -5
- package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +2 -2
- 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 -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 +124 -105
- 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 +28 -15
- 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 +3 -2
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts +0 -4
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +32 -48
- 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 +12 -12
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +206 -101
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
- package/dist/domain/search/search/cli-formatter.js +88 -83
- package/dist/domain/search/search/cli-formatter.js.map +1 -1
- package/dist/extractors/bash.d.ts +6 -0
- package/dist/extractors/bash.d.ts.map +1 -0
- package/dist/extractors/bash.js +91 -0
- package/dist/extractors/bash.js.map +1 -0
- package/dist/extractors/c.d.ts +6 -0
- package/dist/extractors/c.d.ts.map +1 -0
- package/dist/extractors/c.js +204 -0
- package/dist/extractors/c.js.map +1 -0
- package/dist/extractors/cpp.d.ts +6 -0
- package/dist/extractors/cpp.d.ts.map +1 -0
- package/dist/extractors/cpp.js +283 -0
- package/dist/extractors/cpp.js.map +1 -0
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +42 -54
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/dart.d.ts +6 -0
- package/dist/extractors/dart.d.ts.map +1 -0
- package/dist/extractors/dart.js +277 -0
- package/dist/extractors/dart.js.map +1 -0
- package/dist/extractors/elixir.d.ts +9 -0
- package/dist/extractors/elixir.d.ts.map +1 -0
- package/dist/extractors/elixir.js +223 -0
- package/dist/extractors/elixir.js.map +1 -0
- package/dist/extractors/go.d.ts.map +1 -1
- package/dist/extractors/go.js +126 -130
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/haskell.d.ts +8 -0
- package/dist/extractors/haskell.d.ts.map +1 -0
- package/dist/extractors/haskell.js +217 -0
- package/dist/extractors/haskell.js.map +1 -0
- package/dist/extractors/hcl.js +6 -6
- package/dist/extractors/hcl.js.map +1 -1
- package/dist/extractors/helpers.d.ts +32 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +74 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/index.d.ts +12 -0
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +12 -0
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +32 -47
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +306 -292
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.d.ts +6 -0
- package/dist/extractors/kotlin.d.ts.map +1 -0
- package/dist/extractors/kotlin.js +275 -0
- package/dist/extractors/kotlin.js.map +1 -0
- package/dist/extractors/lua.d.ts +6 -0
- package/dist/extractors/lua.d.ts.map +1 -0
- package/dist/extractors/lua.js +162 -0
- package/dist/extractors/lua.js.map +1 -0
- package/dist/extractors/ocaml.d.ts +6 -0
- package/dist/extractors/ocaml.d.ts.map +1 -0
- package/dist/extractors/ocaml.js +236 -0
- package/dist/extractors/ocaml.js.map +1 -0
- package/dist/extractors/php.d.ts.map +1 -1
- package/dist/extractors/php.js +39 -44
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.d.ts.map +1 -1
- package/dist/extractors/python.js +75 -93
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +6 -13
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/rust.d.ts.map +1 -1
- package/dist/extractors/rust.js +58 -83
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/scala.d.ts +6 -0
- package/dist/extractors/scala.d.ts.map +1 -0
- package/dist/extractors/scala.js +269 -0
- package/dist/extractors/scala.js.map +1 -0
- package/dist/extractors/swift.d.ts +6 -0
- package/dist/extractors/swift.d.ts.map +1 -0
- package/dist/extractors/swift.js +275 -0
- package/dist/extractors/swift.js.map +1 -0
- package/dist/extractors/zig.d.ts +9 -0
- package/dist/extractors/zig.d.ts.map +1 -0
- package/dist/extractors/zig.js +276 -0
- package/dist/extractors/zig.js.map +1 -0
- package/dist/features/ast.d.ts +2 -0
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +9 -24
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +17 -21
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +47 -3
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +7 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +72 -61
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +79 -62
- package/dist/features/check.js.map +1 -1
- package/dist/features/complexity-query.d.ts.map +1 -1
- package/dist/features/complexity-query.js +142 -137
- package/dist/features/complexity-query.js.map +1 -1
- package/dist/features/complexity.d.ts +7 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +62 -1
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts +7 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +356 -188
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +117 -104
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +25 -4
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +29 -4
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +35 -15
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +88 -73
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/algorithms/leiden/index.js +43 -28
- package/dist/graph/algorithms/leiden/index.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +90 -104
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/partition.js +89 -106
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts +2 -0
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +20 -8
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts +0 -8
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +73 -62
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -8
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +12 -14
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -36
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +61 -57
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/branch-compare.d.ts.map +1 -1
- package/dist/presentation/branch-compare.js +56 -38
- package/dist/presentation/branch-compare.js.map +1 -1
- package/dist/presentation/check.d.ts.map +1 -1
- package/dist/presentation/check.js +30 -32
- package/dist/presentation/check.js.map +1 -1
- package/dist/presentation/colors.d.ts.map +1 -1
- package/dist/presentation/colors.js +2 -0
- package/dist/presentation/colors.js.map +1 -1
- package/dist/presentation/complexity.d.ts.map +1 -1
- package/dist/presentation/complexity.js +25 -19
- package/dist/presentation/complexity.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +15 -15
- package/dist/presentation/queries-cli/exports.js.map +1 -1
- package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
- package/dist/presentation/queries-cli/impact.js +29 -19
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/types.d.ts +182 -7
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-dart.wasm +0 -0
- package/grammars/tree-sitter-elixir.wasm +0 -0
- package/grammars/tree-sitter-haskell.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-lua.wasm +0 -0
- package/grammars/tree-sitter-ocaml.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/grammars/tree-sitter-zig.wasm +0 -0
- package/package.json +19 -7
- package/src/ast-analysis/engine.ts +147 -138
- package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
- package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
- package/src/db/connection.ts +90 -59
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +36 -32
- package/src/domain/analysis/context.ts +73 -75
- package/src/domain/analysis/dependencies.ts +78 -68
- package/src/domain/analysis/exports.ts +45 -34
- package/src/domain/analysis/fn-impact.ts +67 -64
- package/src/domain/analysis/module-map.ts +103 -8
- package/src/domain/analysis/query-helpers.ts +35 -0
- package/src/domain/graph/builder/helpers.ts +12 -6
- package/src/domain/graph/builder/incremental.ts +3 -2
- package/src/domain/graph/builder/pipeline.ts +71 -3
- package/src/domain/graph/builder/stages/build-edges.ts +10 -75
- package/src/domain/graph/builder/stages/build-structure.ts +9 -7
- package/src/domain/graph/builder/stages/collect-files.ts +2 -2
- package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
- package/src/domain/graph/builder/stages/finalize.ts +159 -125
- package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
- package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
- package/src/domain/graph/resolve.ts +34 -46
- package/src/domain/graph/watcher.ts +12 -14
- package/src/domain/parser.ts +222 -97
- package/src/domain/search/search/cli-formatter.ts +121 -94
- package/src/extractors/bash.ts +97 -0
- package/src/extractors/c.ts +212 -0
- package/src/extractors/cpp.ts +298 -0
- package/src/extractors/csharp.ts +53 -56
- package/src/extractors/dart.ts +304 -0
- package/src/extractors/elixir.ts +251 -0
- package/src/extractors/go.ts +152 -134
- package/src/extractors/haskell.ts +235 -0
- package/src/extractors/hcl.ts +6 -6
- package/src/extractors/helpers.ts +93 -1
- package/src/extractors/index.ts +12 -0
- package/src/extractors/java.ts +43 -48
- package/src/extractors/javascript.ts +328 -281
- package/src/extractors/kotlin.ts +293 -0
- package/src/extractors/lua.ts +169 -0
- package/src/extractors/ocaml.ts +259 -0
- package/src/extractors/php.ts +46 -40
- package/src/extractors/python.ts +81 -104
- package/src/extractors/ruby.ts +6 -13
- package/src/extractors/rust.ts +65 -85
- package/src/extractors/scala.ts +285 -0
- package/src/extractors/swift.ts +293 -0
- package/src/extractors/zig.ts +294 -0
- package/src/features/ast.ts +10 -25
- package/src/features/audit.ts +24 -20
- package/src/features/branch-compare.ts +51 -4
- package/src/features/cfg.ts +113 -65
- package/src/features/check.ts +90 -74
- package/src/features/complexity-query.ts +181 -163
- package/src/features/complexity.ts +64 -1
- package/src/features/dataflow.ts +462 -217
- package/src/features/graph-enrichment.ts +161 -117
- package/src/features/sequence.ts +27 -4
- package/src/features/structure-query.ts +43 -4
- package/src/features/structure.ts +50 -22
- package/src/graph/algorithms/leiden/adapter.ts +126 -71
- package/src/graph/algorithms/leiden/index.ts +67 -28
- package/src/graph/algorithms/leiden/optimiser.ts +114 -105
- package/src/graph/algorithms/leiden/partition.ts +131 -98
- package/src/graph/model.ts +19 -7
- package/src/infrastructure/config.ts +60 -58
- package/src/infrastructure/registry.ts +17 -14
- package/src/mcp/server.ts +46 -37
- package/src/presentation/audit.ts +72 -67
- package/src/presentation/branch-compare.ts +54 -50
- package/src/presentation/check.ts +34 -34
- package/src/presentation/colors.ts +2 -0
- package/src/presentation/complexity.ts +39 -33
- package/src/presentation/queries-cli/exports.ts +17 -17
- package/src/presentation/queries-cli/impact.ts +30 -22
- package/src/types.ts +195 -7
package/src/db/connection.ts
CHANGED
|
@@ -29,6 +29,23 @@ function getPackageVersion(): string {
|
|
|
29
29
|
/** Warn once per process when DB version mismatches the running codegraph version. */
|
|
30
30
|
let _versionWarned = false;
|
|
31
31
|
|
|
32
|
+
/** Check and warn (once) if the running codegraph version differs from the DB build version. */
|
|
33
|
+
function warnOnVersionMismatch(getBuildVersion: () => string | undefined | null): void {
|
|
34
|
+
if (_versionWarned) return;
|
|
35
|
+
_versionWarned = true;
|
|
36
|
+
try {
|
|
37
|
+
const buildVersion = getBuildVersion();
|
|
38
|
+
const currentVersion = getPackageVersion();
|
|
39
|
+
if (buildVersion && currentVersion && buildVersion !== currentVersion) {
|
|
40
|
+
warn(
|
|
41
|
+
`DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
// build_meta table may not exist in older DBs — silently ignore
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
32
49
|
/** DB instance with optional advisory lock path. */
|
|
33
50
|
export type LockedDatabase = BetterSqlite3Database & { __lockPath?: string };
|
|
34
51
|
|
|
@@ -81,11 +98,6 @@ export function _resetRepoRootCache(): void {
|
|
|
81
98
|
_cachedRepoRootCwd = undefined;
|
|
82
99
|
}
|
|
83
100
|
|
|
84
|
-
/** Reset the version warning flag (for testing). */
|
|
85
|
-
export function _resetVersionWarning(): void {
|
|
86
|
-
_versionWarned = false;
|
|
87
|
-
}
|
|
88
|
-
|
|
89
101
|
function isProcessAlive(pid: number): boolean {
|
|
90
102
|
try {
|
|
91
103
|
process.kill(pid, 0);
|
|
@@ -299,28 +311,41 @@ export function openReadonlyOrFail(customPath?: string): BetterSqlite3Database {
|
|
|
299
311
|
const Database = getDatabase();
|
|
300
312
|
const db = new Database(dbPath, { readonly: true }) as unknown as BetterSqlite3Database;
|
|
301
313
|
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
const buildVersion = row?.value;
|
|
309
|
-
const currentVersion = getPackageVersion();
|
|
310
|
-
if (buildVersion && currentVersion && buildVersion !== currentVersion) {
|
|
311
|
-
warn(
|
|
312
|
-
`DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
|
|
313
|
-
);
|
|
314
|
-
}
|
|
315
|
-
} catch {
|
|
316
|
-
// build_meta table may not exist in older DBs — silently ignore
|
|
317
|
-
}
|
|
318
|
-
_versionWarned = true;
|
|
319
|
-
}
|
|
314
|
+
warnOnVersionMismatch(() => {
|
|
315
|
+
const row = db
|
|
316
|
+
.prepare<{ value: string }>('SELECT value FROM build_meta WHERE key = ?')
|
|
317
|
+
.get('codegraph_version');
|
|
318
|
+
return row?.value;
|
|
319
|
+
});
|
|
320
320
|
|
|
321
321
|
return db;
|
|
322
322
|
}
|
|
323
323
|
|
|
324
|
+
/** Open a NativeRepository via rusqlite, throwing DbError if the DB file is missing. */
|
|
325
|
+
function openRepoNative(customDbPath?: string): { repo: Repository; close(): void } {
|
|
326
|
+
const dbPath = findDbPath(customDbPath);
|
|
327
|
+
if (!fs.existsSync(dbPath)) {
|
|
328
|
+
throw new DbError(
|
|
329
|
+
`No codegraph database found at ${dbPath}.\nRun "codegraph build" first to analyze your codebase.`,
|
|
330
|
+
{ file: dbPath },
|
|
331
|
+
);
|
|
332
|
+
}
|
|
333
|
+
const native = getNative();
|
|
334
|
+
const ndb = native.NativeDatabase.openReadonly(dbPath);
|
|
335
|
+
try {
|
|
336
|
+
warnOnVersionMismatch(() => ndb.getBuildMeta('codegraph_version'));
|
|
337
|
+
return {
|
|
338
|
+
repo: new NativeRepository(ndb),
|
|
339
|
+
close() {
|
|
340
|
+
ndb.close();
|
|
341
|
+
},
|
|
342
|
+
};
|
|
343
|
+
} catch (innerErr) {
|
|
344
|
+
ndb.close();
|
|
345
|
+
throw innerErr;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
324
349
|
/**
|
|
325
350
|
* Open a Repository from either an injected instance or a DB path.
|
|
326
351
|
*
|
|
@@ -345,42 +370,7 @@ export function openRepo(
|
|
|
345
370
|
// Try native rusqlite path first (Phase 6.14)
|
|
346
371
|
if (isNativeAvailable()) {
|
|
347
372
|
try {
|
|
348
|
-
|
|
349
|
-
if (!fs.existsSync(dbPath)) {
|
|
350
|
-
throw new DbError(
|
|
351
|
-
`No codegraph database found at ${dbPath}.\nRun "codegraph build" first to analyze your codebase.`,
|
|
352
|
-
{ file: dbPath },
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
const native = getNative();
|
|
356
|
-
const ndb = native.NativeDatabase.openReadonly(dbPath);
|
|
357
|
-
try {
|
|
358
|
-
// Version check (same logic as openReadonlyOrFail)
|
|
359
|
-
if (!_versionWarned) {
|
|
360
|
-
try {
|
|
361
|
-
const buildVersion = ndb.getBuildMeta('codegraph_version');
|
|
362
|
-
const currentVersion = getPackageVersion();
|
|
363
|
-
if (buildVersion && currentVersion && buildVersion !== currentVersion) {
|
|
364
|
-
warn(
|
|
365
|
-
`DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
|
|
366
|
-
);
|
|
367
|
-
}
|
|
368
|
-
} catch {
|
|
369
|
-
// build_meta table may not exist in older DBs
|
|
370
|
-
}
|
|
371
|
-
_versionWarned = true;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
return {
|
|
375
|
-
repo: new NativeRepository(ndb),
|
|
376
|
-
close() {
|
|
377
|
-
ndb.close();
|
|
378
|
-
},
|
|
379
|
-
};
|
|
380
|
-
} catch (innerErr) {
|
|
381
|
-
ndb.close();
|
|
382
|
-
throw innerErr;
|
|
383
|
-
}
|
|
373
|
+
return openRepoNative(customDbPath);
|
|
384
374
|
} catch (e) {
|
|
385
375
|
// Re-throw user-visible errors (e.g. DB not found) — only silently
|
|
386
376
|
// fall back for native-engine failures (e.g. incompatible native binary).
|
|
@@ -399,3 +389,44 @@ export function openRepo(
|
|
|
399
389
|
},
|
|
400
390
|
};
|
|
401
391
|
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Open a readonly DB with an optional NativeDatabase alongside it.
|
|
395
|
+
*
|
|
396
|
+
* Returns the better-sqlite3 handle (for backwards compat) plus an optional
|
|
397
|
+
* NativeDatabase for modules that can use batched Rust query methods.
|
|
398
|
+
* Callers should use nativeDb when available and fall back to db.prepare().
|
|
399
|
+
*/
|
|
400
|
+
export function openReadonlyWithNative(customPath?: string): {
|
|
401
|
+
db: BetterSqlite3Database;
|
|
402
|
+
nativeDb: NativeDatabase | undefined;
|
|
403
|
+
close(): void;
|
|
404
|
+
} {
|
|
405
|
+
const db = openReadonlyOrFail(customPath);
|
|
406
|
+
|
|
407
|
+
let nativeDb: NativeDatabase | undefined;
|
|
408
|
+
if (isNativeAvailable()) {
|
|
409
|
+
try {
|
|
410
|
+
const dbPath = findDbPath(customPath);
|
|
411
|
+
const native = getNative();
|
|
412
|
+
nativeDb = native.NativeDatabase.openReadonly(dbPath);
|
|
413
|
+
} catch (e) {
|
|
414
|
+
debug(`openReadonlyWithNative: native path failed: ${(e as Error).message}`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return {
|
|
419
|
+
db,
|
|
420
|
+
nativeDb,
|
|
421
|
+
close() {
|
|
422
|
+
db.close();
|
|
423
|
+
if (nativeDb) {
|
|
424
|
+
try {
|
|
425
|
+
nativeDb.close();
|
|
426
|
+
} catch {
|
|
427
|
+
// already closed or not closeable
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
},
|
|
431
|
+
};
|
|
432
|
+
}
|
package/src/db/index.ts
CHANGED
package/src/db/migrations.ts
CHANGED
|
@@ -304,7 +304,8 @@ export function setBuildMeta(
|
|
|
304
304
|
tx();
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
|
|
307
|
+
/** Run numbered migrations that haven't been applied yet. */
|
|
308
|
+
function applyMigrations(db: BetterSqlite3Database): void {
|
|
308
309
|
db.exec(`CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL DEFAULT 0)`);
|
|
309
310
|
|
|
310
311
|
const row = db.prepare<{ version: number }>('SELECT version FROM schema_version').get();
|
|
@@ -322,40 +323,43 @@ export function initSchema(db: BetterSqlite3Database): void {
|
|
|
322
323
|
currentVersion = migration.version;
|
|
323
324
|
}
|
|
324
325
|
}
|
|
326
|
+
}
|
|
325
327
|
|
|
326
|
-
|
|
328
|
+
/** Ensure columns and indexes exist for pre-migration DBs (legacy compat). */
|
|
329
|
+
function ensureLegacyColumns(db: BetterSqlite3Database): void {
|
|
327
330
|
if (hasTable(db, 'nodes')) {
|
|
328
|
-
|
|
329
|
-
db.exec('ALTER TABLE nodes ADD COLUMN end_line INTEGER');
|
|
330
|
-
}
|
|
331
|
-
if (!hasColumn(db, 'nodes', 'role')) {
|
|
332
|
-
db.exec('ALTER TABLE nodes ADD COLUMN role TEXT');
|
|
333
|
-
}
|
|
334
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_role ON nodes(role)');
|
|
335
|
-
if (!hasColumn(db, 'nodes', 'parent_id')) {
|
|
336
|
-
db.exec('ALTER TABLE nodes ADD COLUMN parent_id INTEGER REFERENCES nodes(id)');
|
|
337
|
-
}
|
|
338
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent_id)');
|
|
339
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_kind_parent ON nodes(kind, parent_id)');
|
|
340
|
-
if (!hasColumn(db, 'nodes', 'qualified_name')) {
|
|
341
|
-
db.exec('ALTER TABLE nodes ADD COLUMN qualified_name TEXT');
|
|
342
|
-
}
|
|
343
|
-
if (!hasColumn(db, 'nodes', 'scope')) {
|
|
344
|
-
db.exec('ALTER TABLE nodes ADD COLUMN scope TEXT');
|
|
345
|
-
}
|
|
346
|
-
if (!hasColumn(db, 'nodes', 'visibility')) {
|
|
347
|
-
db.exec('ALTER TABLE nodes ADD COLUMN visibility TEXT');
|
|
348
|
-
}
|
|
349
|
-
db.exec('UPDATE nodes SET qualified_name = name WHERE qualified_name IS NULL');
|
|
350
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_qualified_name ON nodes(qualified_name)');
|
|
351
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope)');
|
|
331
|
+
ensureNodeColumns(db);
|
|
352
332
|
}
|
|
353
333
|
if (hasTable(db, 'edges')) {
|
|
354
|
-
|
|
355
|
-
db.exec('ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0');
|
|
356
|
-
}
|
|
357
|
-
if (!hasColumn(db, 'edges', 'dynamic')) {
|
|
358
|
-
db.exec('ALTER TABLE edges ADD COLUMN dynamic INTEGER DEFAULT 0');
|
|
359
|
-
}
|
|
334
|
+
ensureEdgeColumns(db);
|
|
360
335
|
}
|
|
361
336
|
}
|
|
337
|
+
|
|
338
|
+
function ensureNodeColumns(db: BetterSqlite3Database): void {
|
|
339
|
+
const missing = (col: string) => !hasColumn(db, 'nodes', col);
|
|
340
|
+
if (missing('end_line')) db.exec('ALTER TABLE nodes ADD COLUMN end_line INTEGER');
|
|
341
|
+
if (missing('role')) db.exec('ALTER TABLE nodes ADD COLUMN role TEXT');
|
|
342
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_role ON nodes(role)');
|
|
343
|
+
if (missing('parent_id'))
|
|
344
|
+
db.exec('ALTER TABLE nodes ADD COLUMN parent_id INTEGER REFERENCES nodes(id)');
|
|
345
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent_id)');
|
|
346
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_kind_parent ON nodes(kind, parent_id)');
|
|
347
|
+
if (missing('qualified_name')) db.exec('ALTER TABLE nodes ADD COLUMN qualified_name TEXT');
|
|
348
|
+
if (missing('scope')) db.exec('ALTER TABLE nodes ADD COLUMN scope TEXT');
|
|
349
|
+
if (missing('visibility')) db.exec('ALTER TABLE nodes ADD COLUMN visibility TEXT');
|
|
350
|
+
db.exec('UPDATE nodes SET qualified_name = name WHERE qualified_name IS NULL');
|
|
351
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_qualified_name ON nodes(qualified_name)');
|
|
352
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope)');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function ensureEdgeColumns(db: BetterSqlite3Database): void {
|
|
356
|
+
if (!hasColumn(db, 'edges', 'confidence'))
|
|
357
|
+
db.exec('ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0');
|
|
358
|
+
if (!hasColumn(db, 'edges', 'dynamic'))
|
|
359
|
+
db.exec('ALTER TABLE edges ADD COLUMN dynamic INTEGER DEFAULT 0');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function initSchema(db: BetterSqlite3Database): void {
|
|
363
|
+
applyMigrations(db);
|
|
364
|
+
ensureLegacyColumns(db);
|
|
365
|
+
}
|
|
@@ -15,10 +15,8 @@ import {
|
|
|
15
15
|
getComplexityForNode,
|
|
16
16
|
getLineCountForNode,
|
|
17
17
|
getMaxEndLineForFile,
|
|
18
|
-
openReadonlyOrFail,
|
|
19
18
|
} from '../../db/index.js';
|
|
20
19
|
import { cachedStmt } from '../../db/repository/cached-stmt.js';
|
|
21
|
-
import { loadConfig } from '../../infrastructure/config.js';
|
|
22
20
|
import { debug } from '../../infrastructure/logger.js';
|
|
23
21
|
import { isTestFile } from '../../infrastructure/test-filter.js';
|
|
24
22
|
import {
|
|
@@ -40,6 +38,7 @@ import type {
|
|
|
40
38
|
RelatedNodeRow,
|
|
41
39
|
StmtCache,
|
|
42
40
|
} from '../../types.js';
|
|
41
|
+
import { resolveAnalysisOpts, withReadonlyDb } from './query-helpers.js';
|
|
43
42
|
import { findMatchingNodes } from './symbol-lookup.js';
|
|
44
43
|
|
|
45
44
|
interface DisplayOpts {
|
|
@@ -52,6 +51,60 @@ interface DisplayOpts {
|
|
|
52
51
|
[key: string]: unknown;
|
|
53
52
|
}
|
|
54
53
|
|
|
54
|
+
/** Format a callee row into the output shape with summary and source. */
|
|
55
|
+
function formatCalleeRow(
|
|
56
|
+
c: RelatedNodeRow,
|
|
57
|
+
repoRoot: string,
|
|
58
|
+
getFileLines: (file: string) => string[] | null,
|
|
59
|
+
displayOpts: DisplayOpts,
|
|
60
|
+
includeSource: boolean,
|
|
61
|
+
) {
|
|
62
|
+
const cLines = getFileLines(c.file);
|
|
63
|
+
return {
|
|
64
|
+
name: c.name,
|
|
65
|
+
kind: c.kind,
|
|
66
|
+
file: c.file,
|
|
67
|
+
line: c.line,
|
|
68
|
+
endLine: c.end_line || null,
|
|
69
|
+
summary: cLines ? extractSummary(cLines, c.line, displayOpts) : null,
|
|
70
|
+
source: includeSource
|
|
71
|
+
? readSourceRange(repoRoot, c.file, c.line, c.end_line ?? undefined, displayOpts)
|
|
72
|
+
: null,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** BFS to collect deeper callees beyond the first level. */
|
|
77
|
+
function collectDeeperCallees(
|
|
78
|
+
db: BetterSqlite3Database,
|
|
79
|
+
startIds: number[],
|
|
80
|
+
rootId: number,
|
|
81
|
+
repoRoot: string,
|
|
82
|
+
getFileLines: (file: string) => string[] | null,
|
|
83
|
+
opts: { noTests: boolean; maxDepth: number; displayOpts: DisplayOpts },
|
|
84
|
+
) {
|
|
85
|
+
const { noTests, maxDepth, displayOpts } = opts;
|
|
86
|
+
const visited = new Set(startIds);
|
|
87
|
+
visited.add(rootId);
|
|
88
|
+
let frontier = [...startIds];
|
|
89
|
+
const result: ReturnType<typeof formatCalleeRow>[] = [];
|
|
90
|
+
|
|
91
|
+
for (let d = 2; d <= maxDepth; d++) {
|
|
92
|
+
const nextFrontier: number[] = [];
|
|
93
|
+
for (const fid of frontier) {
|
|
94
|
+
const deeper = findCallees(db, fid) as RelatedNodeRow[];
|
|
95
|
+
for (const c of deeper) {
|
|
96
|
+
if (visited.has(c.id) || (noTests && isTestFile(c.file))) continue;
|
|
97
|
+
visited.add(c.id);
|
|
98
|
+
nextFrontier.push(c.id);
|
|
99
|
+
result.push(formatCalleeRow(c, repoRoot, getFileLines, displayOpts, true));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
frontier = nextFrontier;
|
|
103
|
+
if (frontier.length === 0) break;
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
55
108
|
function buildCallees(
|
|
56
109
|
db: BetterSqlite3Database,
|
|
57
110
|
node: NodeRow,
|
|
@@ -63,65 +116,20 @@ function buildCallees(
|
|
|
63
116
|
const calleeRows = findCallees(db, node.id) as RelatedNodeRow[];
|
|
64
117
|
const filteredCallees = noTests ? calleeRows.filter((c) => !isTestFile(c.file)) : calleeRows;
|
|
65
118
|
|
|
66
|
-
const callees = filteredCallees.map((c) =>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
let calleeSource: string | null = null;
|
|
70
|
-
if (depth >= 1) {
|
|
71
|
-
calleeSource = readSourceRange(
|
|
72
|
-
repoRoot,
|
|
73
|
-
c.file,
|
|
74
|
-
c.line,
|
|
75
|
-
c.end_line ?? undefined,
|
|
76
|
-
displayOpts,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
name: c.name,
|
|
81
|
-
kind: c.kind,
|
|
82
|
-
file: c.file,
|
|
83
|
-
line: c.line,
|
|
84
|
-
endLine: c.end_line || null,
|
|
85
|
-
summary,
|
|
86
|
-
source: calleeSource,
|
|
87
|
-
};
|
|
88
|
-
});
|
|
119
|
+
const callees = filteredCallees.map((c) =>
|
|
120
|
+
formatCalleeRow(c, repoRoot, getFileLines, displayOpts, depth >= 1),
|
|
121
|
+
);
|
|
89
122
|
|
|
90
123
|
if (depth > 1) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (!visited.has(c.id) && (!noTests || !isTestFile(c.file))) {
|
|
101
|
-
visited.add(c.id);
|
|
102
|
-
nextFrontier.push(c.id);
|
|
103
|
-
const cLines = getFileLines(c.file);
|
|
104
|
-
callees.push({
|
|
105
|
-
name: c.name,
|
|
106
|
-
kind: c.kind,
|
|
107
|
-
file: c.file,
|
|
108
|
-
line: c.line,
|
|
109
|
-
endLine: c.end_line || null,
|
|
110
|
-
summary: cLines ? extractSummary(cLines, c.line, displayOpts) : null,
|
|
111
|
-
source: readSourceRange(
|
|
112
|
-
repoRoot,
|
|
113
|
-
c.file,
|
|
114
|
-
c.line,
|
|
115
|
-
c.end_line ?? undefined,
|
|
116
|
-
displayOpts,
|
|
117
|
-
),
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
frontier = nextFrontier;
|
|
123
|
-
if (frontier.length === 0) break;
|
|
124
|
-
}
|
|
124
|
+
const deeper = collectDeeperCallees(
|
|
125
|
+
db,
|
|
126
|
+
filteredCallees.map((c) => c.id),
|
|
127
|
+
node.id,
|
|
128
|
+
repoRoot,
|
|
129
|
+
getFileLines,
|
|
130
|
+
{ noTests, maxDepth: Math.min(depth, 5), displayOpts },
|
|
131
|
+
);
|
|
132
|
+
callees.push(...deeper);
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
return callees;
|
|
@@ -433,15 +441,12 @@ export function contextData(
|
|
|
433
441
|
config?: any;
|
|
434
442
|
} = {},
|
|
435
443
|
) {
|
|
436
|
-
|
|
437
|
-
try {
|
|
444
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
438
445
|
const depth = opts.depth || 0;
|
|
439
446
|
const noSource = opts.noSource || false;
|
|
440
|
-
const noTests = opts.noTests || false;
|
|
441
447
|
const includeTests = opts.includeTests || false;
|
|
442
448
|
|
|
443
|
-
const
|
|
444
|
-
const displayOpts: DisplayOpts = config.display || {};
|
|
449
|
+
const { noTests, displayOpts } = resolveAnalysisOpts(opts);
|
|
445
450
|
|
|
446
451
|
const dbPath = findDbPath(customDbPath);
|
|
447
452
|
const repoRoot = path.resolve(path.dirname(dbPath), '..');
|
|
@@ -494,9 +499,7 @@ export function contextData(
|
|
|
494
499
|
|
|
495
500
|
const base = { name, results };
|
|
496
501
|
return paginateResult(base, 'results', { limit: opts.limit, offset: opts.offset });
|
|
497
|
-
}
|
|
498
|
-
db.close();
|
|
499
|
-
}
|
|
502
|
+
});
|
|
500
503
|
}
|
|
501
504
|
|
|
502
505
|
export function explainData(
|
|
@@ -510,14 +513,11 @@ export function explainData(
|
|
|
510
513
|
config?: any;
|
|
511
514
|
} = {},
|
|
512
515
|
) {
|
|
513
|
-
|
|
514
|
-
try {
|
|
515
|
-
const noTests = opts.noTests || false;
|
|
516
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
516
517
|
const depth = opts.depth || 0;
|
|
517
518
|
const kind = isFileLikeTarget(target) ? 'file' : 'function';
|
|
518
519
|
|
|
519
|
-
const
|
|
520
|
-
const displayOpts: DisplayOpts = config.display || {};
|
|
520
|
+
const { noTests, displayOpts } = resolveAnalysisOpts(opts);
|
|
521
521
|
|
|
522
522
|
const dbPath = findDbPath(customDbPath);
|
|
523
523
|
const repoRoot = path.resolve(path.dirname(dbPath), '..');
|
|
@@ -536,7 +536,5 @@ export function explainData(
|
|
|
536
536
|
|
|
537
537
|
const base = { target, kind, results };
|
|
538
538
|
return paginateResult(base, 'results', { limit: opts.limit, offset: opts.offset });
|
|
539
|
-
}
|
|
540
|
-
db.close();
|
|
541
|
-
}
|
|
539
|
+
});
|
|
542
540
|
}
|