@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
|
@@ -255,11 +255,18 @@ async function parseSymbols(opts) {
|
|
|
255
255
|
} else if (ts.isHeritageClause(node)) {
|
|
256
256
|
for (const t of node.types) {
|
|
257
257
|
const name = getTypeName(t.expression);
|
|
258
|
-
if (name)
|
|
258
|
+
if (name)
|
|
259
|
+
refs.push({
|
|
260
|
+
fromId: 0,
|
|
261
|
+
toName: name,
|
|
262
|
+
callType: node.token === ts.SyntaxKind.ExtendsKeyword ? "inherit" : "implement",
|
|
263
|
+
line: lineNum
|
|
264
|
+
});
|
|
259
265
|
}
|
|
260
266
|
} else if (ts.isImportDeclaration(node)) {
|
|
261
|
-
|
|
262
|
-
|
|
267
|
+
emitImportSpecifierRefs(node, refs, lineNum);
|
|
268
|
+
} else if (ts.isExportDeclaration(node) && node.moduleSpecifier) {
|
|
269
|
+
emitExportSpecifierRefs(node, refs, lineNum);
|
|
263
270
|
}
|
|
264
271
|
const scopeIdx = scopeParts.length;
|
|
265
272
|
pushScopeName(node, scopeParts);
|
|
@@ -275,11 +282,6 @@ function getTypeName(name) {
|
|
|
275
282
|
if (ts.isQualifiedName(name)) return `${getTypeName(name.left)}.${name.right.text}`;
|
|
276
283
|
return "";
|
|
277
284
|
}
|
|
278
|
-
function getModuleName(node) {
|
|
279
|
-
const moduleSpecifier = node.moduleSpecifier;
|
|
280
|
-
if (ts.isStringLiteral(moduleSpecifier)) return moduleSpecifier.text;
|
|
281
|
-
return "";
|
|
282
|
-
}
|
|
283
285
|
function deduplicateRefs(refs) {
|
|
284
286
|
const seen = /* @__PURE__ */ new Set();
|
|
285
287
|
return refs.filter((r) => {
|
|
@@ -289,6 +291,44 @@ function deduplicateRefs(refs) {
|
|
|
289
291
|
return true;
|
|
290
292
|
});
|
|
291
293
|
}
|
|
294
|
+
function getImportSpecifierName(spec) {
|
|
295
|
+
return spec.propertyName?.text ?? spec.name.text;
|
|
296
|
+
}
|
|
297
|
+
function emitImportSpecifierRefs(node, refs, lineNum) {
|
|
298
|
+
const clause = node.importClause;
|
|
299
|
+
if (!clause) return;
|
|
300
|
+
if (clause.name) {
|
|
301
|
+
refs.push({ fromId: 0, toName: clause.name.text, callType: "import", line: lineNum });
|
|
302
|
+
}
|
|
303
|
+
const bindings = clause.namedBindings;
|
|
304
|
+
if (!bindings) return;
|
|
305
|
+
if (ts.isNamedImports(bindings)) {
|
|
306
|
+
for (const element of bindings.elements) {
|
|
307
|
+
refs.push({
|
|
308
|
+
fromId: 0,
|
|
309
|
+
toName: getImportSpecifierName(element),
|
|
310
|
+
callType: "import",
|
|
311
|
+
line: lineNum
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
} else if (ts.isNamespaceImport(bindings)) {
|
|
315
|
+
refs.push({ fromId: 0, toName: bindings.name.text, callType: "import", line: lineNum });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function emitExportSpecifierRefs(node, refs, lineNum) {
|
|
319
|
+
const clause = node.exportClause;
|
|
320
|
+
if (clause && ts.isNamespaceExport(clause)) {
|
|
321
|
+
refs.push({ fromId: 0, toName: clause.name.text, callType: "import", line: lineNum });
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (clause && ts.isNamedExports(clause)) {
|
|
325
|
+
for (const element of clause.elements) {
|
|
326
|
+
const originalName = element.propertyName?.text ?? element.name.text;
|
|
327
|
+
refs.push({ fromId: 0, toName: originalName, callType: "import", line: lineNum });
|
|
328
|
+
}
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
292
332
|
var ts, tsLoad, kindMapCache;
|
|
293
333
|
var init_ts_parser = __esm({
|
|
294
334
|
"src/codebase-index/ts-parser.ts"() {
|
|
@@ -2130,71 +2170,6 @@ import { expectDefined as expectDefined4 } from "@wrongstack/core/utils";
|
|
|
2130
2170
|
import * as fs7 from "node:fs";
|
|
2131
2171
|
import * as path10 from "node:path";
|
|
2132
2172
|
|
|
2133
|
-
// src/codebase-index/schema.ts
|
|
2134
|
-
var SCHEMA_VERSION = 3;
|
|
2135
|
-
|
|
2136
|
-
// src/codebase-index/lsp-kind.ts
|
|
2137
|
-
function lspKindToInternalKind(k) {
|
|
2138
|
-
switch (k) {
|
|
2139
|
-
case 5 /* Class */:
|
|
2140
|
-
return "class";
|
|
2141
|
-
case 6 /* Method */:
|
|
2142
|
-
return "method";
|
|
2143
|
-
case 7 /* Property */:
|
|
2144
|
-
case 8 /* Field */:
|
|
2145
|
-
return "property";
|
|
2146
|
-
case 9 /* Constructor */:
|
|
2147
|
-
return "class";
|
|
2148
|
-
case 10 /* Enum */:
|
|
2149
|
-
return "enum";
|
|
2150
|
-
case 11 /* Interface */:
|
|
2151
|
-
return "interface";
|
|
2152
|
-
case 12 /* Function */:
|
|
2153
|
-
return "function";
|
|
2154
|
-
case 13 /* Variable */:
|
|
2155
|
-
return "var";
|
|
2156
|
-
case 14 /* Constant */:
|
|
2157
|
-
return "const";
|
|
2158
|
-
case 22 /* EnumMember */:
|
|
2159
|
-
return "enum";
|
|
2160
|
-
case 26 /* TypeParameter */:
|
|
2161
|
-
return "type";
|
|
2162
|
-
case 3 /* Namespace */:
|
|
2163
|
-
return "namespace";
|
|
2164
|
-
default:
|
|
2165
|
-
return null;
|
|
2166
|
-
}
|
|
2167
|
-
}
|
|
2168
|
-
function internalKindToLspKind(k) {
|
|
2169
|
-
switch (k) {
|
|
2170
|
-
case "class":
|
|
2171
|
-
return 5 /* Class */;
|
|
2172
|
-
case "method":
|
|
2173
|
-
return 6 /* Method */;
|
|
2174
|
-
case "property":
|
|
2175
|
-
return 7 /* Property */;
|
|
2176
|
-
case "function":
|
|
2177
|
-
return 12 /* Function */;
|
|
2178
|
-
case "var":
|
|
2179
|
-
return 13 /* Variable */;
|
|
2180
|
-
case "const":
|
|
2181
|
-
return 14 /* Constant */;
|
|
2182
|
-
case "let":
|
|
2183
|
-
return 13 /* Variable */;
|
|
2184
|
-
case "enum":
|
|
2185
|
-
return 10 /* Enum */;
|
|
2186
|
-
case "interface":
|
|
2187
|
-
return 11 /* Interface */;
|
|
2188
|
-
case "namespace":
|
|
2189
|
-
return 3 /* Namespace */;
|
|
2190
|
-
case "type":
|
|
2191
|
-
return 26 /* TypeParameter */;
|
|
2192
|
-
// parameter and other internal-only kinds have no LSP equivalent
|
|
2193
|
-
default:
|
|
2194
|
-
return null;
|
|
2195
|
-
}
|
|
2196
|
-
}
|
|
2197
|
-
|
|
2198
2173
|
// src/codebase-index/bm25.ts
|
|
2199
2174
|
var K1 = 1.5;
|
|
2200
2175
|
var B = 0.75;
|
|
@@ -2284,6 +2259,71 @@ var Bm25Index = class {
|
|
|
2284
2259
|
}
|
|
2285
2260
|
};
|
|
2286
2261
|
|
|
2262
|
+
// src/codebase-index/lsp-kind.ts
|
|
2263
|
+
function lspKindToInternalKind(k) {
|
|
2264
|
+
switch (k) {
|
|
2265
|
+
case 5 /* Class */:
|
|
2266
|
+
return "class";
|
|
2267
|
+
case 6 /* Method */:
|
|
2268
|
+
return "method";
|
|
2269
|
+
case 7 /* Property */:
|
|
2270
|
+
case 8 /* Field */:
|
|
2271
|
+
return "property";
|
|
2272
|
+
case 9 /* Constructor */:
|
|
2273
|
+
return "class";
|
|
2274
|
+
case 10 /* Enum */:
|
|
2275
|
+
return "enum";
|
|
2276
|
+
case 11 /* Interface */:
|
|
2277
|
+
return "interface";
|
|
2278
|
+
case 12 /* Function */:
|
|
2279
|
+
return "function";
|
|
2280
|
+
case 13 /* Variable */:
|
|
2281
|
+
return "var";
|
|
2282
|
+
case 14 /* Constant */:
|
|
2283
|
+
return "const";
|
|
2284
|
+
case 22 /* EnumMember */:
|
|
2285
|
+
return "enum";
|
|
2286
|
+
case 26 /* TypeParameter */:
|
|
2287
|
+
return "type";
|
|
2288
|
+
case 3 /* Namespace */:
|
|
2289
|
+
return "namespace";
|
|
2290
|
+
default:
|
|
2291
|
+
return null;
|
|
2292
|
+
}
|
|
2293
|
+
}
|
|
2294
|
+
function internalKindToLspKind(k) {
|
|
2295
|
+
switch (k) {
|
|
2296
|
+
case "class":
|
|
2297
|
+
return 5 /* Class */;
|
|
2298
|
+
case "method":
|
|
2299
|
+
return 6 /* Method */;
|
|
2300
|
+
case "property":
|
|
2301
|
+
return 7 /* Property */;
|
|
2302
|
+
case "function":
|
|
2303
|
+
return 12 /* Function */;
|
|
2304
|
+
case "var":
|
|
2305
|
+
return 13 /* Variable */;
|
|
2306
|
+
case "const":
|
|
2307
|
+
return 14 /* Constant */;
|
|
2308
|
+
case "let":
|
|
2309
|
+
return 13 /* Variable */;
|
|
2310
|
+
case "enum":
|
|
2311
|
+
return 10 /* Enum */;
|
|
2312
|
+
case "interface":
|
|
2313
|
+
return 11 /* Interface */;
|
|
2314
|
+
case "namespace":
|
|
2315
|
+
return 3 /* Namespace */;
|
|
2316
|
+
case "type":
|
|
2317
|
+
return 26 /* TypeParameter */;
|
|
2318
|
+
// parameter and other internal-only kinds have no LSP equivalent
|
|
2319
|
+
default:
|
|
2320
|
+
return null;
|
|
2321
|
+
}
|
|
2322
|
+
}
|
|
2323
|
+
|
|
2324
|
+
// src/codebase-index/schema.ts
|
|
2325
|
+
var SCHEMA_VERSION = 3;
|
|
2326
|
+
|
|
2287
2327
|
// src/codebase-index/sqlite-runtime.ts
|
|
2288
2328
|
import { createRequire } from "node:module";
|
|
2289
2329
|
import { toErrorMessage } from "@wrongstack/core/utils";
|
|
@@ -2351,96 +2391,6 @@ function runSqliteWithRetry(fn) {
|
|
|
2351
2391
|
throw lastError;
|
|
2352
2392
|
}
|
|
2353
2393
|
|
|
2354
|
-
// src/codebase-index/writer-helpers.ts
|
|
2355
|
-
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
2356
|
-
function escapeLike(value) {
|
|
2357
|
-
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
2358
|
-
}
|
|
2359
|
-
function assignRefsToSymbols(refs, symbols) {
|
|
2360
|
-
if (refs.length === 0 || symbols.length === 0) return [];
|
|
2361
|
-
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
2362
|
-
const seen = /* @__PURE__ */ new Set();
|
|
2363
|
-
const assigned = [];
|
|
2364
|
-
for (const ref of refs) {
|
|
2365
|
-
let owner;
|
|
2366
|
-
for (const symbol of ordered) {
|
|
2367
|
-
if (symbol.line > ref.line) break;
|
|
2368
|
-
owner = symbol;
|
|
2369
|
-
}
|
|
2370
|
-
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
2371
|
-
if (!owner || owner.id <= 0) continue;
|
|
2372
|
-
const key = `${owner.id}:${ref.toName}:${ref.callType}`;
|
|
2373
|
-
if (seen.has(key)) continue;
|
|
2374
|
-
seen.add(key);
|
|
2375
|
-
assigned.push({ ...ref, fromId: owner.id });
|
|
2376
|
-
}
|
|
2377
|
-
return assigned;
|
|
2378
|
-
}
|
|
2379
|
-
function resolveIndexDir(projectRoot, override) {
|
|
2380
|
-
return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
|
|
2381
|
-
}
|
|
2382
|
-
function codebaseIndexDirOverride(ctx) {
|
|
2383
|
-
const v = ctx.meta?.["codebaseIndexDir"];
|
|
2384
|
-
return typeof v === "string" ? v : void 0;
|
|
2385
|
-
}
|
|
2386
|
-
|
|
2387
|
-
// src/codebase-index/writer-schema.ts
|
|
2388
|
-
var METADATA_TABLE_SQL = `
|
|
2389
|
-
CREATE TABLE IF NOT EXISTS metadata (
|
|
2390
|
-
key TEXT PRIMARY KEY,
|
|
2391
|
-
value TEXT NOT NULL
|
|
2392
|
-
);
|
|
2393
|
-
`;
|
|
2394
|
-
var CORE_TABLES_SQL = `
|
|
2395
|
-
CREATE TABLE IF NOT EXISTS files (
|
|
2396
|
-
file TEXT PRIMARY KEY,
|
|
2397
|
-
lang TEXT NOT NULL,
|
|
2398
|
-
mtime_ms INTEGER NOT NULL,
|
|
2399
|
-
symbol_count INTEGER NOT NULL DEFAULT 0,
|
|
2400
|
-
last_indexed INTEGER NOT NULL
|
|
2401
|
-
);
|
|
2402
|
-
CREATE TABLE IF NOT EXISTS symbols (
|
|
2403
|
-
id INTEGER PRIMARY KEY,
|
|
2404
|
-
lang TEXT NOT NULL,
|
|
2405
|
-
kind TEXT NOT NULL,
|
|
2406
|
-
name TEXT NOT NULL,
|
|
2407
|
-
file TEXT NOT NULL,
|
|
2408
|
-
line INTEGER NOT NULL,
|
|
2409
|
-
col INTEGER NOT NULL,
|
|
2410
|
-
signature TEXT NOT NULL DEFAULT '',
|
|
2411
|
-
doc_comment TEXT NOT NULL DEFAULT '',
|
|
2412
|
-
scope TEXT NOT NULL DEFAULT '',
|
|
2413
|
-
text TEXT NOT NULL DEFAULT '',
|
|
2414
|
-
file_fk TEXT NOT NULL
|
|
2415
|
-
);
|
|
2416
|
-
`;
|
|
2417
|
-
var SYMBOL_INDEX_SQL = [
|
|
2418
|
-
"CREATE INDEX IF NOT EXISTS idx_s_name ON symbols(name)",
|
|
2419
|
-
"CREATE INDEX IF NOT EXISTS idx_s_kind ON symbols(kind)",
|
|
2420
|
-
"CREATE INDEX IF NOT EXISTS idx_s_lang ON symbols(lang)",
|
|
2421
|
-
"CREATE INDEX IF NOT EXISTS idx_s_file ON symbols(file)",
|
|
2422
|
-
"CREATE INDEX IF NOT EXISTS idx_s_lang_kind ON symbols(lang, kind)",
|
|
2423
|
-
"CREATE INDEX IF NOT EXISTS idx_s_file_fk ON symbols(file_fk)",
|
|
2424
|
-
"CREATE INDEX IF NOT EXISTS idx_s_name_id ON symbols(name, id)"
|
|
2425
|
-
];
|
|
2426
|
-
var REFS_TABLE_SQL = `
|
|
2427
|
-
CREATE TABLE IF NOT EXISTS refs (
|
|
2428
|
-
id INTEGER PRIMARY KEY,
|
|
2429
|
-
from_id INTEGER NOT NULL,
|
|
2430
|
-
to_name TEXT NOT NULL,
|
|
2431
|
-
to_id INTEGER,
|
|
2432
|
-
call_type TEXT NOT NULL,
|
|
2433
|
-
line INTEGER NOT NULL
|
|
2434
|
-
);
|
|
2435
|
-
`;
|
|
2436
|
-
var REFS_INDEX_SQL = [
|
|
2437
|
-
"CREATE INDEX IF NOT EXISTS idx_r_from ON refs(from_id)",
|
|
2438
|
-
"CREATE INDEX IF NOT EXISTS idx_r_to_id ON refs(to_id)",
|
|
2439
|
-
"CREATE INDEX IF NOT EXISTS idx_r_to_name ON refs(to_name)",
|
|
2440
|
-
"CREATE INDEX IF NOT EXISTS idx_r_call_type ON refs(call_type)"
|
|
2441
|
-
];
|
|
2442
|
-
var SYMBOLS_FTS_SQL = "CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(text, tokenize = 'unicode61')";
|
|
2443
|
-
|
|
2444
2394
|
// src/codebase-index/writer-admin.ts
|
|
2445
2395
|
import * as fs6 from "node:fs";
|
|
2446
2396
|
import * as path8 from "node:path";
|
|
@@ -2913,6 +2863,39 @@ function getSymbolGraphWithStatement(stmt, fileFilter) {
|
|
|
2913
2863
|
return { nodes, edges };
|
|
2914
2864
|
}
|
|
2915
2865
|
|
|
2866
|
+
// src/codebase-index/writer-helpers.ts
|
|
2867
|
+
import { resolveWstackPaths } from "@wrongstack/core/utils";
|
|
2868
|
+
function escapeLike(value) {
|
|
2869
|
+
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
2870
|
+
}
|
|
2871
|
+
function assignRefsToSymbols(refs, symbols) {
|
|
2872
|
+
if (refs.length === 0 || symbols.length === 0) return [];
|
|
2873
|
+
const ordered = [...symbols].sort((a, b) => a.line - b.line || a.col - b.col || a.id - b.id);
|
|
2874
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2875
|
+
const assigned = [];
|
|
2876
|
+
for (const ref of refs) {
|
|
2877
|
+
let owner;
|
|
2878
|
+
for (const symbol of ordered) {
|
|
2879
|
+
if (symbol.line > ref.line) break;
|
|
2880
|
+
owner = symbol;
|
|
2881
|
+
}
|
|
2882
|
+
if (!owner && ref.callType === "import") owner = ordered[0];
|
|
2883
|
+
if (!owner || owner.id <= 0) continue;
|
|
2884
|
+
const key = `${owner.id}:${ref.toName}:${ref.callType}`;
|
|
2885
|
+
if (seen.has(key)) continue;
|
|
2886
|
+
seen.add(key);
|
|
2887
|
+
assigned.push({ ...ref, fromId: owner.id });
|
|
2888
|
+
}
|
|
2889
|
+
return assigned;
|
|
2890
|
+
}
|
|
2891
|
+
function resolveIndexDir(projectRoot, override) {
|
|
2892
|
+
return override ?? resolveWstackPaths({ projectRoot }).projectCodebaseIndex;
|
|
2893
|
+
}
|
|
2894
|
+
function codebaseIndexDirOverride(ctx) {
|
|
2895
|
+
const v = ctx.meta?.["codebaseIndexDir"];
|
|
2896
|
+
return typeof v === "string" ? v : void 0;
|
|
2897
|
+
}
|
|
2898
|
+
|
|
2916
2899
|
// src/codebase-index/writer-pragmas.ts
|
|
2917
2900
|
import { sqliteCachePragmas } from "@wrongstack/core/utils";
|
|
2918
2901
|
function applyIndexStorePragmas(db) {
|
|
@@ -2931,6 +2914,63 @@ function applyIndexStorePragmas(db) {
|
|
|
2931
2914
|
}
|
|
2932
2915
|
}
|
|
2933
2916
|
|
|
2917
|
+
// src/codebase-index/writer-schema.ts
|
|
2918
|
+
var METADATA_TABLE_SQL = `
|
|
2919
|
+
CREATE TABLE IF NOT EXISTS metadata (
|
|
2920
|
+
key TEXT PRIMARY KEY,
|
|
2921
|
+
value TEXT NOT NULL
|
|
2922
|
+
);
|
|
2923
|
+
`;
|
|
2924
|
+
var CORE_TABLES_SQL = `
|
|
2925
|
+
CREATE TABLE IF NOT EXISTS files (
|
|
2926
|
+
file TEXT PRIMARY KEY,
|
|
2927
|
+
lang TEXT NOT NULL,
|
|
2928
|
+
mtime_ms INTEGER NOT NULL,
|
|
2929
|
+
symbol_count INTEGER NOT NULL DEFAULT 0,
|
|
2930
|
+
last_indexed INTEGER NOT NULL
|
|
2931
|
+
);
|
|
2932
|
+
CREATE TABLE IF NOT EXISTS symbols (
|
|
2933
|
+
id INTEGER PRIMARY KEY,
|
|
2934
|
+
lang TEXT NOT NULL,
|
|
2935
|
+
kind TEXT NOT NULL,
|
|
2936
|
+
name TEXT NOT NULL,
|
|
2937
|
+
file TEXT NOT NULL,
|
|
2938
|
+
line INTEGER NOT NULL,
|
|
2939
|
+
col INTEGER NOT NULL,
|
|
2940
|
+
signature TEXT NOT NULL DEFAULT '',
|
|
2941
|
+
doc_comment TEXT NOT NULL DEFAULT '',
|
|
2942
|
+
scope TEXT NOT NULL DEFAULT '',
|
|
2943
|
+
text TEXT NOT NULL DEFAULT '',
|
|
2944
|
+
file_fk TEXT NOT NULL
|
|
2945
|
+
);
|
|
2946
|
+
`;
|
|
2947
|
+
var SYMBOL_INDEX_SQL = [
|
|
2948
|
+
"CREATE INDEX IF NOT EXISTS idx_s_name ON symbols(name)",
|
|
2949
|
+
"CREATE INDEX IF NOT EXISTS idx_s_kind ON symbols(kind)",
|
|
2950
|
+
"CREATE INDEX IF NOT EXISTS idx_s_lang ON symbols(lang)",
|
|
2951
|
+
"CREATE INDEX IF NOT EXISTS idx_s_file ON symbols(file)",
|
|
2952
|
+
"CREATE INDEX IF NOT EXISTS idx_s_lang_kind ON symbols(lang, kind)",
|
|
2953
|
+
"CREATE INDEX IF NOT EXISTS idx_s_file_fk ON symbols(file_fk)",
|
|
2954
|
+
"CREATE INDEX IF NOT EXISTS idx_s_name_id ON symbols(name, id)"
|
|
2955
|
+
];
|
|
2956
|
+
var REFS_TABLE_SQL = `
|
|
2957
|
+
CREATE TABLE IF NOT EXISTS refs (
|
|
2958
|
+
id INTEGER PRIMARY KEY,
|
|
2959
|
+
from_id INTEGER NOT NULL,
|
|
2960
|
+
to_name TEXT NOT NULL,
|
|
2961
|
+
to_id INTEGER,
|
|
2962
|
+
call_type TEXT NOT NULL,
|
|
2963
|
+
line INTEGER NOT NULL
|
|
2964
|
+
);
|
|
2965
|
+
`;
|
|
2966
|
+
var REFS_INDEX_SQL = [
|
|
2967
|
+
"CREATE INDEX IF NOT EXISTS idx_r_from ON refs(from_id)",
|
|
2968
|
+
"CREATE INDEX IF NOT EXISTS idx_r_to_id ON refs(to_id)",
|
|
2969
|
+
"CREATE INDEX IF NOT EXISTS idx_r_to_name ON refs(to_name)",
|
|
2970
|
+
"CREATE INDEX IF NOT EXISTS idx_r_call_type ON refs(call_type)"
|
|
2971
|
+
];
|
|
2972
|
+
var SYMBOLS_FTS_SQL = "CREATE VIRTUAL TABLE IF NOT EXISTS symbols_fts USING fts5(text, tokenize = 'unicode61')";
|
|
2973
|
+
|
|
2934
2974
|
// src/codebase-index/writer-search-helpers.ts
|
|
2935
2975
|
function normalizeSearchLimit(limit) {
|
|
2936
2976
|
return typeof limit === "number" && Number.isFinite(limit) ? Math.max(0, Math.trunc(limit)) : void 0;
|
|
@@ -3139,9 +3179,15 @@ var IndexStore = class _IndexStore {
|
|
|
3139
3179
|
DROP TABLE IF EXISTS refs;
|
|
3140
3180
|
`);
|
|
3141
3181
|
this.db.exec("DROP TABLE IF EXISTS symbols_fts");
|
|
3142
|
-
this.stmt("UPDATE metadata SET value = ? WHERE key = ?").run(
|
|
3182
|
+
this.stmt("UPDATE metadata SET value = ? WHERE key = ?").run(
|
|
3183
|
+
String(SCHEMA_VERSION),
|
|
3184
|
+
"version"
|
|
3185
|
+
);
|
|
3143
3186
|
} else if (storedVersion === null) {
|
|
3144
|
-
this.stmt("INSERT INTO metadata(key, value) VALUES (?, ?)").run(
|
|
3187
|
+
this.stmt("INSERT INTO metadata(key, value) VALUES (?, ?)").run(
|
|
3188
|
+
"version",
|
|
3189
|
+
String(SCHEMA_VERSION)
|
|
3190
|
+
);
|
|
3145
3191
|
}
|
|
3146
3192
|
this.db.exec(CORE_TABLES_SQL);
|
|
3147
3193
|
for (const sql of SYMBOL_INDEX_SQL) this.db.exec(sql);
|
|
@@ -3158,7 +3204,9 @@ var IndexStore = class _IndexStore {
|
|
|
3158
3204
|
);
|
|
3159
3205
|
if (symbolCount !== ftsCount) {
|
|
3160
3206
|
this.db.exec("DELETE FROM symbols_fts");
|
|
3161
|
-
const rows = this.stmt(
|
|
3207
|
+
const rows = this.stmt(
|
|
3208
|
+
"SELECT id, name, signature, doc_comment FROM symbols ORDER BY id"
|
|
3209
|
+
).all();
|
|
3162
3210
|
bulkInsertFtsWithStatement(
|
|
3163
3211
|
(sql) => this.stmt(sql),
|
|
3164
3212
|
_IndexStore.MAX_SQL_VARS,
|
|
@@ -3380,7 +3428,9 @@ var IndexStore = class _IndexStore {
|
|
|
3380
3428
|
const limitSql = limit !== void 0 ? " LIMIT ?" : "";
|
|
3381
3429
|
const sql = `SELECT id, lang, kind, name, file, line, col, signature, doc_comment, text FROM symbols ${where}${limitSql}`;
|
|
3382
3430
|
const binds = limit !== void 0 ? [...values, limit] : values;
|
|
3383
|
-
const rows = this.stmt(sql).all(
|
|
3431
|
+
const rows = this.stmt(sql).all(
|
|
3432
|
+
...binds
|
|
3433
|
+
);
|
|
3384
3434
|
return rows.map((row) => mapWriterSearchRow(row, filter?.lspKind));
|
|
3385
3435
|
}
|
|
3386
3436
|
/** Shared WHERE builder for {@link search} / empty-query ranked totals. */
|
|
@@ -3556,7 +3606,9 @@ var IndexStore = class _IndexStore {
|
|
|
3556
3606
|
}
|
|
3557
3607
|
setLastIndexed(ts2) {
|
|
3558
3608
|
this.runWithRetry(() => {
|
|
3559
|
-
this.stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES('last_indexed', ?)").run(
|
|
3609
|
+
this.stmt("INSERT OR REPLACE INTO metadata(key, value) VALUES('last_indexed', ?)").run(
|
|
3610
|
+
String(ts2)
|
|
3611
|
+
);
|
|
3560
3612
|
});
|
|
3561
3613
|
}
|
|
3562
3614
|
getMetadata(key) {
|
|
@@ -3667,7 +3719,9 @@ var IndexStore = class _IndexStore {
|
|
|
3667
3719
|
this.stmt(
|
|
3668
3720
|
`DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file IN (${placeholders}))`
|
|
3669
3721
|
).run(...options.deleteForFiles);
|
|
3670
|
-
this.stmt(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(
|
|
3722
|
+
this.stmt(`DELETE FROM symbols WHERE file IN (${placeholders})`).run(
|
|
3723
|
+
...options.deleteForFiles
|
|
3724
|
+
);
|
|
3671
3725
|
}
|
|
3672
3726
|
const totalSymbols = entries.reduce((n, e) => n + e.symbols.length, 0);
|
|
3673
3727
|
let nextId = this.allocateSymbolIds(totalSymbols);
|
|
@@ -3711,11 +3765,7 @@ var IndexStore = class _IndexStore {
|
|
|
3711
3765
|
this.ftsAvailable,
|
|
3712
3766
|
ftsRows
|
|
3713
3767
|
);
|
|
3714
|
-
bulkInsertRefsWithStatement(
|
|
3715
|
-
(sql) => this.stmt(sql),
|
|
3716
|
-
_IndexStore.MAX_SQL_VARS,
|
|
3717
|
-
refsToInsert
|
|
3718
|
-
);
|
|
3768
|
+
bulkInsertRefsWithStatement((sql) => this.stmt(sql), _IndexStore.MAX_SQL_VARS, refsToInsert);
|
|
3719
3769
|
const upsertStmt = this.stmt(
|
|
3720
3770
|
`INSERT INTO files(file, lang, mtime_ms, symbol_count, last_indexed)
|
|
3721
3771
|
VALUES (?, ?, ?, ?, ?)
|
|
@@ -3744,7 +3794,9 @@ var IndexStore = class _IndexStore {
|
|
|
3744
3794
|
*/
|
|
3745
3795
|
deleteRefsForFile(file) {
|
|
3746
3796
|
this.runWithRetry(() => {
|
|
3747
|
-
this.stmt("DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file = ?)").run(
|
|
3797
|
+
this.stmt("DELETE FROM refs WHERE from_id IN (SELECT id FROM symbols WHERE file = ?)").run(
|
|
3798
|
+
file
|
|
3799
|
+
);
|
|
3748
3800
|
});
|
|
3749
3801
|
}
|
|
3750
3802
|
/**
|
|
@@ -3899,9 +3951,7 @@ var IndexStore = class _IndexStore {
|
|
|
3899
3951
|
* build the full symbol universe for the reachability scan.
|
|
3900
3952
|
*/
|
|
3901
3953
|
getAllSymbols() {
|
|
3902
|
-
return this.stmt(
|
|
3903
|
-
"SELECT id, name, file, kind, line FROM symbols ORDER BY id"
|
|
3904
|
-
).all().map((r) => ({ ...r, kind: r.kind }));
|
|
3954
|
+
return this.stmt("SELECT id, name, file, kind, line FROM symbols ORDER BY id").all().map((r) => ({ ...r, kind: r.kind }));
|
|
3905
3955
|
}
|
|
3906
3956
|
/**
|
|
3907
3957
|
* Returns every resolved reference (to_id IS NOT NULL). Used by
|
|
@@ -3913,6 +3963,25 @@ var IndexStore = class _IndexStore {
|
|
|
3913
3963
|
"SELECT from_id AS fromId, to_id AS toId, call_type AS callType FROM refs WHERE to_id IS NOT NULL"
|
|
3914
3964
|
).all();
|
|
3915
3965
|
}
|
|
3966
|
+
/**
|
|
3967
|
+
* Returns ALL import refs (including unresolved) with their source-file
|
|
3968
|
+
* path and resolved target id. Used by the dead-code scan's file-level
|
|
3969
|
+
* graph traversal to handle barrel-only entry points where no symbol
|
|
3970
|
+
* carries the ref.
|
|
3971
|
+
*
|
|
3972
|
+
* Refs whose `from_id` doesn't match a known symbol (e.g. pure-barrel
|
|
3973
|
+
* files with no declarations) will have `sourceFile === null`.
|
|
3974
|
+
*/
|
|
3975
|
+
getAllImportRefs() {
|
|
3976
|
+
return this.stmt(
|
|
3977
|
+
`SELECT s.file AS sourceFile, r.to_name AS toName, r.to_id AS toId,
|
|
3978
|
+
r.call_type AS callType, r.line
|
|
3979
|
+
FROM refs r
|
|
3980
|
+
LEFT JOIN symbols s ON r.from_id = s.id
|
|
3981
|
+
WHERE r.call_type = 'import'
|
|
3982
|
+
ORDER BY r.line`
|
|
3983
|
+
).all();
|
|
3984
|
+
}
|
|
3916
3985
|
close() {
|
|
3917
3986
|
this.stmtCache.clear();
|
|
3918
3987
|
this.bm25Dirty = true;
|
|
@@ -5808,6 +5877,7 @@ var codebaseStatsTool = {
|
|
|
5808
5877
|
};
|
|
5809
5878
|
|
|
5810
5879
|
// src/codebase-index/dead-code-scan.ts
|
|
5880
|
+
init_languages();
|
|
5811
5881
|
import * as fs12 from "node:fs";
|
|
5812
5882
|
import * as path13 from "node:path";
|
|
5813
5883
|
var deadCodeScanTool = {
|
|
@@ -5876,7 +5946,15 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
|
|
|
5876
5946
|
if (rootPkg) {
|
|
5877
5947
|
addPkgJsonEntryPoints(projectRoot, rootPkg, entries);
|
|
5878
5948
|
}
|
|
5879
|
-
|
|
5949
|
+
let workspaces;
|
|
5950
|
+
if (rootPkg) {
|
|
5951
|
+
workspaces = extractWorkspaceGlobs(rootPkg, projectRoot);
|
|
5952
|
+
if (workspaces.length === 0) {
|
|
5953
|
+
workspaces = extractPnpmWorkspaceDirs(projectRoot);
|
|
5954
|
+
}
|
|
5955
|
+
} else {
|
|
5956
|
+
workspaces = [];
|
|
5957
|
+
}
|
|
5880
5958
|
for (const wsDir of workspaces) {
|
|
5881
5959
|
const pkgJsonPath = path13.join(wsDir, "package.json");
|
|
5882
5960
|
const pkg = tryReadJson(pkgJsonPath);
|
|
@@ -5898,77 +5976,189 @@ function discoverEntryPoints(projectRoot, userEntryPoints) {
|
|
|
5898
5976
|
}
|
|
5899
5977
|
return [...entries];
|
|
5900
5978
|
}
|
|
5979
|
+
var BUILD_OUTPUT_DIRS = ["dist", "out", "build", "release"];
|
|
5980
|
+
var BUILD_OUTPUT_DIR_NAMES = BUILD_OUTPUT_DIRS.map((d) => `${path13.sep}${d}${path13.sep}`);
|
|
5981
|
+
function trySourceEquivalent(resolved) {
|
|
5982
|
+
resolved = resolved.replace(/[/\\]/g, path13.sep);
|
|
5983
|
+
for (const marker of BUILD_OUTPUT_DIR_NAMES) {
|
|
5984
|
+
const idx = resolved.indexOf(marker);
|
|
5985
|
+
if (idx === -1) continue;
|
|
5986
|
+
const base = resolved.replace(marker, `${path13.sep}src${path13.sep}`);
|
|
5987
|
+
const candidate = base.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
5988
|
+
if (candidate !== base && fs12.existsSync(candidate)) {
|
|
5989
|
+
return candidate;
|
|
5990
|
+
}
|
|
5991
|
+
const dtsStripped = base.replace(/\.d\.ts$/, "");
|
|
5992
|
+
const candidateDts = dtsStripped + ".ts";
|
|
5993
|
+
if (candidateDts !== base && candidateDts !== candidate && fs12.existsSync(candidateDts)) {
|
|
5994
|
+
return candidateDts;
|
|
5995
|
+
}
|
|
5996
|
+
const candidateNoExt = base + ".ts";
|
|
5997
|
+
if (candidate !== candidateNoExt && candidateNoExt !== candidateDts && fs12.existsSync(candidateNoExt)) {
|
|
5998
|
+
return candidateNoExt;
|
|
5999
|
+
}
|
|
6000
|
+
}
|
|
6001
|
+
return null;
|
|
6002
|
+
}
|
|
6003
|
+
function tryAddEntryPath(pkgDir, rawPath, entries) {
|
|
6004
|
+
const resolved = resolveAgainst(pkgDir, rawPath);
|
|
6005
|
+
if (fs12.existsSync(resolved)) entries.add(resolved);
|
|
6006
|
+
const tsResolved = resolved.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
6007
|
+
if (tsResolved !== resolved && fs12.existsSync(tsResolved)) {
|
|
6008
|
+
entries.add(tsResolved);
|
|
6009
|
+
}
|
|
6010
|
+
const srcAlt = trySourceEquivalent(resolved);
|
|
6011
|
+
if (srcAlt) entries.add(srcAlt);
|
|
6012
|
+
}
|
|
5901
6013
|
function addPkgJsonEntryPoints(pkgDir, pkg, entries) {
|
|
5902
6014
|
if (typeof pkg.main === "string") {
|
|
5903
|
-
|
|
5904
|
-
if (fs12.existsSync(resolved)) entries.add(resolved);
|
|
5905
|
-
const tsResolved = resolved.replace(/\.(js|mjs|cjs)$/, ".ts");
|
|
5906
|
-
if (tsResolved !== resolved && fs12.existsSync(tsResolved)) {
|
|
5907
|
-
entries.add(tsResolved);
|
|
5908
|
-
}
|
|
6015
|
+
tryAddEntryPath(pkgDir, pkg.main, entries);
|
|
5909
6016
|
}
|
|
5910
6017
|
const bin = pkg.bin;
|
|
5911
6018
|
if (typeof bin === "string") {
|
|
5912
|
-
|
|
5913
|
-
if (fs12.existsSync(resolved)) entries.add(resolved);
|
|
6019
|
+
tryAddEntryPath(pkgDir, bin, entries);
|
|
5914
6020
|
} else if (bin && typeof bin === "object") {
|
|
5915
6021
|
for (const value of Object.values(bin)) {
|
|
5916
6022
|
if (typeof value === "string") {
|
|
5917
|
-
|
|
5918
|
-
if (fs12.existsSync(resolved)) entries.add(resolved);
|
|
6023
|
+
tryAddEntryPath(pkgDir, value, entries);
|
|
5919
6024
|
}
|
|
5920
6025
|
}
|
|
5921
6026
|
}
|
|
5922
6027
|
for (const key of ["types", "typings"]) {
|
|
5923
6028
|
if (typeof pkg[key] === "string") {
|
|
5924
|
-
|
|
5925
|
-
if (fs12.existsSync(resolved)) entries.add(resolved);
|
|
6029
|
+
tryAddEntryPath(pkgDir, pkg[key], entries);
|
|
5926
6030
|
}
|
|
5927
6031
|
}
|
|
5928
6032
|
const exports_ = pkg.exports;
|
|
5929
6033
|
if (exports_ && typeof exports_ === "object") {
|
|
5930
6034
|
for (const value of Object.values(exports_)) {
|
|
5931
6035
|
if (typeof value === "string") {
|
|
5932
|
-
|
|
5933
|
-
if (fs12.existsSync(resolved)) entries.add(resolved);
|
|
6036
|
+
tryAddEntryPath(pkgDir, value, entries);
|
|
5934
6037
|
} else if (value && typeof value === "object") {
|
|
5935
|
-
for (const nested of Object.values(
|
|
5936
|
-
value
|
|
5937
|
-
)) {
|
|
6038
|
+
for (const nested of Object.values(value)) {
|
|
5938
6039
|
if (typeof nested === "string") {
|
|
5939
|
-
|
|
5940
|
-
if (fs12.existsSync(resolved)) entries.add(resolved);
|
|
6040
|
+
tryAddEntryPath(pkgDir, nested, entries);
|
|
5941
6041
|
}
|
|
5942
6042
|
}
|
|
5943
6043
|
}
|
|
5944
6044
|
}
|
|
5945
6045
|
}
|
|
5946
6046
|
}
|
|
6047
|
+
function expandGlobPattern(entry, projectRoot) {
|
|
6048
|
+
const dirs = [];
|
|
6049
|
+
if (entry.includes("*")) {
|
|
6050
|
+
const base = entry.replace(/\/\*+$/, "");
|
|
6051
|
+
const baseDir = path13.resolve(projectRoot, base);
|
|
6052
|
+
try {
|
|
6053
|
+
const children = fs12.readdirSync(baseDir, { withFileTypes: true });
|
|
6054
|
+
for (const child of children) {
|
|
6055
|
+
if (child.isDirectory()) {
|
|
6056
|
+
dirs.push(path13.join(baseDir, child.name));
|
|
6057
|
+
}
|
|
6058
|
+
}
|
|
6059
|
+
} catch {
|
|
6060
|
+
}
|
|
6061
|
+
} else {
|
|
6062
|
+
dirs.push(path13.resolve(projectRoot, entry));
|
|
6063
|
+
}
|
|
6064
|
+
return dirs;
|
|
6065
|
+
}
|
|
5947
6066
|
function extractWorkspaceGlobs(pkg, projectRoot) {
|
|
5948
6067
|
const dirs = [];
|
|
5949
6068
|
const workspaces = pkg.workspaces;
|
|
5950
6069
|
if (Array.isArray(workspaces)) {
|
|
5951
6070
|
for (const entry of workspaces) {
|
|
5952
6071
|
if (typeof entry === "string") {
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
5962
|
-
|
|
5963
|
-
|
|
6072
|
+
dirs.push(...expandGlobPattern(entry, projectRoot));
|
|
6073
|
+
}
|
|
6074
|
+
}
|
|
6075
|
+
}
|
|
6076
|
+
return dirs;
|
|
6077
|
+
}
|
|
6078
|
+
function extractPnpmWorkspaceDirs(projectRoot) {
|
|
6079
|
+
const yamlPath = path13.join(projectRoot, "pnpm-workspace.yaml");
|
|
6080
|
+
if (!fs12.existsSync(yamlPath)) return [];
|
|
6081
|
+
try {
|
|
6082
|
+
const content = fs12.readFileSync(yamlPath, "utf8");
|
|
6083
|
+
const dirs = [];
|
|
6084
|
+
let inPackages = false;
|
|
6085
|
+
const lines = content.split("\n");
|
|
6086
|
+
const itemRe = /^\s+-\s+"([^"]+)"|^\s+-\s+'([^']+)'|^\s+-\s+(\S+)/;
|
|
6087
|
+
for (const line of lines) {
|
|
6088
|
+
const trimmed = line.trim();
|
|
6089
|
+
if (/^packages\s*:\s*$/.test(trimmed)) {
|
|
6090
|
+
inPackages = true;
|
|
6091
|
+
continue;
|
|
6092
|
+
}
|
|
6093
|
+
if (inPackages && trimmed.length > 0 && !line.startsWith(" ") && !line.startsWith(" ")) {
|
|
6094
|
+
if (!trimmed.startsWith("-")) {
|
|
6095
|
+
inPackages = false;
|
|
6096
|
+
continue;
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
if (inPackages) {
|
|
6100
|
+
const m = itemRe.exec(line);
|
|
6101
|
+
if (m) {
|
|
6102
|
+
const entry = m[1] ?? m[2] ?? m[3];
|
|
6103
|
+
if (entry) {
|
|
6104
|
+
dirs.push(...expandGlobPattern(entry, projectRoot));
|
|
5964
6105
|
}
|
|
5965
|
-
} else {
|
|
5966
|
-
dirs.push(path13.resolve(projectRoot, entry));
|
|
5967
6106
|
}
|
|
5968
6107
|
}
|
|
5969
6108
|
}
|
|
6109
|
+
return dirs;
|
|
6110
|
+
} catch {
|
|
6111
|
+
return [];
|
|
5970
6112
|
}
|
|
5971
|
-
|
|
6113
|
+
}
|
|
6114
|
+
function resolveModulePath(importerPath, moduleSpecifier, indexedFiles) {
|
|
6115
|
+
if (!moduleSpecifier.startsWith(".")) return [];
|
|
6116
|
+
const dir = path13.dirname(importerPath);
|
|
6117
|
+
const base = path13.resolve(dir, moduleSpecifier);
|
|
6118
|
+
const results = [];
|
|
6119
|
+
const stripped = base.replace(/\.(ts|tsx|js|jsx|mjs|cjs)$/, "");
|
|
6120
|
+
const skipBase = stripped !== base && /\.(ts|tsx|js|jsx|mjs|cjs)$/.test(base);
|
|
6121
|
+
const candidates = skipBase ? [stripped] : [base];
|
|
6122
|
+
for (const candidate of candidates) {
|
|
6123
|
+
if (indexedFiles.has(candidate + ".ts")) results.push(candidate + ".ts");
|
|
6124
|
+
if (indexedFiles.has(candidate + ".tsx")) results.push(candidate + ".tsx");
|
|
6125
|
+
if (indexedFiles.has(candidate + ".js")) results.push(candidate + ".js");
|
|
6126
|
+
if (indexedFiles.has(candidate + ".jsx")) results.push(candidate + ".jsx");
|
|
6127
|
+
if (indexedFiles.has(candidate + ".mjs")) results.push(candidate + ".mjs");
|
|
6128
|
+
if (indexedFiles.has(candidate + ".cjs")) results.push(candidate + ".cjs");
|
|
6129
|
+
if (indexedFiles.has(path13.join(candidate, "index.ts")))
|
|
6130
|
+
results.push(path13.join(candidate, "index.ts"));
|
|
6131
|
+
if (indexedFiles.has(path13.join(candidate, "index.tsx")))
|
|
6132
|
+
results.push(path13.join(candidate, "index.tsx"));
|
|
6133
|
+
if (indexedFiles.has(path13.join(candidate, "index.js")))
|
|
6134
|
+
results.push(path13.join(candidate, "index.js"));
|
|
6135
|
+
if (indexedFiles.has(path13.join(candidate, "index.jsx")))
|
|
6136
|
+
results.push(path13.join(candidate, "index.jsx"));
|
|
6137
|
+
if (indexedFiles.has(path13.join(candidate, "index.mjs")))
|
|
6138
|
+
results.push(path13.join(candidate, "index.mjs"));
|
|
6139
|
+
if (indexedFiles.has(path13.join(candidate, "index.cjs")))
|
|
6140
|
+
results.push(path13.join(candidate, "index.cjs"));
|
|
6141
|
+
}
|
|
6142
|
+
return [...new Set(results)];
|
|
6143
|
+
}
|
|
6144
|
+
function parseNamedExportSymbols(matchText) {
|
|
6145
|
+
const braceStart = matchText.indexOf("{");
|
|
6146
|
+
if (braceStart === -1) return null;
|
|
6147
|
+
const braceEnd = matchText.indexOf("}", braceStart);
|
|
6148
|
+
if (braceEnd === -1) return null;
|
|
6149
|
+
const inner = matchText.slice(braceStart + 1, braceEnd);
|
|
6150
|
+
const symbols = [];
|
|
6151
|
+
for (const part of inner.split(",")) {
|
|
6152
|
+
let s = part.trim();
|
|
6153
|
+
if (!s) continue;
|
|
6154
|
+
s = s.replace(/^type\s+/, "");
|
|
6155
|
+
const asIdx = s.search(/\s+as\s+/);
|
|
6156
|
+
if (asIdx !== -1) {
|
|
6157
|
+
s = s.slice(0, asIdx).trim();
|
|
6158
|
+
}
|
|
6159
|
+
if (s) symbols.push(s);
|
|
6160
|
+
}
|
|
6161
|
+
return symbols;
|
|
5972
6162
|
}
|
|
5973
6163
|
function runDeadCodeScan(projectRoot, opts = {}) {
|
|
5974
6164
|
const store = opts.store ?? indexStorePool.acquire(projectRoot, { indexDir: opts.indexDir });
|
|
@@ -5990,12 +6180,71 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
5990
6180
|
}
|
|
5991
6181
|
const discoveredFiles = discoverEntryPoints(projectRoot, opts.userEntryPoints);
|
|
5992
6182
|
const entryFileSet = new Set(discoveredFiles.map((f) => path13.resolve(f)));
|
|
6183
|
+
const indexedFiles = /* @__PURE__ */ new Set();
|
|
6184
|
+
for (const s of allSymbols) indexedFiles.add(s.file);
|
|
6185
|
+
for (const fm of store.getAllFileMetas()) indexedFiles.add(fm.file);
|
|
5993
6186
|
const seedIds = /* @__PURE__ */ new Set();
|
|
5994
6187
|
for (const s of allSymbols) {
|
|
5995
6188
|
if (entryFileSet.has(s.file)) {
|
|
5996
6189
|
seedIds.add(s.id);
|
|
5997
6190
|
}
|
|
5998
6191
|
}
|
|
6192
|
+
const fileToSymbolIds = /* @__PURE__ */ new Map();
|
|
6193
|
+
for (const s of allSymbols) {
|
|
6194
|
+
let byFile = fileToSymbolIds.get(s.file);
|
|
6195
|
+
if (!byFile) {
|
|
6196
|
+
byFile = [];
|
|
6197
|
+
fileToSymbolIds.set(s.file, byFile);
|
|
6198
|
+
}
|
|
6199
|
+
byFile.push(s.id);
|
|
6200
|
+
}
|
|
6201
|
+
const scannedBarrels = /* @__PURE__ */ new Set();
|
|
6202
|
+
const barrelWorkList = [...entryFileSet];
|
|
6203
|
+
while (barrelWorkList.length > 0) {
|
|
6204
|
+
const epFile = barrelWorkList.pop();
|
|
6205
|
+
if (scannedBarrels.has(epFile)) continue;
|
|
6206
|
+
scannedBarrels.add(epFile);
|
|
6207
|
+
try {
|
|
6208
|
+
const content = fs12.readFileSync(epFile, "utf8");
|
|
6209
|
+
const strippedContent = content.replace(/\/\*[\s\S]*?\*\//g, (m) => " ".repeat(m.length)).replace(/\/\/[^\n]*/g, (m) => " ".repeat(m.length));
|
|
6210
|
+
const reExportRe = /export\s+(?:(?:type\s+)?\{[\s\S]*?\}\s+from|\*\s+as\s+\w+\s+from|\*\s+from)\s+['"]([^'"]+)['"]/g;
|
|
6211
|
+
let match;
|
|
6212
|
+
while ((match = reExportRe.exec(strippedContent)) !== null) {
|
|
6213
|
+
const moduleSpec = match[1];
|
|
6214
|
+
const resolvedFiles = resolveModulePath(epFile, moduleSpec, indexedFiles);
|
|
6215
|
+
for (const rf of resolvedFiles) {
|
|
6216
|
+
const fileSyms = fileToSymbolIds.get(rf);
|
|
6217
|
+
if (fileSyms) {
|
|
6218
|
+
const namedSymbols = parseNamedExportSymbols(match[0]);
|
|
6219
|
+
if (namedSymbols) {
|
|
6220
|
+
const nameSet = new Set(namedSymbols);
|
|
6221
|
+
for (const sid of fileSyms) {
|
|
6222
|
+
const sym = symbolById.get(sid);
|
|
6223
|
+
if (sym && nameSet.has(sym.name)) seedIds.add(sid);
|
|
6224
|
+
}
|
|
6225
|
+
} else {
|
|
6226
|
+
for (const sid of fileSyms) seedIds.add(sid);
|
|
6227
|
+
}
|
|
6228
|
+
}
|
|
6229
|
+
if (!scannedBarrels.has(rf)) {
|
|
6230
|
+
barrelWorkList.push(rf);
|
|
6231
|
+
}
|
|
6232
|
+
}
|
|
6233
|
+
}
|
|
6234
|
+
} catch (err) {
|
|
6235
|
+
if (err instanceof Error && err.code !== "ENOENT") {
|
|
6236
|
+
console.warn(
|
|
6237
|
+
JSON.stringify({
|
|
6238
|
+
level: "warn",
|
|
6239
|
+
event: "dead_code_scan_barrel_read_failed",
|
|
6240
|
+
message: err.message,
|
|
6241
|
+
file: epFile,
|
|
6242
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
6243
|
+
})
|
|
6244
|
+
);
|
|
6245
|
+
}
|
|
6246
|
+
}
|
|
6247
|
+
}
|
|
5999
6248
|
const alive = new Set(seedIds);
|
|
6000
6249
|
const frontier = [...seedIds];
|
|
6001
6250
|
const visitedEdges = /* @__PURE__ */ new Set();
|
|
@@ -6029,8 +6278,7 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
6029
6278
|
dead.push({
|
|
6030
6279
|
name: s.name,
|
|
6031
6280
|
kind: s.kind,
|
|
6032
|
-
lang: "ts",
|
|
6033
|
-
// populated from symbol file metadata
|
|
6281
|
+
lang: detectLang(s.file) ?? "ts",
|
|
6034
6282
|
file: s.file,
|
|
6035
6283
|
line: s.line,
|
|
6036
6284
|
reason
|
|
@@ -6055,16 +6303,14 @@ function runDeadCodeScan(projectRoot, opts = {}) {
|
|
|
6055
6303
|
deadFiles.push({
|
|
6056
6304
|
file,
|
|
6057
6305
|
symbolCount: syms.length,
|
|
6058
|
-
lang:
|
|
6306
|
+
lang: detectLang(file) ?? "ts"
|
|
6059
6307
|
});
|
|
6060
6308
|
}
|
|
6061
6309
|
}
|
|
6062
6310
|
const deadPackages = [];
|
|
6063
6311
|
const pkgEntries = findPackageEntries(projectRoot);
|
|
6064
6312
|
for (const [pkgName, pkgDir] of pkgEntries) {
|
|
6065
|
-
const pkgFiles = allSymbols.filter(
|
|
6066
|
-
(s) => s.file.startsWith(pkgDir + path13.sep)
|
|
6067
|
-
);
|
|
6313
|
+
const pkgFiles = allSymbols.filter((s) => s.file.startsWith(pkgDir + path13.sep));
|
|
6068
6314
|
if (pkgFiles.length === 0) continue;
|
|
6069
6315
|
const pkgUsed = pkgFiles.filter((s) => alive.has(s.id));
|
|
6070
6316
|
if (pkgUsed.length === 0) {
|
|
@@ -6105,7 +6351,10 @@ function findPackageEntries(projectRoot) {
|
|
|
6105
6351
|
pkgMap.set(rootPkg.name, projectRoot);
|
|
6106
6352
|
}
|
|
6107
6353
|
if (rootPkg) {
|
|
6108
|
-
|
|
6354
|
+
let wsDirs = extractWorkspaceGlobs(rootPkg, projectRoot);
|
|
6355
|
+
if (wsDirs.length === 0) {
|
|
6356
|
+
wsDirs = extractPnpmWorkspaceDirs(projectRoot);
|
|
6357
|
+
}
|
|
6109
6358
|
for (const wsDir of wsDirs) {
|
|
6110
6359
|
const wsPkg = tryReadJson(path13.join(wsDir, "package.json"));
|
|
6111
6360
|
if (wsPkg && typeof wsPkg.name === "string") {
|