@optave/codegraph 3.10.0 → 3.11.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 +40 -33
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +91 -60
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/rules/index.d.ts.map +1 -1
- package/dist/ast-analysis/rules/index.js +77 -0
- package/dist/ast-analysis/rules/index.js.map +1 -1
- package/dist/ast-analysis/visitor-utils.d.ts +3 -0
- package/dist/ast-analysis/visitor-utils.d.ts.map +1 -1
- package/dist/ast-analysis/visitor-utils.js +83 -49
- package/dist/ast-analysis/visitor-utils.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 +78 -62
- package/dist/ast-analysis/visitors/ast-store-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 +61 -42
- package/dist/ast-analysis/visitors/dataflow-visitor.js.map +1 -1
- package/dist/cli/commands/audit.js +1 -1
- package/dist/cli/commands/audit.js.map +1 -1
- package/dist/cli/commands/build.d.ts.map +1 -1
- package/dist/cli/commands/build.js +2 -0
- package/dist/cli/commands/build.js.map +1 -1
- package/dist/cli/commands/check.js +1 -1
- package/dist/cli/commands/check.js.map +1 -1
- package/dist/cli/commands/children.js +1 -1
- package/dist/cli/commands/children.js.map +1 -1
- package/dist/cli/commands/diff-impact.js +1 -1
- package/dist/cli/commands/diff-impact.js.map +1 -1
- package/dist/cli/commands/embed.d.ts.map +1 -1
- package/dist/cli/commands/embed.js +49 -4
- package/dist/cli/commands/embed.js.map +1 -1
- package/dist/cli/commands/roles.js +1 -1
- package/dist/cli/commands/roles.js.map +1 -1
- package/dist/cli/commands/structure.js +1 -1
- package/dist/cli/commands/structure.js.map +1 -1
- package/dist/cli/shared/options.js +1 -1
- package/dist/cli/shared/options.js.map +1 -1
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +8 -0
- package/dist/db/connection.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +106 -80
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +77 -52
- 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 +132 -121
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/graph/builder/helpers.d.ts +4 -4
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +47 -33
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts +6 -6
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +148 -99
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts +1 -0
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +23 -637
- 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 +141 -98
- 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 +82 -65
- 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 +84 -56
- 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 +60 -51
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts +8 -6
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +107 -122
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts +14 -0
- package/dist/domain/graph/builder/stages/native-db-lifecycle.d.ts.map +1 -0
- package/dist/domain/graph/builder/stages/native-db-lifecycle.js +77 -0
- package/dist/domain/graph/builder/stages/native-db-lifecycle.js.map +1 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts +62 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.d.ts.map +1 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.js +747 -0
- package/dist/domain/graph/builder/stages/native-orchestrator.js.map +1 -0
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +73 -22
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/cycles.d.ts +6 -4
- package/dist/domain/graph/cycles.d.ts.map +1 -1
- package/dist/domain/graph/cycles.js +50 -55
- package/dist/domain/graph/cycles.js.map +1 -1
- package/dist/domain/graph/journal.d.ts.map +1 -1
- package/dist/domain/graph/journal.js +89 -70
- package/dist/domain/graph/journal.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +28 -20
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +12 -23
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +153 -80
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/generator.d.ts +3 -1
- package/dist/domain/search/generator.d.ts.map +1 -1
- package/dist/domain/search/generator.js +68 -45
- package/dist/domain/search/generator.js.map +1 -1
- package/dist/domain/search/models.d.ts +18 -0
- package/dist/domain/search/models.d.ts.map +1 -1
- package/dist/domain/search/models.js +72 -4
- 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 +49 -40
- package/dist/domain/search/search/hybrid.js.map +1 -1
- package/dist/domain/search/search/semantic.d.ts.map +1 -1
- package/dist/domain/search/search/semantic.js +69 -49
- package/dist/domain/search/search/semantic.js.map +1 -1
- package/dist/domain/wasm-worker-entry.js +209 -137
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/extractors/c.js +25 -6
- package/dist/extractors/c.js.map +1 -1
- package/dist/extractors/cpp.js +47 -6
- package/dist/extractors/cpp.js.map +1 -1
- package/dist/extractors/cuda.js +90 -14
- package/dist/extractors/cuda.js.map +1 -1
- package/dist/extractors/elixir.js +108 -4
- package/dist/extractors/elixir.js.map +1 -1
- package/dist/extractors/erlang.js +56 -20
- package/dist/extractors/erlang.js.map +1 -1
- package/dist/extractors/fsharp.d.ts +7 -0
- package/dist/extractors/fsharp.d.ts.map +1 -1
- package/dist/extractors/fsharp.js +94 -0
- package/dist/extractors/fsharp.js.map +1 -1
- package/dist/extractors/gleam.d.ts.map +1 -1
- package/dist/extractors/gleam.js +29 -33
- package/dist/extractors/gleam.js.map +1 -1
- package/dist/extractors/groovy.js +41 -1
- package/dist/extractors/groovy.js.map +1 -1
- package/dist/extractors/haskell.js +48 -4
- package/dist/extractors/haskell.js.map +1 -1
- package/dist/extractors/helpers.d.ts +79 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +137 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +37 -49
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +44 -44
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/julia.js +198 -74
- package/dist/extractors/julia.js.map +1 -1
- package/dist/extractors/kotlin.js +4 -0
- package/dist/extractors/kotlin.js.map +1 -1
- package/dist/extractors/objc.js +184 -47
- package/dist/extractors/objc.js.map +1 -1
- package/dist/extractors/python.js +7 -4
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/r.d.ts.map +1 -1
- package/dist/extractors/r.js +103 -87
- package/dist/extractors/r.js.map +1 -1
- package/dist/extractors/scala.d.ts.map +1 -1
- package/dist/extractors/scala.js +18 -32
- package/dist/extractors/scala.js.map +1 -1
- package/dist/extractors/solidity.d.ts.map +1 -1
- package/dist/extractors/solidity.js +55 -69
- package/dist/extractors/solidity.js.map +1 -1
- package/dist/extractors/verilog.js +80 -15
- package/dist/extractors/verilog.js.map +1 -1
- package/dist/features/boundaries.d.ts.map +1 -1
- package/dist/features/boundaries.js +49 -39
- package/dist/features/boundaries.js.map +1 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +90 -63
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +43 -34
- package/dist/features/check.js.map +1 -1
- package/dist/features/cochange.d.ts.map +1 -1
- package/dist/features/cochange.js +68 -56
- package/dist/features/cochange.js.map +1 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +105 -75
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +37 -29
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/flow.d.ts.map +1 -1
- package/dist/features/flow.js +31 -22
- package/dist/features/flow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +77 -70
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/owners.d.ts +17 -26
- package/dist/features/owners.d.ts.map +1 -1
- package/dist/features/owners.js +120 -109
- package/dist/features/owners.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +59 -54
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +60 -60
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.js +28 -36
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +100 -69
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/classifiers/roles.d.ts.map +1 -1
- package/dist/graph/classifiers/roles.js +63 -59
- package/dist/graph/classifiers/roles.js.map +1 -1
- package/dist/infrastructure/config.d.ts +1 -1
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +1 -1
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/mcp/tool-registry.d.ts.map +1 -1
- package/dist/mcp/tool-registry.js +4 -0
- package/dist/mcp/tool-registry.js.map +1 -1
- package/dist/mcp/tools/semantic-search.d.ts +1 -0
- package/dist/mcp/tools/semantic-search.d.ts.map +1 -1
- package/dist/mcp/tools/semantic-search.js +1 -0
- package/dist/mcp/tools/semantic-search.js.map +1 -1
- package/dist/presentation/cfg.d.ts.map +1 -1
- package/dist/presentation/cfg.js +44 -29
- package/dist/presentation/cfg.js.map +1 -1
- package/dist/presentation/flow.d.ts.map +1 -1
- package/dist/presentation/flow.js +58 -38
- package/dist/presentation/flow.js.map +1 -1
- package/dist/types.d.ts +16 -2
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-erlang.wasm +0 -0
- package/grammars/tree-sitter-fsharp.wasm +0 -0
- package/grammars/tree-sitter-fsharp_signature.wasm +0 -0
- package/grammars/tree-sitter-gleam.wasm +0 -0
- package/package.json +10 -10
- package/src/ast-analysis/engine.ts +145 -61
- package/src/ast-analysis/rules/index.ts +87 -0
- package/src/ast-analysis/visitor-utils.ts +86 -46
- package/src/ast-analysis/visitors/ast-store-visitor.ts +104 -69
- package/src/ast-analysis/visitors/dataflow-visitor.ts +86 -47
- package/src/cli/commands/audit.ts +1 -1
- package/src/cli/commands/build.ts +2 -0
- package/src/cli/commands/check.ts +1 -1
- package/src/cli/commands/children.ts +1 -1
- package/src/cli/commands/diff-impact.ts +1 -1
- package/src/cli/commands/embed.ts +54 -4
- package/src/cli/commands/roles.ts +1 -1
- package/src/cli/commands/structure.ts +1 -1
- package/src/cli/shared/options.ts +1 -1
- package/src/db/connection.ts +8 -0
- package/src/domain/analysis/dependencies.ts +166 -85
- package/src/domain/analysis/fn-impact.ts +120 -50
- package/src/domain/analysis/module-map.ts +175 -140
- package/src/domain/graph/builder/helpers.ts +85 -76
- package/src/domain/graph/builder/incremental.ts +223 -131
- package/src/domain/graph/builder/pipeline.ts +32 -785
- package/src/domain/graph/builder/stages/build-edges.ts +207 -142
- package/src/domain/graph/builder/stages/build-structure.ts +115 -82
- package/src/domain/graph/builder/stages/detect-changes.ts +107 -64
- package/src/domain/graph/builder/stages/finalize.ts +72 -70
- package/src/domain/graph/builder/stages/insert-nodes.ts +154 -120
- package/src/domain/graph/builder/stages/native-db-lifecycle.ts +74 -0
- package/src/domain/graph/builder/stages/native-orchestrator.ts +942 -0
- package/src/domain/graph/builder/stages/resolve-imports.ts +79 -25
- package/src/domain/graph/cycles.ts +51 -49
- package/src/domain/graph/journal.ts +84 -69
- package/src/domain/graph/watcher.ts +29 -25
- package/src/domain/parser.ts +170 -67
- package/src/domain/search/generator.ts +132 -74
- package/src/domain/search/models.ts +75 -4
- package/src/domain/search/search/hybrid.ts +53 -42
- package/src/domain/search/search/semantic.ts +105 -65
- package/src/domain/wasm-worker-entry.ts +243 -153
- package/src/extractors/c.ts +27 -8
- package/src/extractors/cpp.ts +50 -8
- package/src/extractors/cuda.ts +90 -16
- package/src/extractors/elixir.ts +103 -4
- package/src/extractors/erlang.ts +63 -20
- package/src/extractors/fsharp.ts +104 -0
- package/src/extractors/gleam.ts +40 -39
- package/src/extractors/groovy.ts +45 -1
- package/src/extractors/haskell.ts +45 -4
- package/src/extractors/helpers.ts +205 -1
- package/src/extractors/java.ts +42 -45
- package/src/extractors/javascript.ts +44 -43
- package/src/extractors/julia.ts +191 -77
- package/src/extractors/kotlin.ts +4 -0
- package/src/extractors/objc.ts +171 -47
- package/src/extractors/python.ts +5 -3
- package/src/extractors/r.ts +104 -82
- package/src/extractors/scala.ts +24 -36
- package/src/extractors/solidity.ts +59 -78
- package/src/extractors/verilog.ts +83 -15
- package/src/features/boundaries.ts +64 -46
- package/src/features/cfg.ts +145 -74
- package/src/features/check.ts +60 -43
- package/src/features/cochange.ts +95 -72
- package/src/features/complexity.ts +134 -79
- package/src/features/dataflow.ts +57 -34
- package/src/features/flow.ts +48 -24
- package/src/features/graph-enrichment.ts +105 -70
- package/src/features/owners.ts +186 -146
- package/src/features/sequence.ts +99 -69
- package/src/features/structure-query.ts +94 -79
- package/src/features/structure.ts +56 -56
- package/src/graph/algorithms/leiden/optimiser.ts +142 -87
- package/src/graph/classifiers/roles.ts +64 -54
- package/src/infrastructure/config.ts +1 -1
- package/src/mcp/tool-registry.ts +5 -0
- package/src/mcp/tools/semantic-search.ts +2 -0
- package/src/presentation/cfg.ts +48 -32
- package/src/presentation/flow.ts +100 -52
- package/src/types.ts +16 -1
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import fs from 'node:fs';
|
|
11
11
|
import path from 'node:path';
|
|
12
|
-
import { bulkNodeIdsByFile } from '../../../db/index.js';
|
|
12
|
+
import { bulkNodeIdsByFile, purgeFileData } from '../../../db/index.js';
|
|
13
13
|
import { debug, warn } from '../../../infrastructure/logger.js';
|
|
14
14
|
import { normalizePath } from '../../../shared/constants.js';
|
|
15
15
|
import type {
|
|
@@ -29,9 +29,8 @@ export interface IncrementalStmts {
|
|
|
29
29
|
insertNode: { run: (...params: unknown[]) => unknown };
|
|
30
30
|
insertEdge: { run: (...params: unknown[]) => unknown };
|
|
31
31
|
getNodeId: { get: (...params: unknown[]) => { id: number } | undefined };
|
|
32
|
-
deleteEdgesForFile: { run: (...params: unknown[]) => unknown };
|
|
33
|
-
deleteNodes: { run: (...params: unknown[]) => unknown };
|
|
34
32
|
countNodes: { get: (...params: unknown[]) => { c: number } | undefined };
|
|
33
|
+
countEdges: { get: (...params: unknown[]) => { c: number } | undefined };
|
|
35
34
|
listSymbols: { all: (...params: unknown[]) => unknown[] };
|
|
36
35
|
findNodeInFile: { all: (...params: unknown[]) => unknown[] };
|
|
37
36
|
findNodeByName: { all: (...params: unknown[]) => unknown[] };
|
|
@@ -42,6 +41,7 @@ interface RebuildResult {
|
|
|
42
41
|
nodesAdded: number;
|
|
43
42
|
nodesRemoved: number;
|
|
44
43
|
edgesAdded: number;
|
|
44
|
+
edgesBefore: number;
|
|
45
45
|
deleted?: boolean;
|
|
46
46
|
event?: string;
|
|
47
47
|
symbolDiff?: unknown;
|
|
@@ -208,40 +208,6 @@ function rebuildDirContainment(
|
|
|
208
208
|
return 0;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
// ── Ancillary table cleanup ────────────────────────────────────────────
|
|
212
|
-
|
|
213
|
-
function purgeAncillaryData(db: BetterSqlite3Database, relPath: string): void {
|
|
214
|
-
const tryExec = (sql: string, ...args: string[]): void => {
|
|
215
|
-
try {
|
|
216
|
-
db.prepare(sql).run(...args);
|
|
217
|
-
} catch (err: unknown) {
|
|
218
|
-
if (!(err as Error | undefined)?.message?.includes('no such table')) throw err;
|
|
219
|
-
}
|
|
220
|
-
};
|
|
221
|
-
tryExec(
|
|
222
|
-
'DELETE FROM function_complexity WHERE node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
223
|
-
relPath,
|
|
224
|
-
);
|
|
225
|
-
tryExec(
|
|
226
|
-
'DELETE FROM node_metrics WHERE node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
227
|
-
relPath,
|
|
228
|
-
);
|
|
229
|
-
tryExec(
|
|
230
|
-
'DELETE FROM cfg_edges WHERE function_node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
231
|
-
relPath,
|
|
232
|
-
);
|
|
233
|
-
tryExec(
|
|
234
|
-
'DELETE FROM cfg_blocks WHERE function_node_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
235
|
-
relPath,
|
|
236
|
-
);
|
|
237
|
-
tryExec(
|
|
238
|
-
'DELETE FROM dataflow WHERE source_id IN (SELECT id FROM nodes WHERE file = ?) OR target_id IN (SELECT id FROM nodes WHERE file = ?)',
|
|
239
|
-
relPath,
|
|
240
|
-
relPath,
|
|
241
|
-
);
|
|
242
|
-
tryExec('DELETE FROM ast_nodes WHERE file = ?', relPath);
|
|
243
|
-
}
|
|
244
|
-
|
|
245
211
|
// ── Import edge building ────────────────────────────────────────────────
|
|
246
212
|
|
|
247
213
|
// Lazily-cached prepared statements for barrel resolution (avoid re-preparing in hot loops)
|
|
@@ -343,6 +309,63 @@ function resolveBarrelImportEdges(
|
|
|
343
309
|
return edgesAdded;
|
|
344
310
|
}
|
|
345
311
|
|
|
312
|
+
/** Emit symbol-level `imports-type` edges for a single `import type` statement. */
|
|
313
|
+
function emitTypeOnlySymbolEdges(
|
|
314
|
+
db: BetterSqlite3Database | null,
|
|
315
|
+
stmts: IncrementalStmts,
|
|
316
|
+
imp: ExtractorOutput['imports'][number],
|
|
317
|
+
resolvedPath: string,
|
|
318
|
+
fileNodeId: number,
|
|
319
|
+
): number {
|
|
320
|
+
let edgesAdded = 0;
|
|
321
|
+
for (const name of imp.names) {
|
|
322
|
+
const cleanName = name.replace(/^\*\s+as\s+/, '');
|
|
323
|
+
let targetFile = resolvedPath;
|
|
324
|
+
if (db && isBarrelFile(db, resolvedPath)) {
|
|
325
|
+
const actual = resolveBarrelTarget(db, resolvedPath, cleanName);
|
|
326
|
+
if (actual) targetFile = actual;
|
|
327
|
+
}
|
|
328
|
+
const candidates = stmts.findNodeInFile.all(cleanName, targetFile) as Array<{
|
|
329
|
+
id: number;
|
|
330
|
+
file: string;
|
|
331
|
+
}>;
|
|
332
|
+
if (candidates.length === 0) continue;
|
|
333
|
+
stmts.insertEdge.run(fileNodeId, candidates[0]!.id, 'imports-type', 1.0, 0);
|
|
334
|
+
edgesAdded++;
|
|
335
|
+
}
|
|
336
|
+
return edgesAdded;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* Process a single import statement: emit the file→file edge, any
|
|
341
|
+
* symbol-level type-only edges, and barrel re-export edges.
|
|
342
|
+
*/
|
|
343
|
+
function emitEdgesForImport(
|
|
344
|
+
stmts: IncrementalStmts,
|
|
345
|
+
imp: ExtractorOutput['imports'][number],
|
|
346
|
+
fileNodeId: number,
|
|
347
|
+
relPath: string,
|
|
348
|
+
rootDir: string,
|
|
349
|
+
aliases: PathAliases,
|
|
350
|
+
db: BetterSqlite3Database | null,
|
|
351
|
+
): number {
|
|
352
|
+
const resolvedPath = resolveImportPath(path.join(rootDir, relPath), imp.source, rootDir, aliases);
|
|
353
|
+
const targetRow = stmts.getNodeId.get(resolvedPath, 'file', resolvedPath, 0);
|
|
354
|
+
if (!targetRow) return 0;
|
|
355
|
+
|
|
356
|
+
const edgeKind = imp.reexport ? 'reexports' : imp.typeOnly ? 'imports-type' : 'imports';
|
|
357
|
+
stmts.insertEdge.run(fileNodeId, targetRow.id, edgeKind, 1.0, 0);
|
|
358
|
+
let edgesAdded = 1;
|
|
359
|
+
|
|
360
|
+
if (imp.typeOnly) {
|
|
361
|
+
edgesAdded += emitTypeOnlySymbolEdges(db, stmts, imp, resolvedPath, fileNodeId);
|
|
362
|
+
}
|
|
363
|
+
if (!imp.reexport && db) {
|
|
364
|
+
edgesAdded += resolveBarrelImportEdges(db, stmts, fileNodeId, resolvedPath, imp);
|
|
365
|
+
}
|
|
366
|
+
return edgesAdded;
|
|
367
|
+
}
|
|
368
|
+
|
|
346
369
|
function buildImportEdges(
|
|
347
370
|
stmts: IncrementalStmts,
|
|
348
371
|
relPath: string,
|
|
@@ -354,44 +377,7 @@ function buildImportEdges(
|
|
|
354
377
|
): number {
|
|
355
378
|
let edgesAdded = 0;
|
|
356
379
|
for (const imp of symbols.imports) {
|
|
357
|
-
|
|
358
|
-
path.join(rootDir, relPath),
|
|
359
|
-
imp.source,
|
|
360
|
-
rootDir,
|
|
361
|
-
aliases,
|
|
362
|
-
);
|
|
363
|
-
const targetRow = stmts.getNodeId.get(resolvedPath, 'file', resolvedPath, 0);
|
|
364
|
-
if (targetRow) {
|
|
365
|
-
const edgeKind = imp.reexport ? 'reexports' : imp.typeOnly ? 'imports-type' : 'imports';
|
|
366
|
-
stmts.insertEdge.run(fileNodeId, targetRow.id, edgeKind, 1.0, 0);
|
|
367
|
-
edgesAdded++;
|
|
368
|
-
|
|
369
|
-
// Type-only imports: create symbol-level edges so the target symbols
|
|
370
|
-
// get fan-in credit and aren't falsely classified as dead code.
|
|
371
|
-
if (imp.typeOnly) {
|
|
372
|
-
for (const name of imp.names) {
|
|
373
|
-
const cleanName = name.replace(/^\*\s+as\s+/, '');
|
|
374
|
-
let targetFile = resolvedPath;
|
|
375
|
-
if (db && isBarrelFile(db, resolvedPath)) {
|
|
376
|
-
const actual = resolveBarrelTarget(db, resolvedPath, cleanName);
|
|
377
|
-
if (actual) targetFile = actual;
|
|
378
|
-
}
|
|
379
|
-
const candidates = stmts.findNodeInFile.all(cleanName, targetFile) as Array<{
|
|
380
|
-
id: number;
|
|
381
|
-
file: string;
|
|
382
|
-
}>;
|
|
383
|
-
if (candidates.length > 0) {
|
|
384
|
-
stmts.insertEdge.run(fileNodeId, candidates[0]!.id, 'imports-type', 1.0, 0);
|
|
385
|
-
edgesAdded++;
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Barrel resolution: create edges through re-export chains
|
|
391
|
-
if (!imp.reexport && db) {
|
|
392
|
-
edgesAdded += resolveBarrelImportEdges(db, stmts, fileNodeId, resolvedPath, imp);
|
|
393
|
-
}
|
|
394
|
-
}
|
|
380
|
+
edgesAdded += emitEdgesForImport(stmts, imp, fileNodeId, relPath, rootDir, aliases, db);
|
|
395
381
|
}
|
|
396
382
|
return edgesAdded;
|
|
397
383
|
}
|
|
@@ -527,6 +513,139 @@ function buildCallEdges(
|
|
|
527
513
|
|
|
528
514
|
// ── Main entry point ────────────────────────────────────────────────────
|
|
529
515
|
|
|
516
|
+
/** Build the "this file was deleted" result returned by `rebuildFile`. */
|
|
517
|
+
function buildDeletionResult(
|
|
518
|
+
relPath: string,
|
|
519
|
+
oldNodes: number,
|
|
520
|
+
edgesBefore: number,
|
|
521
|
+
oldSymbols: unknown[],
|
|
522
|
+
diffSymbols: ((old: unknown[], new_: unknown[]) => unknown) | undefined,
|
|
523
|
+
): RebuildResult {
|
|
524
|
+
const symbolDiff = diffSymbols ? diffSymbols(oldSymbols, []) : null;
|
|
525
|
+
return {
|
|
526
|
+
file: relPath,
|
|
527
|
+
nodesAdded: 0,
|
|
528
|
+
nodesRemoved: oldNodes,
|
|
529
|
+
edgesAdded: 0,
|
|
530
|
+
edgesBefore,
|
|
531
|
+
deleted: true,
|
|
532
|
+
event: 'deleted',
|
|
533
|
+
symbolDiff,
|
|
534
|
+
nodesBefore: oldNodes,
|
|
535
|
+
nodesAfter: 0,
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
/** Rebuild all edges originating in the single (just-parsed) target file. */
|
|
540
|
+
function rebuildEdgesForTargetFile(
|
|
541
|
+
db: BetterSqlite3Database,
|
|
542
|
+
stmts: IncrementalStmts,
|
|
543
|
+
relPath: string,
|
|
544
|
+
symbols: ExtractorOutput,
|
|
545
|
+
fileNodeRow: { id: number },
|
|
546
|
+
rootDir: string,
|
|
547
|
+
): number {
|
|
548
|
+
const aliases: PathAliases = { baseUrl: null, paths: {} };
|
|
549
|
+
let edgesAdded = buildContainmentEdges(db, stmts, relPath, symbols);
|
|
550
|
+
edgesAdded += rebuildDirContainment(db, stmts, relPath);
|
|
551
|
+
edgesAdded += buildImportEdges(stmts, relPath, symbols, rootDir, fileNodeRow.id, aliases, db);
|
|
552
|
+
const importedNames = buildImportedNamesMap(symbols, rootDir, relPath, aliases);
|
|
553
|
+
edgesAdded += buildCallEdges(stmts, relPath, symbols, fileNodeRow, importedNames);
|
|
554
|
+
return edgesAdded;
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
/**
|
|
558
|
+
* Re-parse the reverse-deps and delete their outgoing edges so the cascade
|
|
559
|
+
* can rebuild them. Returns the parsed symbols map together with the total
|
|
560
|
+
* edge count across all deps measured *before* deletion — callers add this
|
|
561
|
+
* to their own `edgesBefore` so the net delta stays correct even when the
|
|
562
|
+
* reverse-dep cascade re-inserts edges.
|
|
563
|
+
*/
|
|
564
|
+
async function parseReverseDeps(
|
|
565
|
+
db: BetterSqlite3Database,
|
|
566
|
+
rootDir: string,
|
|
567
|
+
reverseDeps: string[],
|
|
568
|
+
stmts: IncrementalStmts,
|
|
569
|
+
engineOpts: EngineOpts,
|
|
570
|
+
cache: unknown,
|
|
571
|
+
): Promise<{ depSymbols: Map<string, ExtractorOutput>; reverseDepsEdgesBefore: number }> {
|
|
572
|
+
const depSymbols = new Map<string, ExtractorOutput>();
|
|
573
|
+
let reverseDepsEdgesBefore = 0;
|
|
574
|
+
for (const depRelPath of reverseDeps) {
|
|
575
|
+
const symbols_ = await parseReverseDep(rootDir, depRelPath, engineOpts, cache);
|
|
576
|
+
if (symbols_) {
|
|
577
|
+
reverseDepsEdgesBefore += stmts.countEdges.get(depRelPath)?.c ?? 0;
|
|
578
|
+
deleteOutgoingEdges(db, depRelPath);
|
|
579
|
+
depSymbols.set(depRelPath, symbols_);
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return { depSymbols, reverseDepsEdgesBefore };
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
/**
|
|
586
|
+
* Pass 2 of the reverse-dep cascade: now that the changed file's `reexports`
|
|
587
|
+
* edges exist, resolve barrel imports for every reverse-dep so transitive
|
|
588
|
+
* call edges through the barrel still find their targets.
|
|
589
|
+
*/
|
|
590
|
+
function emitBarrelImportEdgesForReverseDeps(
|
|
591
|
+
db: BetterSqlite3Database,
|
|
592
|
+
stmts: IncrementalStmts,
|
|
593
|
+
depSymbols: Map<string, ExtractorOutput>,
|
|
594
|
+
rootDir: string,
|
|
595
|
+
): number {
|
|
596
|
+
let edgesAdded = 0;
|
|
597
|
+
for (const [depRelPath, symbols_] of depSymbols) {
|
|
598
|
+
const fileNodeRow_ = stmts.getNodeId.get(depRelPath, 'file', depRelPath, 0);
|
|
599
|
+
if (!fileNodeRow_) continue;
|
|
600
|
+
const aliases_: PathAliases = { baseUrl: null, paths: {} };
|
|
601
|
+
for (const imp of symbols_.imports) {
|
|
602
|
+
if (imp.reexport) continue;
|
|
603
|
+
const resolvedPath = resolveImportPath(
|
|
604
|
+
path.join(rootDir, depRelPath),
|
|
605
|
+
imp.source,
|
|
606
|
+
rootDir,
|
|
607
|
+
aliases_,
|
|
608
|
+
);
|
|
609
|
+
edgesAdded += resolveBarrelImportEdges(db, stmts, fileNodeRow_.id, resolvedPath, imp);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return edgesAdded;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Two-pass reverse-dep cascade:
|
|
617
|
+
* 1. Rebuild direct edges (creating `reexports` edges for barrels).
|
|
618
|
+
* 2. Add barrel import edges (which need `reexports` edges to exist).
|
|
619
|
+
* Returns both the gross edges-added count and the pre-deletion edge count
|
|
620
|
+
* for all reverse deps so callers can compute a true net delta.
|
|
621
|
+
*/
|
|
622
|
+
async function runReverseDepCascade(
|
|
623
|
+
db: BetterSqlite3Database,
|
|
624
|
+
rootDir: string,
|
|
625
|
+
reverseDeps: string[],
|
|
626
|
+
stmts: IncrementalStmts,
|
|
627
|
+
engineOpts: EngineOpts,
|
|
628
|
+
cache: unknown,
|
|
629
|
+
): Promise<{ edgesAdded: number; reverseDepsEdgesBefore: number }> {
|
|
630
|
+
const { depSymbols, reverseDepsEdgesBefore } = await parseReverseDeps(
|
|
631
|
+
db,
|
|
632
|
+
rootDir,
|
|
633
|
+
reverseDeps,
|
|
634
|
+
stmts,
|
|
635
|
+
engineOpts,
|
|
636
|
+
cache,
|
|
637
|
+
);
|
|
638
|
+
|
|
639
|
+
let edgesAdded = 0;
|
|
640
|
+
// Pass 1: direct edges only (no barrel resolution) — creates reexports edges
|
|
641
|
+
for (const [depRelPath, symbols_] of depSymbols) {
|
|
642
|
+
edgesAdded += rebuildReverseDepEdges(db, rootDir, depRelPath, symbols_, stmts, true);
|
|
643
|
+
}
|
|
644
|
+
// Pass 2: add barrel import edges (reexports edges now exist)
|
|
645
|
+
edgesAdded += emitBarrelImportEdgesForReverseDeps(db, stmts, depSymbols, rootDir);
|
|
646
|
+
return { edgesAdded, reverseDepsEdgesBefore };
|
|
647
|
+
}
|
|
648
|
+
|
|
530
649
|
/**
|
|
531
650
|
* Parse a single file and update the database incrementally.
|
|
532
651
|
*/
|
|
@@ -542,30 +661,21 @@ export async function rebuildFile(
|
|
|
542
661
|
const { diffSymbols } = options;
|
|
543
662
|
const relPath = normalizePath(path.relative(rootDir, filePath));
|
|
544
663
|
const oldNodes = stmts.countNodes.get(relPath)?.c || 0;
|
|
664
|
+
const edgesBefore = stmts.countEdges.get(relPath)?.c || 0;
|
|
545
665
|
const oldSymbols: unknown[] = diffSymbols ? stmts.listSymbols.all(relPath) : [];
|
|
546
666
|
|
|
547
667
|
// Find reverse-deps BEFORE purging (edges still reference the old nodes)
|
|
548
668
|
const reverseDeps = findReverseDeps(db, relPath);
|
|
549
669
|
|
|
550
|
-
// Purge ancillary tables,
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
670
|
+
// Purge ancillary tables (incl. embeddings), edges, and nodes in one pass.
|
|
671
|
+
// Embeddings must be purged before nodes — better-sqlite3 enforces foreign
|
|
672
|
+
// keys by default, and `embeddings.node_id` references `nodes.id`. Issue #1176.
|
|
673
|
+
// `purgeHashes: false` preserves file_hashes for the next incremental build.
|
|
674
|
+
purgeFileData(db, relPath, { purgeHashes: false });
|
|
554
675
|
|
|
555
676
|
if (!fs.existsSync(filePath)) {
|
|
556
677
|
if (cache) (cache as { remove(p: string): void }).remove(filePath);
|
|
557
|
-
|
|
558
|
-
return {
|
|
559
|
-
file: relPath,
|
|
560
|
-
nodesAdded: 0,
|
|
561
|
-
nodesRemoved: oldNodes,
|
|
562
|
-
edgesAdded: 0,
|
|
563
|
-
deleted: true,
|
|
564
|
-
event: 'deleted',
|
|
565
|
-
symbolDiff,
|
|
566
|
-
nodesBefore: oldNodes,
|
|
567
|
-
nodesAfter: 0,
|
|
568
|
-
};
|
|
678
|
+
return buildDeletionResult(relPath, oldNodes, edgesBefore, oldSymbols, diffSymbols);
|
|
569
679
|
}
|
|
570
680
|
|
|
571
681
|
let code: string;
|
|
@@ -586,47 +696,28 @@ export async function rebuildFile(
|
|
|
586
696
|
|
|
587
697
|
const fileNodeRow = stmts.getNodeId.get(relPath, 'file', relPath, 0);
|
|
588
698
|
if (!fileNodeRow)
|
|
589
|
-
return {
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
const importedNames = buildImportedNamesMap(symbols, rootDir, relPath, aliases);
|
|
597
|
-
edgesAdded += buildCallEdges(stmts, relPath, symbols, fileNodeRow, importedNames);
|
|
699
|
+
return {
|
|
700
|
+
file: relPath,
|
|
701
|
+
nodesAdded: newNodes,
|
|
702
|
+
nodesRemoved: oldNodes,
|
|
703
|
+
edgesAdded: 0,
|
|
704
|
+
edgesBefore,
|
|
705
|
+
};
|
|
598
706
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
//
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
}
|
|
614
|
-
// Pass 2: add barrel import edges (reexports edges now exist)
|
|
615
|
-
for (const [depRelPath, symbols_] of depSymbols) {
|
|
616
|
-
const fileNodeRow_ = stmts.getNodeId.get(depRelPath, 'file', depRelPath, 0);
|
|
617
|
-
if (!fileNodeRow_) continue;
|
|
618
|
-
const aliases_: PathAliases = { baseUrl: null, paths: {} };
|
|
619
|
-
for (const imp of symbols_.imports) {
|
|
620
|
-
if (imp.reexport) continue;
|
|
621
|
-
const resolvedPath = resolveImportPath(
|
|
622
|
-
path.join(rootDir, depRelPath),
|
|
623
|
-
imp.source,
|
|
624
|
-
rootDir,
|
|
625
|
-
aliases_,
|
|
626
|
-
);
|
|
627
|
-
edgesAdded += resolveBarrelImportEdges(db, stmts, fileNodeRow_.id, resolvedPath, imp);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
707
|
+
let edgesAdded = rebuildEdgesForTargetFile(db, stmts, relPath, symbols, fileNodeRow, rootDir);
|
|
708
|
+
const { edgesAdded: cascadeEdges, reverseDepsEdgesBefore } = await runReverseDepCascade(
|
|
709
|
+
db,
|
|
710
|
+
rootDir,
|
|
711
|
+
reverseDeps,
|
|
712
|
+
stmts,
|
|
713
|
+
engineOpts,
|
|
714
|
+
cache,
|
|
715
|
+
);
|
|
716
|
+
edgesAdded += cascadeEdges;
|
|
717
|
+
// Include pre-deletion edge counts from reverse deps so the net delta
|
|
718
|
+
// (edgesAdded - edgesBefore) is correct even when the cascade re-inserts
|
|
719
|
+
// their edges unchanged.
|
|
720
|
+
const totalEdgesBefore = edgesBefore + reverseDepsEdgesBefore;
|
|
630
721
|
|
|
631
722
|
const symbolDiff = diffSymbols ? diffSymbols(oldSymbols, newSymbols) : null;
|
|
632
723
|
const event = oldNodes === 0 ? 'added' : 'modified';
|
|
@@ -636,6 +727,7 @@ export async function rebuildFile(
|
|
|
636
727
|
nodesAdded: newNodes,
|
|
637
728
|
nodesRemoved: oldNodes,
|
|
638
729
|
edgesAdded,
|
|
730
|
+
edgesBefore: totalEdgesBefore,
|
|
639
731
|
deleted: false,
|
|
640
732
|
event,
|
|
641
733
|
symbolDiff,
|