scip-query 0.3.4 → 0.4.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.
Files changed (154) hide show
  1. package/README.md +2 -26
  2. package/dist/{chunk-FYYOWQXK.js → chunk-2F2WH5WQ.js} +19 -36
  3. package/dist/{chunk-C7H5WBTJ.js → chunk-2UISVZGQ.js} +2 -2
  4. package/dist/{chunk-HLKAFWWJ.js → chunk-4ZT7UGWW.js} +56 -91
  5. package/dist/chunk-5AJJGPZE.js +60 -0
  6. package/dist/chunk-5RKYZSQ6.js +75 -0
  7. package/dist/chunk-7YBLWIXY.js +115 -0
  8. package/dist/{chunk-O7Q7FDUJ.js → chunk-A4GWYETB.js} +2 -2
  9. package/dist/{chunk-CHDJXYBG.js → chunk-A5BGEBM7.js} +2 -2
  10. package/dist/{chunk-KKCHYLVI.js → chunk-A7YY7IDA.js} +2 -2
  11. package/dist/chunk-AS7N27JK.js +115 -0
  12. package/dist/{chunk-F7XU27LU.js → chunk-CQRYLK33.js} +26 -2
  13. package/dist/{chunk-NFS5W3PP.js → chunk-CQUNEJYM.js} +2 -2
  14. package/dist/chunk-D4I3ZMN5.js +38 -0
  15. package/dist/{chunk-J3JSOSUO.js → chunk-E7J7Q7UW.js} +2 -2
  16. package/dist/{chunk-GEXE2T6I.js → chunk-EOHPASDV.js} +22 -14
  17. package/dist/chunk-FVH3Y44U.js +1 -0
  18. package/dist/chunk-GIBETK3W.js +37 -0
  19. package/dist/{chunk-SMDCNPMK.js → chunk-H3FPW5YN.js} +2 -2
  20. package/dist/{chunk-GJDHTTR2.js → chunk-HNURMDF4.js} +32 -17
  21. package/dist/{chunk-7KIMF5PV.js → chunk-HRDPUTIQ.js} +2 -2
  22. package/dist/{chunk-OIDHN6GD.js → chunk-I2JM34UV.js} +146 -5
  23. package/dist/{chunk-EPWLXXBL.js → chunk-IV6NZ426.js} +27 -29
  24. package/dist/{chunk-VT4JBH6L.js → chunk-KDCQJTYW.js} +2 -2
  25. package/dist/{chunk-5OMVSV6E.js → chunk-LOVDB4C6.js} +2 -2
  26. package/dist/chunk-MA3B3IUT.js +75 -0
  27. package/dist/{chunk-26DOJ63W.js → chunk-N2LH3M2P.js} +13 -2
  28. package/dist/chunk-NWCJWA36.js +162 -0
  29. package/dist/{chunk-NG5F43OU.js → chunk-P3VCDYMJ.js} +70 -1
  30. package/dist/{chunk-P3E6L7KW.js → chunk-P42KQKJZ.js} +83 -3
  31. package/dist/{chunk-YDBXNPYU.js → chunk-PGHN5UTM.js} +2 -2
  32. package/dist/{chunk-UGQKAVCD.js → chunk-QCYR4S6T.js} +2 -2
  33. package/dist/chunk-QGCEAVJD.js +2529 -0
  34. package/dist/{chunk-KBOQX573.js → chunk-RIEA5DOB.js} +19 -2
  35. package/dist/{chunk-VIYSWZCO.js → chunk-SL674KAW.js} +31 -3
  36. package/dist/chunk-SRELHCMG.js +110 -0
  37. package/dist/chunk-UTRKBUCB.js +87 -0
  38. package/dist/{chunk-HJZUSUPU.js → chunk-VCOJRQPP.js} +5 -5
  39. package/dist/chunk-VISMEWYP.js +34 -0
  40. package/dist/{chunk-LFJQVJYJ.js → chunk-VU7FDTWV.js} +2 -2
  41. package/dist/{chunk-HLUS2HEB.js → chunk-VUBLUTMU.js} +5 -4
  42. package/dist/{chunk-WGAD3GNR.js → chunk-WNPF2I25.js} +5 -5
  43. package/dist/{chunk-YY4QGUQ5.js → chunk-X3J4VPWM.js} +2 -2
  44. package/dist/{chunk-GSH2FPKV.js → chunk-XH56HXLC.js} +2 -2
  45. package/dist/{chunk-DH7G3DDV.js → chunk-ZU2AQQB5.js} +2 -2
  46. package/dist/cli.js +2722 -1036
  47. package/dist/{db-ShvwGDKf.d.ts → db-C4rPbKkI.d.ts} +7 -14
  48. package/dist/index.d.ts +4 -5
  49. package/dist/index.js +378 -149
  50. package/dist/postinstall.js +9 -3
  51. package/dist/queries/affected.d.ts +1 -1
  52. package/dist/queries/affected.js +2 -2
  53. package/dist/queries/bottlenecks.d.ts +1 -1
  54. package/dist/queries/bottlenecks.js +2 -1
  55. package/dist/queries/by-kind.d.ts +1 -1
  56. package/dist/queries/by-kind.js +2 -1
  57. package/dist/queries/call-graph.d.ts +1 -1
  58. package/dist/queries/call-graph.js +2 -2
  59. package/dist/queries/change-surface.d.ts +1 -1
  60. package/dist/queries/change-surface.js +2 -2
  61. package/dist/queries/code.d.ts +1 -1
  62. package/dist/queries/code.js +2 -2
  63. package/dist/queries/complexity-hotspots.d.ts +1 -1
  64. package/dist/queries/complexity-hotspots.js +2 -2
  65. package/dist/queries/complexity.d.ts +1 -1
  66. package/dist/queries/complexity.js +2 -2
  67. package/dist/queries/convergence.d.ts +1 -1
  68. package/dist/queries/convergence.js +2 -2
  69. package/dist/queries/coupling.d.ts +1 -1
  70. package/dist/queries/coupling.js +2 -2
  71. package/dist/queries/cycles.d.ts +1 -1
  72. package/dist/queries/cycles.js +2 -2
  73. package/dist/queries/dataflow.d.ts +1 -1
  74. package/dist/queries/dataflow.js +2 -2
  75. package/dist/queries/dead.d.ts +1 -1
  76. package/dist/queries/dead.js +3 -3
  77. package/dist/queries/deep-chains.d.ts +1 -1
  78. package/dist/queries/deep-chains.js +2 -2
  79. package/dist/queries/deps.d.ts +1 -1
  80. package/dist/queries/deps.js +2 -2
  81. package/dist/queries/diff-impact.d.ts +1 -1
  82. package/dist/queries/drift.d.ts +1 -1
  83. package/dist/queries/drift.js +2 -2
  84. package/dist/queries/extract-candidates.d.ts +1 -1
  85. package/dist/queries/extract-candidates.js +2 -2
  86. package/dist/queries/fan.d.ts +1 -1
  87. package/dist/queries/fan.js +2 -2
  88. package/dist/queries/files.d.ts +1 -1
  89. package/dist/queries/health.d.ts +1 -1
  90. package/dist/queries/health.js +13 -13
  91. package/dist/queries/hierarchy.d.ts +1 -1
  92. package/dist/queries/hierarchy.js +2 -2
  93. package/dist/queries/hotspots.d.ts +1 -1
  94. package/dist/queries/hotspots.js +2 -1
  95. package/dist/queries/imports.d.ts +1 -1
  96. package/dist/queries/imports.js +2 -2
  97. package/dist/queries/index.d.ts +1 -2
  98. package/dist/queries/index.js +49 -53
  99. package/dist/queries/isolated.d.ts +3 -4
  100. package/dist/queries/isolated.js +3 -3
  101. package/dist/queries/members.d.ts +1 -1
  102. package/dist/queries/members.js +2 -2
  103. package/dist/queries/methods.d.ts +1 -1
  104. package/dist/queries/methods.js +2 -1
  105. package/dist/queries/outline.d.ts +1 -1
  106. package/dist/queries/outline.js +2 -2
  107. package/dist/queries/passthrough-candidates.d.ts +1 -1
  108. package/dist/queries/passthrough-candidates.js +2 -2
  109. package/dist/queries/redundant-reexports.d.ts +1 -1
  110. package/dist/queries/redundant-reexports.js +3 -3
  111. package/dist/queries/refs.d.ts +1 -1
  112. package/dist/queries/refs.js +2 -2
  113. package/dist/queries/similar-chains.d.ts +1 -1
  114. package/dist/queries/similar-chains.js +2 -2
  115. package/dist/queries/similar-files.d.ts +1 -1
  116. package/dist/queries/similar-files.js +2 -2
  117. package/dist/queries/similar-signatures.d.ts +5 -3
  118. package/dist/queries/similar-signatures.js +2 -1
  119. package/dist/queries/similar.d.ts +1 -1
  120. package/dist/queries/similar.js +2 -2
  121. package/dist/queries/slice.d.ts +1 -1
  122. package/dist/queries/slice.js +2 -2
  123. package/dist/queries/stale-abstractions.d.ts +1 -1
  124. package/dist/queries/stale-abstractions.js +2 -2
  125. package/dist/queries/stats.d.ts +1 -1
  126. package/dist/queries/surface.d.ts +1 -1
  127. package/dist/queries/surface.js +2 -2
  128. package/dist/queries/symbols.d.ts +1 -1
  129. package/dist/queries/symbols.js +2 -2
  130. package/dist/queries/system.d.ts +1 -1
  131. package/dist/queries/system.js +2 -2
  132. package/dist/queries/trace.d.ts +1 -1
  133. package/dist/queries/trace.js +2 -2
  134. package/dist/queries/wrapper-candidates.d.ts +1 -1
  135. package/dist/queries/wrapper-candidates.js +2 -2
  136. package/dist/reindex-worker.js +213 -62
  137. package/package.json +1 -1
  138. package/skills/scip-language-playbook/SKILL.md +371 -0
  139. package/dist/chunk-2UELLEBI.js +0 -1
  140. package/dist/chunk-4JCSOF2O.js +0 -97
  141. package/dist/chunk-AXQKUYKF.js +0 -1442
  142. package/dist/chunk-CPVAQJEC.js +0 -46
  143. package/dist/chunk-EOROMIFO.js +0 -41
  144. package/dist/chunk-GU2H5QRN.js +0 -28
  145. package/dist/chunk-LQJUPXQY.js +0 -109
  146. package/dist/chunk-MPGIHELS.js +0 -39
  147. package/dist/chunk-P4WO3BBW.js +0 -64
  148. package/dist/chunk-TOIEB3LG.js +0 -78
  149. package/dist/chunk-UQEQ6AHX.js +0 -60
  150. package/dist/chunk-VJJKSGIX.js +0 -121
  151. package/dist/chunk-YZ6L7GFO.js +0 -73
  152. package/dist/chunk-ZEUCXQBN.js +0 -71
  153. package/dist/queries/doc-coverage.d.ts +0 -14
  154. package/dist/queries/doc-coverage.js +0 -8
