scip-query 0.3.4 → 0.3.5

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.
Files changed (66) hide show
  1. package/README.md +1 -26
  2. package/dist/{chunk-FYYOWQXK.js → chunk-6FKIA6EI.js} +10 -27
  3. package/dist/{chunk-HLKAFWWJ.js → chunk-EN2Z2CLO.js} +59 -91
  4. package/dist/chunk-FVH3Y44U.js +1 -0
  5. package/dist/{chunk-HJZUSUPU.js → chunk-TRESG7OB.js} +4 -4
  6. package/dist/{chunk-GJDHTTR2.js → chunk-VMM4SYV4.js} +17 -15
  7. package/dist/{chunk-P4WO3BBW.js → chunk-YGGFLMTM.js} +31 -12
  8. package/dist/cli.js +109 -225
  9. package/dist/{db-ShvwGDKf.d.ts → db-viWlyVtv.d.ts} +1 -13
  10. package/dist/index.d.ts +2 -3
  11. package/dist/index.js +14 -18
  12. package/dist/queries/affected.d.ts +1 -1
  13. package/dist/queries/bottlenecks.d.ts +1 -1
  14. package/dist/queries/by-kind.d.ts +1 -1
  15. package/dist/queries/by-kind.js +1 -1
  16. package/dist/queries/call-graph.d.ts +1 -1
  17. package/dist/queries/change-surface.d.ts +1 -1
  18. package/dist/queries/code.d.ts +1 -1
  19. package/dist/queries/complexity-hotspots.d.ts +1 -1
  20. package/dist/queries/complexity.d.ts +1 -1
  21. package/dist/queries/convergence.d.ts +1 -1
  22. package/dist/queries/convergence.js +1 -1
  23. package/dist/queries/coupling.d.ts +1 -1
  24. package/dist/queries/cycles.d.ts +1 -1
  25. package/dist/queries/dataflow.d.ts +1 -1
  26. package/dist/queries/dead.d.ts +1 -1
  27. package/dist/queries/deep-chains.d.ts +1 -1
  28. package/dist/queries/deps.d.ts +1 -1
  29. package/dist/queries/diff-impact.d.ts +1 -1
  30. package/dist/queries/drift.d.ts +1 -1
  31. package/dist/queries/extract-candidates.d.ts +1 -1
  32. package/dist/queries/fan.d.ts +1 -1
  33. package/dist/queries/fan.js +1 -1
  34. package/dist/queries/files.d.ts +1 -1
  35. package/dist/queries/health.d.ts +1 -1
  36. package/dist/queries/health.js +3 -3
  37. package/dist/queries/hierarchy.d.ts +1 -1
  38. package/dist/queries/hotspots.d.ts +1 -1
  39. package/dist/queries/imports.d.ts +1 -1
  40. package/dist/queries/index.d.ts +1 -2
  41. package/dist/queries/index.js +14 -18
  42. package/dist/queries/isolated.d.ts +1 -1
  43. package/dist/queries/members.d.ts +1 -1
  44. package/dist/queries/methods.d.ts +1 -1
  45. package/dist/queries/outline.d.ts +1 -1
  46. package/dist/queries/passthrough-candidates.d.ts +1 -1
  47. package/dist/queries/redundant-reexports.d.ts +1 -1
  48. package/dist/queries/refs.d.ts +1 -1
  49. package/dist/queries/similar-chains.d.ts +1 -1
  50. package/dist/queries/similar-files.d.ts +1 -1
  51. package/dist/queries/similar-signatures.d.ts +1 -1
  52. package/dist/queries/similar.d.ts +1 -1
  53. package/dist/queries/slice.d.ts +1 -1
  54. package/dist/queries/stale-abstractions.d.ts +1 -1
  55. package/dist/queries/stale-abstractions.js +1 -1
  56. package/dist/queries/stats.d.ts +1 -1
  57. package/dist/queries/surface.d.ts +1 -1
  58. package/dist/queries/symbols.d.ts +1 -1
  59. package/dist/queries/system.d.ts +1 -1
  60. package/dist/queries/trace.d.ts +1 -1
  61. package/dist/queries/wrapper-candidates.d.ts +1 -1
  62. package/package.json +1 -1
  63. package/dist/chunk-2UELLEBI.js +0 -1
  64. package/dist/chunk-YZ6L7GFO.js +0 -73
  65. package/dist/queries/doc-coverage.d.ts +0 -14
  66. package/dist/queries/doc-coverage.js +0 -8
