@wrongstack/tools 0.269.0 → 0.272.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/audit.js +10 -5
- package/dist/audit.js.map +1 -1
- package/dist/{background-indexer-CJ5JiV5i.d.ts → background-indexer-BoTUw0EM.d.ts} +1 -1
- package/dist/bash.js +591 -11
- package/dist/bash.js.map +1 -1
- package/dist/builtin.js +857 -174
- package/dist/builtin.js.map +1 -1
- package/dist/codebase-index/index.d.ts +13 -3
- package/dist/codebase-index/index.js +129 -74
- package/dist/codebase-index/index.js.map +1 -1
- package/dist/codebase-index/worker.js +126 -71
- package/dist/codebase-index/worker.js.map +1 -1
- package/dist/exec.js +5 -2
- package/dist/exec.js.map +1 -1
- package/dist/fetch.js +24 -1
- package/dist/fetch.js.map +1 -1
- package/dist/format.js +10 -5
- package/dist/format.js.map +1 -1
- package/dist/grep.js +55 -33
- package/dist/grep.js.map +1 -1
- package/dist/index.d.ts +317 -3
- package/dist/index.js +1416 -202
- package/dist/index.js.map +1 -1
- package/dist/install.js +10 -5
- package/dist/install.js.map +1 -1
- package/dist/lint.js +10 -5
- package/dist/lint.js.map +1 -1
- package/dist/pack.js +857 -174
- package/dist/pack.js.map +1 -1
- package/dist/process-registry.js +5 -2
- package/dist/process-registry.js.map +1 -1
- package/dist/read.js +2 -2
- package/dist/read.js.map +1 -1
- package/dist/search.js.map +1 -1
- package/dist/test.js +10 -5
- package/dist/test.js.map +1 -1
- package/dist/typecheck.js +10 -5
- package/dist/typecheck.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
import { parentPort } from 'node:worker_threads';
|
|
2
2
|
import { expectDefined, resolveWstackPaths, compileGlob, truncate } from '@wrongstack/core';
|
|
3
|
-
import * as
|
|
3
|
+
import * as fs6 from 'node:fs/promises';
|
|
4
4
|
import * as path4 from 'node:path';
|
|
5
5
|
import { toErrorMessage } from '@wrongstack/core/utils';
|
|
6
6
|
import { createRequire } from 'node:module';
|
|
7
7
|
import * as fs from 'node:fs';
|
|
8
|
-
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
9
8
|
import * as ts from 'typescript';
|
|
10
|
-
import { execFileSync,
|
|
9
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
11
10
|
import * as os from 'node:os';
|
|
12
11
|
|
|
13
12
|
// src/codebase-index/worker.ts
|
|
@@ -385,33 +384,53 @@ var IndexStore = class {
|
|
|
385
384
|
}
|
|
386
385
|
}
|
|
387
386
|
// ─── Symbol CRUD ─────────────────────────────────────────────────────────────
|
|
388
|
-
|
|
387
|
+
/**
|
|
388
|
+
* Insert symbols, assigning IDs atomically inside `BEGIN IMMEDIATE` /
|
|
389
|
+
* `COMMIT`. The ID allocation (`SELECT MAX(id)`) and all `INSERT`s share
|
|
390
|
+
* the same transaction, preventing UNIQUE constraint violations when two
|
|
391
|
+
* processes index concurrently (each would see a different `MAX(id)` and
|
|
392
|
+
* neither can insert with the other's IDs).
|
|
393
|
+
*
|
|
394
|
+
* @returns The symbols array with `id` fields populated so the caller can
|
|
395
|
+
* use them for refs without re-reading from the DB.
|
|
396
|
+
*/
|
|
397
|
+
insertSymbols(symbols) {
|
|
389
398
|
return this.runWithRetry(() => {
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
stmt.run(
|
|
398
|
-
id,
|
|
399
|
-
s.lang,
|
|
400
|
-
s.kind,
|
|
401
|
-
s.name,
|
|
402
|
-
s.file,
|
|
403
|
-
s.line,
|
|
404
|
-
s.col,
|
|
405
|
-
s.signature,
|
|
406
|
-
s.docComment,
|
|
407
|
-
s.scope,
|
|
408
|
-
s.text,
|
|
409
|
-
s.file
|
|
399
|
+
this.db.exec("BEGIN IMMEDIATE");
|
|
400
|
+
try {
|
|
401
|
+
const maxRows = this.db.prepare("SELECT MAX(id) AS m FROM symbols").all();
|
|
402
|
+
let nextId = (maxRows[0]?.m ?? 0) + 1;
|
|
403
|
+
const stmt = this.db.prepare(
|
|
404
|
+
`INSERT INTO symbols(id, lang, kind, name, file, line, col, signature, doc_comment, scope, text, file_fk)
|
|
405
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
410
406
|
);
|
|
411
|
-
ftsStmt
|
|
412
|
-
|
|
407
|
+
const ftsStmt = this.ftsAvailable ? this.db.prepare("INSERT INTO symbols_fts(rowid, text) VALUES (?, ?)") : null;
|
|
408
|
+
const result = [];
|
|
409
|
+
for (const s of symbols) {
|
|
410
|
+
const id = nextId++;
|
|
411
|
+
stmt.run(
|
|
412
|
+
id,
|
|
413
|
+
s.lang,
|
|
414
|
+
s.kind,
|
|
415
|
+
s.name,
|
|
416
|
+
s.file,
|
|
417
|
+
s.line,
|
|
418
|
+
s.col,
|
|
419
|
+
s.signature,
|
|
420
|
+
s.docComment,
|
|
421
|
+
s.scope,
|
|
422
|
+
s.text,
|
|
423
|
+
s.file
|
|
424
|
+
);
|
|
425
|
+
ftsStmt?.run(id, buildIndexableText(s.name, s.signature, s.docComment));
|
|
426
|
+
result.push({ ...s, id });
|
|
427
|
+
}
|
|
428
|
+
this.db.exec("COMMIT");
|
|
429
|
+
return result;
|
|
430
|
+
} catch (err) {
|
|
431
|
+
this.db.exec("ROLLBACK");
|
|
432
|
+
throw err;
|
|
413
433
|
}
|
|
414
|
-
return id;
|
|
415
434
|
});
|
|
416
435
|
}
|
|
417
436
|
deleteSymbolsForFile(file) {
|
|
@@ -965,10 +984,10 @@ function detectLang(file) {
|
|
|
965
984
|
if (idx < 0) return null;
|
|
966
985
|
return extToLang(file.slice(idx));
|
|
967
986
|
}
|
|
968
|
-
function parseSymbols2(opts) {
|
|
987
|
+
async function parseSymbols2(opts) {
|
|
969
988
|
const { file, content, lang } = opts;
|
|
970
989
|
try {
|
|
971
|
-
return syncGoParse(file, content, lang);
|
|
990
|
+
return await syncGoParse(file, content, lang);
|
|
972
991
|
} catch {
|
|
973
992
|
return { file, lang, symbols: [], mtimeMs: Date.now() };
|
|
974
993
|
}
|
|
@@ -1205,19 +1224,34 @@ func formatType(t ast.Expr) string {
|
|
|
1205
1224
|
}
|
|
1206
1225
|
}
|
|
1207
1226
|
`;
|
|
1208
|
-
function syncGoParse(filePath, content, lang) {
|
|
1227
|
+
async function syncGoParse(filePath, content, lang) {
|
|
1209
1228
|
const tmpDir = path4.join(os.tmpdir(), "ws-go-parse");
|
|
1210
1229
|
try {
|
|
1211
|
-
|
|
1230
|
+
await fs6.mkdir(tmpDir, { recursive: true });
|
|
1212
1231
|
const scriptPath = path4.join(tmpDir, "parse.go");
|
|
1213
|
-
|
|
1214
|
-
const
|
|
1215
|
-
|
|
1216
|
-
timeout: 15e3,
|
|
1217
|
-
encoding: "utf8",
|
|
1232
|
+
await fs6.writeFile(scriptPath, GO_PARSE_SCRIPT, "utf8");
|
|
1233
|
+
const proc = spawn("go", ["run", scriptPath], {
|
|
1234
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1218
1235
|
windowsHide: true
|
|
1219
1236
|
});
|
|
1220
|
-
|
|
1237
|
+
let stdout = "";
|
|
1238
|
+
proc.stdout?.on("data", (chunk) => {
|
|
1239
|
+
stdout += chunk.toString();
|
|
1240
|
+
});
|
|
1241
|
+
proc.stdin?.write(content);
|
|
1242
|
+
proc.stdin?.end();
|
|
1243
|
+
const { code } = await Promise.race([
|
|
1244
|
+
new Promise((resolve2) => {
|
|
1245
|
+
proc.on("close", (c) => resolve2({ code: c }));
|
|
1246
|
+
}),
|
|
1247
|
+
new Promise(
|
|
1248
|
+
(_, reject) => setTimeout(() => {
|
|
1249
|
+
proc.kill("SIGKILL");
|
|
1250
|
+
reject(new Error("timeout"));
|
|
1251
|
+
}, 15e3)
|
|
1252
|
+
)
|
|
1253
|
+
]).catch(() => ({ code: -1 }));
|
|
1254
|
+
if (code !== 0 || !stdout.trim()) {
|
|
1221
1255
|
return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
|
|
1222
1256
|
}
|
|
1223
1257
|
const raw = JSON.parse(stdout.trim());
|
|
@@ -1239,10 +1273,10 @@ function syncGoParse(filePath, content, lang) {
|
|
|
1239
1273
|
return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
|
|
1240
1274
|
}
|
|
1241
1275
|
}
|
|
1242
|
-
function parseSymbols3(opts) {
|
|
1276
|
+
async function parseSymbols3(opts) {
|
|
1243
1277
|
const { file, lang } = opts;
|
|
1244
1278
|
try {
|
|
1245
|
-
return syncPyParse(file, lang);
|
|
1279
|
+
return await syncPyParse(file, lang);
|
|
1246
1280
|
} catch {
|
|
1247
1281
|
return { file, lang, symbols: [], mtimeMs: Date.now() };
|
|
1248
1282
|
}
|
|
@@ -1451,18 +1485,32 @@ visitor.visit(tree)
|
|
|
1451
1485
|
|
|
1452
1486
|
print(json.dumps([s.to_dict() for s in syms]))
|
|
1453
1487
|
`;
|
|
1454
|
-
function syncPyParse(filePath, lang) {
|
|
1488
|
+
async function syncPyParse(filePath, lang) {
|
|
1455
1489
|
try {
|
|
1456
1490
|
const tmpDir = path4.join(os.tmpdir(), "ws-py-parse");
|
|
1457
|
-
|
|
1491
|
+
await fs6.mkdir(tmpDir, { recursive: true });
|
|
1458
1492
|
const scriptPath = path4.join(tmpDir, "parse.py");
|
|
1459
|
-
|
|
1460
|
-
const
|
|
1461
|
-
|
|
1462
|
-
encoding: "utf8",
|
|
1493
|
+
await fs6.writeFile(scriptPath, PY_PARSE_SCRIPT, "utf8");
|
|
1494
|
+
const proc = spawn("python", [scriptPath, filePath], {
|
|
1495
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1463
1496
|
windowsHide: true
|
|
1464
1497
|
});
|
|
1465
|
-
|
|
1498
|
+
let stdout = "";
|
|
1499
|
+
proc.stdout?.on("data", (chunk) => {
|
|
1500
|
+
stdout += chunk.toString();
|
|
1501
|
+
});
|
|
1502
|
+
const { code } = await Promise.race([
|
|
1503
|
+
new Promise((resolve2) => {
|
|
1504
|
+
proc.on("close", (c) => resolve2({ code: c }));
|
|
1505
|
+
}),
|
|
1506
|
+
new Promise(
|
|
1507
|
+
(_, reject) => setTimeout(() => {
|
|
1508
|
+
proc.kill("SIGKILL");
|
|
1509
|
+
reject(new Error("timeout"));
|
|
1510
|
+
}, 15e3)
|
|
1511
|
+
)
|
|
1512
|
+
]).catch(() => ({ code: -1 }));
|
|
1513
|
+
if (code !== 0 || !stdout.trim()) {
|
|
1466
1514
|
return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
|
|
1467
1515
|
}
|
|
1468
1516
|
const raw = JSON.parse(stdout.trim());
|
|
@@ -1484,11 +1532,11 @@ function syncPyParse(filePath, lang) {
|
|
|
1484
1532
|
return { file: filePath, lang, symbols: [], mtimeMs: Date.now() };
|
|
1485
1533
|
}
|
|
1486
1534
|
}
|
|
1487
|
-
function parseSymbols4(opts) {
|
|
1535
|
+
async function parseSymbols4(opts) {
|
|
1488
1536
|
const { file, content, lang } = opts;
|
|
1489
1537
|
const nativeAvailable = checkNativeParser();
|
|
1490
1538
|
if (nativeAvailable) {
|
|
1491
|
-
const result = tryNativeParse(file, content);
|
|
1539
|
+
const result = await tryNativeParse(file, content);
|
|
1492
1540
|
if (result) return result;
|
|
1493
1541
|
}
|
|
1494
1542
|
return regexParse({ file, content, lang });
|
|
@@ -1518,25 +1566,34 @@ function checkNativeParser() {
|
|
|
1518
1566
|
return false;
|
|
1519
1567
|
}
|
|
1520
1568
|
}
|
|
1521
|
-
function tryNativeParse(file, content) {
|
|
1569
|
+
async function tryNativeParse(file, content) {
|
|
1522
1570
|
try {
|
|
1523
1571
|
const toolsDir = path4.join(process.cwd(), "tools");
|
|
1524
1572
|
const crateDir = path4.join(toolsDir, "syn-parser");
|
|
1525
1573
|
const tmpFile = path4.join(crateDir, "src", "input.rs");
|
|
1526
|
-
|
|
1527
|
-
const
|
|
1528
|
-
|
|
1529
|
-
["
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1574
|
+
await fs6.writeFile(tmpFile, content, "utf8");
|
|
1575
|
+
const proc = spawn("cargo", ["run", "--manifest-path", path4.join(toolsDir, "Cargo.toml")], {
|
|
1576
|
+
cwd: process.cwd(),
|
|
1577
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
1578
|
+
windowsHide: true
|
|
1579
|
+
});
|
|
1580
|
+
let stdout = "";
|
|
1581
|
+
proc.stdout?.on("data", (chunk) => {
|
|
1582
|
+
stdout += chunk.toString();
|
|
1583
|
+
});
|
|
1584
|
+
const { code } = await Promise.race([
|
|
1585
|
+
new Promise((resolve2) => {
|
|
1586
|
+
proc.on("close", (c) => resolve2({ code: c }));
|
|
1587
|
+
}),
|
|
1588
|
+
new Promise(
|
|
1589
|
+
(_, reject) => setTimeout(() => {
|
|
1590
|
+
proc.kill("SIGKILL");
|
|
1591
|
+
reject(new Error("timeout"));
|
|
1592
|
+
}, 15e3)
|
|
1593
|
+
)
|
|
1594
|
+
]).catch(() => ({ code: -1 }));
|
|
1595
|
+
if (code === 0 && stdout.trim()) {
|
|
1596
|
+
const symbols = JSON.parse(stdout.trim());
|
|
1540
1597
|
return {
|
|
1541
1598
|
file,
|
|
1542
1599
|
lang: "rs",
|
|
@@ -2005,7 +2062,7 @@ function compileGitignore(lines) {
|
|
|
2005
2062
|
async function loadGitignoreMatcher(projectRoot) {
|
|
2006
2063
|
let lines = [];
|
|
2007
2064
|
try {
|
|
2008
|
-
const raw = await
|
|
2065
|
+
const raw = await fs6.readFile(path4.join(projectRoot, ".gitignore"), "utf8");
|
|
2009
2066
|
lines = raw.split("\n");
|
|
2010
2067
|
} catch {
|
|
2011
2068
|
}
|
|
@@ -2063,7 +2120,7 @@ async function findSourceFiles(projectRoot, ignore, isGitIgnored, signal) {
|
|
|
2063
2120
|
}
|
|
2064
2121
|
let entries;
|
|
2065
2122
|
try {
|
|
2066
|
-
entries = await
|
|
2123
|
+
entries = await fs6.readdir(dir, { withFileTypes: true });
|
|
2067
2124
|
} catch {
|
|
2068
2125
|
return;
|
|
2069
2126
|
}
|
|
@@ -2161,7 +2218,7 @@ async function runIndexerWithStore(store, opts) {
|
|
|
2161
2218
|
batchFiles.map(async (file) => {
|
|
2162
2219
|
let stat2;
|
|
2163
2220
|
try {
|
|
2164
|
-
stat2 = await
|
|
2221
|
+
stat2 = await fs6.stat(file, statOpts);
|
|
2165
2222
|
} catch (e) {
|
|
2166
2223
|
if (isAbortError(e)) throw e;
|
|
2167
2224
|
return { file, stat: null, lang: "", parsed: null, error: `stat error: ${e instanceof Error ? e.message : String(e)}` };
|
|
@@ -2175,7 +2232,7 @@ async function runIndexerWithStore(store, opts) {
|
|
|
2175
2232
|
}
|
|
2176
2233
|
let content;
|
|
2177
2234
|
try {
|
|
2178
|
-
content = await
|
|
2235
|
+
content = await fs6.readFile(file, { encoding: "utf8", signal });
|
|
2179
2236
|
} catch (e) {
|
|
2180
2237
|
if (isAbortError(e)) throw e;
|
|
2181
2238
|
return { file, stat: stat2, lang, parsed: null, error: `read error: ${e instanceof Error ? e.message : String(e)}` };
|
|
@@ -2225,9 +2282,7 @@ async function runIndexerWithStore(store, opts) {
|
|
|
2225
2282
|
filesIndexed++;
|
|
2226
2283
|
continue;
|
|
2227
2284
|
}
|
|
2228
|
-
const
|
|
2229
|
-
const symbolsWithIds = parsed.symbols.map((s, i) => ({ ...s, id: nextId + i }));
|
|
2230
|
-
store.insertSymbols(symbolsWithIds, nextId);
|
|
2285
|
+
const symbolsWithIds = store.insertSymbols(parsed.symbols);
|
|
2231
2286
|
const count = symbolsWithIds.length;
|
|
2232
2287
|
symbolsIndexed += count;
|
|
2233
2288
|
langStats[lang] = (langStats[lang] ?? 0) + count;
|
|
@@ -2256,7 +2311,7 @@ async function runIndexerWithStore(store, opts) {
|
|
|
2256
2311
|
}
|
|
2257
2312
|
for (const [file_] of existingMeta) {
|
|
2258
2313
|
try {
|
|
2259
|
-
await
|
|
2314
|
+
await fs6.stat(file_);
|
|
2260
2315
|
} catch {
|
|
2261
2316
|
store.deleteFile(file_);
|
|
2262
2317
|
}
|