@cldmv/vitest-runner 1.4.2 → 1.4.4

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/index.mjs CHANGED
@@ -1,1335 +1,46 @@
1
- // src/runner.mjs
2
- import fs5 from "fs/promises";
3
- import path5 from "path";
4
- import chalk3 from "chalk";
5
-
6
- // src/utils/resolve.mjs
7
- import { createRequire } from "module";
8
- import path from "path";
9
- import fs from "fs/promises";
10
- import { pathToFileURL } from "url";
11
- function resolveBin(cwd, pkgName, binName = pkgName) {
12
- const require2 = createRequire(pathToFileURL(path.join(cwd, "package.json")));
13
- const pkgJsonPath = require2.resolve(`${pkgName}/package.json`);
14
- const pkg = require2(pkgJsonPath);
15
- const rel = pkg.bin?.[binName] ?? pkg.bin;
16
- if (!rel) throw new Error(`No bin "${binName}" found in ${pkgName}/package.json`);
17
- return path.join(path.dirname(pkgJsonPath), rel);
18
- }
19
- var DEFAULT_CONFIG_NAMES = Object.freeze([
20
- "vitest.config.ts",
21
- "vitest.config.mts",
22
- "vitest.config.cts",
23
- "vitest.config.mjs",
24
- "vitest.config.js",
25
- "vitest.config.cjs",
26
- "vite.config.ts",
27
- "vite.config.mts",
28
- "vite.config.mjs",
29
- "vite.config.js"
30
- ]);
31
- async function resolveVitestConfig(cwd, configPath) {
32
- if (configPath) {
33
- return path.isAbsolute(configPath) ? configPath : path.resolve(cwd, configPath);
34
- }
35
- for (const name of DEFAULT_CONFIG_NAMES) {
36
- const candidate = path.join(cwd, name);
37
- try {
38
- await fs.access(candidate);
39
- return candidate;
40
- } catch {
41
- }
42
- }
43
- return void 0;
44
- }
45
-
46
- // src/core/discover.mjs
47
- import fs2 from "fs/promises";
48
- import path2 from "path";
49
- var DEFAULT_TEST_FILE_PATTERN = /\.test\.vitest\.(?:js|mjs|cjs)$/i;
50
- async function discoverFilesInDir(dir, cwd, pattern = DEFAULT_TEST_FILE_PATTERN) {
51
- const queue = [dir];
52
- const files = [];
53
- while (queue.length) {
54
- const current = queue.pop();
55
- let entries;
56
- try {
57
- entries = await fs2.readdir(current, { withFileTypes: true });
58
- } catch {
59
- continue;
60
- }
61
- for (const entry of entries) {
62
- if (entry.isDirectory()) {
63
- if (entry.name === "node_modules" || entry.name.startsWith(".")) continue;
64
- queue.push(path2.join(current, entry.name));
65
- continue;
66
- }
67
- if (entry.isFile() && pattern.test(entry.name)) {
68
- files.push(path2.relative(cwd, path2.join(current, entry.name)));
69
- }
70
- }
71
- }
72
- return files;
73
- }
74
- function sortWithPriority(files, earlyRunPatterns = []) {
75
- const early = [];
76
- const rest = [];
77
- for (const file of files) {
78
- const normalized = file.replace(/\\/g, "/");
79
- const priorityIndex = earlyRunPatterns.findIndex((pat) => normalized.includes(pat));
80
- if (priorityIndex !== -1) {
81
- early.push({ file, priorityIndex });
82
- } else {
83
- rest.push(file);
84
- }
85
- }
86
- early.sort((a, b) => a.priorityIndex - b.priorityIndex || a.file.localeCompare(b.file));
87
- rest.sort((a, b) => a.localeCompare(b));
88
- return [...early.map((e) => e.file), ...rest];
89
- }
90
- function computeFilterConflicts(files) {
91
- const normalized = files.map((f) => f.replace(/\\/g, "/"));
92
- const conflicts = /* @__PURE__ */ new Map();
93
- for (let i = 0; i < files.length; i++) {
94
- const matches = [];
95
- for (let j = 0; j < files.length; j++) {
96
- if (i === j) continue;
97
- if (normalized[j].includes(normalized[i])) matches.push(files[j]);
98
- }
99
- conflicts.set(files[i], matches);
100
- }
101
- return conflicts;
102
- }
103
- async function discoverVitestFiles(opts) {
104
- const { cwd, testDir, testPatterns = [], testListFile, testFilePattern = DEFAULT_TEST_FILE_PATTERN, earlyRunPatterns = [] } = opts;
105
- const resolvedTestDir = testDir ? path2.isAbsolute(testDir) ? testDir : path2.resolve(cwd, testDir) : cwd;
106
- if (testListFile) {
107
- const resolvedListPath = path2.isAbsolute(testListFile) ? testListFile : path2.resolve(cwd, testListFile);
108
- let testList;
109
- try {
110
- const content = await fs2.readFile(resolvedListPath, "utf8");
111
- testList = JSON.parse(content);
112
- } catch (err) {
113
- throw new Error(`Failed to read test list file "${resolvedListPath}": ${err.message}`, { cause: err });
114
- }
115
- if (!Array.isArray(testList)) {
116
- throw new Error(`Test list file "${resolvedListPath}" must contain a JSON array of test file paths`);
117
- }
118
- console.log(`\u{1F4CB} Loading test list from: ${path2.relative(cwd, resolvedListPath)}`);
119
- return sortWithPriority(testList, earlyRunPatterns);
120
- }
121
- if (testPatterns.length === 0) {
122
- const files2 = await discoverFilesInDir(resolvedTestDir, cwd, testFilePattern);
123
- return sortWithPriority(files2, earlyRunPatterns);
124
- }
125
- const files = [];
126
- for (const pattern of testPatterns) {
127
- const absPath = path2.isAbsolute(pattern) ? pattern : path2.resolve(cwd, pattern);
128
- let stat = null;
129
- try {
130
- stat = await fs2.stat(absPath);
131
- } catch {
132
- }
133
- if (stat?.isFile()) {
134
- if (testFilePattern.test(absPath)) {
135
- files.push(path2.relative(cwd, absPath));
136
- }
137
- } else if (stat?.isDirectory()) {
138
- files.push(...await discoverFilesInDir(absPath, cwd, testFilePattern));
139
- } else {
140
- const allFiles = await discoverFilesInDir(resolvedTestDir, cwd, testFilePattern);
141
- const matched = allFiles.filter((f) => f.replace(/\\/g, "/").includes(pattern.replace(/\\/g, "/")));
142
- if (matched.length > 0) {
143
- files.push(...matched);
144
- } else {
145
- console.warn(`\u26A0\uFE0F No matches found for: ${pattern}`);
146
- }
147
- }
148
- }
149
- return sortWithPriority([...new Set(files)], earlyRunPatterns);
150
- }
151
-
152
- // src/core/spawn.mjs
153
- import { spawn } from "child_process";
154
-
155
- // src/utils/ansi.mjs
156
- function stripAnsi(text) {
157
- return text.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
158
- }
159
- function colourPct(chalk4, pct) {
160
- const str = pct.toFixed(2).padStart(6);
161
- if (pct >= 80) return chalk4.green(str);
162
- if (pct >= 50) return chalk4.yellow(str);
163
- return chalk4.red(str);
164
- }
165
-
166
- // src/core/parse.mjs
167
- function parseVitestOutput(output) {
168
- const cleanOutput = stripAnsi(output);
169
- const result = {
170
- testFilesPass: 0,
171
- testFilesFail: 0,
172
- testsPass: 0,
173
- testsFail: 0,
174
- testsSkip: 0,
175
- duration: 0,
176
- heapMb: null,
177
- errors: []
178
- };
179
- const testFilesLineMatch = cleanOutput.match(/Test Files\s+(.+)/);
180
- if (testFilesLineMatch) {
181
- const line = testFilesLineMatch[1];
182
- const passMatch = line.match(/(\d+)\s+passed/);
183
- const failMatch = line.match(/(\d+)\s+failed/);
184
- if (passMatch) result.testFilesPass = parseInt(passMatch[1], 10);
185
- if (failMatch) result.testFilesFail = parseInt(failMatch[1], 10);
186
- }
187
- const testsLineMatch = cleanOutput.match(/^\s*Tests\s+(.+)$/m);
188
- if (testsLineMatch) {
189
- const line = testsLineMatch[1];
190
- const passMatch = line.match(/(\d+)\s+passed/);
191
- const failMatch = line.match(/(\d+)\s+failed/);
192
- const skipMatch = line.match(/(\d+)\s+skipped/);
193
- if (passMatch) result.testsPass = parseInt(passMatch[1], 10);
194
- if (failMatch) result.testsFail = parseInt(failMatch[1], 10);
195
- if (skipMatch) result.testsSkip = parseInt(skipMatch[1], 10);
196
- }
197
- const durationMatch = cleanOutput.match(/Duration\s+([\d.]+)s/);
198
- if (durationMatch) {
199
- result.duration = parseFloat(durationMatch[1]) * 1e3;
200
- }
201
- const heapMatch = cleanOutput.match(/(\d+)\s*MB\s+heap\s+used/i);
202
- if (heapMatch) {
203
- result.heapMb = parseInt(heapMatch[1], 10);
204
- }
205
- const failedSectionStart = output.indexOf("Failed Tests");
206
- if (failedSectionStart !== -1) {
207
- const failedSectionEnd = output.indexOf("\n Test Files", failedSectionStart);
208
- const errorSection = failedSectionEnd !== -1 ? output.substring(failedSectionStart, failedSectionEnd) : output.substring(failedSectionStart);
209
- const failPattern = /FAIL\s*(?:\x1B\[[0-9;]*[a-zA-Z]|\s)*tests\//g;
210
- const matches = [...errorSection.matchAll(failPattern)];
211
- for (let i = 0; i < matches.length; i++) {
212
- const matchPos = matches[i].index;
213
- const lineStart = errorSection.lastIndexOf("\n", matchPos);
214
- const actualStart = lineStart === -1 ? 0 : lineStart;
215
- const matchEnd = i < matches.length - 1 ? matches[i + 1].index : errorSection.length;
216
- const nextLineStart = errorSection.lastIndexOf("\n", matchEnd);
217
- const actualEnd = nextLineStart === -1 ? matchEnd : nextLineStart;
218
- const errorBlock = errorSection.substring(actualStart, actualEnd).trim();
219
- if (errorBlock) result.errors.push(errorBlock);
220
- }
221
- }
222
- return result;
223
- }
224
- function deduplicateErrors(errors) {
225
- const fullText = errors.join("\n");
226
- const lines = fullText.split("\n");
227
- const failLineMap = /* @__PURE__ */ new Map();
228
- const lineIndices = /* @__PURE__ */ new Map();
229
- lines.forEach((line, idx) => {
230
- if (line.includes("FAIL") && line.includes("Config:")) {
231
- lineIndices.set(line, idx);
232
- const cleaned = stripAnsi(line);
233
- const match = cleaned.match(/^(.+Config:\s+)'*([^'>]+)'*(.+)$/);
234
- if (match) {
235
- const [, before, config, after] = match;
236
- const pattern = `${before.trim()}|||${after.trim()}`;
237
- if (!failLineMap.has(pattern)) {
238
- failLineMap.set(pattern, { lines: [], configs: [] });
239
- }
240
- failLineMap.get(pattern).lines.push(line);
241
- failLineMap.get(pattern).configs.push(config.replace(/'/g, ""));
242
- }
243
- }
244
- });
245
- const skipIndices = /* @__PURE__ */ new Set();
246
- for (const [, data] of failLineMap.entries()) {
247
- if (data.configs.length > 1) {
248
- for (let i = 1; i < data.lines.length; i++) {
249
- const idx = lineIndices.get(data.lines[i]);
250
- skipIndices.add(idx);
251
- }
252
- const firstLine = data.lines[0];
253
- const configArray = `[${data.configs.map((c) => `'${c}'`).join(",")}]`;
254
- const consolidated = stripAnsi(firstLine).replace(/(Config:\s+)'*[^'>]+'*/, `$1${configArray}`);
255
- const firstIdx = lineIndices.get(firstLine);
256
- lines[firstIdx] = consolidated;
257
- }
258
- }
259
- return lines.filter((_, idx) => !skipIndices.has(idx)).join("\n");
260
- }
261
-
262
- // src/utils/env.mjs
263
- function buildNodeOptions({ maxOldSpaceMb, conditions = [], base = process.env.NODE_OPTIONS ?? "" }) {
264
- let opts = base;
265
- for (const cond of conditions) {
266
- const flag = `--conditions=${cond}`;
267
- if (!opts.includes(flag)) {
268
- opts = opts ? `${opts} ${flag}` : flag;
269
- }
270
- }
271
- if (maxOldSpaceMb && !opts.includes("--max-old-space-size")) {
272
- const flag = `--max-old-space-size=${maxOldSpaceMb}`;
273
- opts = opts ? `${opts} ${flag}` : flag;
274
- }
275
- return opts.trim();
276
- }
277
-
278
- // src/core/spawn.mjs
279
- function buildEnv({ maxOldSpaceMb, conditions = [], nodeEnv = "development", extraEnv = {} }) {
280
- const env = { ...process.env };
281
- if (!env.NODE_ENV) env.NODE_ENV = nodeEnv;
282
- const nodeOptions = buildNodeOptions({ maxOldSpaceMb, conditions, base: env.NODE_OPTIONS ?? "" });
283
- if (nodeOptions) env.NODE_OPTIONS = nodeOptions;
284
- Object.assign(env, extraEnv);
285
- return env;
286
- }
287
- function buildBaseArgs(vitestBin, vitestConfig) {
288
- const configArgs = vitestConfig ? ["--config", vitestConfig] : [];
289
- return [vitestBin, ...configArgs, "run"];
290
- }
291
- function runSingleFile(filePath, opts) {
292
- const {
293
- cwd,
294
- vitestBin,
295
- vitestConfig,
296
- maxOldSpaceMb,
297
- conditions = [],
298
- nodeEnv = "development",
299
- vitestArgs = [],
300
- streamOutput = true,
301
- // Other discovered files whose path would spuriously also match Vitest's
302
- // own substring filter on `filePath` (see discover.mjs computeFilterConflicts).
303
- // Excluded explicitly so this invocation runs exactly `filePath`.
304
- excludePaths = [],
305
- // Extra env vars for the child (e.g. VITEST_RUNNER_TMP — see core/scratch.mjs).
306
- extraEnv = {}
307
- } = opts;
308
- return new Promise((resolve) => {
309
- const startTime = Date.now();
310
- const excludeArgs = excludePaths.flatMap((p) => ["--exclude", p]);
311
- const args = [...buildBaseArgs(vitestBin, vitestConfig), ...vitestArgs, ...excludeArgs, filePath];
312
- const env = buildEnv({ maxOldSpaceMb, conditions, nodeEnv, extraEnv });
313
- const child = spawn(process.execPath, args, { cwd, stdio: ["ignore", "pipe", "pipe"], env });
314
- let stdout = "";
315
- let stderr = "";
316
- child.stdout?.on("data", (data) => {
317
- stdout += data.toString();
318
- if (streamOutput) process.stdout.write(data);
319
- });
320
- child.stderr?.on("data", (data) => {
321
- stderr += data.toString();
322
- if (streamOutput) process.stderr.write(data);
323
- });
324
- child.on("close", (code) => {
325
- const spawnDuration = Date.now() - startTime;
326
- const output = `${stdout}
327
- ${stderr}`;
328
- const parsed = parseVitestOutput(output);
329
- resolve({
330
- file: filePath,
331
- code: code ?? 1,
332
- // c8 ignore next -- false branch verified manually; V8 ternary probe mismatch inside object literal
333
- duration: parsed.duration > 0 ? parsed.duration : spawnDuration,
334
- testFilesPass: parsed.testFilesPass,
335
- testFilesFail: parsed.testFilesFail,
336
- testsPass: parsed.testsPass,
337
- testsFail: parsed.testsFail,
338
- testsSkip: parsed.testsSkip,
339
- heapMb: parsed.heapMb,
340
- errors: parsed.errors,
341
- rawOutput: output
342
- });
343
- });
344
- child.on("error", (err) => {
345
- resolve({
346
- file: filePath,
347
- code: 1,
348
- duration: Date.now() - startTime,
349
- testFilesPass: 0,
350
- testFilesFail: 1,
351
- testsPass: 0,
352
- testsFail: 0,
353
- testsSkip: 0,
354
- heapMb: null,
355
- errors: [err.message],
356
- rawOutput: err.toString()
357
- });
358
- });
359
- });
360
- }
361
- function runVitestDirect(opts) {
362
- const { cwd, vitestBin, vitestConfig, maxOldSpaceMb, conditions = [], nodeEnv = "development", vitestArgs = [] } = opts;
363
- return new Promise((resolve) => {
364
- const args = [...buildBaseArgs(vitestBin, vitestConfig), ...vitestArgs];
365
- const env = buildEnv({ maxOldSpaceMb, conditions, nodeEnv });
366
- const child = spawn(process.execPath, args, { cwd, stdio: "inherit", env });
367
- child.on("close", (code) => resolve(code ?? 1));
368
- child.on("error", () => resolve(1));
369
- });
370
- }
371
- function runMergeReports(blobsDir, opts) {
372
- const {
373
- cwd,
374
- vitestBin,
375
- vitestConfig,
376
- maxOldSpaceMb,
377
- conditions = [],
378
- nodeEnv = "development",
379
- extraCoverageArgs = [],
380
- quietOutput = false
381
- } = opts;
382
- return new Promise((resolve) => {
383
- const configArgs = vitestConfig ? ["--config", vitestConfig] : [];
384
- const mergeReporterArgs = quietOutput ? ["--color"] : [];
385
- const args = [vitestBin, ...configArgs, "--mergeReports", blobsDir, "--run", "--coverage", ...mergeReporterArgs, ...extraCoverageArgs];
386
- const env = buildEnv({ maxOldSpaceMb, conditions, nodeEnv });
387
- const child = spawn(process.execPath, args, {
388
- cwd,
389
- stdio: quietOutput ? ["ignore", "pipe", "pipe"] : "inherit",
390
- env
391
- });
392
- let stdout = "";
393
- let stderr = "";
394
- if (quietOutput) {
395
- child.stdout?.on("data", (data) => stdout += data.toString());
396
- child.stderr?.on("data", (data) => stderr += data.toString());
397
- }
398
- child.on("close", (code) => resolve({ exitCode: code ?? 1, output: `${stdout}
399
- ${stderr}` }));
400
- child.on("error", () => resolve({ exitCode: 1, output: "" }));
401
- });
402
- }
403
-
404
- // src/core/progress.mjs
405
- import chalk from "chalk";
406
-
407
- // src/utils/duration.mjs
408
- function formatDuration(ms) {
409
- const totalSeconds = Math.max(0, Math.floor(ms / 1e3));
410
- const hours = Math.floor(totalSeconds / 3600);
411
- const minutes = Math.floor(totalSeconds % 3600 / 60);
412
- const seconds = totalSeconds % 60;
413
- if (hours > 0) {
414
- return `${hours}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
415
- }
416
- return `${minutes}:${seconds.toString().padStart(2, "0")}`;
417
- }
418
-
419
- // src/core/progress.mjs
420
- function createCoverageProgressTracker(total) {
421
- const isTTY = Boolean(process.stdout.isTTY);
422
- const spinnerFrames = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
423
- const barWidth = 26;
424
- const startTime = Date.now();
425
- let completed = 0;
426
- let active = 0;
427
- let failed = 0;
428
- let frameIndex = 0;
429
- let maxLineLength = 0;
430
- let lastPlainLog = 0;
431
- let spinnerTimer = null;
432
- function buildLine() {
433
- const percent = total === 0 ? 100 : completed / total * 100;
434
- const elapsedMs = Date.now() - startTime;
435
- const avgPerFile = completed > 0 ? elapsedMs / completed : 0;
436
- const etaMs = avgPerFile * Math.max(total - completed, 0);
437
- const filled = Math.round(percent / 100 * barWidth);
438
- const spinner = spinnerFrames[frameIndex % spinnerFrames.length];
439
- const bar = `[${"=".repeat(filled)}${"-".repeat(Math.max(0, barWidth - filled))}]`;
440
- let _percent = percent.toFixed(1).padStart(5);
441
- if (percent < 30) {
442
- _percent = chalk.red(_percent + "%");
443
- } else if (percent < 70) {
444
- _percent = chalk.rgb(255, 136, 0)(_percent + "%");
445
- } else if (percent > 99) {
446
- _percent = chalk.green(_percent + "%");
447
- } else {
448
- _percent = chalk.yellow(_percent + "%");
449
- }
450
- if (isTTY) {
451
- return `${chalk.green(spinner)} ${chalk.green(bar)} ${chalk.bold(_percent)} ${completed}/${total} | active ${active} | failed ${failed} | ETA ${formatDuration(etaMs)} | elapsed ${formatDuration(elapsedMs)}`;
452
- }
453
- return `progress ${percent.toFixed(1)}% ${completed}/${total} | active ${active} | failed ${failed} | eta ${formatDuration(etaMs)} | elapsed ${formatDuration(elapsedMs)}`;
454
- }
455
- function render(forcePlainLog = false) {
456
- const line = buildLine();
457
- frameIndex++;
458
- if (isTTY) {
459
- const visibleLength = line.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "").length;
460
- maxLineLength = Math.max(maxLineLength, visibleLength);
461
- process.stdout.write(`\r${line.padEnd(maxLineLength, " ")}`);
462
- return;
463
- }
464
- const now = Date.now();
465
- if (forcePlainLog || now - lastPlainLog >= 2e3) {
466
- console.log(line);
467
- lastPlainLog = now;
468
- }
469
- }
470
- function startSpinnerLoop() {
471
- if (!isTTY || spinnerTimer) return;
472
- spinnerTimer = setInterval(() => {
473
- if (completed >= total && active === 0) return;
474
- render();
475
- }, 120);
476
- spinnerTimer.unref?.();
477
- }
478
- function stopSpinnerLoop() {
479
- if (!spinnerTimer) return;
480
- clearInterval(spinnerTimer);
481
- spinnerTimer = null;
482
- }
483
- render(true);
484
- startSpinnerLoop();
485
- return {
486
- /**
487
- * Call when a file run starts (increments active count).
488
- * @returns {void}
489
- */
490
- onStart() {
491
- active++;
492
- render();
493
- },
494
- /**
495
- * Call when a file run completes.
496
- * @param {boolean} failedRun - Whether the run exited with a non-zero code.
497
- * @returns {void}
498
- */
499
- onComplete(failedRun) {
500
- active = Math.max(0, active - 1);
501
- completed++;
502
- if (failedRun) failed++;
503
- render(true);
504
- },
505
- /**
506
- * Stop the spinner and print the final progress line.
507
- * @returns {void}
508
- */
509
- finish() {
510
- stopSpinnerLoop();
511
- render(true);
512
- if (isTTY) process.stdout.write("\n");
513
- }
514
- };
515
- }
516
- var noopProgressTracker = {
517
- /** @returns {void} */
518
- onStart() {
519
- },
520
- /** @param {boolean} ___failedRun @returns {void} */
521
- onComplete(___failedRun) {
522
- },
523
- /** @returns {void} */
524
- finish() {
525
- }
526
- };
527
-
528
- // src/core/report.mjs
529
- import fs3 from "fs/promises";
530
- import path3 from "path";
531
- import chalk2 from "chalk";
532
- function printQuietCoverageFailureDetails(failedResults) {
533
- if (failedResults.length === 0) return;
534
- console.log(`
535
- ${"=".repeat(80)}`);
536
- console.log(chalk2.bold.red("\u2716 FAILED TEST FILES (VERBOSE OUTPUT)"));
537
- console.log("=".repeat(80));
538
- for (const r of failedResults) {
539
- console.log(`
540
- ${chalk2.red("\u2716")} ${chalk2.red(r.file)} ${chalk2.dim(`(exit ${r.code})`)}`);
541
- if (r.rawOutput?.trim()) {
542
- console.log(r.rawOutput.trimEnd());
543
- } else {
544
- console.log(chalk2.dim("(no child output captured)"));
545
- }
546
- }
547
- console.log(`
548
- ${"=".repeat(80)}`);
549
- }
550
- function printMergeOutput(exitCode, output) {
551
- if (exitCode === 0) {
552
- const marker = "% Coverage report from v8";
553
- const rawLines = output.split("\n");
554
- const markerLineIndex = rawLines.findIndex((line) => stripAnsi(line).includes(marker));
555
- if (markerLineIndex >= 0) {
556
- let endLineIndex = rawLines.length;
557
- for (let i = markerLineIndex + 1; i < rawLines.length; i++) {
558
- const line = stripAnsi(rawLines[i]).trimStart();
559
- if (line.startsWith("stderr |") || line.startsWith("stdout |")) {
560
- endLineIndex = i;
561
- break;
562
- }
563
- }
564
- const coverageBody = rawLines.slice(markerLineIndex + 1, endLineIndex).join("\n").trimEnd();
565
- if (coverageBody) {
566
- const fullBlock = rawLines.slice(markerLineIndex, endLineIndex).join("\n").trimEnd();
567
- console.log(`
568
- ${fullBlock}
569
- `);
570
- }
571
- }
572
- } else {
573
- const trimmed = output.trimEnd();
574
- if (trimmed) console.error(trimmed);
575
- }
576
- }
577
- function computeSummaryFromFinal(finalData) {
578
- const pct = (covered, total) => total === 0 ? 100 : parseFloat((covered / total * 100).toFixed(2));
579
- const summary = {
580
- total: {
581
- statements: { total: 0, covered: 0, pct: 0 },
582
- branches: { total: 0, covered: 0, pct: 0 },
583
- functions: { total: 0, covered: 0, pct: 0 },
584
- lines: { total: 0, covered: 0, pct: 0 }
585
- }
586
- };
587
- for (const [filePath, data] of Object.entries(finalData)) {
588
- const sKeys = Object.keys(data.s ?? {});
589
- const stmtTotal = sKeys.length;
590
- const stmtCovered = sKeys.filter((k) => data.s[k] > 0).length;
591
- const fKeys = Object.keys(data.f ?? {});
592
- const fnTotal = fKeys.length;
593
- const fnCovered = fKeys.filter((k) => data.f[k] > 0).length;
594
- let branchTotal = 0, branchCovered = 0;
595
- for (const counts of Object.values(data.b ?? {})) {
596
- branchTotal += counts.length;
597
- branchCovered += counts.filter((c) => c > 0).length;
598
- }
599
- const coveredLines = /* @__PURE__ */ new Set();
600
- const totalLines = /* @__PURE__ */ new Set();
601
- for (const [sid, loc] of Object.entries(data.statementMap ?? {})) {
602
- const line = loc?.start?.line;
603
- if (line == null) continue;
604
- totalLines.add(line);
605
- if ((data.s ?? {})[sid] > 0) coveredLines.add(line);
606
- }
607
- const fileStats = {
608
- statements: { total: stmtTotal, covered: stmtCovered, pct: pct(stmtCovered, stmtTotal) },
609
- branches: { total: branchTotal, covered: branchCovered, pct: pct(branchCovered, branchTotal) },
610
- functions: { total: fnTotal, covered: fnCovered, pct: pct(fnCovered, fnTotal) },
611
- lines: { total: totalLines.size, covered: coveredLines.size, pct: pct(coveredLines.size, totalLines.size) }
612
- };
613
- summary[filePath] = fileStats;
614
- for (const key of ["statements", "branches", "functions", "lines"]) {
615
- summary.total[key].total += fileStats[key].total;
616
- summary.total[key].covered += fileStats[key].covered;
617
- }
618
- }
619
- for (const key of ["statements", "branches", "functions", "lines"]) {
620
- const { total, covered } = summary.total[key];
621
- summary.total[key].pct = pct(covered, total);
622
- }
623
- return summary;
624
- }
625
- async function printCoverageSummary(cwd, extraCoverageArgs, worstCount = 10, options = {}) {
626
- const { silent = false } = options;
627
- let coverageDir = path3.resolve(cwd, "coverage");
628
- const repoDirArg = extraCoverageArgs.find((a) => a.startsWith("--coverage.reportsDirectory="));
629
- if (repoDirArg) {
630
- const raw = repoDirArg.split("=").slice(1).join("=");
631
- coverageDir = path3.isAbsolute(raw) ? raw : path3.resolve(cwd, raw);
632
- }
633
- let summary;
634
- try {
635
- const content = await fs3.readFile(path3.join(coverageDir, "coverage-summary.json"), "utf8");
636
- summary = JSON.parse(content);
637
- } catch {
638
- try {
639
- const content = await fs3.readFile(path3.join(coverageDir, "coverage-final.json"), "utf8");
640
- summary = computeSummaryFromFinal(JSON.parse(content));
641
- } catch {
642
- if (!silent) console.log(chalk2.dim(" (no coverage JSON found \u2014 skipping summary)"));
643
- return null;
644
- }
645
- }
646
- const { total, ...fileSummaries } = summary;
647
- if (worstCount > 0) {
648
- const fileRows = Object.entries(fileSummaries).map(([absFile, data]) => ({
649
- file: path3.relative(cwd, absFile),
650
- lines: data.lines?.pct ?? 0,
651
- stmts: data.statements?.pct ?? 0,
652
- fns: data.functions?.pct ?? 0,
653
- branches: data.branches?.pct ?? 0
654
- })).filter((r) => Math.min(r.lines, r.stmts, r.fns, r.branches) < 100).sort((a, b) => Math.min(a.lines, a.stmts, a.fns, a.branches) - Math.min(b.lines, b.stmts, b.fns, b.branches));
655
- const rowsToShow = fileRows.slice(0, worstCount);
656
- if (!silent) {
657
- console.log("\n" + chalk2.bold("\u{1F4C9} WORST COVERAGE FILES (lowest metric)"));
658
- console.log("-".repeat(80));
659
- rowsToShow.forEach(({ file, lines, stmts, fns, branches }) => {
660
- const worst = Math.min(lines, stmts, fns, branches);
661
- const extras = chalk2.dim(
662
- `lines ${lines.toFixed(0)}% | stmts ${stmts.toFixed(0)}% | fns ${fns.toFixed(0)}% | branches ${branches.toFixed(0)}%`
663
- );
664
- console.log(` ${colourPct(chalk2, worst)}% ${chalk2.dim(file)} ${extras}`);
665
- });
666
- if (fileRows.length > worstCount) {
667
- console.log(chalk2.dim(` ... and ${fileRows.length - worstCount} more files`));
668
- }
669
- }
670
- const tl2 = total.lines?.pct ?? 0;
671
- const ts2 = total.statements?.pct ?? 0;
672
- const tf2 = total.functions?.pct ?? 0;
673
- const tb2 = total.branches?.pct ?? 0;
674
- if (!silent) {
675
- console.log(
676
- `
677
- ${chalk2.bold("Coverage")} ${colourPct(chalk2, tl2)}% lines ${chalk2.dim("|")} ${colourPct(chalk2, ts2)}% statements ${chalk2.dim("|")} ${colourPct(chalk2, tf2)}% functions ${chalk2.dim("|")} ${colourPct(chalk2, tb2)}% branches`
678
- );
679
- }
680
- return {
681
- coverageDir,
682
- total,
683
- worstFiles: rowsToShow,
684
- worstFilesShown: rowsToShow.length,
685
- worstFilesTotal: fileRows.length,
686
- summary
687
- };
688
- }
689
- const tl = total.lines?.pct ?? 0;
690
- const ts = total.statements?.pct ?? 0;
691
- const tf = total.functions?.pct ?? 0;
692
- const tb = total.branches?.pct ?? 0;
693
- if (!silent) {
694
- console.log(
695
- `
696
- ${chalk2.bold("Coverage")} ${colourPct(chalk2, tl)}% lines ${chalk2.dim("|")} ${colourPct(chalk2, ts)}% statements ${chalk2.dim("|")} ${colourPct(chalk2, tf)}% functions ${chalk2.dim("|")} ${colourPct(chalk2, tb)}% branches`
697
- );
698
- }
699
- return {
700
- coverageDir,
701
- total,
702
- worstFiles: [],
703
- worstFilesShown: 0,
704
- worstFilesTotal: 0,
705
- summary
706
- };
707
- }
708
-
709
- // src/core/scratch.mjs
710
- import fs4 from "fs/promises";
711
- import fsSync from "fs";
712
- import path4 from "path";
713
- var DEFAULT_SCRATCH_DIR = "tmp/vitest-runner";
714
- var RUN_ROOT_NAME_PATTERN = /^(\d+)-\d+$/;
715
- function isPidAlive(pid) {
716
- try {
717
- process.kill(pid, 0);
718
- return true;
719
- } catch (err) {
720
- return err.code !== "ESRCH";
721
- }
722
- }
723
- function sanitizeLabel(label) {
724
- const cleaned = String(label).replace(/[^a-zA-Z0-9_-]+/g, "-").slice(0, 80);
725
- return cleaned || "scratch";
726
- }
727
- async function sweepStaleScratchRoots(cwd, scratchDir) {
728
- const base = path4.resolve(cwd, scratchDir);
729
- let entries;
730
- try {
731
- entries = await fs4.readdir(base, { withFileTypes: true });
732
- } catch {
733
- return;
734
- }
735
- for (const entry of entries) {
736
- if (!entry.isDirectory()) continue;
737
- const match = entry.name.match(RUN_ROOT_NAME_PATTERN);
738
- if (!match) continue;
739
- const pid = parseInt(match[1], 10);
740
- if (isPidAlive(pid)) continue;
741
- await fs4.rm(path4.join(base, entry.name), { recursive: true, force: true }).catch(() => {
742
- });
743
- }
744
- }
745
- async function createRunScratchRoot(cwd, scratchDir) {
746
- const base = path4.resolve(cwd, scratchDir);
747
- const root = path4.join(base, `${process.pid}-${Date.now()}`);
748
- await fs4.mkdir(root, { recursive: true });
749
- return root;
750
- }
751
- async function createFileScratchDir(runRoot, index) {
752
- const dir = path4.join(runRoot, `worker-${index}`);
753
- await fs4.mkdir(dir, { recursive: true });
754
- return dir;
755
- }
756
- async function removeScratchRoot(root) {
757
- await fs4.rm(root, { recursive: true, force: true }).catch(() => {
758
- });
759
- }
760
- function removeScratchRootSync(root) {
761
- try {
762
- fsSync.rmSync(root, { recursive: true, force: true });
763
- } catch {
764
- }
765
- }
766
- function makeRunTmpDir(label) {
767
- const base = process.env.VITEST_RUNNER_TMP;
768
- if (!base) {
769
- throw new Error("makeRunTmpDir() requires VITEST_RUNNER_TMP to be set \u2014 call it from a test file run by vitest-runner.");
770
- }
771
- return fsSync.mkdtempSync(path4.join(base, `${sanitizeLabel(label)}-`));
772
- }
773
-
774
- // src/runner.mjs
775
- function getHeapForFile(filePath, globalMaxMb, overrides) {
776
- const normalized = filePath.replace(/\\/g, "/");
777
- let perFileMb;
778
- for (const { pattern, heapMb } of overrides) {
779
- if (normalized.includes(pattern)) {
780
- perFileMb = heapMb;
781
- break;
782
- }
783
- }
784
- if (perFileMb === void 0 && globalMaxMb === void 0) return void 0;
785
- if (perFileMb === void 0) return globalMaxMb;
786
- if (globalMaxMb === void 0) return perFileMb;
787
- return Math.max(perFileMb, globalMaxMb);
788
- }
789
- async function run(opts) {
790
- const cwd = opts.cwd ?? process.cwd();
791
- const scratchDirOpt = opts.scratchDir ?? DEFAULT_SCRATCH_DIR;
792
- const keepTmp = opts.keepTmp ?? false;
793
- await sweepStaleScratchRoots(cwd, scratchDirOpt);
794
- const scratchRoot = await createRunScratchRoot(cwd, scratchDirOpt);
795
- const onSignal = () => {
796
- removeScratchRootSync(scratchRoot);
797
- process.exitCode = 130;
798
- process.exit();
799
- };
800
- if (!keepTmp) {
801
- process.once("SIGINT", onSignal);
802
- process.once("SIGTERM", onSignal);
803
- }
804
- try {
805
- return await runImpl(opts, scratchRoot);
806
- } finally {
807
- process.removeListener("SIGINT", onSignal);
808
- process.removeListener("SIGTERM", onSignal);
809
- if (!keepTmp) await removeScratchRoot(scratchRoot);
810
- }
811
- }
812
- async function runImpl(opts, scratchRoot) {
813
- const {
814
- cwd = process.cwd(),
815
- testDir,
816
- testPatterns = [],
817
- testListFile,
818
- testFilePattern,
819
- vitestArgs: rawVitestArgs = [],
820
- showErrorDetails = true,
821
- coverageQuiet = false,
822
- suppressFileOutput = false,
823
- suppressPassingFiles = false,
824
- topSummary = true,
825
- json = false,
826
- workers = parseInt(process.env.VITEST_WORKERS ?? "4", 10),
827
- worstCoverageCount = 10,
828
- blobsDir: blobsDirOpt,
829
- mergeReports = true,
830
- earlyRunPatterns = [],
831
- perFileHeapOverrides = [],
832
- conditions = [],
833
- nodeEnv = "development",
834
- /** @internal Inject pre-built results to bypass discovery and spawn (for testing final-report render paths). */
835
- _testResultsOverride = null
836
- } = opts;
837
- let fileScratchIndex = 0;
838
- const maxOldSpaceMb = opts.maxOldSpaceMb ?? (process.env.VITEST_HEAP_MB ? parseInt(process.env.VITEST_HEAP_MB, 10) : void 0);
839
- const emitTextOutput = !json;
840
- const vitestBin = resolveBin(cwd, "vitest", "vitest");
841
- const vitestConfig = await resolveVitestConfig(cwd, opts.vitestConfig);
842
- const spawnBase = { cwd, vitestBin, vitestConfig, conditions, nodeEnv };
843
- const vitestArgs = [...rawVitestArgs];
844
- if (coverageQuiet && !vitestArgs.some((a) => a === "--coverage" || a.startsWith("--coverage."))) {
845
- vitestArgs.unshift("--coverage");
846
- }
847
- const hasCoverage = vitestArgs.some((a) => a === "--coverage" || a.startsWith("--coverage."));
848
- if (hasCoverage) {
849
- const blobsDir = path5.resolve(cwd, blobsDirOpt ?? ".vitest-coverage-blobs");
850
- const coverageTmpBase = path5.resolve(cwd, ".vitest-coverage-tmp");
851
- await Promise.all([fs5.rm(blobsDir, { recursive: true, force: true }), fs5.rm(coverageTmpBase, { recursive: true, force: true })]);
852
- await Promise.all([fs5.mkdir(blobsDir, { recursive: true }), fs5.mkdir(coverageTmpBase, { recursive: true })]);
853
- const allTestFiles = await discoverVitestFiles({ cwd, testDir, testPatterns, testListFile, testFilePattern, earlyRunPatterns });
854
- const filterConflicts2 = computeFilterConflicts(allTestFiles);
855
- if (allTestFiles.length === 0) {
856
- const noTestsMessage = testPatterns.length > 0 ? `\u274C No Vitest test files found matching: ${testPatterns.join(", ")}` : "\u274C No Vitest test files found";
857
- if (emitTextOutput) console.log(noTestsMessage);
858
- if (json) {
859
- return {
860
- exitCode: 1,
861
- mode: "coverage",
862
- message: noTestsMessage,
863
- options: {
864
- cwd,
865
- testDir,
866
- testPatterns,
867
- testListFile,
868
- workers,
869
- coverageQuiet,
870
- suppressFileOutput,
871
- suppressPassingFiles,
872
- topSummary,
873
- vitestArgs
874
- }
875
- };
876
- }
877
- return 1;
878
- }
879
- const extraCoverageArgs = vitestArgs.filter((a) => a !== "--coverage" && a.startsWith("--coverage."));
880
- const nonCoveragePassthrough = vitestArgs.filter((a) => a !== "--coverage" && !a.startsWith("--coverage."));
881
- const soloFiles2 = allTestFiles.filter((f) => earlyRunPatterns.some((p) => f.replace(/\\/g, "/").includes(p)));
882
- const parallelFiles2 = allTestFiles.filter((f) => !earlyRunPatterns.some((p) => f.replace(/\\/g, "/").includes(p)));
883
- const suppressPerFileCoverageOutput = coverageQuiet || suppressFileOutput || json;
884
- const showCoverageProgress = coverageQuiet && !json;
885
- if (!coverageQuiet && !suppressFileOutput && emitTextOutput) {
886
- console.log(`
887
- \u{1F9EA} Running ${allTestFiles.length} test files for coverage (blob + merge mode)`);
888
- console.log(`\u2699\uFE0F Workers: ${workers} (${soloFiles2.length} solo first, then parallel)`);
889
- if (maxOldSpaceMb) console.log(`\u{1F9E0} Heap limit: ${maxOldSpaceMb} MB`);
890
- console.log("");
891
- }
892
- const progress = showCoverageProgress ? createCoverageProgressTracker(allTestFiles.length) : noopProgressTracker;
893
- const coverageResults = [];
894
- let blobIndex = 0;
895
- const runCoverageFile = async (filePath) => {
896
- const blobPath = path5.join(blobsDir, `run-${blobIndex}.blob`);
897
- blobIndex++;
898
- if (!suppressPerFileCoverageOutput && emitTextOutput) {
899
- console.log(`
900
- ${"=".repeat(80)}`);
901
- console.log(`\u25B6\uFE0F ${filePath}`);
902
- console.log("=".repeat(80));
903
- }
904
- progress.onStart();
905
- const tmpCoverageDir = path5.join(coverageTmpBase, `run-${blobIndex}`);
906
- const blobArgs = [
907
- ...nonCoveragePassthrough,
908
- "--coverage",
909
- `--coverage.reportsDirectory=${tmpCoverageDir}`,
910
- "--reporter=default",
911
- "--reporter=blob",
912
- `--outputFile=${blobPath}`
913
- ];
914
- const scratchDir = await createFileScratchDir(scratchRoot, fileScratchIndex++);
915
- const result = await runSingleFile(filePath, {
916
- ...spawnBase,
917
- maxOldSpaceMb: getHeapForFile(filePath, maxOldSpaceMb, perFileHeapOverrides),
918
- vitestArgs: blobArgs,
919
- streamOutput: !suppressPerFileCoverageOutput,
920
- excludePaths: filterConflicts2.get(filePath),
921
- extraEnv: { VITEST_RUNNER_TMP: scratchDir }
922
- });
923
- coverageResults.push(result);
924
- progress.onComplete(result.code !== 0);
925
- if (!suppressPerFileCoverageOutput && emitTextOutput) {
926
- const durationSec = (result.duration / 1e3).toFixed(2);
927
- if (result.code === 0) {
928
- const heapInfo = result.heapMb ? ` | ${result.heapMb} MB heap` : "";
929
- console.log(`
930
- \u2705 PASSED (${durationSec}s${heapInfo})
931
- `);
932
- } else {
933
- console.log(`
934
- \u274C FAILED (exit code ${result.code}, ${durationSec}s)
935
- `);
936
- }
937
- }
938
- };
939
- for (const filePath of soloFiles2) {
940
- await runCoverageFile(filePath).catch((err) => {
941
- if (emitTextOutput) console.error(`Error running ${filePath}:`, err);
942
- });
943
- }
944
- let coverageFileIndex = 0;
945
- const coverageActivePromises = /* @__PURE__ */ new Set();
946
- while (coverageFileIndex < parallelFiles2.length || coverageActivePromises.size > 0) {
947
- while (coverageFileIndex < parallelFiles2.length && coverageActivePromises.size < workers) {
948
- const filePath = parallelFiles2[coverageFileIndex++];
949
- const promise = runCoverageFile(filePath).catch((err) => {
950
- if (emitTextOutput) console.error(`Error running ${filePath}:`, err);
951
- }).finally(() => coverageActivePromises.delete(promise));
952
- coverageActivePromises.add(promise);
953
- }
954
- if (coverageActivePromises.size > 0) await Promise.race(coverageActivePromises);
955
- }
956
- progress.finish();
957
- const blobFiles = (await fs5.readdir(blobsDir).catch(() => [])).filter((f) => f.endsWith(".blob"));
958
- if (blobFiles.length === 0) {
959
- const message = "\u274C No coverage blobs were generated \u2014 coverage report cannot be produced";
960
- if (emitTextOutput) console.error(message);
961
- if (json) {
962
- return {
963
- exitCode: 1,
964
- mode: "coverage",
965
- message,
966
- options: {
967
- cwd,
968
- testDir,
969
- testPatterns,
970
- testListFile,
971
- workers,
972
- coverageQuiet,
973
- suppressFileOutput,
974
- suppressPassingFiles,
975
- topSummary,
976
- showErrorDetails,
977
- worstCoverageCount,
978
- vitestArgs
979
- },
980
- totals: {
981
- testFiles: allTestFiles.length,
982
- failedFiles: coverageResults.filter((r) => r.code !== 0).length,
983
- passedFiles: coverageResults.filter((r) => r.code === 0).length
984
- },
985
- results: {
986
- all: coverageResults,
987
- failed: coverageResults.filter((r) => r.code !== 0)
988
- },
989
- merge: {
990
- blobFiles: 0,
991
- exitCode: 1,
992
- output: ""
993
- },
994
- coverageSummary: null
995
- };
996
- }
997
- return 1;
998
- }
999
- let mergeExitCode = 0;
1000
- let mergeOutput = "";
1001
- let coverageSummary = null;
1002
- if (mergeReports) {
1003
- if (!coverageQuiet && !suppressFileOutput && emitTextOutput) {
1004
- console.log(`
1005
- ${"=".repeat(80)}`);
1006
- console.log(`\u{1F4CA} Merging ${blobFiles.length} coverage blobs into final report...`);
1007
- console.log("=".repeat(80));
1008
- }
1009
- ({ exitCode: mergeExitCode, output: mergeOutput } = await runMergeReports(blobsDir, {
1010
- ...spawnBase,
1011
- maxOldSpaceMb,
1012
- extraCoverageArgs,
1013
- quietOutput: coverageQuiet || json
1014
- }));
1015
- if (coverageQuiet && emitTextOutput) {
1016
- printMergeOutput(mergeExitCode, mergeOutput);
1017
- }
1018
- coverageSummary = await printCoverageSummary(cwd, extraCoverageArgs, worstCoverageCount, { silent: json });
1019
- }
1020
- await Promise.all([
1021
- ...mergeReports ? [fs5.rm(blobsDir, { recursive: true, force: true }).catch(() => {
1022
- })] : [],
1023
- fs5.rm(coverageTmpBase, { recursive: true, force: true }).catch(() => {
1024
- })
1025
- ]);
1026
- const coverageFailed = coverageResults.filter((r) => r.code !== 0);
1027
- if (coverageQuiet && emitTextOutput) printQuietCoverageFailureDetails(coverageFailed);
1028
- const exitCode2 = coverageFailed.length > 0 ? 1 : mergeExitCode;
1029
- if (json) {
1030
- const coverageWithHeap = coverageResults.filter((r) => r.heapMb !== null);
1031
- return {
1032
- exitCode: exitCode2,
1033
- mode: "coverage",
1034
- options: {
1035
- cwd,
1036
- testDir,
1037
- testPatterns,
1038
- testListFile,
1039
- workers,
1040
- coverageQuiet,
1041
- suppressFileOutput,
1042
- suppressPassingFiles,
1043
- topSummary,
1044
- showErrorDetails,
1045
- worstCoverageCount,
1046
- vitestArgs
1047
- },
1048
- totals: {
1049
- testFiles: allTestFiles.length,
1050
- failedFiles: coverageFailed.length,
1051
- passedFiles: coverageResults.length - coverageFailed.length
1052
- },
1053
- results: {
1054
- all: coverageResults,
1055
- failed: coverageFailed
1056
- },
1057
- merge: {
1058
- blobFiles: blobFiles.length,
1059
- exitCode: mergeExitCode,
1060
- output: mergeOutput
1061
- },
1062
- coverageSummary,
1063
- ...topSummary ? {
1064
- topMemoryUsers: [...coverageWithHeap].sort((a, b) => b.heapMb - a.heapMb).slice(0, 10),
1065
- topDuration: [...coverageResults].sort((a, b) => b.duration - a.duration).slice(0, 10)
1066
- } : {}
1067
- };
1068
- }
1069
- return exitCode2;
1070
- }
1071
- const testFiles = await discoverVitestFiles({ cwd, testDir, testPatterns, testListFile, testFilePattern, earlyRunPatterns });
1072
- const filterConflicts = computeFilterConflicts(testFiles);
1073
- if (testFiles.length === 0) {
1074
- const noTestsMessage = testPatterns.length > 0 ? `\u274C No Vitest test files found matching: ${testPatterns.join(", ")}` : "\u274C No Vitest test files found";
1075
- if (emitTextOutput) console.log(noTestsMessage);
1076
- if (json) {
1077
- return {
1078
- exitCode: 1,
1079
- mode: "standard",
1080
- message: noTestsMessage,
1081
- options: {
1082
- cwd,
1083
- testDir,
1084
- testPatterns,
1085
- testListFile,
1086
- workers,
1087
- coverageQuiet,
1088
- suppressFileOutput,
1089
- suppressPassingFiles,
1090
- topSummary,
1091
- vitestArgs
1092
- }
1093
- };
1094
- }
1095
- return 1;
1096
- }
1097
- const soloFiles = testFiles.filter((f) => earlyRunPatterns.some((p) => f.replace(/\\/g, "/").includes(p)));
1098
- const parallelFiles = testFiles.filter((f) => !earlyRunPatterns.some((p) => f.replace(/\\/g, "/").includes(p)));
1099
- const scriptStartTime = Date.now();
1100
- const scriptStartTimeFormatted = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false });
1101
- if (emitTextOutput && !suppressFileOutput && testPatterns.length > 0) {
1102
- console.log(`
1103
- \u{1F9EA} Running ${testFiles.length} test files matching: ${testPatterns.join(", ")}`);
1104
- } else if (emitTextOutput && !suppressFileOutput) {
1105
- console.log(`
1106
- \u{1F9EA} Running ${testFiles.length} test files (${soloFiles.length} solo first, then parallel)`);
1107
- }
1108
- if (emitTextOutput && !suppressFileOutput) {
1109
- console.log(`\u2699\uFE0F Workers: ${workers}`);
1110
- if (maxOldSpaceMb) console.log(`\u{1F9E0} Heap limit: ${maxOldSpaceMb} MB`);
1111
- if (vitestArgs.length > 0) console.log(`\u{1F527} Vitest args: ${vitestArgs.join(" ")}`);
1112
- console.log("");
1113
- }
1114
- const results = [..._testResultsOverride ?? []];
1115
- const runTestFile = async (filePath) => {
1116
- if (!suppressFileOutput && emitTextOutput) {
1117
- console.log(`
1118
- ${"=".repeat(80)}`);
1119
- console.log(`\u25B6\uFE0F ${filePath}`);
1120
- console.log("=".repeat(80));
1121
- }
1122
- const scratchDir = await createFileScratchDir(scratchRoot, fileScratchIndex++);
1123
- const result = await runSingleFile(filePath, {
1124
- ...spawnBase,
1125
- maxOldSpaceMb: getHeapForFile(filePath, maxOldSpaceMb, perFileHeapOverrides),
1126
- vitestArgs,
1127
- streamOutput: !suppressFileOutput && !json,
1128
- excludePaths: filterConflicts.get(filePath),
1129
- extraEnv: { VITEST_RUNNER_TMP: scratchDir }
1130
- });
1131
- if (!suppressFileOutput && emitTextOutput) {
1132
- const durationSec = (result.duration / 1e3).toFixed(2);
1133
- if (result.code === 0) {
1134
- const heapInfo = result.heapMb ? ` | ${result.heapMb} MB heap` : "";
1135
- console.log(`
1136
- \u2705 PASSED (${durationSec}s${heapInfo})
1137
- `);
1138
- } else {
1139
- console.log(`
1140
- \u274C FAILED (exit code ${result.code}, ${durationSec}s)
1141
- `);
1142
- }
1143
- }
1144
- return result;
1145
- };
1146
- if (!_testResultsOverride) {
1147
- for (const filePath of soloFiles) {
1148
- const result = await runTestFile(filePath).catch((err) => {
1149
- if (emitTextOutput) console.error(`Error running ${filePath}:`, err);
1150
- return null;
1151
- });
1152
- if (result) results.push(result);
1153
- }
1154
- let index = 0;
1155
- const activePromises = /* @__PURE__ */ new Set();
1156
- while (index < parallelFiles.length || activePromises.size > 0) {
1157
- while (index < parallelFiles.length && activePromises.size < workers) {
1158
- const filePath = parallelFiles[index++];
1159
- const promise = runTestFile(filePath).then((result) => results.push(result)).catch((err) => {
1160
- if (emitTextOutput) console.error(`Error running ${filePath}:`, err);
1161
- }).finally(() => activePromises.delete(promise));
1162
- activePromises.add(promise);
1163
- }
1164
- if (activePromises.size > 0) await Promise.race(activePromises);
1165
- }
1166
- }
1167
- const totalTestFilesPass = results.reduce((s, r) => s + r.testFilesPass, 0);
1168
- const totalTestFilesFail = results.reduce((s, r) => s + r.testFilesFail, 0);
1169
- const totalTestsPass = results.reduce((s, r) => s + r.testsPass, 0);
1170
- const totalTestsFail = results.reduce((s, r) => s + r.testsFail, 0);
1171
- const totalTestsSkip = results.reduce((s, r) => s + (r.testsSkip || 0), 0);
1172
- const totalDuration = results.reduce((s, r) => s + r.duration, 0);
1173
- const failedFiles = results.filter((r) => r.code !== 0);
1174
- const passedFiles = results.filter((r) => r.code === 0);
1175
- const exitCode = failedFiles.length > 0 ? 1 : 0;
1176
- const scriptMemory = process.memoryUsage();
1177
- const scriptHeapMb = Math.round(scriptMemory.heapUsed / 1024 / 1024);
1178
- const scriptRssMb = Math.round(scriptMemory.rss / 1024 / 1024);
1179
- const withHeap = results.filter((r) => r.heapMb !== null);
1180
- const actualDurationSec = ((Date.now() - scriptStartTime) / 1e3).toFixed(2);
1181
- const testsDurationSec = (totalDuration / 1e3).toFixed(2);
1182
- if (json) {
1183
- return {
1184
- exitCode,
1185
- mode: "standard",
1186
- options: {
1187
- cwd,
1188
- testDir,
1189
- testPatterns,
1190
- testListFile,
1191
- workers,
1192
- coverageQuiet,
1193
- suppressFileOutput,
1194
- suppressPassingFiles,
1195
- topSummary,
1196
- showErrorDetails,
1197
- worstCoverageCount,
1198
- vitestArgs
1199
- },
1200
- totals: {
1201
- testFilesPass: totalTestFilesPass,
1202
- testFilesFail: totalTestFilesFail,
1203
- testsPass: totalTestsPass,
1204
- testsFail: totalTestsFail,
1205
- testsSkip: totalTestsSkip,
1206
- totalTests: totalTestsPass + totalTestsFail + totalTestsSkip
1207
- },
1208
- timing: {
1209
- startAt: scriptStartTimeFormatted,
1210
- wallClockSeconds: Number(actualDurationSec),
1211
- testsSeconds: Number(testsDurationSec)
1212
- },
1213
- heap: {
1214
- scriptHeapMb,
1215
- scriptRssMb,
1216
- maxHeapMb: withHeap.length > 0 ? Math.max(...withHeap.map((r) => r.heapMb)) : null,
1217
- avgHeapMb: withHeap.length > 0 ? Number((withHeap.reduce((sum, r) => sum + r.heapMb, 0) / withHeap.length).toFixed(0)) : null
1218
- },
1219
- results: {
1220
- all: results,
1221
- passed: passedFiles,
1222
- failed: failedFiles
1223
- },
1224
- ...topSummary ? {
1225
- topMemoryUsers: [...withHeap].sort((a, b) => b.heapMb - a.heapMb).slice(0, 10),
1226
- topDuration: [...results].sort((a, b) => b.duration - a.duration).slice(0, 10)
1227
- } : {}
1228
- };
1229
- }
1230
- console.log("\n" + "=".repeat(80));
1231
- if (topSummary && withHeap.length > 0) {
1232
- console.log("\n" + chalk3.bold("\u{1F9E0} TOP MEMORY USERS"));
1233
- console.log("-".repeat(80));
1234
- [...withHeap].sort((a, b) => b.heapMb - a.heapMb).slice(0, 10).forEach((r) => {
1235
- console.log(` ${String(r.heapMb).padStart(4)} MB ${chalk3.dim(r.file)}`);
1236
- });
1237
- }
1238
- if (topSummary && results.length > 0) {
1239
- console.log("\n" + chalk3.bold("\u23F1\uFE0F TOP DURATION"));
1240
- console.log("-".repeat(80));
1241
- [...results].sort((a, b) => b.duration - a.duration).slice(0, 10).forEach((r) => {
1242
- const sec = (r.duration / 1e3).toFixed(2);
1243
- console.log(` ${(sec + "s").padStart(8)} ${chalk3.dim(r.file)}`);
1244
- });
1245
- }
1246
- if (passedFiles.length > 0 && !suppressPassingFiles) {
1247
- console.log("\n" + "=".repeat(80));
1248
- console.log(chalk3.bold.green("\u2713 PASSED TEST FILES"));
1249
- console.log("=".repeat(80));
1250
- passedFiles.forEach((r) => {
1251
- const durationSec = (r.duration / 1e3).toFixed(2);
1252
- const statsInfo = [...r.heapMb ? [`${r.heapMb} MB`] : [], `${durationSec}s`];
1253
- const testInfo = r.testsPass > 0 ? ` - ${r.testsPass} tests` : "";
1254
- console.log(chalk3.green(`\u2713 ${r.file}${testInfo}`) + chalk3.dim(` (${statsInfo.join(", ")})`));
1255
- });
1256
- }
1257
- console.log("\n" + chalk3.bold("=".repeat(80)));
1258
- if (failedFiles.length > 0) {
1259
- console.log(`
1260
- \u274C ${failedFiles.length} test file(s) failed`);
1261
- console.log(chalk3.bold.red("\nFailed Test Files:"));
1262
- failedFiles.forEach((r) => {
1263
- const durationSec = (r.duration / 1e3).toFixed(2);
1264
- const testCounts = [
1265
- ...r.testsFail > 0 ? [chalk3.red(`${r.testsFail} failed`)] : [],
1266
- ...r.testsPass > 0 ? [chalk3.green(`${r.testsPass} passed`)] : [],
1267
- ...r.testsSkip > 0 ? [chalk3.yellow(`${r.testsSkip} skipped`)] : []
1268
- ];
1269
- const statsInfo = [...r.heapMb ? [`${r.heapMb} MB`] : [], `${durationSec}s`];
1270
- const countStr = testCounts.length > 0 ? ` (${testCounts.join(", ")})` : "";
1271
- console.log(` ${chalk3.red("\u2716")} ${r.file}${countStr}` + chalk3.dim(` [${statsInfo.join(", ")}]`));
1272
- if (showErrorDetails && r.errors.length > 0) {
1273
- const deduped = deduplicateErrors(r.errors).split("\n").map((line) => line.trim() ? ` ${line}` : "").join("\n");
1274
- console.log(deduped);
1275
- console.log("");
1276
- }
1277
- });
1278
- console.log("");
1279
- }
1280
- console.log(chalk3.bold("=".repeat(80)));
1281
- if (totalTestFilesFail > 0 && totalTestFilesPass > 0) {
1282
- console.log(
1283
- ` ${chalk3.bold("Test Files")} ${chalk3.red(`${totalTestFilesFail} failed`)} ${chalk3.dim("|")} ${chalk3.green(`${totalTestFilesPass} passed`)} ${chalk3.dim(`(${totalTestFilesPass + totalTestFilesFail})`)}`
1284
- );
1285
- } else if (totalTestFilesFail > 0) {
1286
- console.log(` ${chalk3.bold("Test Files")} ${chalk3.red(`${totalTestFilesFail} failed`)} ${chalk3.dim(`(${totalTestFilesFail})`)}`);
1287
- } else {
1288
- console.log(` ${chalk3.bold("Test Files")} ${chalk3.green(`${totalTestFilesPass} passed`)} ${chalk3.dim(`(${totalTestFilesPass})`)}`);
1289
- }
1290
- const totalTests = totalTestsPass + totalTestsFail + totalTestsSkip;
1291
- const testsParts = [
1292
- ...totalTestsFail > 0 ? [chalk3.red(`${totalTestsFail} failed`)] : [],
1293
- ...totalTestsPass > 0 ? [chalk3.green(`${totalTestsPass} passed`)] : [],
1294
- ...totalTestsSkip > 0 ? [chalk3.yellow(`${totalTestsSkip} skipped`)] : []
1295
- ];
1296
- console.log(` ${chalk3.bold("Tests")} ${testsParts.join(` ${chalk3.dim("|")} `)} ${chalk3.dim(`(${totalTests})`)}`);
1297
- console.log(` ${chalk3.bold("Start at")} ${scriptStartTimeFormatted}`);
1298
- console.log(` ${chalk3.bold("Duration")} ${actualDurationSec}s ${chalk3.dim(`(tests ${testsDurationSec}s)`)}`);
1299
- if (withHeap.length > 0) {
1300
- const maxHeap = Math.max(...withHeap.map((r) => r.heapMb));
1301
- const avgHeap = (withHeap.reduce((s, r) => s + r.heapMb, 0) / withHeap.length).toFixed(0);
1302
- console.log(` ${chalk3.bold("Heap")} max ${maxHeap} MB | avg ${avgHeap} MB | script ${scriptHeapMb} MB (RSS ${scriptRssMb} MB)`);
1303
- } else {
1304
- console.log(` ${chalk3.bold("Heap")} script ${scriptHeapMb} MB (RSS ${scriptRssMb} MB)`);
1305
- }
1306
- if (failedFiles.length > 0) return 1;
1307
- console.log(`
1308
- \u2705 All ${passedFiles.length} test files passed
1309
- `);
1310
- return 0;
1311
- }
1312
- export {
1313
- buildNodeOptions,
1314
- colourPct,
1315
- createCoverageProgressTracker,
1316
- deduplicateErrors,
1317
- discoverFilesInDir,
1318
- discoverVitestFiles,
1319
- formatDuration,
1320
- makeRunTmpDir,
1321
- noopProgressTracker,
1322
- parseVitestOutput,
1323
- printCoverageSummary,
1324
- printMergeOutput,
1325
- printQuietCoverageFailureDetails,
1326
- resolveBin,
1327
- resolveVitestConfig,
1328
- run,
1329
- runMergeReports,
1330
- runSingleFile,
1331
- runVitestDirect,
1332
- sortWithPriority,
1333
- stripAnsi
1334
- };
1
+ import K from"fs/promises";import me from"path";import S from"chalk";import{createRequire as wt}from"module";import Z from"path";import Tt from"fs/promises";import{pathToFileURL as Mt}from"url";function Pe(e,t,o=t){let r=wt(Mt(Z.join(e,"package.json"))),s=r.resolve(`${t}/package.json`),n=r(s),a=n.bin?.[o]??n.bin;if(!a)throw new Error(`No bin "${o}" found in ${t}/package.json`);return Z.join(Z.dirname(s),a)}var Et=Object.freeze(["vitest.config.ts","vitest.config.mts","vitest.config.cts","vitest.config.mjs","vitest.config.js","vitest.config.cjs","vite.config.ts","vite.config.mts","vite.config.mjs","vite.config.js"]);async function Oe(e,t){if(t)return Z.isAbsolute(t)?t:Z.resolve(e,t);for(let o of Et){let r=Z.join(e,o);try{return await Tt.access(r),r}catch{}}}import De from"fs/promises";import R from"path";var et=/\.test\.vitest\.(?:js|mjs|cjs)$/i;async function fe(e,t,o=et){let r=[e],s=[];for(;r.length;){let n=r.pop(),a;try{a=await De.readdir(n,{withFileTypes:!0})}catch{continue}for(let l of a){if(l.isDirectory()){if(l.name==="node_modules"||l.name.startsWith("."))continue;r.push(R.join(n,l.name));continue}l.isFile()&&o.test(l.name)&&s.push(R.relative(t,R.join(n,l.name)))}}return s}function ue(e,t=[]){let o=[],r=[];for(let s of e){let n=s.replace(/\\/g,"/"),a=t.findIndex(l=>n.includes(l));a!==-1?o.push({file:s,priorityIndex:a}):r.push(s)}return o.sort((s,n)=>s.priorityIndex-n.priorityIndex||s.file.localeCompare(n.file)),r.sort((s,n)=>s.localeCompare(n)),[...o.map(s=>s.file),...r]}function Ie(e){let t=e.map(r=>r.replace(/\\/g,"/")),o=new Map;for(let r=0;r<e.length;r++){let s=[];for(let n=0;n<e.length;n++)r!==n&&t[n].includes(t[r])&&s.push(e[n]);o.set(e[r],s)}return o}async function de(e){let{cwd:t,testDir:o,testPatterns:r=[],testListFile:s,testFilePattern:n=et,earlyRunPatterns:a=[]}=e,l=o?R.isAbsolute(o)?o:R.resolve(t,o):t;if(s){let c=R.isAbsolute(s)?s:R.resolve(t,s),p;try{let f=await De.readFile(c,"utf8");p=JSON.parse(f)}catch(f){throw new Error(`Failed to read test list file "${c}": ${f.message}`,{cause:f})}if(!Array.isArray(p))throw new Error(`Test list file "${c}" must contain a JSON array of test file paths`);return console.log(`\u{1F4CB} Loading test list from: ${R.relative(t,c)}`),ue(p,a)}if(r.length===0){let c=await fe(l,t,n);return ue(c,a)}let g=[];for(let c of r){let p=R.isAbsolute(c)?c:R.resolve(t,c),f=null;try{f=await De.stat(p)}catch{}if(f?.isFile())n.test(p)&&g.push(R.relative(t,p));else if(f?.isDirectory())g.push(...await fe(p,t,n));else{let m=(await fe(l,t,n)).filter(h=>h.replace(/\\/g,"/").includes(c.replace(/\\/g,"/")));m.length>0?g.push(...m):console.warn(`\u26A0\uFE0F No matches found for: ${c}`)}}return ue([...new Set(g)],a)}import{spawn as Re}from"child_process";function L(e){return e.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"")}function Y(e){return typeof e=="number"&&Number.isFinite(e)}function X(e,t){return Y(e)?e.toFixed(t):"Unknown"}function H(e,t){if(!Y(t))return e.dim(X(t,2).padStart(6));let o=t.toFixed(2).padStart(6);return t>=80?e.green(o):t>=50?e.yellow(o):e.red(o)}function Ae(e){let t=L(e),o={testFilesPass:0,testFilesFail:0,testsPass:0,testsFail:0,testsSkip:0,duration:0,heapMb:null,errors:[]},r=t.match(/Test Files\s+(.+)/);if(r){let g=r[1],c=g.match(/(\d+)\s+passed/),p=g.match(/(\d+)\s+failed/);c&&(o.testFilesPass=parseInt(c[1],10)),p&&(o.testFilesFail=parseInt(p[1],10))}let s=t.match(/^\s*Tests\s+(.+)$/m);if(s){let g=s[1],c=g.match(/(\d+)\s+passed/),p=g.match(/(\d+)\s+failed/),f=g.match(/(\d+)\s+skipped/);c&&(o.testsPass=parseInt(c[1],10)),p&&(o.testsFail=parseInt(p[1],10)),f&&(o.testsSkip=parseInt(f[1],10))}let n=t.match(/Duration\s+([\d.]+)s/);n&&(o.duration=parseFloat(n[1])*1e3);let a=t.match(/(\d+)\s*MB\s+heap\s+used/i);a&&(o.heapMb=parseInt(a[1],10));let l=e.indexOf("Failed Tests");if(l!==-1){let g=e.indexOf(`
2
+ Test Files`,l),c=g!==-1?e.substring(l,g):e.substring(l),p=/FAIL\s*(?:\x1B\[[0-9;]*[a-zA-Z]|\s)*tests\//g,f=[...c.matchAll(p)];for(let v=0;v<f.length;v++){let m=f[v].index,h=c.lastIndexOf(`
3
+ `,m),w=h===-1?0:h,$=v<f.length-1?f[v+1].index:c.length,d=c.lastIndexOf(`
4
+ `,$),x=d===-1?$:d,y=c.substring(w,x).trim();y&&o.errors.push(y)}}return o}function Ce(e){let o=e.join(`
5
+ `).split(`
6
+ `),r=new Map,s=new Map;o.forEach((a,l)=>{if(a.includes("FAIL")&&a.includes("Config:")){s.set(a,l);let c=L(a).match(/^(.+Config:\s+)'*([^'>]+)'*(.+)$/);if(c){let[,p,f,v]=c,m=`${p.trim()}|||${v.trim()}`;r.has(m)||r.set(m,{lines:[],configs:[]}),r.get(m).lines.push(a),r.get(m).configs.push(f.replace(/'/g,""))}}});let n=new Set;for(let[,a]of r.entries())if(a.configs.length>1){for(let f=1;f<a.lines.length;f++){let v=s.get(a.lines[f]);n.add(v)}let l=a.lines[0],g=`[${a.configs.map(f=>`'${f}'`).join(",")}]`,c=L(l).replace(/(Config:\s+)'*[^'>]+'*/,`$1${g}`),p=s.get(l);o[p]=c}return o.filter((a,l)=>!n.has(l)).join(`
7
+ `)}function ke({maxOldSpaceMb:e,conditions:t=[],base:o=process.env.NODE_OPTIONS??""}){let r=o;for(let s of t){let n=`--conditions=${s}`;r.includes(n)||(r=r?`${r} ${n}`:n)}if(e&&!r.includes("--max-old-space-size")){let s=`--max-old-space-size=${e}`;r=r?`${r} ${s}`:s}return r.trim()}function je({maxOldSpaceMb:e,conditions:t=[],nodeEnv:o="development",extraEnv:r={}}){let s={...process.env};s.NODE_ENV||(s.NODE_ENV=o);let n=ke({maxOldSpaceMb:e,conditions:t,base:s.NODE_OPTIONS??""});return n&&(s.NODE_OPTIONS=n),Object.assign(s,r),s}function tt(e,t){return[e,...t?["--config",t]:[],"run"]}function ge(e,t){let{cwd:o,vitestBin:r,vitestConfig:s,maxOldSpaceMb:n,conditions:a=[],nodeEnv:l="development",vitestArgs:g=[],streamOutput:c=!0,excludePaths:p=[],extraEnv:f={}}=t;return new Promise(v=>{let m=Date.now(),h=p.flatMap(P=>["--exclude",P]),w=[...tt(r,s),...g,...h,e],$=je({maxOldSpaceMb:n,conditions:a,nodeEnv:l,extraEnv:f}),d=Re(process.execPath,w,{cwd:o,stdio:["ignore","pipe","pipe"],env:$}),x="",y="";d.stdout?.on("data",P=>{x+=P.toString(),c&&process.stdout.write(P)}),d.stderr?.on("data",P=>{y+=P.toString(),c&&process.stderr.write(P)}),d.on("close",P=>{let _=Date.now()-m,N=`${x}
8
+ ${y}`,T=Ae(N);v({file:e,code:P??1,duration:T.duration>0?T.duration:_,testFilesPass:T.testFilesPass,testFilesFail:T.testFilesFail,testsPass:T.testsPass,testsFail:T.testsFail,testsSkip:T.testsSkip,heapMb:T.heapMb,errors:T.errors,rawOutput:N})}),d.on("error",P=>{v({file:e,code:1,duration:Date.now()-m,testFilesPass:0,testFilesFail:1,testsPass:0,testsFail:0,testsSkip:0,heapMb:null,errors:[P.message],rawOutput:P.toString()})})})}function yt(e){let{cwd:t,vitestBin:o,vitestConfig:r,maxOldSpaceMb:s,conditions:n=[],nodeEnv:a="development",vitestArgs:l=[]}=e;return new Promise(g=>{let c=[...tt(o,r),...l],p=je({maxOldSpaceMb:s,conditions:n,nodeEnv:a}),f=Re(process.execPath,c,{cwd:t,stdio:"inherit",env:p});f.on("close",v=>g(v??1)),f.on("error",()=>g(1))})}function Ne(e,t){let{cwd:o,vitestBin:r,vitestConfig:s,maxOldSpaceMb:n,conditions:a=[],nodeEnv:l="development",extraCoverageArgs:g=[],quietOutput:c=!1}=t;return new Promise(p=>{let f=s?["--config",s]:[],v=c?["--color"]:[],m=[r,...f,"--mergeReports",e,"--run","--coverage",...v,...g],h=je({maxOldSpaceMb:n,conditions:a,nodeEnv:l}),w=Re(process.execPath,m,{cwd:o,stdio:c?["ignore","pipe","pipe"]:"inherit",env:h}),$="",d="";c&&(w.stdout?.on("data",x=>$+=x.toString()),w.stderr?.on("data",x=>d+=x.toString())),w.on("close",x=>p({exitCode:x??1,output:`${$}
9
+ ${d}`})),w.on("error",()=>p({exitCode:1,output:""}))})}import W from"chalk";function ee(e){let t=Math.max(0,Math.floor(e/1e3)),o=Math.floor(t/3600),r=Math.floor(t%3600/60),s=t%60;return o>0?`${o}:${r.toString().padStart(2,"0")}:${s.toString().padStart(2,"0")}`:`${r}:${s.toString().padStart(2,"0")}`}function Le(e){let t=!!process.stdout.isTTY,o=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],r=26,s=Date.now(),n=0,a=0,l=0,g=0,c=0,p=0,f=null;function v(){let $=e===0?100:n/e*100,d=Date.now()-s,y=(n>0?d/n:0)*Math.max(e-n,0),P=Math.round($/100*r),_=o[g%o.length],N=`[${"=".repeat(P)}${"-".repeat(Math.max(0,r-P))}]`,T=$.toFixed(1).padStart(5);return $<30?T=W.red(T+"%"):$<70?T=W.rgb(255,136,0)(T+"%"):$>99?T=W.green(T+"%"):T=W.yellow(T+"%"),t?`${W.green(_)} ${W.green(N)} ${W.bold(T)} ${n}/${e} | active ${a} | failed ${l} | ETA ${ee(y)} | elapsed ${ee(d)}`:`progress ${$.toFixed(1)}% ${n}/${e} | active ${a} | failed ${l} | eta ${ee(y)} | elapsed ${ee(d)}`}function m($=!1){let d=v();if(g++,t){let y=d.replace(/\x1B\[[0-9;]*[a-zA-Z]/g,"").length;c=Math.max(c,y),process.stdout.write(`\r${d.padEnd(c," ")}`);return}let x=Date.now();($||x-p>=2e3)&&(console.log(d),p=x)}function h(){!t||f||(f=setInterval(()=>{n>=e&&a===0||m()},120),f.unref?.())}function w(){f&&(clearInterval(f),f=null)}return m(!0),h(),{onStart(){a++,m()},onComplete($){a=Math.max(0,a-1),n++,$&&l++,m(!0)},finish(){w(),m(!0),t&&process.stdout.write(`
10
+ `)}}}var _e={onStart(){},onComplete(e){},finish(){}};import ot from"fs/promises";import te from"path";import E from"chalk";function Be(e){if(e.length!==0){console.log(`
11
+ ${"=".repeat(80)}`),console.log(E.bold.red("\u2716 FAILED TEST FILES (VERBOSE OUTPUT)")),console.log("=".repeat(80));for(let t of e)console.log(`
12
+ ${E.red("\u2716")} ${E.red(t.file)} ${E.dim(`(exit ${t.code})`)}`),t.rawOutput?.trim()?console.log(t.rawOutput.trimEnd()):console.log(E.dim("(no child output captured)"));console.log(`
13
+ ${"=".repeat(80)}`)}}function Ve(e,t){if(e===0){let o="% Coverage report from v8",r=t.split(`
14
+ `),s=r.findIndex(n=>L(n).includes(o));if(s>=0){let n=r.length;for(let l=s+1;l<r.length;l++){let g=L(r[l]).trimStart();if(g.startsWith("stderr |")||g.startsWith("stdout |")){n=l;break}}if(r.slice(s+1,n).join(`
15
+ `).trimEnd()){let l=r.slice(s,n).join(`
16
+ `).trimEnd();console.log(`
17
+ ${l}
18
+ `)}}}else{let o=t.trimEnd();o&&console.error(o)}}function Pt(e){let t=(s,n)=>n===0?100:parseFloat((s/n*100).toFixed(2)),o={total:{statements:{total:0,covered:0,pct:0},branches:{total:0,covered:0,pct:0},functions:{total:0,covered:0,pct:0},lines:{total:0,covered:0,pct:0}}};for(let[s,n]of Object.entries(e)){let a=Object.keys(n.s??{}),l=a.length,g=a.filter(d=>n.s[d]>0).length,c=Object.keys(n.f??{}),p=c.length,f=c.filter(d=>n.f[d]>0).length,v=0,m=0;for(let d of Object.values(n.b??{}))v+=d.length,m+=d.filter(x=>x>0).length;let h=new Set,w=new Set;for(let[d,x]of Object.entries(n.statementMap??{})){let y=x?.start?.line;y!=null&&(w.add(y),(n.s??{})[d]>0&&h.add(y))}let $={statements:{total:l,covered:g,pct:t(g,l)},branches:{total:v,covered:m,pct:t(m,v)},functions:{total:p,covered:f,pct:t(f,p)},lines:{total:w.size,covered:h.size,pct:t(h.size,w.size)}};o[s]=$;for(let d of["statements","branches","functions","lines"])o.total[d].total+=$[d].total,o.total[d].covered+=$[d].covered}let r=Object.keys(e).length>0;for(let s of["statements","branches","functions","lines"]){let{total:n,covered:a}=o.total[s];o.total[s].pct=r?t(a,n):"Unknown"}return o}function Ot({lines:e,stmts:t,fns:o,branches:r}){let s=[e,t,o,r].filter(Y);return s.length>0?Math.min(...s):null}function st(e){return e??Number.MAX_VALUE}function Dt({lines:e,stmts:t,fns:o,branches:r}){return![e,t,o,r].every(Y)}function It({lines:e,stmts:t,fns:o,branches:r}){console.log(`
19
+ ${E.bold("Coverage")} ${H(E,e)}% lines ${E.dim("|")} ${H(E,t)}% statements ${E.dim("|")} ${H(E,o)}% functions ${E.dim("|")} ${H(E,r)}% branches`)}async function Ue(e,t,o=10,r={}){let{silent:s=!1}=r,n=te.resolve(e,"coverage"),a=t.find(h=>h.startsWith("--coverage.reportsDirectory="));if(a){let h=a.split("=").slice(1).join("=");n=te.isAbsolute(h)?h:te.resolve(e,h)}let l;try{let h=await ot.readFile(te.join(n,"coverage-summary.json"),"utf8");l=JSON.parse(h)}catch{try{let h=await ot.readFile(te.join(n,"coverage-final.json"),"utf8");l=Pt(JSON.parse(h))}catch{return s||console.log(E.dim(" (no coverage JSON found \u2014 skipping summary)")),null}}let{total:g,...c}=l,p={lines:g.lines?.pct??0,stmts:g.statements?.pct??0,fns:g.functions?.pct??0,branches:g.branches?.pct??0},f=Object.keys(c).length===0&&!Object.values(p).some(Y),v=[],m=0;if(o>0){let h=Object.entries(c).map(([$,d])=>({file:te.relative(e,$),lines:d.lines?.pct??0,stmts:d.statements?.pct??0,fns:d.functions?.pct??0,branches:d.branches?.pct??0})).map($=>({row:$,worst:Ot($)})).filter(({row:$,worst:d})=>Dt($)||d<100).sort(($,d)=>st($.worst)-st(d.worst)),w=h.slice(0,o);s||(console.log(`
20
+ `+E.bold("\u{1F4C9} WORST COVERAGE FILES (lowest metric)")),console.log("-".repeat(80)),w.forEach(({row:{file:$,lines:d,stmts:x,fns:y,branches:P},worst:_})=>{let N=E.dim(`lines ${X(d,0)}% | stmts ${X(x,0)}% | fns ${X(y,0)}% | branches ${X(P,0)}%`);console.log(` ${H(E,_)}% ${E.dim($)} ${N}`)}),h.length>o&&console.log(E.dim(` ... and ${h.length-o} more files`))),v=w.map(({row:$})=>$),m=h.length}return s||(It(p),f&&console.log(E.dim(" No files were measured (the coverage include matched nothing), so every percentage is Unknown and coverage thresholds are skipped."))),{coverageDir:n,total:g,noFilesMeasured:f,worstFiles:v,worstFilesShown:v.length,worstFilesTotal:m,summary:l}}import ae from"fs/promises";import nt from"fs";import oe from"path";var rt="tmp/vitest-runner",At=/^(\d+)-\d+$/;function Ct(e){try{return process.kill(e,0),!0}catch(t){return t.code!=="ESRCH"}}function kt(e){return String(e).replace(/[^a-zA-Z0-9_-]+/g,"-").slice(0,80)||"scratch"}async function it(e,t){let o=oe.resolve(e,t),r;try{r=await ae.readdir(o,{withFileTypes:!0})}catch{return}for(let s of r){if(!s.isDirectory())continue;let n=s.name.match(At);if(!n)continue;let a=parseInt(n[1],10);Ct(a)||await ae.rm(oe.join(o,s.name),{recursive:!0,force:!0}).catch(()=>{})}}async function ct(e,t){let o=oe.resolve(e,t),r=oe.join(o,`${process.pid}-${Date.now()}`);return await ae.mkdir(r,{recursive:!0}),r}async function ze(e,t){let o=oe.join(e,`worker-${t}`);return await ae.mkdir(o,{recursive:!0}),o}async function at(e){await ae.rm(e,{recursive:!0,force:!0}).catch(()=>{})}function lt(e){try{nt.rmSync(e,{recursive:!0,force:!0})}catch{}}function Rt(e){let t=process.env.VITEST_RUNNER_TMP;if(!t)throw new Error("makeRunTmpDir() requires VITEST_RUNNER_TMP to be set \u2014 call it from a test file run by vitest-runner.");return nt.mkdtempSync(oe.join(t,`${kt(e)}-`))}function pt(e,t,o){let r=e.replace(/\\/g,"/"),s;for(let{pattern:n,heapMb:a}of o)if(r.includes(n)){s=a;break}if(!(s===void 0&&t===void 0))return s===void 0?t:t===void 0?s:Math.max(s,t)}async function To(e){let t=e.cwd??process.cwd(),o=e.scratchDir??rt,r=e.keepTmp??!1;await it(t,o);let s=await ct(t,o),n=()=>{lt(s),process.exitCode=130,process.exit()};r||(process.once("SIGINT",n),process.once("SIGTERM",n));try{return await jt(e,s)}finally{process.removeListener("SIGINT",n),process.removeListener("SIGTERM",n),r||await at(s)}}async function jt(e,t){let{cwd:o=process.cwd(),testDir:r,testPatterns:s=[],testListFile:n,testFilePattern:a,vitestArgs:l=[],showErrorDetails:g=!0,coverageQuiet:c=!1,suppressFileOutput:p=!1,suppressPassingFiles:f=!1,topSummary:v=!0,json:m=!1,workers:h=parseInt(process.env.VITEST_WORKERS??"4",10),worstCoverageCount:w=10,blobsDir:$,mergeReports:d=!0,earlyRunPatterns:x=[],perFileHeapOverrides:y=[],conditions:P=[],nodeEnv:_="development",_testResultsOverride:N=null}=e,T=0,B=e.maxOldSpaceMb??(process.env.VITEST_HEAP_MB?parseInt(process.env.VITEST_HEAP_MB,10):void 0),O=!m,ft=Pe(o,"vitest","vitest"),ut=await Oe(o,e.vitestConfig),he={cwd:o,vitestBin:ft,vitestConfig:ut,conditions:P,nodeEnv:_},A=[...l];if(c&&!A.some(i=>i==="--coverage"||i.startsWith("--coverage."))&&A.unshift("--coverage"),A.some(i=>i==="--coverage"||i.startsWith("--coverage."))){let i=me.resolve(o,$??".vitest-coverage-blobs"),u=me.resolve(o,".vitest-coverage-tmp");await Promise.all([K.rm(i,{recursive:!0,force:!0}),K.rm(u,{recursive:!0,force:!0})]),await Promise.all([K.mkdir(i,{recursive:!0}),K.mkdir(u,{recursive:!0})]);let b=await de({cwd:o,testDir:r,testPatterns:s,testListFile:n,testFilePattern:a,earlyRunPatterns:x}),D=Ie(b);if(b.length===0){let F=s.length>0?`\u274C No Vitest test files found matching: ${s.join(", ")}`:"\u274C No Vitest test files found";return O&&console.log(F),m?{exitCode:1,mode:"coverage",message:F,options:{cwd:o,testDir:r,testPatterns:s,testListFile:n,workers:h,coverageQuiet:c,suppressFileOutput:p,suppressPassingFiles:f,topSummary:v,vitestArgs:A}}:1}let k=A.filter(F=>F!=="--coverage"&&F.startsWith("--coverage.")),Fe=A.filter(F=>F!=="--coverage"&&!F.startsWith("--coverage.")),ie=b.filter(F=>x.some(M=>F.replace(/\\/g,"/").includes(M))),be=b.filter(F=>!x.some(M=>F.replace(/\\/g,"/").includes(M))),xe=c||p||m,St=c&&!m;!c&&!p&&O&&(console.log(`
21
+ \u{1F9EA} Running ${b.length} test files for coverage (blob + merge mode)`),console.log(`\u2699\uFE0F Workers: ${h} (${ie.length} solo first, then parallel)`),B&&console.log(`\u{1F9E0} Heap limit: ${B} MB`),console.log(""));let we=St?Le(b.length):_e,j=[],Te=0,Qe=async F=>{let M=me.join(i,`run-${Te}.blob`);Te++,!xe&&O&&(console.log(`
22
+ ${"=".repeat(80)}`),console.log(`\u25B6\uFE0F ${F}`),console.log("=".repeat(80))),we.onStart();let U=me.join(u,`run-${Te}`),Ft=[...Fe,"--coverage",`--coverage.reportsDirectory=${U}`,"--reporter=default","--reporter=blob",`--outputFile=${M}`],bt=await ze(t,T++),z=await ge(F,{...he,maxOldSpaceMb:pt(F,B,y),vitestArgs:Ft,streamOutput:!xe,excludePaths:D.get(F),extraEnv:{VITEST_RUNNER_TMP:bt}});if(j.push(z),we.onComplete(z.code!==0),!xe&&O){let Xe=(z.duration/1e3).toFixed(2);if(z.code===0){let xt=z.heapMb?` | ${z.heapMb} MB heap`:"";console.log(`
23
+ \u2705 PASSED (${Xe}s${xt})
24
+ `)}else console.log(`
25
+ \u274C FAILED (exit code ${z.code}, ${Xe}s)
26
+ `)}};for(let F of ie)await Qe(F).catch(M=>{O&&console.error(`Error running ${F}:`,M)});let Me=0,Q=new Set;for(;Me<be.length||Q.size>0;){for(;Me<be.length&&Q.size<h;){let F=be[Me++],M=Qe(F).catch(U=>{O&&console.error(`Error running ${F}:`,U)}).finally(()=>Q.delete(M));Q.add(M)}Q.size>0&&await Promise.race(Q)}we.finish();let Ee=(await K.readdir(i).catch(()=>[])).filter(F=>F.endsWith(".blob"));if(Ee.length===0){let F="\u274C No coverage blobs were generated \u2014 coverage report cannot be produced";return O&&console.error(F),m?{exitCode:1,mode:"coverage",message:F,options:{cwd:o,testDir:r,testPatterns:s,testListFile:n,workers:h,coverageQuiet:c,suppressFileOutput:p,suppressPassingFiles:f,topSummary:v,showErrorDetails:g,worstCoverageCount:w,vitestArgs:A},totals:{testFiles:b.length,failedFiles:j.filter(M=>M.code!==0).length,passedFiles:j.filter(M=>M.code===0).length},results:{all:j,failed:j.filter(M=>M.code!==0)},merge:{blobFiles:0,exitCode:1,output:""},coverageSummary:null}:1}let pe=0,ye="",Ze=null;d&&(!c&&!p&&O&&(console.log(`
27
+ ${"=".repeat(80)}`),console.log(`\u{1F4CA} Merging ${Ee.length} coverage blobs into final report...`),console.log("=".repeat(80))),{exitCode:pe,output:ye}=await Ne(i,{...he,maxOldSpaceMb:B,extraCoverageArgs:k,quietOutput:c||m}),c&&O&&Ve(pe,ye),Ze=await Ue(o,k,w,{silent:m})),await Promise.all([...d?[K.rm(i,{recursive:!0,force:!0}).catch(()=>{})]:[],K.rm(u,{recursive:!0,force:!0}).catch(()=>{})]);let ce=j.filter(F=>F.code!==0);c&&O&&Be(ce);let Ye=ce.length>0?1:pe;if(m){let F=j.filter(M=>M.heapMb!==null);return{exitCode:Ye,mode:"coverage",options:{cwd:o,testDir:r,testPatterns:s,testListFile:n,workers:h,coverageQuiet:c,suppressFileOutput:p,suppressPassingFiles:f,topSummary:v,showErrorDetails:g,worstCoverageCount:w,vitestArgs:A},totals:{testFiles:b.length,failedFiles:ce.length,passedFiles:j.length-ce.length},results:{all:j,failed:ce},merge:{blobFiles:Ee.length,exitCode:pe,output:ye},coverageSummary:Ze,...v?{topMemoryUsers:[...F].sort((M,U)=>U.heapMb-M.heapMb).slice(0,10),topDuration:[...j].sort((M,U)=>U.duration-M.duration).slice(0,10)}:{}}}return Ye}let q=await de({cwd:o,testDir:r,testPatterns:s,testListFile:n,testFilePattern:a,earlyRunPatterns:x}),dt=Ie(q);if(q.length===0){let i=s.length>0?`\u274C No Vitest test files found matching: ${s.join(", ")}`:"\u274C No Vitest test files found";return O&&console.log(i),m?{exitCode:1,mode:"standard",message:i,options:{cwd:o,testDir:r,testPatterns:s,testListFile:n,workers:h,coverageQuiet:c,suppressFileOutput:p,suppressPassingFiles:f,topSummary:v,vitestArgs:A}}:1}let He=q.filter(i=>x.some(u=>i.replace(/\\/g,"/").includes(u))),ve=q.filter(i=>!x.some(u=>i.replace(/\\/g,"/").includes(u))),gt=Date.now(),We=new Date().toLocaleTimeString("en-US",{hour12:!1});O&&!p&&s.length>0?console.log(`
28
+ \u{1F9EA} Running ${q.length} test files matching: ${s.join(", ")}`):O&&!p&&console.log(`
29
+ \u{1F9EA} Running ${q.length} test files (${He.length} solo first, then parallel)`),O&&!p&&(console.log(`\u2699\uFE0F Workers: ${h}`),B&&console.log(`\u{1F9E0} Heap limit: ${B} MB`),A.length>0&&console.log(`\u{1F527} Vitest args: ${A.join(" ")}`),console.log(""));let I=[...N??[]],Ke=async i=>{!p&&O&&(console.log(`
30
+ ${"=".repeat(80)}`),console.log(`\u25B6\uFE0F ${i}`),console.log("=".repeat(80)));let u=await ze(t,T++),b=await ge(i,{...he,maxOldSpaceMb:pt(i,B,y),vitestArgs:A,streamOutput:!p&&!m,excludePaths:dt.get(i),extraEnv:{VITEST_RUNNER_TMP:u}});if(!p&&O){let D=(b.duration/1e3).toFixed(2);if(b.code===0){let k=b.heapMb?` | ${b.heapMb} MB heap`:"";console.log(`
31
+ \u2705 PASSED (${D}s${k})
32
+ `)}else console.log(`
33
+ \u274C FAILED (exit code ${b.code}, ${D}s)
34
+ `)}return b};if(!N){for(let b of He){let D=await Ke(b).catch(k=>(O&&console.error(`Error running ${b}:`,k),null));D&&I.push(D)}let i=0,u=new Set;for(;i<ve.length||u.size>0;){for(;i<ve.length&&u.size<h;){let b=ve[i++],D=Ke(b).then(k=>I.push(k)).catch(k=>{O&&console.error(`Error running ${b}:`,k)}).finally(()=>u.delete(D));u.add(D)}u.size>0&&await Promise.race(u)}}let G=I.reduce((i,u)=>i+u.testFilesPass,0),V=I.reduce((i,u)=>i+u.testFilesFail,0),se=I.reduce((i,u)=>i+u.testsPass,0),ne=I.reduce((i,u)=>i+u.testsFail,0),re=I.reduce((i,u)=>i+(u.testsSkip||0),0),mt=I.reduce((i,u)=>i+u.duration,0),J=I.filter(i=>i.code!==0),le=I.filter(i=>i.code===0),ht=J.length>0?1:0,qe=process.memoryUsage(),$e=Math.round(qe.heapUsed/1024/1024),Se=Math.round(qe.rss/1024/1024),C=I.filter(i=>i.heapMb!==null),Ge=((Date.now()-gt)/1e3).toFixed(2),Je=(mt/1e3).toFixed(2);if(m)return{exitCode:ht,mode:"standard",options:{cwd:o,testDir:r,testPatterns:s,testListFile:n,workers:h,coverageQuiet:c,suppressFileOutput:p,suppressPassingFiles:f,topSummary:v,showErrorDetails:g,worstCoverageCount:w,vitestArgs:A},totals:{testFilesPass:G,testFilesFail:V,testsPass:se,testsFail:ne,testsSkip:re,totalTests:se+ne+re},timing:{startAt:We,wallClockSeconds:Number(Ge),testsSeconds:Number(Je)},heap:{scriptHeapMb:$e,scriptRssMb:Se,maxHeapMb:C.length>0?Math.max(...C.map(i=>i.heapMb)):null,avgHeapMb:C.length>0?Number((C.reduce((i,u)=>i+u.heapMb,0)/C.length).toFixed(0)):null},results:{all:I,passed:le,failed:J},...v?{topMemoryUsers:[...C].sort((i,u)=>u.heapMb-i.heapMb).slice(0,10),topDuration:[...I].sort((i,u)=>u.duration-i.duration).slice(0,10)}:{}};console.log(`
35
+ `+"=".repeat(80)),v&&C.length>0&&(console.log(`
36
+ `+S.bold("\u{1F9E0} TOP MEMORY USERS")),console.log("-".repeat(80)),[...C].sort((i,u)=>u.heapMb-i.heapMb).slice(0,10).forEach(i=>{console.log(` ${String(i.heapMb).padStart(4)} MB ${S.dim(i.file)}`)})),v&&I.length>0&&(console.log(`
37
+ `+S.bold("\u23F1\uFE0F TOP DURATION")),console.log("-".repeat(80)),[...I].sort((i,u)=>u.duration-i.duration).slice(0,10).forEach(i=>{let u=(i.duration/1e3).toFixed(2);console.log(` ${(u+"s").padStart(8)} ${S.dim(i.file)}`)})),le.length>0&&!f&&(console.log(`
38
+ `+"=".repeat(80)),console.log(S.bold.green("\u2713 PASSED TEST FILES")),console.log("=".repeat(80)),le.forEach(i=>{let u=(i.duration/1e3).toFixed(2),b=[...i.heapMb?[`${i.heapMb} MB`]:[],`${u}s`],D=i.testsPass>0?` - ${i.testsPass} tests`:"";console.log(S.green(`\u2713 ${i.file}${D}`)+S.dim(` (${b.join(", ")})`))})),console.log(`
39
+ `+S.bold("=".repeat(80))),J.length>0&&(console.log(`
40
+ \u274C ${J.length} test file(s) failed`),console.log(S.bold.red(`
41
+ Failed Test Files:`)),J.forEach(i=>{let u=(i.duration/1e3).toFixed(2),b=[...i.testsFail>0?[S.red(`${i.testsFail} failed`)]:[],...i.testsPass>0?[S.green(`${i.testsPass} passed`)]:[],...i.testsSkip>0?[S.yellow(`${i.testsSkip} skipped`)]:[]],D=[...i.heapMb?[`${i.heapMb} MB`]:[],`${u}s`],k=b.length>0?` (${b.join(", ")})`:"";if(console.log(` ${S.red("\u2716")} ${i.file}${k}`+S.dim(` [${D.join(", ")}]`)),g&&i.errors.length>0){let Fe=Ce(i.errors).split(`
42
+ `).map(ie=>ie.trim()?` ${ie}`:"").join(`
43
+ `);console.log(Fe),console.log("")}}),console.log("")),console.log(S.bold("=".repeat(80))),V>0&&G>0?console.log(` ${S.bold("Test Files")} ${S.red(`${V} failed`)} ${S.dim("|")} ${S.green(`${G} passed`)} ${S.dim(`(${G+V})`)}`):V>0?console.log(` ${S.bold("Test Files")} ${S.red(`${V} failed`)} ${S.dim(`(${V})`)}`):console.log(` ${S.bold("Test Files")} ${S.green(`${G} passed`)} ${S.dim(`(${G})`)}`);let vt=se+ne+re,$t=[...ne>0?[S.red(`${ne} failed`)]:[],...se>0?[S.green(`${se} passed`)]:[],...re>0?[S.yellow(`${re} skipped`)]:[]];if(console.log(` ${S.bold("Tests")} ${$t.join(` ${S.dim("|")} `)} ${S.dim(`(${vt})`)}`),console.log(` ${S.bold("Start at")} ${We}`),console.log(` ${S.bold("Duration")} ${Ge}s ${S.dim(`(tests ${Je}s)`)}`),C.length>0){let i=Math.max(...C.map(b=>b.heapMb)),u=(C.reduce((b,D)=>b+D.heapMb,0)/C.length).toFixed(0);console.log(` ${S.bold("Heap")} max ${i} MB | avg ${u} MB | script ${$e} MB (RSS ${Se} MB)`)}else console.log(` ${S.bold("Heap")} script ${$e} MB (RSS ${Se} MB)`);return J.length>0?1:(console.log(`
44
+ \u2705 All ${le.length} test files passed
45
+ `),0)}export{ke as buildNodeOptions,H as colourPct,Le as createCoverageProgressTracker,Ce as deduplicateErrors,fe as discoverFilesInDir,de as discoverVitestFiles,ee as formatDuration,Rt as makeRunTmpDir,_e as noopProgressTracker,Ae as parseVitestOutput,Ue as printCoverageSummary,Ve as printMergeOutput,Be as printQuietCoverageFailureDetails,Pe as resolveBin,Oe as resolveVitestConfig,To as run,Ne as runMergeReports,ge as runSingleFile,yt as runVitestDirect,ue as sortWithPriority,L as stripAnsi};
1335
46
  //# sourceMappingURL=index.mjs.map