@optave/codegraph 3.5.0 → 3.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -14
- package/dist/ast-analysis/engine.d.ts.map +1 -1
- package/dist/ast-analysis/engine.js +119 -127
- package/dist/ast-analysis/engine.js.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js +14 -1
- package/dist/ast-analysis/visitors/ast-store-visitor.js.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.d.ts.map +1 -1
- package/dist/ast-analysis/visitors/complexity-visitor.js +11 -13
- package/dist/ast-analysis/visitors/complexity-visitor.js.map +1 -1
- package/dist/db/connection.d.ts +12 -2
- package/dist/db/connection.d.ts.map +1 -1
- package/dist/db/connection.js +81 -53
- package/dist/db/connection.js.map +1 -1
- package/dist/db/index.d.ts +1 -1
- package/dist/db/index.d.ts.map +1 -1
- package/dist/db/index.js +1 -1
- package/dist/db/index.js.map +1 -1
- package/dist/db/migrations.d.ts.map +1 -1
- package/dist/db/migrations.js +38 -32
- package/dist/db/migrations.js.map +1 -1
- package/dist/domain/analysis/context.d.ts.map +1 -1
- package/dist/domain/analysis/context.js +51 -66
- package/dist/domain/analysis/context.js.map +1 -1
- package/dist/domain/analysis/dependencies.d.ts.map +1 -1
- package/dist/domain/analysis/dependencies.js +62 -70
- package/dist/domain/analysis/dependencies.js.map +1 -1
- package/dist/domain/analysis/diff-impact.d.ts +9 -7
- package/dist/domain/analysis/diff-impact.d.ts.map +1 -1
- package/dist/domain/analysis/exports.d.ts.map +1 -1
- package/dist/domain/analysis/exports.js +29 -33
- package/dist/domain/analysis/exports.js.map +1 -1
- package/dist/domain/analysis/fn-impact.d.ts +15 -17
- package/dist/domain/analysis/fn-impact.d.ts.map +1 -1
- package/dist/domain/analysis/fn-impact.js +35 -65
- package/dist/domain/analysis/fn-impact.js.map +1 -1
- package/dist/domain/analysis/module-map.d.ts.map +1 -1
- package/dist/domain/analysis/module-map.js +91 -6
- package/dist/domain/analysis/module-map.js.map +1 -1
- package/dist/domain/analysis/query-helpers.d.ts +20 -0
- package/dist/domain/analysis/query-helpers.d.ts.map +1 -0
- package/dist/domain/analysis/query-helpers.js +27 -0
- package/dist/domain/analysis/query-helpers.js.map +1 -0
- package/dist/domain/graph/builder/helpers.d.ts.map +1 -1
- package/dist/domain/graph/builder/helpers.js +15 -9
- package/dist/domain/graph/builder/helpers.js.map +1 -1
- package/dist/domain/graph/builder/incremental.d.ts.map +1 -1
- package/dist/domain/graph/builder/incremental.js +3 -2
- package/dist/domain/graph/builder/incremental.js.map +1 -1
- package/dist/domain/graph/builder/pipeline.d.ts.map +1 -1
- package/dist/domain/graph/builder/pipeline.js +69 -3
- package/dist/domain/graph/builder/pipeline.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-edges.js +7 -51
- package/dist/domain/graph/builder/stages/build-edges.js.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/build-structure.js +7 -5
- package/dist/domain/graph/builder/stages/build-structure.js.map +1 -1
- package/dist/domain/graph/builder/stages/collect-files.js +2 -2
- package/dist/domain/graph/builder/stages/collect-files.js.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/detect-changes.js +2 -2
- package/dist/domain/graph/builder/stages/detect-changes.js.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/finalize.js +124 -105
- package/dist/domain/graph/builder/stages/finalize.js.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/insert-nodes.js +28 -15
- package/dist/domain/graph/builder/stages/insert-nodes.js.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.d.ts.map +1 -1
- package/dist/domain/graph/builder/stages/resolve-imports.js +3 -2
- package/dist/domain/graph/builder/stages/resolve-imports.js.map +1 -1
- package/dist/domain/graph/resolve.d.ts +0 -4
- package/dist/domain/graph/resolve.d.ts.map +1 -1
- package/dist/domain/graph/resolve.js +32 -48
- package/dist/domain/graph/resolve.js.map +1 -1
- package/dist/domain/graph/watcher.d.ts.map +1 -1
- package/dist/domain/graph/watcher.js +12 -12
- package/dist/domain/graph/watcher.js.map +1 -1
- package/dist/domain/parser.d.ts +1 -1
- package/dist/domain/parser.d.ts.map +1 -1
- package/dist/domain/parser.js +164 -101
- package/dist/domain/parser.js.map +1 -1
- package/dist/domain/search/search/cli-formatter.d.ts.map +1 -1
- package/dist/domain/search/search/cli-formatter.js +88 -83
- package/dist/domain/search/search/cli-formatter.js.map +1 -1
- package/dist/extractors/bash.d.ts +6 -0
- package/dist/extractors/bash.d.ts.map +1 -0
- package/dist/extractors/bash.js +91 -0
- package/dist/extractors/bash.js.map +1 -0
- package/dist/extractors/c.d.ts +6 -0
- package/dist/extractors/c.d.ts.map +1 -0
- package/dist/extractors/c.js +204 -0
- package/dist/extractors/c.js.map +1 -0
- package/dist/extractors/cpp.d.ts +6 -0
- package/dist/extractors/cpp.d.ts.map +1 -0
- package/dist/extractors/cpp.js +283 -0
- package/dist/extractors/cpp.js.map +1 -0
- package/dist/extractors/csharp.d.ts.map +1 -1
- package/dist/extractors/csharp.js +42 -54
- package/dist/extractors/csharp.js.map +1 -1
- package/dist/extractors/go.d.ts.map +1 -1
- package/dist/extractors/go.js +126 -130
- package/dist/extractors/go.js.map +1 -1
- package/dist/extractors/hcl.js +6 -6
- package/dist/extractors/hcl.js.map +1 -1
- package/dist/extractors/helpers.d.ts +32 -1
- package/dist/extractors/helpers.d.ts.map +1 -1
- package/dist/extractors/helpers.js +74 -0
- package/dist/extractors/helpers.js.map +1 -1
- package/dist/extractors/index.d.ts +6 -0
- package/dist/extractors/index.d.ts.map +1 -1
- package/dist/extractors/index.js +6 -0
- package/dist/extractors/index.js.map +1 -1
- package/dist/extractors/java.d.ts.map +1 -1
- package/dist/extractors/java.js +32 -47
- package/dist/extractors/java.js.map +1 -1
- package/dist/extractors/javascript.d.ts.map +1 -1
- package/dist/extractors/javascript.js +306 -292
- package/dist/extractors/javascript.js.map +1 -1
- package/dist/extractors/kotlin.d.ts +6 -0
- package/dist/extractors/kotlin.d.ts.map +1 -0
- package/dist/extractors/kotlin.js +275 -0
- package/dist/extractors/kotlin.js.map +1 -0
- package/dist/extractors/php.d.ts.map +1 -1
- package/dist/extractors/php.js +39 -44
- package/dist/extractors/php.js.map +1 -1
- package/dist/extractors/python.d.ts.map +1 -1
- package/dist/extractors/python.js +75 -93
- package/dist/extractors/python.js.map +1 -1
- package/dist/extractors/ruby.js +6 -13
- package/dist/extractors/ruby.js.map +1 -1
- package/dist/extractors/rust.d.ts.map +1 -1
- package/dist/extractors/rust.js +58 -83
- package/dist/extractors/rust.js.map +1 -1
- package/dist/extractors/scala.d.ts +6 -0
- package/dist/extractors/scala.d.ts.map +1 -0
- package/dist/extractors/scala.js +269 -0
- package/dist/extractors/scala.js.map +1 -0
- package/dist/extractors/swift.d.ts +6 -0
- package/dist/extractors/swift.d.ts.map +1 -0
- package/dist/extractors/swift.js +275 -0
- package/dist/extractors/swift.js.map +1 -0
- package/dist/features/ast.d.ts +2 -0
- package/dist/features/ast.d.ts.map +1 -1
- package/dist/features/ast.js +9 -24
- package/dist/features/ast.js.map +1 -1
- package/dist/features/audit.d.ts.map +1 -1
- package/dist/features/audit.js +17 -21
- package/dist/features/audit.js.map +1 -1
- package/dist/features/branch-compare.d.ts.map +1 -1
- package/dist/features/branch-compare.js +47 -3
- package/dist/features/branch-compare.js.map +1 -1
- package/dist/features/cfg.d.ts +7 -1
- package/dist/features/cfg.d.ts.map +1 -1
- package/dist/features/cfg.js +118 -62
- package/dist/features/cfg.js.map +1 -1
- package/dist/features/check.d.ts.map +1 -1
- package/dist/features/check.js +79 -62
- package/dist/features/check.js.map +1 -1
- package/dist/features/complexity-query.d.ts.map +1 -1
- package/dist/features/complexity-query.js +142 -137
- package/dist/features/complexity-query.js.map +1 -1
- package/dist/features/complexity.d.ts +7 -1
- package/dist/features/complexity.d.ts.map +1 -1
- package/dist/features/complexity.js +62 -1
- package/dist/features/complexity.js.map +1 -1
- package/dist/features/dataflow.d.ts +7 -1
- package/dist/features/dataflow.d.ts.map +1 -1
- package/dist/features/dataflow.js +356 -188
- package/dist/features/dataflow.js.map +1 -1
- package/dist/features/graph-enrichment.d.ts.map +1 -1
- package/dist/features/graph-enrichment.js +117 -104
- package/dist/features/graph-enrichment.js.map +1 -1
- package/dist/features/sequence.d.ts.map +1 -1
- package/dist/features/sequence.js +25 -4
- package/dist/features/sequence.js.map +1 -1
- package/dist/features/structure-query.d.ts.map +1 -1
- package/dist/features/structure-query.js +29 -4
- package/dist/features/structure-query.js.map +1 -1
- package/dist/features/structure.d.ts.map +1 -1
- package/dist/features/structure.js +35 -15
- package/dist/features/structure.js.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/adapter.js +88 -73
- package/dist/graph/algorithms/leiden/adapter.js.map +1 -1
- package/dist/graph/algorithms/leiden/index.js +43 -28
- package/dist/graph/algorithms/leiden/index.js.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/optimiser.js +90 -104
- package/dist/graph/algorithms/leiden/optimiser.js.map +1 -1
- package/dist/graph/algorithms/leiden/partition.d.ts.map +1 -1
- package/dist/graph/algorithms/leiden/partition.js +89 -106
- package/dist/graph/algorithms/leiden/partition.js.map +1 -1
- package/dist/graph/model.d.ts +2 -0
- package/dist/graph/model.d.ts.map +1 -1
- package/dist/graph/model.js +20 -8
- package/dist/graph/model.js.map +1 -1
- package/dist/infrastructure/config.d.ts +0 -8
- package/dist/infrastructure/config.d.ts.map +1 -1
- package/dist/infrastructure/config.js +73 -62
- package/dist/infrastructure/config.js.map +1 -1
- package/dist/infrastructure/registry.d.ts +0 -8
- package/dist/infrastructure/registry.d.ts.map +1 -1
- package/dist/infrastructure/registry.js +12 -14
- package/dist/infrastructure/registry.js.map +1 -1
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +45 -36
- package/dist/mcp/server.js.map +1 -1
- package/dist/presentation/audit.d.ts.map +1 -1
- package/dist/presentation/audit.js +61 -57
- package/dist/presentation/audit.js.map +1 -1
- package/dist/presentation/branch-compare.d.ts.map +1 -1
- package/dist/presentation/branch-compare.js +56 -38
- package/dist/presentation/branch-compare.js.map +1 -1
- package/dist/presentation/check.d.ts.map +1 -1
- package/dist/presentation/check.js +30 -32
- package/dist/presentation/check.js.map +1 -1
- package/dist/presentation/colors.d.ts.map +1 -1
- package/dist/presentation/colors.js +2 -0
- package/dist/presentation/colors.js.map +1 -1
- package/dist/presentation/complexity.d.ts.map +1 -1
- package/dist/presentation/complexity.js +25 -19
- package/dist/presentation/complexity.js.map +1 -1
- package/dist/presentation/queries-cli/exports.d.ts.map +1 -1
- package/dist/presentation/queries-cli/exports.js +15 -15
- package/dist/presentation/queries-cli/exports.js.map +1 -1
- package/dist/presentation/queries-cli/impact.d.ts.map +1 -1
- package/dist/presentation/queries-cli/impact.js +29 -19
- package/dist/presentation/queries-cli/impact.js.map +1 -1
- package/dist/types.d.ts +182 -7
- package/dist/types.d.ts.map +1 -1
- package/grammars/tree-sitter-bash.wasm +0 -0
- package/grammars/tree-sitter-c.wasm +0 -0
- package/grammars/tree-sitter-cpp.wasm +0 -0
- package/grammars/tree-sitter-kotlin.wasm +0 -0
- package/grammars/tree-sitter-scala.wasm +0 -0
- package/grammars/tree-sitter-swift.wasm +0 -0
- package/package.json +13 -7
- package/src/ast-analysis/engine.ts +147 -138
- package/src/ast-analysis/visitors/ast-store-visitor.ts +15 -2
- package/src/ast-analysis/visitors/complexity-visitor.ts +11 -11
- package/src/db/connection.ts +90 -59
- package/src/db/index.ts +1 -0
- package/src/db/migrations.ts +36 -32
- package/src/domain/analysis/context.ts +73 -75
- package/src/domain/analysis/dependencies.ts +78 -68
- package/src/domain/analysis/exports.ts +45 -34
- package/src/domain/analysis/fn-impact.ts +67 -64
- package/src/domain/analysis/module-map.ts +103 -8
- package/src/domain/analysis/query-helpers.ts +35 -0
- package/src/domain/graph/builder/helpers.ts +12 -6
- package/src/domain/graph/builder/incremental.ts +3 -2
- package/src/domain/graph/builder/pipeline.ts +71 -3
- package/src/domain/graph/builder/stages/build-edges.ts +10 -75
- package/src/domain/graph/builder/stages/build-structure.ts +9 -7
- package/src/domain/graph/builder/stages/collect-files.ts +2 -2
- package/src/domain/graph/builder/stages/detect-changes.ts +7 -2
- package/src/domain/graph/builder/stages/finalize.ts +159 -125
- package/src/domain/graph/builder/stages/insert-nodes.ts +32 -21
- package/src/domain/graph/builder/stages/resolve-imports.ts +3 -2
- package/src/domain/graph/resolve.ts +34 -46
- package/src/domain/graph/watcher.ts +12 -14
- package/src/domain/parser.ts +168 -97
- package/src/domain/search/search/cli-formatter.ts +121 -94
- package/src/extractors/bash.ts +97 -0
- package/src/extractors/c.ts +212 -0
- package/src/extractors/cpp.ts +298 -0
- package/src/extractors/csharp.ts +53 -56
- package/src/extractors/go.ts +152 -134
- package/src/extractors/hcl.ts +6 -6
- package/src/extractors/helpers.ts +93 -1
- package/src/extractors/index.ts +6 -0
- package/src/extractors/java.ts +43 -48
- package/src/extractors/javascript.ts +328 -281
- package/src/extractors/kotlin.ts +293 -0
- package/src/extractors/php.ts +46 -40
- package/src/extractors/python.ts +81 -104
- package/src/extractors/ruby.ts +6 -13
- package/src/extractors/rust.ts +65 -85
- package/src/extractors/scala.ts +285 -0
- package/src/extractors/swift.ts +293 -0
- package/src/features/ast.ts +10 -25
- package/src/features/audit.ts +24 -20
- package/src/features/branch-compare.ts +51 -4
- package/src/features/cfg.ts +158 -65
- package/src/features/check.ts +90 -74
- package/src/features/complexity-query.ts +181 -163
- package/src/features/complexity.ts +64 -1
- package/src/features/dataflow.ts +462 -217
- package/src/features/graph-enrichment.ts +161 -117
- package/src/features/sequence.ts +27 -4
- package/src/features/structure-query.ts +43 -4
- package/src/features/structure.ts +50 -22
- package/src/graph/algorithms/leiden/adapter.ts +126 -71
- package/src/graph/algorithms/leiden/index.ts +67 -28
- package/src/graph/algorithms/leiden/optimiser.ts +114 -105
- package/src/graph/algorithms/leiden/partition.ts +131 -98
- package/src/graph/model.ts +19 -7
- package/src/infrastructure/config.ts +60 -58
- package/src/infrastructure/registry.ts +17 -14
- package/src/mcp/server.ts +46 -37
- package/src/presentation/audit.ts +72 -67
- package/src/presentation/branch-compare.ts +54 -50
- package/src/presentation/check.ts +34 -34
- package/src/presentation/colors.ts +2 -0
- package/src/presentation/complexity.ts +39 -33
- package/src/presentation/queries-cli/exports.ts +17 -17
- package/src/presentation/queries-cli/impact.ts +30 -22
- package/src/types.ts +189 -7
package/src/db/index.ts
CHANGED
package/src/db/migrations.ts
CHANGED
|
@@ -304,7 +304,8 @@ export function setBuildMeta(
|
|
|
304
304
|
tx();
|
|
305
305
|
}
|
|
306
306
|
|
|
307
|
-
|
|
307
|
+
/** Run numbered migrations that haven't been applied yet. */
|
|
308
|
+
function applyMigrations(db: BetterSqlite3Database): void {
|
|
308
309
|
db.exec(`CREATE TABLE IF NOT EXISTS schema_version (version INTEGER NOT NULL DEFAULT 0)`);
|
|
309
310
|
|
|
310
311
|
const row = db.prepare<{ version: number }>('SELECT version FROM schema_version').get();
|
|
@@ -322,40 +323,43 @@ export function initSchema(db: BetterSqlite3Database): void {
|
|
|
322
323
|
currentVersion = migration.version;
|
|
323
324
|
}
|
|
324
325
|
}
|
|
326
|
+
}
|
|
325
327
|
|
|
326
|
-
|
|
328
|
+
/** Ensure columns and indexes exist for pre-migration DBs (legacy compat). */
|
|
329
|
+
function ensureLegacyColumns(db: BetterSqlite3Database): void {
|
|
327
330
|
if (hasTable(db, 'nodes')) {
|
|
328
|
-
|
|
329
|
-
db.exec('ALTER TABLE nodes ADD COLUMN end_line INTEGER');
|
|
330
|
-
}
|
|
331
|
-
if (!hasColumn(db, 'nodes', 'role')) {
|
|
332
|
-
db.exec('ALTER TABLE nodes ADD COLUMN role TEXT');
|
|
333
|
-
}
|
|
334
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_role ON nodes(role)');
|
|
335
|
-
if (!hasColumn(db, 'nodes', 'parent_id')) {
|
|
336
|
-
db.exec('ALTER TABLE nodes ADD COLUMN parent_id INTEGER REFERENCES nodes(id)');
|
|
337
|
-
}
|
|
338
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent_id)');
|
|
339
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_kind_parent ON nodes(kind, parent_id)');
|
|
340
|
-
if (!hasColumn(db, 'nodes', 'qualified_name')) {
|
|
341
|
-
db.exec('ALTER TABLE nodes ADD COLUMN qualified_name TEXT');
|
|
342
|
-
}
|
|
343
|
-
if (!hasColumn(db, 'nodes', 'scope')) {
|
|
344
|
-
db.exec('ALTER TABLE nodes ADD COLUMN scope TEXT');
|
|
345
|
-
}
|
|
346
|
-
if (!hasColumn(db, 'nodes', 'visibility')) {
|
|
347
|
-
db.exec('ALTER TABLE nodes ADD COLUMN visibility TEXT');
|
|
348
|
-
}
|
|
349
|
-
db.exec('UPDATE nodes SET qualified_name = name WHERE qualified_name IS NULL');
|
|
350
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_qualified_name ON nodes(qualified_name)');
|
|
351
|
-
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope)');
|
|
331
|
+
ensureNodeColumns(db);
|
|
352
332
|
}
|
|
353
333
|
if (hasTable(db, 'edges')) {
|
|
354
|
-
|
|
355
|
-
db.exec('ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0');
|
|
356
|
-
}
|
|
357
|
-
if (!hasColumn(db, 'edges', 'dynamic')) {
|
|
358
|
-
db.exec('ALTER TABLE edges ADD COLUMN dynamic INTEGER DEFAULT 0');
|
|
359
|
-
}
|
|
334
|
+
ensureEdgeColumns(db);
|
|
360
335
|
}
|
|
361
336
|
}
|
|
337
|
+
|
|
338
|
+
function ensureNodeColumns(db: BetterSqlite3Database): void {
|
|
339
|
+
const missing = (col: string) => !hasColumn(db, 'nodes', col);
|
|
340
|
+
if (missing('end_line')) db.exec('ALTER TABLE nodes ADD COLUMN end_line INTEGER');
|
|
341
|
+
if (missing('role')) db.exec('ALTER TABLE nodes ADD COLUMN role TEXT');
|
|
342
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_role ON nodes(role)');
|
|
343
|
+
if (missing('parent_id'))
|
|
344
|
+
db.exec('ALTER TABLE nodes ADD COLUMN parent_id INTEGER REFERENCES nodes(id)');
|
|
345
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent_id)');
|
|
346
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_kind_parent ON nodes(kind, parent_id)');
|
|
347
|
+
if (missing('qualified_name')) db.exec('ALTER TABLE nodes ADD COLUMN qualified_name TEXT');
|
|
348
|
+
if (missing('scope')) db.exec('ALTER TABLE nodes ADD COLUMN scope TEXT');
|
|
349
|
+
if (missing('visibility')) db.exec('ALTER TABLE nodes ADD COLUMN visibility TEXT');
|
|
350
|
+
db.exec('UPDATE nodes SET qualified_name = name WHERE qualified_name IS NULL');
|
|
351
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_qualified_name ON nodes(qualified_name)');
|
|
352
|
+
db.exec('CREATE INDEX IF NOT EXISTS idx_nodes_scope ON nodes(scope)');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
function ensureEdgeColumns(db: BetterSqlite3Database): void {
|
|
356
|
+
if (!hasColumn(db, 'edges', 'confidence'))
|
|
357
|
+
db.exec('ALTER TABLE edges ADD COLUMN confidence REAL DEFAULT 1.0');
|
|
358
|
+
if (!hasColumn(db, 'edges', 'dynamic'))
|
|
359
|
+
db.exec('ALTER TABLE edges ADD COLUMN dynamic INTEGER DEFAULT 0');
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
export function initSchema(db: BetterSqlite3Database): void {
|
|
363
|
+
applyMigrations(db);
|
|
364
|
+
ensureLegacyColumns(db);
|
|
365
|
+
}
|
|
@@ -15,10 +15,8 @@ import {
|
|
|
15
15
|
getComplexityForNode,
|
|
16
16
|
getLineCountForNode,
|
|
17
17
|
getMaxEndLineForFile,
|
|
18
|
-
openReadonlyOrFail,
|
|
19
18
|
} from '../../db/index.js';
|
|
20
19
|
import { cachedStmt } from '../../db/repository/cached-stmt.js';
|
|
21
|
-
import { loadConfig } from '../../infrastructure/config.js';
|
|
22
20
|
import { debug } from '../../infrastructure/logger.js';
|
|
23
21
|
import { isTestFile } from '../../infrastructure/test-filter.js';
|
|
24
22
|
import {
|
|
@@ -40,6 +38,7 @@ import type {
|
|
|
40
38
|
RelatedNodeRow,
|
|
41
39
|
StmtCache,
|
|
42
40
|
} from '../../types.js';
|
|
41
|
+
import { resolveAnalysisOpts, withReadonlyDb } from './query-helpers.js';
|
|
43
42
|
import { findMatchingNodes } from './symbol-lookup.js';
|
|
44
43
|
|
|
45
44
|
interface DisplayOpts {
|
|
@@ -52,6 +51,60 @@ interface DisplayOpts {
|
|
|
52
51
|
[key: string]: unknown;
|
|
53
52
|
}
|
|
54
53
|
|
|
54
|
+
/** Format a callee row into the output shape with summary and source. */
|
|
55
|
+
function formatCalleeRow(
|
|
56
|
+
c: RelatedNodeRow,
|
|
57
|
+
repoRoot: string,
|
|
58
|
+
getFileLines: (file: string) => string[] | null,
|
|
59
|
+
displayOpts: DisplayOpts,
|
|
60
|
+
includeSource: boolean,
|
|
61
|
+
) {
|
|
62
|
+
const cLines = getFileLines(c.file);
|
|
63
|
+
return {
|
|
64
|
+
name: c.name,
|
|
65
|
+
kind: c.kind,
|
|
66
|
+
file: c.file,
|
|
67
|
+
line: c.line,
|
|
68
|
+
endLine: c.end_line || null,
|
|
69
|
+
summary: cLines ? extractSummary(cLines, c.line, displayOpts) : null,
|
|
70
|
+
source: includeSource
|
|
71
|
+
? readSourceRange(repoRoot, c.file, c.line, c.end_line ?? undefined, displayOpts)
|
|
72
|
+
: null,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** BFS to collect deeper callees beyond the first level. */
|
|
77
|
+
function collectDeeperCallees(
|
|
78
|
+
db: BetterSqlite3Database,
|
|
79
|
+
startIds: number[],
|
|
80
|
+
rootId: number,
|
|
81
|
+
repoRoot: string,
|
|
82
|
+
getFileLines: (file: string) => string[] | null,
|
|
83
|
+
opts: { noTests: boolean; maxDepth: number; displayOpts: DisplayOpts },
|
|
84
|
+
) {
|
|
85
|
+
const { noTests, maxDepth, displayOpts } = opts;
|
|
86
|
+
const visited = new Set(startIds);
|
|
87
|
+
visited.add(rootId);
|
|
88
|
+
let frontier = [...startIds];
|
|
89
|
+
const result: ReturnType<typeof formatCalleeRow>[] = [];
|
|
90
|
+
|
|
91
|
+
for (let d = 2; d <= maxDepth; d++) {
|
|
92
|
+
const nextFrontier: number[] = [];
|
|
93
|
+
for (const fid of frontier) {
|
|
94
|
+
const deeper = findCallees(db, fid) as RelatedNodeRow[];
|
|
95
|
+
for (const c of deeper) {
|
|
96
|
+
if (visited.has(c.id) || (noTests && isTestFile(c.file))) continue;
|
|
97
|
+
visited.add(c.id);
|
|
98
|
+
nextFrontier.push(c.id);
|
|
99
|
+
result.push(formatCalleeRow(c, repoRoot, getFileLines, displayOpts, true));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
frontier = nextFrontier;
|
|
103
|
+
if (frontier.length === 0) break;
|
|
104
|
+
}
|
|
105
|
+
return result;
|
|
106
|
+
}
|
|
107
|
+
|
|
55
108
|
function buildCallees(
|
|
56
109
|
db: BetterSqlite3Database,
|
|
57
110
|
node: NodeRow,
|
|
@@ -63,65 +116,20 @@ function buildCallees(
|
|
|
63
116
|
const calleeRows = findCallees(db, node.id) as RelatedNodeRow[];
|
|
64
117
|
const filteredCallees = noTests ? calleeRows.filter((c) => !isTestFile(c.file)) : calleeRows;
|
|
65
118
|
|
|
66
|
-
const callees = filteredCallees.map((c) =>
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
let calleeSource: string | null = null;
|
|
70
|
-
if (depth >= 1) {
|
|
71
|
-
calleeSource = readSourceRange(
|
|
72
|
-
repoRoot,
|
|
73
|
-
c.file,
|
|
74
|
-
c.line,
|
|
75
|
-
c.end_line ?? undefined,
|
|
76
|
-
displayOpts,
|
|
77
|
-
);
|
|
78
|
-
}
|
|
79
|
-
return {
|
|
80
|
-
name: c.name,
|
|
81
|
-
kind: c.kind,
|
|
82
|
-
file: c.file,
|
|
83
|
-
line: c.line,
|
|
84
|
-
endLine: c.end_line || null,
|
|
85
|
-
summary,
|
|
86
|
-
source: calleeSource,
|
|
87
|
-
};
|
|
88
|
-
});
|
|
119
|
+
const callees = filteredCallees.map((c) =>
|
|
120
|
+
formatCalleeRow(c, repoRoot, getFileLines, displayOpts, depth >= 1),
|
|
121
|
+
);
|
|
89
122
|
|
|
90
123
|
if (depth > 1) {
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
if (!visited.has(c.id) && (!noTests || !isTestFile(c.file))) {
|
|
101
|
-
visited.add(c.id);
|
|
102
|
-
nextFrontier.push(c.id);
|
|
103
|
-
const cLines = getFileLines(c.file);
|
|
104
|
-
callees.push({
|
|
105
|
-
name: c.name,
|
|
106
|
-
kind: c.kind,
|
|
107
|
-
file: c.file,
|
|
108
|
-
line: c.line,
|
|
109
|
-
endLine: c.end_line || null,
|
|
110
|
-
summary: cLines ? extractSummary(cLines, c.line, displayOpts) : null,
|
|
111
|
-
source: readSourceRange(
|
|
112
|
-
repoRoot,
|
|
113
|
-
c.file,
|
|
114
|
-
c.line,
|
|
115
|
-
c.end_line ?? undefined,
|
|
116
|
-
displayOpts,
|
|
117
|
-
),
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
frontier = nextFrontier;
|
|
123
|
-
if (frontier.length === 0) break;
|
|
124
|
-
}
|
|
124
|
+
const deeper = collectDeeperCallees(
|
|
125
|
+
db,
|
|
126
|
+
filteredCallees.map((c) => c.id),
|
|
127
|
+
node.id,
|
|
128
|
+
repoRoot,
|
|
129
|
+
getFileLines,
|
|
130
|
+
{ noTests, maxDepth: Math.min(depth, 5), displayOpts },
|
|
131
|
+
);
|
|
132
|
+
callees.push(...deeper);
|
|
125
133
|
}
|
|
126
134
|
|
|
127
135
|
return callees;
|
|
@@ -433,15 +441,12 @@ export function contextData(
|
|
|
433
441
|
config?: any;
|
|
434
442
|
} = {},
|
|
435
443
|
) {
|
|
436
|
-
|
|
437
|
-
try {
|
|
444
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
438
445
|
const depth = opts.depth || 0;
|
|
439
446
|
const noSource = opts.noSource || false;
|
|
440
|
-
const noTests = opts.noTests || false;
|
|
441
447
|
const includeTests = opts.includeTests || false;
|
|
442
448
|
|
|
443
|
-
const
|
|
444
|
-
const displayOpts: DisplayOpts = config.display || {};
|
|
449
|
+
const { noTests, displayOpts } = resolveAnalysisOpts(opts);
|
|
445
450
|
|
|
446
451
|
const dbPath = findDbPath(customDbPath);
|
|
447
452
|
const repoRoot = path.resolve(path.dirname(dbPath), '..');
|
|
@@ -494,9 +499,7 @@ export function contextData(
|
|
|
494
499
|
|
|
495
500
|
const base = { name, results };
|
|
496
501
|
return paginateResult(base, 'results', { limit: opts.limit, offset: opts.offset });
|
|
497
|
-
}
|
|
498
|
-
db.close();
|
|
499
|
-
}
|
|
502
|
+
});
|
|
500
503
|
}
|
|
501
504
|
|
|
502
505
|
export function explainData(
|
|
@@ -510,14 +513,11 @@ export function explainData(
|
|
|
510
513
|
config?: any;
|
|
511
514
|
} = {},
|
|
512
515
|
) {
|
|
513
|
-
|
|
514
|
-
try {
|
|
515
|
-
const noTests = opts.noTests || false;
|
|
516
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
516
517
|
const depth = opts.depth || 0;
|
|
517
518
|
const kind = isFileLikeTarget(target) ? 'file' : 'function';
|
|
518
519
|
|
|
519
|
-
const
|
|
520
|
-
const displayOpts: DisplayOpts = config.display || {};
|
|
520
|
+
const { noTests, displayOpts } = resolveAnalysisOpts(opts);
|
|
521
521
|
|
|
522
522
|
const dbPath = findDbPath(customDbPath);
|
|
523
523
|
const repoRoot = path.resolve(path.dirname(dbPath), '..');
|
|
@@ -536,7 +536,5 @@ export function explainData(
|
|
|
536
536
|
|
|
537
537
|
const base = { target, kind, results };
|
|
538
538
|
return paginateResult(base, 'results', { limit: opts.limit, offset: opts.offset });
|
|
539
|
-
}
|
|
540
|
-
db.close();
|
|
541
|
-
}
|
|
539
|
+
});
|
|
542
540
|
}
|
|
@@ -5,7 +5,6 @@ import {
|
|
|
5
5
|
findImportSources,
|
|
6
6
|
findImportTargets,
|
|
7
7
|
findNodesByFile,
|
|
8
|
-
openReadonlyOrFail,
|
|
9
8
|
} from '../../db/index.js';
|
|
10
9
|
import { cachedStmt } from '../../db/repository/cached-stmt.js';
|
|
11
10
|
import { isTestFile } from '../../infrastructure/test-filter.js';
|
|
@@ -19,6 +18,7 @@ import type {
|
|
|
19
18
|
RelatedNodeRow,
|
|
20
19
|
StmtCache,
|
|
21
20
|
} from '../../types.js';
|
|
21
|
+
import { withReadonlyDb } from './query-helpers.js';
|
|
22
22
|
import { findMatchingNodes } from './symbol-lookup.js';
|
|
23
23
|
|
|
24
24
|
type UpstreamRow = { id: number; name: string; kind: string; file: string; line: number };
|
|
@@ -32,8 +32,7 @@ export function fileDepsData(
|
|
|
32
32
|
customDbPath: string,
|
|
33
33
|
opts: { noTests?: boolean; limit?: number; offset?: number } = {},
|
|
34
34
|
) {
|
|
35
|
-
|
|
36
|
-
try {
|
|
35
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
37
36
|
const noTests = opts.noTests || false;
|
|
38
37
|
const fileNodes = findFileNodes(db, `%${file}%`) as NodeRow[];
|
|
39
38
|
if (fileNodes.length === 0) {
|
|
@@ -59,9 +58,7 @@ export function fileDepsData(
|
|
|
59
58
|
|
|
60
59
|
const base = { file, results };
|
|
61
60
|
return paginateResult(base, 'results', { limit: opts.limit, offset: opts.offset });
|
|
62
|
-
}
|
|
63
|
-
db.close();
|
|
64
|
-
}
|
|
61
|
+
});
|
|
65
62
|
}
|
|
66
63
|
|
|
67
64
|
/**
|
|
@@ -140,8 +137,7 @@ export function fnDepsData(
|
|
|
140
137
|
offset?: number;
|
|
141
138
|
} = {},
|
|
142
139
|
) {
|
|
143
|
-
|
|
144
|
-
try {
|
|
140
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
145
141
|
const depth = opts.depth || 3;
|
|
146
142
|
const noTests = opts.noTests || false;
|
|
147
143
|
const hc = new Map();
|
|
@@ -194,9 +190,7 @@ export function fnDepsData(
|
|
|
194
190
|
|
|
195
191
|
const base = { name, results };
|
|
196
192
|
return paginateResult(base, 'results', { limit: opts.limit, offset: opts.offset });
|
|
197
|
-
}
|
|
198
|
-
db.close();
|
|
199
|
-
}
|
|
193
|
+
});
|
|
200
194
|
}
|
|
201
195
|
|
|
202
196
|
/**
|
|
@@ -384,8 +378,7 @@ export function pathData(
|
|
|
384
378
|
kind?: string;
|
|
385
379
|
} = {},
|
|
386
380
|
) {
|
|
387
|
-
|
|
388
|
-
try {
|
|
381
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
389
382
|
const noTests = opts.noTests || false;
|
|
390
383
|
const maxDepth = opts.maxDepth || 10;
|
|
391
384
|
const edgeKinds = opts.edgeKinds || ['calls'];
|
|
@@ -477,13 +470,67 @@ export function pathData(
|
|
|
477
470
|
reverse,
|
|
478
471
|
maxDepth,
|
|
479
472
|
};
|
|
480
|
-
}
|
|
481
|
-
db.close();
|
|
482
|
-
}
|
|
473
|
+
});
|
|
483
474
|
}
|
|
484
475
|
|
|
485
476
|
// ── File-level shortest path ────────────────────────────────────────────
|
|
486
477
|
|
|
478
|
+
/** BFS over file adjacency graph to find shortest path. */
|
|
479
|
+
function bfsFilePath(
|
|
480
|
+
neighborStmt: ReturnType<BetterSqlite3Database['prepare']>,
|
|
481
|
+
sourceFile: string,
|
|
482
|
+
targetFile: string,
|
|
483
|
+
edgeKinds: string[],
|
|
484
|
+
maxDepth: number,
|
|
485
|
+
noTests: boolean,
|
|
486
|
+
): { found: boolean; path: string[]; alternateCount: number } {
|
|
487
|
+
const visited = new Set([sourceFile]);
|
|
488
|
+
const parentMap = new Map<string, string>();
|
|
489
|
+
let queue = [sourceFile];
|
|
490
|
+
let found = false;
|
|
491
|
+
let alternateCount = 0;
|
|
492
|
+
|
|
493
|
+
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
494
|
+
const nextQueue: string[] = [];
|
|
495
|
+
for (const currentFile of queue) {
|
|
496
|
+
const neighbors = neighborStmt.all(currentFile, ...edgeKinds) as Array<{
|
|
497
|
+
neighbor_file: string;
|
|
498
|
+
}>;
|
|
499
|
+
for (const n of neighbors) {
|
|
500
|
+
if (noTests && isTestFile(n.neighbor_file)) continue;
|
|
501
|
+
if (n.neighbor_file === targetFile) {
|
|
502
|
+
if (!found) {
|
|
503
|
+
found = true;
|
|
504
|
+
parentMap.set(n.neighbor_file, currentFile);
|
|
505
|
+
}
|
|
506
|
+
alternateCount++;
|
|
507
|
+
continue;
|
|
508
|
+
}
|
|
509
|
+
if (!visited.has(n.neighbor_file)) {
|
|
510
|
+
visited.add(n.neighbor_file);
|
|
511
|
+
parentMap.set(n.neighbor_file, currentFile);
|
|
512
|
+
nextQueue.push(n.neighbor_file);
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
if (found) break;
|
|
517
|
+
queue = nextQueue;
|
|
518
|
+
if (queue.length === 0) break;
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
if (!found) return { found: false, path: [], alternateCount: 0 };
|
|
522
|
+
|
|
523
|
+
// Reconstruct path
|
|
524
|
+
const filePath: string[] = [targetFile];
|
|
525
|
+
let cur = targetFile;
|
|
526
|
+
while (cur !== sourceFile) {
|
|
527
|
+
cur = parentMap.get(cur)!;
|
|
528
|
+
filePath.push(cur);
|
|
529
|
+
}
|
|
530
|
+
filePath.reverse();
|
|
531
|
+
return { found: true, path: filePath, alternateCount: Math.max(0, alternateCount - 1) };
|
|
532
|
+
}
|
|
533
|
+
|
|
487
534
|
/**
|
|
488
535
|
* BFS at the file level: find shortest import/edge path between two files.
|
|
489
536
|
* Adjacency: file A → file B if any symbol in A has an edge to any symbol in B.
|
|
@@ -499,8 +546,7 @@ export function filePathData(
|
|
|
499
546
|
reverse?: boolean;
|
|
500
547
|
} = {},
|
|
501
548
|
) {
|
|
502
|
-
|
|
503
|
-
try {
|
|
549
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
504
550
|
const noTests = opts.noTests || false;
|
|
505
551
|
const maxDepth = opts.maxDepth || 10;
|
|
506
552
|
const edgeKinds = opts.edgeKinds || ['imports', 'imports-type'];
|
|
@@ -569,42 +615,17 @@ export function filePathData(
|
|
|
569
615
|
WHERE n_src.file = ? AND e.kind IN (${kindPlaceholders}) AND n_tgt.file != n_src.file`;
|
|
570
616
|
const neighborStmt = db.prepare(neighborQuery);
|
|
571
617
|
|
|
572
|
-
// BFS
|
|
573
|
-
const
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
for (const currentFile of queue) {
|
|
582
|
-
const neighbors = neighborStmt.all(currentFile, ...edgeKinds) as Array<{
|
|
583
|
-
neighbor_file: string;
|
|
584
|
-
}>;
|
|
585
|
-
for (const n of neighbors) {
|
|
586
|
-
if (noTests && isTestFile(n.neighbor_file)) continue;
|
|
587
|
-
if (n.neighbor_file === targetFile) {
|
|
588
|
-
if (!found) {
|
|
589
|
-
found = true;
|
|
590
|
-
parentMap.set(n.neighbor_file, currentFile);
|
|
591
|
-
}
|
|
592
|
-
alternateCount++;
|
|
593
|
-
continue;
|
|
594
|
-
}
|
|
595
|
-
if (!visited.has(n.neighbor_file)) {
|
|
596
|
-
visited.add(n.neighbor_file);
|
|
597
|
-
parentMap.set(n.neighbor_file, currentFile);
|
|
598
|
-
nextQueue.push(n.neighbor_file);
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
}
|
|
602
|
-
if (found) break;
|
|
603
|
-
queue = nextQueue;
|
|
604
|
-
if (queue.length === 0) break;
|
|
605
|
-
}
|
|
618
|
+
// BFS to find shortest file path
|
|
619
|
+
const bfsResult = bfsFilePath(
|
|
620
|
+
neighborStmt,
|
|
621
|
+
sourceFile,
|
|
622
|
+
targetFile,
|
|
623
|
+
edgeKinds,
|
|
624
|
+
maxDepth,
|
|
625
|
+
noTests,
|
|
626
|
+
);
|
|
606
627
|
|
|
607
|
-
if (!found) {
|
|
628
|
+
if (!bfsResult.found) {
|
|
608
629
|
return {
|
|
609
630
|
from,
|
|
610
631
|
to,
|
|
@@ -620,29 +641,18 @@ export function filePathData(
|
|
|
620
641
|
};
|
|
621
642
|
}
|
|
622
643
|
|
|
623
|
-
// Reconstruct path
|
|
624
|
-
const filePath: string[] = [targetFile];
|
|
625
|
-
let cur = targetFile;
|
|
626
|
-
while (cur !== sourceFile) {
|
|
627
|
-
cur = parentMap.get(cur)!;
|
|
628
|
-
filePath.push(cur);
|
|
629
|
-
}
|
|
630
|
-
filePath.reverse();
|
|
631
|
-
|
|
632
644
|
return {
|
|
633
645
|
from,
|
|
634
646
|
to,
|
|
635
647
|
fromCandidates,
|
|
636
648
|
toCandidates,
|
|
637
649
|
found: true,
|
|
638
|
-
hops:
|
|
639
|
-
path:
|
|
640
|
-
alternateCount:
|
|
650
|
+
hops: bfsResult.path.length - 1,
|
|
651
|
+
path: bfsResult.path,
|
|
652
|
+
alternateCount: bfsResult.alternateCount,
|
|
641
653
|
edgeKinds,
|
|
642
654
|
reverse,
|
|
643
655
|
maxDepth,
|
|
644
656
|
};
|
|
645
|
-
}
|
|
646
|
-
db.close();
|
|
647
|
-
}
|
|
657
|
+
});
|
|
648
658
|
}
|
|
@@ -4,10 +4,8 @@ import {
|
|
|
4
4
|
findDbPath,
|
|
5
5
|
findFileNodes,
|
|
6
6
|
findNodesByFile,
|
|
7
|
-
openReadonlyOrFail,
|
|
8
7
|
} from '../../db/index.js';
|
|
9
8
|
import { cachedStmt } from '../../db/repository/cached-stmt.js';
|
|
10
|
-
import { loadConfig } from '../../infrastructure/config.js';
|
|
11
9
|
import { debug } from '../../infrastructure/logger.js';
|
|
12
10
|
import { isTestFile } from '../../infrastructure/test-filter.js';
|
|
13
11
|
import {
|
|
@@ -17,6 +15,7 @@ import {
|
|
|
17
15
|
} from '../../shared/file-utils.js';
|
|
18
16
|
import { paginateResult } from '../../shared/paginate.js';
|
|
19
17
|
import type { BetterSqlite3Database, NodeRow, StmtCache } from '../../types.js';
|
|
18
|
+
import { resolveAnalysisOpts, withReadonlyDb } from './query-helpers.js';
|
|
20
19
|
|
|
21
20
|
/** Cache the schema probe for the `exported` column per db handle. */
|
|
22
21
|
const _hasExportedColCache: WeakMap<BetterSqlite3Database, boolean> = new WeakMap();
|
|
@@ -37,12 +36,8 @@ export function exportsData(
|
|
|
37
36
|
config?: any;
|
|
38
37
|
} = {},
|
|
39
38
|
) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const noTests = opts.noTests || false;
|
|
43
|
-
|
|
44
|
-
const config = opts.config || loadConfig();
|
|
45
|
-
const displayOpts = config.display || {};
|
|
39
|
+
return withReadonlyDb(customDbPath, (db) => {
|
|
40
|
+
const { noTests, displayOpts } = resolveAnalysisOpts(opts);
|
|
46
41
|
|
|
47
42
|
const dbFilePath = findDbPath(customDbPath);
|
|
48
43
|
const repoRoot = path.resolve(path.dirname(dbFilePath), '..');
|
|
@@ -101,9 +96,39 @@ export function exportsData(
|
|
|
101
96
|
}
|
|
102
97
|
}
|
|
103
98
|
return paginated;
|
|
104
|
-
}
|
|
105
|
-
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/** Collect symbols re-exported through barrel files. */
|
|
103
|
+
function collectReexportedSymbols(
|
|
104
|
+
db: BetterSqlite3Database,
|
|
105
|
+
fileNodeId: number,
|
|
106
|
+
reexportsToStmt: ReturnType<BetterSqlite3Database['prepare']>,
|
|
107
|
+
exportedNodesStmt: ReturnType<BetterSqlite3Database['prepare']> | null,
|
|
108
|
+
hasExportedCol: boolean,
|
|
109
|
+
getFileLines: (file: string) => string[] | null,
|
|
110
|
+
buildSymbolResult: (s: NodeRow, fileLines: string[] | null) => any,
|
|
111
|
+
) {
|
|
112
|
+
const reexportTargets = reexportsToStmt.all(fileNodeId) as Array<{ file: string }>;
|
|
113
|
+
const reexportedSymbols: Array<ReturnType<typeof buildSymbolResult> & { originFile: string }> =
|
|
114
|
+
[];
|
|
115
|
+
for (const reexTarget of reexportTargets) {
|
|
116
|
+
let targetExported: NodeRow[];
|
|
117
|
+
if (hasExportedCol) {
|
|
118
|
+
targetExported = exportedNodesStmt!.all(reexTarget.file) as NodeRow[];
|
|
119
|
+
} else {
|
|
120
|
+
const targetSymbols = findNodesByFile(db, reexTarget.file) as NodeRow[];
|
|
121
|
+
const exportedIds = findCrossFileCallTargets(db, reexTarget.file) as Set<number>;
|
|
122
|
+
targetExported = targetSymbols.filter((s) => exportedIds.has(s.id));
|
|
123
|
+
}
|
|
124
|
+
for (const s of targetExported) {
|
|
125
|
+
reexportedSymbols.push({
|
|
126
|
+
...buildSymbolResult(s, getFileLines(reexTarget.file)),
|
|
127
|
+
originFile: reexTarget.file,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
106
130
|
}
|
|
131
|
+
return reexportedSymbols;
|
|
107
132
|
}
|
|
108
133
|
|
|
109
134
|
function exportsFileImpl(
|
|
@@ -197,34 +222,20 @@ function exportsFileImpl(
|
|
|
197
222
|
|
|
198
223
|
const totalUnused = results.filter((r) => r.consumerCount === 0).length;
|
|
199
224
|
|
|
200
|
-
// Files that re-export this file (barrel -> this file)
|
|
201
225
|
const reexports = (reexportsFromStmt.all(fn.id) as Array<{ file: string }>).map((r) => ({
|
|
202
226
|
file: r.file,
|
|
203
227
|
}));
|
|
204
228
|
|
|
205
|
-
//
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
// Fallback: same heuristic as direct exports — symbols called from other files
|
|
216
|
-
const targetSymbols = findNodesByFile(db, reexTarget.file) as NodeRow[];
|
|
217
|
-
const exportedIds = findCrossFileCallTargets(db, reexTarget.file) as Set<number>;
|
|
218
|
-
targetExported = targetSymbols.filter((s) => exportedIds.has(s.id));
|
|
219
|
-
}
|
|
220
|
-
for (const s of targetExported) {
|
|
221
|
-
const fileLines = getFileLines(reexTarget.file);
|
|
222
|
-
reexportedSymbols.push({
|
|
223
|
-
...buildSymbolResult(s, fileLines),
|
|
224
|
-
originFile: reexTarget.file,
|
|
225
|
-
});
|
|
226
|
-
}
|
|
227
|
-
}
|
|
229
|
+
// Gather symbols re-exported from target modules (barrel file support)
|
|
230
|
+
const reexportedSymbols = collectReexportedSymbols(
|
|
231
|
+
db,
|
|
232
|
+
fn.id,
|
|
233
|
+
reexportsToStmt,
|
|
234
|
+
exportedNodesStmt,
|
|
235
|
+
hasExportedCol,
|
|
236
|
+
getFileLines,
|
|
237
|
+
buildSymbolResult,
|
|
238
|
+
);
|
|
228
239
|
|
|
229
240
|
let filteredResults = results;
|
|
230
241
|
let filteredReexported = reexportedSymbols;
|