@@ -0,0 +1,115 @@
1
+ import {
2
+ buildFileDepGraph,
3
+ getCallerRowsForSymbol,
4
+ getDefinitionsForFile
5
+ } from "./chunk-QGCEAVJD.js";
6
+ import {
7
+ isFunctionLikeSymbol,
8
+ shortenSymbol
9
+ } from "./chunk-QIXNAB5K.js";
10
+
11
+ // src/queries/wrapper-candidates.ts
12
+ import { basename, extname } from "path";
13
+ function wrapperCandidates(db, opts) {
14
+ const { scope, maxLoc = 15, limit = 30 } = opts ?? {};
15
+ const reverseFanIn = buildReverseFileFanIn(buildFileDepGraph(db, scope));
16
+ const symbols = getScopedDefinitions(db, scope).filter((definition) => definitionLoc(definition) <= maxLoc && definitionLoc(definition) >= 2);
17
+ const results = [];
18
+ for (const symbol of symbols) {
19
+ if (db.isIgnored(symbol.relativePath) || !isFunctionLikeSymbol(symbol.symbol)) continue;
20
+ const symbolStem = basename(symbol.relativePath, extname(symbol.relativePath));
21
+ const callerRows = dedupeRows(
22
+ getCallerRowsForSymbol(db, symbol, { limit: 200 }).filter((row) => row.file !== symbol.relativePath)
23
+ ).filter((row) => basename(row.file, extname(row.file)) !== symbolStem);
24
+ if (callerRows.length !== 1) continue;
25
+ const caller = callerRows[0];
26
+ const callerDefinition = getDefinitionsForFile(db, caller.file).find((definition) => definition.symbol === caller.symbol);
27
+ const useDefinitionFanIn = callerDefinition?.isFunctionLike ?? false;
28
+ let callerFanIn;
29
+ if (useDefinitionFanIn && callerDefinition) {
30
+ callerFanIn = new Set(
31
+ getCallerRowsForSymbol(db, callerDefinition, { limit: 500 }).filter((row) => row.file !== callerDefinition.relativePath).map((row) => row.file)
32
+ ).size;
33
+ } else {
34
+ callerFanIn = fallbackCallerFanIn(db, reverseFanIn, caller.file);
35
+ }
36
+ if (callerFanIn <= 3) continue;
37
+ results.push({
38
+ symbol: symbol.symbol,
39
+ shortName: shortenSymbol(symbol.symbol),
40
+ file: symbol.relativePath,
41
+ startLine: symbol.startLine,
42
+ endLine: symbol.endLine,
43
+ loc: definitionLoc(symbol),
44
+ singleCaller: caller.symbol,
45
+ singleCallerShort: useDefinitionFanIn ? shortenSymbol(caller.symbol) : basename(caller.file),
46
+ callerFanIn
47
+ });
48
+ }
49
+ results.sort((left, right) => right.callerFanIn - left.callerFanIn || right.loc - left.loc);
50
+ return results.slice(0, limit);
51
+ }
52
+ function definitionLoc(definition) {
53
+ return definition.endLine - definition.startLine + 1;
54
+ }
55
+ function getScopedDefinitions(db, scope) {
56
+ const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
57
+ return db.all(
58
+ `SELECT relative_path
59
+ FROM documents
60
+ WHERE 1 = 1
61
+ ${db.pathExclusionsFor("documents")}
62
+ ${scopeFilter}
63
+ ORDER BY relative_path`
64
+ ).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
65
+ }
66
+ function dedupeRows(rows) {
67
+ const seen = /* @__PURE__ */ new Set();
68
+ const unique = [];
69
+ for (const row of rows) {
70
+ const key = `${row.symbol}|${row.file}`;
71
+ if (seen.has(key)) continue;
72
+ seen.add(key);
73
+ unique.push(row);
74
+ }
75
+ return unique;
76
+ }
77
+ function buildReverseFileFanIn(graph) {
78
+ const reverse = /* @__PURE__ */ new Map();
79
+ for (const [fromFile, deps] of graph) {
80
+ if (!reverse.has(fromFile)) {
81
+ reverse.set(fromFile, reverse.get(fromFile) ?? 0);
82
+ }
83
+ for (const dep of deps) {
84
+ reverse.set(dep, (reverse.get(dep) ?? 0) + 1);
85
+ }
86
+ }
87
+ return reverse;
88
+ }
89
+ function fallbackCallerFanIn(db, reverseFanIn, callerFile) {
90
+ const functionLikeFanIn = getDefinitionsForFile(db, callerFile).filter((definition) => definition.isFunctionLike).map((definition) => new Set(
91
+ getCallerRowsForSymbol(db, definition, { limit: 500 }).filter((row) => row.file !== definition.relativePath).map((row) => row.file)
92
+ ).size).sort((left, right) => right - left)[0] ?? 0;
93
+ if (functionLikeFanIn > 0) {
94
+ return functionLikeFanIn;
95
+ }
96
+ const direct = reverseFanIn.get(callerFile) ?? 0;
97
+ if (direct > 0) {
98
+ return direct;
99
+ }
100
+ const stem = basename(callerFile, extname(callerFile));
101
+ let best = 0;
102
+ for (const [file, fanIn] of reverseFanIn) {
103
+ if (file === callerFile) continue;
104
+ if (basename(file, extname(file)) !== stem) continue;
105
+ if (fanIn > best) {
106
+ best = fanIn;
107
+ }
108
+ }
109
+ return best;
110
+ }
111
+
112
+ export {
113
+ wrapperCandidates
114
+ };
115
+ //# sourceMappingURL=chunk-AS7N27JK.js.map
@@ -1,3 +1,8 @@
1
+ import {
2
+ getAllDefinitions,
3
+ getCalleeRowsForSymbol,
4
+ getCallerRowsForSymbol
5
+ } from "./chunk-QGCEAVJD.js";
1
6
  import {
2
7
  shortenSymbol
3
8
  } from "./chunk-QIXNAB5K.js";
