scip-query 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/{chunk-HNURMDF4.js → chunk-24LF6IZB.js} +3 -3
- package/dist/{chunk-IV6NZ426.js → chunk-3NJSJ7TE.js} +3 -3
- package/dist/{chunk-H3FPW5YN.js → chunk-43A4UCS7.js} +3 -3
- package/dist/{chunk-A5BGEBM7.js → chunk-5GCORUNV.js} +3 -3
- package/dist/{chunk-I2JM34UV.js → chunk-6CH23IAS.js} +4 -4
- package/dist/{chunk-5AJJGPZE.js → chunk-6ECR2FLR.js} +3 -3
- package/dist/{chunk-2UISVZGQ.js → chunk-6UZU7DFL.js} +3 -3
- package/dist/{chunk-NWCJWA36.js → chunk-7BS4CPJX.js} +5 -5
- package/dist/{chunk-QCYR4S6T.js → chunk-A6XLXV6W.js} +3 -3
- package/dist/{chunk-QGCEAVJD.js → chunk-ALUFWH3U.js} +232 -66
- package/dist/{chunk-CQRYLK33.js → chunk-CBIWNZZZ.js} +3 -3
- package/dist/{chunk-N2LH3M2P.js → chunk-DUJNJQPO.js} +3 -3
- package/dist/{chunk-XH56HXLC.js → chunk-EAGKJFDX.js} +3 -3
- package/dist/{chunk-SL674KAW.js → chunk-ELFGD5EW.js} +3 -3
- package/dist/{chunk-GIBETK3W.js → chunk-FVJE4MQL.js} +3 -3
- package/dist/{chunk-CQUNEJYM.js → chunk-GNAMV3JC.js} +3 -3
- package/dist/{chunk-VCOJRQPP.js → chunk-J47VSL6I.js} +3 -3
- package/dist/{chunk-7YBLWIXY.js → chunk-J6QXMYAQ.js} +3 -3
- package/dist/{chunk-2F2WH5WQ.js → chunk-JHVQB4Y5.js} +12 -12
- package/dist/{chunk-X3J4VPWM.js → chunk-JKXHHV4B.js} +2 -2
- package/dist/{chunk-4ZT7UGWW.js → chunk-KG4OFQEN.js} +3 -3
- package/dist/{chunk-SRELHCMG.js → chunk-KLNKDX6A.js} +4 -4
- package/dist/{chunk-LOVDB4C6.js → chunk-KYPXKV64.js} +3 -3
- package/dist/{chunk-UTRKBUCB.js → chunk-NXUIWD6K.js} +3 -3
- package/dist/{chunk-VU7FDTWV.js → chunk-OXX3QF24.js} +2 -2
- package/dist/{chunk-7HK5ZLOE.js → chunk-PCU455MX.js} +2 -2
- package/dist/{chunk-A4GWYETB.js → chunk-POLELLNM.js} +3 -3
- package/dist/{chunk-AS7N27JK.js → chunk-PU2254N2.js} +3 -3
- package/dist/{chunk-WNPF2I25.js → chunk-QMXSLHZP.js} +2 -2
- package/dist/{chunk-PGHN5UTM.js → chunk-R7HPHMRZ.js} +3 -3
- package/dist/{chunk-VUBLUTMU.js → chunk-RE7POFGI.js} +2 -2
- package/dist/{chunk-KDCQJTYW.js → chunk-RJ5GULL6.js} +2 -2
- package/dist/{chunk-HRDPUTIQ.js → chunk-RL74LF47.js} +2 -2
- package/dist/{chunk-5RKYZSQ6.js → chunk-SVLUJSY7.js} +3 -3
- package/dist/{chunk-D4I3ZMN5.js → chunk-SYQR4QGK.js} +3 -3
- package/dist/{chunk-QIXNAB5K.js → chunk-TO3L4YNK.js} +1 -2
- package/dist/{chunk-P42KQKJZ.js → chunk-TWVXFKJA.js} +4 -4
- package/dist/{chunk-MA3B3IUT.js → chunk-UJWI5CBB.js} +3 -3
- package/dist/{chunk-E7J7Q7UW.js → chunk-VKBOLNYN.js} +3 -3
- package/dist/{chunk-RIEA5DOB.js → chunk-VY2L4TP6.js} +3 -3
- package/dist/{chunk-A7YY7IDA.js → chunk-W46L2BXT.js} +2 -2
- package/dist/{chunk-VISMEWYP.js → chunk-XUVPQDXW.js} +4 -4
- package/dist/{chunk-ZU2AQQB5.js → chunk-Z5VSUOEE.js} +2 -2
- package/dist/{chunk-EOHPASDV.js → chunk-ZVZAIIB5.js} +3 -3
- package/dist/cli.js +254 -88
- package/dist/index.js +47 -46
- package/dist/queries/affected.js +3 -3
- package/dist/queries/bottlenecks.js +3 -3
- package/dist/queries/by-kind.js +3 -3
- package/dist/queries/call-graph.js +3 -3
- package/dist/queries/change-surface.js +3 -3
- package/dist/queries/code.js +3 -3
- package/dist/queries/complexity-hotspots.js +3 -3
- package/dist/queries/complexity.js +3 -3
- package/dist/queries/convergence.js +3 -3
- package/dist/queries/coupling.js +3 -3
- package/dist/queries/cycles.js +3 -3
- package/dist/queries/dataflow.js +3 -3
- package/dist/queries/dead.js +4 -4
- package/dist/queries/deep-chains.js +3 -3
- package/dist/queries/deps.js +3 -3
- package/dist/queries/diff-impact.js +2 -2
- package/dist/queries/drift.js +3 -3
- package/dist/queries/extract-candidates.js +3 -3
- package/dist/queries/fan.js +3 -3
- package/dist/queries/health.js +14 -14
- package/dist/queries/hierarchy.js +3 -3
- package/dist/queries/hotspots.js +3 -3
- package/dist/queries/imports.js +3 -3
- package/dist/queries/index.js +44 -44
- package/dist/queries/isolated.js +4 -4
- package/dist/queries/members.js +3 -3
- package/dist/queries/methods.js +3 -3
- package/dist/queries/outline.js +3 -3
- package/dist/queries/passthrough-candidates.js +3 -3
- package/dist/queries/redundant-reexports.js +4 -4
- package/dist/queries/refs.js +3 -3
- package/dist/queries/similar-chains.js +3 -3
- package/dist/queries/similar-files.js +3 -3
- package/dist/queries/similar-signatures.js +3 -3
- package/dist/queries/similar.js +3 -3
- package/dist/queries/slice.js +3 -3
- package/dist/queries/stale-abstractions.js +3 -3
- package/dist/queries/surface.js +3 -3
- package/dist/queries/symbols.js +3 -3
- package/dist/queries/system.js +3 -3
- package/dist/queries/trace.js +3 -3
- package/dist/queries/wrapper-candidates.js +3 -3
- package/dist/reindex-worker.js +3 -2
- package/package.json +5 -1
package/dist/cli.js
CHANGED
|
@@ -1048,7 +1048,8 @@ async function reindex(opts) {
|
|
|
1048
1048
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1049
1049
|
throw new Error(
|
|
1050
1050
|
`Failed to index ${lang} with ${resolvedBinary}: ${msg}
|
|
1051
|
-
Make sure ${binaryLabel} is installed and available on PATH
|
|
1051
|
+
Make sure ${binaryLabel} is installed and available on PATH.`,
|
|
1052
|
+
{ cause: err }
|
|
1052
1053
|
);
|
|
1053
1054
|
}
|
|
1054
1055
|
moveDefaultOutputIfNeeded(config, projectRoot, outputScip);
|
|
@@ -1065,7 +1066,7 @@ Make sure ${binaryLabel} is installed and available on PATH.`
|
|
|
1065
1066
|
});
|
|
1066
1067
|
} catch (err) {
|
|
1067
1068
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1068
|
-
throw new Error(`Failed to convert SCIP index to SQLite: ${msg}
|
|
1069
|
+
throw new Error(`Failed to convert SCIP index to SQLite: ${msg}`, { cause: err });
|
|
1069
1070
|
}
|
|
1070
1071
|
const durationMs = Date.now() - start;
|
|
1071
1072
|
onStatus(`Done in ${(durationMs / 1e3).toFixed(1)}s`);
|
|
@@ -1328,7 +1329,7 @@ import { basename as basename2 } from "path";
|
|
|
1328
1329
|
// src/source-analysis.ts
|
|
1329
1330
|
import {
|
|
1330
1331
|
existsSync as existsSync8,
|
|
1331
|
-
readFileSync as
|
|
1332
|
+
readFileSync as readFileSync3
|
|
1332
1333
|
} from "fs";
|
|
1333
1334
|
import {
|
|
1334
1335
|
basename,
|
|
@@ -1365,7 +1366,7 @@ function getSourceImports(db, relativePath) {
|
|
|
1365
1366
|
cache.set(normalized, []);
|
|
1366
1367
|
return [];
|
|
1367
1368
|
}
|
|
1368
|
-
const source =
|
|
1369
|
+
const source = readFileSync3(fullPath, "utf-8");
|
|
1369
1370
|
const parsed = isPythonSourcePath(normalized) ? parsePythonImports(db, normalized, source) : isJavaScriptSourcePath(normalized) ? parseJavaScriptImports(db, normalized, source) : isJvmSourcePath(normalized) ? parseJvmImports(db, normalized, source) : isRustSourcePath(normalized) ? parseRustImports(db, normalized, source) : isRubySourcePath(normalized) ? parseRubyImports(db, normalized, source) : isCLikeSourcePath(normalized) ? parseCLikeImports(db, normalized, source) : isDotNetSourcePath(normalized) ? parseDotNetImports(db, normalized, source) : isDartSourcePath(normalized) ? parseDartImports(db, normalized, source) : isPhpSourcePath(normalized) ? parsePhpImports(db, normalized, source) : [];
|
|
1370
1371
|
cache.set(normalized, parsed);
|
|
1371
1372
|
return parsed;
|
|
@@ -1382,7 +1383,7 @@ function getSourceExports(db, relativePath) {
|
|
|
1382
1383
|
cache.set(normalized, []);
|
|
1383
1384
|
return [];
|
|
1384
1385
|
}
|
|
1385
|
-
const source =
|
|
1386
|
+
const source = readFileSync3(fullPath, "utf-8");
|
|
1386
1387
|
const parsed = isDartSourcePath(normalized) ? parseDartExports(db, normalized, source) : isRustSourcePath(normalized) ? parseRustExports(db, normalized, source) : [];
|
|
1387
1388
|
cache.set(normalized, parsed);
|
|
1388
1389
|
return parsed;
|
|
@@ -2424,7 +2425,7 @@ function getSourceText(db, relativePath) {
|
|
|
2424
2425
|
cache.set(normalized, "");
|
|
2425
2426
|
return "";
|
|
2426
2427
|
}
|
|
2427
|
-
const source =
|
|
2428
|
+
const source = readFileSync3(fullPath, "utf-8");
|
|
2428
2429
|
cache.set(normalized, source);
|
|
2429
2430
|
return source;
|
|
2430
2431
|
}
|
|
@@ -2526,7 +2527,6 @@ function parseDescriptors(input) {
|
|
|
2526
2527
|
const closingTick = input.indexOf("`", i + 1);
|
|
2527
2528
|
if (closingTick === -1) {
|
|
2528
2529
|
name = input.slice(i + 1);
|
|
2529
|
-
i = input.length;
|
|
2530
2530
|
descriptors.push({ name, suffix: "term" });
|
|
2531
2531
|
break;
|
|
2532
2532
|
}
|
|
@@ -2707,6 +2707,10 @@ function buildFileDepGraph(db, scope) {
|
|
|
2707
2707
|
return graph;
|
|
2708
2708
|
}
|
|
2709
2709
|
function findFirstSymbolMatch(db, symbolPattern) {
|
|
2710
|
+
const exact = findExactSymbolMatch(db, symbolPattern.trim());
|
|
2711
|
+
if (exact) {
|
|
2712
|
+
return exact;
|
|
2713
|
+
}
|
|
2710
2714
|
const fileLineMatch = symbolPattern.match(/^(.+):(\d+)-(\d+)$/);
|
|
2711
2715
|
if (fileLineMatch) {
|
|
2712
2716
|
const [, filePath, startStr, endStr] = fileLineMatch;
|
|
@@ -2744,19 +2748,16 @@ function findFirstSymbolMatch(db, symbolPattern) {
|
|
|
2744
2748
|
);
|
|
2745
2749
|
}
|
|
2746
2750
|
if (row && !db.isIgnored(row.relative_path)) {
|
|
2747
|
-
return
|
|
2748
|
-
symbolId: row.id,
|
|
2749
|
-
symbol: row.symbol,
|
|
2750
|
-
documentId: row.document_id,
|
|
2751
|
-
startLine: row.start_line,
|
|
2752
|
-
endLine: row.end_line,
|
|
2753
|
-
relativePath: row.relative_path
|
|
2754
|
-
};
|
|
2751
|
+
return hydrateSymbolMatch(db, row);
|
|
2755
2752
|
}
|
|
2756
2753
|
}
|
|
2757
2754
|
const cleaned = normalizeLookupPattern(symbolPattern);
|
|
2758
2755
|
const tokens = lookupTokens(symbolPattern);
|
|
2759
2756
|
const candidates = getSymbolLookupCandidates(db, tokens);
|
|
2757
|
+
const direct = findDirectSymbolCandidate(candidates, symbolPattern, cleaned);
|
|
2758
|
+
if (direct && !db.isIgnored(direct.relative_path)) {
|
|
2759
|
+
return hydrateSymbolMatch(db, direct);
|
|
2760
|
+
}
|
|
2760
2761
|
let best = null;
|
|
2761
2762
|
for (const row of candidates) {
|
|
2762
2763
|
if (db.isIgnored(row.relative_path)) continue;
|
|
@@ -2767,14 +2768,7 @@ function findFirstSymbolMatch(db, symbolPattern) {
|
|
|
2767
2768
|
}
|
|
2768
2769
|
}
|
|
2769
2770
|
if (best) {
|
|
2770
|
-
return
|
|
2771
|
-
symbolId: best.row.id,
|
|
2772
|
-
symbol: best.row.symbol,
|
|
2773
|
-
documentId: best.row.document_id,
|
|
2774
|
-
startLine: best.row.start_line,
|
|
2775
|
-
endLine: best.row.end_line,
|
|
2776
|
-
relativePath: best.row.relative_path
|
|
2777
|
-
};
|
|
2771
|
+
return hydrateSymbolMatch(db, best.row);
|
|
2778
2772
|
}
|
|
2779
2773
|
return null;
|
|
2780
2774
|
}
|
|
@@ -2793,14 +2787,7 @@ function findExactSymbolMatch(db, symbol) {
|
|
|
2793
2787
|
if (!row || db.isIgnored(row.relative_path)) {
|
|
2794
2788
|
return null;
|
|
2795
2789
|
}
|
|
2796
|
-
return
|
|
2797
|
-
symbolId: row.id,
|
|
2798
|
-
symbol: row.symbol,
|
|
2799
|
-
documentId: row.document_id,
|
|
2800
|
-
startLine: row.start_line,
|
|
2801
|
-
endLine: row.end_line,
|
|
2802
|
-
relativePath: row.relative_path
|
|
2803
|
-
};
|
|
2790
|
+
return hydrateSymbolMatch(db, row);
|
|
2804
2791
|
}
|
|
2805
2792
|
function resolveIndexedFile(db, filePattern) {
|
|
2806
2793
|
return resolveDocumentCandidates(db, filePattern, { allowMultiple: false })[0]?.relativePath ?? null;
|
|
@@ -2941,27 +2928,10 @@ function getCalleeRowsForSymbol(db, symbol, opts = {}) {
|
|
|
2941
2928
|
});
|
|
2942
2929
|
}
|
|
2943
2930
|
const sourceFallback = getSourceBackedCalleeRows(db, symbol, opts.limit);
|
|
2944
|
-
if (sourceFallback.length
|
|
2945
|
-
return primary;
|
|
2946
|
-
}
|
|
2947
|
-
if (primary.length === 0) {
|
|
2931
|
+
if (sourceFallback.length > 0) {
|
|
2948
2932
|
return applyLimit(sourceFallback, opts.limit);
|
|
2949
2933
|
}
|
|
2950
|
-
|
|
2951
|
-
const seen = new Set(merged.map((row) => `${row.symbol}|${row.file}`));
|
|
2952
|
-
const preferredFallbackLeaves = new Set(
|
|
2953
|
-
sourceFallback.filter((row) => !isLikelyTestPath(row.file)).map((row) => leafName(row.symbol))
|
|
2954
|
-
);
|
|
2955
|
-
for (const row of primary) {
|
|
2956
|
-
if (isLikelyTestPath(row.file) && preferredFallbackLeaves.has(leafName(row.symbol))) {
|
|
2957
|
-
continue;
|
|
2958
|
-
}
|
|
2959
|
-
const key = `${row.symbol}|${row.file}`;
|
|
2960
|
-
if (seen.has(key)) continue;
|
|
2961
|
-
seen.add(key);
|
|
2962
|
-
merged.push(row);
|
|
2963
|
-
}
|
|
2964
|
-
return applyLimit(merged, opts.limit);
|
|
2934
|
+
return primary;
|
|
2965
2935
|
}
|
|
2966
2936
|
function getCallerRowsForSymbol(db, symbol, opts = {}) {
|
|
2967
2937
|
const match = getFullSymbolMatch(db, symbol);
|
|
@@ -2994,11 +2964,13 @@ function getCallerRowsForSymbol(db, symbol, opts = {}) {
|
|
|
2994
2964
|
...getGenericSourceCallerRows(db, match, opts.limit)
|
|
2995
2965
|
]);
|
|
2996
2966
|
if (sourceFallback.length === 0) {
|
|
2997
|
-
return primary;
|
|
2967
|
+
return dedupeCallerRows(primary);
|
|
2998
2968
|
}
|
|
2999
2969
|
const merged = [...sourceFallback];
|
|
2970
|
+
const fallbackFiles = new Set(sourceFallback.map((row) => row.file));
|
|
3000
2971
|
const seen = new Set(merged.map((row) => `${row.symbol}|${row.file}`));
|
|
3001
2972
|
for (const row of primary) {
|
|
2973
|
+
if (fallbackFiles.has(row.file)) continue;
|
|
3002
2974
|
const key = `${row.symbol}|${row.file}`;
|
|
3003
2975
|
if (seen.has(key)) continue;
|
|
3004
2976
|
if (isFunctionLikeSymbol(row.symbol) || merged.length === 0) {
|
|
@@ -3379,14 +3351,7 @@ function getFullSymbolMatch(db, symbol) {
|
|
|
3379
3351
|
if (!row) {
|
|
3380
3352
|
return null;
|
|
3381
3353
|
}
|
|
3382
|
-
return
|
|
3383
|
-
symbolId: row.id,
|
|
3384
|
-
documentId: row.document_id,
|
|
3385
|
-
startLine: row.start_line,
|
|
3386
|
-
endLine: row.end_line,
|
|
3387
|
-
symbol: row.symbol,
|
|
3388
|
-
relativePath: row.relative_path
|
|
3389
|
-
};
|
|
3354
|
+
return hydrateSymbolMatch(db, row);
|
|
3390
3355
|
}
|
|
3391
3356
|
function getDefinitionsForFile(db, relativePath) {
|
|
3392
3357
|
let cache = FILE_DEFINITION_CACHE.get(db);
|
|
@@ -3406,6 +3371,7 @@ function getDefinitionsForFile(db, relativePath) {
|
|
|
3406
3371
|
der.start_line,
|
|
3407
3372
|
der.end_line,
|
|
3408
3373
|
d.relative_path,
|
|
3374
|
+
gs.display_name,
|
|
3409
3375
|
gs.kind,
|
|
3410
3376
|
gs.documentation,
|
|
3411
3377
|
gs.enclosing_symbol
|
|
@@ -3425,6 +3391,7 @@ function getDefinitionsForFile(db, relativePath) {
|
|
|
3425
3391
|
MIN(c.start_line) AS start_line,
|
|
3426
3392
|
MAX(c.end_line) AS end_line,
|
|
3427
3393
|
d.relative_path,
|
|
3394
|
+
gs.display_name,
|
|
3428
3395
|
gs.kind,
|
|
3429
3396
|
gs.documentation,
|
|
3430
3397
|
gs.enclosing_symbol
|
|
@@ -3439,23 +3406,222 @@ function getDefinitionsForFile(db, relativePath) {
|
|
|
3439
3406
|
ORDER BY start_line, end_line`,
|
|
3440
3407
|
relativePath
|
|
3441
3408
|
);
|
|
3442
|
-
const definitions = (
|
|
3409
|
+
const definitions = correctDefinitionRangesFromSource(
|
|
3410
|
+
db,
|
|
3411
|
+
relativePath,
|
|
3412
|
+
(primary.length > 0 ? primary : fallback).map((row) => ({
|
|
3413
|
+
symbolId: row.id,
|
|
3414
|
+
symbol: row.symbol,
|
|
3415
|
+
documentId: row.document_id,
|
|
3416
|
+
startLine: row.start_line,
|
|
3417
|
+
endLine: row.end_line,
|
|
3418
|
+
relativePath: row.relative_path,
|
|
3419
|
+
leaf: leafName(row.symbol),
|
|
3420
|
+
parentTypeName: parentTypeName(row.symbol),
|
|
3421
|
+
isFunctionLike: isFunctionLikeSymbol(row.symbol),
|
|
3422
|
+
isTypeLike: leafSuffix(row.symbol) === "type",
|
|
3423
|
+
kind: row.kind ?? null,
|
|
3424
|
+
documentation: row.documentation ?? null,
|
|
3425
|
+
enclosingSymbol: row.enclosing_symbol ?? null
|
|
3426
|
+
}))
|
|
3427
|
+
);
|
|
3428
|
+
cache.set(relativePath, definitions);
|
|
3429
|
+
return definitions;
|
|
3430
|
+
}
|
|
3431
|
+
function hydrateSymbolMatch(db, row) {
|
|
3432
|
+
const corrected = getDefinitionsForFile(db, row.relative_path).find((definition) => definition.symbolId === row.id);
|
|
3433
|
+
if (corrected) {
|
|
3434
|
+
return {
|
|
3435
|
+
symbolId: corrected.symbolId,
|
|
3436
|
+
symbol: corrected.symbol,
|
|
3437
|
+
documentId: corrected.documentId,
|
|
3438
|
+
startLine: corrected.startLine,
|
|
3439
|
+
endLine: corrected.endLine,
|
|
3440
|
+
relativePath: corrected.relativePath
|
|
3441
|
+
};
|
|
3442
|
+
}
|
|
3443
|
+
return {
|
|
3443
3444
|
symbolId: row.id,
|
|
3444
3445
|
symbol: row.symbol,
|
|
3445
3446
|
documentId: row.document_id,
|
|
3446
3447
|
startLine: row.start_line,
|
|
3447
3448
|
endLine: row.end_line,
|
|
3448
|
-
relativePath: row.relative_path
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3449
|
+
relativePath: row.relative_path
|
|
3450
|
+
};
|
|
3451
|
+
}
|
|
3452
|
+
function findDirectSymbolCandidate(candidates, symbolPattern, cleanedPattern) {
|
|
3453
|
+
const trimmed = symbolPattern.trim();
|
|
3454
|
+
const directMatches = candidates.filter((row) => {
|
|
3455
|
+
const short = shortenSymbol(row.symbol);
|
|
3456
|
+
const display = (row.display_name ?? "").trim();
|
|
3457
|
+
return row.symbol === trimmed || short === trimmed || short === cleanedPattern || display === trimmed || display === cleanedPattern || `${display}()` === trimmed || row.relative_path === trimmed;
|
|
3458
|
+
});
|
|
3459
|
+
if (directMatches.length === 0) {
|
|
3460
|
+
return null;
|
|
3461
|
+
}
|
|
3462
|
+
directMatches.sort(
|
|
3463
|
+
(left, right) => left.end_line - left.start_line - (right.end_line - right.start_line) || left.relative_path.localeCompare(right.relative_path) || left.symbol.localeCompare(right.symbol)
|
|
3464
|
+
);
|
|
3465
|
+
return directMatches[0] ?? null;
|
|
3466
|
+
}
|
|
3467
|
+
function correctDefinitionRangesFromSource(db, relativePath, definitions) {
|
|
3468
|
+
const source = getSourceText(db, relativePath);
|
|
3469
|
+
if (!source) {
|
|
3470
|
+
return definitions;
|
|
3471
|
+
}
|
|
3472
|
+
const lines = source.split(/\r?\n/);
|
|
3473
|
+
const correctedStarts = /* @__PURE__ */ new Map();
|
|
3474
|
+
for (const definition of definitions) {
|
|
3475
|
+
correctedStarts.set(
|
|
3476
|
+
definition.symbolId,
|
|
3477
|
+
resolveCallableDefinitionStartLine(lines, definition)
|
|
3478
|
+
);
|
|
3479
|
+
}
|
|
3480
|
+
const correctedRanges = /* @__PURE__ */ new Map();
|
|
3481
|
+
const callableDefinitions = definitions.filter((definition) => isCallableDefinition(definition.symbol)).map((definition) => ({
|
|
3482
|
+
definition,
|
|
3483
|
+
startLine: correctedStarts.get(definition.symbolId) ?? definition.startLine
|
|
3484
|
+
})).sort(
|
|
3485
|
+
(left, right) => left.startLine - right.startLine || left.definition.startLine - right.definition.startLine || left.definition.symbol.localeCompare(right.definition.symbol)
|
|
3486
|
+
);
|
|
3487
|
+
for (let index = 0; index < callableDefinitions.length; index += 1) {
|
|
3488
|
+
const current = callableDefinitions[index];
|
|
3489
|
+
const next = callableDefinitions[index + 1];
|
|
3490
|
+
const maxEndLine = next ? Math.max(current.startLine, next.startLine - 1) : lines.length - 1;
|
|
3491
|
+
correctedRanges.set(current.definition.symbolId, {
|
|
3492
|
+
startLine: current.startLine,
|
|
3493
|
+
endLine: resolveCallableDefinitionEndLine(
|
|
3494
|
+
lines,
|
|
3495
|
+
current.definition,
|
|
3496
|
+
current.startLine,
|
|
3497
|
+
maxEndLine
|
|
3498
|
+
)
|
|
3499
|
+
});
|
|
3500
|
+
}
|
|
3501
|
+
return definitions.map((definition) => {
|
|
3502
|
+
const corrected = correctedRanges.get(definition.symbolId);
|
|
3503
|
+
if (!corrected) {
|
|
3504
|
+
return definition;
|
|
3505
|
+
}
|
|
3506
|
+
return {
|
|
3507
|
+
...definition,
|
|
3508
|
+
startLine: corrected.startLine,
|
|
3509
|
+
endLine: corrected.endLine
|
|
3510
|
+
};
|
|
3511
|
+
});
|
|
3512
|
+
}
|
|
3513
|
+
function resolveCallableDefinitionStartLine(lines, definition) {
|
|
3514
|
+
if (!isCallableDefinition(definition.symbol)) {
|
|
3515
|
+
return definition.startLine;
|
|
3516
|
+
}
|
|
3517
|
+
const escapedLeaf = escapeRegex2(definition.leaf);
|
|
3518
|
+
const strongPatterns = [
|
|
3519
|
+
new RegExp(`\\b(?:function|def|fn)\\s+${escapedLeaf}\\b`),
|
|
3520
|
+
new RegExp(`\\b${escapedLeaf}\\b\\s*[:=]\\s*(?:async\\s*)?(?:function\\b|\\()`)
|
|
3521
|
+
];
|
|
3522
|
+
const fallbackPatterns = [
|
|
3523
|
+
new RegExp(`\\b${escapedLeaf}\\b\\s*\\(`)
|
|
3524
|
+
];
|
|
3525
|
+
return findNearestMatchingLine(
|
|
3526
|
+
lines,
|
|
3527
|
+
[...strongPatterns, ...fallbackPatterns],
|
|
3528
|
+
definition.startLine,
|
|
3529
|
+
definition.endLine
|
|
3530
|
+
);
|
|
3531
|
+
}
|
|
3532
|
+
function findNearestMatchingLine(lines, patterns, preferredStartLine, preferredEndLine) {
|
|
3533
|
+
const windowStart = Math.max(0, preferredStartLine - 40);
|
|
3534
|
+
const windowEnd = Math.min(lines.length - 1, Math.max(preferredEndLine + 40, preferredStartLine + 5));
|
|
3535
|
+
const windowMatch = matchNearestLine(lines, patterns, preferredStartLine, windowStart, windowEnd);
|
|
3536
|
+
if (windowMatch !== null) {
|
|
3537
|
+
return windowMatch;
|
|
3538
|
+
}
|
|
3539
|
+
const fullMatch = matchNearestLine(lines, patterns, preferredStartLine, 0, lines.length - 1);
|
|
3540
|
+
return fullMatch ?? Math.max(0, Math.min(preferredStartLine, lines.length - 1));
|
|
3541
|
+
}
|
|
3542
|
+
function matchNearestLine(lines, patterns, preferredLine, startLine, endLine) {
|
|
3543
|
+
let best = null;
|
|
3544
|
+
for (let lineIndex = startLine; lineIndex <= endLine; lineIndex += 1) {
|
|
3545
|
+
const line = lines[lineIndex] ?? "";
|
|
3546
|
+
if (!patterns.some((pattern) => pattern.test(line))) continue;
|
|
3547
|
+
const distance = Math.abs(lineIndex - preferredLine);
|
|
3548
|
+
if (!best || distance < best.distance) {
|
|
3549
|
+
best = { line: lineIndex, distance };
|
|
3550
|
+
}
|
|
3551
|
+
}
|
|
3552
|
+
return best?.line ?? null;
|
|
3553
|
+
}
|
|
3554
|
+
function resolveCallableDefinitionEndLine(lines, definition, startLine, maxEndLine) {
|
|
3555
|
+
const boundedEndLine = Math.max(startLine, Math.min(lines.length - 1, maxEndLine));
|
|
3556
|
+
const fallbackEndLine = Math.max(startLine, Math.min(boundedEndLine, definition.endLine));
|
|
3557
|
+
let braceDepth = 0;
|
|
3558
|
+
let parenDepth = 0;
|
|
3559
|
+
let sawOpeningBrace = false;
|
|
3560
|
+
for (let lineIndex = startLine; lineIndex <= boundedEndLine; lineIndex += 1) {
|
|
3561
|
+
const masked = maskStructuralLine(lines[lineIndex] ?? "");
|
|
3562
|
+
for (const char of masked) {
|
|
3563
|
+
if (char === "{") {
|
|
3564
|
+
braceDepth += 1;
|
|
3565
|
+
sawOpeningBrace = true;
|
|
3566
|
+
} else if (char === "}") {
|
|
3567
|
+
braceDepth = Math.max(0, braceDepth - 1);
|
|
3568
|
+
} else if (char === "(") {
|
|
3569
|
+
parenDepth += 1;
|
|
3570
|
+
} else if (char === ")") {
|
|
3571
|
+
parenDepth = Math.max(0, parenDepth - 1);
|
|
3572
|
+
}
|
|
3573
|
+
}
|
|
3574
|
+
if (sawOpeningBrace && braceDepth === 0) {
|
|
3575
|
+
return lineIndex;
|
|
3576
|
+
}
|
|
3577
|
+
if (!sawOpeningBrace && parenDepth === 0 && lineIndex >= fallbackEndLine) {
|
|
3578
|
+
return lineIndex;
|
|
3579
|
+
}
|
|
3580
|
+
}
|
|
3581
|
+
return fallbackEndLine;
|
|
3582
|
+
}
|
|
3583
|
+
function maskStructuralLine(line) {
|
|
3584
|
+
let masked = "";
|
|
3585
|
+
let quote = null;
|
|
3586
|
+
let escaping = false;
|
|
3587
|
+
for (let index = 0; index < line.length; index += 1) {
|
|
3588
|
+
const char = line[index];
|
|
3589
|
+
const next = line[index + 1];
|
|
3590
|
+
if (!quote && char === "/" && next === "/") {
|
|
3591
|
+
masked += " ".repeat(line.length - index);
|
|
3592
|
+
break;
|
|
3593
|
+
}
|
|
3594
|
+
if (quote) {
|
|
3595
|
+
if (escaping) {
|
|
3596
|
+
escaping = false;
|
|
3597
|
+
masked += " ";
|
|
3598
|
+
continue;
|
|
3599
|
+
}
|
|
3600
|
+
if (char === "\\") {
|
|
3601
|
+
escaping = true;
|
|
3602
|
+
masked += " ";
|
|
3603
|
+
continue;
|
|
3604
|
+
}
|
|
3605
|
+
if (char === quote) {
|
|
3606
|
+
quote = null;
|
|
3607
|
+
}
|
|
3608
|
+
masked += " ";
|
|
3609
|
+
continue;
|
|
3610
|
+
}
|
|
3611
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
3612
|
+
quote = char;
|
|
3613
|
+
masked += " ";
|
|
3614
|
+
continue;
|
|
3615
|
+
}
|
|
3616
|
+
masked += char;
|
|
3617
|
+
}
|
|
3618
|
+
return masked;
|
|
3619
|
+
}
|
|
3620
|
+
function isCallableDefinition(symbol) {
|
|
3621
|
+
return symbol.includes("().");
|
|
3622
|
+
}
|
|
3623
|
+
function escapeRegex2(value) {
|
|
3624
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
3459
3625
|
}
|
|
3460
3626
|
function getAllDefinitions(db, opts = {}) {
|
|
3461
3627
|
const { scope } = opts;
|
|
@@ -5526,7 +5692,7 @@ function similar(db, symbolPattern, opts = {}) {
|
|
|
5526
5692
|
const results = [];
|
|
5527
5693
|
for (const candidate of candidates) {
|
|
5528
5694
|
if (candidate.callees.size < 3) continue;
|
|
5529
|
-
const { similarity, significantShared
|
|
5695
|
+
const { similarity, significantShared } = weightedSimilarity(
|
|
5530
5696
|
target.callees,
|
|
5531
5697
|
candidate.callees,
|
|
5532
5698
|
idfWeights
|
|
@@ -5763,11 +5929,11 @@ function definitionSnippet(db, relativePath, startLine, endLine, leaf) {
|
|
|
5763
5929
|
return lines.slice(startLine, endLine + 1).join("\n");
|
|
5764
5930
|
}
|
|
5765
5931
|
const markerPatterns = [
|
|
5766
|
-
new RegExp(`\\bdef\\s+${
|
|
5767
|
-
new RegExp(`\\bfun\\s+${
|
|
5768
|
-
new RegExp(`\\bfn\\s+${
|
|
5769
|
-
new RegExp(`\\bfunction\\s+${
|
|
5770
|
-
new RegExp(`\\b${
|
|
5932
|
+
new RegExp(`\\bdef\\s+${escapeRegex3(leaf)}\\b`),
|
|
5933
|
+
new RegExp(`\\bfun\\s+${escapeRegex3(leaf)}\\b`),
|
|
5934
|
+
new RegExp(`\\bfn\\s+${escapeRegex3(leaf)}\\b`),
|
|
5935
|
+
new RegExp(`\\bfunction\\s+${escapeRegex3(leaf)}\\b`),
|
|
5936
|
+
new RegExp(`\\b${escapeRegex3(leaf)}\\s*\\(`)
|
|
5771
5937
|
];
|
|
5772
5938
|
const definitionStart = lines.findIndex((line) => markerPatterns.some((pattern) => pattern.test(line)));
|
|
5773
5939
|
if (definitionStart >= 0) {
|
|
@@ -5829,7 +5995,7 @@ function splitIdentifier(value) {
|
|
|
5829
5995
|
function looksLikeDefinitionBoundary(line) {
|
|
5830
5996
|
return /^\s*(?:def|fun|fn|function|class|trait|module|object|enum|interface|public|private|protected)\b/.test(line);
|
|
5831
5997
|
}
|
|
5832
|
-
function
|
|
5998
|
+
function escapeRegex3(value) {
|
|
5833
5999
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5834
6000
|
}
|
|
5835
6001
|
|
|
@@ -7229,7 +7395,7 @@ function convergence(db, symbolPatternA, symbolPatternB) {
|
|
|
7229
7395
|
}
|
|
7230
7396
|
|
|
7231
7397
|
// src/queries/code.ts
|
|
7232
|
-
import { readFileSync as
|
|
7398
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
7233
7399
|
import { join as join9 } from "path";
|
|
7234
7400
|
function code(db, symbolPattern, opts = {}) {
|
|
7235
7401
|
const { context = 0 } = opts;
|
|
@@ -7246,7 +7412,7 @@ function code(db, symbolPattern, opts = {}) {
|
|
|
7246
7412
|
const filePath = join9(db.config.projectRoot, match.relativePath);
|
|
7247
7413
|
let fileContent;
|
|
7248
7414
|
try {
|
|
7249
|
-
fileContent =
|
|
7415
|
+
fileContent = readFileSync4(filePath, "utf-8");
|
|
7250
7416
|
} catch {
|
|
7251
7417
|
return null;
|
|
7252
7418
|
}
|
|
@@ -7276,7 +7442,7 @@ function readFileRange(db, filePath, startLine, endLine, context) {
|
|
|
7276
7442
|
const fullPath = join9(db.config.projectRoot, doc.relative_path);
|
|
7277
7443
|
let fileContent;
|
|
7278
7444
|
try {
|
|
7279
|
-
fileContent =
|
|
7445
|
+
fileContent = readFileSync4(fullPath, "utf-8");
|
|
7280
7446
|
} catch {
|
|
7281
7447
|
return null;
|
|
7282
7448
|
}
|
|
@@ -7296,7 +7462,7 @@ function readFileRange(db, filePath, startLine, endLine, context) {
|
|
|
7296
7462
|
}
|
|
7297
7463
|
|
|
7298
7464
|
// src/queries/complexity.ts
|
|
7299
|
-
import { readFileSync as
|
|
7465
|
+
import { readFileSync as readFileSync5 } from "fs";
|
|
7300
7466
|
import { join as join10 } from "path";
|
|
7301
7467
|
function complexity(db, symbolPattern) {
|
|
7302
7468
|
const match = findFirstSymbolMatch(db, symbolPattern);
|
|
@@ -7309,7 +7475,7 @@ function complexity(db, symbolPattern) {
|
|
|
7309
7475
|
const filePath = join10(db.config.projectRoot, match.relativePath);
|
|
7310
7476
|
let source = "";
|
|
7311
7477
|
try {
|
|
7312
|
-
const lines =
|
|
7478
|
+
const lines = readFileSync5(filePath, "utf-8").split("\n");
|
|
7313
7479
|
source = lines.slice(match.startLine, match.endLine + 1).join("\n");
|
|
7314
7480
|
} catch {
|
|
7315
7481
|
}
|
|
@@ -7820,17 +7986,17 @@ function normalizeSignature(raw) {
|
|
|
7820
7986
|
}
|
|
7821
7987
|
function normalizeSourceSignature(raw, leaf) {
|
|
7822
7988
|
if (!raw || !raw.trim()) return null;
|
|
7823
|
-
|
|
7989
|
+
const declaration = raw.replace(/\s+/g, " ").trim();
|
|
7824
7990
|
const parenIdx = declaration.indexOf("(");
|
|
7825
7991
|
if (parenIdx === -1) return null;
|
|
7826
7992
|
let prefix = declaration.slice(0, parenIdx);
|
|
7827
|
-
const leafPattern = new RegExp(`\\b${
|
|
7993
|
+
const leafPattern = new RegExp(`\\b${escapeRegex4(leaf)}\\b`, "i");
|
|
7828
7994
|
const leafMatch = leafPattern.exec(prefix);
|
|
7829
7995
|
if (leafMatch && typeof leafMatch.index === "number") {
|
|
7830
7996
|
prefix = prefix.slice(0, leafMatch.index);
|
|
7831
7997
|
}
|
|
7832
7998
|
prefix = prefix.replace(/\b(public|private|protected|internal|final|static|abstract|sealed|virtual|override|async|suspend|inline|constexpr|consteval|constinit|const|pub|fn|function|def|sub|friend|shared|readonly|new|open|partial|export)\b/gi, " ").replace(/\s+/g, " ").trim();
|
|
7833
|
-
|
|
7999
|
+
const suffix = declaration.slice(parenIdx).replace(/\s*\{[\s\S]*$/, "").replace(/\s*=>[\s\S]*$/, "").replace(/\)\s*=\s*[\s\S]*$/, ")").replace(/\s+throws\s+[^={]+$/i, "").replace(/\s+where\s+.+$/i, "").replace(/\s+/g, " ").trim();
|
|
7834
8000
|
if (!suffix.startsWith("(")) {
|
|
7835
8001
|
return null;
|
|
7836
8002
|
}
|
|
@@ -7838,7 +8004,7 @@ function normalizeSourceSignature(raw, leaf) {
|
|
|
7838
8004
|
return normalized.length >= 3 ? normalized : null;
|
|
7839
8005
|
}
|
|
7840
8006
|
function declarationStartLines(lines, startLine, endLine, leaf) {
|
|
7841
|
-
const escapedLeaf =
|
|
8007
|
+
const escapedLeaf = escapeRegex4(leaf);
|
|
7842
8008
|
const callablePattern = new RegExp(`\\b${escapedLeaf}\\b\\s*\\(`, "i");
|
|
7843
8009
|
const rubyPattern = new RegExp(`\\bdef\\s+${escapedLeaf}\\b`, "i");
|
|
7844
8010
|
const candidates = [];
|
|
@@ -7869,7 +8035,7 @@ function parenBalance(value) {
|
|
|
7869
8035
|
}
|
|
7870
8036
|
return balance;
|
|
7871
8037
|
}
|
|
7872
|
-
function
|
|
8038
|
+
function escapeRegex4(value) {
|
|
7873
8039
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
7874
8040
|
}
|
|
7875
8041
|
|