@optave/codegraph 3.11.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 +38 -31
- 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/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/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/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 -0
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +142 -76
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts +1 -44
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +10 -766
- 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 +133 -96
- 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/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 +5 -2
- 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 +126 -79
- 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 +2 -0
- package/dist/domain/search/models.d.ts.map +1 -1
- package/dist/domain/search/models.js +37 -3
- 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 +201 -136
- package/dist/domain/wasm-worker-entry.js.map +1 -1
- package/dist/extractors/elixir.js +95 -71
- package/dist/extractors/elixir.js.map +1 -1
- package/dist/extractors/gleam.d.ts.map +1 -1
- package/dist/extractors/gleam.js +23 -31
- package/dist/extractors/gleam.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 +27 -34
- package/dist/extractors/julia.js.map +1 -1
- package/dist/extractors/r.d.ts.map +1 -1
- package/dist/extractors/r.js +33 -58
- package/dist/extractors/r.js.map +1 -1
- package/dist/extractors/solidity.d.ts.map +1 -1
- package/dist/extractors/solidity.js +38 -61
- package/dist/extractors/solidity.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/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 +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +7 -7
- package/src/ast-analysis/engine.ts +145 -61
- 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/embed.ts +54 -4
- 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 +217 -90
- package/src/domain/graph/builder/pipeline.ts +19 -957
- package/src/domain/graph/builder/stages/build-edges.ts +198 -140
- 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/cycles.ts +51 -49
- package/src/domain/graph/journal.ts +84 -69
- package/src/domain/graph/watcher.ts +8 -2
- package/src/domain/parser.ts +143 -66
- package/src/domain/search/generator.ts +132 -74
- package/src/domain/search/models.ts +39 -3
- 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 +235 -152
- package/src/extractors/elixir.ts +91 -64
- package/src/extractors/gleam.ts +33 -37
- 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 +28 -35
- package/src/extractors/r.ts +38 -56
- package/src/extractors/solidity.ts +43 -71
- 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/presentation/cfg.ts +48 -32
- package/src/presentation/flow.ts +100 -52
- package/src/types.ts +1 -1
|
@@ -30,6 +30,7 @@ export interface IncrementalStmts {
|
|
|
30
30
|
insertEdge: { run: (...params: unknown[]) => unknown };
|
|
31
31
|
getNodeId: { get: (...params: unknown[]) => { id: number } | undefined };
|
|
32
32
|
countNodes: { get: (...params: unknown[]) => { c: number } | undefined };
|
|
33
|
+
countEdges: { get: (...params: unknown[]) => { c: number } | undefined };
|
|
33
34
|
listSymbols: { all: (...params: unknown[]) => unknown[] };
|
|
34
35
|
findNodeInFile: { all: (...params: unknown[]) => unknown[] };
|
|
35
36
|
findNodeByName: { all: (...params: unknown[]) => unknown[] };
|
|
@@ -40,6 +41,7 @@ interface RebuildResult {
|
|
|
40
41
|
nodesAdded: number;
|
|
41
42
|
nodesRemoved: number;
|
|
42
43
|
edgesAdded: number;
|
|
44
|
+
edgesBefore: number;
|
|
43
45
|
deleted?: boolean;
|
|
44
46
|
event?: string;
|
|
45
47
|
symbolDiff?: unknown;
|
|
@@ -307,6 +309,63 @@ function resolveBarrelImportEdges(
|
|
|
307
309
|
return edgesAdded;
|
|
308
310
|
}
|
|
309
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
|
+
|
|
310
369
|
function buildImportEdges(
|
|
311
370
|
stmts: IncrementalStmts,
|
|
312
371
|
relPath: string,
|
|
@@ -318,44 +377,7 @@ function buildImportEdges(
|
|
|
318
377
|
): number {
|
|
319
378
|
let edgesAdded = 0;
|
|
320
379
|
for (const imp of symbols.imports) {
|
|
321
|
-
|
|
322
|
-
path.join(rootDir, relPath),
|
|
323
|
-
imp.source,
|
|
324
|
-
rootDir,
|
|
325
|
-
aliases,
|
|
326
|
-
);
|
|
327
|
-
const targetRow = stmts.getNodeId.get(resolvedPath, 'file', resolvedPath, 0);
|
|
328
|
-
if (targetRow) {
|
|
329
|
-
const edgeKind = imp.reexport ? 'reexports' : imp.typeOnly ? 'imports-type' : 'imports';
|
|
330
|
-
stmts.insertEdge.run(fileNodeId, targetRow.id, edgeKind, 1.0, 0);
|
|
331
|
-
edgesAdded++;
|
|
332
|
-
|
|
333
|
-
// Type-only imports: create symbol-level edges so the target symbols
|
|
334
|
-
// get fan-in credit and aren't falsely classified as dead code.
|
|
335
|
-
if (imp.typeOnly) {
|
|
336
|
-
for (const name of imp.names) {
|
|
337
|
-
const cleanName = name.replace(/^\*\s+as\s+/, '');
|
|
338
|
-
let targetFile = resolvedPath;
|
|
339
|
-
if (db && isBarrelFile(db, resolvedPath)) {
|
|
340
|
-
const actual = resolveBarrelTarget(db, resolvedPath, cleanName);
|
|
341
|
-
if (actual) targetFile = actual;
|
|
342
|
-
}
|
|
343
|
-
const candidates = stmts.findNodeInFile.all(cleanName, targetFile) as Array<{
|
|
344
|
-
id: number;
|
|
345
|
-
file: string;
|
|
346
|
-
}>;
|
|
347
|
-
if (candidates.length > 0) {
|
|
348
|
-
stmts.insertEdge.run(fileNodeId, candidates[0]!.id, 'imports-type', 1.0, 0);
|
|
349
|
-
edgesAdded++;
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
// Barrel resolution: create edges through re-export chains
|
|
355
|
-
if (!imp.reexport && db) {
|
|
356
|
-
edgesAdded += resolveBarrelImportEdges(db, stmts, fileNodeId, resolvedPath, imp);
|
|
357
|
-
}
|
|
358
|
-
}
|
|
380
|
+
edgesAdded += emitEdgesForImport(stmts, imp, fileNodeId, relPath, rootDir, aliases, db);
|
|
359
381
|
}
|
|
360
382
|
return edgesAdded;
|
|
361
383
|
}
|
|
@@ -491,6 +513,139 @@ function buildCallEdges(
|
|
|
491
513
|
|
|
492
514
|
// ── Main entry point ────────────────────────────────────────────────────
|
|
493
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
|
+
|
|
494
649
|
/**
|
|
495
650
|
* Parse a single file and update the database incrementally.
|
|
496
651
|
*/
|
|
@@ -506,6 +661,7 @@ export async function rebuildFile(
|
|
|
506
661
|
const { diffSymbols } = options;
|
|
507
662
|
const relPath = normalizePath(path.relative(rootDir, filePath));
|
|
508
663
|
const oldNodes = stmts.countNodes.get(relPath)?.c || 0;
|
|
664
|
+
const edgesBefore = stmts.countEdges.get(relPath)?.c || 0;
|
|
509
665
|
const oldSymbols: unknown[] = diffSymbols ? stmts.listSymbols.all(relPath) : [];
|
|
510
666
|
|
|
511
667
|
// Find reverse-deps BEFORE purging (edges still reference the old nodes)
|
|
@@ -519,18 +675,7 @@ export async function rebuildFile(
|
|
|
519
675
|
|
|
520
676
|
if (!fs.existsSync(filePath)) {
|
|
521
677
|
if (cache) (cache as { remove(p: string): void }).remove(filePath);
|
|
522
|
-
|
|
523
|
-
return {
|
|
524
|
-
file: relPath,
|
|
525
|
-
nodesAdded: 0,
|
|
526
|
-
nodesRemoved: oldNodes,
|
|
527
|
-
edgesAdded: 0,
|
|
528
|
-
deleted: true,
|
|
529
|
-
event: 'deleted',
|
|
530
|
-
symbolDiff,
|
|
531
|
-
nodesBefore: oldNodes,
|
|
532
|
-
nodesAfter: 0,
|
|
533
|
-
};
|
|
678
|
+
return buildDeletionResult(relPath, oldNodes, edgesBefore, oldSymbols, diffSymbols);
|
|
534
679
|
}
|
|
535
680
|
|
|
536
681
|
let code: string;
|
|
@@ -551,47 +696,28 @@ export async function rebuildFile(
|
|
|
551
696
|
|
|
552
697
|
const fileNodeRow = stmts.getNodeId.get(relPath, 'file', relPath, 0);
|
|
553
698
|
if (!fileNodeRow)
|
|
554
|
-
return {
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
const importedNames = buildImportedNamesMap(symbols, rootDir, relPath, aliases);
|
|
562
|
-
edgesAdded += buildCallEdges(stmts, relPath, symbols, fileNodeRow, importedNames);
|
|
699
|
+
return {
|
|
700
|
+
file: relPath,
|
|
701
|
+
nodesAdded: newNodes,
|
|
702
|
+
nodesRemoved: oldNodes,
|
|
703
|
+
edgesAdded: 0,
|
|
704
|
+
edgesBefore,
|
|
705
|
+
};
|
|
563
706
|
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
//
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
}
|
|
579
|
-
// Pass 2: add barrel import edges (reexports edges now exist)
|
|
580
|
-
for (const [depRelPath, symbols_] of depSymbols) {
|
|
581
|
-
const fileNodeRow_ = stmts.getNodeId.get(depRelPath, 'file', depRelPath, 0);
|
|
582
|
-
if (!fileNodeRow_) continue;
|
|
583
|
-
const aliases_: PathAliases = { baseUrl: null, paths: {} };
|
|
584
|
-
for (const imp of symbols_.imports) {
|
|
585
|
-
if (imp.reexport) continue;
|
|
586
|
-
const resolvedPath = resolveImportPath(
|
|
587
|
-
path.join(rootDir, depRelPath),
|
|
588
|
-
imp.source,
|
|
589
|
-
rootDir,
|
|
590
|
-
aliases_,
|
|
591
|
-
);
|
|
592
|
-
edgesAdded += resolveBarrelImportEdges(db, stmts, fileNodeRow_.id, resolvedPath, imp);
|
|
593
|
-
}
|
|
594
|
-
}
|
|
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;
|
|
595
721
|
|
|
596
722
|
const symbolDiff = diffSymbols ? diffSymbols(oldSymbols, newSymbols) : null;
|
|
597
723
|
const event = oldNodes === 0 ? 'added' : 'modified';
|
|
@@ -601,6 +727,7 @@ export async function rebuildFile(
|
|
|
601
727
|
nodesAdded: newNodes,
|
|
602
728
|
nodesRemoved: oldNodes,
|
|
603
729
|
edgesAdded,
|
|
730
|
+
edgesBefore: totalEdgesBefore,
|
|
604
731
|
deleted: false,
|
|
605
732
|
event,
|
|
606
733
|
symbolDiff,
|