@@ -39,7 +44,7 @@ function bottlenecks(db, opts = {}) {
39
44
  minFanOut,
40
45
  limit
41
46
  );
42
- return rows.filter((r) => !db.isIgnored(r.defined_in)).map((r) => ({
47
+ const indexedResults = rows.filter((r) => !db.isIgnored(r.defined_in)).map((r) => ({
43
48
  symbol: r.symbol,
44
49
  shortName: shortenSymbol(r.symbol),
45
50
  fanIn: r.fan_in,
@@ -47,9 +52,28 @@ function bottlenecks(db, opts = {}) {
47
52
  score: r.fan_in * r.fan_out,
48
53
  definedIn: r.defined_in
49
54
  }));
55
+ if (indexedResults.length > 0) {
56
+ return indexedResults;
57
+ }
58
+ return getAllDefinitions(db, { scope }).filter((definition) => !db.isIgnored(definition.relativePath)).map((definition) => {
59
+ const fanIn = new Set(
60
+ getCallerRowsForSymbol(db, definition, { limit: 500 }).map((row) => row.file)
61
+ ).size;
62
+ const fanOut = new Set(
63
+ getCalleeRowsForSymbol(db, definition, { limit: 500 }).filter((row) => row.file !== definition.relativePath).map((row) => `${row.symbol}|${row.file}`)
64
+ ).size;
65
+ return {
66
+ symbol: definition.symbol,
67
+ shortName: shortenSymbol(definition.symbol),
68
+ fanIn,
69
+ fanOut,
70
+ score: fanIn * fanOut,
71
+ definedIn: definition.relativePath
72
+ };
73
+ }).filter((row) => row.fanIn >= minFanIn && row.fanOut >= minFanOut).sort((left, right) => right.score - left.score || right.fanIn - left.fanIn).slice(0, limit);
50
74
  }
51
75
 
52
76
  export {
53
77
  bottlenecks
54
78
  };
55
- //# sourceMappingURL=chunk-F7XU27LU.js.map
79
+ //# sourceMappingURL=chunk-CQRYLK33.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  findFirstSymbolMatch
3
- } from "./chunk-AXQKUYKF.js";
3
+ } from "./chunk-QGCEAVJD.js";
4
4
  import {
5
5
  isDirectChildSymbol,
6
6
  leafSuffix,
@@ -34,4 +34,4 @@ function members(db, symbolPattern) {
34
34
  export {
35
35
  members
36
36
  };
37
- //# sourceMappingURL=chunk-NFS5W3PP.js.map
37
+ //# sourceMappingURL=chunk-CQUNEJYM.js.map
@@ -0,0 +1,38 @@
1
+ import {
2
+ cleanSignature
3
+ } from "./chunk-4TYLS5XX.js";
4
+ import {
5
+ getDefinitionsForFile,
6
+ resolveIndexedPaths
7
+ } from "./chunk-QGCEAVJD.js";
8
+ import {
9
+ shortenSymbol
10
+ } from "./chunk-QIXNAB5K.js";
11
+
12
+ // src/queries/symbols.ts
13
+ function symbols(db, filePattern) {
14
+ const resolvedPaths = resolveIndexedPaths(db, filePattern);
15
+ if (resolvedPaths.length === 0) {
16
+ return [];
17
+ }
18
+ return resolvedPaths.flatMap((relativePath) => getDefinitionsForFile(db, relativePath)).filter((row) => !db.isIgnored(row.relativePath)).map((row) => {
19
+ const docRow = db.get(
20
+ `SELECT REPLACE(SUBSTR(documentation, INSTR(documentation, '|') + 1), char(10), ' ') AS sig
21
+ FROM global_symbols
22
+ WHERE id = ?`,
23
+ row.symbolId
24
+ );
25
+ return {
26
+ startLine: row.startLine,
27
+ endLine: row.endLine,
28
+ symbol: row.symbol,
29
+ shortName: shortenSymbol(row.symbol),
30
+ signature: cleanSignature(docRow?.sig ?? null)
31
+ };
32
+ });
33
+ }
34
+
35
+ export {
36
+ symbols
37
+ };
38
+ //# sourceMappingURL=chunk-D4I3ZMN5.js.map
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  findFirstSymbolMatch,
3
3
  resolveIndexedFile
4
- } from "./chunk-AXQKUYKF.js";
4
+ } from "./chunk-QGCEAVJD.js";
5
5
  import {
6
6
  shortenSymbol
7
7
  } from "./chunk-QIXNAB5K.js";
@@ -76,4 +76,4 @@ function readFileRange(db, filePath, startLine, endLine, context) {
76
76
  export {
77
77
  code
78
78
  };
79
- //# sourceMappingURL=chunk-J3JSOSUO.js.map
79
+ //# sourceMappingURL=chunk-E7J7Q7UW.js.map
@@ -3,8 +3,9 @@ import {
3
3
  } from "./chunk-4TYLS5XX.js";
4
4
  import {
5
5
  findFirstSymbolMatch,
6
- getSourceReferenceSites
7
- } from "./chunk-AXQKUYKF.js";
6
+ getSourceReferenceSites,
7
+ getSourceText
8
+ } from "./chunk-QGCEAVJD.js";
8
9
  import {
9
10
  isFunctionLikeSymbol,
10
11
  shortenSymbol
@@ -16,24 +17,22 @@ function trace(db, symbolPattern) {
16
17
  if (!match) {
17
18
  return { definitions: [], referencedBy: [] };
18
19
  }
19
- const defRows = db.all(
20
- `SELECT d.relative_path, der.start_line, der.end_line,
20
+ const definitionMeta = db.get(
21
+ `SELECT
21
22
  gs.display_name,
22
23
  REPLACE(SUBSTR(gs.documentation, INSTR(gs.documentation, '|') + 1), char(10), ' ') AS sig
23
24
  FROM global_symbols gs
24
- JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
25
- JOIN documents d ON der.document_id = d.id
26
25
  WHERE gs.id = ?
27
- ORDER BY d.relative_path, der.start_line
28
26
  LIMIT 10`,
29
27
  match.symbolId
30
28
  );
31
- const definitions = defRows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
32
- relativePath: r.relative_path,
33
- startLine: r.start_line,
34
- endLine: r.end_line,
35
- signature: buildTraceSignature(r.sig, r.display_name, match.symbol)
36
- }));
29
+ const definitions = db.isIgnored(match.relativePath) ? [] : [{
30
+ relativePath: match.relativePath,
31
+ startLine: match.startLine,
32
+ endLine: match.endLine,
33
+ signature: buildTraceSignature(definitionMeta?.sig ?? null, definitionMeta?.display_name ?? null, match.symbol),
34
+ source: definitionSource(db, match.relativePath, match.startLine, match.endLine)
35
+ }];
37
36
  const sourceSites = getSourceReferenceSites(db, match);
38
37
  const referencedBy = sourceSites.length > 0 ? sourceSites.filter((site) => !db.isIgnored(site.file)).map((site) => ({
39
38
  relativePath: site.file,
@@ -66,6 +65,15 @@ function trace(db, symbolPattern) {
66
65
  }));
67
66
  return { definitions, referencedBy };
68
67
  }
68
+ function definitionSource(db, relativePath, startLine, endLine) {
69
+ const source = getSourceText(db, relativePath);
70
+ if (!source) {
71
+ return null;
72
+ }
73
+ const lines = source.split("\n");
74
+ const slice = lines.slice(startLine, endLine + 1).join("\n").trimEnd();
75
+ return slice.length > 0 ? slice : null;
76
+ }
69
77
  function buildTraceSignature(signature, displayName, rawSymbol) {
70
78
  const cleaned = cleanSignature(signature);
71
79
  if (cleaned && !looksBogusSignature(cleaned)) {
@@ -84,4 +92,4 @@ function looksBogusSignature(signature) {
84
92
  export {
85
93
  trace
86
94
  };
87
- //# sourceMappingURL=chunk-GEXE2T6I.js.map
95
+ //# sourceMappingURL=chunk-EOHPASDV.js.map
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=chunk-FVH3Y44U.js.map
@@ -0,0 +1,37 @@
1
+ import {
2
+ findFirstSymbolMatch,
3
+ getDefinitionsForFile
4
+ } from "./chunk-QGCEAVJD.js";
5
+ import {
6
+ leafName,
7
+ leafSuffix
8
+ } from "./chunk-QIXNAB5K.js";
9
+
10
+ // src/queries/methods.ts
11
+ import { basename } from "path";
12
+ function methods(db, className) {
13
+ const classMatch = findFirstSymbolMatch(db, className);
14
+ if (!classMatch) {
15
+ return [];
16
+ }
17
+ const ownerName = leafName(classMatch.symbol);
18
+ const definitions = getDefinitionsForFile(db, classMatch.relativePath).filter((definition) => isCallableSymbol(definition.symbol));
19
+ const directMethods = definitions.filter((definition) => definition.parentTypeName === ownerName || definition.symbol.includes(ownerName));
20
+ const fileScopedMethods = directMethods.length > 0 ? directMethods : stripExtension(basename(classMatch.relativePath)) === ownerName ? definitions.filter((definition) => definition.symbol.includes("<invalid-global-code>")) : [];
21
+ return fileScopedMethods.map((definition) => ({
22
+ startLine: definition.startLine,
23
+ endLine: definition.endLine,
24
+ name: leafName(definition.symbol)
25
+ }));
26
+ }
27
+ function isCallableSymbol(rawSymbol) {
28
+ return rawSymbol.endsWith("().") || leafSuffix(rawSymbol) === "method";
29
+ }
30
+ function stripExtension(relativePath) {
31
+ return relativePath.replace(/\.[^.]+$/, "");
32
+ }
33
+
34
+ export {
35
+ methods
36
+ };
37
+ //# sourceMappingURL=chunk-GIBETK3W.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveIndexedFile
3
- } from "./chunk-AXQKUYKF.js";
3
+ } from "./chunk-QGCEAVJD.js";
4
4
  import {
5
5
  shortenSymbol
6
6
  } from "./chunk-QIXNAB5K.js";
@@ -68,4 +68,4 @@ function changeSurface(db, filePattern) {
68
68
  export {
69
69
  changeSurface
70
70
  };
71
- //# sourceMappingURL=chunk-SMDCNPMK.js.map
71
+ //# sourceMappingURL=chunk-H3FPW5YN.js.map
@@ -1,27 +1,30 @@
1
1
  import {
2
+ buildFileDepGraph,
3
+ findFirstSymbolMatch,
2
4
  resolveIndexedFile
3
- } from "./chunk-AXQKUYKF.js";
5
+ } from "./chunk-QGCEAVJD.js";
4
6
  import {
5
7
  shortenSymbol
6
8
  } from "./chunk-QIXNAB5K.js";
7
9
 
8
10
  // src/queries/fan.ts
9
11
  function fanIn(db, symbolPattern) {
10
- const rows = db.all(
11
- `SELECT gs.symbol, COUNT(DISTINCT c.document_id) AS file_count
12
- FROM mentions m
13
- JOIN chunks c ON m.chunk_id = c.id
14
- JOIN global_symbols gs ON m.symbol_id = gs.id
15
- WHERE gs.symbol LIKE ?
16
- AND m.role != 1
17
- GROUP BY gs.id
18
- ORDER BY file_count DESC`,
19
- `%${symbolPattern}%`
12
+ const match = findFirstSymbolMatch(db, symbolPattern);
13
+ if (!match) {
14
+ return [];
15
+ }
16
+ const row = db.get(
17
+ `SELECT COUNT(DISTINCT c.document_id) AS file_count
18
+ FROM mentions m
19
+ JOIN chunks c ON m.chunk_id = c.id
20
+ WHERE m.symbol_id = ?
21
+ AND m.role != 1`,
22
+ match.symbolId
20
23
  );
21
- return rows.map((r) => ({
22
- name: shortenSymbol(r.symbol),
23
- count: r.file_count
24
- }));
24
+ return [{
25
+ name: shortenSymbol(match.symbol),
26
+ count: row?.file_count ?? 0
27
+ }];
25
28
  }
26
29
  function fanOut(db, filePattern) {
27
30
  const resolvedFile = resolveIndexedFile(db, filePattern);
@@ -43,10 +46,22 @@ function fanOut(db, filePattern) {
43
46
  ORDER BY symbol_count DESC`,
44
47
  resolvedFile
45
48
  );
46
- return rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
49
+ const indexedResults = rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
47
50
  name: r.relative_path,
48
51
  count: r.symbol_count
49
52
  }));
