@halecraft/verify 1.2.0 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +73 -15
- package/bin/verify.mjs +13 -1
- package/dist/index.d.ts +56 -14
- package/dist/index.js +181 -74
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -25,6 +25,7 @@ var VerificationNodeSchema = z.lazy(
|
|
|
25
25
|
}),
|
|
26
26
|
name: z.string().optional(),
|
|
27
27
|
run: z.union([z.string(), VerificationCommandSchema]).optional(),
|
|
28
|
+
fix: z.union([z.string(), VerificationCommandSchema]).optional(),
|
|
28
29
|
children: z.array(VerificationNodeSchema).optional(),
|
|
29
30
|
strategy: z.enum(["parallel", "sequential", "fail-fast"]).optional(),
|
|
30
31
|
parser: z.string().optional(),
|
|
@@ -43,7 +44,9 @@ var VerifyOptionsSchema = z.object({
|
|
|
43
44
|
noColor: z.boolean().optional(),
|
|
44
45
|
topLevelOnly: z.boolean().optional(),
|
|
45
46
|
noTty: z.boolean().optional(),
|
|
46
|
-
|
|
47
|
+
quiet: z.boolean().optional(),
|
|
48
|
+
passthrough: z.array(z.string()).optional(),
|
|
49
|
+
fix: z.boolean().optional()
|
|
47
50
|
});
|
|
48
51
|
var PackageDiscoveryOptionsSchema = z.object({
|
|
49
52
|
patterns: z.array(z.string()).optional(),
|
|
@@ -123,7 +126,9 @@ function mergeOptions(configOptions, cliOptions) {
|
|
|
123
126
|
noColor: cliOptions?.noColor ?? configOptions?.noColor ?? false,
|
|
124
127
|
topLevelOnly: cliOptions?.topLevelOnly ?? configOptions?.topLevelOnly ?? false,
|
|
125
128
|
noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false,
|
|
126
|
-
|
|
129
|
+
quiet: cliOptions?.quiet ?? configOptions?.quiet ?? false,
|
|
130
|
+
passthrough: cliOptions?.passthrough ?? configOptions?.passthrough,
|
|
131
|
+
fix: cliOptions?.fix ?? configOptions?.fix ?? false
|
|
127
132
|
};
|
|
128
133
|
}
|
|
129
134
|
|
|
@@ -238,6 +243,33 @@ function collectPaths(nodes) {
|
|
|
238
243
|
});
|
|
239
244
|
return paths;
|
|
240
245
|
}
|
|
246
|
+
function flattenResults(results) {
|
|
247
|
+
const flat = [];
|
|
248
|
+
for (const r of results) {
|
|
249
|
+
flat.push(r);
|
|
250
|
+
if (r.children) {
|
|
251
|
+
flat.push(...flattenResults(r.children));
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return flat;
|
|
255
|
+
}
|
|
256
|
+
function hasFixAvailable(tasks, results) {
|
|
257
|
+
const failedPaths = /* @__PURE__ */ new Set();
|
|
258
|
+
for (const r of flattenResults(results)) {
|
|
259
|
+
if (!r.ok && !r.blocked) {
|
|
260
|
+
failedPaths.add(r.path);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (failedPaths.size === 0) return false;
|
|
264
|
+
let found = false;
|
|
265
|
+
walkNodes(tasks, (node, path) => {
|
|
266
|
+
if (found) return;
|
|
267
|
+
if (node.fix && !node.children && failedPaths.has(path)) {
|
|
268
|
+
found = true;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
return found;
|
|
272
|
+
}
|
|
241
273
|
|
|
242
274
|
// src/filter.ts
|
|
243
275
|
var TaskNotFoundError = class extends Error {
|
|
@@ -351,6 +383,12 @@ var TOOL_PATTERNS = [
|
|
|
351
383
|
const biomeMatch = content.match(/biome\s+([^&|;]+)/);
|
|
352
384
|
return biomeMatch ? biomeMatch[1].trim() : "check .";
|
|
353
385
|
},
|
|
386
|
+
getFixArgs: (match, content) => {
|
|
387
|
+
const biomeMatch = content.match(/biome\s+([^&|;]+)/);
|
|
388
|
+
const args = biomeMatch ? biomeMatch[1].trim() : "check .";
|
|
389
|
+
if (args.includes("--write")) return null;
|
|
390
|
+
return args.replace(/^(check|lint|format)/, "$1 --write");
|
|
391
|
+
},
|
|
354
392
|
parser: "biome"
|
|
355
393
|
},
|
|
356
394
|
// ESLint
|
|
@@ -360,6 +398,12 @@ var TOOL_PATTERNS = [
|
|
|
360
398
|
getArgs: (_, content) => {
|
|
361
399
|
const eslintMatch = content.match(/eslint\s+([^&|;]+)/);
|
|
362
400
|
return eslintMatch ? eslintMatch[1].trim() : ".";
|
|
401
|
+
},
|
|
402
|
+
getFixArgs: (_, content) => {
|
|
403
|
+
const eslintMatch = content.match(/eslint\s+([^&|;]+)/);
|
|
404
|
+
const args = eslintMatch ? eslintMatch[1].trim() : ".";
|
|
405
|
+
if (args.includes("--fix")) return null;
|
|
406
|
+
return `${args} --fix`;
|
|
363
407
|
}
|
|
364
408
|
},
|
|
365
409
|
// Prettier
|
|
@@ -369,6 +413,13 @@ var TOOL_PATTERNS = [
|
|
|
369
413
|
getArgs: (_, content) => {
|
|
370
414
|
const prettierMatch = content.match(/prettier\s+([^&|;]+)/);
|
|
371
415
|
return prettierMatch ? prettierMatch[1].trim() : "--check .";
|
|
416
|
+
},
|
|
417
|
+
getFixArgs: (_, content) => {
|
|
418
|
+
const prettierMatch = content.match(/prettier\s+([^&|;]+)/);
|
|
419
|
+
const args = prettierMatch ? prettierMatch[1].trim() : "--check .";
|
|
420
|
+
if (args.includes("--write")) return null;
|
|
421
|
+
if (args.includes("--check")) return args.replace("--check", "--write");
|
|
422
|
+
return `--write ${args}`;
|
|
372
423
|
}
|
|
373
424
|
},
|
|
374
425
|
// TypeScript
|
|
@@ -514,7 +565,14 @@ function extractOptimizedCommand(cwd, scriptContent) {
|
|
|
514
565
|
if (match && binaryExists(cwd, tool.binary)) {
|
|
515
566
|
const args = tool.getArgs(match, scriptContent);
|
|
516
567
|
const command = args ? `${tool.binary} ${args}` : tool.binary;
|
|
517
|
-
|
|
568
|
+
let fixCommand;
|
|
569
|
+
if (tool.getFixArgs) {
|
|
570
|
+
const fixArgs = tool.getFixArgs(match, scriptContent);
|
|
571
|
+
if (fixArgs) {
|
|
572
|
+
fixCommand = `${tool.binary} ${fixArgs}`;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
return { command, parser: tool.parser, fixCommand };
|
|
518
576
|
}
|
|
519
577
|
}
|
|
520
578
|
return null;
|
|
@@ -542,7 +600,8 @@ function detectFromPackageJson(cwd) {
|
|
|
542
600
|
scriptName,
|
|
543
601
|
command: optimized?.command ?? `npm run ${scriptName}`,
|
|
544
602
|
category,
|
|
545
|
-
parser: optimized?.parser
|
|
603
|
+
parser: optimized?.parser,
|
|
604
|
+
fixCommand: optimized?.fixCommand
|
|
546
605
|
});
|
|
547
606
|
}
|
|
548
607
|
break;
|
|
@@ -612,6 +671,9 @@ function generateImport(format) {
|
|
|
612
671
|
}
|
|
613
672
|
function generateTask(task, indent) {
|
|
614
673
|
const parts = [`key: "${task.key}"`, `run: "${task.command}"`];
|
|
674
|
+
if (task.fixCommand) {
|
|
675
|
+
parts.push(`fix: "${task.fixCommand}"`);
|
|
676
|
+
}
|
|
615
677
|
if (task.parser) {
|
|
616
678
|
parts.push(`parser: "${task.parser}"`);
|
|
617
679
|
}
|
|
@@ -956,20 +1018,36 @@ var vitestParser = {
|
|
|
956
1018
|
id: "vitest",
|
|
957
1019
|
parse(output, exitCode) {
|
|
958
1020
|
const cleanOutput = stripAnsi(output);
|
|
959
|
-
const
|
|
1021
|
+
const testsLineMatch = cleanOutput.match(/Tests\s+(.+?)\s*\((\d+)\)/m);
|
|
960
1022
|
const durationMatch = cleanOutput.match(/Duration\s+([\d.]+(?:ms|s))\b/m);
|
|
961
|
-
if (!
|
|
1023
|
+
if (!testsLineMatch) {
|
|
962
1024
|
return null;
|
|
963
1025
|
}
|
|
964
|
-
const
|
|
965
|
-
const total = Number.parseInt(
|
|
1026
|
+
const statsStr = testsLineMatch[1];
|
|
1027
|
+
const total = Number.parseInt(testsLineMatch[2], 10);
|
|
1028
|
+
const passedMatch = statsStr.match(/(\d+)\s+passed/);
|
|
1029
|
+
const failedMatch = statsStr.match(/(\d+)\s+failed/);
|
|
1030
|
+
const skippedMatch = statsStr.match(/(\d+)\s+skipped/);
|
|
1031
|
+
const passed = passedMatch ? Number.parseInt(passedMatch[1], 10) : 0;
|
|
1032
|
+
const skipped = skippedMatch ? Number.parseInt(skippedMatch[1], 10) : 0;
|
|
966
1033
|
const duration = durationMatch ? durationMatch[1] : void 0;
|
|
1034
|
+
const failed = failedMatch ? Number.parseInt(failedMatch[1], 10) : total - passed - skipped;
|
|
1035
|
+
const ran = passed + failed;
|
|
1036
|
+
let summary;
|
|
1037
|
+
if (ran === 0 && skipped > 0) {
|
|
1038
|
+
summary = `${skipped} tests skipped (no matches)`;
|
|
1039
|
+
} else if (skipped > 0) {
|
|
1040
|
+
summary = exitCode === 0 ? `passed ${passed}/${ran} tests (${skipped} skipped)` : `passed ${passed}/${ran} tests (${skipped} skipped, some failed)`;
|
|
1041
|
+
} else {
|
|
1042
|
+
summary = exitCode === 0 ? `passed ${passed}/${total} tests` : `passed ${passed}/${total} tests (some failed)`;
|
|
1043
|
+
}
|
|
967
1044
|
return {
|
|
968
|
-
summary
|
|
1045
|
+
summary,
|
|
969
1046
|
metrics: {
|
|
970
1047
|
passed,
|
|
971
1048
|
total,
|
|
972
|
-
failed
|
|
1049
|
+
failed,
|
|
1050
|
+
skipped,
|
|
973
1051
|
duration
|
|
974
1052
|
}
|
|
975
1053
|
};
|
|
@@ -1106,20 +1184,31 @@ var cursor = {
|
|
|
1106
1184
|
moveToStart: "\x1B[0G",
|
|
1107
1185
|
clearLine: "\x1B[2K"
|
|
1108
1186
|
};
|
|
1109
|
-
function
|
|
1187
|
+
function defaultTerminalContext() {
|
|
1188
|
+
return { isTTY: !!process.stdout.isTTY, env: process.env };
|
|
1189
|
+
}
|
|
1190
|
+
function shouldUseColors(options, ctx) {
|
|
1110
1191
|
if (options.noColor) return false;
|
|
1111
1192
|
if (options.format === "json") return false;
|
|
1112
|
-
if (!
|
|
1113
|
-
if ("NO_COLOR" in
|
|
1114
|
-
if (
|
|
1193
|
+
if (!ctx.isTTY) return false;
|
|
1194
|
+
if ("NO_COLOR" in ctx.env) return false;
|
|
1195
|
+
if (ctx.env.TERM === "dumb") return false;
|
|
1196
|
+
return true;
|
|
1197
|
+
}
|
|
1198
|
+
function shouldUseLiveDashboard(options, ctx) {
|
|
1199
|
+
if (options.noTty) return false;
|
|
1200
|
+
if (ctx.env.TURBO_IS_TUI === "true") return false;
|
|
1201
|
+
if (ctx.isTTY && ctx.env.TURBO_HASH != null) return false;
|
|
1202
|
+
if (!ctx.isTTY) return false;
|
|
1115
1203
|
return true;
|
|
1116
1204
|
}
|
|
1117
1205
|
var BaseReporter = class {
|
|
1118
1206
|
colorEnabled;
|
|
1119
1207
|
stream;
|
|
1120
1208
|
taskDepths = /* @__PURE__ */ new Map();
|
|
1121
|
-
constructor(options = {}) {
|
|
1122
|
-
|
|
1209
|
+
constructor(options = {}, ctx) {
|
|
1210
|
+
const termCtx = ctx ?? defaultTerminalContext();
|
|
1211
|
+
this.colorEnabled = shouldUseColors(options, termCtx);
|
|
1123
1212
|
this.stream = options.format === "json" ? process.stderr : process.stdout;
|
|
1124
1213
|
}
|
|
1125
1214
|
/**
|
|
@@ -1141,10 +1230,10 @@ var BaseReporter = class {
|
|
|
1141
1230
|
return this.colorEnabled ? this.c(ansi.red, "\u2717") : "FAIL";
|
|
1142
1231
|
}
|
|
1143
1232
|
/**
|
|
1144
|
-
* Get
|
|
1233
|
+
* Get blocked mark (⊘ or BLOCK)
|
|
1145
1234
|
*/
|
|
1146
|
-
|
|
1147
|
-
return this.colorEnabled ? this.c(ansi.yellow, "\u2298") : "
|
|
1235
|
+
blockedMark() {
|
|
1236
|
+
return this.colorEnabled ? this.c(ansi.yellow, "\u2298") : "BLOCK";
|
|
1148
1237
|
}
|
|
1149
1238
|
/**
|
|
1150
1239
|
* Get arrow symbol (→ or ->)
|
|
@@ -1172,6 +1261,22 @@ var BaseReporter = class {
|
|
|
1172
1261
|
this.taskDepths.set(path, depth);
|
|
1173
1262
|
});
|
|
1174
1263
|
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Format a completed task result line in name-first format.
|
|
1266
|
+
* Shared by LiveDashboardReporter and SequentialReporter.
|
|
1267
|
+
*/
|
|
1268
|
+
formatResultLine(name, result) {
|
|
1269
|
+
const duration = this.c(ansi.dim, `${result.durationMs}ms`);
|
|
1270
|
+
if (result.blocked) {
|
|
1271
|
+
const reason = result.blockedBy ? `by ${result.blockedBy}` : "by dependency";
|
|
1272
|
+
return `${this.blockedMark()} ${this.c(ansi.bold, name)} blocked ${this.c(ansi.dim, `(${reason}, ${duration})`)}`;
|
|
1273
|
+
}
|
|
1274
|
+
const summary = this.extractSummary(result);
|
|
1275
|
+
if (result.ok) {
|
|
1276
|
+
return `${this.okMark()} ${this.c(ansi.bold, name)} verified ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
|
|
1277
|
+
}
|
|
1278
|
+
return `${this.failMark()} ${this.c(ansi.bold, name)} failed ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
|
|
1279
|
+
}
|
|
1175
1280
|
/**
|
|
1176
1281
|
* Extract summary from task result
|
|
1177
1282
|
*/
|
|
@@ -1207,7 +1312,7 @@ var BaseReporter = class {
|
|
|
1207
1312
|
for (const r of flatResults) {
|
|
1208
1313
|
if (r.children) continue;
|
|
1209
1314
|
if (logsMode === "failed" && r.ok) continue;
|
|
1210
|
-
if (r.
|
|
1315
|
+
if (r.blocked) continue;
|
|
1211
1316
|
const status = r.ok ? this.c(ansi.green, "OK") : this.c(ansi.red, "FAIL");
|
|
1212
1317
|
this.stream.write(
|
|
1213
1318
|
`
|
|
@@ -1225,6 +1330,13 @@ ${this.c(ansi.bold, "====")} ${this.c(ansi.bold, r.path.toUpperCase())} ${status
|
|
|
1225
1330
|
this.stream.write(`${finalMessage}
|
|
1226
1331
|
`);
|
|
1227
1332
|
}
|
|
1333
|
+
outputFixHint(result) {
|
|
1334
|
+
if (result.fixAvailable && !result.ok) {
|
|
1335
|
+
this.stream.write(`
|
|
1336
|
+
\u{1F4A1} Tip: run "verify --fix" to attempt auto-fixes
|
|
1337
|
+
`);
|
|
1338
|
+
}
|
|
1339
|
+
}
|
|
1228
1340
|
};
|
|
1229
1341
|
var LiveDashboardReporter = class extends BaseReporter {
|
|
1230
1342
|
topLevelOnly;
|
|
@@ -1232,8 +1344,8 @@ var LiveDashboardReporter = class extends BaseReporter {
|
|
|
1232
1344
|
taskOrder = [];
|
|
1233
1345
|
spinner;
|
|
1234
1346
|
lineCount = 0;
|
|
1235
|
-
constructor(options = {}) {
|
|
1236
|
-
super(options);
|
|
1347
|
+
constructor(options = {}, ctx) {
|
|
1348
|
+
super(options, ctx);
|
|
1237
1349
|
this.topLevelOnly = options.topLevelOnly ?? false;
|
|
1238
1350
|
this.spinner = new SpinnerManager();
|
|
1239
1351
|
const cleanup = () => {
|
|
@@ -1294,16 +1406,7 @@ var LiveDashboardReporter = class extends BaseReporter {
|
|
|
1294
1406
|
return `${indent}${this.arrow()} verifying ${this.c(ansi.bold, displayKey)} ${spinnerChar}`;
|
|
1295
1407
|
}
|
|
1296
1408
|
if (task.status === "completed" && task.result) {
|
|
1297
|
-
|
|
1298
|
-
if (task.result.suppressed) {
|
|
1299
|
-
const reason = task.result.suppressedBy ? `${task.result.suppressedBy} failed` : "dependency failed";
|
|
1300
|
-
return `${indent}${this.suppressedMark()} suppressed ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${reason}, ${duration})`)}`;
|
|
1301
|
-
}
|
|
1302
|
-
const summary = this.extractSummary(task.result);
|
|
1303
|
-
if (task.result.ok) {
|
|
1304
|
-
return `${indent}${this.okMark()} verified ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
|
|
1305
|
-
}
|
|
1306
|
-
return `${indent}${this.failMark()} failed ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
|
|
1409
|
+
return `${indent}${this.formatResultLine(displayKey, task.result)}`;
|
|
1307
1410
|
}
|
|
1308
1411
|
return "";
|
|
1309
1412
|
}
|
|
@@ -1353,8 +1456,8 @@ var LiveDashboardReporter = class extends BaseReporter {
|
|
|
1353
1456
|
};
|
|
1354
1457
|
var SequentialReporter = class extends BaseReporter {
|
|
1355
1458
|
topLevelOnly;
|
|
1356
|
-
constructor(options = {}) {
|
|
1357
|
-
super(options);
|
|
1459
|
+
constructor(options = {}, ctx) {
|
|
1460
|
+
super(options, ctx);
|
|
1358
1461
|
this.topLevelOnly = options.topLevelOnly ?? false;
|
|
1359
1462
|
}
|
|
1360
1463
|
onStart(tasks) {
|
|
@@ -1374,27 +1477,8 @@ var SequentialReporter = class extends BaseReporter {
|
|
|
1374
1477
|
}
|
|
1375
1478
|
onTaskComplete(result) {
|
|
1376
1479
|
if (!this.shouldDisplay(result.path)) return;
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
const reason = result.suppressedBy ? `${result.suppressedBy} failed` : "dependency failed";
|
|
1380
|
-
this.stream.write(
|
|
1381
|
-
`${this.suppressedMark()} suppressed ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${reason}, ${duration})`)}
|
|
1382
|
-
`
|
|
1383
|
-
);
|
|
1384
|
-
return;
|
|
1385
|
-
}
|
|
1386
|
-
const summary = this.extractSummary(result);
|
|
1387
|
-
if (result.ok) {
|
|
1388
|
-
this.stream.write(
|
|
1389
|
-
`${this.okMark()} verified ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}
|
|
1390
|
-
`
|
|
1391
|
-
);
|
|
1392
|
-
} else {
|
|
1393
|
-
this.stream.write(
|
|
1394
|
-
`${this.failMark()} failed ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}
|
|
1395
|
-
`
|
|
1396
|
-
);
|
|
1397
|
-
}
|
|
1480
|
+
this.stream.write(`${this.formatResultLine(result.path, result)}
|
|
1481
|
+
`);
|
|
1398
1482
|
}
|
|
1399
1483
|
onFinish() {
|
|
1400
1484
|
}
|
|
@@ -1416,6 +1500,7 @@ var JSONReporter = class {
|
|
|
1416
1500
|
startedAt: result.startedAt,
|
|
1417
1501
|
finishedAt: result.finishedAt,
|
|
1418
1502
|
durationMs: result.durationMs,
|
|
1503
|
+
...result.fixAvailable ? { fixAvailable: result.fixAvailable } : {},
|
|
1419
1504
|
tasks: this.serializeTasks(result.tasks)
|
|
1420
1505
|
};
|
|
1421
1506
|
process.stdout.write(`${JSON.stringify(summary)}
|
|
@@ -1429,8 +1514,8 @@ var JSONReporter = class {
|
|
|
1429
1514
|
code: t.code,
|
|
1430
1515
|
durationMs: t.durationMs,
|
|
1431
1516
|
summaryLine: t.summaryLine,
|
|
1432
|
-
...t.
|
|
1433
|
-
...t.
|
|
1517
|
+
...t.blocked ? { blocked: t.blocked } : {},
|
|
1518
|
+
...t.blockedBy ? { blockedBy: t.blockedBy } : {},
|
|
1434
1519
|
...t.children ? { children: this.serializeTasks(t.children) } : {}
|
|
1435
1520
|
}));
|
|
1436
1521
|
}
|
|
@@ -1451,15 +1536,25 @@ var QuietReporter = class extends BaseReporter {
|
|
|
1451
1536
|
process.stdout.write(`${message}
|
|
1452
1537
|
`);
|
|
1453
1538
|
}
|
|
1539
|
+
outputFixHint(result) {
|
|
1540
|
+
if (result.fixAvailable && !result.ok) {
|
|
1541
|
+
process.stdout.write(`\u{1F4A1} fix available: verify --fix
|
|
1542
|
+
`);
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1454
1545
|
};
|
|
1455
1546
|
function createReporter(options) {
|
|
1547
|
+
const ctx = defaultTerminalContext();
|
|
1456
1548
|
if (options.format === "json") {
|
|
1457
1549
|
return new JSONReporter();
|
|
1458
1550
|
}
|
|
1459
|
-
if (
|
|
1460
|
-
return new
|
|
1551
|
+
if (options.quiet) {
|
|
1552
|
+
return new QuietReporter(options, ctx);
|
|
1461
1553
|
}
|
|
1462
|
-
|
|
1554
|
+
if (shouldUseLiveDashboard(options, ctx)) {
|
|
1555
|
+
return new LiveDashboardReporter(options, ctx);
|
|
1556
|
+
}
|
|
1557
|
+
return new SequentialReporter(options, ctx);
|
|
1463
1558
|
}
|
|
1464
1559
|
|
|
1465
1560
|
// src/runner.ts
|
|
@@ -1716,6 +1811,10 @@ var ReportingDependencyTracker = class {
|
|
|
1716
1811
|
};
|
|
1717
1812
|
|
|
1718
1813
|
// src/runner.ts
|
|
1814
|
+
function resolveCommand(node, fix) {
|
|
1815
|
+
if (fix && node.fix) return node.fix;
|
|
1816
|
+
return node.run;
|
|
1817
|
+
}
|
|
1719
1818
|
function mergeEnv(base, overlay) {
|
|
1720
1819
|
if (!overlay) return { ...base };
|
|
1721
1820
|
const result = { ...base };
|
|
@@ -1911,12 +2010,14 @@ var VerificationRunner = class {
|
|
|
1911
2010
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1912
2011
|
const durationMs = Date.now() - wallStart;
|
|
1913
2012
|
const allOk = results.every((r) => r.ok);
|
|
2013
|
+
const fixAvailable = hasFixAvailable(tasks, results);
|
|
1914
2014
|
return {
|
|
1915
2015
|
ok: allOk,
|
|
1916
2016
|
startedAt,
|
|
1917
2017
|
finishedAt,
|
|
1918
2018
|
durationMs,
|
|
1919
|
-
tasks: results
|
|
2019
|
+
tasks: results,
|
|
2020
|
+
...fixAvailable ? { fixAvailable } : {}
|
|
1920
2021
|
};
|
|
1921
2022
|
}
|
|
1922
2023
|
/**
|
|
@@ -1973,9 +2074,9 @@ var VerificationRunner = class {
|
|
|
1973
2074
|
nodeEnv
|
|
1974
2075
|
);
|
|
1975
2076
|
const durationMs2 = Date.now() - start;
|
|
1976
|
-
const allOk = childResults.every((r) => r.ok || r.
|
|
1977
|
-
const
|
|
1978
|
-
const
|
|
2077
|
+
const allOk = childResults.every((r) => r.ok || r.blocked);
|
|
2078
|
+
const allBlocked = childResults.length > 0 && childResults.every((r) => r.blocked);
|
|
2079
|
+
const anyBlocked = childResults.some((r) => r.blocked);
|
|
1979
2080
|
const result2 = {
|
|
1980
2081
|
key: node.key,
|
|
1981
2082
|
path,
|
|
@@ -1986,16 +2087,17 @@ var VerificationRunner = class {
|
|
|
1986
2087
|
summaryLine: allOk ? node.successLabel ?? `${node.key}: all passed` : node.failureLabel ?? `${node.key}: some failed`,
|
|
1987
2088
|
children: childResults
|
|
1988
2089
|
};
|
|
1989
|
-
if (
|
|
1990
|
-
result2.
|
|
1991
|
-
result2.
|
|
1992
|
-
} else if (
|
|
2090
|
+
if (allBlocked) {
|
|
2091
|
+
result2.blocked = true;
|
|
2092
|
+
result2.blockedBy = childResults[0].blockedBy;
|
|
2093
|
+
} else if (anyBlocked && !allOk) {
|
|
1993
2094
|
}
|
|
1994
2095
|
this.dependencyTracker.recordResult(result2);
|
|
1995
2096
|
this.callbacks.onTaskComplete?.(result2);
|
|
1996
2097
|
return result2;
|
|
1997
2098
|
}
|
|
1998
|
-
|
|
2099
|
+
const effectiveRun = resolveCommand(node, this.options.fix ?? false);
|
|
2100
|
+
if (!effectiveRun) {
|
|
1999
2101
|
const result2 = {
|
|
2000
2102
|
key: node.key,
|
|
2001
2103
|
path,
|
|
@@ -2011,7 +2113,7 @@ var VerificationRunner = class {
|
|
|
2011
2113
|
}
|
|
2012
2114
|
const passthrough = this.options.passthrough;
|
|
2013
2115
|
const command = normalizeCommand(
|
|
2014
|
-
|
|
2116
|
+
effectiveRun,
|
|
2015
2117
|
node.timeout,
|
|
2016
2118
|
passthrough,
|
|
2017
2119
|
nodeEnv
|
|
@@ -2050,8 +2152,8 @@ var VerificationRunner = class {
|
|
|
2050
2152
|
durationMs,
|
|
2051
2153
|
output,
|
|
2052
2154
|
summaryLine: `${node.key}: terminated`,
|
|
2053
|
-
|
|
2054
|
-
|
|
2155
|
+
blocked: true,
|
|
2156
|
+
blockedBy: failedDep ?? "unknown"
|
|
2055
2157
|
};
|
|
2056
2158
|
this.dependencyTracker.recordResult(result2);
|
|
2057
2159
|
this.callbacks.onTaskComplete?.(result2);
|
|
@@ -2087,8 +2189,8 @@ var VerificationRunner = class {
|
|
|
2087
2189
|
if (failedDep) {
|
|
2088
2190
|
result = {
|
|
2089
2191
|
...result,
|
|
2090
|
-
|
|
2091
|
-
|
|
2192
|
+
blocked: true,
|
|
2193
|
+
blockedBy: failedDep
|
|
2092
2194
|
};
|
|
2093
2195
|
}
|
|
2094
2196
|
}
|
|
@@ -2126,6 +2228,9 @@ async function verify(config, cliOptions) {
|
|
|
2126
2228
|
reporter.onFinish?.();
|
|
2127
2229
|
reporter.outputLogs(result.tasks, options.logs ?? "failed");
|
|
2128
2230
|
reporter.outputSummary(result);
|
|
2231
|
+
if (!options.fix) {
|
|
2232
|
+
reporter.outputFixHint?.(result);
|
|
2233
|
+
}
|
|
2129
2234
|
return result;
|
|
2130
2235
|
}
|
|
2131
2236
|
async function verifyFromConfig(cwd = process.cwd(), cliOptions) {
|
|
@@ -2163,11 +2268,13 @@ export {
|
|
|
2163
2268
|
generateConfigContent,
|
|
2164
2269
|
genericParser,
|
|
2165
2270
|
gotestParser,
|
|
2271
|
+
hasFixAvailable,
|
|
2166
2272
|
hasPackageChanged,
|
|
2167
2273
|
loadConfig,
|
|
2168
2274
|
loadConfigFromCwd,
|
|
2169
2275
|
mergeOptions,
|
|
2170
2276
|
parsers,
|
|
2277
|
+
resolveCommand,
|
|
2171
2278
|
resolveFilters,
|
|
2172
2279
|
runInit,
|
|
2173
2280
|
tscParser,
|