scip-query 0.4.2 → 0.5.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/dist/{chunk-OXX3QF24.js → chunk-2MQ5DPY6.js} +2 -2
- package/dist/{chunk-RL74LF47.js → chunk-2QTYIOJ5.js} +2 -2
- package/dist/{chunk-DUJNJQPO.js → chunk-3VI4YXCL.js} +3 -3
- package/dist/{chunk-XUVPQDXW.js → chunk-3VV2G6U7.js} +4 -4
- package/dist/{chunk-J47VSL6I.js → chunk-44PFXVXG.js} +3 -3
- package/dist/{chunk-SVLUJSY7.js → chunk-6SLFQR36.js} +4 -15
- package/dist/{chunk-JHVQB4Y5.js → chunk-7DBPRGMS.js} +12 -12
- package/dist/{chunk-A6XLXV6W.js → chunk-DTB724R3.js} +3 -3
- package/dist/{chunk-TWVXFKJA.js → chunk-FLOYI6I4.js} +4 -4
- package/dist/{chunk-MGNMHKX3.js → chunk-FO2CBB7U.js} +10 -2
- package/dist/{chunk-4TYLS5XX.js → chunk-GJT3MO2T.js} +9 -2
- package/dist/{chunk-EAGKJFDX.js → chunk-HAP4LJKX.js} +8 -29
- package/dist/{chunk-RE7POFGI.js → chunk-JCOJQ4I6.js} +2 -2
- package/dist/{chunk-VY2L4TP6.js → chunk-JGQMOS4V.js} +3 -3
- package/dist/{chunk-QMXSLHZP.js → chunk-JMD4WJ2Q.js} +2 -2
- package/dist/{chunk-43A4UCS7.js → chunk-JSQPZOPO.js} +11 -18
- package/dist/{chunk-PCU455MX.js → chunk-JSXGC2EH.js} +2 -2
- package/dist/chunk-JZN3DRCT.js +59 -0
- package/dist/{chunk-ZVZAIIB5.js → chunk-KMWYB3CX.js} +12 -36
- package/dist/{chunk-SYQR4QGK.js → chunk-MRM755FU.js} +8 -9
- package/dist/{chunk-R7HPHMRZ.js → chunk-N2XO3Z5F.js} +3 -3
- package/dist/{chunk-POLELLNM.js → chunk-OLW5UL36.js} +19 -25
- package/dist/{chunk-ALUFWH3U.js → chunk-OMCRXXDX.js} +187 -282
- package/dist/{chunk-Z5VSUOEE.js → chunk-OWJOHUZE.js} +2 -2
- package/dist/{chunk-RJ5GULL6.js → chunk-PEDH3D4G.js} +2 -2
- package/dist/{chunk-6UZU7DFL.js → chunk-POAN4SCR.js} +3 -3
- package/dist/{chunk-3NJSJ7TE.js → chunk-PTMGEBU3.js} +4 -15
- package/dist/{chunk-NXUIWD6K.js → chunk-PU44HK7P.js} +3 -3
- package/dist/{chunk-6CH23IAS.js → chunk-QJI7EECA.js} +22 -34
- package/dist/{chunk-KLNKDX6A.js → chunk-R5HICGMB.js} +4 -4
- package/dist/{chunk-6ECR2FLR.js → chunk-RJ2D6YWQ.js} +4 -15
- package/dist/{chunk-CBIWNZZZ.js → chunk-RZ5GYPBP.js} +3 -3
- package/dist/chunk-SRLQNO6O.js +101 -0
- package/dist/{chunk-JKXHHV4B.js → chunk-UGS7HJI4.js} +2 -2
- package/dist/{chunk-PU2254N2.js → chunk-VKUUXOE7.js} +5 -15
- package/dist/{chunk-W46L2BXT.js → chunk-VPUJSJCI.js} +2 -2
- package/dist/{chunk-UJWI5CBB.js → chunk-VRWVV3EP.js} +4 -7
- package/dist/{chunk-7BS4CPJX.js → chunk-WJWQEU4A.js} +3 -3
- package/dist/chunk-WJZHDUSB.js +40 -0
- package/dist/{chunk-FVJE4MQL.js → chunk-WWOCQ5W4.js} +5 -8
- package/dist/chunk-X3Q2OVRL.js +77 -0
- package/dist/chunk-Y3P7QKKN.js +27 -0
- package/dist/{chunk-VKBOLNYN.js → chunk-Y6FAHY4N.js} +10 -8
- package/dist/{chunk-TO3L4YNK.js → chunk-YMSJCSRG.js} +5 -1
- package/dist/{chunk-24LF6IZB.js → chunk-ZDL3U4W2.js} +3 -3
- package/dist/{chunk-KG4OFQEN.js → chunk-ZXNX5JRE.js} +3 -3
- package/dist/cli.js +368 -721
- package/dist/{db-C4rPbKkI.d.ts → db-6F9R9e_t.d.ts} +0 -4
- package/dist/index.d.ts +2 -4
- package/dist/index.js +46 -58
- package/dist/queries/affected.d.ts +1 -1
- package/dist/queries/affected.js +3 -3
- package/dist/queries/bottlenecks.d.ts +1 -1
- package/dist/queries/bottlenecks.js +3 -3
- package/dist/queries/by-kind.d.ts +1 -1
- package/dist/queries/by-kind.js +3 -3
- package/dist/queries/call-graph.d.ts +1 -1
- package/dist/queries/call-graph.js +3 -3
- package/dist/queries/change-surface.d.ts +4 -1
- package/dist/queries/change-surface.js +3 -3
- package/dist/queries/clean-signature.d.ts +9 -1
- package/dist/queries/clean-signature.js +5 -3
- package/dist/queries/code.d.ts +1 -1
- package/dist/queries/code.js +3 -3
- package/dist/queries/complexity-hotspots.d.ts +8 -1
- package/dist/queries/complexity-hotspots.js +3 -3
- package/dist/queries/complexity.d.ts +1 -1
- package/dist/queries/complexity.js +3 -3
- package/dist/queries/convergence.d.ts +1 -1
- package/dist/queries/convergence.js +3 -3
- package/dist/queries/coupling.d.ts +1 -1
- package/dist/queries/coupling.js +3 -3
- package/dist/queries/cycles.d.ts +1 -1
- package/dist/queries/cycles.js +3 -3
- package/dist/queries/dataflow.d.ts +1 -1
- package/dist/queries/dataflow.js +3 -3
- package/dist/queries/dead.d.ts +1 -1
- package/dist/queries/dead.js +4 -4
- package/dist/queries/deep-chains.d.ts +1 -1
- package/dist/queries/deep-chains.js +3 -3
- package/dist/queries/deps.d.ts +1 -1
- package/dist/queries/deps.js +3 -3
- package/dist/queries/diff-impact.d.ts +1 -1
- package/dist/queries/diff-impact.js +2 -2
- package/dist/queries/drift.d.ts +1 -1
- package/dist/queries/drift.js +3 -3
- package/dist/queries/extract-candidates.d.ts +1 -1
- package/dist/queries/extract-candidates.js +3 -3
- package/dist/queries/fan.d.ts +1 -1
- package/dist/queries/fan.js +3 -3
- package/dist/queries/files.d.ts +1 -1
- package/dist/queries/files.js +1 -1
- package/dist/queries/health.d.ts +1 -1
- package/dist/queries/health.js +14 -14
- package/dist/queries/hierarchy.d.ts +1 -1
- package/dist/queries/hierarchy.js +3 -3
- package/dist/queries/hotspots.d.ts +1 -1
- package/dist/queries/hotspots.js +3 -3
- package/dist/queries/imports.d.ts +1 -1
- package/dist/queries/imports.js +3 -3
- package/dist/queries/index.d.ts +1 -1
- package/dist/queries/index.js +46 -46
- package/dist/queries/isolated.d.ts +1 -1
- package/dist/queries/isolated.js +4 -4
- package/dist/queries/members.d.ts +4 -1
- package/dist/queries/members.js +3 -3
- package/dist/queries/methods.d.ts +1 -1
- package/dist/queries/methods.js +3 -3
- package/dist/queries/outline.d.ts +4 -1
- package/dist/queries/outline.js +3 -3
- package/dist/queries/passthrough-candidates.d.ts +1 -1
- package/dist/queries/passthrough-candidates.js +3 -3
- package/dist/queries/redundant-reexports.d.ts +1 -1
- package/dist/queries/redundant-reexports.js +4 -4
- package/dist/queries/refs.d.ts +1 -1
- package/dist/queries/refs.js +3 -3
- package/dist/queries/similar-chains.d.ts +1 -1
- package/dist/queries/similar-chains.js +3 -3
- package/dist/queries/similar-files.d.ts +1 -1
- package/dist/queries/similar-files.js +3 -3
- package/dist/queries/similar-signatures.d.ts +1 -1
- package/dist/queries/similar-signatures.js +3 -3
- package/dist/queries/similar.d.ts +2 -1
- package/dist/queries/similar.js +3 -3
- package/dist/queries/slice.d.ts +4 -3
- package/dist/queries/slice.js +3 -3
- package/dist/queries/stale-abstractions.d.ts +1 -1
- package/dist/queries/stale-abstractions.js +3 -3
- package/dist/queries/stats.d.ts +1 -1
- package/dist/queries/surface.d.ts +1 -1
- package/dist/queries/surface.js +3 -3
- package/dist/queries/symbols.d.ts +1 -1
- package/dist/queries/symbols.js +4 -4
- package/dist/queries/system.d.ts +6 -2
- package/dist/queries/system.js +4 -4
- package/dist/queries/trace.d.ts +1 -1
- package/dist/queries/trace.js +4 -4
- package/dist/queries/wrapper-candidates.d.ts +1 -1
- package/dist/queries/wrapper-candidates.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-5GCORUNV.js +0 -100
- package/dist/chunk-ELFGD5EW.js +0 -130
- package/dist/chunk-GNAMV3JC.js +0 -37
- package/dist/chunk-J6QXMYAQ.js +0 -115
- package/dist/chunk-KYPXKV64.js +0 -51
package/dist/cli.js
CHANGED
|
@@ -20,18 +20,10 @@ var ScipDatabase = class {
|
|
|
20
20
|
this.db = new Database(config.dbPath, { readonly: true });
|
|
21
21
|
this.db.pragma("busy_timeout = 5000");
|
|
22
22
|
}
|
|
23
|
-
/** Attach a gitignore-based path filter for query results */
|
|
24
|
-
setPathFilter(filter) {
|
|
25
|
-
this.pathFilter = filter;
|
|
26
|
-
}
|
|
27
23
|
/** Check if a path should be excluded based on .gitignore rules */
|
|
28
24
|
isIgnored(relativePath) {
|
|
29
25
|
return this.pathFilter?.isIgnored(relativePath) ?? false;
|
|
30
26
|
}
|
|
31
|
-
/** Filter an array of paths using the gitignore filter */
|
|
32
|
-
filterPaths(paths) {
|
|
33
|
-
return this.pathFilter?.filter(paths) ?? paths;
|
|
34
|
-
}
|
|
35
27
|
/**
|
|
36
28
|
* The local-symbol predicate: only match symbols that are defined
|
|
37
29
|
* in files NOT excluded by gitignore. This replaces the old hardcoded
|
|
@@ -1323,10 +1315,6 @@ var Watcher = class {
|
|
|
1323
1315
|
if (this.cooldownTimer) clearTimeout(this.cooldownTimer);
|
|
1324
1316
|
this.setStatus({ state: "idle" });
|
|
1325
1317
|
}
|
|
1326
|
-
/** Get current watcher status */
|
|
1327
|
-
getStatus() {
|
|
1328
|
-
return this.status;
|
|
1329
|
-
}
|
|
1330
1318
|
// ── Internal ─────────────────────────────────────────────
|
|
1331
1319
|
handleFileChange(filename) {
|
|
1332
1320
|
const rel = relative2(this.projectRoot, join7(this.projectRoot, filename));
|
|
@@ -1479,12 +1467,20 @@ function stats(db) {
|
|
|
1479
1467
|
}
|
|
1480
1468
|
|
|
1481
1469
|
// src/queries/files.ts
|
|
1470
|
+
function globToLike(pattern) {
|
|
1471
|
+
const hasGlobChars = /[*?]/.test(pattern);
|
|
1472
|
+
if (!hasGlobChars) {
|
|
1473
|
+
return `%${pattern}%`;
|
|
1474
|
+
}
|
|
1475
|
+
return pattern.replace(/\*\*/g, "%").replace(/\*/g, "%").replace(/\?/g, "_");
|
|
1476
|
+
}
|
|
1482
1477
|
function files(db, pattern) {
|
|
1478
|
+
const likePattern = globToLike(pattern);
|
|
1483
1479
|
const rows = db.all(
|
|
1484
1480
|
`SELECT relative_path FROM documents
|
|
1485
1481
|
WHERE relative_path LIKE ?
|
|
1486
1482
|
ORDER BY relative_path`,
|
|
1487
|
-
|
|
1483
|
+
likePattern
|
|
1488
1484
|
);
|
|
1489
1485
|
return rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({ relativePath: r.relative_path }));
|
|
1490
1486
|
}
|
|
@@ -2539,44 +2535,55 @@ function getCachedMap(cache, db) {
|
|
|
2539
2535
|
function normalizePath(path2) {
|
|
2540
2536
|
return path2.replace(/\\/g, "/");
|
|
2541
2537
|
}
|
|
2538
|
+
var LANGUAGE_EXTENSION_FAMILIES = [
|
|
2539
|
+
SOURCE_EXTENSIONS,
|
|
2540
|
+
PYTHON_SOURCE_EXTENSIONS,
|
|
2541
|
+
JVM_SOURCE_EXTENSIONS,
|
|
2542
|
+
RUST_SOURCE_EXTENSIONS,
|
|
2543
|
+
RUBY_SOURCE_EXTENSIONS,
|
|
2544
|
+
C_LIKE_SOURCE_EXTENSIONS,
|
|
2545
|
+
DOTNET_SOURCE_EXTENSIONS,
|
|
2546
|
+
DART_SOURCE_EXTENSIONS,
|
|
2547
|
+
PHP_SOURCE_EXTENSIONS
|
|
2548
|
+
];
|
|
2549
|
+
function hasExtensionIn(relativePath, extensions) {
|
|
2550
|
+
return extensions.includes(extname3(relativePath).toLowerCase());
|
|
2551
|
+
}
|
|
2542
2552
|
function isJavaScriptSourcePath(relativePath) {
|
|
2543
|
-
return
|
|
2553
|
+
return hasExtensionIn(relativePath, SOURCE_EXTENSIONS);
|
|
2544
2554
|
}
|
|
2545
2555
|
function isPythonSourcePath(relativePath) {
|
|
2546
|
-
return
|
|
2556
|
+
return hasExtensionIn(relativePath, PYTHON_SOURCE_EXTENSIONS);
|
|
2547
2557
|
}
|
|
2548
2558
|
function isJvmSourcePath(relativePath) {
|
|
2549
|
-
return
|
|
2559
|
+
return hasExtensionIn(relativePath, JVM_SOURCE_EXTENSIONS);
|
|
2550
2560
|
}
|
|
2551
2561
|
function isRustSourcePath(relativePath) {
|
|
2552
|
-
return
|
|
2562
|
+
return hasExtensionIn(relativePath, RUST_SOURCE_EXTENSIONS);
|
|
2553
2563
|
}
|
|
2554
2564
|
function isRubySourcePath(relativePath) {
|
|
2555
|
-
return
|
|
2565
|
+
return hasExtensionIn(relativePath, RUBY_SOURCE_EXTENSIONS);
|
|
2556
2566
|
}
|
|
2557
2567
|
function isCLikeSourcePath(relativePath) {
|
|
2558
|
-
return
|
|
2568
|
+
return hasExtensionIn(relativePath, C_LIKE_SOURCE_EXTENSIONS);
|
|
2559
2569
|
}
|
|
2560
2570
|
function isDotNetSourcePath(relativePath) {
|
|
2561
|
-
return
|
|
2571
|
+
return hasExtensionIn(relativePath, DOTNET_SOURCE_EXTENSIONS);
|
|
2562
2572
|
}
|
|
2563
2573
|
function isVisualBasicSourcePath(relativePath) {
|
|
2564
2574
|
return extname3(relativePath).toLowerCase() === ".vb";
|
|
2565
2575
|
}
|
|
2566
2576
|
function isDartSourcePath(relativePath) {
|
|
2567
|
-
return
|
|
2577
|
+
return hasExtensionIn(relativePath, DART_SOURCE_EXTENSIONS);
|
|
2568
2578
|
}
|
|
2569
2579
|
function isPhpSourcePath(relativePath) {
|
|
2570
|
-
return
|
|
2580
|
+
return hasExtensionIn(relativePath, PHP_SOURCE_EXTENSIONS);
|
|
2571
2581
|
}
|
|
2572
2582
|
function extensionFamilyFor(relativePath) {
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
if (isCLikeSourcePath(relativePath)) return C_LIKE_SOURCE_EXTENSIONS;
|
|
2578
|
-
if (isRustSourcePath(relativePath)) return RUST_SOURCE_EXTENSIONS;
|
|
2579
|
-
if (isRubySourcePath(relativePath)) return RUBY_SOURCE_EXTENSIONS;
|
|
2583
|
+
const ext = extname3(relativePath).toLowerCase();
|
|
2584
|
+
for (const family of LANGUAGE_EXTENSION_FAMILIES) {
|
|
2585
|
+
if (family.includes(ext)) return family;
|
|
2586
|
+
}
|
|
2580
2587
|
return SOURCE_EXTENSIONS;
|
|
2581
2588
|
}
|
|
2582
2589
|
function getSourceText(db, relativePath) {
|
|
@@ -2778,6 +2785,9 @@ function leafSuffix(raw) {
|
|
|
2778
2785
|
const last = sym.descriptors[sym.descriptors.length - 1];
|
|
2779
2786
|
return last?.suffix ?? null;
|
|
2780
2787
|
}
|
|
2788
|
+
function isCallableSymbol(raw) {
|
|
2789
|
+
return raw.endsWith("().") || leafSuffix(raw) === "method";
|
|
2790
|
+
}
|
|
2781
2791
|
function isFunctionLikeSymbol(raw) {
|
|
2782
2792
|
const suffix = leafSuffix(raw);
|
|
2783
2793
|
return suffix === "method" || suffix === "term";
|
|
@@ -2822,10 +2832,6 @@ var TEST_FILE_PATTERNS = [
|
|
|
2822
2832
|
var TEST_SUPPORT_PATH_PATTERNS = [
|
|
2823
2833
|
"%/test-utils/%"
|
|
2824
2834
|
];
|
|
2825
|
-
function testFileExclusionSql(alias, extraPatterns = []) {
|
|
2826
|
-
const patterns = uniquePatterns([...TEST_FILE_PATTERNS, ...extraPatterns]);
|
|
2827
|
-
return patterns.map((pattern) => `${alias}.relative_path NOT LIKE '${pattern}'`).join("\n AND ");
|
|
2828
|
-
}
|
|
2829
2835
|
function buildFileDepGraph(db, scope) {
|
|
2830
2836
|
const scopeFilter = scope ? `AND d1.relative_path LIKE '%${scope}%'` : "";
|
|
2831
2837
|
const edges = db.all(
|
|
@@ -2880,6 +2886,8 @@ function findFirstSymbolMatch(db, symbolPattern) {
|
|
|
2880
2886
|
const fileLineMatch = symbolPattern.match(/^(.+):(\d+)-(\d+)$/);
|
|
2881
2887
|
if (fileLineMatch) {
|
|
2882
2888
|
const [, filePath, startStr, endStr] = fileLineMatch;
|
|
2889
|
+
const userStart0 = Math.max(0, parseInt(startStr, 10) - 1);
|
|
2890
|
+
const userEnd0 = Math.max(userStart0, parseInt(endStr, 10) - 1);
|
|
2883
2891
|
let row = db.get(
|
|
2884
2892
|
`SELECT gs.id, gs.symbol, der.document_id, der.start_line, der.end_line, d.relative_path
|
|
2885
2893
|
FROM global_symbols gs
|
|
@@ -2891,8 +2899,8 @@ function findFirstSymbolMatch(db, symbolPattern) {
|
|
|
2891
2899
|
ORDER BY (der.end_line - der.start_line) ASC
|
|
2892
2900
|
LIMIT 1`,
|
|
2893
2901
|
`%${filePath}%`,
|
|
2894
|
-
|
|
2895
|
-
|
|
2902
|
+
userStart0,
|
|
2903
|
+
userEnd0
|
|
2896
2904
|
);
|
|
2897
2905
|
if (!row) {
|
|
2898
2906
|
row = db.get(
|
|
@@ -2909,8 +2917,8 @@ function findFirstSymbolMatch(db, symbolPattern) {
|
|
|
2909
2917
|
ORDER BY (MAX(c.end_line) - MIN(c.start_line)) ASC
|
|
2910
2918
|
LIMIT 1`,
|
|
2911
2919
|
`%${filePath}%`,
|
|
2912
|
-
|
|
2913
|
-
|
|
2920
|
+
userStart0,
|
|
2921
|
+
userEnd0
|
|
2914
2922
|
);
|
|
2915
2923
|
}
|
|
2916
2924
|
if (row && !db.isIgnored(row.relative_path)) {
|
|
@@ -3202,6 +3210,59 @@ function getSourceReferenceSites(db, symbol) {
|
|
|
3202
3210
|
}
|
|
3203
3211
|
return sites;
|
|
3204
3212
|
}
|
|
3213
|
+
function getResolvedReferenceSites(db, symbol) {
|
|
3214
|
+
const match = getFullSymbolMatch(db, symbol);
|
|
3215
|
+
if (!match) {
|
|
3216
|
+
return [];
|
|
3217
|
+
}
|
|
3218
|
+
const rows = db.all(
|
|
3219
|
+
`SELECT DISTINCT d.relative_path, c.start_line, c.end_line
|
|
3220
|
+
FROM mentions m
|
|
3221
|
+
JOIN chunks c ON m.chunk_id = c.id
|
|
3222
|
+
JOIN documents d ON c.document_id = d.id
|
|
3223
|
+
WHERE m.symbol_id = ?
|
|
3224
|
+
AND m.role != 1
|
|
3225
|
+
${db.pathExclusionsFor("d")}
|
|
3226
|
+
ORDER BY d.relative_path, c.start_line`,
|
|
3227
|
+
match.symbolId
|
|
3228
|
+
);
|
|
3229
|
+
const chunksByFile = /* @__PURE__ */ new Map();
|
|
3230
|
+
for (const row of rows) {
|
|
3231
|
+
if (db.isIgnored(row.relative_path)) continue;
|
|
3232
|
+
let bucket = chunksByFile.get(row.relative_path);
|
|
3233
|
+
if (!bucket) {
|
|
3234
|
+
bucket = [];
|
|
3235
|
+
chunksByFile.set(row.relative_path, bucket);
|
|
3236
|
+
}
|
|
3237
|
+
bucket.push({ start_line: row.start_line, end_line: row.end_line });
|
|
3238
|
+
}
|
|
3239
|
+
const identifier = leafName(match.symbol);
|
|
3240
|
+
const sites = [];
|
|
3241
|
+
const seen = /* @__PURE__ */ new Set();
|
|
3242
|
+
for (const [file, chunks] of chunksByFile) {
|
|
3243
|
+
const definitions = getDefinitionsForFile(db, file);
|
|
3244
|
+
const excludeOpts = file === match.relativePath ? { excludeStartLine: match.startLine, excludeEndLine: match.endLine } : {};
|
|
3245
|
+
const allHits = identifier ? findIdentifierLines(db, file, identifier, excludeOpts) : [];
|
|
3246
|
+
for (const chunk of chunks) {
|
|
3247
|
+
const hitsInChunk = allHits.filter(
|
|
3248
|
+
(line) => line >= chunk.start_line && line <= chunk.end_line
|
|
3249
|
+
);
|
|
3250
|
+
const lines = hitsInChunk.length > 0 ? hitsInChunk : [chunk.start_line];
|
|
3251
|
+
for (const line of lines) {
|
|
3252
|
+
const enclosing = findEnclosingDefinition(definitions, line);
|
|
3253
|
+
const key = `${file}|${line}|${enclosing?.symbol ?? ""}`;
|
|
3254
|
+
if (seen.has(key)) continue;
|
|
3255
|
+
seen.add(key);
|
|
3256
|
+
sites.push({
|
|
3257
|
+
file,
|
|
3258
|
+
line,
|
|
3259
|
+
enclosingSymbol: enclosing?.symbol ?? null
|
|
3260
|
+
});
|
|
3261
|
+
}
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
return sites;
|
|
3265
|
+
}
|
|
3205
3266
|
function calleeQueryParams(symbol, limit) {
|
|
3206
3267
|
const params = [
|
|
3207
3268
|
symbol.documentId,
|
|
@@ -3231,56 +3292,41 @@ function findEnclosingDefinition(definitions, line) {
|
|
|
3231
3292
|
}
|
|
3232
3293
|
return best;
|
|
3233
3294
|
}
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
}
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
)
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3269
|
-
if (seen.has(key)) continue;
|
|
3270
|
-
seen.add(key);
|
|
3271
|
-
rows.push({
|
|
3272
|
-
symbol: resolved.symbol,
|
|
3273
|
-
file: resolved.relativePath,
|
|
3274
|
-
chunkId
|
|
3275
|
-
});
|
|
3276
|
-
}
|
|
3277
|
-
return applyLimit(rows, limit);
|
|
3278
|
-
}
|
|
3279
|
-
function getJavaScriptSourceCalleeRows(db, symbol, limit) {
|
|
3280
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3281
|
-
if (!match || !isJavaScriptDocument(db, match.relativePath)) {
|
|
3282
|
-
return [];
|
|
3283
|
-
}
|
|
3295
|
+
var LANGUAGE_CALLEE_CONFIGS = [
|
|
3296
|
+
// Python (index 0) — complex resolver
|
|
3297
|
+
{ kind: "complex", languageIndex: 0, resolver: resolvePythonCallTarget },
|
|
3298
|
+
// JavaScript/TypeScript (index 1) — complex resolver
|
|
3299
|
+
{ kind: "complex", languageIndex: 1, resolver: resolveJavaScriptCallTarget },
|
|
3300
|
+
// Java (index 2) — simple with field bindings
|
|
3301
|
+
{ kind: "simple", languageIndex: 2, parseBindings: (_db, source) => parseJavaFieldBindings(source) },
|
|
3302
|
+
// Kotlin (index 3) — simple with field bindings
|
|
3303
|
+
{ kind: "simple", languageIndex: 3, parseBindings: (_db, source) => parseKotlinFieldBindings(source) },
|
|
3304
|
+
// Scala (index 4) — simple, no bindings
|
|
3305
|
+
{ kind: "simple", languageIndex: 4, parseBindings: null },
|
|
3306
|
+
// C# (index 5) — simple, no bindings
|
|
3307
|
+
{ kind: "simple", languageIndex: 5, parseBindings: null },
|
|
3308
|
+
// Visual Basic (index 6) — simple, no bindings
|
|
3309
|
+
{ kind: "simple", languageIndex: 6, parseBindings: null },
|
|
3310
|
+
// C++ (index 7) — simple with receiver bindings
|
|
3311
|
+
{ kind: "simple", languageIndex: 7, parseBindings: (_db, source) => parseCppReceiverBindings(source) },
|
|
3312
|
+
// Rust (index 8) — simple, no bindings
|
|
3313
|
+
{ kind: "simple", languageIndex: 8, parseBindings: null },
|
|
3314
|
+
// Ruby (index 9) — simple with dual-attempt logic
|
|
3315
|
+
{
|
|
3316
|
+
kind: "simple",
|
|
3317
|
+
languageIndex: 9,
|
|
3318
|
+
parseBindings: (db, source) => parseRubyReceiverBindings(db, source),
|
|
3319
|
+
dualAttempt: {
|
|
3320
|
+
baseOpts: { allowInstanceVariables: true },
|
|
3321
|
+
extendedOpts: { allowInstanceVariables: true, allowBareMemberCalls: true }
|
|
3322
|
+
}
|
|
3323
|
+
},
|
|
3324
|
+
// Dart (index 10) — simple, no bindings
|
|
3325
|
+
{ kind: "simple", languageIndex: 10, parseBindings: null },
|
|
3326
|
+
// PHP (index 11) — simple, no bindings
|
|
3327
|
+
{ kind: "simple", languageIndex: 11, parseBindings: null }
|
|
3328
|
+
];
|
|
3329
|
+
function getComplexSourceCalleeRows(db, match, config, limit) {
|
|
3284
3330
|
const definitions = getDefinitionsForFile(db, match.relativePath);
|
|
3285
3331
|
const current = definitions.find((definition) => definition.symbolId === match.symbolId);
|
|
3286
3332
|
if (!current) {
|
|
@@ -3299,7 +3345,7 @@ function getJavaScriptSourceCalleeRows(db, symbol, limit) {
|
|
|
3299
3345
|
startLine: match.startLine,
|
|
3300
3346
|
endLine: match.endLine
|
|
3301
3347
|
})) {
|
|
3302
|
-
const resolved =
|
|
3348
|
+
const resolved = config.resolver(
|
|
3303
3349
|
db,
|
|
3304
3350
|
current,
|
|
3305
3351
|
definitions,
|
|
@@ -3321,134 +3367,31 @@ function getJavaScriptSourceCalleeRows(db, symbol, limit) {
|
|
|
3321
3367
|
}
|
|
3322
3368
|
return applyLimit(rows, limit);
|
|
3323
3369
|
}
|
|
3324
|
-
function
|
|
3325
|
-
|
|
3326
|
-
if (
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
}
|
|
3333
|
-
function getKotlinSourceCalleeRows(db, symbol, limit) {
|
|
3334
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3335
|
-
if (!match || !isKotlinDocument(db, match.relativePath)) {
|
|
3336
|
-
return [];
|
|
3337
|
-
}
|
|
3338
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine);
|
|
3339
|
-
const bindings = parseKotlinFieldBindings(getSourceText(db, match.relativePath));
|
|
3340
|
-
return resolveSimpleSourceCallees(db, match, calls, bindings, limit);
|
|
3341
|
-
}
|
|
3342
|
-
function getScalaSourceCalleeRows(db, symbol, limit) {
|
|
3343
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3344
|
-
if (!match || !isScalaDocument(db, match.relativePath)) {
|
|
3345
|
-
return [];
|
|
3346
|
-
}
|
|
3347
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine);
|
|
3348
|
-
return resolveSimpleSourceCallees(db, match, calls, /* @__PURE__ */ new Map(), limit);
|
|
3349
|
-
}
|
|
3350
|
-
function getCSharpSourceCalleeRows(db, symbol, limit) {
|
|
3351
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3352
|
-
if (!match || !isCSharpDocument(db, match.relativePath)) {
|
|
3353
|
-
return [];
|
|
3354
|
-
}
|
|
3355
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine);
|
|
3356
|
-
return resolveSimpleSourceCallees(db, match, calls, /* @__PURE__ */ new Map(), limit);
|
|
3357
|
-
}
|
|
3358
|
-
function getVisualBasicSourceCalleeRows(db, symbol, limit) {
|
|
3359
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3360
|
-
if (!match || !isVisualBasicDocument(db, match.relativePath)) {
|
|
3361
|
-
return [];
|
|
3362
|
-
}
|
|
3363
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine);
|
|
3364
|
-
return resolveSimpleSourceCallees(db, match, calls, /* @__PURE__ */ new Map(), limit);
|
|
3365
|
-
}
|
|
3366
|
-
function getCppSourceCalleeRows(db, symbol, limit) {
|
|
3367
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3368
|
-
if (!match || !isCppDocument(db, match.relativePath)) {
|
|
3369
|
-
return [];
|
|
3370
|
+
function getSimpleLanguageCalleeRows(db, match, config, limit) {
|
|
3371
|
+
let calls;
|
|
3372
|
+
if (config.dualAttempt) {
|
|
3373
|
+
const baseCalls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine, config.dualAttempt.baseOpts);
|
|
3374
|
+
const extendedCalls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine, config.dualAttempt.extendedOpts);
|
|
3375
|
+
calls = extendedCalls.length > 0 ? extendedCalls : baseCalls;
|
|
3376
|
+
} else {
|
|
3377
|
+
calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine, config.sourceCallOpts);
|
|
3370
3378
|
}
|
|
3371
|
-
const
|
|
3372
|
-
const bindings = parseCppReceiverBindings(getSourceText(db, match.relativePath));
|
|
3379
|
+
const bindings = config.parseBindings ? config.parseBindings(db, getSourceText(db, match.relativePath)) : /* @__PURE__ */ new Map();
|
|
3373
3380
|
return resolveSimpleSourceCallees(db, match, calls, bindings, limit);
|
|
3374
3381
|
}
|
|
3375
|
-
function getRustSourceCalleeRows(db, symbol, limit) {
|
|
3376
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3377
|
-
if (!match || !isRustDocument(db, match.relativePath)) {
|
|
3378
|
-
return [];
|
|
3379
|
-
}
|
|
3380
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine);
|
|
3381
|
-
return resolveSimpleSourceCallees(db, match, calls, /* @__PURE__ */ new Map(), limit);
|
|
3382
|
-
}
|
|
3383
|
-
function getRubySourceCalleeRows(db, symbol, limit) {
|
|
3384
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3385
|
-
if (!match || !isRubyDocument(db, match.relativePath)) {
|
|
3386
|
-
return [];
|
|
3387
|
-
}
|
|
3388
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine, { allowInstanceVariables: true });
|
|
3389
|
-
const rubyCalls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine, {
|
|
3390
|
-
allowInstanceVariables: true,
|
|
3391
|
-
allowBareMemberCalls: true
|
|
3392
|
-
});
|
|
3393
|
-
const bindings = parseRubyReceiverBindings(db, getSourceText(db, match.relativePath));
|
|
3394
|
-
return resolveSimpleSourceCallees(db, match, rubyCalls.length > 0 ? rubyCalls : calls, bindings, limit);
|
|
3395
|
-
}
|
|
3396
|
-
function getDartSourceCalleeRows(db, symbol, limit) {
|
|
3397
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3398
|
-
if (!match || !isDartDocument(db, match.relativePath)) {
|
|
3399
|
-
return [];
|
|
3400
|
-
}
|
|
3401
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine);
|
|
3402
|
-
return resolveSimpleSourceCallees(db, match, calls, /* @__PURE__ */ new Map(), limit);
|
|
3403
|
-
}
|
|
3404
|
-
function getPhpSourceCalleeRows(db, symbol, limit) {
|
|
3405
|
-
const match = getFullSymbolMatch(db, symbol);
|
|
3406
|
-
if (!match || !isPhpDocument(db, match.relativePath)) {
|
|
3407
|
-
return [];
|
|
3408
|
-
}
|
|
3409
|
-
const calls = getSimpleSourceCalls(db, match.relativePath, match.startLine, match.endLine);
|
|
3410
|
-
return resolveSimpleSourceCallees(db, match, calls, /* @__PURE__ */ new Map(), limit);
|
|
3411
|
-
}
|
|
3412
3382
|
function getSourceBackedCalleeRows(db, symbol, limit) {
|
|
3413
3383
|
const match = getFullSymbolMatch(db, symbol);
|
|
3414
3384
|
if (!match) {
|
|
3415
3385
|
return [];
|
|
3416
3386
|
}
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
return
|
|
3425
|
-
}
|
|
3426
|
-
if (isScalaDocument(db, match.relativePath)) {
|
|
3427
|
-
return getScalaSourceCalleeRows(db, match, limit);
|
|
3428
|
-
}
|
|
3429
|
-
if (isKotlinDocument(db, match.relativePath)) {
|
|
3430
|
-
return getKotlinSourceCalleeRows(db, match, limit);
|
|
3431
|
-
}
|
|
3432
|
-
if (isCSharpDocument(db, match.relativePath)) {
|
|
3433
|
-
return getCSharpSourceCalleeRows(db, match, limit);
|
|
3434
|
-
}
|
|
3435
|
-
if (isVisualBasicDocument(db, match.relativePath)) {
|
|
3436
|
-
return getVisualBasicSourceCalleeRows(db, match, limit);
|
|
3437
|
-
}
|
|
3438
|
-
if (isCppDocument(db, match.relativePath)) {
|
|
3439
|
-
return getCppSourceCalleeRows(db, match, limit);
|
|
3440
|
-
}
|
|
3441
|
-
if (isRustDocument(db, match.relativePath)) {
|
|
3442
|
-
return getRustSourceCalleeRows(db, match, limit);
|
|
3443
|
-
}
|
|
3444
|
-
if (isRubyDocument(db, match.relativePath)) {
|
|
3445
|
-
return getRubySourceCalleeRows(db, match, limit);
|
|
3446
|
-
}
|
|
3447
|
-
if (isDartDocument(db, match.relativePath)) {
|
|
3448
|
-
return getDartSourceCalleeRows(db, match, limit);
|
|
3449
|
-
}
|
|
3450
|
-
if (isPhpDocument(db, match.relativePath)) {
|
|
3451
|
-
return getPhpSourceCalleeRows(db, match, limit);
|
|
3387
|
+
for (const config of LANGUAGE_CALLEE_CONFIGS) {
|
|
3388
|
+
if (!isDocumentLanguage(db, match.relativePath, DOCUMENT_LANGUAGE_TABLE[config.languageIndex])) {
|
|
3389
|
+
continue;
|
|
3390
|
+
}
|
|
3391
|
+
if (config.kind === "complex") {
|
|
3392
|
+
return getComplexSourceCalleeRows(db, match, config, limit);
|
|
3393
|
+
}
|
|
3394
|
+
return getSimpleLanguageCalleeRows(db, match, config, limit);
|
|
3452
3395
|
}
|
|
3453
3396
|
return [];
|
|
3454
3397
|
}
|
|
@@ -3458,9 +3401,11 @@ function getPythonSourceCallerRows(db, target, limit) {
|
|
|
3458
3401
|
}
|
|
3459
3402
|
const rows = [];
|
|
3460
3403
|
const seen = /* @__PURE__ */ new Set();
|
|
3404
|
+
const pythonConfig = LANGUAGE_CALLEE_CONFIGS[0];
|
|
3461
3405
|
for (const candidate of getAllFunctionLikeDefinitions(db)) {
|
|
3462
3406
|
if (candidate.symbolId === target.symbolId) continue;
|
|
3463
|
-
|
|
3407
|
+
if (!isDocumentLanguage(db, candidate.relativePath, DOCUMENT_LANGUAGE_TABLE[pythonConfig.languageIndex])) continue;
|
|
3408
|
+
const callees = getComplexSourceCalleeRows(db, candidate, pythonConfig);
|
|
3464
3409
|
if (!callees.some((callee) => callee.symbol === target.symbol)) continue;
|
|
3465
3410
|
const key = `${candidate.symbol}|${candidate.relativePath}`;
|
|
3466
3411
|
if (seen.has(key) || db.isIgnored(candidate.relativePath)) continue;
|
|
@@ -3683,7 +3628,16 @@ function resolveCallableDefinitionStartLine(lines, definition) {
|
|
|
3683
3628
|
const escapedLeaf = escapeRegex2(definition.leaf);
|
|
3684
3629
|
const strongPatterns = [
|
|
3685
3630
|
new RegExp(`\\b(?:function|def|fn)\\s+${escapedLeaf}\\b`),
|
|
3686
|
-
new RegExp(`\\b${escapedLeaf}\\b\\s*[:=]\\s*(?:async\\s*)?(?:function\\b|\\()`)
|
|
3631
|
+
new RegExp(`\\b${escapedLeaf}\\b\\s*[:=]\\s*(?:async\\s*)?(?:function\\b|\\()`),
|
|
3632
|
+
// Method/function declaration with optional TypeScript generic
|
|
3633
|
+
// parameters: matches `foo(`, `foo<T>(`, `foo<T = Record<string, unknown>>(`.
|
|
3634
|
+
// `[^(]*` with greedy backtracking handles nested generics as long as
|
|
3635
|
+
// the generic block itself doesn't contain a `(`. Anchored to start of
|
|
3636
|
+
// line content (optional leading whitespace + optional access modifiers)
|
|
3637
|
+
// so it prefers the declaration line over call sites.
|
|
3638
|
+
new RegExp(
|
|
3639
|
+
`^\\s*(?:export\\s+|public\\s+|private\\s+|protected\\s+|static\\s+|readonly\\s+|async\\s+|abstract\\s+|get\\s+|set\\s+)*${escapedLeaf}\\s*(?:<[^(]*>)?\\s*\\(`
|
|
3640
|
+
)
|
|
3687
3641
|
];
|
|
3688
3642
|
const fallbackPatterns = [
|
|
3689
3643
|
new RegExp(`\\b${escapedLeaf}\\b\\s*\\(`)
|
|
@@ -3802,6 +3756,17 @@ function getAllDefinitions(db, opts = {}) {
|
|
|
3802
3756
|
);
|
|
3803
3757
|
return rows.filter((row) => !db.isIgnored(row.relative_path)).flatMap((row) => getDefinitionsForFile(db, row.relative_path));
|
|
3804
3758
|
}
|
|
3759
|
+
function getScopedDefinitions(db, scope) {
|
|
3760
|
+
const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
|
|
3761
|
+
return db.all(
|
|
3762
|
+
`SELECT relative_path
|
|
3763
|
+
FROM documents
|
|
3764
|
+
WHERE 1 = 1
|
|
3765
|
+
${db.pathExclusionsFor("documents")}
|
|
3766
|
+
${scopeFilter}
|
|
3767
|
+
ORDER BY relative_path`
|
|
3768
|
+
).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
|
|
3769
|
+
}
|
|
3805
3770
|
function getAllFunctionLikeDefinitions(db) {
|
|
3806
3771
|
return getAllDefinitions(db).filter((definition) => definition.isFunctionLike);
|
|
3807
3772
|
}
|
|
@@ -4219,89 +4184,29 @@ function parentTypeName(rawSymbol) {
|
|
|
4219
4184
|
}
|
|
4220
4185
|
return null;
|
|
4221
4186
|
}
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
)
|
|
4227
|
-
|
|
4228
|
-
}
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
function
|
|
4237
|
-
const row = db.get(
|
|
4238
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4239
|
-
relativePath
|
|
4240
|
-
);
|
|
4241
|
-
return row?.language === "java" || relativePath.endsWith(".java");
|
|
4242
|
-
}
|
|
4243
|
-
function isKotlinDocument(db, relativePath) {
|
|
4244
|
-
const row = db.get(
|
|
4245
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4246
|
-
relativePath
|
|
4247
|
-
);
|
|
4248
|
-
return row?.language === "kotlin" || relativePath.endsWith(".kt") || relativePath.endsWith(".kts");
|
|
4249
|
-
}
|
|
4250
|
-
function isScalaDocument(db, relativePath) {
|
|
4251
|
-
const row = db.get(
|
|
4252
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4253
|
-
relativePath
|
|
4254
|
-
);
|
|
4255
|
-
return row?.language === "scala" || relativePath.endsWith(".scala");
|
|
4256
|
-
}
|
|
4257
|
-
function isCSharpDocument(db, relativePath) {
|
|
4258
|
-
const row = db.get(
|
|
4259
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4260
|
-
relativePath
|
|
4261
|
-
);
|
|
4262
|
-
return row?.language === "C#" || relativePath.endsWith(".cs");
|
|
4263
|
-
}
|
|
4264
|
-
function isVisualBasicDocument(db, relativePath) {
|
|
4265
|
-
const row = db.get(
|
|
4266
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4267
|
-
relativePath
|
|
4268
|
-
);
|
|
4269
|
-
return row?.language === "Visual Basic" || relativePath.endsWith(".vb");
|
|
4270
|
-
}
|
|
4271
|
-
function isCppDocument(db, relativePath) {
|
|
4272
|
-
const row = db.get(
|
|
4273
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4274
|
-
relativePath
|
|
4275
|
-
);
|
|
4276
|
-
return row?.language === "CPP" || /\.(?:cc|cpp|cxx|hpp|hh|hxx)$/.test(relativePath);
|
|
4277
|
-
}
|
|
4278
|
-
function isRustDocument(db, relativePath) {
|
|
4279
|
-
const row = db.get(
|
|
4280
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4281
|
-
relativePath
|
|
4282
|
-
);
|
|
4283
|
-
return row?.language === "Rust" || relativePath.endsWith(".rs");
|
|
4284
|
-
}
|
|
4285
|
-
function isRubyDocument(db, relativePath) {
|
|
4286
|
-
const row = db.get(
|
|
4287
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4288
|
-
relativePath
|
|
4289
|
-
);
|
|
4290
|
-
return row?.language === "ruby" || relativePath.endsWith(".rb");
|
|
4291
|
-
}
|
|
4292
|
-
function isDartDocument(db, relativePath) {
|
|
4187
|
+
var DOCUMENT_LANGUAGE_TABLE = [
|
|
4188
|
+
{ languages: ["python"], extensionPattern: /\.(?:py|pyi)$/ },
|
|
4189
|
+
{ languages: ["typescript", "javascript"], extensionPattern: /\.(?:[cm]?[jt]sx?)$/ },
|
|
4190
|
+
{ languages: ["java"], extensionPattern: /\.java$/ },
|
|
4191
|
+
{ languages: ["kotlin"], extensionPattern: /\.(?:kt|kts)$/ },
|
|
4192
|
+
{ languages: ["scala"], extensionPattern: /\.scala$/ },
|
|
4193
|
+
{ languages: ["C#"], extensionPattern: /\.cs$/ },
|
|
4194
|
+
{ languages: ["Visual Basic"], extensionPattern: /\.vb$/ },
|
|
4195
|
+
{ languages: ["CPP"], extensionPattern: /\.(?:cc|cpp|cxx|hpp|hh|hxx)$/ },
|
|
4196
|
+
{ languages: ["Rust"], extensionPattern: /\.rs$/ },
|
|
4197
|
+
{ languages: ["ruby"], extensionPattern: /\.rb$/ },
|
|
4198
|
+
{ languages: ["Dart"], extensionPattern: /\.dart$/ },
|
|
4199
|
+
{ languages: ["PHP"], extensionPattern: /\.php$/ }
|
|
4200
|
+
];
|
|
4201
|
+
function isDocumentLanguage(db, relativePath, entry) {
|
|
4293
4202
|
const row = db.get(
|
|
4294
4203
|
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4295
4204
|
relativePath
|
|
4296
4205
|
);
|
|
4297
|
-
return row?.language
|
|
4206
|
+
return entry.languages.includes(row?.language ?? "") || entry.extensionPattern.test(relativePath);
|
|
4298
4207
|
}
|
|
4299
|
-
function
|
|
4300
|
-
|
|
4301
|
-
`SELECT language FROM documents WHERE relative_path = ? LIMIT 1`,
|
|
4302
|
-
relativePath
|
|
4303
|
-
);
|
|
4304
|
-
return row?.language === "PHP" || relativePath.endsWith(".php");
|
|
4208
|
+
function isPythonDocument(db, relativePath) {
|
|
4209
|
+
return isDocumentLanguage(db, relativePath, DOCUMENT_LANGUAGE_TABLE[0]);
|
|
4305
4210
|
}
|
|
4306
4211
|
function applyLimit(values, limit) {
|
|
4307
4212
|
return typeof limit === "number" ? values.slice(0, limit) : values;
|
|
@@ -4353,15 +4258,18 @@ function scoreDocumentPath(relativePath, rawPattern) {
|
|
|
4353
4258
|
function normalizeLookupPath(filePattern) {
|
|
4354
4259
|
return filePattern.trim().replace(/\\/g, "/").replace(/^\.\//, "").replace(/^\/+/, "").replace(/\/+$/, "");
|
|
4355
4260
|
}
|
|
4356
|
-
function uniquePatterns(patterns) {
|
|
4357
|
-
return [...new Set(patterns)];
|
|
4358
|
-
}
|
|
4359
4261
|
|
|
4360
4262
|
// src/queries/clean-signature.ts
|
|
4361
4263
|
function cleanSignature(sig) {
|
|
4362
4264
|
if (!sig || !sig.trim()) return null;
|
|
4363
4265
|
return sig.replace(/^```\w*\s*/, "").replace(/\s*```$/, "").replace(/^\(method\)\s*/, "").replace(/^\(property\)\s*/, "").replace(/^\(function\)\s*/, "").replace(/^\(class\)\s*/, "").replace(/^\(interface\)\s*/, "").replace(/^\(enum\)\s*/, "").replace(/^\(type alias\)\s*/, "").replace(/^\(const\)\s*/, "").replace(/^\(var\)\s*/, "").trim() || null;
|
|
4364
4266
|
}
|
|
4267
|
+
function extractSignature(doc) {
|
|
4268
|
+
if (!doc) return null;
|
|
4269
|
+
const pipeIdx = doc.indexOf("|");
|
|
4270
|
+
if (pipeIdx === -1) return doc.replace(/\n/g, " ");
|
|
4271
|
+
return doc.slice(pipeIdx + 1).replace(/\n/g, " ");
|
|
4272
|
+
}
|
|
4365
4273
|
|
|
4366
4274
|
// src/queries/symbols.ts
|
|
4367
4275
|
function symbols(db, filePattern) {
|
|
@@ -4371,9 +4279,7 @@ function symbols(db, filePattern) {
|
|
|
4371
4279
|
}
|
|
4372
4280
|
return resolvedPaths.flatMap((relativePath) => getDefinitionsForFile(db, relativePath)).filter((row) => !db.isIgnored(row.relativePath)).map((row) => {
|
|
4373
4281
|
const docRow = db.get(
|
|
4374
|
-
|
|
4375
|
-
FROM global_symbols
|
|
4376
|
-
WHERE id = ?`,
|
|
4282
|
+
"SELECT documentation FROM global_symbols WHERE id = ?",
|
|
4377
4283
|
row.symbolId
|
|
4378
4284
|
);
|
|
4379
4285
|
return {
|
|
@@ -4381,7 +4287,7 @@ function symbols(db, filePattern) {
|
|
|
4381
4287
|
endLine: row.endLine,
|
|
4382
4288
|
symbol: row.symbol,
|
|
4383
4289
|
shortName: shortenSymbol(row.symbol),
|
|
4384
|
-
signature: cleanSignature(docRow?.
|
|
4290
|
+
signature: cleanSignature(extractSignature(docRow?.documentation ?? null))
|
|
4385
4291
|
};
|
|
4386
4292
|
});
|
|
4387
4293
|
}
|
|
@@ -4403,9 +4309,6 @@ function methods(db, className) {
|
|
|
4403
4309
|
name: leafName(definition.symbol)
|
|
4404
4310
|
}));
|
|
4405
4311
|
}
|
|
4406
|
-
function isCallableSymbol(rawSymbol) {
|
|
4407
|
-
return rawSymbol.endsWith("().") || leafSuffix(rawSymbol) === "method";
|
|
4408
|
-
}
|
|
4409
4312
|
function stripExtension(relativePath) {
|
|
4410
4313
|
return relativePath.replace(/\.[^.]+$/, "");
|
|
4411
4314
|
}
|
|
@@ -4413,60 +4316,21 @@ function stripExtension(relativePath) {
|
|
|
4413
4316
|
// src/queries/refs.ts
|
|
4414
4317
|
function refs(db, symbolPattern) {
|
|
4415
4318
|
const match = findFirstSymbolMatch(db, symbolPattern);
|
|
4416
|
-
if (match)
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
}));
|
|
4426
|
-
if (sourceSites.length > 0) {
|
|
4427
|
-
const seen2 = /* @__PURE__ */ new Set();
|
|
4428
|
-
const rows2 = [...definitionRows, ...sourceSites, ...getRubySemanticRefs(db, match)].filter((site) => {
|
|
4429
|
-
const key = `${site.relativePath}:${site.line}`;
|
|
4430
|
-
if (seen2.has(key)) return false;
|
|
4431
|
-
seen2.add(key);
|
|
4432
|
-
return true;
|
|
4433
|
-
});
|
|
4434
|
-
return rows2;
|
|
4435
|
-
}
|
|
4436
|
-
}
|
|
4437
|
-
const rows = db.all(
|
|
4438
|
-
`SELECT DISTINCT d.relative_path, c.start_line
|
|
4439
|
-
FROM mentions m
|
|
4440
|
-
JOIN chunks c ON m.chunk_id = c.id
|
|
4441
|
-
JOIN documents d ON c.document_id = d.id
|
|
4442
|
-
JOIN global_symbols gs ON m.symbol_id = gs.id
|
|
4443
|
-
WHERE m.symbol_id = ?
|
|
4444
|
-
AND ${db.localSymbolPredicate}
|
|
4445
|
-
AND m.role != 1
|
|
4446
|
-
ORDER BY d.relative_path, c.start_line`,
|
|
4447
|
-
match?.symbolId ?? -1
|
|
4448
|
-
);
|
|
4449
|
-
const referenceRows = rows.filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
|
|
4450
|
-
relativePath: r.relative_path,
|
|
4451
|
-
line: r.start_line
|
|
4452
|
-
}));
|
|
4453
|
-
if (!match || db.isIgnored(match.relativePath) || isFunctionLikeSymbol(match.symbol)) {
|
|
4454
|
-
return referenceRows;
|
|
4455
|
-
}
|
|
4456
|
-
const seen = new Set(referenceRows.map((row) => `${row.relativePath}:${row.line}`));
|
|
4457
|
-
if (!seen.has(`${match.relativePath}:${match.startLine}`)) {
|
|
4458
|
-
referenceRows.unshift({
|
|
4459
|
-
relativePath: match.relativePath,
|
|
4460
|
-
line: match.startLine
|
|
4461
|
-
});
|
|
4462
|
-
}
|
|
4463
|
-
for (const row of getRubySemanticRefs(db, match)) {
|
|
4319
|
+
if (!match) return [];
|
|
4320
|
+
const includeDefinitionSite = !isFunctionLikeSymbol(match.symbol);
|
|
4321
|
+
const definitionRows = includeDefinitionSite && !db.isIgnored(match.relativePath) ? [{ relativePath: match.relativePath, line: match.startLine }] : [];
|
|
4322
|
+
const sourceSites = getSourceReferenceSites(db, match);
|
|
4323
|
+
const referenceSites = (sourceSites.length > 0 ? sourceSites : getResolvedReferenceSites(db, match)).filter((site) => !db.isIgnored(site.file)).map((site) => ({ relativePath: site.file, line: site.line }));
|
|
4324
|
+
const rubySites = getRubySemanticRefs(db, match);
|
|
4325
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4326
|
+
const out = [];
|
|
4327
|
+
for (const row of [...definitionRows, ...referenceSites, ...rubySites]) {
|
|
4464
4328
|
const key = `${row.relativePath}:${row.line}`;
|
|
4465
4329
|
if (seen.has(key)) continue;
|
|
4466
4330
|
seen.add(key);
|
|
4467
|
-
|
|
4331
|
+
out.push(row);
|
|
4468
4332
|
}
|
|
4469
|
-
return
|
|
4333
|
+
return out;
|
|
4470
4334
|
}
|
|
4471
4335
|
function getRubySemanticRefs(db, match) {
|
|
4472
4336
|
if (!match.relativePath.endsWith(".rb")) {
|
|
@@ -4519,50 +4383,24 @@ function trace(db, symbolPattern) {
|
|
|
4519
4383
|
return { definitions: [], referencedBy: [] };
|
|
4520
4384
|
}
|
|
4521
4385
|
const definitionMeta = db.get(
|
|
4522
|
-
|
|
4523
|
-
gs.display_name,
|
|
4524
|
-
REPLACE(SUBSTR(gs.documentation, INSTR(gs.documentation, '|') + 1), char(10), ' ') AS sig
|
|
4525
|
-
FROM global_symbols gs
|
|
4526
|
-
WHERE gs.id = ?
|
|
4527
|
-
LIMIT 10`,
|
|
4386
|
+
"SELECT display_name, documentation FROM global_symbols WHERE id = ?",
|
|
4528
4387
|
match.symbolId
|
|
4529
4388
|
);
|
|
4389
|
+
const sig = extractSignature(definitionMeta?.documentation ?? null);
|
|
4530
4390
|
const definitions = db.isIgnored(match.relativePath) ? [] : [{
|
|
4531
4391
|
relativePath: match.relativePath,
|
|
4532
4392
|
startLine: match.startLine,
|
|
4533
4393
|
endLine: match.endLine,
|
|
4534
|
-
signature: buildTraceSignature(
|
|
4394
|
+
signature: buildTraceSignature(sig, definitionMeta?.display_name ?? null, match.symbol),
|
|
4535
4395
|
source: definitionSource(db, match.relativePath, match.startLine, match.endLine)
|
|
4536
4396
|
}];
|
|
4537
4397
|
const sourceSites = getSourceReferenceSites(db, match);
|
|
4538
|
-
const
|
|
4398
|
+
const resolvedSites = sourceSites.length > 0 ? sourceSites : getResolvedReferenceSites(db, match);
|
|
4399
|
+
const referencedBy = resolvedSites.filter((site) => !db.isIgnored(site.file)).map((site) => ({
|
|
4539
4400
|
relativePath: site.file,
|
|
4540
4401
|
line: site.line,
|
|
4541
4402
|
enclosingSymbol: site.enclosingSymbol,
|
|
4542
4403
|
enclosingShort: site.enclosingSymbol ? shortenSymbol(site.enclosingSymbol) : "(top-level)"
|
|
4543
|
-
})) : db.all(
|
|
4544
|
-
`SELECT DISTINCT d.relative_path, c.start_line AS line,
|
|
4545
|
-
(SELECT enc_gs.symbol
|
|
4546
|
-
FROM defn_enclosing_ranges enc_der
|
|
4547
|
-
JOIN global_symbols enc_gs ON enc_der.symbol_id = enc_gs.id
|
|
4548
|
-
WHERE enc_der.document_id = d.id
|
|
4549
|
-
AND enc_der.start_line <= c.start_line
|
|
4550
|
-
AND enc_der.end_line >= c.end_line
|
|
4551
|
-
ORDER BY (enc_der.end_line - enc_der.start_line) ASC
|
|
4552
|
-
LIMIT 1
|
|
4553
|
-
) AS enclosing_symbol
|
|
4554
|
-
FROM mentions m
|
|
4555
|
-
JOIN chunks c ON m.chunk_id = c.id
|
|
4556
|
-
JOIN documents d ON c.document_id = d.id
|
|
4557
|
-
WHERE m.symbol_id = ?
|
|
4558
|
-
AND m.role != 1
|
|
4559
|
-
ORDER BY d.relative_path, c.start_line`,
|
|
4560
|
-
match.symbolId
|
|
4561
|
-
).filter((r) => !db.isIgnored(r.relative_path)).map((r) => ({
|
|
4562
|
-
relativePath: r.relative_path,
|
|
4563
|
-
line: r.line,
|
|
4564
|
-
enclosingSymbol: r.enclosing_symbol,
|
|
4565
|
-
enclosingShort: r.enclosing_symbol ? shortenSymbol(r.enclosing_symbol) : "(top-level)"
|
|
4566
4404
|
}));
|
|
4567
4405
|
return { definitions, referencedBy };
|
|
4568
4406
|
}
|
|
@@ -4648,26 +4486,18 @@ function system(db, modulePattern) {
|
|
|
4648
4486
|
...matchedPaths
|
|
4649
4487
|
);
|
|
4650
4488
|
const files2 = fileRows.map((r) => r.relative_path).filter((p) => !db.isIgnored(p));
|
|
4651
|
-
const
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
);
|
|
4664
|
-
const symbols2 = symbolRows.map((r) => ({
|
|
4665
|
-
startLine: r.start_line,
|
|
4666
|
-
endLine: r.end_line,
|
|
4667
|
-
symbol: r.symbol,
|
|
4668
|
-
shortName: shortenSymbol(r.symbol),
|
|
4669
|
-
signature: cleanSignature(r.sig)
|
|
4670
|
-
}));
|
|
4489
|
+
const symbols2 = files2.flatMap((relativePath) => getDefinitionsForFile(db, relativePath)).filter((d) => d.documentation !== null && d.documentation !== "").sort(
|
|
4490
|
+
(a, b) => a.relativePath.localeCompare(b.relativePath) || a.startLine - b.startLine || a.endLine - b.endLine
|
|
4491
|
+
).map((d) => {
|
|
4492
|
+
const sig = extractSignature(d.documentation);
|
|
4493
|
+
return {
|
|
4494
|
+
startLine: d.startLine,
|
|
4495
|
+
endLine: d.endLine,
|
|
4496
|
+
symbol: d.symbol,
|
|
4497
|
+
shortName: shortenSymbol(d.symbol),
|
|
4498
|
+
signature: cleanSignature(sig)
|
|
4499
|
+
};
|
|
4500
|
+
});
|
|
4671
4501
|
const depRows = db.all(
|
|
4672
4502
|
`SELECT DISTINCT d2.relative_path
|
|
4673
4503
|
FROM mentions m
|
|
@@ -4743,7 +4573,7 @@ function surface(db, modulePattern) {
|
|
|
4743
4573
|
...matchedPaths
|
|
4744
4574
|
);
|
|
4745
4575
|
const exposedDefinitions = matchedPaths.flatMap(
|
|
4746
|
-
(relativePath) => getDefinitionsForFile(db, relativePath).filter((definition) =>
|
|
4576
|
+
(relativePath) => getDefinitionsForFile(db, relativePath).filter((definition) => isCallableSymbol(definition.symbol)).map((definition) => ({
|
|
4747
4577
|
relative_path: relativePath,
|
|
4748
4578
|
symbol: definition.symbol
|
|
4749
4579
|
}))
|
|
@@ -4760,9 +4590,6 @@ function surface(db, modulePattern) {
|
|
|
4760
4590
|
shortName: shortenSymbol(r.symbol)
|
|
4761
4591
|
}));
|
|
4762
4592
|
}
|
|
4763
|
-
function isCallableSymbol2(rawSymbol) {
|
|
4764
|
-
return rawSymbol.endsWith("().") || leafSuffix(rawSymbol) === "method";
|
|
4765
|
-
}
|
|
4766
4593
|
|
|
4767
4594
|
// src/entry-surfaces.ts
|
|
4768
4595
|
var liveBarrelCache = /* @__PURE__ */ new WeakMap();
|
|
@@ -5137,33 +4964,40 @@ function outline(db, filePattern) {
|
|
|
5137
4964
|
if (resolvedPaths.length === 0) {
|
|
5138
4965
|
return [];
|
|
5139
4966
|
}
|
|
5140
|
-
const
|
|
5141
|
-
|
|
5142
|
-
`SELECT gs.symbol, gs.enclosing_symbol, der.start_line, der.end_line
|
|
5143
|
-
FROM defn_enclosing_ranges der
|
|
5144
|
-
JOIN global_symbols gs ON der.symbol_id = gs.id
|
|
5145
|
-
JOIN documents d ON der.document_id = d.id
|
|
5146
|
-
WHERE d.relative_path IN (${placeholders})
|
|
5147
|
-
${db.symbolNoise}
|
|
5148
|
-
ORDER BY d.relative_path, der.start_line`,
|
|
5149
|
-
...resolvedPaths
|
|
4967
|
+
const definitions = resolvedPaths.flatMap((relativePath) => getDefinitionsForFile(db, relativePath)).filter((d) => !db.isIgnored(d.relativePath)).sort(
|
|
4968
|
+
(a, b) => a.relativePath.localeCompare(b.relativePath) || a.startLine - b.startLine || a.endLine - b.endLine
|
|
5150
4969
|
);
|
|
4970
|
+
const nodes = definitions.map((d) => ({
|
|
4971
|
+
symbol: d.symbol,
|
|
4972
|
+
shortName: shortenSymbol(d.symbol),
|
|
4973
|
+
startLine: d.startLine,
|
|
4974
|
+
endLine: d.endLine,
|
|
4975
|
+
children: []
|
|
4976
|
+
}));
|
|
5151
4977
|
const nodeMap = /* @__PURE__ */ new Map();
|
|
4978
|
+
for (const n of nodes) nodeMap.set(n.symbol, n);
|
|
5152
4979
|
const roots = [];
|
|
5153
|
-
for (
|
|
5154
|
-
const
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
4980
|
+
for (let i = 0; i < definitions.length; i++) {
|
|
4981
|
+
const d = definitions[i];
|
|
4982
|
+
const node = nodes[i];
|
|
4983
|
+
if (d.enclosingSymbol && nodeMap.has(d.enclosingSymbol)) {
|
|
4984
|
+
nodeMap.get(d.enclosingSymbol).children.push(node);
|
|
4985
|
+
continue;
|
|
4986
|
+
}
|
|
4987
|
+
let bestParent = null;
|
|
4988
|
+
let bestSize = Infinity;
|
|
4989
|
+
for (const candidate of nodes) {
|
|
4990
|
+
if (candidate === node) continue;
|
|
4991
|
+
if (candidate.startLine <= node.startLine && candidate.endLine >= node.endLine) {
|
|
4992
|
+
const size = candidate.endLine - candidate.startLine;
|
|
4993
|
+
if (size < bestSize) {
|
|
4994
|
+
bestSize = size;
|
|
4995
|
+
bestParent = candidate;
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
}
|
|
4999
|
+
if (bestParent) {
|
|
5000
|
+
bestParent.children.push(node);
|
|
5167
5001
|
} else {
|
|
5168
5002
|
roots.push(node);
|
|
5169
5003
|
}
|
|
@@ -5175,23 +5009,12 @@ function outline(db, filePattern) {
|
|
|
5175
5009
|
function members(db, symbolPattern) {
|
|
5176
5010
|
const parent = findFirstSymbolMatch(db, symbolPattern);
|
|
5177
5011
|
if (!parent) return [];
|
|
5178
|
-
|
|
5179
|
-
|
|
5180
|
-
|
|
5181
|
-
|
|
5182
|
-
|
|
5183
|
-
|
|
5184
|
-
${db.symbolNoiseFor("gs")}
|
|
5185
|
-
ORDER BY der.start_line`,
|
|
5186
|
-
parent.documentId,
|
|
5187
|
-
parent.symbol
|
|
5188
|
-
);
|
|
5189
|
-
return rows.filter((row) => isDirectChildSymbol(parent.symbol, row.symbol)).map((row) => ({
|
|
5190
|
-
symbol: row.symbol,
|
|
5191
|
-
shortName: shortenSymbol(row.symbol),
|
|
5192
|
-
startLine: row.start_line,
|
|
5193
|
-
endLine: row.end_line,
|
|
5194
|
-
kind: leafSuffix(row.symbol) ?? "unknown"
|
|
5012
|
+
return getDefinitionsForFile(db, parent.relativePath).filter((definition) => definition.symbol !== parent.symbol).filter((definition) => isDirectChildSymbol(parent.symbol, definition.symbol)).sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine).map((definition) => ({
|
|
5013
|
+
symbol: definition.symbol,
|
|
5014
|
+
shortName: shortenSymbol(definition.symbol),
|
|
5015
|
+
startLine: definition.startLine,
|
|
5016
|
+
endLine: definition.endLine,
|
|
5017
|
+
kind: leafSuffix(definition.symbol) ?? "unknown"
|
|
5195
5018
|
}));
|
|
5196
5019
|
}
|
|
5197
5020
|
|
|
@@ -5885,7 +5708,7 @@ function similar(db, symbolPattern, opts = {}) {
|
|
|
5885
5708
|
return similarBySourceShape(db, symbolPattern, { minSimilarity, limit });
|
|
5886
5709
|
}
|
|
5887
5710
|
function similarAll(db, opts = {}) {
|
|
5888
|
-
const { minSimilarity = 0.5, limit = 20, scope, minCallees = 4 } = opts;
|
|
5711
|
+
const { minSimilarity = 0.5, limit = 20, scope, minCallees = 4, crossFileOnly = false } = opts;
|
|
5889
5712
|
const all = getAllCalleeFingerprints(db, { minCallees, scope });
|
|
5890
5713
|
const idfWeights = computeIdf(all);
|
|
5891
5714
|
const results = [];
|
|
@@ -5893,14 +5716,16 @@ function similarAll(db, opts = {}) {
|
|
|
5893
5716
|
for (let j = i + 1; j < all.length; j++) {
|
|
5894
5717
|
const a = all[i];
|
|
5895
5718
|
const b = all[j];
|
|
5896
|
-
if (a.file === b.file) continue;
|
|
5719
|
+
if (crossFileOnly && a.file === b.file) continue;
|
|
5897
5720
|
const { similarity, significantShared } = weightedSimilarity(
|
|
5898
5721
|
a.callees,
|
|
5899
5722
|
b.callees,
|
|
5900
5723
|
idfWeights
|
|
5901
5724
|
);
|
|
5902
5725
|
if (similarity < minSimilarity) continue;
|
|
5903
|
-
|
|
5726
|
+
const sharedCount = intersection(a.callees, b.callees).size;
|
|
5727
|
+
if (significantShared.length < 2 && sharedCount < 4) continue;
|
|
5728
|
+
const displayShared = significantShared.length > 0 ? significantShared : [...intersection(a.callees, b.callees)];
|
|
5904
5729
|
results.push({
|
|
5905
5730
|
symbolA: a.symbol,
|
|
5906
5731
|
shortNameA: shortenSymbol(a.symbol),
|
|
@@ -5909,7 +5734,7 @@ function similarAll(db, opts = {}) {
|
|
|
5909
5734
|
shortNameB: shortenSymbol(b.symbol),
|
|
5910
5735
|
fileB: b.file,
|
|
5911
5736
|
similarity,
|
|
5912
|
-
sharedCallees:
|
|
5737
|
+
sharedCallees: displayShared.map(shortenSymbol),
|
|
5913
5738
|
uniqueToA: [...difference(a.callees, b.callees)].map(shortenSymbol),
|
|
5914
5739
|
uniqueToB: [...difference(b.callees, a.callees)].map(shortenSymbol)
|
|
5915
5740
|
});
|
|
@@ -5983,35 +5808,21 @@ function findCallees(db, symbolPattern) {
|
|
|
5983
5808
|
}
|
|
5984
5809
|
function getAllCalleeFingerprints(db, opts) {
|
|
5985
5810
|
const { minCallees, scope, excludeSymbol } = opts;
|
|
5986
|
-
const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
|
|
5987
|
-
const excludeFilter = excludeSymbol ? `AND gs.symbol != '${excludeSymbol.replace(/'/g, "''")}'` : "";
|
|
5988
|
-
const symbols2 = db.all(
|
|
5989
|
-
`SELECT gs.id, gs.symbol, der.document_id, der.start_line, der.end_line, d.relative_path
|
|
5990
|
-
FROM global_symbols gs
|
|
5991
|
-
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
5992
|
-
JOIN documents d ON der.document_id = d.id
|
|
5993
|
-
WHERE 1 = 1
|
|
5994
|
-
${db.pathExclusionsFor("d")}
|
|
5995
|
-
${db.symbolNoiseFor("gs")}
|
|
5996
|
-
AND (der.end_line - der.start_line + 1) >= 5
|
|
5997
|
-
${scopeFilter}
|
|
5998
|
-
${excludeFilter}
|
|
5999
|
-
ORDER BY d.relative_path`
|
|
6000
|
-
);
|
|
6001
5811
|
const fingerprints = [];
|
|
6002
|
-
for (const
|
|
6003
|
-
if (db.isIgnored(
|
|
6004
|
-
if (!
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
5812
|
+
for (const definition of getAllDefinitions(db, { scope })) {
|
|
5813
|
+
if (db.isIgnored(definition.relativePath)) continue;
|
|
5814
|
+
if (!definition.isFunctionLike) continue;
|
|
5815
|
+
if (excludeSymbol && definition.symbol === excludeSymbol) continue;
|
|
5816
|
+
if (definition.endLine - definition.startLine + 1 < 5) continue;
|
|
5817
|
+
const callees = new Set(
|
|
5818
|
+
getCalleeRowsForSymbol(db, definition).map((row) => row.symbol)
|
|
5819
|
+
);
|
|
5820
|
+
if (callees.size < minCallees) continue;
|
|
5821
|
+
fingerprints.push({
|
|
5822
|
+
symbol: definition.symbol,
|
|
5823
|
+
file: definition.relativePath,
|
|
5824
|
+
callees
|
|
6010
5825
|
});
|
|
6011
|
-
const callees = new Set(calleeRows.map((r) => r.symbol));
|
|
6012
|
-
if (callees.size >= minCallees) {
|
|
6013
|
-
fingerprints.push({ symbol: sym.symbol, file: sym.relative_path, callees });
|
|
6014
|
-
}
|
|
6015
5826
|
}
|
|
6016
5827
|
return fingerprints;
|
|
6017
5828
|
}
|
|
@@ -6539,17 +6350,6 @@ function extractCandidates(db, opts = {}) {
|
|
|
6539
6350
|
results.sort((a, b) => b.clusters.length - a.clusters.length || b.loc - a.loc);
|
|
6540
6351
|
return results.slice(0, limit);
|
|
6541
6352
|
}
|
|
6542
|
-
function getScopedDefinitions(db, scope) {
|
|
6543
|
-
const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
|
|
6544
|
-
return db.all(
|
|
6545
|
-
`SELECT relative_path
|
|
6546
|
-
FROM documents
|
|
6547
|
-
WHERE 1 = 1
|
|
6548
|
-
${db.pathExclusionsFor("documents")}
|
|
6549
|
-
${scopeFilter}
|
|
6550
|
-
ORDER BY relative_path`
|
|
6551
|
-
).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
|
|
6552
|
-
}
|
|
6553
6353
|
function definitionLoc(definition) {
|
|
6554
6354
|
return definition.endLine - definition.startLine + 1;
|
|
6555
6355
|
}
|
|
@@ -6640,18 +6440,10 @@ function changeSurface(db, filePattern) {
|
|
|
6640
6440
|
resolvedFile
|
|
6641
6441
|
);
|
|
6642
6442
|
if (!doc || db.isIgnored(doc.relative_path)) return null;
|
|
6643
|
-
const
|
|
6644
|
-
`SELECT DISTINCT gs.id AS symbol_id, gs.symbol, der.start_line, der.end_line
|
|
6645
|
-
FROM defn_enclosing_ranges der
|
|
6646
|
-
JOIN global_symbols gs ON der.symbol_id = gs.id
|
|
6647
|
-
WHERE der.document_id = ?
|
|
6648
|
-
${db.symbolNoiseFor("gs")}
|
|
6649
|
-
ORDER BY der.start_line`,
|
|
6650
|
-
doc.id
|
|
6651
|
-
);
|
|
6443
|
+
const definitions = getDefinitionsForFile(db, doc.relative_path).sort((a, b) => a.startLine - b.startLine || a.endLine - b.endLine);
|
|
6652
6444
|
const symbols2 = [];
|
|
6653
6445
|
let totalExternalConsumers = 0;
|
|
6654
|
-
for (const
|
|
6446
|
+
for (const def of definitions) {
|
|
6655
6447
|
const consumerRow = db.get(
|
|
6656
6448
|
`SELECT COUNT(DISTINCT c.document_id) AS consumer_count
|
|
6657
6449
|
FROM mentions m
|
|
@@ -6659,7 +6451,7 @@ function changeSurface(db, filePattern) {
|
|
|
6659
6451
|
WHERE m.symbol_id = ?
|
|
6660
6452
|
AND m.role != 1
|
|
6661
6453
|
AND c.document_id != ?`,
|
|
6662
|
-
|
|
6454
|
+
def.symbolId,
|
|
6663
6455
|
doc.id
|
|
6664
6456
|
);
|
|
6665
6457
|
const externalConsumers = consumerRow?.consumer_count ?? 0;
|
|
@@ -6673,10 +6465,10 @@ function changeSurface(db, filePattern) {
|
|
|
6673
6465
|
}
|
|
6674
6466
|
totalExternalConsumers += externalConsumers;
|
|
6675
6467
|
symbols2.push({
|
|
6676
|
-
symbol:
|
|
6677
|
-
shortName: shortenSymbol(
|
|
6678
|
-
startLine:
|
|
6679
|
-
endLine:
|
|
6468
|
+
symbol: def.symbol,
|
|
6469
|
+
shortName: shortenSymbol(def.symbol),
|
|
6470
|
+
startLine: def.startLine,
|
|
6471
|
+
endLine: def.endLine,
|
|
6680
6472
|
externalConsumers,
|
|
6681
6473
|
riskLevel
|
|
6682
6474
|
});
|
|
@@ -6993,7 +6785,7 @@ import { basename as basename5, extname as extname4 } from "path";
|
|
|
6993
6785
|
function wrapperCandidates(db, opts) {
|
|
6994
6786
|
const { scope, maxLoc = 15, limit = 30 } = opts ?? {};
|
|
6995
6787
|
const reverseFanIn = buildReverseFileFanIn(buildFileDepGraph(db, scope));
|
|
6996
|
-
const symbols2 =
|
|
6788
|
+
const symbols2 = getScopedDefinitions(db, scope).filter((definition) => definitionLoc2(definition) <= maxLoc && definitionLoc2(definition) >= 2);
|
|
6997
6789
|
const results = [];
|
|
6998
6790
|
for (const symbol of symbols2) {
|
|
6999
6791
|
if (db.isIgnored(symbol.relativePath) || !isFunctionLikeSymbol(symbol.symbol)) continue;
|
|
@@ -7032,17 +6824,6 @@ function wrapperCandidates(db, opts) {
|
|
|
7032
6824
|
function definitionLoc2(definition) {
|
|
7033
6825
|
return definition.endLine - definition.startLine + 1;
|
|
7034
6826
|
}
|
|
7035
|
-
function getScopedDefinitions2(db, scope) {
|
|
7036
|
-
const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
|
|
7037
|
-
return db.all(
|
|
7038
|
-
`SELECT relative_path
|
|
7039
|
-
FROM documents
|
|
7040
|
-
WHERE 1 = 1
|
|
7041
|
-
${db.pathExclusionsFor("documents")}
|
|
7042
|
-
${scopeFilter}
|
|
7043
|
-
ORDER BY relative_path`
|
|
7044
|
-
).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
|
|
7045
|
-
}
|
|
7046
6827
|
function dedupeRows(rows) {
|
|
7047
6828
|
const seen = /* @__PURE__ */ new Set();
|
|
7048
6829
|
const unique = [];
|
|
@@ -7092,7 +6873,7 @@ function fallbackCallerFanIn(db, reverseFanIn, callerFile) {
|
|
|
7092
6873
|
// src/queries/passthrough-candidates.ts
|
|
7093
6874
|
function passthroughCandidates(db, opts) {
|
|
7094
6875
|
const { scope, maxLoc = 15, limit = 30 } = opts ?? {};
|
|
7095
|
-
const symbols2 =
|
|
6876
|
+
const symbols2 = getScopedDefinitions(db, scope).filter((definition) => definitionLoc3(definition) >= 3 && definitionLoc3(definition) <= maxLoc);
|
|
7096
6877
|
const results = [];
|
|
7097
6878
|
for (const sym of symbols2) {
|
|
7098
6879
|
if (db.isIgnored(sym.relativePath) || !isFunctionLikeSymbol(sym.symbol)) continue;
|
|
@@ -7121,17 +6902,6 @@ function passthroughCandidates(db, opts) {
|
|
|
7121
6902
|
results.sort((a, b) => a.loc - b.loc || a.file.localeCompare(b.file));
|
|
7122
6903
|
return results.slice(0, limit);
|
|
7123
6904
|
}
|
|
7124
|
-
function getScopedDefinitions3(db, scope) {
|
|
7125
|
-
const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
|
|
7126
|
-
return db.all(
|
|
7127
|
-
`SELECT relative_path
|
|
7128
|
-
FROM documents
|
|
7129
|
-
WHERE 1 = 1
|
|
7130
|
-
${db.pathExclusionsFor("documents")}
|
|
7131
|
-
${scopeFilter}
|
|
7132
|
-
ORDER BY relative_path`
|
|
7133
|
-
).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
|
|
7134
|
-
}
|
|
7135
6905
|
function definitionLoc3(definition) {
|
|
7136
6906
|
return definition.endLine - definition.startLine + 1;
|
|
7137
6907
|
}
|
|
@@ -7139,7 +6909,7 @@ function definitionLoc3(definition) {
|
|
|
7139
6909
|
// src/queries/stale-abstractions.ts
|
|
7140
6910
|
function staleAbstractions(db, opts) {
|
|
7141
6911
|
const { scope, minLoc = 3, limit = 30 } = opts ?? {};
|
|
7142
|
-
const rows =
|
|
6912
|
+
const rows = getScopedDefinitions(db, scope).filter((definition) => definition.isTypeLike && definitionLoc4(definition) >= minLoc).map((definition) => ({
|
|
7143
6913
|
symbol: definition.symbol,
|
|
7144
6914
|
file: definition.relativePath,
|
|
7145
6915
|
start_line: definition.startLine,
|
|
@@ -7159,7 +6929,7 @@ function staleAbstractions(db, opts) {
|
|
|
7159
6929
|
})).slice(0, limit);
|
|
7160
6930
|
}
|
|
7161
6931
|
function getFilesWithFunctions(db, scope) {
|
|
7162
|
-
return new Set(
|
|
6932
|
+
return new Set(getScopedDefinitions(db, scope).filter((definition) => definition.isFunctionLike).map((definition) => definition.relativePath));
|
|
7163
6933
|
}
|
|
7164
6934
|
function isTrueStaleAbstraction(row, filesWithFunctions) {
|
|
7165
6935
|
const basename6 = row.file.split("/").pop() ?? "";
|
|
@@ -7172,17 +6942,6 @@ function isTrueStaleAbstraction(row, filesWithFunctions) {
|
|
|
7172
6942
|
}
|
|
7173
6943
|
return true;
|
|
7174
6944
|
}
|
|
7175
|
-
function getScopedDefinitions4(db, scope) {
|
|
7176
|
-
const scopeFilter = scope ? `AND relative_path LIKE '%${scope}%'` : "";
|
|
7177
|
-
return db.all(
|
|
7178
|
-
`SELECT relative_path
|
|
7179
|
-
FROM documents
|
|
7180
|
-
WHERE 1 = 1
|
|
7181
|
-
${db.pathExclusionsFor("documents")}
|
|
7182
|
-
${scopeFilter}
|
|
7183
|
-
ORDER BY relative_path`
|
|
7184
|
-
).flatMap((row) => getDefinitionsForFile(db, row.relative_path)).filter((row) => !db.isIgnored(row.relativePath));
|
|
7185
|
-
}
|
|
7186
6945
|
function countCrossFileConsumers(db, definition) {
|
|
7187
6946
|
const callers = db.all(
|
|
7188
6947
|
`SELECT DISTINCT d.relative_path
|
|
@@ -7203,95 +6962,6 @@ function definitionLoc4(definition) {
|
|
|
7203
6962
|
// src/queries/complexity-hotspots.ts
|
|
7204
6963
|
function complexityHotspots(db, opts) {
|
|
7205
6964
|
const { scope, minLoc = 10, limit = 30 } = opts ?? {};
|
|
7206
|
-
const scopeFilter = scope ? `AND d.relative_path LIKE '%${scope}%'` : "";
|
|
7207
|
-
const rows = db.all(
|
|
7208
|
-
`SELECT
|
|
7209
|
-
gs.symbol,
|
|
7210
|
-
d.relative_path AS file,
|
|
7211
|
-
der.start_line,
|
|
7212
|
-
der.end_line,
|
|
7213
|
-
(der.end_line - der.start_line + 1) AS loc,
|
|
7214
|
-
-- fanIn: distinct files that reference this symbol
|
|
7215
|
-
(SELECT COUNT(DISTINCT ref_c.document_id)
|
|
7216
|
-
FROM mentions ref_m
|
|
7217
|
-
JOIN chunks ref_c ON ref_m.chunk_id = ref_c.id
|
|
7218
|
-
WHERE ref_m.symbol_id = gs.id AND ref_m.role != 1
|
|
7219
|
-
) AS fan_in,
|
|
7220
|
-
-- fanOut: distinct symbols referenced within this definition range
|
|
7221
|
-
-- that are defined in different files
|
|
7222
|
-
(SELECT COUNT(DISTINCT out_gs.id)
|
|
7223
|
-
FROM mentions out_m
|
|
7224
|
-
JOIN chunks out_c ON out_m.chunk_id = out_c.id
|
|
7225
|
-
JOIN global_symbols out_gs ON out_m.symbol_id = out_gs.id
|
|
7226
|
-
JOIN defn_enclosing_ranges out_der ON out_gs.id = out_der.symbol_id
|
|
7227
|
-
WHERE out_c.document_id = der.document_id
|
|
7228
|
-
AND out_c.start_line >= der.start_line
|
|
7229
|
-
AND out_c.end_line <= der.end_line
|
|
7230
|
-
AND out_m.role != 1
|
|
7231
|
-
AND out_gs.id != gs.id
|
|
7232
|
-
AND out_der.document_id != der.document_id
|
|
7233
|
-
) AS fan_out,
|
|
7234
|
-
-- calleeCount: total distinct callees within definition range
|
|
7235
|
-
(SELECT COUNT(DISTINCT callee_gs.id)
|
|
7236
|
-
FROM mentions callee_m
|
|
7237
|
-
JOIN chunks callee_c ON callee_m.chunk_id = callee_c.id
|
|
7238
|
-
JOIN global_symbols callee_gs ON callee_m.symbol_id = callee_gs.id
|
|
7239
|
-
WHERE callee_c.document_id = der.document_id
|
|
7240
|
-
AND callee_c.start_line >= der.start_line
|
|
7241
|
-
AND callee_c.end_line <= der.end_line
|
|
7242
|
-
AND callee_m.role != 1
|
|
7243
|
-
AND callee_gs.id != gs.id
|
|
7244
|
-
) AS callee_count
|
|
7245
|
-
FROM global_symbols gs
|
|
7246
|
-
JOIN defn_enclosing_ranges der ON gs.id = der.symbol_id
|
|
7247
|
-
JOIN documents d ON der.document_id = d.id
|
|
7248
|
-
WHERE 1 = 1
|
|
7249
|
-
${db.pathExclusionsFor("d")}
|
|
7250
|
-
AND ${testFileExclusionSql("d")}
|
|
7251
|
-
${db.symbolNoiseFor("gs")}
|
|
7252
|
-
AND (der.end_line - der.start_line + 1) >= ?
|
|
7253
|
-
${scopeFilter}
|
|
7254
|
-
ORDER BY (
|
|
7255
|
-
CAST((der.end_line - der.start_line + 1) AS REAL) / 50.0
|
|
7256
|
-
* CAST((SELECT COUNT(DISTINCT ref_c2.document_id)
|
|
7257
|
-
FROM mentions ref_m2
|
|
7258
|
-
JOIN chunks ref_c2 ON ref_m2.chunk_id = ref_c2.id
|
|
7259
|
-
WHERE ref_m2.symbol_id = gs.id AND ref_m2.role != 1
|
|
7260
|
-
) AS REAL) / 5.0
|
|
7261
|
-
* MAX(CAST((SELECT COUNT(DISTINCT out_gs2.id)
|
|
7262
|
-
FROM mentions out_m2
|
|
7263
|
-
JOIN chunks out_c2 ON out_m2.chunk_id = out_c2.id
|
|
7264
|
-
JOIN global_symbols out_gs2 ON out_m2.symbol_id = out_gs2.id
|
|
7265
|
-
JOIN defn_enclosing_ranges out_der2 ON out_gs2.id = out_der2.symbol_id
|
|
7266
|
-
WHERE out_c2.document_id = der.document_id
|
|
7267
|
-
AND out_c2.start_line >= der.start_line
|
|
7268
|
-
AND out_c2.end_line <= der.end_line
|
|
7269
|
-
AND out_m2.role != 1
|
|
7270
|
-
AND out_gs2.id != gs.id
|
|
7271
|
-
AND out_der2.document_id != der.document_id
|
|
7272
|
-
) AS REAL) / 5.0, 1.0)
|
|
7273
|
-
) DESC
|
|
7274
|
-
LIMIT ?`,
|
|
7275
|
-
minLoc,
|
|
7276
|
-
limit
|
|
7277
|
-
);
|
|
7278
|
-
const indexedResults = rows.filter((r) => !db.isIgnored(r.file)).map((r) => ({
|
|
7279
|
-
symbol: r.symbol,
|
|
7280
|
-
shortName: shortenSymbol(r.symbol),
|
|
7281
|
-
file: r.file,
|
|
7282
|
-
startLine: r.start_line,
|
|
7283
|
-
endLine: r.end_line,
|
|
7284
|
-
loc: r.loc,
|
|
7285
|
-
fanIn: r.fan_in,
|
|
7286
|
-
fanOut: r.fan_out,
|
|
7287
|
-
calleeCount: r.callee_count,
|
|
7288
|
-
score: Math.round(
|
|
7289
|
-
r.loc / 50 * (r.fan_in / 5) * Math.max(r.fan_out / 5, 1) * 100
|
|
7290
|
-
) / 100
|
|
7291
|
-
}));
|
|
7292
|
-
if (indexedResults.length > 0) {
|
|
7293
|
-
return indexedResults;
|
|
7294
|
-
}
|
|
7295
6965
|
return getAllDefinitions(db, { scope }).filter((definition) => !db.isIgnored(definition.relativePath)).map((definition) => {
|
|
7296
6966
|
const loc = definition.endLine - definition.startLine + 1;
|
|
7297
6967
|
const callerRows = getCallerRowsForSymbol(db, definition, { limit: 500 });
|
|
@@ -7590,9 +7260,11 @@ function code(db, symbolPattern, opts = {}) {
|
|
|
7590
7260
|
symbol: match.symbol,
|
|
7591
7261
|
shortName: shortenSymbol(match.symbol),
|
|
7592
7262
|
relativePath: match.relativePath,
|
|
7593
|
-
|
|
7594
|
-
// 1-indexed
|
|
7595
|
-
|
|
7263
|
+
// 0-indexed, like every other query result. The CLI's displayLine()
|
|
7264
|
+
// converts once at render time. Returning 1-indexed here caused a
|
|
7265
|
+
// double-conversion in the CLI and printed labels off by +1.
|
|
7266
|
+
startLine,
|
|
7267
|
+
endLine,
|
|
7596
7268
|
language: doc?.language ?? null,
|
|
7597
7269
|
source
|
|
7598
7270
|
};
|
|
@@ -7620,8 +7292,8 @@ function readFileRange(db, filePath, startLine, endLine, context) {
|
|
|
7620
7292
|
symbol: `${doc.relative_path}:${startLine}-${endLine}`,
|
|
7621
7293
|
shortName: `${doc.relative_path}:${startLine}-${endLine}`,
|
|
7622
7294
|
relativePath: doc.relative_path,
|
|
7623
|
-
startLine: start
|
|
7624
|
-
endLine: end
|
|
7295
|
+
startLine: start,
|
|
7296
|
+
endLine: end,
|
|
7625
7297
|
language: doc.language,
|
|
7626
7298
|
source
|
|
7627
7299
|
};
|
|
@@ -7734,34 +7406,12 @@ function dataflow(db, symbolPattern) {
|
|
|
7734
7406
|
line: match.startLine
|
|
7735
7407
|
}];
|
|
7736
7408
|
const sourceUsageSites = getSourceReferenceSites(db, match);
|
|
7737
|
-
const
|
|
7409
|
+
const resolvedSites = sourceUsageSites.length > 0 ? sourceUsageSites : getResolvedReferenceSites(db, match);
|
|
7410
|
+
const normalizedUsageSites = resolvedSites.filter((site) => !db.isIgnored(site.file)).map((site) => ({
|
|
7738
7411
|
file: site.file,
|
|
7739
7412
|
line: site.line,
|
|
7740
|
-
|
|
7741
|
-
|
|
7742
|
-
`SELECT d.relative_path AS file, c.start_line AS line,
|
|
7743
|
-
(SELECT enc_gs.symbol
|
|
7744
|
-
FROM defn_enclosing_ranges enc_der
|
|
7745
|
-
JOIN global_symbols enc_gs ON enc_der.symbol_id = enc_gs.id
|
|
7746
|
-
WHERE enc_der.document_id = d.id
|
|
7747
|
-
AND enc_der.start_line <= c.start_line
|
|
7748
|
-
AND enc_der.end_line >= c.end_line
|
|
7749
|
-
ORDER BY (enc_der.end_line - enc_der.start_line) ASC
|
|
7750
|
-
LIMIT 1
|
|
7751
|
-
) AS enclosing_symbol
|
|
7752
|
-
FROM mentions m
|
|
7753
|
-
JOIN chunks c ON m.chunk_id = c.id
|
|
7754
|
-
JOIN documents d ON c.document_id = d.id
|
|
7755
|
-
WHERE m.symbol_id = ? AND m.role != 1
|
|
7756
|
-
${db.pathExclusionsFor("d")}
|
|
7757
|
-
ORDER BY d.relative_path, c.start_line`,
|
|
7758
|
-
match.symbolId
|
|
7759
|
-
);
|
|
7760
|
-
const normalizedUsageSites = usageSites.filter((site) => !db.isIgnored(site.file)).map((site) => ({
|
|
7761
|
-
file: site.file,
|
|
7762
|
-
line: site.line,
|
|
7763
|
-
enclosingSymbol: site.enclosing_symbol ?? "(top-level)",
|
|
7764
|
-
enclosingShort: site.enclosing_symbol ? shortenSymbol(site.enclosing_symbol) : "(top-level)"
|
|
7413
|
+
enclosingSymbol: site.enclosingSymbol ?? "(top-level)",
|
|
7414
|
+
enclosingShort: site.enclosingSymbol ? shortenSymbol(site.enclosingSymbol) : "(top-level)"
|
|
7765
7415
|
}));
|
|
7766
7416
|
const producers = uniqueSymbolRows(getCalleeRowsForSymbol(db, match, { limit: 30 }).map((row) => ({
|
|
7767
7417
|
symbol: row.symbol,
|
|
@@ -7801,28 +7451,40 @@ function uniqueSymbolRows(rows) {
|
|
|
7801
7451
|
|
|
7802
7452
|
// src/queries/slice.ts
|
|
7803
7453
|
function slice(db, symbolPattern, opts = {}) {
|
|
7804
|
-
const { direction = "backward" } = opts;
|
|
7454
|
+
const { direction = "backward", maxDepth = 3 } = opts;
|
|
7805
7455
|
const match = findFirstSymbolMatch(db, symbolPattern);
|
|
7806
7456
|
if (!match) return null;
|
|
7807
7457
|
if (direction === "backward") {
|
|
7808
|
-
return backwardSlice(db, match);
|
|
7458
|
+
return backwardSlice(db, match, maxDepth);
|
|
7809
7459
|
} else {
|
|
7810
7460
|
return forwardSlice(db, match);
|
|
7811
7461
|
}
|
|
7812
7462
|
}
|
|
7813
|
-
function backwardSlice(db, match) {
|
|
7814
|
-
const callees = getCalleeRowsForSymbol(db, match);
|
|
7815
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7463
|
+
function backwardSlice(db, match, maxDepth) {
|
|
7816
7464
|
const connected = [];
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
7822
|
-
|
|
7823
|
-
|
|
7824
|
-
|
|
7825
|
-
|
|
7465
|
+
const visited = /* @__PURE__ */ new Set([match.symbol]);
|
|
7466
|
+
let frontier = [match];
|
|
7467
|
+
for (let depth = 1; depth <= maxDepth; depth++) {
|
|
7468
|
+
if (frontier.length === 0) break;
|
|
7469
|
+
const nextFrontier = [];
|
|
7470
|
+
for (const current of frontier) {
|
|
7471
|
+
const callees = getCalleeRowsForSymbol(db, current);
|
|
7472
|
+
for (const c of callees) {
|
|
7473
|
+
if (visited.has(c.symbol)) continue;
|
|
7474
|
+
visited.add(c.symbol);
|
|
7475
|
+
connected.push({
|
|
7476
|
+
symbol: c.symbol,
|
|
7477
|
+
shortName: shortenSymbol(c.symbol),
|
|
7478
|
+
file: c.file,
|
|
7479
|
+
relationship: depth === 1 ? "referenced within definition (callee)" : `depth ${depth} callee`
|
|
7480
|
+
});
|
|
7481
|
+
const calleeMatch = findExactSymbolMatch(db, c.symbol);
|
|
7482
|
+
if (calleeMatch && !db.isIgnored(calleeMatch.relativePath)) {
|
|
7483
|
+
nextFrontier.push(calleeMatch);
|
|
7484
|
+
}
|
|
7485
|
+
}
|
|
7486
|
+
}
|
|
7487
|
+
frontier = nextFrontier;
|
|
7826
7488
|
}
|
|
7827
7489
|
return {
|
|
7828
7490
|
symbol: match.symbol,
|
|
@@ -7832,53 +7494,37 @@ function backwardSlice(db, match) {
|
|
|
7832
7494
|
};
|
|
7833
7495
|
}
|
|
7834
7496
|
function forwardSlice(db, match) {
|
|
7835
|
-
const
|
|
7836
|
-
|
|
7837
|
-
|
|
7838
|
-
enc_d.relative_path AS enclosing_file,
|
|
7839
|
-
out_gs.symbol AS output_symbol,
|
|
7840
|
-
out_d.relative_path AS output_file
|
|
7841
|
-
FROM mentions ref_m
|
|
7842
|
-
JOIN chunks ref_c ON ref_m.chunk_id = ref_c.id
|
|
7843
|
-
JOIN documents ref_d ON ref_c.document_id = ref_d.id
|
|
7844
|
-
-- Find enclosing function at each reference site
|
|
7845
|
-
JOIN defn_enclosing_ranges enc_der
|
|
7846
|
-
ON enc_der.document_id = ref_d.id
|
|
7847
|
-
AND enc_der.start_line <= ref_c.start_line
|
|
7848
|
-
AND enc_der.end_line >= ref_c.end_line
|
|
7849
|
-
JOIN global_symbols enc_gs ON enc_der.symbol_id = enc_gs.id
|
|
7850
|
-
JOIN documents enc_d ON enc_der.document_id = enc_d.id
|
|
7851
|
-
-- Find other symbols referenced within that enclosing function
|
|
7852
|
-
JOIN mentions out_m ON out_m.role != 1
|
|
7853
|
-
JOIN chunks out_c ON out_m.chunk_id = out_c.id
|
|
7854
|
-
AND out_c.document_id = enc_der.document_id
|
|
7855
|
-
AND out_c.start_line >= enc_der.start_line
|
|
7856
|
-
AND out_c.end_line <= enc_der.end_line
|
|
7857
|
-
JOIN global_symbols out_gs ON out_m.symbol_id = out_gs.id
|
|
7858
|
-
JOIN defn_enclosing_ranges out_der ON out_gs.id = out_der.symbol_id
|
|
7859
|
-
JOIN documents out_d ON out_der.document_id = out_d.id
|
|
7860
|
-
WHERE ref_m.symbol_id = ? AND ref_m.role != 1
|
|
7861
|
-
AND out_gs.id != ? AND out_gs.id != enc_gs.id
|
|
7862
|
-
AND out_d.id != ref_d.id
|
|
7863
|
-
${db.symbolNoiseFor("out_gs")}
|
|
7864
|
-
${db.pathExclusionsFor("out_d")}
|
|
7865
|
-
ORDER BY out_d.relative_path
|
|
7866
|
-
LIMIT 30`,
|
|
7867
|
-
match.symbolId,
|
|
7868
|
-
match.symbolId
|
|
7869
|
-
);
|
|
7870
|
-
const seen = /* @__PURE__ */ new Set();
|
|
7497
|
+
const sourceRefs = getSourceReferenceSites(db, match);
|
|
7498
|
+
const refs2 = sourceRefs.length > 0 ? sourceRefs : getResolvedReferenceSites(db, match);
|
|
7499
|
+
const seenOutputs = /* @__PURE__ */ new Set();
|
|
7871
7500
|
const connected = [];
|
|
7872
|
-
for (const
|
|
7873
|
-
if (
|
|
7874
|
-
|
|
7875
|
-
|
|
7876
|
-
|
|
7877
|
-
|
|
7878
|
-
|
|
7879
|
-
|
|
7880
|
-
|
|
7501
|
+
for (const ref of refs2) {
|
|
7502
|
+
if (connected.length >= 30) break;
|
|
7503
|
+
if (db.isIgnored(ref.file)) continue;
|
|
7504
|
+
const enclosingSymbol = ref.enclosingSymbol ?? findEnclosingDefinition(
|
|
7505
|
+
getDefinitionsForFile(db, ref.file),
|
|
7506
|
+
ref.line
|
|
7507
|
+
)?.symbol ?? null;
|
|
7508
|
+
if (!enclosingSymbol || enclosingSymbol === match.symbol) continue;
|
|
7509
|
+
const enclosingMatch = findExactSymbolMatch(db, enclosingSymbol);
|
|
7510
|
+
if (!enclosingMatch) continue;
|
|
7511
|
+
for (const callee of getCalleeRowsForSymbol(db, enclosingMatch)) {
|
|
7512
|
+
if (callee.symbol === match.symbol) continue;
|
|
7513
|
+
if (callee.symbol === enclosingSymbol) continue;
|
|
7514
|
+
if (callee.file === ref.file) continue;
|
|
7515
|
+
if (db.isIgnored(callee.file)) continue;
|
|
7516
|
+
if (seenOutputs.has(callee.symbol)) continue;
|
|
7517
|
+
seenOutputs.add(callee.symbol);
|
|
7518
|
+
connected.push({
|
|
7519
|
+
symbol: callee.symbol,
|
|
7520
|
+
shortName: shortenSymbol(callee.symbol),
|
|
7521
|
+
file: callee.file,
|
|
7522
|
+
relationship: `used alongside target in ${shortenSymbol(enclosingSymbol)}`
|
|
7523
|
+
});
|
|
7524
|
+
if (connected.length >= 30) break;
|
|
7525
|
+
}
|
|
7881
7526
|
}
|
|
7527
|
+
connected.sort((a, b) => a.file.localeCompare(b.file));
|
|
7882
7528
|
return {
|
|
7883
7529
|
symbol: match.symbol,
|
|
7884
7530
|
shortName: shortenSymbol(match.symbol),
|
|
@@ -8833,7 +8479,7 @@ program.command("call-graph <symbol>").description("Show incoming callers and ou
|
|
|
8833
8479
|
}
|
|
8834
8480
|
);
|
|
8835
8481
|
});
|
|
8836
|
-
program.command("similar [symbol]").description("Find functions with similar callee fingerprints (consolidation candidates)").option("--min-similarity <n>", "Minimum Jaccard similarity (0-1)", parseFloat, 0.4).option("-n, --limit <n>", "Number of results", parseIntSafe, 20).option("-s, --scope <path>", "Limit to files matching path").option("--min-callees <n>", "Minimum callees to consider", parseIntSafe, 4).action((symbol, opts) => {
|
|
8482
|
+
program.command("similar [symbol]").description("Find functions with similar callee fingerprints (consolidation candidates)").option("--min-similarity <n>", "Minimum Jaccard similarity (0-1)", parseFloat, 0.4).option("-n, --limit <n>", "Number of results", parseIntSafe, 20).option("-s, --scope <path>", "Limit to files matching path").option("--min-callees <n>", "Minimum callees to consider", parseIntSafe, 4).option("--cross-file-only", "Only show cross-file pairs (skip same-file matches)").action((symbol, opts) => {
|
|
8837
8483
|
withDb((db) => {
|
|
8838
8484
|
if (symbol) {
|
|
8839
8485
|
const results = queries.similar(db, symbol, {
|
|
@@ -8858,7 +8504,8 @@ ${Math.round(r.similarity * 100)}% similar:`);
|
|
|
8858
8504
|
minSimilarity: opts.minSimilarity,
|
|
8859
8505
|
limit: opts.limit,
|
|
8860
8506
|
scope: opts.scope,
|
|
8861
|
-
minCallees: opts.minCallees
|
|
8507
|
+
minCallees: opts.minCallees,
|
|
8508
|
+
crossFileOnly: opts.crossFileOnly
|
|
8862
8509
|
});
|
|
8863
8510
|
if (results.length === 0) {
|
|
8864
8511
|
console.log("No similar symbol pairs found.");
|
|
@@ -9253,10 +8900,10 @@ program.command("dataflow <symbol>").description("Reference-level dataflow: defi
|
|
|
9253
8900
|
}
|
|
9254
8901
|
db.close();
|
|
9255
8902
|
});
|
|
9256
|
-
program.command("slice <symbol>").description("Reference-level program slice: what affects this (backward) or what this affects (forward)").option("--forward", "Forward slice (what does this affect). Default is backward.").action((symbol, opts) => {
|
|
8903
|
+
program.command("slice <symbol>").description("Reference-level program slice: what affects this (backward) or what this affects (forward)").option("--forward", "Forward slice (what does this affect). Default is backward.").option("--depth <n>", "Max transitive depth for backward slice", parseIntSafe, 3).action((symbol, opts) => {
|
|
9257
8904
|
const db = openDb();
|
|
9258
8905
|
const direction = opts.forward ? "forward" : "backward";
|
|
9259
|
-
const result = queries.slice(db, symbol, { direction });
|
|
8906
|
+
const result = queries.slice(db, symbol, { direction, maxDepth: opts.depth });
|
|
9260
8907
|
if (!result) {
|
|
9261
8908
|
console.log("Symbol not found.");
|
|
9262
8909
|
db.close();
|