53
+ if (indexedResults.length > 0) {
54
+ return indexedResults;
55
+ }
56
+ const graph = buildFileDepGraph(db);
57
+ const deps = graph.get(resolvedFile);
58
+ if (!deps || deps.size === 0) {
59
+ return [];
60
+ }
61
+ return [{
62
+ name: resolvedFile,
63
+ count: deps.size
64
+ }];
50
65
  }
51
66
  function topFanIn(db, opts = {}) {
52
67
  const { limit = 30, scope } = opts;
@@ -106,4 +121,4 @@ export {
106
121
  topFanIn,
107
122
  topFanOut
108
123
  };
109
- //# sourceMappingURL=chunk-GJDHTTR2.js.map
124
+ //# sourceMappingURL=chunk-HNURMDF4.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  buildFileDepGraph
3
- } from "./chunk-AXQKUYKF.js";
3
+ } from "./chunk-QGCEAVJD.js";
4
4
 
5
5
  // src/queries/drift.ts
6
6
  import path from "path";
@@ -162,4 +162,4 @@ function isTestLikePath(filePath) {
162
162
  export {
163
163
  drift
164
164
  };
165
- //# sourceMappingURL=chunk-7KIMF5PV.js.map
165
+ //# sourceMappingURL=chunk-HRDPUTIQ.js.map
@@ -1,9 +1,12 @@
1
1
  import {
2
2
  findFirstSymbolMatch,
3
- getCalleeRowsForSymbol
4
- } from "./chunk-AXQKUYKF.js";
3
+ getAllDefinitions,
4
+ getCalleeRowsForSymbol,
5
+ getSourceText
6
+ } from "./chunk-QGCEAVJD.js";
5
7
  import {
6
8
  isFunctionLikeSymbol,
9
+ leafName,
7
10
  shortenSymbol
8
11
  } from "./chunk-QIXNAB5K.js";
