@optave/codegraph 3.8.0 → 3.8.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 +9 -8
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +95 -87
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/metrics.d.ts +0 -3
- package/dist/ast-analysis/metrics.d.ts.map +1 -1
- package/dist/ast-analysis/metrics.js +30 -13
- package/dist/ast-analysis/metrics.js.map +1 -1
- package/dist/ast-analysis/shared.d.ts.map +1 -1
- package/dist/ast-analysis/shared.js +24 -19
- package/dist/ast-analysis/shared.js.map +1 -1
- package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
- package/dist/ast-analysis/visitor-utils.js +55 -39
- 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 +91 -70
- package/dist/ast-analysis/visitor.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 +54 -58
- 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 +32 -39
- 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 +57 -38
- package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
- package/dist/cli/commands/watch.d.ts.map +1 -1
- package/dist/cli/commands/watch.js +16 -2
- package/dist/cli/commands/watch.js.map +1 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +29 -26
- package/dist/db/connection.js.map +1 -1
- package/dist/db/query-builder.d.ts.map +1 -1
- package/dist/db/query-builder.js +16 -5
- package/dist/db/query-builder.js.map +1 -1
- package/dist/db/repository/base.d.ts +10 -0
- package/dist/db/repository/base.d.ts.map +1 -1
- package/dist/db/repository/base.js +17 -0
- package/dist/db/repository/base.js.map +1 -1
- package/dist/db/repository/native-repository.d.ts +6 -1
- package/dist/db/repository/native-repository.d.ts.map +1 -1
- package/dist/db/repository/native-repository.js +77 -1
- package/dist/db/repository/native-repository.js.map +1 -1
- package/dist/db/repository/nodes.d.ts.map +1 -1
- package/dist/db/repository/nodes.js +8 -4
- package/dist/db/repository/nodes.js.map +1 -1
- package/dist/db/repository/sqlite-repository.d.ts +3 -0
- package/dist/db/repository/sqlite-repository.d.ts.map +1 -1
- package/dist/db/repository/sqlite-repository.js +26 -0
- package/dist/db/repository/sqlite-repository.js.map +1 -1
- package/dist/domain/analysis/brief.d.ts.map +1 -1
- package/dist/domain/analysis/brief.js +13 -17
- 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 +14 -11
- 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 +53 -52
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +2 -7
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +33 -31
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/implementations.d.ts.map +1 -1
- package/dist/domain/analysis/implementations.js +11 -19
- package/dist/domain/analysis/implementations.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +55 -76
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +7 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -1
- package/dist/domain/analysis/query-helpers.js +15 -1
- package/dist/domain/analysis/query-helpers.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +255 -105
- 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 +22 -17
- package/dist/domain/graph/builder/stages/build-edges.js.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.js +2 -2
- 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 +32 -21
- 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 +95 -84
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/cycles.d.ts +6 -0
- package/dist/domain/graph/cycles.d.ts.map +1 -1
- package/dist/domain/graph/cycles.js +114 -22
- package/dist/domain/graph/cycles.js.map +1 -1
- package/dist/domain/graph/resolve.js +1 -1
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts +2 -0
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +170 -75
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +0 -5
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +13 -28
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/generator.js +1 -1
- package/dist/domain/search/generator.js.map +1 -1
- package/dist/domain/search/models.d.ts +4 -3
- package/dist/domain/search/models.d.ts.map +1 -1
- package/dist/domain/search/models.js +18 -5
- package/dist/domain/search/models.js.map +1 -1
- package/dist/domain/search/search/hybrid.d.ts.map +1 -1
- package/dist/domain/search/search/hybrid.js +29 -18
- package/dist/domain/search/search/hybrid.js.map +1 -1
- package/dist/extractors/go.js +36 -33
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +40 -29
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.js +58 -46
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.js +46 -45
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.js +84 -78
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/python.js +29 -24
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/rust.js +41 -32
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/solidity.js +58 -67
- package/dist/extractors/solidity.js.map +1 -1
- package/dist/extractors/swift.js +83 -81
- package/dist/extractors/swift.js.map +1 -1
- package/dist/extractors/zig.js +58 -60
- package/dist/extractors/zig.js.map +1 -1
- package/dist/features/ast.d.ts +16 -14
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +83 -81
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +8 -6
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +69 -72
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/communities.d.ts.map +1 -1
- package/dist/features/communities.js +19 -7
- package/dist/features/communities.js.map +1 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +120 -125
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +136 -137
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/flow.d.ts.map +1 -1
- package/dist/features/flow.js +84 -79
- package/dist/features/flow.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +69 -65
- package/dist/features/structure-query.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +70 -55
- 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 +288 -266
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +5 -1
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +6 -4
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/suppress.d.ts +25 -0
- package/dist/infrastructure/suppress.d.ts.map +1 -0
- package/dist/infrastructure/suppress.js +43 -0
- package/dist/infrastructure/suppress.js.map +1 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +29 -24
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/dataflow.d.ts.map +1 -1
- package/dist/presentation/dataflow.js +47 -38
- package/dist/presentation/dataflow.js.map +1 -1
- package/dist/presentation/diff-impact-mermaid.d.ts.map +1 -1
- package/dist/presentation/diff-impact-mermaid.js +60 -51
- package/dist/presentation/diff-impact-mermaid.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +20 -14
- 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 +15 -13
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/presentation/queries-cli/inspect.d.ts.map +1 -1
- package/dist/presentation/queries-cli/inspect.js +101 -79
- package/dist/presentation/queries-cli/inspect.js.map +1 -1
- package/dist/presentation/queries-cli/overview.d.ts.map +1 -1
- package/dist/presentation/queries-cli/overview.js +25 -16
- package/dist/presentation/queries-cli/overview.js.map +1 -1
- package/dist/presentation/queries-cli/path.js +26 -20
- package/dist/presentation/queries-cli/path.js.map +1 -1
- package/dist/presentation/result-formatter.d.ts +10 -0
- package/dist/presentation/result-formatter.d.ts.map +1 -1
- package/dist/presentation/result-formatter.js +16 -1
- package/dist/presentation/result-formatter.js.map +1 -1
- package/dist/presentation/viewer.d.ts.map +1 -1
- package/dist/presentation/viewer.js +18 -12
- package/dist/presentation/viewer.js.map +1 -1
- package/dist/shared/errors.d.ts +5 -0
- package/dist/shared/errors.d.ts.map +1 -1
- package/dist/shared/errors.js +5 -0
- package/dist/shared/errors.js.map +1 -1
- package/dist/shared/hierarchy.d.ts +8 -2
- package/dist/shared/hierarchy.d.ts.map +1 -1
- package/dist/shared/hierarchy.js +42 -1
- package/dist/shared/hierarchy.js.map +1 -1
- package/dist/shared/normalize.d.ts +6 -1
- package/dist/shared/normalize.d.ts.map +1 -1
- package/dist/shared/normalize.js +20 -12
- package/dist/shared/normalize.js.map +1 -1
- package/dist/shared/paginate.d.ts +0 -9
- package/dist/shared/paginate.d.ts.map +1 -1
- package/dist/shared/paginate.js +0 -15
- package/dist/shared/paginate.js.map +1 -1
- package/dist/types.d.ts +10 -4
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/ast-analysis/engine.ts +126 -105
- package/src/ast-analysis/metrics.ts +33 -11
- package/src/ast-analysis/shared.ts +33 -24
- package/src/ast-analysis/visitor-utils.ts +52 -32
- package/src/ast-analysis/visitor.ts +132 -71
- package/src/ast-analysis/visitors/ast-store-visitor.ts +53 -50
- package/src/ast-analysis/visitors/complexity-visitor.ts +35 -40
- package/src/ast-analysis/visitors/dataflow-visitor.ts +87 -43
- package/src/cli/commands/watch.ts +16 -2
- package/src/db/connection.ts +29 -28
- package/src/db/query-builder.ts +15 -3
- package/src/db/repository/base.ts +20 -0
- package/src/db/repository/native-repository.ts +79 -1
- package/src/db/repository/nodes.ts +13 -8
- package/src/db/repository/sqlite-repository.ts +29 -0
- package/src/domain/analysis/brief.ts +15 -25
- package/src/domain/analysis/context.ts +17 -10
- package/src/domain/analysis/dependencies.ts +67 -76
- package/src/domain/analysis/fn-impact.ts +36 -43
- package/src/domain/analysis/implementations.ts +11 -17
- package/src/domain/analysis/module-map.ts +58 -92
- package/src/domain/analysis/query-helpers.ts +18 -1
- package/src/domain/graph/builder/pipeline.ts +286 -97
- package/src/domain/graph/builder/stages/build-edges.ts +22 -18
- package/src/domain/graph/builder/stages/detect-changes.ts +2 -2
- package/src/domain/graph/builder/stages/finalize.ts +2 -2
- package/src/domain/graph/builder/stages/insert-nodes.ts +59 -34
- package/src/domain/graph/builder/stages/resolve-imports.ts +122 -100
- package/src/domain/graph/cycles.ts +110 -23
- package/src/domain/graph/resolve.ts +1 -1
- package/src/domain/graph/watcher.ts +202 -96
- package/src/domain/parser.ts +14 -26
- package/src/domain/search/generator.ts +1 -1
- package/src/domain/search/models.ts +17 -4
- package/src/domain/search/search/hybrid.ts +69 -51
- package/src/extractors/go.ts +43 -33
- package/src/extractors/helpers.ts +37 -23
- package/src/extractors/java.ts +66 -47
- package/src/extractors/javascript.ts +45 -46
- package/src/extractors/kotlin.ts +84 -77
- package/src/extractors/python.ts +31 -25
- package/src/extractors/rust.ts +37 -29
- package/src/extractors/solidity.ts +57 -61
- package/src/extractors/swift.ts +81 -80
- package/src/extractors/zig.ts +58 -61
- package/src/features/ast.ts +130 -110
- package/src/features/audit.ts +8 -6
- package/src/features/branch-compare.ts +105 -79
- package/src/features/communities.ts +25 -10
- package/src/features/complexity.ts +171 -134
- package/src/features/dataflow.ts +165 -175
- package/src/features/flow.ts +129 -92
- package/src/features/structure-query.ts +79 -64
- package/src/graph/algorithms/leiden/optimiser.ts +99 -55
- package/src/graph/algorithms/leiden/partition.ts +359 -294
- package/src/graph/model.ts +6 -1
- package/src/infrastructure/config.ts +6 -4
- package/src/infrastructure/suppress.ts +47 -0
- package/src/mcp/server.ts +53 -37
- package/src/presentation/dataflow.ts +50 -44
- package/src/presentation/diff-impact-mermaid.ts +104 -62
- package/src/presentation/queries-cli/exports.ts +21 -13
- package/src/presentation/queries-cli/impact.ts +15 -13
- package/src/presentation/queries-cli/inspect.ts +100 -81
- package/src/presentation/queries-cli/overview.ts +26 -16
- package/src/presentation/queries-cli/path.ts +33 -25
- package/src/presentation/result-formatter.ts +19 -1
- package/src/presentation/viewer.ts +42 -14
- package/src/shared/errors.ts +6 -0
- package/src/shared/hierarchy.ts +50 -2
- package/src/shared/normalize.ts +31 -12
- package/src/shared/paginate.ts +0 -17
- package/src/types.ts +24 -4
package/src/db/connection.ts
CHANGED
|
@@ -4,7 +4,7 @@ import path from 'node:path';
|
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
5
|
import { debug, warn } from '../infrastructure/logger.js';
|
|
6
6
|
import { getNative, isNativeAvailable } from '../infrastructure/native.js';
|
|
7
|
-
import { DbError } from '../shared/errors.js';
|
|
7
|
+
import { DbError, toErrorMessage } from '../shared/errors.js';
|
|
8
8
|
import type { BetterSqlite3Database, NativeDatabase } from '../types.js';
|
|
9
9
|
import { getDatabase } from './better-sqlite3.js';
|
|
10
10
|
import { Repository } from './repository/base.js';
|
|
@@ -20,7 +20,8 @@ function getPackageVersion(): string {
|
|
|
20
20
|
const pkgPath = path.join(connDir, '..', '..', 'package.json');
|
|
21
21
|
_packageVersion = (JSON.parse(fs.readFileSync(pkgPath, 'utf-8')) as { version: string })
|
|
22
22
|
.version;
|
|
23
|
-
} catch {
|
|
23
|
+
} catch (e) {
|
|
24
|
+
debug(`Failed to read package version: ${toErrorMessage(e)}`);
|
|
24
25
|
_packageVersion = '';
|
|
25
26
|
}
|
|
26
27
|
return _packageVersion;
|
|
@@ -41,8 +42,8 @@ function warnOnVersionMismatch(getBuildVersion: () => string | undefined | null)
|
|
|
41
42
|
`DB was built with codegraph v${buildVersion}, running v${currentVersion}. Consider: codegraph build --no-incremental`,
|
|
42
43
|
);
|
|
43
44
|
}
|
|
44
|
-
} catch {
|
|
45
|
-
|
|
45
|
+
} catch (e) {
|
|
46
|
+
debug(`Version mismatch check skipped (build_meta may not exist): ${toErrorMessage(e)}`);
|
|
46
47
|
}
|
|
47
48
|
}
|
|
48
49
|
|
|
@@ -78,11 +79,11 @@ export function findRepoRoot(fromDir?: string): string | null {
|
|
|
78
79
|
try {
|
|
79
80
|
root = fs.realpathSync(raw);
|
|
80
81
|
} catch (e) {
|
|
81
|
-
debug(`realpathSync failed for git root "${raw}", using resolve: ${(e
|
|
82
|
+
debug(`realpathSync failed for git root "${raw}", using resolve: ${toErrorMessage(e)}`);
|
|
82
83
|
root = path.resolve(raw);
|
|
83
84
|
}
|
|
84
85
|
} catch (e) {
|
|
85
|
-
debug(`git rev-parse failed for "${dir}": ${(e
|
|
86
|
+
debug(`git rev-parse failed for "${dir}": ${toErrorMessage(e)}`);
|
|
86
87
|
root = null;
|
|
87
88
|
}
|
|
88
89
|
if (!fromDir) {
|
|
@@ -103,7 +104,7 @@ function isProcessAlive(pid: number): boolean {
|
|
|
103
104
|
process.kill(pid, 0);
|
|
104
105
|
return true;
|
|
105
106
|
} catch (e) {
|
|
106
|
-
debug(`PID ${pid} not alive: ${(e as NodeJS.ErrnoException).code || (e
|
|
107
|
+
debug(`PID ${pid} not alive: ${(e as NodeJS.ErrnoException).code || toErrorMessage(e)}`);
|
|
107
108
|
return false;
|
|
108
109
|
}
|
|
109
110
|
}
|
|
@@ -119,12 +120,12 @@ function acquireAdvisoryLock(dbPath: string): void {
|
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
} catch (e) {
|
|
122
|
-
debug(`Advisory lock read failed: ${(e
|
|
123
|
+
debug(`Advisory lock read failed: ${toErrorMessage(e)}`);
|
|
123
124
|
}
|
|
124
125
|
try {
|
|
125
126
|
fs.writeFileSync(lockPath, String(process.pid), 'utf-8');
|
|
126
127
|
} catch (e) {
|
|
127
|
-
debug(`Advisory lock write failed: ${(e
|
|
128
|
+
debug(`Advisory lock write failed: ${toErrorMessage(e)}`);
|
|
128
129
|
}
|
|
129
130
|
}
|
|
130
131
|
|
|
@@ -135,7 +136,7 @@ function releaseAdvisoryLock(lockPath: string): void {
|
|
|
135
136
|
fs.unlinkSync(lockPath);
|
|
136
137
|
}
|
|
137
138
|
} catch (e) {
|
|
138
|
-
debug(`Advisory lock release failed for ${lockPath}: ${(e
|
|
139
|
+
debug(`Advisory lock release failed for ${lockPath}: ${toErrorMessage(e)}`);
|
|
139
140
|
}
|
|
140
141
|
}
|
|
141
142
|
|
|
@@ -151,7 +152,7 @@ function isSameDirectory(a: string, b: string): boolean {
|
|
|
151
152
|
const sb = fs.statSync(b);
|
|
152
153
|
return sa.dev === sb.dev && sa.ino === sb.ino;
|
|
153
154
|
} catch (e) {
|
|
154
|
-
debug(`isSameDirectory stat failed: ${(e
|
|
155
|
+
debug(`isSameDirectory stat failed: ${toErrorMessage(e)}`);
|
|
155
156
|
return false;
|
|
156
157
|
}
|
|
157
158
|
}
|
|
@@ -187,8 +188,8 @@ export function flushDeferredClose(): void {
|
|
|
187
188
|
const db = _deferredDbs.pop()!;
|
|
188
189
|
try {
|
|
189
190
|
db.close();
|
|
190
|
-
} catch {
|
|
191
|
-
|
|
191
|
+
} catch (e) {
|
|
192
|
+
debug(`Deferred DB close failed (handle may already be closed): ${toErrorMessage(e)}`);
|
|
192
193
|
}
|
|
193
194
|
}
|
|
194
195
|
}
|
|
@@ -216,8 +217,8 @@ export function closeDbDeferred(db: LockedDatabase): void {
|
|
|
216
217
|
_deferredDbs.splice(idx, 1);
|
|
217
218
|
try {
|
|
218
219
|
db.close();
|
|
219
|
-
} catch {
|
|
220
|
-
|
|
220
|
+
} catch (e) {
|
|
221
|
+
debug(`Deferred DB close failed (may already be closed by flush): ${toErrorMessage(e)}`);
|
|
221
222
|
}
|
|
222
223
|
}
|
|
223
224
|
});
|
|
@@ -239,8 +240,8 @@ export function closeDbPair(pair: LockedDatabasePair): void {
|
|
|
239
240
|
if (pair.nativeDb) {
|
|
240
241
|
try {
|
|
241
242
|
pair.nativeDb.close();
|
|
242
|
-
} catch {
|
|
243
|
-
|
|
243
|
+
} catch (e) {
|
|
244
|
+
debug(`closeDbPair: native close failed: ${toErrorMessage(e)}`);
|
|
244
245
|
}
|
|
245
246
|
}
|
|
246
247
|
closeDb(pair.db);
|
|
@@ -251,8 +252,8 @@ export function closeDbPairDeferred(pair: LockedDatabasePair): void {
|
|
|
251
252
|
if (pair.nativeDb) {
|
|
252
253
|
try {
|
|
253
254
|
pair.nativeDb.close();
|
|
254
|
-
} catch {
|
|
255
|
-
|
|
255
|
+
} catch (e) {
|
|
256
|
+
debug(`closeDbPairDeferred: native close failed: ${toErrorMessage(e)}`);
|
|
256
257
|
}
|
|
257
258
|
}
|
|
258
259
|
closeDbDeferred(pair.db);
|
|
@@ -270,7 +271,7 @@ export function findDbPath(customPath?: string): string {
|
|
|
270
271
|
try {
|
|
271
272
|
ceiling = fs.realpathSync(rawCeiling);
|
|
272
273
|
} catch (e) {
|
|
273
|
-
debug(`realpathSync failed for ceiling "${rawCeiling}": ${(e
|
|
274
|
+
debug(`realpathSync failed for ceiling "${rawCeiling}": ${toErrorMessage(e)}`);
|
|
274
275
|
ceiling = rawCeiling;
|
|
275
276
|
}
|
|
276
277
|
} else {
|
|
@@ -281,7 +282,7 @@ export function findDbPath(customPath?: string): string {
|
|
|
281
282
|
try {
|
|
282
283
|
dir = fs.realpathSync(process.cwd());
|
|
283
284
|
} catch (e) {
|
|
284
|
-
debug(`realpathSync failed for cwd: ${(e
|
|
285
|
+
debug(`realpathSync failed for cwd: ${toErrorMessage(e)}`);
|
|
285
286
|
dir = process.cwd();
|
|
286
287
|
}
|
|
287
288
|
while (true) {
|
|
@@ -334,9 +335,11 @@ function openRepoNative(customDbPath?: string): { repo: Repository; close(): voi
|
|
|
334
335
|
const ndb = native.NativeDatabase.openReadonly(dbPath);
|
|
335
336
|
try {
|
|
336
337
|
warnOnVersionMismatch(() => ndb.getBuildMeta('codegraph_version'));
|
|
338
|
+
const repo = new NativeRepository(ndb, dbPath);
|
|
337
339
|
return {
|
|
338
|
-
repo
|
|
340
|
+
repo,
|
|
339
341
|
close() {
|
|
342
|
+
repo.closeFallback();
|
|
340
343
|
ndb.close();
|
|
341
344
|
},
|
|
342
345
|
};
|
|
@@ -375,9 +378,7 @@ export function openRepo(
|
|
|
375
378
|
// Re-throw user-visible errors (e.g. DB not found) — only silently
|
|
376
379
|
// fall back for native-engine failures (e.g. incompatible native binary).
|
|
377
380
|
if (e instanceof DbError) throw e;
|
|
378
|
-
debug(
|
|
379
|
-
`openRepo: native path failed, falling back to better-sqlite3: ${(e as Error).message}`,
|
|
380
|
-
);
|
|
381
|
+
debug(`openRepo: native path failed, falling back to better-sqlite3: ${toErrorMessage(e)}`);
|
|
381
382
|
}
|
|
382
383
|
}
|
|
383
384
|
|
|
@@ -411,7 +412,7 @@ export function openReadonlyWithNative(customPath?: string): {
|
|
|
411
412
|
const native = getNative();
|
|
412
413
|
nativeDb = native.NativeDatabase.openReadonly(dbPath);
|
|
413
414
|
} catch (e) {
|
|
414
|
-
debug(`openReadonlyWithNative: native path failed: ${(e
|
|
415
|
+
debug(`openReadonlyWithNative: native path failed: ${toErrorMessage(e)}`);
|
|
415
416
|
}
|
|
416
417
|
}
|
|
417
418
|
|
|
@@ -423,8 +424,8 @@ export function openReadonlyWithNative(customPath?: string): {
|
|
|
423
424
|
if (nativeDb) {
|
|
424
425
|
try {
|
|
425
426
|
nativeDb.close();
|
|
426
|
-
} catch {
|
|
427
|
-
|
|
427
|
+
} catch (e) {
|
|
428
|
+
debug(`openReadonlyWithNative: native close failed: ${toErrorMessage(e)}`);
|
|
428
429
|
}
|
|
429
430
|
}
|
|
430
431
|
},
|
package/src/db/query-builder.ts
CHANGED
|
@@ -33,14 +33,26 @@ function validateOrderBy(clause: string): void {
|
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
+
/**
|
|
37
|
+
* Track parenthesis depth change for a character.
|
|
38
|
+
* Returns non-zero only for '(' / ')'; a character that is '(' or ')'
|
|
39
|
+
* can never simultaneously be ',' so the comma check in the caller
|
|
40
|
+
* remains mutually exclusive with the depth update.
|
|
41
|
+
*/
|
|
42
|
+
function parenDepthDelta(ch: string): number {
|
|
43
|
+
if (ch === '(') return 1;
|
|
44
|
+
if (ch === ')') return -1;
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
36
48
|
function splitTopLevelCommas(str: string): string[] {
|
|
37
49
|
const parts: string[] = [];
|
|
38
50
|
let depth = 0;
|
|
39
51
|
let start = 0;
|
|
40
52
|
for (let i = 0; i < str.length; i++) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
53
|
+
const ch = str[i]!;
|
|
54
|
+
depth += parenDepthDelta(ch);
|
|
55
|
+
if (ch === ',' && depth === 0) {
|
|
44
56
|
parts.push(str.slice(start, i).trim());
|
|
45
57
|
start = i + 1;
|
|
46
58
|
}
|
|
@@ -189,4 +189,24 @@ export class Repository implements IRepository {
|
|
|
189
189
|
getComplexityForNode(_nodeId: number): ComplexityMetrics | undefined {
|
|
190
190
|
throw new Error('not implemented');
|
|
191
191
|
}
|
|
192
|
+
|
|
193
|
+
// ── Convenience queries ──────────────────────────────────────────────
|
|
194
|
+
/**
|
|
195
|
+
* Look up the stored content hash for a file.
|
|
196
|
+
* Returns null when the file is not in file_hashes or the method is
|
|
197
|
+
* not yet implemented on the concrete repository.
|
|
198
|
+
*/
|
|
199
|
+
getFileHash(_file: string): string | null {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
/** Check whether the graph contains any 'implements' edges. */
|
|
204
|
+
hasImplementsEdges(): boolean {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/** Check whether the co_changes table exists and has data. */
|
|
209
|
+
hasCoChangesTable(): boolean {
|
|
210
|
+
return false;
|
|
211
|
+
}
|
|
192
212
|
}
|
|
@@ -8,9 +8,11 @@
|
|
|
8
8
|
* back to the snake_case field names that the Repository interface expects.
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import Database from 'better-sqlite3';
|
|
11
12
|
import { ConfigError } from '../../shared/errors.js';
|
|
12
13
|
import type {
|
|
13
14
|
AdjacentEdgeRow,
|
|
15
|
+
BetterSqlite3Database,
|
|
14
16
|
CallableNodeRow,
|
|
15
17
|
CallEdgeRow,
|
|
16
18
|
ChildNodeRow,
|
|
@@ -159,10 +161,33 @@ function toComplexityMetrics(r: NativeComplexityMetrics): ComplexityMetrics {
|
|
|
159
161
|
|
|
160
162
|
export class NativeRepository extends Repository {
|
|
161
163
|
#ndb: NativeDatabase;
|
|
164
|
+
#dbPath?: string;
|
|
165
|
+
#fallbackDb?: BetterSqlite3Database;
|
|
162
166
|
|
|
163
|
-
constructor(ndb: NativeDatabase) {
|
|
167
|
+
constructor(ndb: NativeDatabase, dbPath?: string) {
|
|
164
168
|
super();
|
|
165
169
|
this.#ndb = ndb;
|
|
170
|
+
this.#dbPath = dbPath;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/** Lazy better-sqlite3 handle for methods not yet ported to Rust. */
|
|
174
|
+
#getFallbackDb(): BetterSqlite3Database | undefined {
|
|
175
|
+
if (this.#fallbackDb) return this.#fallbackDb;
|
|
176
|
+
if (!this.#dbPath) return undefined;
|
|
177
|
+
try {
|
|
178
|
+
this.#fallbackDb = new Database(this.#dbPath, { readonly: true });
|
|
179
|
+
return this.#fallbackDb;
|
|
180
|
+
} catch {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Close the lazy fallback connection if it was opened. */
|
|
186
|
+
closeFallback(): void {
|
|
187
|
+
if (this.#fallbackDb) {
|
|
188
|
+
this.#fallbackDb.close();
|
|
189
|
+
this.#fallbackDb = undefined;
|
|
190
|
+
}
|
|
166
191
|
}
|
|
167
192
|
|
|
168
193
|
// ── Node lookups ──────────────────────────────────────────────────
|
|
@@ -358,4 +383,57 @@ export class NativeRepository extends Repository {
|
|
|
358
383
|
const r = this.#ndb.getComplexityForNode(nodeId);
|
|
359
384
|
return r ? toComplexityMetrics(r) : undefined;
|
|
360
385
|
}
|
|
386
|
+
|
|
387
|
+
// ── Convenience queries ────────────────────────────────────────────
|
|
388
|
+
|
|
389
|
+
getFileHash(file: string): string | null {
|
|
390
|
+
if (typeof this.#ndb.getFileHash === 'function') return this.#ndb.getFileHash(file);
|
|
391
|
+
// Fallback to better-sqlite3 until Rust implements getFileHash
|
|
392
|
+
const db = this.#getFallbackDb();
|
|
393
|
+
if (db) {
|
|
394
|
+
const row = db.prepare('SELECT hash FROM file_hashes WHERE file = ?').get(file) as
|
|
395
|
+
| { hash: string }
|
|
396
|
+
| undefined;
|
|
397
|
+
return row?.hash ?? null;
|
|
398
|
+
}
|
|
399
|
+
return null;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
#implementsEdgesCache?: boolean;
|
|
403
|
+
hasImplementsEdges(): boolean {
|
|
404
|
+
if (this.#implementsEdgesCache !== undefined) return this.#implementsEdgesCache;
|
|
405
|
+
if (typeof this.#ndb.hasImplementsEdges === 'function') {
|
|
406
|
+
this.#implementsEdgesCache = this.#ndb.hasImplementsEdges();
|
|
407
|
+
return this.#implementsEdgesCache;
|
|
408
|
+
}
|
|
409
|
+
// Fallback to better-sqlite3
|
|
410
|
+
const db = this.#getFallbackDb();
|
|
411
|
+
if (db) {
|
|
412
|
+
this.#implementsEdgesCache = !!db
|
|
413
|
+
.prepare("SELECT 1 FROM edges WHERE kind = 'implements' LIMIT 1")
|
|
414
|
+
.get();
|
|
415
|
+
return this.#implementsEdgesCache;
|
|
416
|
+
}
|
|
417
|
+
return true; // conservative: assume yes when no fallback available
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
#coChangesTableCache?: boolean;
|
|
421
|
+
hasCoChangesTable(): boolean {
|
|
422
|
+
if (this.#coChangesTableCache !== undefined) return this.#coChangesTableCache;
|
|
423
|
+
if (typeof this.#ndb.hasCoChangesTable === 'function') {
|
|
424
|
+
this.#coChangesTableCache = this.#ndb.hasCoChangesTable();
|
|
425
|
+
return this.#coChangesTableCache;
|
|
426
|
+
}
|
|
427
|
+
// Fallback to better-sqlite3
|
|
428
|
+
const db = this.#getFallbackDb();
|
|
429
|
+
if (db) {
|
|
430
|
+
try {
|
|
431
|
+
this.#coChangesTableCache = !!db.prepare('SELECT 1 FROM co_changes LIMIT 1').get();
|
|
432
|
+
} catch {
|
|
433
|
+
this.#coChangesTableCache = false;
|
|
434
|
+
}
|
|
435
|
+
return this.#coChangesTableCache;
|
|
436
|
+
}
|
|
437
|
+
return false;
|
|
438
|
+
}
|
|
361
439
|
}
|
|
@@ -42,14 +42,8 @@ export function findNodesWithFanIn(
|
|
|
42
42
|
return q.all(db, nativeDb);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
/**
|
|
46
|
-
|
|
47
|
-
*/
|
|
48
|
-
export function findNodesForTriage(
|
|
49
|
-
db: BetterSqlite3Database,
|
|
50
|
-
opts: TriageQueryOpts = {},
|
|
51
|
-
nativeDb?: NativeDatabase,
|
|
52
|
-
): TriageNodeRow[] {
|
|
45
|
+
/** Validate kind and role options, throwing on invalid values. */
|
|
46
|
+
function validateTriageOpts(opts: TriageQueryOpts): void {
|
|
53
47
|
if (opts.kind && !(EVERY_SYMBOL_KIND as readonly string[]).includes(opts.kind)) {
|
|
54
48
|
throw new ConfigError(
|
|
55
49
|
`Invalid kind: ${opts.kind} (expected one of ${EVERY_SYMBOL_KIND.join(', ')})`,
|
|
@@ -58,6 +52,17 @@ export function findNodesForTriage(
|
|
|
58
52
|
if (opts.role && !VALID_ROLES.includes(opts.role)) {
|
|
59
53
|
throw new ConfigError(`Invalid role: ${opts.role} (expected one of ${VALID_ROLES.join(', ')})`);
|
|
60
54
|
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Fetch nodes for triage scoring: fan-in + complexity + churn.
|
|
59
|
+
*/
|
|
60
|
+
export function findNodesForTriage(
|
|
61
|
+
db: BetterSqlite3Database,
|
|
62
|
+
opts: TriageQueryOpts = {},
|
|
63
|
+
nativeDb?: NativeDatabase,
|
|
64
|
+
): TriageNodeRow[] {
|
|
65
|
+
validateTriageOpts(opts);
|
|
61
66
|
|
|
62
67
|
const kindsToUse = opts.kind ? [opts.kind] : ['function', 'method', 'class'];
|
|
63
68
|
const q = new NodeQuery()
|
|
@@ -245,4 +245,33 @@ export class SqliteRepository extends Repository {
|
|
|
245
245
|
getComplexityForNode(nodeId: number): ComplexityMetrics | undefined {
|
|
246
246
|
return getComplexityForNode(this.#db, nodeId);
|
|
247
247
|
}
|
|
248
|
+
|
|
249
|
+
// ── Convenience queries ────────────────────────────────────────────
|
|
250
|
+
|
|
251
|
+
getFileHash(file: string): string | null {
|
|
252
|
+
const row = this.#db.prepare('SELECT hash FROM file_hashes WHERE file = ?').get(file) as
|
|
253
|
+
| { hash: string }
|
|
254
|
+
| undefined;
|
|
255
|
+
return row?.hash ?? null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
#implementsEdgesCache?: boolean;
|
|
259
|
+
hasImplementsEdges(): boolean {
|
|
260
|
+
if (this.#implementsEdgesCache !== undefined) return this.#implementsEdgesCache;
|
|
261
|
+
this.#implementsEdgesCache = !!this.#db
|
|
262
|
+
.prepare("SELECT 1 FROM edges WHERE kind = 'implements' LIMIT 1")
|
|
263
|
+
.get();
|
|
264
|
+
return this.#implementsEdgesCache;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
#coChangesTableCache?: boolean;
|
|
268
|
+
hasCoChangesTable(): boolean {
|
|
269
|
+
if (this.#coChangesTableCache !== undefined) return this.#coChangesTableCache;
|
|
270
|
+
try {
|
|
271
|
+
this.#coChangesTableCache = !!this.#db.prepare('SELECT 1 FROM co_changes LIMIT 1').get();
|
|
272
|
+
} catch {
|
|
273
|
+
this.#coChangesTableCache = false;
|
|
274
|
+
}
|
|
275
|
+
return this.#coChangesTableCache;
|
|
276
|
+
}
|
|
248
277
|
}
|
|
@@ -1,15 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
findDistinctCallers,
|
|
3
|
-
findFileNodes,
|
|
4
|
-
findImportDependents,
|
|
5
|
-
findImportSources,
|
|
6
|
-
findImportTargets,
|
|
7
|
-
findNodesByFile,
|
|
8
|
-
openReadonlyOrFail,
|
|
9
|
-
} from '../../db/index.js';
|
|
1
|
+
import type { Repository } from '../../db/index.js';
|
|
10
2
|
import { loadConfig } from '../../infrastructure/config.js';
|
|
11
3
|
import { isTestFile } from '../../infrastructure/test-filter.js';
|
|
12
|
-
import type {
|
|
4
|
+
import type { ImportEdgeRow, NodeRow, RelatedNodeRow } from '../../types.js';
|
|
5
|
+
import { withRepo } from './query-helpers.js';
|
|
13
6
|
|
|
14
7
|
/** Symbol kinds meaningful for a file brief — excludes parameters, properties, constants. */
|
|
15
8
|
const BRIEF_KINDS = new Set([
|
|
@@ -49,7 +42,7 @@ function computeRiskTier(
|
|
|
49
42
|
* Lightweight variant — only counts, does not collect details.
|
|
50
43
|
*/
|
|
51
44
|
function countTransitiveCallers(
|
|
52
|
-
|
|
45
|
+
repo: InstanceType<typeof Repository>,
|
|
53
46
|
startId: number,
|
|
54
47
|
noTests: boolean,
|
|
55
48
|
maxDepth = 5,
|
|
@@ -60,7 +53,7 @@ function countTransitiveCallers(
|
|
|
60
53
|
for (let d = 1; d <= maxDepth; d++) {
|
|
61
54
|
const nextFrontier: number[] = [];
|
|
62
55
|
for (const fid of frontier) {
|
|
63
|
-
const callers = findDistinctCallers(
|
|
56
|
+
const callers = repo.findDistinctCallers(fid) as RelatedNodeRow[];
|
|
64
57
|
for (const c of callers) {
|
|
65
58
|
if (!visited.has(c.id) && (!noTests || !isTestFile(c.file))) {
|
|
66
59
|
visited.add(c.id);
|
|
@@ -80,7 +73,7 @@ function countTransitiveCallers(
|
|
|
80
73
|
* Depth-bounded to match countTransitiveCallers and keep hook latency predictable.
|
|
81
74
|
*/
|
|
82
75
|
function countTransitiveImporters(
|
|
83
|
-
|
|
76
|
+
repo: InstanceType<typeof Repository>,
|
|
84
77
|
fileNodeIds: number[],
|
|
85
78
|
noTests: boolean,
|
|
86
79
|
maxDepth = 5,
|
|
@@ -91,7 +84,7 @@ function countTransitiveImporters(
|
|
|
91
84
|
for (let d = 1; d <= maxDepth; d++) {
|
|
92
85
|
const nextFrontier: number[] = [];
|
|
93
86
|
for (const current of frontier) {
|
|
94
|
-
const dependents = findImportDependents(
|
|
87
|
+
const dependents = repo.findImportDependents(current) as RelatedNodeRow[];
|
|
95
88
|
for (const dep of dependents) {
|
|
96
89
|
if (!visited.has(dep.id) && (!noTests || !isTestFile(dep.file))) {
|
|
97
90
|
visited.add(dep.id);
|
|
@@ -115,38 +108,37 @@ export function briefData(
|
|
|
115
108
|
customDbPath: string,
|
|
116
109
|
opts: { noTests?: boolean; config?: any } = {},
|
|
117
110
|
) {
|
|
118
|
-
|
|
119
|
-
try {
|
|
111
|
+
return withRepo(customDbPath, (repo) => {
|
|
120
112
|
const noTests = opts.noTests || false;
|
|
121
113
|
const config = opts.config || loadConfig();
|
|
122
114
|
const callerDepth = config.analysis?.briefCallerDepth ?? 5;
|
|
123
115
|
const importerDepth = config.analysis?.briefImporterDepth ?? 5;
|
|
124
116
|
const highRiskCallers = config.analysis?.briefHighRiskCallers ?? 10;
|
|
125
117
|
const mediumRiskCallers = config.analysis?.briefMediumRiskCallers ?? 3;
|
|
126
|
-
const fileNodes = findFileNodes(
|
|
118
|
+
const fileNodes = repo.findFileNodes(`%${file}%`) as NodeRow[];
|
|
127
119
|
if (fileNodes.length === 0) {
|
|
128
120
|
return { file, results: [] };
|
|
129
121
|
}
|
|
130
122
|
|
|
131
123
|
const results = fileNodes.map((fn) => {
|
|
132
124
|
// Direct importers
|
|
133
|
-
let importedBy = findImportSources(
|
|
125
|
+
let importedBy = repo.findImportSources(fn.id) as ImportEdgeRow[];
|
|
134
126
|
if (noTests) importedBy = importedBy.filter((i) => !isTestFile(i.file));
|
|
135
127
|
const directImporters = [...new Set(importedBy.map((i) => i.file))];
|
|
136
128
|
|
|
137
129
|
// Transitive importer count
|
|
138
|
-
const totalImporterCount = countTransitiveImporters(
|
|
130
|
+
const totalImporterCount = countTransitiveImporters(repo, [fn.id], noTests, importerDepth);
|
|
139
131
|
|
|
140
132
|
// Direct imports
|
|
141
|
-
let importsTo = findImportTargets(
|
|
133
|
+
let importsTo = repo.findImportTargets(fn.id) as ImportEdgeRow[];
|
|
142
134
|
if (noTests) importsTo = importsTo.filter((i) => !isTestFile(i.file));
|
|
143
135
|
|
|
144
136
|
// Symbol definitions with roles and caller counts
|
|
145
|
-
const defs = (findNodesByFile(
|
|
137
|
+
const defs = (repo.findNodesByFile(fn.file) as NodeRow[]).filter((d) =>
|
|
146
138
|
BRIEF_KINDS.has(d.kind),
|
|
147
139
|
);
|
|
148
140
|
const symbols = defs.map((d) => {
|
|
149
|
-
const callerCount = countTransitiveCallers(
|
|
141
|
+
const callerCount = countTransitiveCallers(repo, d.id, noTests, callerDepth);
|
|
150
142
|
return {
|
|
151
143
|
name: d.name,
|
|
152
144
|
kind: d.kind,
|
|
@@ -169,7 +161,5 @@ export function briefData(
|
|
|
169
161
|
});
|
|
170
162
|
|
|
171
163
|
return { file, results };
|
|
172
|
-
}
|
|
173
|
-
db.close();
|
|
174
|
-
}
|
|
164
|
+
});
|
|
175
165
|
}
|
|
@@ -264,6 +264,22 @@ function getNodeChildrenSafe(db: BetterSqlite3Database, nodeId: number) {
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
function buildIntraFileDataFlow(
|
|
268
|
+
db: BetterSqlite3Database,
|
|
269
|
+
file: string,
|
|
270
|
+
): Array<{ caller: string; callees: string[] }> {
|
|
271
|
+
const intraEdges = findIntraFileCallEdges(db, file) as IntraFileCallEdge[];
|
|
272
|
+
const dataFlowMap = new Map<string, string[]>();
|
|
273
|
+
for (const edge of intraEdges) {
|
|
274
|
+
if (!dataFlowMap.has(edge.caller_name)) dataFlowMap.set(edge.caller_name, []);
|
|
275
|
+
dataFlowMap.get(edge.caller_name)!.push(edge.callee_name);
|
|
276
|
+
}
|
|
277
|
+
return [...dataFlowMap.entries()].map(([caller, callees]) => ({
|
|
278
|
+
caller,
|
|
279
|
+
callees,
|
|
280
|
+
}));
|
|
281
|
+
}
|
|
282
|
+
|
|
267
283
|
function explainFileImpl(
|
|
268
284
|
db: BetterSqlite3Database,
|
|
269
285
|
target: string,
|
|
@@ -299,16 +315,7 @@ function explainFileImpl(
|
|
|
299
315
|
file: r.file,
|
|
300
316
|
}));
|
|
301
317
|
|
|
302
|
-
const
|
|
303
|
-
const dataFlowMap = new Map<string, string[]>();
|
|
304
|
-
for (const edge of intraEdges) {
|
|
305
|
-
if (!dataFlowMap.has(edge.caller_name)) dataFlowMap.set(edge.caller_name, []);
|
|
306
|
-
dataFlowMap.get(edge.caller_name)!.push(edge.callee_name);
|
|
307
|
-
}
|
|
308
|
-
const dataFlow = [...dataFlowMap.entries()].map(([caller, callees]) => ({
|
|
309
|
-
caller,
|
|
310
|
-
callees,
|
|
311
|
-
}));
|
|
318
|
+
const dataFlow = buildIntraFileDataFlow(db, fn.file);
|
|
312
319
|
|
|
313
320
|
const metric = getLineCountForNode(db, fn.id) as { line_count: number } | undefined;
|
|
314
321
|
let lineCount: number | null = metric?.line_count || null;
|