@wrongstack/tools 0.296.2 → 0.296.3
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/browser/artifacts.d.ts +2 -0
- package/dist/browser/artifacts.d.ts.map +1 -1
- package/dist/browser/index.js +41 -0
- package/dist/browser/index.js.map +2 -2
- package/dist/builtin.js +557 -204
- package/dist/builtin.js.map +4 -4
- package/dist/codebase-index/dead-code-scan.d.ts +2 -2
- package/dist/codebase-index/dead-code-scan.d.ts.map +1 -1
- package/dist/codebase-index/index.js +468 -219
- package/dist/codebase-index/index.js.map +3 -3
- package/dist/codebase-index/project-server.js +222 -147
- package/dist/codebase-index/project-server.js.map +4 -4
- package/dist/codebase-index/ts-parser.d.ts.map +1 -1
- package/dist/codebase-index/worker.js +214 -145
- package/dist/codebase-index/worker.js.map +3 -3
- package/dist/codebase-index/writer.d.ts +19 -1
- package/dist/codebase-index/writer.d.ts.map +1 -1
- package/dist/index.js +559 -206
- package/dist/index.js.map +4 -4
- package/dist/pack.js +557 -204
- package/dist/pack.js.map +4 -4
- package/dist/read.d.ts +31 -0
- package/dist/read.d.ts.map +1 -1
- package/dist/read.js +5434 -78
- package/dist/read.js.map +4 -4
- package/dist/tool-tier.js +557 -204
- package/dist/tool-tier.js.map +4 -4
- package/package.json +3 -3
package/dist/tool-tier.js
CHANGED
|
@@ -5131,11 +5131,18 @@ async function parseSymbols(opts) {
|
|
|
5131
5131
|
} else if (ts.isHeritageClause(node)) {
|
|
5132
5132
|
for (const t of node.types) {
|
|
5133
5133
|
const name = getTypeName(t.expression);
|
|
5134
|
-
if (name)
|
|
5134
|
+
if (name)
|
|
5135
|
+
refs.push({
|
|
5136
|
+
fromId: 0,
|
|
5137
|
+
toName: name,
|
|
5138
|
+
callType: node.token === ts.SyntaxKind.ExtendsKeyword ? "inherit" : "implement",
|
|
5139
|
+
line: lineNum
|
|
5140
|
+
});
|
|
5135
5141
|
}
|
|
5136
5142
|
} else if (ts.isImportDeclaration(node)) {
|
|
5137
|
-
|
|
5138
|
-
|
|
5143
|
+
emitImportSpecifierRefs(node, refs, lineNum);
|
|
5144
|
+
} else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
|
|
5145
|
+
emitExportSpecifierRefs(node, refs, lineNum);
|
|
5139
5146
|
}
|
|
5140
5147
|
const scopeIdx = scopeParts.length;
|
|
5141
5148
|
pushScopeName(node, scopeParts);
|
|
@@ -5151,11 +5158,6 @@ function getTypeName(name) {
|
|
|
5151
5158
|
if (ts.isQualifiedName(name)) return `${getTypeName(name.left)}.${name.right.text}`;
|
|
5152
5159
|
return "";
|
|
5153
5160
|
}
|
|
5154
|
-
function getModuleName(node) {
|
|
5155
|
-
const moduleSpecifier = node.moduleSpecifier;
|
|
5156
|
-
if (ts.isStringLiteral(moduleSpecifier)) return moduleSpecifier.text;
|
|
5157
|
-
return "";
|
|
5158
|
-
}
|
|
5159
5161
|
function deduplicateRefs(refs) {
|
|
5160
5162
|
const seen = /* @__PURE__ */ new Set();
|
|
5161
5163
|
return refs.filter((r) => {
|
|
@@ -5165,6 +5167,44 @@ function deduplicateRefs(refs) {
|
|
|
5165
5167
|
return true;
|
|
5166
5168
|
});
|
|
5167
5169
|
}
|
|
5170
|
+
function getImportSpecifierName(spec) {
|
|
5171
|
+
return spec.propertyName?.text ?? spec.name.text;
|
|
5172
|
+
}
|
|
5173
|
+
function emitImportSpecifierRefs(node, refs, lineNum) {
|
|
5174
|
+
const clause = node.importClause;
|
|
5175
|
+
if (!clause) return;
|
|
5176
|
+
if (clause.name) {
|
|
5177
|
+
refs.push({ fromId: 0, toName: clause.name.text, callType: "import", line: lineNum });
|
|
5178
|
+
}
|
|
5179
|
+
const bindings = clause.namedBindings;
|
|
5180
|
+
if (!bindings) return;
|
|
5181
|
+
if (ts.isNamedImports(bindings)) {
|
|
5182
|
+
for (const element of bindings.elements) {
|
|
5183
|
+
refs.push({
|
|
5184
|
+
fromId: 0,
|
|
5185
|
+
toName: getImportSpecifierName(element),
|
|
5186
|
+
callType: "import",
|
|
5187
|
+
line: lineNum
|
|
5188
|
+
});
|
|
5189
|
+
}
|
|
5190
|
+
} else if (ts.isNamespaceImport(bindings)) {
|
|
5191
|
+
refs.push({ fromId: 0, toName: bindings.name.text, callType: "import", line: lineNum });
|
|
5192
|
+
}
|
|
5193
|
+
}
|
|
5194
|
+
function emitExportSpecifierRefs(node, refs, lineNum) {
|
|
5195
|
+
const clause = node.exportClause;
|
|
5196
|
+
if (clause && ts.isNamespaceExport(clause)) {
|
|
5197
|
+
refs.push({ fromId: 0, toName: clause.name.text, callType: "import", line: lineNum });
|
|
5198
|
+
return;
|
|
5199
|
+
}
|
|
5200
|
+
if (clause && ts.isNamedExports(clause)) {
|
|
5201
|
+
for (const element of clause.elements) {
|
|
5202
|
+
const originalName = element.propertyName?.text ?? element.name.text;
|
|
5203
|
+
refs.push({ fromId: 0, toName: originalName, callType: "import", line: lineNum });
|
|
5204
|
+
}
|
|
5205
|
+
return;
|
|
5206
|
+
}
|
|
5207
|
+
}
|
|
5168
5208
|
var ts, tsLoad, kindMapCache;
|
|
5169
5209
|
var init_ts_parser = __esm({
|
|
5170
5210
|
"src/codebase-index/ts-parser.ts"() {
|
|
@@ -8454,9 +8494,50 @@ import { createReadStream } from "node:fs";
|
|
|
8454
8494
|
import * as fs7 from "node:fs/promises";
|
|
8455
8495
|
import * as path10 from "node:path";
|
|
8456
8496
|
import { atomicWrite, ulid } from "@wrongstack/core/utils";
|
|
8497
|
+
var ARTIFACT_RETENTION_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
8498
|
+
var sweptRoots = /* @__PURE__ */ new Set();
|
|
8499
|
+
function sweepOldArtifacts(root) {
|
|
8500
|
+
if (sweptRoots.has(root)) return;
|
|
8501
|
+
sweptRoots.add(root);
|
|
8502
|
+
void (async () => {
|
|
8503
|
+
const cutoff = Date.now() - ARTIFACT_RETENTION_MS;
|
|
8504
|
+
let sessionDirs;
|
|
8505
|
+
try {
|
|
8506
|
+
const entries = await fs7.readdir(root, { withFileTypes: true });
|
|
8507
|
+
sessionDirs = entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
8508
|
+
} catch {
|
|
8509
|
+
return;
|
|
8510
|
+
}
|
|
8511
|
+
for (const sessionDir of sessionDirs) {
|
|
8512
|
+
const dir = path10.join(root, sessionDir);
|
|
8513
|
+
let names;
|
|
8514
|
+
try {
|
|
8515
|
+
names = await fs7.readdir(dir);
|
|
8516
|
+
} catch {
|
|
8517
|
+
continue;
|
|
8518
|
+
}
|
|
8519
|
+
let removed = 0;
|
|
8520
|
+
for (const name of names) {
|
|
8521
|
+
const target = path10.join(dir, name);
|
|
8522
|
+
try {
|
|
8523
|
+
const stat17 = await fs7.stat(target);
|
|
8524
|
+
if (stat17.isFile() && stat17.mtimeMs < cutoff) {
|
|
8525
|
+
await fs7.rm(target, { force: true });
|
|
8526
|
+
removed++;
|
|
8527
|
+
}
|
|
8528
|
+
} catch {
|
|
8529
|
+
}
|
|
8530
|
+
}
|
|
8531
|
+
if (removed === names.length && names.length > 0) {
|
|
8532
|
+
await fs7.rmdir(dir).catch(() => void 0);
|
|
8533
|
+
}
|
|
8534
|
+
}
|
|
8535
|
+
})();
|
|
8536
|
+
}
|
|
8457
8537
|
var BrowserArtifactStore = class {
|
|
8458
8538
|
constructor(root) {
|
|
8459
8539
|
this.root = root;
|
|
8540
|
+
sweepOldArtifacts(root);
|
|
8460
8541
|
}
|
|
8461
8542
|
root;
|
|
8462
8543
|
async write(sessionId, kind, extension, mimeType, content) {
|
|
@@ -9886,42 +9967,6 @@ import { expectDefined as expectDefined5 } from "@wrongstack/core/utils";
|
|
|
9886
9967
|
import * as fs14 from "node:fs";
|
|
9887
9968
|
import * as path21 from "node:path";
|
|
9888
9969
|
|
|
9889
|
-
// src/codebase-index/schema.ts
|
|
9890
|
-
var SCHEMA_VERSION = 3;
|
|
9891
|
-
|
|
9892
|
-
// src/codebase-index/lsp-kind.ts
|
|
9893
|
-
function lspKindToInternalKind(k) {
|
|
9894
|
-
switch (k) {
|
|
9895
|
-
case 5 /* Class */:
|
|
9896
|
-
return "class";
|
|
9897
|
-
case 6 /* Method */:
|
|
9898
|
-
return "method";
|
|
9899
|
-
case 7 /* Property */:
|
|
9900
|
-
case 8 /* Field */:
|
|
9901
|
-
return "property";
|
|
9902
|
-
case 9 /* Constructor */:
|
|
9903
|
-
return "class";
|
|
9904
|
-
case 10 /* Enum */:
|
|
9905
|
-
return "enum";
|
|
9906
|
-
case 11 /* Interface */:
|
|
9907
|
-
return "interface";
|
|
9908
|
-
case 12 /* Function */:
|
|
9909
|
-
return "function";
|
|
9910
|
-
case 13 /* Variable */:
|
|
9911
|
-
return "var";
|
|
9912
|
-
case 14 /* Constant */:
|
|
9913
|
-
return "const";
|
|
9914
|
-
case 22 /* EnumMember */:
|
|
9915
|
-
return "enum";
|
|
9916
|
-
case 26 /* TypeParameter */:
|
|
9917
|
-
return "type";
|
|
9918
|
-
case 3 /* Namespace */:
|
|
9919
|
-
return "namespace";
|
|
9920
|
-
default:
|
|
9921
|
-
return null;
|
|
9922
|
-
}
|
|
9923
|
-
}
|
|
9924
|
-
|
|
9925
9970
|
// src/codebase-index/bm25.ts
|
|
9926
9971
|
var K1 = 1.5;
|
|
9927
9972
|
var B = 0.75;
|
|
@@ -10011,6 +10056,42 @@ var Bm25Index = class {
|
|
|
10011
10056
|
}
|
|
10012
10057
|
};
|
|
10013
10058
|
|
|
10059
|
+
// src/codebase-index/lsp-kind.ts
|
|
10060
|
+
function lspKindToInternalKind(k) {
|
|
10061
|
+
switch (k) {
|
|
10062
|
+
case 5 /* Class */:
|
|
10063
|
+
return "class";
|
|
10064
|
+
case 6 /* Method */:
|
|
10065
|
+
return "method";
|
|
10066
|
+
case 7 /* Property */:
|
|
10067
|
+
case 8 /* Field */:
|
|
10068
|
+
return "property";
|
|
10069
|
+
case 9 /* Constructor */:
|
|
10070
|
+
return "class";
|
|
10071
|
+
case 10 /* Enum */:
|
|
10072
|
+
return "enum";
|
|
10073
|
+
case 11 /* Interface */:
|
|
10074
|
+
return "interface";
|
|
10075
|
+
case 12 /* Function */:
|
|
10076
|
+
return "function";
|
|
10077
|
+
case 13 /* Variable */:
|
|
10078
|
+
return "var";
|
|
10079
|
+
case 14 /* Constant */:
|
|
10080
|
+
return "const";
|
|
10081
|
+
case 22 /* EnumMember */:
|
|
10082
|
+
return "enum";
|
|
10083
|
+
case 26 /* TypeParameter */:
|
|
10084
|
+
return "type";
|
|
10085
|
+
case 3 /* Namespace */:
|
|
10086
|
+
return "namespace";
|
|
10087
|
+
default:
|
|
10088
|
+
return null;
|
|
10089
|
+
}
|
|
10090
|
+
}
|
|
10091
|
+
|
|
10092
|
+
// src/codebase-index/schema.ts
|
|
10093
|
+
var SCHEMA_VERSION = 3;
|
|
10094
|
+
|
|
10014
10095
|
// src/codebase-index/sqlite-runtime.ts
|
|
10015
10096
|
import { createRequire } from "node:module";
|
|
10016
10097
|
import { toErrorMessage as toErrorMessage2 } from "@wrongstack/core/utils";
|
|
@@ -10078,96 +10159,6 @@ function runSqliteWithRetry(fn) {
|
|
|
10078
10159
|
throw lastError;
|
|
10079
10160
|
}
|
|
10080
10161
|
|
|
10081
|
-
// src/codebase-index/writer-helpers.ts
|
|
10082
|
-
import { resolveWstackPaths as resolveWstackPaths2 } from "@wrongstack/core/utils";
|
|
10083
|
-
function escapeLike(value) {
|
|
10084
|
-
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
10085
|
-
}
|
|
10086
|
-
function assignRefsToSymbols(refs, symbols) {
|
|
10087
|
-
if (refs.length === 0 || symbols.length === 0) return [];
|
|
10088
|
-
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
10089
|
-
const seen = /* @__PURE__ */ new Set();
|
|
10090
|
-
const assigned = [];
|
|
10091
|
-
for (const ref of refs) {
|
|
10092
|
-
let owner2;
|
|
10093
|
-
for (const symbol of ordered) {
|
|
10094
|
-
if (symbol.line > ref.line) break;
|
|
10095
|
-
owner2 = symbol;
|
|
10096
|
-
}
|
|
10097
|
-
if (!owner2 && ref.callType === "import") owner2 = ordered[0];
|
|
10098
|
-
if (!owner2 || owner2.id <= 0) continue;
|
|
10099
|
-
const key = `${owner2.id}:${ref.toName}:${ref.callType}`;
|
|
10100
|
-
if (seen.has(key)) continue;
|
|
10101
|
-
seen.add(key);
|
|
10102
|
-
assigned.push({ ...ref, fromId: owner2.id });
|
|
10103
|
-
}
|
|
10104
|
-
return assigned;
|
|
10105
|
-
}
|
|
10106
|
-
function resolveIndexDir(projectRoot, override) {
|
|
10107
|
-
return override ?? resolveWstackPaths2({ projectRoot }).projectCodebaseIndex;
|
|
10108
|
-
}
|
|
10109
|
-
function codebaseIndexDirOverride(ctx) {
|
|
10110
|
-
const v = ctx.meta?.["codebaseIndexDir"];
|
|
10111
|
-
return typeof v === "string" ? v : void 0;
|
|
10112
|
-
}
|
|
10113
|
-
|
|
10114
|
-
// src/codebase-index/writer-schema.ts
|
|
10115
|
-
var METADATA_TABLE_SQL = `
|
|
10116
|
-
CREATE TABLE IF NOT EXISTS metadata (
|
|
10117
|
-
key TEXT PRIMARY KEY,
|
|
10118
|
-
value TEXT NOT NULL
|
|
10119
|
-
);
|
|
10120
|
-
`;
|
|
10121
|
-
var CORE_TABLES_SQL = `
|
|
10122
|
-
CREATE TABLE IF NOT EXISTS files (
|
|
10123
|
-
file TEXT PRIMARY KEY,
|
|
10124
|
-
lang TEXT NOT NULL,
|
|
10125
|
-
mtime_ms INTEGER NOT NULL,
|
|
10126
|
-
symbol_count INTEGER NOT NULL DEFAULT 0,
|
|
10127
|
-
last_indexed INTEGER NOT NULL
|
|
10128
|
-
);
|
|
10129
|
-
CREATE TABLE IF NOT EXISTS symbols (
|
|
10130
|
-
id INTEGER PRIMARY KEY,
|
|
10131
|
-
lang TEXT NOT NULL,
|
|
10132
|
-
kind TEXT NOT NULL,
|
|
10133
|
-
name TEXT NOT NULL,
|
|
10134
|
-
file TEXT NOT NULL,
|
|
10135
|
-
line INTEGER NOT NULL,
|
|
10136
|
-
col INTEGER NOT NULL,
|
|
10137
|
-
signature TEXT NOT NULL DEFAULT '',
|
|
10138
|
-
doc_comment TEXT NOT NULL DEFAULT '',
|
|
10139
|
-
scope TEXT NOT NULL DEFAULT '',
|
|
10140
|
-
text TEXT NOT NULL DEFAULT '',
|
|
10141
|
-
file_fk TEXT NOT NULL
|
|
10142
|
-
);
|
|
10143
|
-
`;
|
|
10144
|
-
var SYMBOL_INDEX_SQL = [
|
|
10145
|
-
"CREATE INDEX IF NOT EXISTS idx_s_name ON symbols(name)",
|
|
10146
|
-
"CREATE INDEX IF NOT EXISTS idx_s_kind ON symbols(kind)",
|
|
10147
|
-
"CREATE INDEX IF NOT EXISTS idx_s_lang ON symbols(lang)",
|
|
10148
|
-
"CREATE INDEX IF NOT EXISTS idx_s_file ON symbols(file)",
|
|
10149
|
-
"CREATE INDEX IF NOT EXISTS idx_s_lang_kind ON symbols(lang, kind)",
|
|
10150
|
-
"CREATE INDEX IF NOT EXISTS idx_s_file_fk ON symbols(file_fk)",
|
|
10151
|
-
"CREATE INDEX IF NOT EXISTS idx_s_name_id ON symbols(name, id)"
|
|
10152
|
-
];
|
|
10153
|
-
var REFS_TABLE_SQL = `
|
|
10154
|
-
CREATE TABLE IF NOT EXISTS refs (
|
|
10155
|
-
id INTEGER PRIMARY KEY,
|
|
10156
|
-
from_id INTEGER NOT NULL,
|
|
10157
|
-
to_name TEXT NOT NULL,
|
|
10158
|
-
to_id INTEGER,
|
|
10159
|
-
call_type TEXT NOT NULL,
|
|
10160
|
-
line INTEGER NOT NULL
|
|
10161
|
-
);
|
|
10162
|
-
`;
|
|
10163
|
-
var REFS_INDEX_SQL = [
|
|
10164
|
-
"CREATE INDEX IF NOT EXISTS idx_r_from ON refs(from_id)",
|
|
10165
|
-
"CREATE INDEX IF NOT EXISTS idx_r_to_id ON refs(to_id)",
|
|
10166
|
-
"CREATE INDEX IF NOT EXISTS idx_r_to_name ON refs(to_name)",
|
|
10167
|
-
"CREATE INDEX IF NOT EXISTS idx_r_call_type ON refs(call_type)"
|
|
10168
|
-
];
|
|
10169
|
-
var SYMBOLS_FTS_SQL = "CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(text, tokenize = 'unicode61')";
|
|
10170
|
-
|
|
10171
10162
|
// src/codebase-index/writer-admin.ts
|
|
10172
10163
|
import * as fs13 from "node:fs";
|
|
10173
10164
|
import * as path19 from "node:path";
|
|
@@ -10640,6 +10631,39 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
10640
10631
|
return { nodes, edges };
|
|
10641
10632
|
}
|
|
10642
10633
|
|
|
10634
|
+
// src/codebase-index/writer-helpers.ts
|
|
10635
|
+
import { resolveWstackPaths as resolveWstackPaths2 } from "@wrongstack/core/utils";
|
|
10636
|
+
function escapeLike(value) {
|
|
10637
|
+
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
10638
|
+
}
|
|
10639
|
+
function assignRefsToSymbols(refs, symbols) {
|
|
10640
|
+
if (refs.length === 0 || symbols.length === 0) return [];
|
|
10641
|
+
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
10642
|
+
const seen = /* @__PURE__ */ new Set();
|
|
10643
|
+
const assigned = [];
|
|
10644
|
+
for (const ref of refs) {
|
|
10645
|
+
let owner2;
|
|
10646
|
+
for (const symbol of ordered) {
|
|
10647
|
+
if (symbol.line > ref.line) break;
|
|
10648
|
+
owner2 = symbol;
|
|
10649
|
+
}
|
|
10650
|
+
if (!owner2 && ref.callType === "import") owner2 = ordered[0];
|
|
10651
|
+
if (!owner2 || owner2.id <= 0) continue;
|
|
10652
|
+
const key = `${owner2.id}:${ref.toName}:${ref.callType}`;
|
|
10653
|
+
if (seen.has(key)) continue;
|
|
10654
|
+
seen.add(key);
|
|
10655
|
+
assigned.push({ ...ref, fromId: owner2.id });
|
|
10656
|
+
}
|
|
10657
|
+
return assigned;
|
|
10658
|
+
}
|
|
10659
|
+
function resolveIndexDir(projectRoot, override) {
|
|
10660
|
+
return override ?? resolveWstackPaths2({ projectRoot }).projectCodebaseIndex;
|
|
10661
|
+
}
|
|
10662
|
+
function codebaseIndexDirOverride(ctx) {
|
|
10663
|
+
const v = ctx.meta?.["codebaseIndexDir"];
|
|
10664
|
+
return typeof v === "string" ? v : void 0;
|
|
10665
|
+
}
|
|
10666
|
+
|
|
10643
10667
|
// src/codebase-index/writer-pragmas.ts
|
|
10644
10668
|
import { sqliteCachePragmas } from "@wrongstack/core/utils";
|
|
10645
10669
|
function applyIndexStorePragmas(db) {
|
|
@@ -10658,6 +10682,63 @@ function applyIndexStorePragmas(db) {
|
|
|
10658
10682
|
}
|
|
10659
10683
|
}
|
|
10660
10684
|
|
|
10685
|
+
// src/codebase-index/writer-schema.ts
|
|
10686
|
+
var METADATA_TABLE_SQL = `
|
|
10687
|
+
CREATE TABLE IF NOT EXISTS metadata (
|
|
10688
|
+
key TEXT PRIMARY KEY,
|
|
10689
|
+
value TEXT NOT NULL
|
|
10690
|
+
);
|
|
10691
|
+
`;
|
|
10692
|
+
var CORE_TABLES_SQL = `
|
|
10693
|
+
CREATE TABLE IF NOT EXISTS files (
|
|
10694
|
+
file TEXT PRIMARY KEY,
|
|
10695
|
+
lang TEXT NOT NULL,
|
|
10696
|
+
mtime_ms INTEGER NOT NULL,
|
|
10697
|
+
symbol_count INTEGER NOT NULL DEFAULT 0,
|
|
10698
|
+
last_indexed INTEGER NOT NULL
|
|
10699
|
+
);
|
|
10700
|
+
CREATE TABLE IF NOT EXISTS symbols (
|
|
10701
|
+
id INTEGER PRIMARY KEY,
|
|
10702
|
+
lang TEXT NOT NULL,
|
|
10703
|
+
kind TEXT NOT NULL,
|
|
10704
|
+
name TEXT NOT NULL,
|
|
10705
|
+
file TEXT NOT NULL,
|
|
10706
|
+
line INTEGER NOT NULL,
|
|
10707
|
+
col INTEGER NOT NULL,
|
|
10708
|
+
signature TEXT NOT NULL DEFAULT '',
|
|
10709
|
+
doc_comment TEXT NOT NULL DEFAULT '',
|
|
10710
|
+
scope TEXT NOT NULL DEFAULT '',
|
|
10711
|
+
text TEXT NOT NULL DEFAULT '',
|
|
10712
|
+
file_fk TEXT NOT NULL
|
|
10713
|
+
);
|
|
10714
|
+
`;
|
|
10715
|
+
var SYMBOL_INDEX_SQL = [
|
|
10716
|
+
"CREATE INDEX IF NOT EXISTS idx_s_name ON symbols(name)",
|
|
10717
|
+
"CREATE INDEX IF NOT EXISTS idx_s_kind ON symbols(kind)",
|
|
10718
|
+
"CREATE INDEX IF NOT EXISTS idx_s_lang ON symbols(lang)",
|
|
10719
|
+
"CREATE INDEX IF NOT EXISTS idx_s_file ON symbols(file)",
|
|
10720
|
+
"CREATE INDEX IF NOT EXISTS idx_s_lang_kind ON symbols(lang, kind)",
|
|
10721
|
+
"CREATE INDEX IF NOT EXISTS idx_s_file_fk ON symbols(file_fk)",
|
|
10722
|
+
"CREATE INDEX IF NOT EXISTS idx_s_name_id ON symbols(name, id)"
|
|
10723
|
+
];
|
|
10724
|
+
var REFS_TABLE_SQL = `
|
|
10725
|
+
CREATE TABLE IF NOT EXISTS refs (
|
|
10726
|
+
id INTEGER PRIMARY KEY,
|
|
10727
|
+
from_id INTEGER NOT NULL,
|
|
10728
|
+
to_name TEXT NOT NULL,
|
|
10729
|
+
to_id INTEGER,
|
|
10730
|
+
call_type TEXT NOT NULL,
|
|
10731
|
+
line INTEGER NOT NULL
|
|
10732
|
+
);
|
|
10733
|
+
`;
|
|
10734
|
+
var REFS_INDEX_SQL = [
|
|
10735
|
+
"CREATE INDEX IF NOT EXISTS idx_r_from ON refs(from_id)",
|
|
10736
|
+
"CREATE INDEX IF NOT EXISTS idx_r_to_id ON refs(to_id)",
|
|
10737
|
+
"CREATE INDEX IF NOT EXISTS idx_r_to_name ON refs(to_name)",
|
|
10738
|
+
"CREATE INDEX IF NOT EXISTS idx_r_call_type ON refs(call_type)"
|
|
10739
|
+
];
|
|
10740
|
+
var SYMBOLS_FTS_SQL = "CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(text, tokenize = 'unicode61')";
|
|
10741
|
+
|
|
10661
10742
|
// src/codebase-index/writer-search-helpers.ts
|
|
10662
10743
|
function normalizeSearchLimit(limit) {
|
|
10663
10744
|
return typeof limit === "number" && Number.isFinite(limit) ? Math.max(0, Math.trunc(limit)) : void 0;
|
|
@@ -10866,9 +10947,15 @@ var IndexStore = class _IndexStore {
|
|
|
10866
10947
|
DROP TABLE IF EXISTS refs;
|
|
10867
10948
|
`);
|
|
10868
10949
|
this.db.exec("DROP TABLE IF EXISTS symbols_fts");
|
|
10869
|
-
this.stmt("UPDATE metadata SET value = ? WHERE key = ?").run(
|
|
10950
|
+
this.stmt("UPDATE metadata SET value = ? WHERE key = ?").run(
|
|
10951
|
+
String(SCHEMA_VERSION),
|
|
10952
|
+
"version"
|
|
10953
|
+
);
|
|
10870
10954
|
} else if (storedVersion === null) {
|
|
10871
|
-
this.stmt("INSERT INTO metadata(key, value) VALUES (?, ?)").run(
|
|
10955
|
+
this.stmt("INSERT INTO metadata(key, value) VALUES (?, ?)").run(
|
|
10956
|
+
"version",
|
|
10957
|
+
String(SCHEMA_VERSION)
|
|
10958
|
+
);
|
|
10872
10959
|
}
|
|
10873
10960
|
this.db.exec(CORE_TABLES_SQL);
|
|
10874
10961
|
for (const sql of SYMBOL_INDEX_SQL) this.db.exec(sql);
|
|
@@ -10885,7 +10972,9 @@ var IndexStore = class _IndexStore {
|
|
|
10885
10972
|
);
|
|
10886
10973
|
if (symbolCount !== ftsCount) {
|
|
10887
10974
|
this.db.exec("DELETE FROM symbols_fts");
|
|
10888
|
-
const rows = this.stmt(
|
|
10975
|
+
const rows = this.stmt(
|
|
10976
|
+
"SELECT id, name, signature, doc_comment FROM symbols ORDER BY id"
|
|
10977
|
+
).all();
|
|
10889
10978
|
bulkInsertFtsWithStatement(
|
|
10890
10979
|
(sql) => this.stmt(sql),
|
|
10891
10980
|
_IndexStore.MAX_SQL_VARS,
|
|
@@ -11107,7 +11196,9 @@ var IndexStore = class _IndexStore {
|
|
|
11107
11196
|
const limitSql = limit !== void 0 ? " LIMIT ?" : "";
|
|
11108
11197
|
const sql = `SELECT id, lang, kind, name, file, line, col, signature, doc_comment, text FROM symbols ${where}${limitSql}`;
|
|
11109
11198
|
const binds = limit !== void 0 ? [...values, limit] : values;
|
|
11110
|
-
const rows = this.stmt(sql).all(
|
|
11199
|
+
const rows = this.stmt(sql).all(
|
|
11200
|
+
...binds
|
|
11201
|
+
);
|
|
11111
11202
|
return rows.map((row) => mapWriterSearchRow(row, filter?.lspKind));
|
|
11112
11203
|
}
|
|
11113
11204
|
/** Shared WHERE builder for {@link search} / empty-query ranked totals. */
|
|
@@ -11283,7 +11374,9 @@ var IndexStore = class _IndexStore {
|
|
|
11283
11374
|
}
|
|
11284
11375
|
setLastIndexed(ts2) {
|
|
11285
11376
|
this.runWithRetry(() => {
|
|
11286
|
-
this.stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES('last_indexed', ?)").run(
|
|
11377
|
+
this.stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES('last_indexed', ?)").run(
|
|
11378
|
+
String(ts2)
|
|
11379
|
+
);
|
|
11287
11380
|
});
|
|
11288
11381
|
}
|
|
11289
11382
|
getMetadata(key) {
|
|
@@ -11394,7 +11487,9 @@ var IndexStore = class _IndexStore {
|
|
|
11394
11487
|
this.stmt(
|
|
11395
11488
|
`DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file IN (${placeholders}))`
|
|
11396
11489
|
).run(...options.deleteForFiles);
|
|
11397
|
-
this.stmt(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(
|
|
11490
|
+
this.stmt(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(
|
|
11491
|
+
...options.deleteForFiles
|
|
11492
|
+
);
|
|
11398
11493
|
}
|
|
11399
11494
|
const totalSymbols = entries.reduce((n, e) => n + e.symbols.length, 0);
|
|
11400
11495
|
let nextId = this.allocateSymbolIds(totalSymbols);
|
|
@@ -11438,11 +11533,7 @@ var IndexStore = class _IndexStore {
|
|
|
11438
11533
|
this.ftsAvailable,
|
|
11439
11534
|
ftsRows
|
|
11440
11535
|
);
|
|
11441
|
-
bulkInsertRefsWithStatement(
|
|
11442
|
-
(sql) => this.stmt(sql),
|
|
11443
|
-
_IndexStore.MAX_SQL_VARS,
|
|
11444
|
-
refsToInsert
|
|
11445
|
-
);
|
|
11536
|
+
bulkInsertRefsWithStatement((sql) => this.stmt(sql), _IndexStore.MAX_SQL_VARS, refsToInsert);
|
|
11446
11537
|
const upsertStmt = this.stmt(
|
|
11447
11538
|
`INSERT INTO files(file, lang, mtime_ms, symbol_count, last_indexed)
|
|
11448
11539
|
VALUES (?, ?, ?, ?, ?)
|
|
@@ -11471,7 +11562,9 @@ var IndexStore = class _IndexStore {
|
|
|
11471
11562
|
*/
|
|
11472
11563
|
deleteRefsForFile(file) {
|
|
11473
11564
|
this.runWithRetry(() => {
|
|
11474
|
-
this.stmt("DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file = ?)").run(
|
|
11565
|
+
this.stmt("DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file = ?)").run(
|
|
11566
|
+
file
|
|
11567
|
+
);
|
|
11475
11568
|
});
|
|
11476
11569
|
}
|
|
11477
11570
|
/**
|
|
@@ -11626,9 +11719,7 @@ var IndexStore = class _IndexStore {
|
|
|
11626
11719
|
* build the full symbol universe for the reachability scan.
|
|
11627
11720
|
*/
|
|
11628
11721
|
getAllSymbols() {
|
|
11629
|
-
return this.stmt(
|
|
11630
|
-
"SELECT id, name, file, kind, line FROM symbols ORDER BY id"
|
|
11631
|
-
).all().map((r) => ({ ...r, kind: r.kind }));
|
|
11722
|
+
return this.stmt("SELECT id, name, file, kind, line FROM symbols ORDER BY id").all().map((r) => ({ ...r, kind: r.kind }));
|
|
11632
11723
|
}
|
|
11633
11724
|
/**
|
|
11634
11725
|
* Returns every resolved reference (to_id IS NOT NULL). Used by
|
|
@@ -11640,6 +11731,25 @@ var IndexStore = class _IndexStore {
|
|
|
11640
11731
|
"SELECT from_id AS fromId, to_id AS toId, call_type AS callType FROM refs WHERE to_id IS NOT NULL"
|
|
11641
11732
|
).all();
|
|
11642
11733
|
}
|
|
11734
|
+
/**
|
|
11735
|
+
* Returns ALL import refs (including unresolved) with their source-file
|
|
11736
|
+
* path and resolved target id. Used by the dead-code scan's file-level
|
|
11737
|
+
* graph traversal to handle barrel-only entry points where no symbol
|
|
11738
|
+
* carries the ref.
|
|
11739
|
+
*
|
|
11740
|
+
* Refs whose `from_id` doesn't match a known symbol (e.g. pure-barrel
|
|
11741
|
+
* files with no declarations) will have `sourceFile === null`.
|
|
11742
|
+
*/
|
|
11743
|
+
getAllImportRefs() {
|
|
11744
|
+
return this.stmt(
|
|
11745
|
+
`SELECT s.file AS sourceFile, r.to_name AS toName, r.to_id AS toId,
|
|
11746
|
+
r.call_type AS callType, r.line
|
|
11747
|
+
FROM refs r
|
|
11748
|
+
LEFT JOIN symbols s ON r.from_id = s.id
|
|
11749
|
+
WHERE r.call_type = 'import'
|
|
11750
|
+
ORDER BY r.line`
|
|
11751
|
+
).all();
|
|
11752
|
+
}
|
|
11643
11753
|
close() {
|
|
11644
11754
|
this.stmtCache.clear();
|
|
11645
11755
|
this.bm25Dirty = true;
|
|
@@ -13349,6 +13459,7 @@ var codebaseStatsTool = {
|
|
|
13349
13459
|
};
|
|
13350
13460
|
|
|
13351
13461
|
// src/codebase-index/dead-code-scan.ts
|
|
13462
|
+
init_languages2();
|
|
13352
13463
|
import * as fs19 from "node:fs";
|
|
13353
13464
|
import * as path24 from "node:path";
|
|
13354
13465
|
var deadCodeScanTool = {
|
|
@@ -13417,7 +13528,15 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
|
|
|
13417
13528
|
if (rootPkg) {
|
|
13418
13529
|
addPkgJsonEntryPoints(projectRoot, rootPkg, entries);
|
|
13419
13530
|
}
|
|
13420
|
-
|
|
13531
|
+
let workspaces;
|
|
13532
|
+
if (rootPkg) {
|
|
13533
|
+
workspaces = extractWorkspaceGlobs(rootPkg, projectRoot);
|
|
13534
|
+
if (workspaces.length === 0) {
|
|
13535
|
+
workspaces = extractPnpmWorkspaceDirs(projectRoot);
|
|
13536
|
+
}
|
|
13537
|
+
} else {
|
|
13538
|
+
workspaces = [];
|
|
13539
|
+
}
|
|
13421
13540
|
for (const wsDir of workspaces) {
|
|
13422
13541
|
const pkgJsonPath = path24.join(wsDir, "package.json");
|
|
13423
13542
|
const pkg = tryReadJson(pkgJsonPath);
|
|
@@ -13439,77 +13558,189 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
|
|
|
13439
13558
|
}
|
|
13440
13559
|
return [...entries];
|
|
13441
13560
|
}
|
|
13561
|
+
var BUILD_OUTPUT_DIRS = ["dist", "out", "build", "release"];
|
|
13562
|
+
var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path24.sep}${d}${path24.sep}`);
|
|
13563
|
+
function trySourceEquivalent(resolved) {
|
|
13564
|
+
resolved = resolved.replace(/[/\\]/g, path24.sep);
|
|
13565
|
+
for (const marker of BUILD_OUTPUT_DIR_NAMES) {
|
|
13566
|
+
const idx = resolved.indexOf(marker);
|
|
13567
|
+
if (idx === -1) continue;
|
|
13568
|
+
const base = resolved.replace(marker, `${path24.sep}src${path24.sep}`);
|
|
13569
|
+
const candidate = base.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
13570
|
+
if (candidate !== base && fs19.existsSync(candidate)) {
|
|
13571
|
+
return candidate;
|
|
13572
|
+
}
|
|
13573
|
+
const dtsStripped = base.replace(/\.d\.ts$/, "");
|
|
13574
|
+
const candidateDts = dtsStripped + ".ts";
|
|
13575
|
+
if (candidateDts !== base && candidateDts !== candidate && fs19.existsSync(candidateDts)) {
|
|
13576
|
+
return candidateDts;
|
|
13577
|
+
}
|
|
13578
|
+
const candidateNoExt = base + ".ts";
|
|
13579
|
+
if (candidate !== candidateNoExt && candidateNoExt !== candidateDts && fs19.existsSync(candidateNoExt)) {
|
|
13580
|
+
return candidateNoExt;
|
|
13581
|
+
}
|
|
13582
|
+
}
|
|
13583
|
+
return null;
|
|
13584
|
+
}
|
|
13585
|
+
function tryAddEntryPath(pkgDir, rawPath, entries) {
|
|
13586
|
+
const resolved = resolveAgainst(pkgDir, rawPath);
|
|
13587
|
+
if (fs19.existsSync(resolved)) entries.add(resolved);
|
|
13588
|
+
const tsResolved = resolved.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
13589
|
+
if (tsResolved !== resolved && fs19.existsSync(tsResolved)) {
|
|
13590
|
+
entries.add(tsResolved);
|
|
13591
|
+
}
|
|
13592
|
+
const srcAlt = trySourceEquivalent(resolved);
|
|
13593
|
+
if (srcAlt) entries.add(srcAlt);
|
|
13594
|
+
}
|
|
13442
13595
|
function addPkgJsonEntryPoints(pkgDir, pkg, entries) {
|
|
13443
13596
|
if (typeof pkg.main === "string") {
|
|
13444
|
-
|
|
13445
|
-
if (fs19.existsSync(resolved)) entries.add(resolved);
|
|
13446
|
-
const tsResolved = resolved.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
13447
|
-
if (tsResolved !== resolved && fs19.existsSync(tsResolved)) {
|
|
13448
|
-
entries.add(tsResolved);
|
|
13449
|
-
}
|
|
13597
|
+
tryAddEntryPath(pkgDir, pkg.main, entries);
|
|
13450
13598
|
}
|
|
13451
13599
|
const bin = pkg.bin;
|
|
13452
13600
|
if (typeof bin === "string") {
|
|
13453
|
-
|
|
13454
|
-
if (fs19.existsSync(resolved)) entries.add(resolved);
|
|
13601
|
+
tryAddEntryPath(pkgDir, bin, entries);
|
|
13455
13602
|
} else if (bin && typeof bin === "object") {
|
|
13456
13603
|
for (const value of Object.values(bin)) {
|
|
13457
13604
|
if (typeof value === "string") {
|
|
13458
|
-
|
|
13459
|
-
if (fs19.existsSync(resolved)) entries.add(resolved);
|
|
13605
|
+
tryAddEntryPath(pkgDir, value, entries);
|
|
13460
13606
|
}
|
|
13461
13607
|
}
|
|
13462
13608
|
}
|
|
13463
13609
|
for (const key of ["types", "typings"]) {
|
|
13464
13610
|
if (typeof pkg[key] === "string") {
|
|
13465
|
-
|
|
13466
|
-
if (fs19.existsSync(resolved)) entries.add(resolved);
|
|
13611
|
+
tryAddEntryPath(pkgDir, pkg[key], entries);
|
|
13467
13612
|
}
|
|
13468
13613
|
}
|
|
13469
13614
|
const exports_ = pkg.exports;
|
|
13470
13615
|
if (exports_ && typeof exports_ === "object") {
|
|
13471
13616
|
for (const value of Object.values(exports_)) {
|
|
13472
13617
|
if (typeof value === "string") {
|
|
13473
|
-
|
|
13474
|
-
if (fs19.existsSync(resolved)) entries.add(resolved);
|
|
13618
|
+
tryAddEntryPath(pkgDir, value, entries);
|
|
13475
13619
|
} else if (value && typeof value === "object") {
|
|
13476
|
-
for (const nested of Object.values(
|
|
13477
|
-
value
|
|
13478
|
-
)) {
|
|
13620
|
+
for (const nested of Object.values(value)) {
|
|
13479
13621
|
if (typeof nested === "string") {
|
|
13480
|
-
|
|
13481
|
-
if (fs19.existsSync(resolved)) entries.add(resolved);
|
|
13622
|
+
tryAddEntryPath(pkgDir, nested, entries);
|
|
13482
13623
|
}
|
|
13483
13624
|
}
|
|
13484
13625
|
}
|
|
13485
13626
|
}
|
|
13486
13627
|
}
|
|
13487
13628
|
}
|
|
13629
|
+
function expandGlobPattern(entry, projectRoot) {
|
|
13630
|
+
const dirs = [];
|
|
13631
|
+
if (entry.includes("*")) {
|
|
13632
|
+
const base = entry.replace(/\/\*+$/, "");
|
|
13633
|
+
const baseDir = path24.resolve(projectRoot, base);
|
|
13634
|
+
try {
|
|
13635
|
+
const children = fs19.readdirSync(baseDir, { withFileTypes: true });
|
|
13636
|
+
for (const child of children) {
|
|
13637
|
+
if (child.isDirectory()) {
|
|
13638
|
+
dirs.push(path24.join(baseDir, child.name));
|
|
13639
|
+
}
|
|
13640
|
+
}
|
|
13641
|
+
} catch {
|
|
13642
|
+
}
|
|
13643
|
+
} else {
|
|
13644
|
+
dirs.push(path24.resolve(projectRoot, entry));
|
|
13645
|
+
}
|
|
13646
|
+
return dirs;
|
|
13647
|
+
}
|
|
13488
13648
|
function extractWorkspaceGlobs(pkg, projectRoot) {
|
|
13489
13649
|
const dirs = [];
|
|
13490
13650
|
const workspaces = pkg.workspaces;
|
|
13491
13651
|
if (Array.isArray(workspaces)) {
|
|
13492
13652
|
for (const entry of workspaces) {
|
|
13493
13653
|
if (typeof entry === "string") {
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13501
|
-
|
|
13502
|
-
|
|
13503
|
-
|
|
13504
|
-
|
|
13654
|
+
dirs.push(...expandGlobPattern(entry, projectRoot));
|
|
13655
|
+
}
|
|
13656
|
+
}
|
|
13657
|
+
}
|
|
13658
|
+
return dirs;
|
|
13659
|
+
}
|
|
13660
|
+
function extractPnpmWorkspaceDirs(projectRoot) {
|
|
13661
|
+
const yamlPath = path24.join(projectRoot, "pnpm-workspace.yaml");
|
|
13662
|
+
if (!fs19.existsSync(yamlPath)) return [];
|
|
13663
|
+
try {
|
|
13664
|
+
const content = fs19.readFileSync(yamlPath, "utf8");
|
|
13665
|
+
const dirs = [];
|
|
13666
|
+
let inPackages = false;
|
|
13667
|
+
const lines = content.split("\n");
|
|
13668
|
+
const itemRe = /^\s+-\s+"([^"]+)"|^\s+-\s+'([^']+)'|^\s+-\s+(\S+)/;
|
|
13669
|
+
for (const line of lines) {
|
|
13670
|
+
const trimmed = line.trim();
|
|
13671
|
+
if (/^packages\s*:\s*$/.test(trimmed)) {
|
|
13672
|
+
inPackages = true;
|
|
13673
|
+
continue;
|
|
13674
|
+
}
|
|
13675
|
+
if (inPackages && trimmed.length > 0 && !line.startsWith(" ") && !line.startsWith(" ")) {
|
|
13676
|
+
if (!trimmed.startsWith("-")) {
|
|
13677
|
+
inPackages = false;
|
|
13678
|
+
continue;
|
|
13679
|
+
}
|
|
13680
|
+
}
|
|
13681
|
+
if (inPackages) {
|
|
13682
|
+
const m = itemRe.exec(line);
|
|
13683
|
+
if (m) {
|
|
13684
|
+
const entry = m[1] ?? m[2] ?? m[3];
|
|
13685
|
+
if (entry) {
|
|
13686
|
+
dirs.push(...expandGlobPattern(entry, projectRoot));
|
|
13505
13687
|
}
|
|
13506
|
-
} else {
|
|
13507
|
-
dirs.push(path24.resolve(projectRoot, entry));
|
|
13508
13688
|
}
|
|
13509
13689
|
}
|
|
13510
13690
|
}
|
|
13691
|
+
return dirs;
|
|
13692
|
+
} catch {
|
|
13693
|
+
return [];
|
|
13694
|
+
}
|
|
13695
|
+
}
|
|
13696
|
+
function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
|
|
13697
|
+
if (!moduleSpecifier.startsWith(".")) return [];
|
|
13698
|
+
const dir = path24.dirname(importerPath);
|
|
13699
|
+
const base = path24.resolve(dir, moduleSpecifier);
|
|
13700
|
+
const results = [];
|
|
13701
|
+
const stripped = base.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
13702
|
+
const skipBase = stripped !== base && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(base);
|
|
13703
|
+
const candidates = skipBase ? [stripped] : [base];
|
|
13704
|
+
for (const candidate of candidates) {
|
|
13705
|
+
if (indexedFiles.has(candidate + ".ts")) results.push(candidate + ".ts");
|
|
13706
|
+
if (indexedFiles.has(candidate + ".tsx")) results.push(candidate + ".tsx");
|
|
13707
|
+
if (indexedFiles.has(candidate + ".js")) results.push(candidate + ".js");
|
|
13708
|
+
if (indexedFiles.has(candidate + ".jsx")) results.push(candidate + ".jsx");
|
|
13709
|
+
if (indexedFiles.has(candidate + ".mjs")) results.push(candidate + ".mjs");
|
|
13710
|
+
if (indexedFiles.has(candidate + ".cjs")) results.push(candidate + ".cjs");
|
|
13711
|
+
if (indexedFiles.has(path24.join(candidate, "index.ts")))
|
|
13712
|
+
results.push(path24.join(candidate, "index.ts"));
|
|
13713
|
+
if (indexedFiles.has(path24.join(candidate, "index.tsx")))
|
|
13714
|
+
results.push(path24.join(candidate, "index.tsx"));
|
|
13715
|
+
if (indexedFiles.has(path24.join(candidate, "index.js")))
|
|
13716
|
+
results.push(path24.join(candidate, "index.js"));
|
|
13717
|
+
if (indexedFiles.has(path24.join(candidate, "index.jsx")))
|
|
13718
|
+
results.push(path24.join(candidate, "index.jsx"));
|
|
13719
|
+
if (indexedFiles.has(path24.join(candidate, "index.mjs")))
|
|
13720
|
+
results.push(path24.join(candidate, "index.mjs"));
|
|
13721
|
+
if (indexedFiles.has(path24.join(candidate, "index.cjs")))
|
|
13722
|
+
results.push(path24.join(candidate, "index.cjs"));
|
|
13723
|
+
}
|
|
13724
|
+
return [...new Set(results)];
|
|
13725
|
+
}
|
|
13726
|
+
function parseNamedExportSymbols(matchText) {
|
|
13727
|
+
const braceStart = matchText.indexOf("{");
|
|
13728
|
+
if (braceStart === -1) return null;
|
|
13729
|
+
const braceEnd = matchText.indexOf("}", braceStart);
|
|
13730
|
+
if (braceEnd === -1) return null;
|
|
13731
|
+
const inner = matchText.slice(braceStart + 1, braceEnd);
|
|
13732
|
+
const symbols = [];
|
|
13733
|
+
for (const part of inner.split(",")) {
|
|
13734
|
+
let s = part.trim();
|
|
13735
|
+
if (!s) continue;
|
|
13736
|
+
s = s.replace(/^type\s+/, "");
|
|
13737
|
+
const asIdx = s.search(/\s+as\s+/);
|
|
13738
|
+
if (asIdx !== -1) {
|
|
13739
|
+
s = s.slice(0, asIdx).trim();
|
|
13740
|
+
}
|
|
13741
|
+
if (s) symbols.push(s);
|
|
13511
13742
|
}
|
|
13512
|
-
return
|
|
13743
|
+
return symbols;
|
|
13513
13744
|
}
|
|
13514
13745
|
function runDeadCodeScan(projectRoot, opts = {}) {
|
|
13515
13746
|
const store = opts.store ?? indexStorePool.acquire(projectRoot, { indexDir: opts.indexDir });
|
|
@@ -13531,12 +13762,71 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
13531
13762
|
}
|
|
13532
13763
|
const discoveredFiles = discoverEntryPoints(projectRoot, opts.userEntryPoints);
|
|
13533
13764
|
const entryFileSet = new Set(discoveredFiles.map((f) => path24.resolve(f)));
|
|
13765
|
+
const indexedFiles = /* @__PURE__ */ new Set();
|
|
13766
|
+
for (const s of allSymbols) indexedFiles.add(s.file);
|
|
13767
|
+
for (const fm of store.getAllFileMetas()) indexedFiles.add(fm.file);
|
|
13534
13768
|
const seedIds = /* @__PURE__ */ new Set();
|
|
13535
13769
|
for (const s of allSymbols) {
|
|
13536
13770
|
if (entryFileSet.has(s.file)) {
|
|
13537
13771
|
seedIds.add(s.id);
|
|
13538
13772
|
}
|
|
13539
13773
|
}
|
|
13774
|
+
const fileToSymbolIds = /* @__PURE__ */ new Map();
|
|
13775
|
+
for (const s of allSymbols) {
|
|
13776
|
+
let byFile = fileToSymbolIds.get(s.file);
|
|
13777
|
+
if (!byFile) {
|
|
13778
|
+
byFile = [];
|
|
13779
|
+
fileToSymbolIds.set(s.file, byFile);
|
|
13780
|
+
}
|
|
13781
|
+
byFile.push(s.id);
|
|
13782
|
+
}
|
|
13783
|
+
const scannedBarrels = /* @__PURE__ */ new Set();
|
|
13784
|
+
const barrelWorkList = [...entryFileSet];
|
|
13785
|
+
while (barrelWorkList.length > 0) {
|
|
13786
|
+
const epFile = barrelWorkList.pop();
|
|
13787
|
+
if (scannedBarrels.has(epFile)) continue;
|
|
13788
|
+
scannedBarrels.add(epFile);
|
|
13789
|
+
try {
|
|
13790
|
+
const content = fs19.readFileSync(epFile, "utf8");
|
|
13791
|
+
const strippedContent = content.replace(/\/\*[\s\S]*?\*\//g, (m) => " ".repeat(m.length)).replace(/\/\/[^\n]*/g, (m) => " ".repeat(m.length));
|
|
13792
|
+
const reExportRe = /export\s+(?:(?:type\s+)?\{[\s\S]*?\}\s+from|\*\s+as\s+\w+\s+from|\*\s+from)\s+['"]([^'"]+)['"]/g;
|
|
13793
|
+
let match;
|
|
13794
|
+
while ((match = reExportRe.exec(strippedContent)) !== null) {
|
|
13795
|
+
const moduleSpec = match[1];
|
|
13796
|
+
const resolvedFiles = resolveModulePath(epFile, moduleSpec, indexedFiles);
|
|
13797
|
+
for (const rf of resolvedFiles) {
|
|
13798
|
+
const fileSyms = fileToSymbolIds.get(rf);
|
|
13799
|
+
if (fileSyms) {
|
|
13800
|
+
const namedSymbols = parseNamedExportSymbols(match[0]);
|
|
13801
|
+
if (namedSymbols) {
|
|
13802
|
+
const nameSet = new Set(namedSymbols);
|
|
13803
|
+
for (const sid of fileSyms) {
|
|
13804
|
+
const sym = symbolById.get(sid);
|
|
13805
|
+
if (sym && nameSet.has(sym.name)) seedIds.add(sid);
|
|
13806
|
+
}
|
|
13807
|
+
} else {
|
|
13808
|
+
for (const sid of fileSyms) seedIds.add(sid);
|
|
13809
|
+
}
|
|
13810
|
+
}
|
|
13811
|
+
if (!scannedBarrels.has(rf)) {
|
|
13812
|
+
barrelWorkList.push(rf);
|
|
13813
|
+
}
|
|
13814
|
+
}
|
|
13815
|
+
}
|
|
13816
|
+
} catch (err) {
|
|
13817
|
+
if (err instanceof Error && err.code !== "ENOENT") {
|
|
13818
|
+
console.warn(
|
|
13819
|
+
JSON.stringify({
|
|
13820
|
+
level: "warn",
|
|
13821
|
+
event: "dead_code_scan_barrel_read_failed",
|
|
13822
|
+
message: err.message,
|
|
13823
|
+
file: epFile,
|
|
13824
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
13825
|
+
})
|
|
13826
|
+
);
|
|
13827
|
+
}
|
|
13828
|
+
}
|
|
13829
|
+
}
|
|
13540
13830
|
const alive = new Set(seedIds);
|
|
13541
13831
|
const frontier = [...seedIds];
|
|
13542
13832
|
const visitedEdges = /* @__PURE__ */ new Set();
|
|
@@ -13570,8 +13860,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
13570
13860
|
dead.push({
|
|
13571
13861
|
name: s.name,
|
|
13572
13862
|
kind: s.kind,
|
|
13573
|
-
lang: "ts",
|
|
13574
|
-
// populated from symbol file metadata
|
|
13863
|
+
lang: detectLang(s.file) ?? "ts",
|
|
13575
13864
|
file: s.file,
|
|
13576
13865
|
line: s.line,
|
|
13577
13866
|
reason
|
|
@@ -13596,16 +13885,14 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
13596
13885
|
deadFiles.push({
|
|
13597
13886
|
file,
|
|
13598
13887
|
symbolCount: syms.length,
|
|
13599
|
-
lang:
|
|
13888
|
+
lang: detectLang(file) ?? "ts"
|
|
13600
13889
|
});
|
|
13601
13890
|
}
|
|
13602
13891
|
}
|
|
13603
13892
|
const deadPackages = [];
|
|
13604
13893
|
const pkgEntries = findPackageEntries(projectRoot);
|
|
13605
13894
|
for (const [pkgName, pkgDir] of pkgEntries) {
|
|
13606
|
-
const pkgFiles = allSymbols.filter(
|
|
13607
|
-
(s) => s.file.startsWith(pkgDir + path24.sep)
|
|
13608
|
-
);
|
|
13895
|
+
const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path24.sep));
|
|
13609
13896
|
if (pkgFiles.length === 0) continue;
|
|
13610
13897
|
const pkgUsed = pkgFiles.filter((s) => alive.has(s.id));
|
|
13611
13898
|
if (pkgUsed.length === 0) {
|
|
@@ -13646,7 +13933,10 @@ function findPackageEntries(projectRoot) {
|
|
|
13646
13933
|
pkgMap.set(rootPkg.name, projectRoot);
|
|
13647
13934
|
}
|
|
13648
13935
|
if (rootPkg) {
|
|
13649
|
-
|
|
13936
|
+
let wsDirs = extractWorkspaceGlobs(rootPkg, projectRoot);
|
|
13937
|
+
if (wsDirs.length === 0) {
|
|
13938
|
+
wsDirs = extractPnpmWorkspaceDirs(projectRoot);
|
|
13939
|
+
}
|
|
13650
13940
|
for (const wsDir of wsDirs) {
|
|
13651
13941
|
const wsPkg = tryReadJson(path24.join(wsDir, "package.json"));
|
|
13652
13942
|
if (wsPkg && typeof wsPkg.name === "string") {
|
|
@@ -14263,7 +14553,7 @@ function processFile(content, absPath, _style, _overwrite, target) {
|
|
|
14263
14553
|
|
|
14264
14554
|
// src/e2e.ts
|
|
14265
14555
|
init_util();
|
|
14266
|
-
import { open, readdir as
|
|
14556
|
+
import { open, readdir as readdir6 } from "node:fs/promises";
|
|
14267
14557
|
import * as path27 from "node:path";
|
|
14268
14558
|
async function readBoundedText(filePath, maxBytes) {
|
|
14269
14559
|
let handle;
|
|
@@ -14381,7 +14671,7 @@ async function scanWorkspace(root, maxDepth, signal) {
|
|
|
14381
14671
|
}
|
|
14382
14672
|
let entries;
|
|
14383
14673
|
try {
|
|
14384
|
-
entries = await
|
|
14674
|
+
entries = await readdir6(current.directory, { withFileTypes: true });
|
|
14385
14675
|
} catch {
|
|
14386
14676
|
continue;
|
|
14387
14677
|
}
|
|
@@ -14440,7 +14730,7 @@ async function detectPackageManager3(projectRoot, scanRoot, declared) {
|
|
|
14440
14730
|
while (true) {
|
|
14441
14731
|
const names = /* @__PURE__ */ new Set();
|
|
14442
14732
|
try {
|
|
14443
|
-
for (const entry of await
|
|
14733
|
+
for (const entry of await readdir6(directory)) names.add(entry);
|
|
14444
14734
|
} catch {
|
|
14445
14735
|
}
|
|
14446
14736
|
if (names.has("pnpm-lock.yaml")) return "pnpm";
|
|
@@ -14508,7 +14798,7 @@ async function collectSpecs(root, framework, testDirectory, signal) {
|
|
|
14508
14798
|
if (scanned > MAX_SCAN_DIRECTORIES) return { count, samples, truncated: true };
|
|
14509
14799
|
let entries;
|
|
14510
14800
|
try {
|
|
14511
|
-
entries = await
|
|
14801
|
+
entries = await readdir6(directory, { withFileTypes: true });
|
|
14512
14802
|
} catch {
|
|
14513
14803
|
continue;
|
|
14514
14804
|
}
|
|
@@ -17217,7 +17507,7 @@ async function detectFixer(cwd) {
|
|
|
17217
17507
|
init_util();
|
|
17218
17508
|
import { spawn as spawn10 } from "node:child_process";
|
|
17219
17509
|
import { statSync as statSync4 } from "node:fs";
|
|
17220
|
-
import { dirname as
|
|
17510
|
+
import { dirname as dirname14, resolve as resolve13, sep as sep6 } from "node:path";
|
|
17221
17511
|
import { assessCommitSafety } from "@wrongstack/core/coordination";
|
|
17222
17512
|
import { buildChildEnv as buildChildEnv4 } from "@wrongstack/core/utils";
|
|
17223
17513
|
var TIMEOUT_MS2 = 3e4;
|
|
@@ -17379,7 +17669,7 @@ function findGitDir2(cwd, projectRoot) {
|
|
|
17379
17669
|
} catch {
|
|
17380
17670
|
}
|
|
17381
17671
|
if (dir === root) break;
|
|
17382
|
-
const parent =
|
|
17672
|
+
const parent = dirname14(dir);
|
|
17383
17673
|
if (parent === dir) break;
|
|
17384
17674
|
dir = parent;
|
|
17385
17675
|
}
|
|
@@ -21477,12 +21767,13 @@ init_util();
|
|
|
21477
21767
|
import * as fs28 from "node:fs/promises";
|
|
21478
21768
|
import { FsError, ToolValidationError as ToolValidationError5 } from "@wrongstack/core/types";
|
|
21479
21769
|
import { toErrorMessage as toErrorMessage4 } from "@wrongstack/core/utils";
|
|
21770
|
+
var ADVANCED_MODE_META_KEY = "tools.read.advancedMode";
|
|
21480
21771
|
var MAX_BYTES2 = 5 * 1024 * 1024;
|
|
21481
21772
|
var readTool = {
|
|
21482
21773
|
name: "read",
|
|
21483
21774
|
category: "Filesystem",
|
|
21484
|
-
description: "Read the contents of a file with line numbers. This is the primary way to inspect source code, configuration, or any text file before making changes. Lines are returned 1-indexed with a ` N| ` prefix for easy reference in edits.",
|
|
21485
|
-
usageHint: "FOUNDATIONAL TOOL \u2014 call this before almost any edit operation.\n\nBest practices:\n- Always read a file before using `edit`, `replace`, or `write` on it (the system often requires it for safety).\n- Use `offset` + `limit` for very large files instead of reading everything at once.\n- Default limit is generous (2000 lines) but can be increased.\n- The output format is designed to be directly usable as context for `edit` operations.",
|
|
21775
|
+
description: "Read the contents of a file with line numbers. This is the primary way to inspect source code, configuration, or any text file before making changes. Lines are returned 1-indexed with a ` N| ` prefix for easy reference in edits. When advanced mode is on or `includeSymbols` is set, the result also includes a `symbols` field listing codebase-index symbol names, kinds, and line numbers for the file (not file content).",
|
|
21776
|
+
usageHint: "FOUNDATIONAL TOOL \u2014 call this before almost any edit operation.\n\nBest practices:\n- Always read a file before using `edit`, `replace`, or `write` on it (the system often requires it for safety).\n- Use `offset` + `limit` for very large files instead of reading everything at once.\n- Default limit is generous (2000 lines) but can be increased.\n- The output format is designed to be directly usable as context for `edit` operations.\n- Set `includeSymbols: true` to also receive the codebase-index symbol listing for the file.\n- Enable advanced mode (`ctx.meta['tools.read.advancedMode'] = true`) to auto-inject symbols on every read.",
|
|
21486
21777
|
selection: {
|
|
21487
21778
|
doNotUseWhen: "you need to search many files for matching content.",
|
|
21488
21779
|
useInstead: ["grep"]
|
|
@@ -21512,11 +21803,15 @@ var readTool = {
|
|
|
21512
21803
|
type: "string",
|
|
21513
21804
|
enum: ["content", "summary"],
|
|
21514
21805
|
description: "Return full line-numbered content (default) or a compact file summary with imports/exports/symbols."
|
|
21806
|
+
},
|
|
21807
|
+
includeSymbols: {
|
|
21808
|
+
type: "boolean",
|
|
21809
|
+
description: "When true, include the codebase-index symbol list for this file as a structured `symbols` field in the result. Overrides the advanced-mode meta flag per-call."
|
|
21515
21810
|
}
|
|
21516
21811
|
},
|
|
21517
21812
|
required: ["path"]
|
|
21518
21813
|
},
|
|
21519
|
-
async execute(input, ctx) {
|
|
21814
|
+
async execute(input, ctx, execOpts) {
|
|
21520
21815
|
if (!input?.path) {
|
|
21521
21816
|
throw new ToolValidationError5({
|
|
21522
21817
|
message: "read: path is required",
|
|
@@ -21524,6 +21819,7 @@ var readTool = {
|
|
|
21524
21819
|
});
|
|
21525
21820
|
}
|
|
21526
21821
|
const absPath = await safeResolveReal(input.path, ctx);
|
|
21822
|
+
const shouldIncludeSymbols = input.includeSymbols === true || input.includeSymbols !== false && ctx.meta[ADVANCED_MODE_META_KEY] === true;
|
|
21527
21823
|
let stat17;
|
|
21528
21824
|
try {
|
|
21529
21825
|
stat17 = await fs28.stat(absPath);
|
|
@@ -21567,13 +21863,15 @@ var readTool = {
|
|
|
21567
21863
|
const requestedEnd = prior ? Math.min(offset + limit - 1, prior.totalLines) : offset + limit - 1;
|
|
21568
21864
|
if (input.mode !== "summary" && limit > 0 && prior && coversRange(prior, stat17.mtimeMs, offset, requestedEnd)) {
|
|
21569
21865
|
ctx.recordRead(absPath, stat17.mtimeMs);
|
|
21866
|
+
const symResult2 = shouldIncludeSymbols ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal) : void 0;
|
|
21570
21867
|
return {
|
|
21571
21868
|
text: `[unchanged since previous read: "${input.path}" mtime=${Math.round(stat17.mtimeMs)}; requested lines ${offset}-${requestedEnd} were already shown. Use offset/limit for a new range if needed.]`,
|
|
21572
21869
|
total_lines: prior.totalLines,
|
|
21573
21870
|
encoding: "utf8",
|
|
21574
21871
|
truncated: requestedEnd < prior.totalLines,
|
|
21575
21872
|
cached: true,
|
|
21576
|
-
note: "Repeated read suppressed to save tokens."
|
|
21873
|
+
note: mergeSymbolNote("Repeated read suppressed to save tokens.", symResult2?.note),
|
|
21874
|
+
...symResult2?.symbols ? { symbols: symResult2.symbols } : {}
|
|
21577
21875
|
};
|
|
21578
21876
|
}
|
|
21579
21877
|
const buf = await fs28.readFile(absPath);
|
|
@@ -21587,27 +21885,43 @@ var readTool = {
|
|
|
21587
21885
|
if (input.mode === "summary") {
|
|
21588
21886
|
ctx.recordRead(absPath, stat17.mtimeMs, "user", contentHash);
|
|
21589
21887
|
rememberReadRange(ctx, absPath, stat17.mtimeMs, total, 1, Math.min(total, 200));
|
|
21888
|
+
const symResult2 = shouldIncludeSymbols ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal) : void 0;
|
|
21590
21889
|
return {
|
|
21591
21890
|
text: summarizeFile(input.path, stat17.size, allLines),
|
|
21592
21891
|
total_lines: total,
|
|
21593
21892
|
encoding: "utf8",
|
|
21594
21893
|
truncated: total > 200,
|
|
21595
|
-
note:
|
|
21894
|
+
note: mergeSymbolNote(
|
|
21895
|
+
"Summary mode returned compact structure instead of full file content.",
|
|
21896
|
+
symResult2?.note
|
|
21897
|
+
),
|
|
21898
|
+
...symResult2?.symbols ? { symbols: symResult2.symbols } : {}
|
|
21596
21899
|
};
|
|
21597
21900
|
}
|
|
21598
21901
|
if (limit === 0) {
|
|
21599
21902
|
ctx.recordRead(absPath, stat17.mtimeMs, "user", contentHash);
|
|
21600
21903
|
rememberReadRange(ctx, absPath, stat17.mtimeMs, total, 1, 0);
|
|
21601
|
-
|
|
21904
|
+
const symResult2 = shouldIncludeSymbols ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal) : void 0;
|
|
21905
|
+
return {
|
|
21906
|
+
text: "",
|
|
21907
|
+
total_lines: total,
|
|
21908
|
+
encoding: "utf8",
|
|
21909
|
+
truncated: total > 0,
|
|
21910
|
+
...symResult2?.symbols ? { symbols: symResult2.symbols } : {},
|
|
21911
|
+
...symResult2?.note ? { note: symResult2.note } : {}
|
|
21912
|
+
};
|
|
21602
21913
|
}
|
|
21603
21914
|
if (offset > total) {
|
|
21604
21915
|
ctx.recordRead(absPath, stat17.mtimeMs, "user", contentHash);
|
|
21605
21916
|
rememberReadRange(ctx, absPath, stat17.mtimeMs, total, total + 1, total + 1);
|
|
21917
|
+
const symResult2 = shouldIncludeSymbols ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal) : void 0;
|
|
21606
21918
|
return {
|
|
21607
21919
|
text: `[offset ${offset} is past end of file "${input.path}" \u2014 file has ${total} line(s). Do not retry this offset.]`,
|
|
21608
21920
|
total_lines: total,
|
|
21609
21921
|
encoding: "utf8",
|
|
21610
|
-
truncated: false
|
|
21922
|
+
truncated: false,
|
|
21923
|
+
...symResult2?.symbols ? { symbols: symResult2.symbols } : {},
|
|
21924
|
+
...symResult2?.note ? { note: symResult2.note } : {}
|
|
21611
21925
|
};
|
|
21612
21926
|
}
|
|
21613
21927
|
const slice = allLines.slice(offset - 1, offset - 1 + limit);
|
|
@@ -21616,14 +21930,53 @@ var readTool = {
|
|
|
21616
21930
|
const numbered = slice.map((line, i) => `${String(offset + i).padStart(width, " ")}\u2192${line}`).join("\n");
|
|
21617
21931
|
ctx.recordRead(absPath, stat17.mtimeMs, "user", contentHash);
|
|
21618
21932
|
rememberReadRange(ctx, absPath, stat17.mtimeMs, total, offset, offset + slice.length - 1);
|
|
21933
|
+
const symResult = shouldIncludeSymbols ? await fetchSymbolsForFile(absPath, ctx, execOpts?.signal) : void 0;
|
|
21619
21934
|
return {
|
|
21620
21935
|
text: numbered,
|
|
21621
21936
|
total_lines: total,
|
|
21622
21937
|
encoding: "utf8",
|
|
21623
|
-
truncated
|
|
21938
|
+
truncated,
|
|
21939
|
+
...symResult?.symbols ? { symbols: symResult.symbols } : {},
|
|
21940
|
+
...symResult?.note ? { note: symResult.note } : {}
|
|
21624
21941
|
};
|
|
21625
21942
|
}
|
|
21626
21943
|
};
|
|
21944
|
+
async function fetchSymbolsForFile(absPath, ctx, signal) {
|
|
21945
|
+
try {
|
|
21946
|
+
const state = getIndexState();
|
|
21947
|
+
if (!state.ready) return {};
|
|
21948
|
+
const { results, total } = await searchCodebaseIndex(
|
|
21949
|
+
{
|
|
21950
|
+
projectRoot: ctx.projectRoot,
|
|
21951
|
+
indexDir: codebaseIndexDirOverride(ctx),
|
|
21952
|
+
query: "",
|
|
21953
|
+
file: absPath,
|
|
21954
|
+
limit: 500
|
|
21955
|
+
},
|
|
21956
|
+
{ signal }
|
|
21957
|
+
);
|
|
21958
|
+
if (results.length === 0) return {};
|
|
21959
|
+
const sorted = results.map((r) => ({
|
|
21960
|
+
name: r.name,
|
|
21961
|
+
kind: r.kind,
|
|
21962
|
+
line: r.line,
|
|
21963
|
+
col: r.col,
|
|
21964
|
+
signature: r.signature
|
|
21965
|
+
})).sort((a, b) => a.line - b.line || a.col - b.col);
|
|
21966
|
+
const result = { symbols: sorted };
|
|
21967
|
+
if (total > results.length) {
|
|
21968
|
+
result.note = `Symbol listing truncated to ${results.length} of ${total} entries.`;
|
|
21969
|
+
}
|
|
21970
|
+
return result;
|
|
21971
|
+
} catch {
|
|
21972
|
+
return {};
|
|
21973
|
+
}
|
|
21974
|
+
}
|
|
21975
|
+
function mergeSymbolNote(note, symNote) {
|
|
21976
|
+
if (!symNote) return note;
|
|
21977
|
+
if (!note) return symNote;
|
|
21978
|
+
return `${note} ${symNote}`;
|
|
21979
|
+
}
|
|
21627
21980
|
var READ_RANGES_META_KEY = "tools.read.ranges.v1";
|
|
21628
21981
|
function getReadRanges(ctx) {
|
|
21629
21982
|
const existing = ctx.meta[READ_RANGES_META_KEY];
|