@halecraft/verify 1.0.0 → 1.2.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/README.md +216 -13
- package/bin/verify.mjs +120 -134
- package/dist/index.d.ts +157 -11
- package/dist/index.js +495 -111
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/dist/index.js
CHANGED
|
@@ -1,14 +1,76 @@
|
|
|
1
|
-
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
-
}) : x)(function(x) {
|
|
4
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
-
});
|
|
7
|
-
|
|
8
1
|
// src/config.ts
|
|
9
2
|
import { existsSync } from "fs";
|
|
10
3
|
import { join, resolve } from "path";
|
|
11
4
|
import { pathToFileURL } from "url";
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
var ConfigError = class extends Error {
|
|
7
|
+
constructor(message, configPath) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.configPath = configPath;
|
|
10
|
+
this.name = "ConfigError";
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var EnvSchema = z.record(z.string(), z.string().nullable()).optional();
|
|
14
|
+
var VerificationCommandSchema = z.object({
|
|
15
|
+
cmd: z.string(),
|
|
16
|
+
args: z.array(z.string()),
|
|
17
|
+
cwd: z.string().optional(),
|
|
18
|
+
env: EnvSchema,
|
|
19
|
+
timeout: z.number().positive().optional()
|
|
20
|
+
});
|
|
21
|
+
var VerificationNodeSchema = z.lazy(
|
|
22
|
+
() => z.object({
|
|
23
|
+
key: z.string().min(1, "Task key cannot be empty").refine((key) => !key.includes(":"), {
|
|
24
|
+
message: "Task key cannot contain ':' (reserved for paths)"
|
|
25
|
+
}),
|
|
26
|
+
name: z.string().optional(),
|
|
27
|
+
run: z.union([z.string(), VerificationCommandSchema]).optional(),
|
|
28
|
+
children: z.array(VerificationNodeSchema).optional(),
|
|
29
|
+
strategy: z.enum(["parallel", "sequential", "fail-fast"]).optional(),
|
|
30
|
+
parser: z.string().optional(),
|
|
31
|
+
successLabel: z.string().optional(),
|
|
32
|
+
failureLabel: z.string().optional(),
|
|
33
|
+
reportingDependsOn: z.array(z.string()).optional(),
|
|
34
|
+
timeout: z.number().positive().optional(),
|
|
35
|
+
env: EnvSchema
|
|
36
|
+
})
|
|
37
|
+
);
|
|
38
|
+
var VerifyOptionsSchema = z.object({
|
|
39
|
+
logs: z.enum(["all", "failed", "none"]).optional(),
|
|
40
|
+
format: z.enum(["human", "json"]).optional(),
|
|
41
|
+
filter: z.array(z.string()).optional(),
|
|
42
|
+
cwd: z.string().optional(),
|
|
43
|
+
noColor: z.boolean().optional(),
|
|
44
|
+
topLevelOnly: z.boolean().optional(),
|
|
45
|
+
noTty: z.boolean().optional(),
|
|
46
|
+
passthrough: z.array(z.string()).optional()
|
|
47
|
+
});
|
|
48
|
+
var PackageDiscoveryOptionsSchema = z.object({
|
|
49
|
+
patterns: z.array(z.string()).optional(),
|
|
50
|
+
filter: z.array(z.string()).optional(),
|
|
51
|
+
changed: z.boolean().optional()
|
|
52
|
+
});
|
|
53
|
+
var VerifyConfigSchema = z.object({
|
|
54
|
+
tasks: z.array(VerificationNodeSchema),
|
|
55
|
+
packages: PackageDiscoveryOptionsSchema.optional(),
|
|
56
|
+
options: VerifyOptionsSchema.optional(),
|
|
57
|
+
env: EnvSchema
|
|
58
|
+
});
|
|
59
|
+
function validateConfig(value, configPath) {
|
|
60
|
+
const result = VerifyConfigSchema.safeParse(value);
|
|
61
|
+
if (!result.success) {
|
|
62
|
+
const errors = result.error.issues.map((issue) => {
|
|
63
|
+
const path = issue.path.join(".");
|
|
64
|
+
return path ? `${path}: ${issue.message}` : issue.message;
|
|
65
|
+
});
|
|
66
|
+
throw new ConfigError(
|
|
67
|
+
`Invalid config:
|
|
68
|
+
- ${errors.join("\n - ")}`,
|
|
69
|
+
configPath
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
return result.data;
|
|
73
|
+
}
|
|
12
74
|
function defineConfig(config) {
|
|
13
75
|
return config;
|
|
14
76
|
}
|
|
@@ -38,9 +100,9 @@ async function loadConfig(configPath) {
|
|
|
38
100
|
const fileUrl = pathToFileURL(absolutePath).href;
|
|
39
101
|
const module = await import(fileUrl);
|
|
40
102
|
if (!module.default) {
|
|
41
|
-
throw new
|
|
103
|
+
throw new ConfigError(`Config file must have a default export`, configPath);
|
|
42
104
|
}
|
|
43
|
-
return module.default;
|
|
105
|
+
return validateConfig(module.default, configPath);
|
|
44
106
|
}
|
|
45
107
|
async function loadConfigFromCwd(cwd, configPath) {
|
|
46
108
|
if (configPath) {
|
|
@@ -60,13 +122,32 @@ function mergeOptions(configOptions, cliOptions) {
|
|
|
60
122
|
cwd: cliOptions?.cwd ?? configOptions?.cwd ?? process.cwd(),
|
|
61
123
|
noColor: cliOptions?.noColor ?? configOptions?.noColor ?? false,
|
|
62
124
|
topLevelOnly: cliOptions?.topLevelOnly ?? configOptions?.topLevelOnly ?? false,
|
|
63
|
-
noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false
|
|
125
|
+
noTty: cliOptions?.noTty ?? configOptions?.noTty ?? false,
|
|
126
|
+
passthrough: cliOptions?.passthrough ?? configOptions?.passthrough
|
|
64
127
|
};
|
|
65
128
|
}
|
|
66
129
|
|
|
67
130
|
// src/discovery.ts
|
|
68
|
-
import { existsSync as existsSync2, readdirSync, statSync } from "fs";
|
|
131
|
+
import { existsSync as existsSync2, readdirSync, readFileSync, statSync } from "fs";
|
|
69
132
|
import { join as join2, relative } from "path";
|
|
133
|
+
|
|
134
|
+
// src/schemas/package-json.ts
|
|
135
|
+
import { z as z2 } from "zod";
|
|
136
|
+
var PackageJsonSchema = z2.object({
|
|
137
|
+
name: z2.string().optional(),
|
|
138
|
+
scripts: z2.record(z2.string(), z2.string()).optional()
|
|
139
|
+
}).passthrough();
|
|
140
|
+
function parsePackageJson(content) {
|
|
141
|
+
try {
|
|
142
|
+
const parsed = JSON.parse(content);
|
|
143
|
+
const result = PackageJsonSchema.safeParse(parsed);
|
|
144
|
+
return result.success ? result.data : null;
|
|
145
|
+
} catch {
|
|
146
|
+
return null;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/discovery.ts
|
|
70
151
|
var DEFAULT_PATTERNS = ["packages/*", "apps/*"];
|
|
71
152
|
function findMatchingDirs(rootDir, patterns) {
|
|
72
153
|
const results = [];
|
|
@@ -98,8 +179,9 @@ function getPackageName(packageDir) {
|
|
|
98
179
|
return null;
|
|
99
180
|
}
|
|
100
181
|
try {
|
|
101
|
-
const content =
|
|
102
|
-
|
|
182
|
+
const content = readFileSync(packageJsonPath, "utf-8");
|
|
183
|
+
const parsed = parsePackageJson(content);
|
|
184
|
+
return parsed?.name ?? null;
|
|
103
185
|
} catch {
|
|
104
186
|
return null;
|
|
105
187
|
}
|
|
@@ -132,8 +214,133 @@ async function hasPackageChanged(_packagePath, _baseBranch = "main") {
|
|
|
132
214
|
return true;
|
|
133
215
|
}
|
|
134
216
|
|
|
217
|
+
// src/filter.ts
|
|
218
|
+
import leven from "leven";
|
|
219
|
+
|
|
220
|
+
// src/tree.ts
|
|
221
|
+
var PATH_SEPARATOR = ":";
|
|
222
|
+
function buildTaskPath(parentPath, key) {
|
|
223
|
+
return parentPath ? `${parentPath}${PATH_SEPARATOR}${key}` : key;
|
|
224
|
+
}
|
|
225
|
+
function walkNodes(nodes, visitor, parentPath = "", depth = 0) {
|
|
226
|
+
for (const node of nodes) {
|
|
227
|
+
const path = buildTaskPath(parentPath, node.key);
|
|
228
|
+
visitor(node, path, depth);
|
|
229
|
+
if (node.children) {
|
|
230
|
+
walkNodes(node.children, visitor, path, depth + 1);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function collectPaths(nodes) {
|
|
235
|
+
const paths = [];
|
|
236
|
+
walkNodes(nodes, (_node, path) => {
|
|
237
|
+
paths.push(path);
|
|
238
|
+
});
|
|
239
|
+
return paths;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/filter.ts
|
|
243
|
+
var TaskNotFoundError = class extends Error {
|
|
244
|
+
constructor(filter, suggestion, availableTasks) {
|
|
245
|
+
super(buildErrorMessage(filter, suggestion, availableTasks));
|
|
246
|
+
this.filter = filter;
|
|
247
|
+
this.suggestion = suggestion;
|
|
248
|
+
this.availableTasks = availableTasks;
|
|
249
|
+
this.name = "TaskNotFoundError";
|
|
250
|
+
}
|
|
251
|
+
exitCode = 2;
|
|
252
|
+
};
|
|
253
|
+
var AmbiguousTaskError = class extends Error {
|
|
254
|
+
constructor(filter, matches) {
|
|
255
|
+
super(buildAmbiguousErrorMessage(filter, matches));
|
|
256
|
+
this.filter = filter;
|
|
257
|
+
this.matches = matches;
|
|
258
|
+
this.name = "AmbiguousTaskError";
|
|
259
|
+
}
|
|
260
|
+
exitCode = 2;
|
|
261
|
+
};
|
|
262
|
+
function buildErrorMessage(filter, suggestion, availableTasks) {
|
|
263
|
+
let message = `Task "${filter}" not found.`;
|
|
264
|
+
if (suggestion) {
|
|
265
|
+
message += `
|
|
266
|
+
|
|
267
|
+
Did you mean "${suggestion}"?`;
|
|
268
|
+
}
|
|
269
|
+
message += "\n\nAvailable tasks:";
|
|
270
|
+
for (const task of availableTasks) {
|
|
271
|
+
message += `
|
|
272
|
+
${task}`;
|
|
273
|
+
}
|
|
274
|
+
return message;
|
|
275
|
+
}
|
|
276
|
+
function buildAmbiguousErrorMessage(filter, matches) {
|
|
277
|
+
let message = `Task "${filter}" is ambiguous.`;
|
|
278
|
+
message += "\n\nMatches multiple tasks:";
|
|
279
|
+
for (const match of matches) {
|
|
280
|
+
message += `
|
|
281
|
+
${match}`;
|
|
282
|
+
}
|
|
283
|
+
return message;
|
|
284
|
+
}
|
|
285
|
+
function findBestSuggestion(availablePaths, invalidFilter) {
|
|
286
|
+
let bestPath;
|
|
287
|
+
let bestDistance = Number.POSITIVE_INFINITY;
|
|
288
|
+
const threshold = Math.max(2, Math.floor(invalidFilter.length / 3));
|
|
289
|
+
for (const path of availablePaths) {
|
|
290
|
+
const distance = leven(invalidFilter, path);
|
|
291
|
+
if (distance < bestDistance && distance <= threshold) {
|
|
292
|
+
bestDistance = distance;
|
|
293
|
+
bestPath = path;
|
|
294
|
+
}
|
|
295
|
+
const lastSegment = path.split(PATH_SEPARATOR).pop();
|
|
296
|
+
if (lastSegment && lastSegment !== path) {
|
|
297
|
+
const segmentDistance = leven(invalidFilter, lastSegment);
|
|
298
|
+
if (segmentDistance < bestDistance && segmentDistance <= threshold) {
|
|
299
|
+
bestDistance = segmentDistance;
|
|
300
|
+
bestPath = path;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return bestPath;
|
|
305
|
+
}
|
|
306
|
+
function resolveFilter(filter, availablePaths) {
|
|
307
|
+
if (availablePaths.includes(filter)) {
|
|
308
|
+
return { original: filter, resolved: filter, wasShortcut: false };
|
|
309
|
+
}
|
|
310
|
+
const prefixMatches = availablePaths.filter(
|
|
311
|
+
(path) => path === filter || path.startsWith(`${filter}${PATH_SEPARATOR}`)
|
|
312
|
+
);
|
|
313
|
+
if (prefixMatches.length > 0) {
|
|
314
|
+
return { original: filter, resolved: filter, wasShortcut: false };
|
|
315
|
+
}
|
|
316
|
+
const childMatches = availablePaths.filter((path) => {
|
|
317
|
+
const lastSegment = path.split(PATH_SEPARATOR).pop();
|
|
318
|
+
return lastSegment === filter;
|
|
319
|
+
});
|
|
320
|
+
if (childMatches.length === 1) {
|
|
321
|
+
return {
|
|
322
|
+
original: filter,
|
|
323
|
+
resolved: childMatches[0],
|
|
324
|
+
wasShortcut: true
|
|
325
|
+
};
|
|
326
|
+
}
|
|
327
|
+
if (childMatches.length > 1) {
|
|
328
|
+
throw new AmbiguousTaskError(filter, childMatches);
|
|
329
|
+
}
|
|
330
|
+
const suggestion = findBestSuggestion(availablePaths, filter);
|
|
331
|
+
throw new TaskNotFoundError(filter, suggestion, availablePaths);
|
|
332
|
+
}
|
|
333
|
+
function resolveFilters(nodes, filters) {
|
|
334
|
+
const availablePaths = collectPaths(nodes);
|
|
335
|
+
const resolved = [];
|
|
336
|
+
for (const filter of filters) {
|
|
337
|
+
resolved.push(resolveFilter(filter, availablePaths));
|
|
338
|
+
}
|
|
339
|
+
return resolved;
|
|
340
|
+
}
|
|
341
|
+
|
|
135
342
|
// src/init/detect.ts
|
|
136
|
-
import { existsSync as existsSync3, readFileSync } from "fs";
|
|
343
|
+
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
137
344
|
import { join as join3 } from "path";
|
|
138
345
|
var TOOL_PATTERNS = [
|
|
139
346
|
// Biome
|
|
@@ -292,8 +499,8 @@ function readPackageJson(cwd) {
|
|
|
292
499
|
return null;
|
|
293
500
|
}
|
|
294
501
|
try {
|
|
295
|
-
const content =
|
|
296
|
-
return
|
|
502
|
+
const content = readFileSync2(packageJsonPath, "utf-8");
|
|
503
|
+
return parsePackageJson(content);
|
|
297
504
|
} catch {
|
|
298
505
|
return null;
|
|
299
506
|
}
|
|
@@ -306,7 +513,7 @@ function extractOptimizedCommand(cwd, scriptContent) {
|
|
|
306
513
|
const match = scriptContent.match(tool.pattern);
|
|
307
514
|
if (match && binaryExists(cwd, tool.binary)) {
|
|
308
515
|
const args = tool.getArgs(match, scriptContent);
|
|
309
|
-
const command = args ?
|
|
516
|
+
const command = args ? `${tool.binary} ${args}` : tool.binary;
|
|
310
517
|
return { command, parser: tool.parser };
|
|
311
518
|
}
|
|
312
519
|
}
|
|
@@ -383,7 +590,7 @@ function detectTasks(cwd) {
|
|
|
383
590
|
const packageManager = detectPackageManager(cwd);
|
|
384
591
|
const tasks = detectFromPackageJson(cwd);
|
|
385
592
|
return tasks.map((task) => {
|
|
386
|
-
if (task.command.startsWith("
|
|
593
|
+
if (!task.command.startsWith("npm run ")) {
|
|
387
594
|
return task;
|
|
388
595
|
}
|
|
389
596
|
return {
|
|
@@ -419,12 +626,15 @@ function generateSkeleton(format) {
|
|
|
419
626
|
return `${importStatement}
|
|
420
627
|
|
|
421
628
|
export default defineConfig({
|
|
629
|
+
env: {
|
|
630
|
+
NO_COLOR: "1",
|
|
631
|
+
},
|
|
422
632
|
tasks: [
|
|
423
633
|
// Add your verification tasks here
|
|
424
634
|
// Example:
|
|
425
|
-
// { key: "format", run: "
|
|
426
|
-
// { key: "types", run: "
|
|
427
|
-
// { key: "test", run: "
|
|
635
|
+
// { key: "format", run: "biome check ." },
|
|
636
|
+
// { key: "types", run: "tsc --noEmit" },
|
|
637
|
+
// { key: "test", run: "vitest run" },
|
|
428
638
|
],
|
|
429
639
|
})
|
|
430
640
|
`;
|
|
@@ -439,6 +649,9 @@ function generateConfigContent(tasks, format) {
|
|
|
439
649
|
return `${importStatement}
|
|
440
650
|
|
|
441
651
|
export default defineConfig({
|
|
652
|
+
env: {
|
|
653
|
+
NO_COLOR: "1",
|
|
654
|
+
},
|
|
442
655
|
tasks: [
|
|
443
656
|
${taskLines.join(",\n")},
|
|
444
657
|
],
|
|
@@ -764,6 +977,18 @@ var vitestParser = {
|
|
|
764
977
|
};
|
|
765
978
|
|
|
766
979
|
// src/parsers/index.ts
|
|
980
|
+
var parsers = {
|
|
981
|
+
/** Vitest/Jest test runner output parser */
|
|
982
|
+
vitest: "vitest",
|
|
983
|
+
/** TypeScript compiler (tsc/tsgo) output parser */
|
|
984
|
+
tsc: "tsc",
|
|
985
|
+
/** Biome/ESLint linter output parser */
|
|
986
|
+
biome: "biome",
|
|
987
|
+
/** Go test runner output parser */
|
|
988
|
+
gotest: "gotest",
|
|
989
|
+
/** Generic fallback parser */
|
|
990
|
+
generic: "generic"
|
|
991
|
+
};
|
|
767
992
|
var ParserRegistry = class {
|
|
768
993
|
parsers = /* @__PURE__ */ new Map();
|
|
769
994
|
constructor() {
|
|
@@ -791,24 +1016,24 @@ var ParserRegistry = class {
|
|
|
791
1016
|
detectParser(cmd) {
|
|
792
1017
|
const cmdLower = cmd.toLowerCase();
|
|
793
1018
|
if (cmdLower.includes("vitest") || cmdLower.includes("jest")) {
|
|
794
|
-
return
|
|
1019
|
+
return parsers.vitest;
|
|
795
1020
|
}
|
|
796
1021
|
if (cmdLower.includes("tsc") || cmdLower.includes("tsgo")) {
|
|
797
|
-
return
|
|
1022
|
+
return parsers.tsc;
|
|
798
1023
|
}
|
|
799
1024
|
if (cmdLower.includes("biome") || cmdLower.includes("eslint")) {
|
|
800
|
-
return
|
|
1025
|
+
return parsers.biome;
|
|
801
1026
|
}
|
|
802
1027
|
if (cmdLower.includes("go test") || cmdLower.includes("go") && cmdLower.includes("test")) {
|
|
803
|
-
return
|
|
1028
|
+
return parsers.gotest;
|
|
804
1029
|
}
|
|
805
|
-
return
|
|
1030
|
+
return parsers.generic;
|
|
806
1031
|
}
|
|
807
1032
|
/**
|
|
808
1033
|
* Parse output using the specified or auto-detected parser
|
|
809
1034
|
*/
|
|
810
1035
|
parse(output, exitCode, parserId, cmd) {
|
|
811
|
-
const id = parserId ?? (cmd ? this.detectParser(cmd) :
|
|
1036
|
+
const id = parserId ?? (cmd ? this.detectParser(cmd) : parsers.generic);
|
|
812
1037
|
const parser = this.parsers.get(id) ?? genericParser;
|
|
813
1038
|
const result = parser.parse(output, exitCode);
|
|
814
1039
|
if (result) {
|
|
@@ -940,16 +1165,12 @@ var BaseReporter = class {
|
|
|
940
1165
|
return this.taskDepths.get(path) ?? 0;
|
|
941
1166
|
}
|
|
942
1167
|
/**
|
|
943
|
-
*
|
|
1168
|
+
* Collect task depths from verification tree using walkNodes
|
|
944
1169
|
*/
|
|
945
|
-
collectTaskDepths(nodes
|
|
946
|
-
|
|
947
|
-
const path = parentPath ? `${parentPath}:${node.key}` : node.key;
|
|
1170
|
+
collectTaskDepths(nodes) {
|
|
1171
|
+
walkNodes(nodes, (_node, path, depth) => {
|
|
948
1172
|
this.taskDepths.set(path, depth);
|
|
949
|
-
|
|
950
|
-
this.collectTaskDepths(node.children, path, depth + 1);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
1173
|
+
});
|
|
953
1174
|
}
|
|
954
1175
|
/**
|
|
955
1176
|
* Extract summary from task result
|
|
@@ -1027,16 +1248,15 @@ var LiveDashboardReporter = class extends BaseReporter {
|
|
|
1027
1248
|
* Initialize task list from verification nodes
|
|
1028
1249
|
*/
|
|
1029
1250
|
onStart(tasks) {
|
|
1030
|
-
this.collectTasks(tasks
|
|
1251
|
+
this.collectTasks(tasks);
|
|
1031
1252
|
this.stream.write(cursor.hide);
|
|
1032
1253
|
this.spinner.start(() => this.redraw());
|
|
1033
1254
|
}
|
|
1034
1255
|
/**
|
|
1035
|
-
*
|
|
1256
|
+
* Collect tasks from verification tree using walkNodes
|
|
1036
1257
|
*/
|
|
1037
|
-
collectTasks(nodes
|
|
1038
|
-
|
|
1039
|
-
const path = parentPath ? `${parentPath}:${node.key}` : node.key;
|
|
1258
|
+
collectTasks(nodes) {
|
|
1259
|
+
walkNodes(nodes, (node, path, depth) => {
|
|
1040
1260
|
this.tasks.set(path, {
|
|
1041
1261
|
key: node.key,
|
|
1042
1262
|
path,
|
|
@@ -1045,10 +1265,7 @@ var LiveDashboardReporter = class extends BaseReporter {
|
|
|
1045
1265
|
});
|
|
1046
1266
|
this.taskOrder.push(path);
|
|
1047
1267
|
this.taskDepths.set(path, depth);
|
|
1048
|
-
|
|
1049
|
-
this.collectTasks(node.children, path, depth + 1);
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1268
|
+
});
|
|
1052
1269
|
}
|
|
1053
1270
|
/**
|
|
1054
1271
|
* Get display key - shows :key for nested, key for root
|
|
@@ -1084,9 +1301,9 @@ var LiveDashboardReporter = class extends BaseReporter {
|
|
|
1084
1301
|
}
|
|
1085
1302
|
const summary = this.extractSummary(task.result);
|
|
1086
1303
|
if (task.result.ok) {
|
|
1087
|
-
return
|
|
1304
|
+
return `${indent}${this.okMark()} verified ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
|
|
1088
1305
|
}
|
|
1089
|
-
return `${indent}${this.failMark()}
|
|
1306
|
+
return `${indent}${this.failMark()} failed ${this.c(ansi.bold, displayKey)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}`;
|
|
1090
1307
|
}
|
|
1091
1308
|
return "";
|
|
1092
1309
|
}
|
|
@@ -1141,7 +1358,7 @@ var SequentialReporter = class extends BaseReporter {
|
|
|
1141
1358
|
this.topLevelOnly = options.topLevelOnly ?? false;
|
|
1142
1359
|
}
|
|
1143
1360
|
onStart(tasks) {
|
|
1144
|
-
this.collectTaskDepths(tasks
|
|
1361
|
+
this.collectTaskDepths(tasks);
|
|
1145
1362
|
}
|
|
1146
1363
|
/**
|
|
1147
1364
|
* Check if task should be displayed based on topLevelOnly flag
|
|
@@ -1166,13 +1383,18 @@ var SequentialReporter = class extends BaseReporter {
|
|
|
1166
1383
|
);
|
|
1167
1384
|
return;
|
|
1168
1385
|
}
|
|
1169
|
-
const mark = result.ok ? this.okMark() : this.failMark();
|
|
1170
|
-
const verb = result.ok ? "verified" : "failed";
|
|
1171
1386
|
const summary = this.extractSummary(result);
|
|
1172
|
-
|
|
1173
|
-
|
|
1387
|
+
if (result.ok) {
|
|
1388
|
+
this.stream.write(
|
|
1389
|
+
`${this.okMark()} verified ${this.c(ansi.bold, result.path)} ${this.c(ansi.dim, `(${summary}, ${duration})`)}
|
|
1174
1390
|
`
|
|
1175
|
-
|
|
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
|
+
}
|
|
1176
1398
|
}
|
|
1177
1399
|
onFinish() {
|
|
1178
1400
|
}
|
|
@@ -1242,23 +1464,11 @@ function createReporter(options) {
|
|
|
1242
1464
|
|
|
1243
1465
|
// src/runner.ts
|
|
1244
1466
|
import { spawn } from "child_process";
|
|
1467
|
+
import { dirname, join as join4, resolve as resolve3 } from "path";
|
|
1468
|
+
import treeKill2 from "tree-kill";
|
|
1469
|
+
|
|
1470
|
+
// src/dependency-tracker.ts
|
|
1245
1471
|
import treeKill from "tree-kill";
|
|
1246
|
-
function normalizeCommand(run) {
|
|
1247
|
-
if (typeof run === "string") {
|
|
1248
|
-
const parts = run.split(/\s+/);
|
|
1249
|
-
return {
|
|
1250
|
-
cmd: parts[0],
|
|
1251
|
-
args: parts.slice(1)
|
|
1252
|
-
};
|
|
1253
|
-
}
|
|
1254
|
-
if (Array.isArray(run)) {
|
|
1255
|
-
return {
|
|
1256
|
-
cmd: run[0],
|
|
1257
|
-
args: run[1]
|
|
1258
|
-
};
|
|
1259
|
-
}
|
|
1260
|
-
return run;
|
|
1261
|
-
}
|
|
1262
1472
|
var ReportingDependencyTracker = class {
|
|
1263
1473
|
/** Map of task path/key to their results */
|
|
1264
1474
|
results = /* @__PURE__ */ new Map();
|
|
@@ -1276,26 +1486,22 @@ var ReportingDependencyTracker = class {
|
|
|
1276
1486
|
processes = /* @__PURE__ */ new Map();
|
|
1277
1487
|
/** Set of task paths that have been killed */
|
|
1278
1488
|
killedPaths = /* @__PURE__ */ new Set();
|
|
1489
|
+
/** Set of task paths that will actually run (based on filter) */
|
|
1490
|
+
activePaths = /* @__PURE__ */ new Set();
|
|
1279
1491
|
/**
|
|
1280
1492
|
* Initialize the tracker with all tasks from the verification tree.
|
|
1281
1493
|
* Also validates for circular dependencies and builds reverse dependency map.
|
|
1282
1494
|
*/
|
|
1283
|
-
initialize(nodes
|
|
1284
|
-
|
|
1285
|
-
const path = parentPath ? `${parentPath}:${node.key}` : node.key;
|
|
1495
|
+
initialize(nodes) {
|
|
1496
|
+
walkNodes(nodes, (node, path) => {
|
|
1286
1497
|
this.pathToKey.set(path, node.key);
|
|
1287
1498
|
this.keyToPath.set(node.key, path);
|
|
1288
1499
|
if (node.reportingDependsOn && node.reportingDependsOn.length > 0) {
|
|
1289
1500
|
this.dependencies.set(path, node.reportingDependsOn);
|
|
1290
1501
|
}
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
}
|
|
1295
|
-
if (parentPath === "") {
|
|
1296
|
-
this.validateNoCycles();
|
|
1297
|
-
this.buildReverseDeps();
|
|
1298
|
-
}
|
|
1502
|
+
});
|
|
1503
|
+
this.validateNoCycles();
|
|
1504
|
+
this.buildReverseDeps();
|
|
1299
1505
|
}
|
|
1300
1506
|
/**
|
|
1301
1507
|
* Build reverse dependency map (task → tasks that depend on it)
|
|
@@ -1398,15 +1604,35 @@ var ReportingDependencyTracker = class {
|
|
|
1398
1604
|
this.waiters.delete(key);
|
|
1399
1605
|
}
|
|
1400
1606
|
}
|
|
1607
|
+
/**
|
|
1608
|
+
* Mark a task as active (will actually run).
|
|
1609
|
+
* Called before running each task to track which tasks are in the execution set.
|
|
1610
|
+
*/
|
|
1611
|
+
markActive(path) {
|
|
1612
|
+
this.activePaths.add(path);
|
|
1613
|
+
}
|
|
1614
|
+
/**
|
|
1615
|
+
* Check if a dependency is active (will run).
|
|
1616
|
+
* If not active, we shouldn't wait for it.
|
|
1617
|
+
*/
|
|
1618
|
+
isDependencyActive(dep) {
|
|
1619
|
+
const resolvedPath = this.resolveDependency(dep);
|
|
1620
|
+
if (!resolvedPath) {
|
|
1621
|
+
return false;
|
|
1622
|
+
}
|
|
1623
|
+
return this.activePaths.has(resolvedPath);
|
|
1624
|
+
}
|
|
1401
1625
|
/**
|
|
1402
1626
|
* Wait for all dependencies of a task to complete.
|
|
1627
|
+
* Only waits for dependencies that are actually active (will run).
|
|
1403
1628
|
*/
|
|
1404
1629
|
async waitForDependencies(path) {
|
|
1405
1630
|
const deps = this.dependencies.get(path);
|
|
1406
1631
|
if (!deps || deps.length === 0) {
|
|
1407
1632
|
return;
|
|
1408
1633
|
}
|
|
1409
|
-
const
|
|
1634
|
+
const activeDeps = deps.filter((dep) => this.isDependencyActive(dep));
|
|
1635
|
+
const waitPromises = activeDeps.map((dep) => this.waitForResult(dep));
|
|
1410
1636
|
await Promise.all(waitPromises);
|
|
1411
1637
|
}
|
|
1412
1638
|
/**
|
|
@@ -1420,9 +1646,9 @@ var ReportingDependencyTracker = class {
|
|
|
1420
1646
|
if (this.results.has(pathOrKey)) {
|
|
1421
1647
|
return Promise.resolve();
|
|
1422
1648
|
}
|
|
1423
|
-
return new Promise((
|
|
1649
|
+
return new Promise((resolve4) => {
|
|
1424
1650
|
const waiters = this.waiters.get(pathOrKey) ?? [];
|
|
1425
|
-
waiters.push(
|
|
1651
|
+
waiters.push(resolve4);
|
|
1426
1652
|
this.waiters.set(pathOrKey, waiters);
|
|
1427
1653
|
});
|
|
1428
1654
|
}
|
|
@@ -1488,18 +1714,116 @@ var ReportingDependencyTracker = class {
|
|
|
1488
1714
|
}
|
|
1489
1715
|
}
|
|
1490
1716
|
};
|
|
1717
|
+
|
|
1718
|
+
// src/runner.ts
|
|
1719
|
+
function mergeEnv(base, overlay) {
|
|
1720
|
+
if (!overlay) return { ...base };
|
|
1721
|
+
const result = { ...base };
|
|
1722
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
1723
|
+
if (value === null) {
|
|
1724
|
+
result[key] = null;
|
|
1725
|
+
} else {
|
|
1726
|
+
result[key] = value;
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
return result;
|
|
1730
|
+
}
|
|
1731
|
+
function buildFinalEnv(processEnv, path, overlay) {
|
|
1732
|
+
const result = {};
|
|
1733
|
+
for (const [key, value] of Object.entries(processEnv)) {
|
|
1734
|
+
if (value !== void 0) {
|
|
1735
|
+
result[key] = value;
|
|
1736
|
+
}
|
|
1737
|
+
}
|
|
1738
|
+
result.PATH = path;
|
|
1739
|
+
if (overlay) {
|
|
1740
|
+
for (const [key, value] of Object.entries(overlay)) {
|
|
1741
|
+
if (value === null) {
|
|
1742
|
+
delete result[key];
|
|
1743
|
+
} else {
|
|
1744
|
+
result[key] = value;
|
|
1745
|
+
}
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
return result;
|
|
1749
|
+
}
|
|
1750
|
+
function shellEscape(arg) {
|
|
1751
|
+
if (/[\s"'`$\\!&|;<>(){}[\]*?#~]/.test(arg)) {
|
|
1752
|
+
return `"${arg.replace(/"/g, '\\"')}"`;
|
|
1753
|
+
}
|
|
1754
|
+
return arg;
|
|
1755
|
+
}
|
|
1756
|
+
function buildNodeModulesPath(cwd) {
|
|
1757
|
+
const pathSeparator = process.platform === "win32" ? ";" : ":";
|
|
1758
|
+
const existingPath = process.env.PATH ?? "";
|
|
1759
|
+
const binPaths = [];
|
|
1760
|
+
let current = resolve3(cwd);
|
|
1761
|
+
while (true) {
|
|
1762
|
+
binPaths.push(join4(current, "node_modules", ".bin"));
|
|
1763
|
+
const parent = dirname(current);
|
|
1764
|
+
if (parent === current) break;
|
|
1765
|
+
current = parent;
|
|
1766
|
+
}
|
|
1767
|
+
return [...binPaths, existingPath].join(pathSeparator);
|
|
1768
|
+
}
|
|
1769
|
+
function normalizeCommand(run, nodeTimeout, passthrough, inheritedEnv) {
|
|
1770
|
+
if (typeof run === "string") {
|
|
1771
|
+
let cmd = run;
|
|
1772
|
+
if (passthrough && passthrough.length > 0) {
|
|
1773
|
+
const escapedArgs = passthrough.map(shellEscape).join(" ");
|
|
1774
|
+
cmd = `${run} ${escapedArgs}`;
|
|
1775
|
+
}
|
|
1776
|
+
return {
|
|
1777
|
+
cmd,
|
|
1778
|
+
args: [],
|
|
1779
|
+
shell: true,
|
|
1780
|
+
timeout: nodeTimeout,
|
|
1781
|
+
env: inheritedEnv
|
|
1782
|
+
};
|
|
1783
|
+
}
|
|
1784
|
+
const args = passthrough ? [...run.args, ...passthrough] : run.args;
|
|
1785
|
+
const env = mergeEnv(inheritedEnv ?? {}, run.env);
|
|
1786
|
+
return {
|
|
1787
|
+
cmd: run.cmd,
|
|
1788
|
+
args,
|
|
1789
|
+
cwd: run.cwd,
|
|
1790
|
+
env: Object.keys(env).length > 0 ? env : void 0,
|
|
1791
|
+
shell: false,
|
|
1792
|
+
// Command-level timeout takes precedence over node-level timeout
|
|
1793
|
+
timeout: run.timeout ?? nodeTimeout
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1491
1796
|
async function executeCommand(command, cwd, tracker, path) {
|
|
1492
1797
|
const start = Date.now();
|
|
1493
|
-
return new Promise((
|
|
1798
|
+
return new Promise((resolve4) => {
|
|
1799
|
+
const useShell = command.shell || process.platform === "win32";
|
|
1800
|
+
const effectiveCwd = command.cwd ?? cwd;
|
|
1801
|
+
const finalEnv = buildFinalEnv(
|
|
1802
|
+
process.env,
|
|
1803
|
+
buildNodeModulesPath(effectiveCwd),
|
|
1804
|
+
command.env
|
|
1805
|
+
);
|
|
1494
1806
|
const proc = spawn(command.cmd, command.args, {
|
|
1495
|
-
shell:
|
|
1496
|
-
cwd:
|
|
1497
|
-
env:
|
|
1807
|
+
shell: useShell,
|
|
1808
|
+
cwd: effectiveCwd,
|
|
1809
|
+
env: finalEnv
|
|
1498
1810
|
});
|
|
1499
1811
|
if (tracker && path) {
|
|
1500
1812
|
tracker.registerProcess(path, proc);
|
|
1501
1813
|
}
|
|
1502
1814
|
let output = "";
|
|
1815
|
+
let timedOut = false;
|
|
1816
|
+
let timeoutId;
|
|
1817
|
+
if (command.timeout && proc.pid) {
|
|
1818
|
+
const pid = proc.pid;
|
|
1819
|
+
timeoutId = setTimeout(() => {
|
|
1820
|
+
timedOut = true;
|
|
1821
|
+
treeKill2(pid, "SIGTERM", (err) => {
|
|
1822
|
+
if (err) {
|
|
1823
|
+
}
|
|
1824
|
+
});
|
|
1825
|
+
}, command.timeout);
|
|
1826
|
+
}
|
|
1503
1827
|
proc.stdout.on("data", (data) => {
|
|
1504
1828
|
output += data.toString();
|
|
1505
1829
|
});
|
|
@@ -1507,35 +1831,41 @@ async function executeCommand(command, cwd, tracker, path) {
|
|
|
1507
1831
|
output += data.toString();
|
|
1508
1832
|
});
|
|
1509
1833
|
proc.on("close", (code, signal) => {
|
|
1834
|
+
if (timeoutId) {
|
|
1835
|
+
clearTimeout(timeoutId);
|
|
1836
|
+
}
|
|
1510
1837
|
if (tracker && path) {
|
|
1511
1838
|
tracker.unregisterProcess(path);
|
|
1512
1839
|
}
|
|
1513
1840
|
const durationMs = Date.now() - start;
|
|
1514
1841
|
const killed = signal === "SIGTERM" || code === 143 || (tracker?.wasKilled(path ?? "") ?? false);
|
|
1515
|
-
|
|
1842
|
+
resolve4({
|
|
1516
1843
|
code: code ?? 1,
|
|
1517
1844
|
output,
|
|
1518
1845
|
durationMs,
|
|
1519
|
-
killed
|
|
1846
|
+
killed: killed && !timedOut,
|
|
1847
|
+
// Don't mark as killed if it was a timeout
|
|
1848
|
+
timedOut
|
|
1520
1849
|
});
|
|
1521
1850
|
});
|
|
1522
1851
|
proc.on("error", (err) => {
|
|
1852
|
+
if (timeoutId) {
|
|
1853
|
+
clearTimeout(timeoutId);
|
|
1854
|
+
}
|
|
1523
1855
|
if (tracker && path) {
|
|
1524
1856
|
tracker.unregisterProcess(path);
|
|
1525
1857
|
}
|
|
1526
1858
|
const durationMs = Date.now() - start;
|
|
1527
|
-
|
|
1859
|
+
resolve4({
|
|
1528
1860
|
code: 1,
|
|
1529
1861
|
output: `Failed to execute command: ${err.message}`,
|
|
1530
1862
|
durationMs,
|
|
1531
|
-
killed: false
|
|
1863
|
+
killed: false,
|
|
1864
|
+
timedOut: false
|
|
1532
1865
|
});
|
|
1533
1866
|
});
|
|
1534
1867
|
});
|
|
1535
1868
|
}
|
|
1536
|
-
function buildPath(parentPath, key) {
|
|
1537
|
-
return parentPath ? `${parentPath}:${key}` : key;
|
|
1538
|
-
}
|
|
1539
1869
|
function matchesFilter(path, filters) {
|
|
1540
1870
|
if (!filters || filters.length === 0) {
|
|
1541
1871
|
return true;
|
|
@@ -1545,7 +1875,7 @@ function matchesFilter(path, filters) {
|
|
|
1545
1875
|
});
|
|
1546
1876
|
}
|
|
1547
1877
|
function hasMatchingDescendant(node, parentPath, filters) {
|
|
1548
|
-
const path =
|
|
1878
|
+
const path = buildTaskPath(parentPath, node.key);
|
|
1549
1879
|
if (matchesFilter(path, filters)) {
|
|
1550
1880
|
return true;
|
|
1551
1881
|
}
|
|
@@ -1561,11 +1891,13 @@ var VerificationRunner = class {
|
|
|
1561
1891
|
options;
|
|
1562
1892
|
callbacks;
|
|
1563
1893
|
dependencyTracker;
|
|
1564
|
-
|
|
1894
|
+
configEnv;
|
|
1895
|
+
constructor(options = {}, registry = defaultRegistry, callbacks = {}, configEnv = {}) {
|
|
1565
1896
|
this.options = options;
|
|
1566
1897
|
this.registry = registry;
|
|
1567
1898
|
this.callbacks = callbacks;
|
|
1568
1899
|
this.dependencyTracker = new ReportingDependencyTracker();
|
|
1900
|
+
this.configEnv = configEnv;
|
|
1569
1901
|
}
|
|
1570
1902
|
/**
|
|
1571
1903
|
* Run all verification tasks
|
|
@@ -1574,7 +1906,8 @@ var VerificationRunner = class {
|
|
|
1574
1906
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1575
1907
|
const wallStart = Date.now();
|
|
1576
1908
|
this.dependencyTracker.initialize(tasks);
|
|
1577
|
-
const
|
|
1909
|
+
const baseEnv = mergeEnv({}, this.configEnv);
|
|
1910
|
+
const results = await this.runNodes(tasks, "", "parallel", baseEnv);
|
|
1578
1911
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
1579
1912
|
const durationMs = Date.now() - wallStart;
|
|
1580
1913
|
const allOk = results.every((r) => r.ok);
|
|
@@ -1589,7 +1922,7 @@ var VerificationRunner = class {
|
|
|
1589
1922
|
/**
|
|
1590
1923
|
* Run a list of nodes with the appropriate strategy
|
|
1591
1924
|
*/
|
|
1592
|
-
async runNodes(nodes, parentPath, strategy = "parallel") {
|
|
1925
|
+
async runNodes(nodes, parentPath, strategy = "parallel", inheritedEnv = {}) {
|
|
1593
1926
|
const filteredNodes = nodes.filter(
|
|
1594
1927
|
(node) => hasMatchingDescendant(node, parentPath, this.options.filter)
|
|
1595
1928
|
);
|
|
@@ -1599,19 +1932,21 @@ var VerificationRunner = class {
|
|
|
1599
1932
|
switch (strategy) {
|
|
1600
1933
|
case "parallel":
|
|
1601
1934
|
return Promise.all(
|
|
1602
|
-
filteredNodes.map(
|
|
1935
|
+
filteredNodes.map(
|
|
1936
|
+
(node) => this.runNode(node, parentPath, inheritedEnv)
|
|
1937
|
+
)
|
|
1603
1938
|
);
|
|
1604
1939
|
case "sequential": {
|
|
1605
1940
|
const results = [];
|
|
1606
1941
|
for (const node of filteredNodes) {
|
|
1607
|
-
results.push(await this.runNode(node, parentPath));
|
|
1942
|
+
results.push(await this.runNode(node, parentPath, inheritedEnv));
|
|
1608
1943
|
}
|
|
1609
1944
|
return results;
|
|
1610
1945
|
}
|
|
1611
1946
|
case "fail-fast": {
|
|
1612
1947
|
const results = [];
|
|
1613
1948
|
for (const node of filteredNodes) {
|
|
1614
|
-
const result = await this.runNode(node, parentPath);
|
|
1949
|
+
const result = await this.runNode(node, parentPath, inheritedEnv);
|
|
1615
1950
|
results.push(result);
|
|
1616
1951
|
if (!result.ok) {
|
|
1617
1952
|
break;
|
|
@@ -1624,15 +1959,18 @@ var VerificationRunner = class {
|
|
|
1624
1959
|
/**
|
|
1625
1960
|
* Run a single node (leaf or group)
|
|
1626
1961
|
*/
|
|
1627
|
-
async runNode(node, parentPath) {
|
|
1628
|
-
const path =
|
|
1962
|
+
async runNode(node, parentPath, inheritedEnv = {}) {
|
|
1963
|
+
const path = buildTaskPath(parentPath, node.key);
|
|
1964
|
+
const nodeEnv = mergeEnv(inheritedEnv, node.env);
|
|
1965
|
+
this.dependencyTracker.markActive(path);
|
|
1629
1966
|
this.callbacks.onTaskStart?.(path, node.key);
|
|
1630
1967
|
if (node.children && node.children.length > 0) {
|
|
1631
1968
|
const start = Date.now();
|
|
1632
1969
|
const childResults = await this.runNodes(
|
|
1633
1970
|
node.children,
|
|
1634
1971
|
path,
|
|
1635
|
-
node.strategy ?? "parallel"
|
|
1972
|
+
node.strategy ?? "parallel",
|
|
1973
|
+
nodeEnv
|
|
1636
1974
|
);
|
|
1637
1975
|
const durationMs2 = Date.now() - start;
|
|
1638
1976
|
const allOk = childResults.every((r) => r.ok || r.suppressed);
|
|
@@ -1671,15 +2009,36 @@ var VerificationRunner = class {
|
|
|
1671
2009
|
this.callbacks.onTaskComplete?.(result2);
|
|
1672
2010
|
return result2;
|
|
1673
2011
|
}
|
|
1674
|
-
const
|
|
2012
|
+
const passthrough = this.options.passthrough;
|
|
2013
|
+
const command = normalizeCommand(
|
|
2014
|
+
node.run,
|
|
2015
|
+
node.timeout,
|
|
2016
|
+
passthrough,
|
|
2017
|
+
nodeEnv
|
|
2018
|
+
);
|
|
1675
2019
|
const cwd = this.options.cwd ?? process.cwd();
|
|
1676
|
-
const { code, output, durationMs, killed } = await executeCommand(
|
|
2020
|
+
const { code, output, durationMs, killed, timedOut } = await executeCommand(
|
|
1677
2021
|
command,
|
|
1678
2022
|
cwd,
|
|
1679
2023
|
this.dependencyTracker,
|
|
1680
2024
|
path
|
|
1681
2025
|
);
|
|
1682
2026
|
const ok = code === 0;
|
|
2027
|
+
if (timedOut) {
|
|
2028
|
+
const result2 = {
|
|
2029
|
+
key: node.key,
|
|
2030
|
+
path,
|
|
2031
|
+
ok: false,
|
|
2032
|
+
code,
|
|
2033
|
+
durationMs,
|
|
2034
|
+
output,
|
|
2035
|
+
summaryLine: `${node.key}: timed out after ${command.timeout}ms`,
|
|
2036
|
+
timedOut: true
|
|
2037
|
+
};
|
|
2038
|
+
this.dependencyTracker.recordResult(result2);
|
|
2039
|
+
this.callbacks.onTaskComplete?.(result2);
|
|
2040
|
+
return result2;
|
|
2041
|
+
}
|
|
1683
2042
|
if (killed) {
|
|
1684
2043
|
await this.dependencyTracker.waitForDependencies(path);
|
|
1685
2044
|
const failedDep = this.dependencyTracker.getFailedDependency(path);
|
|
@@ -1698,7 +2057,7 @@ var VerificationRunner = class {
|
|
|
1698
2057
|
this.callbacks.onTaskComplete?.(result2);
|
|
1699
2058
|
return result2;
|
|
1700
2059
|
}
|
|
1701
|
-
const cmdString = `${command.cmd} ${command.args.join(" ")}`;
|
|
2060
|
+
const cmdString = command.shell ? command.cmd : `${command.cmd} ${command.args.join(" ")}`;
|
|
1702
2061
|
const parsed = this.registry.parse(
|
|
1703
2062
|
output,
|
|
1704
2063
|
code,
|
|
@@ -1743,12 +2102,26 @@ var VerificationRunner = class {
|
|
|
1743
2102
|
// src/index.ts
|
|
1744
2103
|
async function verify(config, cliOptions) {
|
|
1745
2104
|
const options = mergeOptions(config.options, cliOptions);
|
|
2105
|
+
if (options.filter && options.filter.length > 0) {
|
|
2106
|
+
const resolved = resolveFilters(config.tasks, options.filter);
|
|
2107
|
+
for (const r of resolved) {
|
|
2108
|
+
if (r.wasShortcut) {
|
|
2109
|
+
console.error(`\u2192 Resolving "${r.original}" to "${r.resolved}"`);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
options.filter = resolved.map((r) => r.resolved);
|
|
2113
|
+
}
|
|
1746
2114
|
const reporter = createReporter(options);
|
|
1747
2115
|
reporter.onStart?.(config.tasks);
|
|
1748
|
-
const runner = new VerificationRunner(
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
2116
|
+
const runner = new VerificationRunner(
|
|
2117
|
+
options,
|
|
2118
|
+
void 0,
|
|
2119
|
+
{
|
|
2120
|
+
onTaskStart: (path, key) => reporter.onTaskStart(path, key),
|
|
2121
|
+
onTaskComplete: (result2) => reporter.onTaskComplete(result2)
|
|
2122
|
+
},
|
|
2123
|
+
config.env
|
|
2124
|
+
);
|
|
1752
2125
|
const result = await runner.run(config.tasks);
|
|
1753
2126
|
reporter.onFinish?.();
|
|
1754
2127
|
reporter.outputLogs(result.tasks, options.logs ?? "failed");
|
|
@@ -1765,20 +2138,27 @@ async function verifyFromConfig(cwd = process.cwd(), cliOptions) {
|
|
|
1765
2138
|
return verify(config, { ...cliOptions, cwd });
|
|
1766
2139
|
}
|
|
1767
2140
|
export {
|
|
2141
|
+
AmbiguousTaskError,
|
|
2142
|
+
ConfigError,
|
|
1768
2143
|
JSONReporter,
|
|
1769
2144
|
LiveDashboardReporter,
|
|
2145
|
+
PATH_SEPARATOR,
|
|
1770
2146
|
ParserRegistry,
|
|
1771
2147
|
QuietReporter,
|
|
1772
2148
|
SequentialReporter,
|
|
1773
2149
|
SequentialReporter as TTYReporter,
|
|
2150
|
+
TaskNotFoundError,
|
|
1774
2151
|
VerificationRunner,
|
|
1775
2152
|
biomeParser,
|
|
2153
|
+
buildTaskPath,
|
|
2154
|
+
collectPaths,
|
|
1776
2155
|
createReporter,
|
|
1777
2156
|
defaultRegistry,
|
|
1778
2157
|
defineConfig,
|
|
1779
2158
|
defineTask,
|
|
1780
2159
|
detectTasks,
|
|
1781
2160
|
discoverPackages,
|
|
2161
|
+
findBestSuggestion,
|
|
1782
2162
|
findConfigFile,
|
|
1783
2163
|
generateConfigContent,
|
|
1784
2164
|
genericParser,
|
|
@@ -1787,10 +2167,14 @@ export {
|
|
|
1787
2167
|
loadConfig,
|
|
1788
2168
|
loadConfigFromCwd,
|
|
1789
2169
|
mergeOptions,
|
|
2170
|
+
parsers,
|
|
2171
|
+
resolveFilters,
|
|
1790
2172
|
runInit,
|
|
1791
2173
|
tscParser,
|
|
2174
|
+
validateConfig,
|
|
1792
2175
|
verify,
|
|
1793
2176
|
verifyFromConfig,
|
|
1794
|
-
vitestParser
|
|
2177
|
+
vitestParser,
|
|
2178
|
+
walkNodes
|
|
1795
2179
|
};
|
|
1796
2180
|
//# sourceMappingURL=index.js.map
|