@wrongstack/tools 0.7.7 → 0.7.8

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.
@@ -1,9 +1,9 @@
1
1
  import * as fs2 from 'node:fs/promises';
2
2
  import * as path3 from 'node:path';
3
3
  import { compileGlob } from '@wrongstack/core';
4
+ import { createRequire } from 'node:module';
4
5
  import * as fs from 'node:fs';
5
6
  import { mkdirSync, writeFileSync, unlinkSync } from 'node:fs';
6
- import { DatabaseSync } from 'node:sqlite';
7
7
  import * as ts from 'typescript';
8
8
  import { execSync, spawnSync } from 'node:child_process';
9
9
 
@@ -82,12 +82,39 @@ function internalKindToLspKind(k) {
82
82
  // src/codebase-index/writer.ts
83
83
  var INDEX_DIR = ".codebase-index";
84
84
  var DB_FILE = "index.db";
85
+ var warningSilenced = false;
86
+ function silenceSqliteExperimentalWarning() {
87
+ if (warningSilenced) return;
88
+ warningSilenced = true;
89
+ const original = process.emitWarning.bind(process);
90
+ process.emitWarning = ((warning, ...rest) => {
91
+ const msg = typeof warning === "string" ? warning : warning?.message ?? "";
92
+ const name = typeof warning === "string" ? String(rest[0] ?? "") : warning?.name ?? "";
93
+ if (/sqlite/i.test(msg) && /experimental/i.test(`${name} ${msg}`)) return;
94
+ original(warning, ...rest);
95
+ });
96
+ }
97
+ var DatabaseSyncCtor;
98
+ function loadDatabaseSync() {
99
+ if (DatabaseSyncCtor) return DatabaseSyncCtor;
100
+ silenceSqliteExperimentalWarning();
101
+ try {
102
+ const req = createRequire(import.meta.url);
103
+ DatabaseSyncCtor = req("node:sqlite").DatabaseSync;
104
+ } catch (err) {
105
+ throw new Error(
106
+ `The codebase index needs Node's built-in SQLite (node:sqlite), available since Node 22.5. This runtime doesn't provide it: ${err instanceof Error ? err.message : String(err)}`
107
+ );
108
+ }
109
+ return DatabaseSyncCtor;
110
+ }
85
111
  var IndexStore = class {
86
112
  constructor(projectRoot) {
87
113
  this.projectRoot = projectRoot;
88
114
  const dir = path3.join(projectRoot, INDEX_DIR);
89
115
  fs.mkdirSync(dir, { recursive: true });
90
- this.db = new DatabaseSync(path3.join(dir, DB_FILE));
116
+ const Database = loadDatabaseSync();
117
+ this.db = new Database(path3.join(dir, DB_FILE));
91
118
  this.initSchema();
92
119
  }
93
120
  projectRoot;
@@ -1102,7 +1129,10 @@ function checkNativeParser() {
1102
1129
  execSync("rustc --version", { stdio: "pipe" });
1103
1130
  const toolsDir = path3.join(process.cwd(), "tools");
1104
1131
  try {
1105
- execSync("cargo metadata --no-deps --format-version 1 --manifest-path " + path3.join(toolsDir, "Cargo.toml"), { stdio: "pipe" });
1132
+ execSync(
1133
+ "cargo metadata --no-deps --format-version 1 --manifest-path " + path3.join(toolsDir, "Cargo.toml"),
1134
+ { stdio: "pipe" }
1135
+ );
1106
1136
  return true;
1107
1137
  } catch {
1108
1138
  return false;
@@ -1118,12 +1148,16 @@ function tryNativeParse(file, content) {
1118
1148
  const tmpFile = path3.join(crateDir, "src", "input.rs");
1119
1149
  const { writeFileSync: writeFileSync2 } = __require("node:fs");
1120
1150
  writeFileSync2(tmpFile, content, "utf8");
1121
- const result = spawnSync("cargo", ["run", "--manifest-path", path3.join(toolsDir, "Cargo.toml")], {
1122
- cwd: process.cwd(),
1123
- encoding: "utf8",
1124
- timeout: 15e3,
1125
- stdio: ["pipe", "pipe", "pipe"]
1126
- });
1151
+ const result = spawnSync(
1152
+ "cargo",
1153
+ ["run", "--manifest-path", path3.join(toolsDir, "Cargo.toml")],
1154
+ {
1155
+ cwd: process.cwd(),
1156
+ encoding: "utf8",
1157
+ timeout: 15e3,
1158
+ stdio: ["pipe", "pipe", "pipe"]
1159
+ }
1160
+ );
1127
1161
  if (result.status === 0 && result.stdout) {
1128
1162
  const symbols = JSON.parse(result.stdout);
1129
1163
  return {
@@ -1157,7 +1191,8 @@ function regexParse(opts) {
1157
1191
  lineOffsets.push(lineOffsets[i] + lines[i].length + 1);
1158
1192
  }
1159
1193
  function lineFromOffset(offset) {
1160
- let lo = 0, hi = lineOffsets.length - 1;
1194
+ let lo = 0;
1195
+ let hi = lineOffsets.length - 1;
1161
1196
  while (lo < hi) {
1162
1197
  const mid = lo + hi + 1 >>> 1;
1163
1198
  if (lineOffsets[mid] <= offset) lo = mid;
@@ -1171,8 +1206,7 @@ function regexParse(opts) {
1171
1206
  }
1172
1207
  for (const pattern of RS_PATTERNS) {
1173
1208
  pattern.regex.lastIndex = 0;
1174
- let match;
1175
- while ((match = pattern.regex.exec(content)) !== null) {
1209
+ for (let match = pattern.regex.exec(content); match !== null; match = pattern.regex.exec(content)) {
1176
1210
  const name = match[1];
1177
1211
  const offset = match.index;
1178
1212
  const line = lineFromOffset(offset);
@@ -1225,7 +1259,8 @@ function regexParse2(opts) {
1225
1259
  lineOffsets.push(lineOffsets[i] + lines[i].length + 1);
1226
1260
  }
1227
1261
  function lineFromOffset(offset) {
1228
- let lo = 0, hi = lineOffsets.length - 1;
1262
+ let lo = 0;
1263
+ let hi = lineOffsets.length - 1;
1229
1264
  while (lo < hi) {
1230
1265
  const mid = lo + hi + 1 >>> 1;
1231
1266
  if (lineOffsets[mid] <= offset) lo = mid;
@@ -1237,19 +1272,20 @@ function regexParse2(opts) {
1237
1272
  if (rootMatch) {
1238
1273
  const offset = rootMatch.index;
1239
1274
  const line = lineFromOffset(offset);
1240
- symbols.push(makeSymbol({
1241
- name: path3.basename(file),
1242
- kind: "object",
1243
- line,
1244
- col: 0,
1245
- signature: `"${path3.basename(file)}" = { ... }`,
1246
- file,
1247
- lang
1248
- }));
1275
+ symbols.push(
1276
+ makeSymbol({
1277
+ name: path3.basename(file),
1278
+ kind: "object",
1279
+ line,
1280
+ col: 0,
1281
+ signature: `"${path3.basename(file)}" = { ... }`,
1282
+ file,
1283
+ lang
1284
+ })
1285
+ );
1249
1286
  }
1250
1287
  const topLevelKeyRegex = /^\s*"([^"]+)"\s*:/gm;
1251
- let match;
1252
- while ((match = topLevelKeyRegex.exec(content)) !== null) {
1288
+ for (let match = topLevelKeyRegex.exec(content); match !== null; match = topLevelKeyRegex.exec(content)) {
1253
1289
  const key = match[1];
1254
1290
  const offset = match.index;
1255
1291
  const line = lineFromOffset(offset);
@@ -1276,15 +1312,17 @@ function regexParse2(opts) {
1276
1312
  signature = `"$ref": "..."`;
1277
1313
  }
1278
1314
  }
1279
- symbols.push(makeSymbol({
1280
- name: key,
1281
- kind,
1282
- line,
1283
- col,
1284
- signature,
1285
- file,
1286
- lang
1287
- }));
1315
+ symbols.push(
1316
+ makeSymbol({
1317
+ name: key,
1318
+ kind,
1319
+ line,
1320
+ col,
1321
+ signature,
1322
+ file,
1323
+ lang
1324
+ })
1325
+ );
1288
1326
  if (isPackageJson && key === "scripts") {
1289
1327
  extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFromOffset);
1290
1328
  }
@@ -1293,20 +1331,21 @@ function regexParse2(opts) {
1293
1331
  }
1294
1332
  }
1295
1333
  const defsRegex = /"\$defs"\s*:|"\$defs"\s*:/g;
1296
- let defsMatch;
1297
- while ((defsMatch = defsRegex.exec(content)) !== null) {
1334
+ const defsMatch = defsRegex.exec(content);
1335
+ if (defsMatch !== null) {
1298
1336
  const offset = defsMatch.index;
1299
1337
  const line = lineFromOffset(offset);
1300
- symbols.push(makeSymbol({
1301
- name: "$defs",
1302
- kind: "property",
1303
- line,
1304
- col: offset - (lineOffsets[line - 1] ?? 0),
1305
- signature: '"$defs": { ... }',
1306
- file,
1307
- lang
1308
- }));
1309
- break;
1338
+ symbols.push(
1339
+ makeSymbol({
1340
+ name: "$defs",
1341
+ kind: "property",
1342
+ line,
1343
+ col: offset - (lineOffsets[line - 1] ?? 0),
1344
+ signature: '"$defs": { ... }',
1345
+ file,
1346
+ lang
1347
+ })
1348
+ );
1310
1349
  }
1311
1350
  const defsPatterns = [
1312
1351
  /"\$defs"\s*:/g,
@@ -1316,69 +1355,71 @@ function regexParse2(opts) {
1316
1355
  ];
1317
1356
  for (const pat of defsPatterns) {
1318
1357
  pat.lastIndex = 0;
1319
- while ((match = pat.exec(content)) !== null) {
1358
+ for (let match = pat.exec(content); match !== null; match = pat.exec(content)) {
1320
1359
  const offset = match.index;
1321
1360
  const line = lineFromOffset(offset);
1322
1361
  const key = match[0].match(/"([^"]+)"/)?.[1] ?? match[0];
1323
- symbols.push(makeSymbol({
1324
- name: key,
1325
- kind: "property",
1326
- line,
1327
- col: offset - (lineOffsets[line - 1] ?? 0),
1328
- signature: `"${key}": { ... }`,
1329
- file,
1330
- lang
1331
- }));
1362
+ symbols.push(
1363
+ makeSymbol({
1364
+ name: key,
1365
+ kind: "property",
1366
+ line,
1367
+ col: offset - (lineOffsets[line - 1] ?? 0),
1368
+ signature: `"${key}": { ... }`,
1369
+ file,
1370
+ lang
1371
+ })
1372
+ );
1332
1373
  }
1333
1374
  }
1334
1375
  return { file, lang, symbols, mtimeMs: Date.now() };
1335
1376
  }
1336
1377
  function extractPackageScripts(content, symbols, file, lang, lineOffsets, lineFromOffset) {
1337
1378
  const scriptsBlockRegex = /"scripts"\s*:\s*\{([^}]+)\}/g;
1338
- let match;
1339
- while ((match = scriptsBlockRegex.exec(content)) !== null) {
1379
+ for (let match = scriptsBlockRegex.exec(content); match !== null; match = scriptsBlockRegex.exec(content)) {
1340
1380
  const blockContent = match[0];
1341
1381
  const blockOffset = match.index;
1342
1382
  const scriptKeyRegex = /"(\w[\w-]*)"\s*:/g;
1343
- let scriptMatch;
1344
- while ((scriptMatch = scriptKeyRegex.exec(blockContent)) !== null) {
1383
+ for (let scriptMatch = scriptKeyRegex.exec(blockContent); scriptMatch !== null; scriptMatch = scriptKeyRegex.exec(blockContent)) {
1345
1384
  const key = scriptMatch[1];
1346
1385
  const keyOffset = blockOffset + scriptMatch.index;
1347
1386
  const line = lineFromOffset(keyOffset);
1348
- symbols.push(makeSymbol({
1349
- name: key,
1350
- kind: "function",
1351
- line,
1352
- col: keyOffset - (lineOffsets[line - 1] ?? 0),
1353
- signature: `"${key}": "..."`,
1354
- file,
1355
- lang
1356
- }));
1387
+ symbols.push(
1388
+ makeSymbol({
1389
+ name: key,
1390
+ kind: "function",
1391
+ line,
1392
+ col: keyOffset - (lineOffsets[line - 1] ?? 0),
1393
+ signature: `"${key}": "..."`,
1394
+ file,
1395
+ lang
1396
+ })
1397
+ );
1357
1398
  }
1358
1399
  }
1359
1400
  }
1360
1401
  function extractCompilerOptions(content, symbols, file, lang, lineOffsets, parentLine, lineFromOffset) {
1361
1402
  const optsBlockRegex = /"compilerOptions"\s*:\s*\{([^}]+)\}/g;
1362
- let match;
1363
- while ((match = optsBlockRegex.exec(content)) !== null) {
1403
+ for (let match = optsBlockRegex.exec(content); match !== null; match = optsBlockRegex.exec(content)) {
1364
1404
  const blockContent = match[0];
1365
1405
  const blockOffset = match.index;
1366
1406
  const optKeyRegex = /"(\w[\w]*)"\s*:/g;
1367
- let optMatch;
1368
- while ((optMatch = optKeyRegex.exec(blockContent)) !== null) {
1407
+ for (let optMatch = optKeyRegex.exec(blockContent); optMatch !== null; optMatch = optKeyRegex.exec(blockContent)) {
1369
1408
  const key = optMatch[1];
1370
1409
  const keyOffset = blockOffset + optMatch.index;
1371
1410
  const line = lineFromOffset(keyOffset);
1372
1411
  if (line <= parentLine) continue;
1373
- symbols.push(makeSymbol({
1374
- name: key,
1375
- kind: "property",
1376
- line,
1377
- col: keyOffset - (lineOffsets[line - 1] ?? 0),
1378
- signature: `"${key}": ...`,
1379
- file,
1380
- lang
1381
- }));
1412
+ symbols.push(
1413
+ makeSymbol({
1414
+ name: key,
1415
+ kind: "property",
1416
+ line,
1417
+ col: keyOffset - (lineOffsets[line - 1] ?? 0),
1418
+ signature: `"${key}": ...`,
1419
+ file,
1420
+ lang
1421
+ })
1422
+ );
1382
1423
  }
1383
1424
  }
1384
1425
  }
@@ -1416,7 +1457,8 @@ function regexParse3(opts) {
1416
1457
  lineOffsets.push(lineOffsets[i] + lines[i].length + 1);
1417
1458
  }
1418
1459
  function lineFromOffset(offset) {
1419
- let lo = 0, hi = lineOffsets.length - 1;
1460
+ let lo = 0;
1461
+ let hi = lineOffsets.length - 1;
1420
1462
  while (lo < hi) {
1421
1463
  const mid = lo + hi + 1 >>> 1;
1422
1464
  if (lineOffsets[mid] <= offset) lo = mid;
@@ -1425,40 +1467,43 @@ function regexParse3(opts) {
1425
1467
  return lo + 1;
1426
1468
  }
1427
1469
  const anchorRegex = /&(\w[\w-]*)/g;
1428
- let match;
1429
- while ((match = anchorRegex.exec(content)) !== null) {
1470
+ for (let match = anchorRegex.exec(content); match !== null; match = anchorRegex.exec(content)) {
1430
1471
  const name = match[1];
1431
1472
  const offset = match.index;
1432
1473
  const line = lineFromOffset(offset);
1433
1474
  const col = offset - (lineOffsets[line - 1] ?? 0);
1434
- symbols.push(makeSymbol2({
1435
- name,
1436
- kind: "const",
1437
- line,
1438
- col,
1439
- signature: `&${name}`,
1440
- file,
1441
- lang
1442
- }));
1475
+ symbols.push(
1476
+ makeSymbol2({
1477
+ name,
1478
+ kind: "const",
1479
+ line,
1480
+ col,
1481
+ signature: `&${name}`,
1482
+ file,
1483
+ lang
1484
+ })
1485
+ );
1443
1486
  }
1444
1487
  const aliasRegex = /\*(\w[\w-]*)/g;
1445
- while ((match = aliasRegex.exec(content)) !== null) {
1488
+ for (let match = aliasRegex.exec(content); match !== null; match = aliasRegex.exec(content)) {
1446
1489
  const name = match[1];
1447
1490
  const offset = match.index;
1448
1491
  const line = lineFromOffset(offset);
1449
1492
  const col = offset - (lineOffsets[line - 1] ?? 0);
1450
- symbols.push(makeSymbol2({
1451
- name,
1452
- kind: "const",
1453
- line,
1454
- col,
1455
- signature: `*${name}`,
1456
- file,
1457
- lang
1458
- }));
1493
+ symbols.push(
1494
+ makeSymbol2({
1495
+ name,
1496
+ kind: "const",
1497
+ line,
1498
+ col,
1499
+ signature: `*${name}`,
1500
+ file,
1501
+ lang
1502
+ })
1503
+ );
1459
1504
  }
1460
1505
  const kvRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:/gm;
1461
- while ((match = kvRegex.exec(content)) !== null) {
1506
+ for (let match = kvRegex.exec(content); match !== null; match = kvRegex.exec(content)) {
1462
1507
  const indent = match[1].length;
1463
1508
  const key = match[2];
1464
1509
  const offset = match.index;
@@ -1474,38 +1519,42 @@ function regexParse3(opts) {
1474
1519
  symbols.push(makeSymbol2({ name: key, kind, line, col, signature, file, lang }));
1475
1520
  }
1476
1521
  const listItemRegex = /^-(\s+)([^:#\s][^:#\s]*)\s*:/gm;
1477
- while ((match = listItemRegex.exec(content)) !== null) {
1522
+ for (let match = listItemRegex.exec(content); match !== null; match = listItemRegex.exec(content)) {
1478
1523
  const key = match[2];
1479
1524
  const offset = match.index;
1480
1525
  const line = lineFromOffset(offset);
1481
1526
  const col = offset - (lineOffsets[line - 1] ?? 0);
1482
1527
  const value = extractValue(content, offset + match[0].length);
1483
1528
  const kind = isScalar(value) ? "literal" : "property";
1484
- symbols.push(makeSymbol2({
1485
- name: key,
1486
- kind,
1487
- line,
1488
- col,
1489
- signature: `- ${key}: ${truncate(value, 60)}`,
1490
- file,
1491
- lang
1492
- }));
1529
+ symbols.push(
1530
+ makeSymbol2({
1531
+ name: key,
1532
+ kind,
1533
+ line,
1534
+ col,
1535
+ signature: `- ${key}: ${truncate(value, 60)}`,
1536
+ file,
1537
+ lang
1538
+ })
1539
+ );
1493
1540
  }
1494
1541
  const blockScalarRegex = /^(\s*)([^:#\s][^:#\s]*)\s*:\s*[|>](\s|$)/gm;
1495
- while ((match = blockScalarRegex.exec(content)) !== null) {
1542
+ for (let match = blockScalarRegex.exec(content); match !== null; match = blockScalarRegex.exec(content)) {
1496
1543
  const key = match[2];
1497
1544
  const offset = match.index;
1498
1545
  const line = lineFromOffset(offset);
1499
1546
  const col = offset - (lineOffsets[line - 1] ?? 0);
1500
- symbols.push(makeSymbol2({
1501
- name: key,
1502
- kind: "property",
1503
- line,
1504
- col,
1505
- signature: `${key}: | ...`,
1506
- file,
1507
- lang
1508
- }));
1547
+ symbols.push(
1548
+ makeSymbol2({
1549
+ name: key,
1550
+ kind: "property",
1551
+ line,
1552
+ col,
1553
+ signature: `${key}: | ...`,
1554
+ file,
1555
+ lang
1556
+ })
1557
+ );
1509
1558
  }
1510
1559
  return { file, lang, symbols, mtimeMs: Date.now() };
1511
1560
  }