package/dist/cli.js CHANGED
@@ -3374,21 +3374,22 @@ function members(db, symbolPattern) {
3374
3374
 
3375
3375
  // src/queries/fan.ts
3376
3376
  function fanIn(db, symbolPattern) {
3377
- const rows = db.all(
3378
- `SELECT gs.symbol, COUNT(DISTINCT c.document_id) AS file_count
3379
- FROM mentions m
3380
- JOIN chunks c ON m.chunk_id = c.id
3381
- JOIN global_symbols gs ON m.symbol_id = gs.id
3382
- WHERE gs.symbol LIKE ?
3383
- AND m.role != 1
3384
- GROUP BY gs.id
3385
- ORDER BY file_count DESC`,
3386
- `%${symbolPattern}%`
3377
+ const match = findFirstSymbolMatch(db, symbolPattern);
3378
+ if (!match) {
3379
+ return [];
3380
+ }
3381
+ const row = db.get(
3382
+ `SELECT COUNT(DISTINCT c.document_id) AS file_count
3383
+ FROM mentions m
3384
+ JOIN chunks c ON m.chunk_id = c.id
3385
+ WHERE m.symbol_id = ?
3386
+ AND m.role != 1`,
3387
+ match.symbolId
3387
3388
  );
3388
- return rows.map((r) => ({
3389
- name: shortenSymbol(r.symbol),
3390
- count: r.file_count
3391
- }));
3389
+ return [{
3390
+ name: shortenSymbol(match.symbol),
3391
+ count: row?.file_count ?? 0
3392
+ }];
3392
3393
  }
3393
3394
  function fanOut(db, filePattern) {
3394
3395
  const resolvedFile = resolveIndexedFile(db, filePattern);
@@ -3799,102 +3800,26 @@ function byKind(db, kindQuery, opts = {}) {
3799
3800
  if (kindNum === null) {
3800
3801
  return [];
3801
3802
  }
3802
- const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
3803
- const hasKinds = db.get(
3804
- `SELECT COUNT(*) AS c FROM global_symbols WHERE kind IS NOT NULL`
3805
- );
3806
- if (!hasKinds || hasKinds.c === 0) {
3807
- return inferByKind(db, kindNum, scope, limit);
3808
- }
3809
- const rows = db.all(
3810
- `SELECT gs.symbol, gs.kind, d.relative_path, der.start_line, der.end_line
3811
- FROM global_symbols gs
3812
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3813
- JOIN documents d ON der.document_id = d.id
3814
- WHERE gs.kind = ?
3815
- ${db.pathExclusionsFor("d")}
3816
- ${scopeFilter}
3817
- ORDER BY d.relative_path, der.start_line
3818
- LIMIT ?`,
3819
- kindNum,
3820
- limit
3821
- );
3822
- return rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
3823
- symbol: r.symbol,
3824
- shortName: shortenSymbol(r.symbol),
3825
- kind: r.kind,
3826
- kindName: KIND_NAMES[r.kind] ?? "Unknown",
3827
- relativePath: r.relative_path,
3828
- startLine: r.start_line,
3829
- endLine: r.end_line
3830
- }));
3831
- }
3832
- function kindCounts(db, opts = {}) {
3833
- const scopeFilter = opts.scope ? `AND d.relative_path LIKE '%${opts.scope}%'` : "";
3834
- const rows = db.all(
3835
- `SELECT gs.kind, COUNT(*) AS cnt
3836
- FROM global_symbols gs
3837
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3838
- JOIN documents d ON der.document_id = d.id
3839
- WHERE 1 = 1
3840
- ${db.pathExclusionsFor("d")}
3841
- AND gs.kind IS NOT NULL
3842
- AND gs.kind != 0
3843
- ${scopeFilter}
3844
- GROUP BY gs.kind
3845
- ORDER BY cnt DESC`
3846
- );
3847
- if (rows.length === 0) {
3848
- return inferKindCounts(db, opts.scope);
3849
- }
3850
- return rows.map((r) => ({
3851
- kind: r.kind,
3852
- kindName: KIND_NAMES[r.kind] ?? "Unknown",
3853
- count: r.cnt
3854
- }));
3855
- }
3856
- function inferByKind(db, kindNum, scope, limit = 100) {
3857
- const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
3858
- const rows = db.all(
3859
- `SELECT gs.symbol, d.relative_path, der.start_line, der.end_line, gs.documentation, gs.enclosing_symbol
3860
- FROM global_symbols gs
3861
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3862
- JOIN documents d ON der.document_id = d.id
3863
- WHERE 1 = 1
3864
- ${db.pathExclusionsFor("d")}
3865
- ${scopeFilter}
3866
- ORDER BY d.relative_path, der.start_line`
3867
- );
3868
- return rows.filter((row) => !db.isIgnored(row.relative_path)).map((row) => ({
3803
+ const rows = loadKindRows(db, scope).map((row) => ({
3869
3804
  row,
3870
- inferredKind: inferKindNumber(row.symbol, row.documentation, row.enclosing_symbol)
3871
- })).filter((entry) => entry.inferredKind === kindNum).slice(0, limit).map(({ row, inferredKind }) => ({
3805
+ resolvedKind: resolveKindNumber(row)
3806
+ })).filter((entry) => entry.resolvedKind === kindNum).slice(0, limit);
3807
+ return rows.map(({ row, resolvedKind }) => ({
3872
3808
  symbol: row.symbol,
3873
3809
  shortName: shortenSymbol(row.symbol),
3874
- kind: inferredKind,
3875
- kindName: KIND_NAMES[inferredKind] ?? "Unknown",
3810
+ kind: resolvedKind,
3811
+ kindName: KIND_NAMES[resolvedKind] ?? "Unknown",
3876
3812
  relativePath: row.relative_path,
3877
3813
  startLine: row.start_line,
3878
3814
  endLine: row.end_line
3879
3815
  }));
3880
3816
  }
3881
- function inferKindCounts(db, scope) {
3882
- const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
3883
- const rows = db.all(
3884
- `SELECT gs.symbol, gs.documentation, gs.enclosing_symbol, d.relative_path
3885
- FROM global_symbols gs
3886
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3887
- JOIN documents d ON der.document_id = d.id
3888
- WHERE 1 = 1
3889
- ${db.pathExclusionsFor("d")}
3890
- ${scopeFilter}`
3891
- );
3817
+ function kindCounts(db, opts = {}) {
3892
3818
  const counts = /* @__PURE__ */ new Map();
3893
- for (const row of rows) {
3894
- if (db.isIgnored(row.relative_path)) continue;
3895
- const inferred = inferKindNumber(row.symbol, row.documentation, row.enclosing_symbol);
3896
- if (inferred === null || inferred === 0) continue;
3897
- counts.set(inferred, (counts.get(inferred) ?? 0) + 1);
3819
+ for (const row of loadKindRows(db, opts.scope)) {
3820
+ const kind = resolveKindNumber(row);
3821
+ if (kind === null || kind === 0) continue;
3822
+ counts.set(kind, (counts.get(kind) ?? 0) + 1);
3898
3823
  }
3899
3824
  return [...counts.entries()].sort((a, b) => b[1] - a[1] || a[0] - b[0]).map(([kind, count]) => ({
3900
3825
  kind,
@@ -3902,22 +3827,66 @@ function inferKindCounts(db, scope) {
3902
3827
  count
3903
3828
  }));
3904
3829
  }
3830
+ function loadKindRows(db, scope) {
3831
+ const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
3832
+ return db.all(
3833
+ `SELECT
3834
+ gs.symbol,
3835
+ gs.kind,
3836
+ gs.documentation,
3837
+ gs.enclosing_symbol,
3838
+ d.relative_path,
3839
+ der.start_line,
3840
+ der.end_line
3841
+ FROM global_symbols gs
3842
+ JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3843
+ JOIN documents d ON der.document_id = d.id
3844
+ WHERE 1 = 1
3845
+ ${db.pathExclusionsFor("d")}
3846
+ ${scopeFilter}
3847
+ ORDER BY d.relative_path, der.start_line`
3848
+ ).filter((row) => !db.isIgnored(row.relative_path));
3849
+ }
3850
+ function resolveKindNumber(row) {
3851
+ if (row.kind !== null && row.kind !== 0) {
3852
+ return normalizeIndexedKind(row.kind, row.symbol, row.documentation);
3853
+ }
3854
+ return inferKindNumber(row.symbol, row.documentation, row.enclosing_symbol);
3855
+ }
3856
+ function normalizeIndexedKind(kind, symbol, documentation) {
3857
+ const signature = (documentation ?? "").toLowerCase();
3858
+ const suffix = leafSuffix(symbol);
3859
+ if (suffix === "type") {
3860
+ if (signature.includes("type ")) return 76;
3861
+ if (signature.includes("interface ")) return 27;
3862
+ if (signature.includes("struct ")) return 68;
3863
+ if (signature.includes("trait ")) return 73;
3864
+ if (signature.includes("class ")) return 9;
3865
+ }
3866
+ return kind;
3867
+ }
3905
3868
  function inferKindNumber(symbol, documentation, enclosingSymbol) {
3906
3869
  const parsed = parseSymbol(symbol);
3907
3870
  if ("kind" in parsed) {
3908
3871
  return null;
3909
3872
  }
3910
3873
  const descriptors = parsed.descriptors;
3911
- const last = descriptors[descriptors.length - 1] ?? null;
3912
3874
  const parent = descriptors[descriptors.length - 2] ?? null;
3913
3875
  const suffix = leafSuffix(symbol);
3914
- if (suffix === "type") return 9;
3876
+ const signature = (documentation ?? "").toLowerCase();
3877
+ if (suffix === "type") {
3878
+ if (signature.includes("type ")) return 76;
3879
+ if (signature.includes("interface ")) return 27;
3880
+ if (signature.includes("struct ")) return 68;
3881
+ if (signature.includes("trait ")) return 73;
3882
+ if (signature.includes("class ")) return 9;
3883
+ return 9;
3884
+ }
3915
3885
  if (suffix === "method") {
3916
3886
  return parent?.suffix === "type" ? 33 : 23;
3917
3887
  }
3918
3888
  if (suffix === "namespace") return 39;
3919
3889
  if (suffix !== "term") return null;
3920
- const signature = (documentation ?? "").toLowerCase();
3921
3890
  if (signature.includes("async def ") || signature.includes("def ")) {
3922
3891
  return 23;
3923
3892
  }
@@ -3928,71 +3897,6 @@ function inferKindNumber(symbol, documentation, enclosingSymbol) {
3928
3897
  return 83;
3929
3898
  }
3930
3899
 
3931
- // src/queries/doc-coverage.ts
3932
- function docCoverage(db, opts = {}) {
3933
- const { scope, minLoc = 3, limit = 50 } = opts;
3934
- const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
3935
- const totalRow = db.get(
3936
- `SELECT COUNT(*) AS c
3937
- FROM global_symbols gs
3938
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3939
- JOIN documents d ON der.document_id = d.id
3940
- WHERE 1 = 1
3941
- ${db.pathExclusionsFor("d")}
3942
- ${db.symbolNoiseFor("gs")}
3943
- AND gs.symbol NOT LIKE '%#%'
3944
- AND (der.end_line - der.start_line + 1) >= ?
3945
- ${scopeFilter}`,
3946
- minLoc
3947
- );
3948
- const docRow = db.get(
3949
- `SELECT COUNT(*) AS c
3950
- FROM global_symbols gs
3951
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3952
- JOIN documents d ON der.document_id = d.id
3953
- WHERE 1 = 1
3954
- ${db.pathExclusionsFor("d")}
3955
- ${db.symbolNoiseFor("gs")}
3956
- AND gs.symbol NOT LIKE '%#%'
3957
- AND (der.end_line - der.start_line + 1) >= ?
3958
- AND gs.documentation IS NOT NULL
3959
- AND gs.documentation != ''
3960
- ${scopeFilter}`,
3961
- minLoc
3962
- );
3963
- const total = totalRow?.c ?? 0;
3964
- const documented = docRow?.c ?? 0;
3965
- const undocRows = db.all(
3966
- `SELECT gs.symbol, d.relative_path, der.start_line
3967
- FROM global_symbols gs
3968
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
3969
- JOIN documents d ON der.document_id = d.id
3970
- WHERE 1 = 1
3971
- ${db.pathExclusionsFor("d")}
3972
- ${db.symbolNoiseFor("gs")}
3973
- AND gs.symbol NOT LIKE '%#%'
3974
- AND (der.end_line - der.start_line + 1) >= ?
3975
- AND (gs.documentation IS NULL OR gs.documentation = '')
3976
- ${scopeFilter}
3977
- ORDER BY d.relative_path, der.start_line
3978
- LIMIT ?`,
3979
- minLoc,
3980
- limit
3981
- );
3982
- return {
3983
- totalSymbols: total,
3984
- documented,
3985
- undocumented: total - documented,
3986
- coveragePercent: total > 0 ? Math.round(documented / total * 100) : 0,
3987
- undocumentedSymbols: undocRows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
3988
- symbol: r.symbol,
3989
- shortName: shortenSymbol(r.symbol),
3990
- relativePath: r.relative_path,
3991
- startLine: r.start_line
3992
- }))
3993
- };
3994
- }
3995
-
3996
3900
  // src/queries/deep-chains.ts
3997
3901
  function deepChains(db, opts = {}) {
3998
3902
  const { limit = 10, scope, minDepth = 3 } = opts;
@@ -5340,17 +5244,11 @@ function staleAbstractions(db, opts) {
5340
5244
  AND (der.end_line - der.start_line + 1) >= ?
5341
5245
  ${scopeFilter}
5342
5246
  ) WHERE consumers <= 1
5343
- ORDER BY loc DESC
5344
- LIMIT ?`,
5345
- minLoc,
5346
- limit
5247
+ ORDER BY loc DESC, file ASC, start_line ASC`,
5248
+ minLoc
5347
5249
  );
5348
- return rows.filter((r) => !db.isIgnored(r.file)).filter((r) => {
5349
- const basename2 = r.file.split("/").pop() ?? "";
5350
- const isTypeFile = basename2.includes("types") || r.file.includes("/types/");
5351
- if (isTypeFile && r.consumers > 0) return false;
5352
- return true;
5353
- }).map((r) => ({
5250
+ const filesWithFunctions = getFilesWithFunctions(db, scope);
5251
+ return rows.filter((r) => !db.isIgnored(r.file)).filter((r) => isTrueStaleAbstraction(r, filesWithFunctions)).map((r) => ({
5354
5252
  symbol: r.symbol,
5355
5253
  shortName: shortenSymbol(r.symbol),
5356
5254
  file: r.file,
@@ -5358,7 +5256,32 @@ function staleAbstractions(db, opts) {
5358
5256
  endLine: r.end_line,
5359
5257
  loc: r.loc,
5360
5258
  consumers: r.consumers
5361
- }));
5259
+ })).slice(0, limit);
5260
+ }
5261
+ function getFilesWithFunctions(db, scope) {
5262
+ const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
5263
+ return new Set(
5264
+ db.all(
5265
+ `SELECT DISTINCT d.relative_path
5266
+ FROM global_symbols gs
5267
+ JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
5268
+ JOIN documents d ON der.document_id = d.id
5269
+ WHERE gs.symbol LIKE '%().'
5270
+ ${db.pathExclusionsFor("d")}
5271
+ ${scopeFilter}`
5272
+ ).map((row) => row.relative_path).filter((path2) => !db.isIgnored(path2))
5273
+ );
5274
+ }
5275
+ function isTrueStaleAbstraction(row, filesWithFunctions) {
5276
+ const basename2 = row.file.split("/").pop() ?? "";
5277
+ const isTypeFile = basename2.includes("types") || row.file.includes("/types/");
5278
+ if (isTypeFile && row.consumers > 0) {
5279
+ return false;
5280
+ }
5281
+ if (row.consumers === 0 && filesWithFunctions.has(row.file)) {
5282
+ return false;
5283
+ }
5284
+ return true;
5362
5285
  }
5363
5286
 
5364
5287
  // src/queries/complexity-hotspots.ts
@@ -5474,20 +5397,7 @@ function health(db, opts = {}) {
5474
5397
  const trueIsolatedCount = isolatedResult.filter(
5475
5398
  (s2) => !isEntrySurface(db, s2.relativePath)
5476
5399
  ).length;
5477
- const filesWithFunctions = new Set(
5478
- db.all(
5479
- `SELECT DISTINCT d.relative_path
5480
- FROM global_symbols gs
5481
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
5482
- JOIN documents d ON der.document_id = d.id
5483
- WHERE gs.symbol LIKE '%().'
5484
- ${db.pathExclusionsFor("d")}`
5485
- ).map((r) => r.relative_path)
5486
- );
5487
- const trueStaleCount = staleResult.filter((s2) => {
5488
- if (s2.consumers === 0 && filesWithFunctions.has(s2.file)) return false;
5489
- return true;
5490
- }).length;
5400
+ const trueStaleCount = staleResult.length;
5491
5401
  const trueDriftCount = driftResult.results.length;
5492
5402
  const trueSimilarCount = similarResult.length;
5493
5403
  const actions = [];
@@ -5562,11 +5472,7 @@ function health(db, opts = {}) {
5562
5472
  });
5563
5473
  }
5564
5474
  if (trueStaleCount > 0) {
5565
- const trueStaleSymbols = staleResult.filter((s2) => {
5566
- if (s2.consumers === 0 && filesWithFunctions.has(s2.file)) return false;
5567
- return true;
5568
- });
5569
- const unused = trueStaleSymbols.filter((s2) => s2.consumers === 0).length;
5475
+ const unused = staleResult.filter((s2) => s2.consumers === 0).length;
5570
5476
  const singleUse = trueStaleCount - unused;
5571
5477
  const parts = [];
5572
5478
  if (unused > 0) parts.push(`${unused} unused`);
@@ -5577,7 +5483,7 @@ function health(db, opts = {}) {
5577
5483
  effort: "low",
5578
5484
  impact: "medium",
5579
5485
  count: trueStaleCount,
5580
- locRecoverable: staleResult.filter((s2) => s2.consumers === 0 || !s2.file.includes("types")).reduce((sum, r) => sum + r.loc, 0)
5486
+ locRecoverable: staleResult.reduce((sum, r) => sum + r.loc, 0)
5581
5487
  });
5582
5488
  }
5583
5489
  if (trueDriftCount > 0) {
@@ -5680,11 +5586,11 @@ function convergence(db, symbolPatternA, symbolPatternB) {
5680
5586
  } else if (shared.length === 0) {
5681
5587
  strategy = "These functions do not share any callees. They are not a callee-based consolidation candidate.";
5682
5588
  } else if (uniqueA.length === 0 && uniqueB.length === 0) {
5683
- strategy = "These functions have identical callee sets. One can replace the other directly.";
5589
+ strategy = "These functions have identical tracked callee sets. They are a strong structural match, but identical callees do not prove interchangeable semantics; inspect signatures, control flow, and return values before consolidating.";
5684
5590
  } else if (uniqueA.length === 0) {
5685
- strategy = `A is a subset of B. A can be replaced by calling B (B does everything A does plus more).`;
5591
+ strategy = `A's tracked callees are a subset of B's. B may subsume part of A's structure, but verify signatures, guards, and non-call logic before replacing A with B.`;
5686
5592
  } else if (uniqueB.length === 0) {
5687
- strategy = `B is a subset of A. B can be replaced by calling A (A does everything B does plus more).`;
5593
+ strategy = `B's tracked callees are a subset of A's. A may subsume part of B's structure, but verify signatures, guards, and non-call logic before replacing B with A.`;
5688
5594
  } else if (uniqueA.length <= 2 && uniqueB.length <= 2) {
5689
5595
  strategy = `Create a shared function with the ${shared.length} common callees. Pass the ${uniqueA.length + uniqueB.length} divergent callees as parameters or strategy callbacks.`;
5690
5596
  } else {
@@ -6347,7 +6253,6 @@ var queries = {
6347
6253
  isolated,
6348
6254
  byKind,
6349
6255
  kindCounts,
6350
- docCoverage,
6351
6256
  deepChains,
6352
6257
  hierarchy,
6353
6258
  callGraph,
@@ -6760,27 +6665,6 @@ program.command("kind-counts").description("Histogram of symbol kinds in the cod
6760
6665
  }
6761
6666
  );
6762
6667
  });
6763
- program.command("doc-coverage").description("Check documentation coverage across symbols").option("-s, --scope <path>", "Limit to files matching path").option("--min-loc <n>", "Minimum LOC to consider", parseIntSafe, 3).option("-n, --limit <n>", "Max undocumented symbols to show", parseIntSafe, 50).action((opts) => {
6764
- runQuery(
6765
- (db) => queries.docCoverage(db, {
6766
- scope: opts.scope,
6767
- minLoc: opts.minLoc,
6768
- limit: opts.limit
6769
- }),
6770
- (result) => {
6771
- console.log(`Documentation coverage: ${result.coveragePercent}%`);
6772
- console.log(` Total symbols: ${result.totalSymbols}`);
6773
- console.log(` Documented: ${result.documented}`);
6774
- console.log(` Undocumented: ${result.undocumented}`);
6775
- if (result.undocumentedSymbols.length > 0) {
6776
- console.log("\nUndocumented:");
6777
- for (const s of result.undocumentedSymbols) {
6778
- console.log(` ${s.relativePath}:${displayLine(s.startLine)} ${s.shortName}`);
6779
- }
6780
- }
6781
- }
6782
- );
6783
- });
6784
6668
  program.command("deep-chains").description("Find the longest transitive dependency chains").option("-n, --limit <n>", "Number of chains to show", parseIntSafe, 10).option("-s, --scope <path>", "Limit to files matching path").option("--min-depth <n>", "Minimum chain depth", parseIntSafe, 3).action((opts) => {
6785
6669
  runQuery(
6786
6670
  (db) => queries.deepChains(db, {
@@ -187,18 +187,6 @@ interface ByKindResult {
187
187
  startLine: number;
188
188
  endLine: number;
189
189
  }
190
- interface DocCoverageResult {
191
- totalSymbols: number;
192
- documented: number;
193
- undocumented: number;
194
- coveragePercent: number;
195
- undocumentedSymbols: Array<{
196
- symbol: string;
197
- shortName: string;
198
- relativePath: string;
199
- startLine: number;
200
- }>;
201
- }
202
190
  interface DeepChainResult {
203
191
  /** Files in the chain, from leaf to root */
204
192
  chain: string[];
@@ -673,4 +661,4 @@ declare class ScipDatabase {
673
661
  close(): void;
674
662
  }
675
663
 
676
- export { type ChangeSurfaceEntry as $, type AffectedResult as A, type BottleneckResult as B, type CallGraphResult as C, type DataflowResult as D, type ExtractCandidate as E, type FanResult as F, type SimilarChainResult as G, type HealthReport as H, type ImportResult as I, type StaleAbstraction as J, type SliceResult as K, type RedundantReexport as L, type MemberResult as M, type SimilarSignatureGroup as N, type OutlineNode as O, type PassthroughCandidate as P, type ScipSymbol as Q, type RefResult as R, ScipDatabase as S, type TraceResult as T, type UnusedImportResult as U, type ScipLocalSymbol as V, type WrapperCandidate as W, type SupportedLanguage as X, type IndexerConfig as Y, type ProjectConfig as Z, type WatcherStatus as _, type ByKindResult as a, type DeadSymbolResult as a0, type DescriptorSuffix as a1, type DriftResult as a2, type HealthAction as a3, type IndexerOverrides as a4, type InstallMethod as a5, type ScipDescriptor as a6, type ScipQueryConfig as a7, type WatchConfig as a8, createGitignoreFilter as a9, type ChangeSurfaceResult as b, type CodeResult as c, type ComplexityHotspot as d, type ComplexityResult as e, type ConvergenceResult as f, type CouplingResult as g, type CycleResult as h, type DeadOptions as i, type DeadSummary as j, type DeepChainResult as k, type DepResult as l, type DiffImpactResult as m, type DocCoverageResult as n, type DriftSummary as o, type FileResult as p, type HierarchyNode as q, type HotspotResult as r, type IsolatedResult as s, type MethodResult as t, type StatsResult as u, type SymbolResult as v, type SystemResult as w, type SurfaceResult as x, type SimilarSymbolResult as y, type SimilarFileResult as z };
664
+ export { type DeadSymbolResult as $, type AffectedResult as A, type BottleneckResult as B, type CallGraphResult as C, type DataflowResult as D, type ExtractCandidate as E, type FanResult as F, type StaleAbstraction as G, type HealthReport as H, type ImportResult as I, type SliceResult as J, type RedundantReexport as K, type SimilarSignatureGroup as L, type MemberResult as M, type ScipSymbol as N, type OutlineNode as O, type PassthroughCandidate as P, type ScipLocalSymbol as Q, type RefResult as R, ScipDatabase as S, type TraceResult as T, type UnusedImportResult as U, type SupportedLanguage as V, type WrapperCandidate as W, type IndexerConfig as X, type ProjectConfig as Y, type WatcherStatus as Z, type ChangeSurfaceEntry as _, type ByKindResult as a, type DescriptorSuffix as a0, type DriftResult as a1, type HealthAction as a2, type IndexerOverrides as a3, type InstallMethod as a4, type ScipDescriptor as a5, type ScipQueryConfig as a6, type WatchConfig as a7, createGitignoreFilter as a8, type ChangeSurfaceResult as b, type CodeResult as c, type ComplexityHotspot as d, type ComplexityResult as e, type ConvergenceResult as f, type CouplingResult as g, type CycleResult as h, type DeadOptions as i, type DeadSummary as j, type DeepChainResult as k, type DepResult as l, type DiffImpactResult as m, type DriftSummary as n, type FileResult as o, type HierarchyNode as p, type HotspotResult as q, type IsolatedResult as r, type MethodResult as s, type StatsResult as t, type SymbolResult as u, type SystemResult as v, type SurfaceResult as w, type SimilarSymbolResult as x, type SimilarFileResult as y, type SimilarChainResult as z };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { Q as ScipSymbol, V as ScipLocalSymbol, X as SupportedLanguage, Y as IndexerConfig, Z as ProjectConfig, _ as WatcherStatus } from './db-ShvwGDKf.js';
2
- export { A as AffectedResult, B as BottleneckResult, a as ByKindResult, C as CallGraphResult, $ as ChangeSurfaceEntry, b as ChangeSurfaceResult, c as CodeResult, d as ComplexityHotspot, e as ComplexityResult, f as ConvergenceResult, g as CouplingResult, h as CycleResult, D as DataflowResult, i as DeadOptions, j as DeadSummary, a0 as DeadSymbolResult, k as DeepChainResult, l as DepResult, a1 as DescriptorSuffix, m as DiffImpactResult, n as DocCoverageResult, a2 as DriftResult, o as DriftSummary, E as ExtractCandidate, F as FanResult, p as FileResult, a3 as HealthAction, H as HealthReport, q as HierarchyNode, r as HotspotResult, I as ImportResult, a4 as IndexerOverrides, a5 as InstallMethod, s as IsolatedResult, M as MemberResult, t as MethodResult, O as OutlineNode, P as PassthroughCandidate, L as RedundantReexport, R as RefResult, S as ScipDatabase, a6 as ScipDescriptor, a7 as ScipQueryConfig, G as SimilarChainResult, z as SimilarFileResult, N as SimilarSignatureGroup, y as SimilarSymbolResult, K as SliceResult, J as StaleAbstraction, u as StatsResult, x as SurfaceResult, v as SymbolResult, w as SystemResult, T as TraceResult, U as UnusedImportResult, a8 as WatchConfig, W as WrapperCandidate, a9 as createGitignoreFilter } from './db-ShvwGDKf.js';
1
+ import { N as ScipSymbol, Q as ScipLocalSymbol, V as SupportedLanguage, X as IndexerConfig, Y as ProjectConfig, Z as WatcherStatus } from './db-viWlyVtv.js';
2
+ export { A as AffectedResult, B as BottleneckResult, a as ByKindResult, C as CallGraphResult, _ as ChangeSurfaceEntry, b as ChangeSurfaceResult, c as CodeResult, d as ComplexityHotspot, e as ComplexityResult, f as ConvergenceResult, g as CouplingResult, h as CycleResult, D as DataflowResult, i as DeadOptions, j as DeadSummary, $ as DeadSymbolResult, k as DeepChainResult, l as DepResult, a0 as DescriptorSuffix, m as DiffImpactResult, a1 as DriftResult, n as DriftSummary, E as ExtractCandidate, F as FanResult, o as FileResult, a2 as HealthAction, H as HealthReport, p as HierarchyNode, q as HotspotResult, I as ImportResult, a3 as IndexerOverrides, a4 as InstallMethod, r as IsolatedResult, M as MemberResult, s as MethodResult, O as OutlineNode, P as PassthroughCandidate, K as RedundantReexport, R as RefResult, S as ScipDatabase, a5 as ScipDescriptor, a6 as ScipQueryConfig, z as SimilarChainResult, y as SimilarFileResult, L as SimilarSignatureGroup, x as SimilarSymbolResult, J as SliceResult, G as StaleAbstraction, t as StatsResult, w as SurfaceResult, u as SymbolResult, v as SystemResult, T as TraceResult, U as UnusedImportResult, a7 as WatchConfig, W as WrapperCandidate, a8 as createGitignoreFilter } from './db-viWlyVtv.js';
3
3
  export { stats } from './queries/stats.js';
4
4
  export { files } from './queries/files.js';
5
5
  export { symbols } from './queries/symbols.js';
@@ -20,7 +20,6 @@ export { cycles } from './queries/cycles.js';
20
20
  export { bottlenecks } from './queries/bottlenecks.js';
21
21
  export { isolated } from './queries/isolated.js';
22
22
  export { byKind, kindCounts } from './queries/by-kind.js';
23
- export { docCoverage } from './queries/doc-coverage.js';
24
23
  export { deepChains } from './queries/deep-chains.js';
25
24
  export { hierarchy } from './queries/hierarchy.js';
26
25
  export { callGraph } from './queries/call-graph.js';
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import "./chunk-2UELLEBI.js";
1
+ import "./chunk-FVH3Y44U.js";
2
2
  import {
3
3
  surface
4
4
  } from "./chunk-EOROMIFO.js";
@@ -29,9 +29,6 @@ import {
29
29
  import {
30
30
  slice
31
31
  } from "./chunk-CHDJXYBG.js";
32
- import {
33
- hierarchy
34
- } from "./chunk-YDBXNPYU.js";
35
32
  import {
36
33
  hotspots
37
34
  } from "./chunk-KBOQX573.js";
@@ -56,46 +53,46 @@ import {
56
53
  import {
57
54
  diffImpact
58
55
  } from "./chunk-7HK5ZLOE.js";
59
- import {
60
- docCoverage
61
- } from "./chunk-YZ6L7GFO.js";
62
56
  import {
63
57
  fanIn,
64
58
  fanOut,
65
59
  topFanIn,
66
60
  topFanOut
67
- } from "./chunk-GJDHTTR2.js";
61
+ } from "./chunk-VMM4SYV4.js";
68
62
  import {
69
63
  files
70
64
  } from "./chunk-MGNMHKX3.js";
71
65
  import {
72
66
  health
73
- } from "./chunk-FYYOWQXK.js";
74
- import {
75
- staleAbstractions
76
- } from "./chunk-P4WO3BBW.js";
67
+ } from "./chunk-6FKIA6EI.js";
77
68
  import {
78
69
  stats
79
70
  } from "./chunk-74RFWB5T.js";
80
71
  import {
81
72
  wrapperCandidates
82
73
  } from "./chunk-4JCSOF2O.js";
83
- import {
84
- passthroughCandidates
85
- } from "./chunk-ZEUCXQBN.js";
86
74
  import {
87
75
  similar,
88
76
  similarAll
89
77
  } from "./chunk-OIDHN6GD.js";
78
+ import {
79
+ staleAbstractions
80
+ } from "./chunk-YGGFLMTM.js";
90
81
  import {
91
82
  isolated
92
83
  } from "./chunk-UQEQ6AHX.js";
84
+ import {
85
+ passthroughCandidates
86
+ } from "./chunk-ZEUCXQBN.js";
93
87
  import {
94
88
  drift
95
89
  } from "./chunk-7KIMF5PV.js";
96
90
  import {
97
91
  extractCandidates
98
92
  } from "./chunk-EPWLXXBL.js";
93
+ import {
94
+ hierarchy
95
+ } from "./chunk-YDBXNPYU.js";
99
96
  import {
100
97
  complexityHotspots
101
98
  } from "./chunk-VIYSWZCO.js";
@@ -104,7 +101,7 @@ import {
104
101
  } from "./chunk-UGQKAVCD.js";
105
102
  import {
106
103
  convergence
107
- } from "./chunk-HJZUSUPU.js";
104
+ } from "./chunk-TRESG7OB.js";
108
105
  import {
109
106
  coupling,
110
107
  topCoupling
@@ -131,7 +128,7 @@ import {
131
128
  import {
132
129
  byKind,
133
130
  kindCounts
134
- } from "./chunk-HLKAFWWJ.js";
131
+ } from "./chunk-EN2Z2CLO.js";
135
132
  import {
136
133
  callGraph
137
134
  } from "./chunk-C7H5WBTJ.js";
@@ -1245,7 +1242,6 @@ export {
1245
1242
  deps,
1246
1243
  detectLanguages,
1247
1244
  diffImpact,
1248
- docCoverage,
1249
1245
  drift,
1250
1246
  extractCandidates,
1251
1247
  fanIn,
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, A as AffectedResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, A as AffectedResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, B as BottleneckResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, B as BottleneckResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, a as ByKindResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, a as ByKindResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  byKind,
3
3
  kindCounts
4
- } from "../chunk-HLKAFWWJ.js";
4
+ } from "../chunk-EN2Z2CLO.js";
5
5
  import "../chunk-QIXNAB5K.js";
6
6
  export {
7
7
  byKind,
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, C as CallGraphResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, C as CallGraphResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, b as ChangeSurfaceResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, b as ChangeSurfaceResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, c as CodeResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, c as CodeResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, d as ComplexityHotspot } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, d as ComplexityHotspot } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, e as ComplexityResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, e as ComplexityResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { S as ScipDatabase, f as ConvergenceResult } from '../db-ShvwGDKf.js';
1
+ import { S as ScipDatabase, f as ConvergenceResult } from '../db-viWlyVtv.js';
2
2
  import 'better-sqlite3';
3
3
 
4
4
  /**