9
12
 
@@ -11,7 +14,7 @@ import {
11
14
  function similar(db, symbolPattern, opts = {}) {
12
15
  const { minSimilarity = 0.4, limit = 20 } = opts;
13
16
  const target = findCallees(db, symbolPattern);
14
- if (!target || target.callees.size === 0) return [];
17
+ if (!target) return [];
15
18
  if (!isFunctionLikeSymbol(target.symbol)) return [];
16
19
  const candidates = getAllCalleeFingerprints(db, {
17
20
  minCallees: 3,
@@ -43,7 +46,10 @@ function similar(db, symbolPattern, opts = {}) {
43
46
  });
44
47
  }
45
48
  results.sort((a, b) => b.similarity - a.similarity);
46
- return results.slice(0, limit);
49
+ if (results.length > 0) {
50
+ return results.slice(0, limit);
51
+ }
52
+ return similarBySourceShape(db, symbolPattern, { minSimilarity, limit });
47
53
  }
48
54
  function similarAll(db, opts = {}) {
49
55
  const { minSimilarity = 0.5, limit = 20, scope, minCallees = 4 } = opts;
@@ -190,9 +196,144 @@ function difference(a, b) {
190
196
  }
191
197
  return result;
192
198
  }
199
+ function similarBySourceShape(db, symbolPattern, opts) {
200
+ const target = findSourceFingerprint(db, symbolPattern);
201
+ if (!target || target.tokens.size < 3) {
202
+ return [];
203
+ }
204
+ const minSimilarity = opts.minSimilarity >= 0.5 ? opts.minSimilarity : 0.3;
205
+ const results = [];
206
+ for (const candidate of getAllSourceFingerprints(db)) {
207
+ if (candidate.symbol === target.symbol || candidate.tokens.size < 3) continue;
208
+ const shared = intersection(target.tokens, candidate.tokens);
209
+ if (shared.size < 2) continue;
210
+ const union = /* @__PURE__ */ new Set([...target.tokens, ...candidate.tokens]);
211
+ const similarity = union.size > 0 ? shared.size / union.size : 0;
212
+ if (similarity < minSimilarity) continue;
213
+ results.push({
214
+ symbolA: target.symbol,
215
+ shortNameA: shortenSymbol(target.symbol),
216
+ fileA: target.file,
217
+ symbolB: candidate.symbol,
218
+ shortNameB: shortenSymbol(candidate.symbol),
219
+ fileB: candidate.file,
220
+ similarity,
221
+ sharedCallees: [...shared].sort(),
222
+ uniqueToA: [...difference(target.tokens, candidate.tokens)].sort(),
223
+ uniqueToB: [...difference(candidate.tokens, target.tokens)].sort()
224
+ });
225
+ }
226
+ results.sort((a, b) => b.similarity - a.similarity || a.shortNameB.localeCompare(b.shortNameB));
227
+ return results.slice(0, opts.limit);
228
+ }
229
+ function findSourceFingerprint(db, symbolPattern) {
230
+ const match = findFirstSymbolMatch(db, symbolPattern);
231
+ if (!match || !isFunctionLikeSymbol(match.symbol)) {
232
+ return null;
233
+ }
234
+ const snippet = definitionSnippet(db, match.relativePath, match.startLine, match.endLine, leafName(match.symbol));
235
+ const tokens = sourceTokens(snippet, leafName(match.symbol));
236
+ if (tokens.size === 0) {
237
+ return null;
238
+ }
239
+ return {
240
+ symbol: match.symbol,
241
+ file: match.relativePath,
242
+ tokens
243
+ };
244
+ }
245
+ function getAllSourceFingerprints(db) {
246
+ return getAllDefinitions(db).filter((definition) => definition.isFunctionLike).map((definition) => ({
247
+ symbol: definition.symbol,
248
+ file: definition.relativePath,
249
+ tokens: sourceTokens(
250
+ definitionSnippet(db, definition.relativePath, definition.startLine, definition.endLine, definition.leaf),
251
+ definition.leaf
252
+ )
253
+ })).filter((fingerprint) => fingerprint.tokens.size > 0);
254
+ }
255
+ function definitionSnippet(db, relativePath, startLine, endLine, leaf) {
256
+ const source = getSourceText(db, relativePath);
257
+ if (!source) {
258
+ return "";
259
+ }
260
+ const lines = source.split("\n");
261
+ if (endLine >= startLine && endLine - startLine <= 12) {
262
+ return lines.slice(startLine, endLine + 1).join("\n");
263
+ }
264
+ const markerPatterns = [
265
+ new RegExp(`\\bdef\\s+${escapeRegex(leaf)}\\b`),
266
+ new RegExp(`\\bfun\\s+${escapeRegex(leaf)}\\b`),
267
+ new RegExp(`\\bfn\\s+${escapeRegex(leaf)}\\b`),
268
+ new RegExp(`\\bfunction\\s+${escapeRegex(leaf)}\\b`),
269
+ new RegExp(`\\b${escapeRegex(leaf)}\\s*\\(`)
270
+ ];
271
+ const definitionStart = lines.findIndex((line) => markerPatterns.some((pattern) => pattern.test(line)));
272
+ if (definitionStart >= 0) {
273
+ let definitionEnd = definitionStart;
274
+ for (let index = definitionStart + 1; index < lines.length && index <= definitionStart + 8; index++) {
275
+ const line = lines[index] ?? "";
276
+ if (index > definitionStart && looksLikeDefinitionBoundary(line)) {
277
+ break;
278
+ }
279
+ definitionEnd = index;
280
+ if (line.trim() === "" && index > definitionStart + 1) {
281
+ break;
282
+ }
283
+ }
284
+ return lines.slice(definitionStart, definitionEnd + 1).join("\n");
285
+ }
286
+ return lines.slice(startLine, Math.min(lines.length, startLine + 8)).join("\n");
287
+ }
288
+ function sourceTokens(snippet, leaf) {
289
+ if (!snippet) {
290
+ return /* @__PURE__ */ new Set();
291
+ }
292
+ const stopWords = /* @__PURE__ */ new Set([
293
+ "public",
294
+ "private",
295
+ "protected",
296
+ "final",
297
+ "static",
298
+ "class",
299
+ "def",
300
+ "fun",
301
+ "fn",
302
+ "function",
303
+ "return",
304
+ "string",
305
+ "bool",
306
+ "boolean",
307
+ "void",
308
+ "unit",
309
+ "self",
310
+ "this",
311
+ "new",
312
+ "const",
313
+ "let",
314
+ "var",
315
+ "end",
316
+ "pub"
317
+ ]);
318
+ const normalizedLeafParts = splitIdentifier(leaf);
319
+ const normalized = snippet.replace(/["'`]/g, " ").replace(/\b\d+\b/g, " NUM ").replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[^A-Za-z0-9_]+/g, " ").replace(/_/g, " ").toLowerCase();
320
+ const tokens = normalized.split(/\s+/).map((token) => token.trim()).filter((token) => token.length > 1).filter((token) => !stopWords.has(token)).filter((token) => !normalizedLeafParts.has(token));
321
+ return new Set(tokens);
322
+ }
323
+ function splitIdentifier(value) {
324
+ return new Set(
325
+ value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").split(/[^A-Za-z0-9_]+|_/).map((part) => part.toLowerCase()).filter((part) => part.length > 1)
326
+ );
327
+ }
328
+ function looksLikeDefinitionBoundary(line) {
329
+ return /^\s*(?:def|fun|fn|function|class|trait|module|object|enum|interface|public|private|protected)\b/.test(line);
330
+ }
331
+ function escapeRegex(value) {
332
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
333
+ }
193
334
 
194
335
  export {
195
336
  similar,
196
337
  similarAll
197
338
  };
198
- //# sourceMappingURL=chunk-OIDHN6GD.js.map
339
+ //# sourceMappingURL=chunk-I2JM34UV.js.map