headlamp 0.1.9 → 0.1.11

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/cli.cjs CHANGED
@@ -93,7 +93,7 @@ var init_TimeoutError = __esm({
93
93
 
94
94
  // node_modules/es-toolkit/dist/promise/delay.mjs
95
95
  function delay(ms, { signal } = {}) {
96
- return new Promise((resolve9, reject) => {
96
+ return new Promise((resolve10, reject) => {
97
97
  const abortError = () => {
98
98
  reject(new AbortError());
99
99
  };
@@ -106,7 +106,7 @@ function delay(ms, { signal } = {}) {
106
106
  }
107
107
  const timeoutId = setTimeout(() => {
108
108
  signal?.removeEventListener("abort", abortHandler);
109
- resolve9();
109
+ resolve10();
110
110
  }, ms);
111
111
  signal?.addEventListener("abort", abortHandler, { once: true });
112
112
  });
@@ -171,11 +171,11 @@ var init_exec = __esm({
171
171
  child.stderr?.on("data", (chunk) => {
172
172
  stderr += String(chunk);
173
173
  });
174
- const exec = new Promise((resolve9, reject) => {
174
+ const exec = new Promise((resolve10, reject) => {
175
175
  child.on("error", reject);
176
176
  child.on(
177
177
  "close",
178
- (code) => Number(code) === 0 ? resolve9(stdout) : reject(new Error(stderr || `exit ${code}`))
178
+ (code) => Number(code) === 0 ? resolve10(stdout) : reject(new Error(stderr || `exit ${code}`))
179
179
  );
180
180
  });
181
181
  try {
@@ -195,7 +195,7 @@ var init_exec = __esm({
195
195
  throw caughtError;
196
196
  }
197
197
  };
198
- runExitCode = async (cmd, args, opts = {}) => new Promise((resolve9, reject) => {
198
+ runExitCode = async (cmd, args, opts = {}) => new Promise((resolve10, reject) => {
199
199
  const child = (0, import_node_child_process.spawn)(cmd, [...args], {
200
200
  cwd: opts.cwd,
201
201
  env: opts.env,
@@ -204,9 +204,9 @@ var init_exec = __esm({
204
204
  windowsHide: true
205
205
  });
206
206
  child.on("error", reject);
207
- child.on("close", (code) => resolve9(Number(code)));
207
+ child.on("close", (code) => resolve10(Number(code)));
208
208
  });
209
- runWithCapture = async (cmd, args, opts) => new Promise((resolve9, reject) => {
209
+ runWithCapture = async (cmd, args, opts) => new Promise((resolve10, reject) => {
210
210
  const child = (0, import_node_child_process.spawn)(cmd, [...args], {
211
211
  cwd: opts.cwd,
212
212
  env: opts.env,
@@ -222,7 +222,7 @@ var init_exec = __esm({
222
222
  buf += String(chunk);
223
223
  });
224
224
  child.on("error", reject);
225
- child.on("close", (code) => resolve9({ code: Number(code), output: buf }));
225
+ child.on("close", (code) => resolve10({ code: Number(code), output: buf }));
226
226
  });
227
227
  }
228
228
  });
@@ -272,7 +272,7 @@ var init_args = __esm({
272
272
  isSome = (opt) => opt._tag === "some";
273
273
  step = (actions, skipNext = false) => [actions, skipNext];
274
274
  rule = {
275
- when: (predicate, build) => (value, env2) => predicate(value, env2) ? Some(build(value, env2)) : None,
275
+ when: (predicate, build) => (value, env) => predicate(value, env) ? Some(build(value, env)) : None,
276
276
  eq: (flag, build) => rule.when(
277
277
  (value) => value === flag,
278
278
  () => build()
@@ -282,12 +282,12 @@ var init_args = __esm({
282
282
  (value) => build(value)
283
283
  ),
284
284
  inSet: (select, build) => rule.when(
285
- (value, env2) => select(env2).has(value),
285
+ (value, env) => select(env).has(value),
286
286
  (value) => build(value)
287
287
  ),
288
288
  withLookahead: (lookaheadFlag, build) => rule.when(
289
- (value, env2) => value === lookaheadFlag && typeof env2.lookahead === "string" && env2.lookahead.length > 0,
290
- (value, env2) => build(value, env2.lookahead)
289
+ (value, env) => value === lookaheadFlag && typeof env.lookahead === "string" && env.lookahead.length > 0,
290
+ (value, env) => build(value, env.lookahead)
291
291
  )
292
292
  };
293
293
  STRING_EMPTY = "";
@@ -420,7 +420,7 @@ var init_args = __esm({
420
420
  ),
421
421
  rule.startsWith("--testPathPattern=", (value) => step([ActionBuilders.jestArg(value)])),
422
422
  rule.inSet(
423
- (env2) => env2.jestFlags,
423
+ (env) => env.jestFlags,
424
424
  (value) => step([ActionBuilders.jestArg(value)])
425
425
  ),
426
426
  rule.when(
@@ -478,12 +478,12 @@ var init_args = __esm({
478
478
  rule.eq("--changed", () => step([ActionBuilders.changed("all")])),
479
479
  rule.startsWith("--changed=", (value) => {
480
480
  const raw = (value.split("=")[1] ?? "").trim().toLowerCase();
481
- const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
481
+ const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : raw === "branch" ? "branch" : "all";
482
482
  return step([ActionBuilders.changed(mode)]);
483
483
  }),
484
484
  rule.withLookahead("--changed", (_flag, lookahead) => {
485
485
  const raw = String(lookahead).trim().toLowerCase();
486
- const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : "all";
486
+ const mode = raw === "staged" ? "staged" : raw === "unstaged" ? "unstaged" : raw === "branch" ? "branch" : "all";
487
487
  return step([ActionBuilders.changed(mode)], true);
488
488
  }),
489
489
  rule.withLookahead(
@@ -516,9 +516,9 @@ var init_args = __esm({
516
516
  }
517
517
  const tokenValue = token ?? STRING_EMPTY;
518
518
  const nextToken = tokens[index + INDEX_STEP];
519
- let env2 = { jestFlags: jestOnlyFlags };
519
+ let env = { jestFlags: jestOnlyFlags };
520
520
  if (typeof nextToken === "string" && nextToken.length > 0) {
521
- env2 = { jestFlags: jestOnlyFlags, lookahead: nextToken };
521
+ env = { jestFlags: jestOnlyFlags, lookahead: nextToken };
522
522
  }
523
523
  const firstMatch = (rs, value, envForRules) => {
524
524
  for (const ruleFn of rs) {
@@ -529,7 +529,7 @@ var init_args = __esm({
529
529
  }
530
530
  return None;
531
531
  };
532
- const matched = firstMatch(rules, tokenValue, env2);
532
+ const matched = firstMatch(rules, tokenValue, env);
533
533
  const isTestFileToken = (candidate) => /\.(test|spec)\.[tj]sx?$/.test(candidate) || /(^|\/)tests?\//.test(candidate);
534
534
  const isPathLike = (candidate) => /[\\/]/.test(candidate) || /\.(m?[tj]sx?)$/i.test(candidate);
535
535
  const [matchedActions, shouldSkipNext] = isSome(matched) ? matched.value : (() => {
@@ -1987,19 +1987,19 @@ var require_lib = __commonJS({
1987
1987
  "node_modules/json5/lib/index.js"(exports2, module2) {
1988
1988
  var parse = require_parse();
1989
1989
  var stringify = require_stringify();
1990
- var JSON52 = {
1990
+ var JSON53 = {
1991
1991
  parse,
1992
1992
  stringify
1993
1993
  };
1994
- module2.exports = JSON52;
1994
+ module2.exports = JSON53;
1995
1995
  }
1996
1996
  });
1997
1997
 
1998
1998
  // src/lib/program.ts
1999
- var path10 = __toESM(require("node:path"), 1);
1999
+ var path11 = __toESM(require("node:path"), 1);
2000
2000
  var os2 = __toESM(require("node:os"), 1);
2001
2001
  var fsSync3 = __toESM(require("node:fs"), 1);
2002
- var fs5 = __toESM(require("node:fs/promises"), 1);
2002
+ var fs7 = __toESM(require("node:fs/promises"), 1);
2003
2003
  var LibReport = __toESM(require("istanbul-lib-report"), 1);
2004
2004
  var Reports = __toESM(require("istanbul-reports"), 1);
2005
2005
  var import_istanbul_lib_coverage2 = require("istanbul-lib-coverage");
@@ -3370,7 +3370,7 @@ var printCompactCoverage = async (opts) => {
3370
3370
  );
3371
3371
  }
3372
3372
  };
3373
- var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
3373
+ var shortenPathPreservingFilename = (relPath2, maxWidth, opts) => {
3374
3374
  const ellipsis = opts?.ellipsis ?? "\u2026";
3375
3375
  const START_HEAD = Math.max(0, opts?.keepHead ?? 1);
3376
3376
  const START_TAIL = Math.max(0, opts?.keepTail ?? 1);
@@ -3542,7 +3542,7 @@ var shortenPathPreservingFilename = (relPath, maxWidth, opts) => {
3542
3542
  }
3543
3543
  return null;
3544
3544
  };
3545
- const normalized = relPath.replace(/\\/g, "/");
3545
+ const normalized = relPath2.replace(/\\/g, "/");
3546
3546
  if (visibleWidth(normalized) <= maxWidth) {
3547
3547
  return normalized;
3548
3548
  }
@@ -3998,11 +3998,343 @@ var printPerFileCompositeTables = async (opts) => {
3998
3998
  }
3999
3999
  };
4000
4000
 
4001
- // src/lib/jest-bridge.ts
4002
- var path9 = __toESM(require("node:path"), 1);
4003
- var fs4 = __toESM(require("node:fs"), 1);
4004
- var util = __toESM(require("node:util"), 1);
4005
- var import_json5 = __toESM(require_lib(), 1);
4001
+ // src/lib/jest-reporter-source.ts
4002
+ var JEST_BRIDGE_REPORTER_SOURCE = `const fs = require('fs');
4003
+ const path = require('path');
4004
+
4005
+ const isObject = (v) => typeof v === 'object' && v !== null;
4006
+ const sanitizeError = (err) => {
4007
+ if (!isObject(err)) return err;
4008
+ const out = {};
4009
+ const name = err.name || (err.constructor && err.constructor.name) || undefined;
4010
+ if (name) out.name = String(name);
4011
+ if (typeof err.message === 'string') out.message = err.message;
4012
+ if (typeof err.stack === 'string') out.stack = err.stack;
4013
+ if (err.code !== undefined) out.code = err.code;
4014
+ if (err.expected !== undefined) out.expected = err.expected;
4015
+ if (err.received !== undefined) out.received = err.received;
4016
+ if (err.matcherResult && isObject(err.matcherResult)) {
4017
+ const mr = err.matcherResult;
4018
+ let messageText;
4019
+ try {
4020
+ messageText = typeof mr.message === 'function' ? String(mr.message()) : (typeof mr.message === 'string' ? mr.message : undefined);
4021
+ } catch {}
4022
+ out.matcherResult = {
4023
+ matcherName: typeof mr.matcherName === 'string' ? mr.matcherName : undefined,
4024
+ message: messageText,
4025
+ stack: typeof mr.stack === 'string' ? mr.stack : undefined,
4026
+ expected: mr.expected,
4027
+ received: mr.received,
4028
+ actual: mr.actual,
4029
+ pass: typeof mr.pass === 'boolean' ? mr.pass : undefined,
4030
+ };
4031
+ }
4032
+ if (err.cause) {
4033
+ out.cause = sanitizeError(err.cause);
4034
+ }
4035
+ // Copy own enumerable props to preserve custom data
4036
+ try {
4037
+ for (const key of Object.keys(err)) {
4038
+ if (!(key in out)) out[key] = err[key];
4039
+ }
4040
+ } catch {}
4041
+ return out;
4042
+ };
4043
+ const sanitizeDetail = (d) => {
4044
+ if (typeof d === 'string') return d;
4045
+ if (!isObject(d)) return d;
4046
+ // Common Jest detail shapes
4047
+ const out = {};
4048
+ if (d.message) out.message = d.message;
4049
+ if (d.stack) out.stack = d.stack;
4050
+ if (d.error) out.error = sanitizeError(d.error);
4051
+ if (d.matcherResult) out.matcherResult = sanitizeError({ matcherResult: d.matcherResult }).matcherResult;
4052
+ if (d.expected !== undefined) out.expected = d.expected;
4053
+ if (d.received !== undefined) out.received = d.received;
4054
+ // Copy the rest
4055
+ try {
4056
+ for (const key of Object.keys(d)) {
4057
+ if (!(key in out)) out[key] = d[key];
4058
+ }
4059
+ } catch {}
4060
+ return out;
4061
+ };
4062
+
4063
+ class BridgeReporter {
4064
+ constructor(globalConfig, options) {
4065
+ this.out = process.env.JEST_BRIDGE_OUT || (options && options.outFile) || path.join(process.cwd(), 'coverage', 'jest-run.json');
4066
+ this.buf = { startTime: Date.now(), testResults: [], aggregated: null };
4067
+ }
4068
+ onRunStart() { this.buf.startTime = Date.now(); }
4069
+ onTestResult(_test, tr) {
4070
+ const mapAssertion = (a) => ({
4071
+ title: a.title,
4072
+ fullName: a.fullName || [...(a.ancestorTitles || []), a.title].join(' '),
4073
+ status: a.status,
4074
+ duration: a.duration || 0,
4075
+ location: a.location || null,
4076
+ failureMessages: (a.failureMessages || []).map(String),
4077
+ failureDetails: (a.failureDetails || []).map(sanitizeDetail),
4078
+ });
4079
+ this.buf.testResults.push({
4080
+ testFilePath: tr.testFilePath,
4081
+ status: tr.numFailingTests ? 'failed' : 'passed',
4082
+ failureMessage: tr.failureMessage || '',
4083
+ failureDetails: (tr.failureDetails || []).map(sanitizeDetail),
4084
+ testExecError: tr.testExecError ? sanitizeError(tr.testExecError) : null,
4085
+ console: tr.console || null,
4086
+ perfStats: tr.perfStats || {},
4087
+ testResults: (tr.testResults || []).map(mapAssertion),
4088
+ });
4089
+ }
4090
+ onRunComplete(_contexts, agg) {
4091
+ this.buf.aggregated = {
4092
+ numTotalTestSuites: agg.numTotalTestSuites,
4093
+ numPassedTestSuites: agg.numPassedTestSuites,
4094
+ numFailedTestSuites: agg.numFailedTestSuites,
4095
+ numTotalTests: agg.numTotalTests,
4096
+ numPassedTests: agg.numPassedTests,
4097
+ numFailedTests: agg.numFailedTests,
4098
+ numPendingTests: agg.numPendingTests,
4099
+ numTodoTests: agg.numTodoTests,
4100
+ startTime: agg.startTime,
4101
+ success: agg.success,
4102
+ runTimeMs: agg.testResults.reduce((t, r) => t + Math.max(0, (r.perfStats?.end || 0) - (r.perfStats?.start || 0)), 0),
4103
+ };
4104
+ fs.mkdirSync(path.dirname(this.out), { recursive: true });
4105
+ fs.writeFileSync(this.out, JSON.stringify(this.buf), 'utf8');
4106
+ }
4107
+ }
4108
+ module.exports = BridgeReporter;`;
4109
+
4110
+ // src/lib/jest-environment-source.ts
4111
+ var JEST_BRIDGE_ENV_SOURCE = `
4112
+ 'use strict';
4113
+
4114
+ const NodeEnvironment = require('jest-environment-node').TestEnvironment || require('jest-environment-node');
4115
+
4116
+ module.exports = class BridgeEnv extends NodeEnvironment {
4117
+ constructor(config, context) {
4118
+ super(config, context);
4119
+ const { AsyncLocalStorage } = require('node:async_hooks');
4120
+ this._als = new AsyncLocalStorage();
4121
+ this._cleanup = [];
4122
+ }
4123
+
4124
+ _ctx() {
4125
+ try { const s = this._als.getStore(); if (s) return s; } catch {}
4126
+ try {
4127
+ const st = this.global.expect && typeof this.global.expect.getState === 'function' ? this.global.expect.getState() : {};
4128
+ return { testPath: st.testPath, currentTestName: st.currentTestName };
4129
+ } catch { return {}; }
4130
+ }
4131
+
4132
+ async setup() {
4133
+ await super.setup();
4134
+
4135
+ try { Error.stackTraceLimit = Math.max(Error.stackTraceLimit || 10, 50); } catch {}
4136
+
4137
+ const print = (payload) => { try { this.global.console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {} };
4138
+ const toErr = (x) => { try { return x instanceof Error ? x : new Error(String(x)); } catch { return new Error('unknown'); } };
4139
+
4140
+ const onRej = (reason) => {
4141
+ const e = toErr(reason);
4142
+ const c = this._ctx();
4143
+ print({ type: 'unhandledRejection', name: e.name, message: e.message, stack: e.stack, code: e.code ?? undefined, ...c });
4144
+ };
4145
+ const onExc = (error) => {
4146
+ const e = toErr(error);
4147
+ const c = this._ctx();
4148
+ print({ type: 'uncaughtException', name: e.name, message: e.message, stack: e.stack, code: e.code ?? undefined, ...c });
4149
+ };
4150
+
4151
+ this.global.process.on('unhandledRejection', onRej);
4152
+ this.global.process.on('uncaughtException', onExc);
4153
+ this._cleanup.push(() => {
4154
+ this.global.process.off('unhandledRejection', onRej);
4155
+ this.global.process.off('uncaughtException', onExc);
4156
+ });
4157
+
4158
+ // Signal environment readiness so we can confirm the custom env loaded
4159
+ try { const c = this._ctx(); print({ type: 'envReady', ...c }); } catch {}
4160
+
4161
+ try {
4162
+ const http = this.global.require ? this.global.require('http') : require('http');
4163
+ const originalEmit = http && http.Server && http.Server.prototype && http.Server.prototype.emit;
4164
+ if (originalEmit) {
4165
+ const MAX = 64 * 1024;
4166
+ const asString = (x) => { try { if (typeof x === 'string') return x; if (Buffer.isBuffer(x)) return x.toString('utf8'); return String(x); } catch { return ''; } };
4167
+
4168
+ const patched = function(eventName, req, res) {
4169
+ try {
4170
+ if (eventName === 'request' && req && res && typeof res.write === 'function' && typeof res.end === 'function') {
4171
+ const startAt = Date.now();
4172
+ const safeHeader = (k) => { try { return req && req.headers ? String((req.headers[k.toLowerCase()] ?? '')) : ''; } catch { return ''; } };
4173
+ const reqIdHeader = safeHeader('x-request-id');
4174
+ const chunks = [];
4175
+ const write = res.write.bind(res);
4176
+ const end = res.end.bind(res);
4177
+ const method = req.method ? String(req.method) : undefined;
4178
+ const url = (req.originalUrl || req.url) ? String(req.originalUrl || req.url) : undefined;
4179
+
4180
+ res.write = function(chunk, enc, cb) {
4181
+ try { const s = asString(chunk); if (s) chunks.push(s); } catch {}
4182
+ return write(chunk, enc, cb);
4183
+ };
4184
+ res.end = function(chunk, enc, cb) {
4185
+ try { const s = asString(chunk); if (s) chunks.push(s); } catch {}
4186
+ try {
4187
+ const preview = chunks.join('').slice(0, MAX);
4188
+ const statusCode = typeof res.statusCode === 'number' ? res.statusCode : undefined;
4189
+ const ct = (typeof res.getHeader === 'function' && res.getHeader('content-type')) || undefined;
4190
+ const routePath = (req && req.route && req.route.path) || (req && req.baseUrl && req.path ? (req.baseUrl + req.path) : undefined);
4191
+ const jsonParsed = (() => { try { return JSON.parse(preview); } catch { return undefined; } })();
4192
+ const requestId = reqIdHeader || (jsonParsed && typeof jsonParsed === 'object' ? (jsonParsed.requestId || jsonParsed.reqId || '') : '');
4193
+ const ctx = (global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx) ? global.__JEST_BRIDGE_ENV_REF._ctx() : {};
4194
+ const payload = {
4195
+ type: 'httpResponse',
4196
+ timestampMs: Date.now(),
4197
+ durationMs: Math.max(0, Date.now() - startAt),
4198
+ method, url, statusCode,
4199
+ route: routePath ? String(routePath) : undefined,
4200
+ contentType: ct ? String(ct) : undefined,
4201
+ headers: (typeof res.getHeaders === 'function') ? res.getHeaders() : undefined,
4202
+ requestId: requestId ? String(requestId) : undefined,
4203
+ bodyPreview: preview,
4204
+ json: jsonParsed,
4205
+ testPath: ctx.testPath, currentTestName: ctx.currentTestName,
4206
+ };
4207
+ try {
4208
+ if (!global.__JEST_HTTP_EVENTS__) global.__JEST_HTTP_EVENTS__ = [];
4209
+ const arr = global.__JEST_HTTP_EVENTS__;
4210
+ arr.push({ timestampMs: payload.timestampMs, durationMs: payload.durationMs, method: payload.method, url: payload.url, route: payload.route, statusCode: payload.statusCode, contentType: payload.contentType, requestId: payload.requestId, json: payload.json, bodyPreview: payload.bodyPreview });
4211
+ if (arr.length > 25) arr.splice(0, arr.length - 25);
4212
+ } catch {}
4213
+ try { console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
4214
+ } catch {}
4215
+ return end(chunk, enc, cb);
4216
+ };
4217
+ try {
4218
+ res.on('close', function onClose() {
4219
+ try {
4220
+ const ended = typeof res.writableEnded === 'boolean' ? res.writableEnded : false;
4221
+ if (!ended) {
4222
+ const routePath = (req && req.route && req.route.path) || (req && req.baseUrl && req.path ? (req.baseUrl + req.path) : undefined);
4223
+ const ctx = (global.__JEST_BRIDGE_ENV_REF && global.__JEST_BRIDGE_ENV_REF._ctx) ? global.__JEST_BRIDGE_ENV_REF._ctx() : {};
4224
+ const payload = {
4225
+ type: 'httpAbort',
4226
+ timestampMs: Date.now(),
4227
+ durationMs: Math.max(0, Date.now() - startAt),
4228
+ method, url,
4229
+ route: routePath ? String(routePath) : undefined,
4230
+ testPath: ctx.testPath, currentTestName: ctx.currentTestName,
4231
+ };
4232
+ try { console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
4233
+ }
4234
+ } catch {}
4235
+ });
4236
+ } catch {}
4237
+ }
4238
+ } catch {}
4239
+ return originalEmit.apply(this, arguments);
4240
+ };
4241
+
4242
+ try { this.global.__JEST_BRIDGE_ENV_REF = this; } catch {}
4243
+ http.Server.prototype.emit = patched;
4244
+
4245
+ this._cleanup.push(() => {
4246
+ try { if (http.Server && http.Server.prototype) http.Server.prototype.emit = originalEmit; } catch {}
4247
+ try { delete this.global.__JEST_BRIDGE_ENV_REF; } catch {}
4248
+ });
4249
+ }
4250
+ } catch {}
4251
+
4252
+ // Wrap test functions to emit rich assertion events on failures
4253
+ try {
4254
+ const g = this.global;
4255
+ const ctxFn = () => {
4256
+ try {
4257
+ const ref = g.__JEST_BRIDGE_ENV_REF;
4258
+ return ref && typeof ref._ctx === 'function' ? ref._ctx() : {};
4259
+ } catch { return {}; }
4260
+ };
4261
+ const emitAssertion = (err) => {
4262
+ try {
4263
+ const e = toErr(err);
4264
+ const mr = e && typeof e === 'object' && e.matcherResult ? e.matcherResult : undefined;
4265
+ const messageText = (() => { try { return mr && typeof mr.message === 'function' ? String(mr.message()) : (e.message || ''); } catch { return e.message || ''; } })();
4266
+ const expectedPreview = (() => { try { return mr && mr.expected !== undefined ? JSON.stringify(mr.expected, null, 2) : undefined; } catch { return undefined; } })();
4267
+ const actualPreview = (() => { try { return mr && mr.received !== undefined ? JSON.stringify(mr.received, null, 2) : undefined; } catch { return undefined; } })();
4268
+ const c = ctxFn();
4269
+ const expectedRaw = (() => { try { return mr?.expected; } catch { return undefined; } })();
4270
+ const receivedRaw = (() => { try { return mr?.received; } catch { return undefined; } })();
4271
+ print({
4272
+ type: 'assertionFailure',
4273
+ timestampMs: Date.now(),
4274
+ matcher: mr && typeof mr.matcherName === 'string' ? mr.matcherName : undefined,
4275
+ expectedPreview,
4276
+ actualPreview,
4277
+ expectedNumber: typeof expectedRaw === 'number' ? expectedRaw : undefined,
4278
+ receivedNumber: typeof receivedRaw === 'number' ? receivedRaw : undefined,
4279
+ message: messageText,
4280
+ stack: e.stack,
4281
+ ...c,
4282
+ });
4283
+ } catch {}
4284
+ };
4285
+ const wrap = (orig) => {
4286
+ if (!orig || typeof orig !== 'function') return orig;
4287
+ const wrapped = function(name, fn, timeout) {
4288
+ if (typeof fn !== 'function') return orig.call(this, name, fn, timeout);
4289
+ const run = function() {
4290
+ try {
4291
+ const res = fn.apply(this, arguments);
4292
+ if (res && typeof res.then === 'function') {
4293
+ return res.catch((err) => { emitAssertion(err); throw err; });
4294
+ }
4295
+ return res;
4296
+ } catch (err) {
4297
+ emitAssertion(err);
4298
+ throw err;
4299
+ }
4300
+ };
4301
+ return orig.call(this, name, run, timeout);
4302
+ };
4303
+ try { wrapped.only = orig.only && typeof orig.only === 'function' ? wrap(orig.only) : orig.only; } catch {}
4304
+ try { wrapped.skip = orig.skip && typeof orig.skip === 'function' ? wrap(orig.skip) : orig.skip; } catch {}
4305
+ return wrapped;
4306
+ };
4307
+ try { g.it = wrap(g.it); } catch {}
4308
+ try { g.test = wrap(g.test); } catch {}
4309
+ } catch {}
4310
+ }
4311
+
4312
+ async handleTestEvent(evt, state) {
4313
+ if (evt.name === 'test_start') {
4314
+ const store = { testPath: state.testPath, currentTestName: evt.test.name };
4315
+ try { this._als.enterWith(store); } catch {}
4316
+ } else if (evt.name === 'test_done') {
4317
+ try { this._als.enterWith({}); } catch {}
4318
+ try {
4319
+ const events = Array.isArray(global.__JEST_HTTP_EVENTS__) ? global.__JEST_HTTP_EVENTS__ : [];
4320
+ if (events.length) {
4321
+ const batch = events.slice(-10);
4322
+ const payload = { type: 'httpResponseBatch', events: batch, testPath: state.testPath, currentTestName: evt.test.name };
4323
+ try { this.global.console.error('[JEST-BRIDGE-EVENT]', JSON.stringify(payload)); } catch {}
4324
+ try { global.__JEST_HTTP_EVENTS__ = []; } catch {}
4325
+ }
4326
+ } catch {}
4327
+ }
4328
+ }
4329
+
4330
+ async teardown() {
4331
+ for (let i = this._cleanup.length - 1; i >= 0; i--) {
4332
+ try { this._cleanup[i](); } catch {}
4333
+ }
4334
+ await super.teardown();
4335
+ }
4336
+ };
4337
+ `;
4006
4338
 
4007
4339
  // src/lib/stacks.ts
4008
4340
  var isStackLine = (line) => /\s+at\s+/.test(line);
@@ -4065,30 +4397,81 @@ var collapseStacks = (lines) => {
4065
4397
  return out;
4066
4398
  };
4067
4399
 
4068
- // src/lib/jest-bridge.ts
4069
- var extractBridgePath = (raw, cwd) => {
4070
- const matches = Array.from(
4071
- raw.matchAll(/Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g)
4072
- );
4073
- if (!matches.length) {
4074
- return null;
4400
+ // src/lib/fp.ts
4401
+ function pipe(initial, ...fns) {
4402
+ return fns.reduce((acc, fn) => fn(acc), initial);
4403
+ }
4404
+ var some = (value) => ({ tag: "Some", value });
4405
+ var none = { tag: "None" };
4406
+ var unfoldr = (initial, step2) => {
4407
+ const out = [];
4408
+ for (let state = initial; ; ) {
4409
+ const result = step2(state);
4410
+ if (result.tag === "None") {
4411
+ break;
4412
+ }
4413
+ const [element, next] = result.value;
4414
+ out.push(element);
4415
+ state = next;
4075
4416
  }
4076
- const jsonPath = matches[matches.length - 1][1].trim().replace(/^["'`]|["'`]$/g, "");
4077
- return path9.isAbsolute(jsonPath) ? jsonPath : path9.resolve(cwd, jsonPath);
4417
+ return out;
4078
4418
  };
4079
- var drawRule = (label) => {
4080
- const width = Math.max(
4081
- 40,
4082
- process.stdout && process.stdout.columns || 80
4083
- );
4084
- if (!label) {
4085
- return ansi.dim("\u2500".repeat(width));
4419
+
4420
+ // src/lib/formatter/parse.ts
4421
+ var isFailureStart = (lineText) => /^\s*●\s+/.test(lineText);
4422
+ var isSuiteLine = (lineText) => /^\s*(PASS|FAIL)\s+/.test(lineText);
4423
+ var isSummaryLine = (lineText) => /^\s*(Test Suites:|Tests:|Snapshots:|Time:|Ran all)/.test(lineText);
4424
+ var collectFailure = (allLines, startIndex) => {
4425
+ const title = stripAnsiSimple(allLines[startIndex]).replace(/^\s*●\s+/, "").trim();
4426
+ const buf = [allLines[startIndex]];
4427
+ let i = startIndex + 1;
4428
+ for (; i < allLines.length; i += 1) {
4429
+ const simple = stripAnsiSimple(allLines[i]);
4430
+ const nextIsStart = isFailureStart(simple) || isSuiteLine(simple) || isSummaryLine(simple);
4431
+ const prevBlank = stripAnsiSimple(allLines[i - 1] ?? "").trim() === "";
4432
+ if (nextIsStart && prevBlank) {
4433
+ break;
4434
+ }
4435
+ buf.push(allLines[i]);
4086
4436
  }
4087
- const plain = stripAnsiSimple(label);
4088
- const pad = Math.max(1, width - plain.length - 1);
4089
- return `${ansi.dim("\u2500".repeat(pad))} ${label}`;
4437
+ return [{ tag: "FailureBlock", title, lines: buf }, i];
4438
+ };
4439
+ var parseSuite = (lineText) => {
4440
+ const match = lineText.match(/^\s*(PASS|FAIL)\s+(.+)$/);
4441
+ return { tag: "PassFail", badge: match[1], rel: match[2] };
4442
+ };
4443
+ var parseChunks = (raw) => {
4444
+ const lines = raw.split(/\r?\n/);
4445
+ return unfoldr({ index: 0 }, (state) => {
4446
+ if (state.index >= lines.length) {
4447
+ return none;
4448
+ }
4449
+ const line = lines[state.index];
4450
+ const simple = stripAnsiSimple(line);
4451
+ if (isFailureStart(simple)) {
4452
+ const [chunk, next] = collectFailure(lines, state.index);
4453
+ return some([chunk, { index: next }]);
4454
+ }
4455
+ if (isSuiteLine(simple)) {
4456
+ return some([parseSuite(simple), { index: state.index + 1 }]);
4457
+ }
4458
+ if (isSummaryLine(simple)) {
4459
+ return some([{ tag: "Summary", line }, { index: state.index + 1 }]);
4460
+ }
4461
+ if (isStackLine(simple)) {
4462
+ return some([{ tag: "Stack", line }, { index: state.index + 1 }]);
4463
+ }
4464
+ return some([{ tag: "Other", line }, { index: state.index + 1 }]);
4465
+ });
4090
4466
  };
4091
- var env = process.env;
4467
+
4468
+ // src/lib/formatter/render.ts
4469
+ var path9 = __toESM(require("node:path"), 1);
4470
+
4471
+ // src/lib/formatter/fns.ts
4472
+ var fs4 = __toESM(require("node:fs"), 1);
4473
+ var util = __toESM(require("node:util"), 1);
4474
+ var import_json5 = __toESM(require_lib(), 1);
4092
4475
  var colorTokens = {
4093
4476
  pass: Colors.Success,
4094
4477
  fail: Colors.Failure,
@@ -4099,31 +4482,17 @@ var colorTokens = {
4099
4482
  failPill: (text) => BackgroundColors.Failure(ansi.white(` ${text} `)),
4100
4483
  runPill: (text) => BackgroundColors.Run(ansi.white(` ${text} `))
4101
4484
  };
4102
- var MAX_CONSOLE_ERRORS_TO_SHOW = 3;
4103
- var isArrayOfPrimitives = (value) => Array.isArray(value) && value.every(
4104
- (element) => ["string", "number", "boolean"].includes(typeof element) || element === null
4105
- );
4106
- var indentBlock = (text, pad = " ") => text.split("\n").map((line) => line ? pad + line : pad.trimEnd()).join("\n");
4107
- var normalizeBlock = (raw) => raw.replace(/^\s*Array\s*\[/, "[").replace(/^\s*Object\s*\{/, "{").replace(/,(\s*[\]}])/g, "$1");
4108
- var stringifyPrettierish = (value) => {
4109
- if (typeof value === "string") {
4110
- const text = normalizeBlock(value.trim());
4111
- if (/^[[{]/.test(text)) {
4112
- try {
4113
- const parsed = import_json5.default.parse(text);
4114
- return JSON.stringify(parsed, null, 2);
4115
- } catch {
4116
- }
4117
- }
4118
- return value;
4119
- }
4120
- if (Array.isArray(value) || value && typeof value === "object") {
4121
- try {
4122
- return JSON.stringify(value, null, 2);
4123
- } catch {
4124
- }
4485
+ var drawRule = (label) => {
4486
+ const width = Math.max(
4487
+ 40,
4488
+ process.stdout && process.stdout.columns || 80
4489
+ );
4490
+ if (!label) {
4491
+ return ansi.dim("\u2500".repeat(width));
4125
4492
  }
4126
- return util.inspect(value, { depth: 10, breakLength: Infinity, compact: false, sorted: true });
4493
+ const plain = stripAnsiSimple(label);
4494
+ const pad = Math.max(1, width - plain.length - 1);
4495
+ return `${ansi.dim("\u2500".repeat(pad))} ${label}`;
4127
4496
  };
4128
4497
  var drawFailLine = () => {
4129
4498
  const width = Math.max(
@@ -4133,9 +4502,29 @@ var drawFailLine = () => {
4133
4502
  return colorTokens.fail("\u2500".repeat(width));
4134
4503
  };
4135
4504
  var renderRunLine = (cwd) => `${colorTokens.runPill("RUN")} ${ansi.dim(cwd.replace(/\\/g, "/"))}`;
4505
+ var buildFileBadgeLine = (rel, failedCount) => failedCount > 0 ? `${colorTokens.failPill("FAIL")} ${ansi.white(rel)}` : `${colorTokens.passPill("PASS")} ${ansi.white(rel)}`;
4506
+ var buildPerFileOverview = (rel, assertions) => {
4507
+ const out = [];
4508
+ out.push(`${ansi.magenta(rel)} ${ansi.dim(`(${assertions.length})`)}`);
4509
+ for (const assertion of assertions) {
4510
+ const name = assertion.fullName;
4511
+ if (assertion.status === "passed") {
4512
+ out.push(` ${colorTokens.pass("\u2713")} ${ansi.dim(name)}`);
4513
+ } else if (assertion.status === "todo") {
4514
+ out.push(` ${colorTokens.todo("\u2610")} ${ansi.dim(name)} ${colorTokens.todo("[todo]")}`);
4515
+ } else if (assertion.status === "pending") {
4516
+ out.push(` ${colorTokens.skip("\u2193")} ${ansi.dim(name)} ${colorTokens.skip("[skipped]")}`);
4517
+ } else {
4518
+ out.push(` ${colorTokens.fail("\xD7")} ${ansi.white(name)}`);
4519
+ }
4520
+ }
4521
+ out.push("");
4522
+ return out;
4523
+ };
4524
+ var isObjectRecord = (value) => typeof value === "object" && value !== null;
4136
4525
  var colorStackLine = (line, projectHint) => {
4137
4526
  const plainLine = stripAnsiSimple(line);
4138
- if (!isStackLine(plainLine)) {
4527
+ if (!/\s+at\s+/.test(plainLine)) {
4139
4528
  return plainLine;
4140
4529
  }
4141
4530
  const match = plainLine.match(/\(?([^\s()]+):(\d+):(\d+)\)?$/);
@@ -4151,298 +4540,144 @@ var colorStackLine = (line, projectHint) => {
4151
4540
  `(${coloredPath}${ansi.dim(":")}${ansi.white(`${lineNumber}:${columnNumber}`)})`
4152
4541
  );
4153
4542
  };
4154
- var renderCodeFrame = (lines, start) => {
4155
- const out = [];
4156
- for (let i = start; i < lines.length; i += 1) {
4157
- const raw = stripAnsiSimple(lines[i]);
4158
- if (!raw.trim()) {
4159
- break;
4160
- }
4161
- if (/^\s*\^+\s*$/.test(raw)) {
4162
- out.push(` ${colorTokens.fail(raw.trimEnd())}`);
4163
- continue;
4164
- }
4165
- const pointerMatch = raw.match(/^\s*>(\s*\d+)\s*\|\s?(.*)$/);
4166
- if (pointerMatch) {
4167
- const num = ansi.dim(pointerMatch[1].trim());
4168
- const code = ansi.yellow(pointerMatch[2] ?? "");
4169
- out.push(` ${colorTokens.fail(">")} ${num} ${ansi.dim("|")} ${code}`);
4170
- continue;
4171
- }
4172
- const normalMatch = raw.match(/^\s*(\d+)\s*\|\s?(.*)$/);
4173
- if (normalMatch) {
4174
- const num = ansi.dim(normalMatch[1]);
4175
- const code = ansi.dim(normalMatch[2] ?? "");
4176
- out.push(` ${num} ${ansi.dim("|")} ${code}`);
4177
- continue;
4178
- }
4179
- out.push(` ${raw}`);
4543
+ var extractBridgePath = (raw, cwd) => {
4544
+ const re = /Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g;
4545
+ const matches = Array.from(raw.matchAll(re));
4546
+ if (matches.length === 0) {
4547
+ return null;
4180
4548
  }
4181
- return out;
4549
+ const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^["'`]|["'`]$/g, "");
4550
+ return /^\//.test(jsonPath) ? jsonPath : `${cwd.replace(/\\/g, "/")}/${jsonPath}`;
4182
4551
  };
4552
+ var findCodeFrameStart = (lines) => lines.findIndex((line) => /^\s*(>?\s*\d+\s*\|)/.test(stripAnsiSimple(line)));
4183
4553
  var _sourceCache = /* @__PURE__ */ new Map();
4184
4554
  var readSource = (file) => {
4185
- const normalizedFile = file.replace(/\\/g, "/");
4186
- const cached = _sourceCache.get(normalizedFile);
4187
- if (cached) {
4188
- return cached;
4555
+ const normalized = file.replace(/\\/g, "/");
4556
+ const hit = _sourceCache.get(normalized);
4557
+ if (hit) {
4558
+ return hit;
4189
4559
  }
4190
4560
  try {
4191
- const txt = fs4.readFileSync(normalizedFile, "utf8");
4192
- const arr = txt.split(/\r?\n/);
4193
- _sourceCache.set(normalizedFile, arr);
4561
+ const arr = fs4.readFileSync(normalized, "utf8").split(/\r?\n/);
4562
+ _sourceCache.set(normalized, arr);
4194
4563
  return arr;
4195
4564
  } catch {
4196
4565
  return [];
4197
4566
  }
4198
4567
  };
4568
+ var renderInlineCodeFrame = (lines, start) => {
4569
+ const out = [];
4570
+ for (let i = start; i < lines.length; i += 1) {
4571
+ const raw = stripAnsiSimple(lines[i]);
4572
+ if (!raw.trim()) {
4573
+ break;
4574
+ }
4575
+ if (/^\s*\^+\s*$/.test(raw)) {
4576
+ out.push(` ${Colors.Failure(raw.trimEnd())}`);
4577
+ } else {
4578
+ const ptr = raw.match(/^\s*>(\s*\d+)\s*\|\s?(.*)$/);
4579
+ if (ptr) {
4580
+ const num = ansi.dim(ptr[1].trim());
4581
+ const code = ansi.yellow(ptr[2] ?? "");
4582
+ out.push(` ${Colors.Failure(">")} ${num} ${ansi.dim("|")} ${code}`);
4583
+ } else {
4584
+ const nor = raw.match(/^\s*(\d+)\s*\|\s?(.*)$/);
4585
+ if (nor) {
4586
+ const num = ansi.dim(nor[1]);
4587
+ const code = ansi.dim(nor[2] ?? "");
4588
+ out.push(` ${num} ${ansi.dim("|")} ${code}`);
4589
+ } else {
4590
+ out.push(` ${raw}`);
4591
+ }
4592
+ }
4593
+ }
4594
+ }
4595
+ return out;
4596
+ };
4199
4597
  var renderSourceCodeFrame = (file, line, context = 3) => {
4200
4598
  const lines = readSource(file);
4201
- if (!lines.length || !Number.isFinite(line)) {
4599
+ if (lines.length === 0 || !Number.isFinite(line)) {
4202
4600
  return [];
4203
4601
  }
4204
4602
  const idx = Math.max(1, Math.min(line, lines.length));
4205
4603
  const start = Math.max(1, idx - context);
4206
4604
  const end = Math.min(lines.length, idx + context);
4207
4605
  const out = [];
4208
- for (let currentLineNumber = start; currentLineNumber <= end; currentLineNumber += 1) {
4209
- const num = ansi.dim(String(currentLineNumber));
4210
- const code = currentLineNumber === idx ? ansi.yellow(lines[currentLineNumber - 1] ?? "") : ansi.dim(lines[currentLineNumber - 1] ?? "");
4211
- if (currentLineNumber === idx) {
4212
- out.push(` ${colorTokens.fail(">")} ${num} ${ansi.dim("|")} ${code}`);
4606
+ for (let current = start; current <= end; current += 1) {
4607
+ const num = ansi.dim(String(current));
4608
+ const code = current === idx ? ansi.yellow(lines[current - 1] ?? "") : ansi.dim(lines[current - 1] ?? "");
4609
+ if (current === idx) {
4610
+ out.push(` ${Colors.Failure(">")} ${num} ${ansi.dim("|")} ${code}`);
4213
4611
  } else {
4214
4612
  out.push(` ${num} ${ansi.dim("|")} ${code}`);
4215
4613
  }
4216
4614
  }
4217
- out.push(` ${colorTokens.fail("^")}`);
4615
+ out.push(` ${Colors.Failure("^")}`);
4218
4616
  return out;
4219
4617
  };
4220
- var findLastProjectFrameIndex = (lines, projectHint) => {
4221
- for (let i = lines.length - 1; i >= 0; i -= 1) {
4222
- const simple = stripAnsiSimple(lines[i]);
4223
- if (isStackLine(simple) && projectHint.test(simple) && !/node_modules|vitest|jest/.test(simple)) {
4224
- return i;
4225
- }
4618
+ var stackLocation = (line) => {
4619
+ const match = stripAnsiSimple(line).match(/\(?([^\s()]+):(\d+):\d+\)?$/);
4620
+ if (!match) {
4621
+ return null;
4226
4622
  }
4227
- return -1;
4623
+ return { file: match[1].replace(/\\/g, "/"), line: Number(match[2]) };
4228
4624
  };
4229
- var renderStackTail = (lines, projectHint, max = 4) => {
4230
- const onlyStack = lines.filter((candidateLine) => isStackLine(stripAnsiSimple(candidateLine)));
4231
- if (!onlyStack.length) {
4232
- return [];
4625
+ var deepestProjectLoc = (stackLines, projectHint) => {
4626
+ for (let i = stackLines.length - 1; i >= 0; i -= 1) {
4627
+ const simple = stripAnsiSimple(stackLines[i]);
4628
+ if (isStackLine(simple) && projectHint.test(simple) && !/node_modules|vitest|jest/.test(simple)) {
4629
+ return stackLocation(stackLines[i]);
4630
+ }
4233
4631
  }
4234
- const tail = onlyStack.slice(-max);
4235
- return tail.map((frameLine) => ` ${colorStackLine(frameLine, projectHint)}`);
4236
- };
4237
- var firstProjectFrames = (lines, projectHint, max = 2) => {
4238
- const onlyStack = lines.filter((ln) => isStackLine(stripAnsiSimple(ln)));
4239
- const projectOnly = onlyStack.filter((ln) => projectHint.test(stripAnsiSimple(ln)));
4240
- return projectOnly.slice(0, max).map((ln) => ` ${colorStackLine(ln, projectHint)}`);
4632
+ return null;
4241
4633
  };
4242
- var isTerminator = (lineText) => !lineText.trim() || isStackLine(lineText);
4243
- var extractAssertionMessage = (msgLines) => {
4244
- const lines = msgLines.map((rawLine) => stripAnsiSimple(rawLine));
4634
+ var buildCodeFrameSection = (messageLines, ctx, synthLoc) => {
4245
4635
  const out = [];
4246
- const hintIdx = lines.findIndex(
4247
- (candidateLine) => /expect\(.+?\)\.(?:to|not\.)/.test(candidateLine) || /\b(?:AssertionError|Error):/.test(candidateLine)
4248
- );
4249
- if (hintIdx >= 0) {
4250
- out.push(lines[hintIdx]);
4636
+ const start = findCodeFrameStart(messageLines);
4637
+ if (start >= 0) {
4638
+ out.push(...renderInlineCodeFrame(messageLines, start), "");
4639
+ return out;
4251
4640
  }
4252
- const collectBlock = (start) => {
4253
- out.push(lines[start]);
4254
- for (let i = start + 1; i < lines.length; i += 1) {
4255
- const candidate = lines[i];
4256
- if (isTerminator(candidate)) {
4257
- break;
4258
- }
4259
- out.push(candidate);
4260
- }
4261
- };
4262
- const expectedIdx = lines.findIndex(
4263
- (candidateLine) => /^\s*Expected:/.test(candidateLine)
4264
- );
4265
- const receivedIdx = lines.findIndex(
4266
- (candidateLine) => /^\s*Received:/.test(candidateLine)
4267
- );
4268
- const diffIdx = lines.findIndex(
4269
- (candidateLine) => /^\s*(?:- Expected|\+ Received|Difference:)/.test(candidateLine)
4270
- );
4271
- if (expectedIdx >= 0) {
4272
- collectBlock(expectedIdx);
4273
- }
4274
- if (receivedIdx >= 0) {
4275
- collectBlock(receivedIdx);
4276
- }
4277
- if (diffIdx >= 0) {
4278
- collectBlock(diffIdx);
4279
- }
4280
- if (out.length === 0 && hintIdx >= 0) {
4281
- for (let i = hintIdx + 1; i < lines.length && out.length < 4; i += 1) {
4282
- const candidate = lines[i];
4283
- if (isTerminator(candidate)) {
4284
- break;
4285
- }
4286
- out.push(candidate);
4287
- }
4641
+ if (ctx.showStacks && synthLoc) {
4642
+ out.push(...renderSourceCodeFrame(synthLoc.file, synthLoc.line), "");
4288
4643
  }
4289
4644
  return out;
4290
4645
  };
4291
- var stackLocation = (line) => {
4292
- const match = stripAnsiSimple(line).match(/\(?([^\s()]+):(\d+):\d+\)?$/);
4293
- return match ? { file: match[1].replace(/\\/g, "/"), line: Number(match[2]) } : null;
4294
- };
4295
- var JEST_BRIDGE_REPORTER_SOURCE = `const fs = require('fs');
4296
- const path = require('path');
4297
-
4298
- class BridgeReporter {
4299
- constructor(globalConfig, options) {
4300
- this.out = process.env.JEST_BRIDGE_OUT || (options && options.outFile) || path.join(process.cwd(), 'coverage', 'jest-run.json');
4301
- this.buf = { startTime: Date.now(), testResults: [], aggregated: null };
4302
- }
4303
- onRunStart() { this.buf.startTime = Date.now(); }
4304
- onTestResult(_test, tr) {
4305
- const mapAssertion = (a) => ({
4306
- title: a.title,
4307
- fullName: a.fullName || [...(a.ancestorTitles || []), a.title].join(' '),
4308
- status: a.status,
4309
- duration: a.duration || 0,
4310
- location: a.location || null,
4311
- failureMessages: (a.failureMessages || []).map(String),
4312
- });
4313
- this.buf.testResults.push({
4314
- testFilePath: tr.testFilePath,
4315
- status: tr.numFailingTests ? 'failed' : 'passed',
4316
- failureMessage: tr.failureMessage || '',
4317
- failureDetails: tr.failureDetails || [],
4318
- console: tr.console || null,
4319
- perfStats: tr.perfStats || {},
4320
- testResults: (tr.testResults || []).map(mapAssertion),
4321
- });
4322
- }
4323
- onRunComplete(_contexts, agg) {
4324
- this.buf.aggregated = {
4325
- numTotalTestSuites: agg.numTotalTestSuites,
4326
- numPassedTestSuites: agg.numPassedTestSuites,
4327
- numFailedTestSuites: agg.numFailedTestSuites,
4328
- numTotalTests: agg.numTotalTests,
4329
- numPassedTests: agg.numPassedTests,
4330
- numFailedTests: agg.numFailedTests,
4331
- numPendingTests: agg.numPendingTests,
4332
- numTodoTests: agg.numTodoTests,
4333
- startTime: agg.startTime,
4334
- success: agg.success,
4335
- runTimeMs: agg.testResults.reduce((t, r) => t + Math.max(0, (r.perfStats?.end || 0) - (r.perfStats?.start || 0)), 0),
4336
- };
4337
- fs.mkdirSync(path.dirname(this.out), { recursive: true });
4338
- fs.writeFileSync(this.out, JSON.stringify(this.buf), 'utf8');
4339
- }
4340
- }
4341
- module.exports = BridgeReporter;`;
4342
- var asDict = (value) => value && typeof value === "object" ? value : null;
4343
- var get = (objectValue, key) => objectValue ? objectValue[key] : void 0;
4344
- var getStr = (objectValue, key) => {
4345
- const candidate = get(objectValue, key);
4346
- return typeof candidate === "string" ? candidate : void 0;
4347
- };
4348
- function linesFromDetails(details) {
4349
- const stacks = [];
4350
- const messages = [];
4351
- if (!details) {
4352
- return { stacks, messages };
4353
- }
4354
- const pushMaybe = (value, bucket) => {
4355
- if (typeof value === "string" && value.trim()) {
4356
- bucket.push(...value.split(/\r?\n/));
4357
- }
4358
- };
4359
- for (const detail of details) {
4360
- if (typeof detail === "string") {
4361
- if (/\s+at\s.+\(.+:\d+:\d+\)/.test(detail)) {
4362
- pushMaybe(detail, stacks);
4363
- } else {
4364
- pushMaybe(detail, messages);
4365
- }
4366
- continue;
4367
- }
4368
- const dict = asDict(detail);
4369
- if (dict) {
4370
- pushMaybe(getStr(dict, "stack"), stacks);
4371
- pushMaybe(getStr(dict, "message"), messages);
4372
- const err = asDict(get(dict, "error"));
4373
- pushMaybe(getStr(err, "stack"), stacks);
4374
- pushMaybe(getStr(err, "message"), messages);
4375
- const matcherResult = asDict(get(dict, "matcherResult"));
4376
- pushMaybe(getStr(matcherResult, "stack"), stacks);
4377
- pushMaybe(getStr(matcherResult, "message"), messages);
4378
- pushMaybe(getStr(matcherResult, "expected"), messages);
4379
- pushMaybe(getStr(matcherResult, "received"), messages);
4380
- }
4381
- }
4382
- return { stacks, messages };
4383
- }
4384
- function labelForMessage(lines) {
4385
- const joined = lines.join(" ");
4386
- const matched = joined.match(/\b(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError)\b/) || joined.match(/\bError\b/);
4387
- if (matched) {
4388
- const typeName = matched[1] ?? "Error";
4389
- return `${typeName}:`;
4390
- }
4391
- return /expect\(.+?\)\.(?:to|not\.)/.test(joined) ? "Assertion:" : "Message:";
4392
- }
4393
- function extractExpectedReceived(details, lines) {
4394
- if (details) {
4395
- for (const detail of details) {
4396
- const dict = asDict(detail);
4397
- const matcherResult = dict && asDict(get(dict, "matcherResult"));
4398
- if (matcherResult) {
4399
- const expected = get(matcherResult, "expected");
4400
- const received = get(matcherResult, "received");
4401
- if (expected !== void 0 || received !== void 0) {
4402
- return { expected, received };
4403
- }
4404
- }
4646
+ var normalizeBlock = (raw) => raw.replace(/^\s*Array\s*\[/, "[").replace(/^\s*Object\s*\{/, "{").replace(/,(\s*[\]}])/g, "$1");
4647
+ var stringifyPrettierish = (value) => {
4648
+ if (typeof value === "string") {
4649
+ const text = normalizeBlock(value.trim());
4650
+ try {
4651
+ const parsed = import_json5.default.parse(text);
4652
+ return JSON.stringify(parsed, null, 2);
4653
+ } catch {
4654
+ return value;
4405
4655
  }
4406
4656
  }
4407
- if (lines && lines.length) {
4408
- const expectedLines = [];
4409
- const receivedLines = [];
4410
- let mode = "none";
4411
- for (const rawLine of lines) {
4412
- const simple = stripAnsiSimple(rawLine);
4413
- if (/^\s*Expected:/.test(simple)) {
4414
- mode = "exp";
4415
- expectedLines.push(simple.replace(/^\s*Expected:\s*/, ""));
4416
- continue;
4417
- }
4418
- if (/^\s*Received:/.test(simple)) {
4419
- mode = "rec";
4420
- receivedLines.push(simple.replace(/^\s*Received:\s*/, ""));
4421
- continue;
4422
- }
4423
- if (/^\s*[-+]\s/.test(simple)) {
4424
- continue;
4425
- }
4426
- if (!simple.trim()) {
4427
- mode = "none";
4428
- } else if (mode === "exp") {
4429
- expectedLines.push(simple);
4430
- } else if (mode === "rec") {
4431
- receivedLines.push(simple);
4432
- }
4433
- }
4434
- if (expectedLines.length || receivedLines.length) {
4435
- return { expected: expectedLines.join("\n"), received: receivedLines.join("\n") };
4436
- }
4437
- const unified = extractFromUnifiedDiff(lines);
4438
- if (unified.expected !== void 0 || unified.received !== void 0) {
4439
- return unified;
4657
+ if (Array.isArray(value) || isObjectRecord(value)) {
4658
+ try {
4659
+ return JSON.stringify(value, null, 2);
4660
+ } catch {
4661
+ return util.inspect(value, {
4662
+ depth: 10,
4663
+ breakLength: Infinity,
4664
+ compact: false,
4665
+ sorted: true
4666
+ });
4440
4667
  }
4441
4668
  }
4442
- return {};
4443
- }
4444
- function extractFromUnifiedDiff(rawLines) {
4445
- const lines = rawLines.map((lineText) => stripAnsiSimple(lineText));
4669
+ return util.inspect(value, {
4670
+ depth: 10,
4671
+ breakLength: Infinity,
4672
+ compact: false,
4673
+ sorted: true
4674
+ });
4675
+ };
4676
+ var isArrayOfPrimitives = (value) => Array.isArray(value) && value.every(
4677
+ (element) => ["string", "number", "boolean"].includes(typeof element) || element === null
4678
+ );
4679
+ var extractFromUnifiedDiff = (rawLines) => {
4680
+ const lines = (rawLines ?? []).map((lineText) => stripAnsiSimple(lineText));
4446
4681
  let startIndex = -1;
4447
4682
  for (let i = 0; i < lines.length; i += 1) {
4448
4683
  const lt = lines[i];
@@ -4489,12 +4724,10 @@ function extractFromUnifiedDiff(rawLines) {
4489
4724
  receivedParts.push(unsigned);
4490
4725
  }
4491
4726
  if (!expDone && expectedParts.length > 0) {
4492
- const expJoined = expectedParts.join("\n");
4493
- expDone = canParseJsonish(expJoined);
4727
+ expDone = canParseJsonish(expectedParts.join("\n"));
4494
4728
  }
4495
4729
  if (!recDone && receivedParts.length > 0) {
4496
- const recJoined = receivedParts.join("\n");
4497
- recDone = canParseJsonish(recJoined);
4730
+ recDone = canParseJsonish(receivedParts.join("\n"));
4498
4731
  }
4499
4732
  if (opened && expDone && recDone) {
4500
4733
  break;
@@ -4524,32 +4757,108 @@ function extractFromUnifiedDiff(rawLines) {
4524
4757
  result.received = recStr;
4525
4758
  }
4526
4759
  return result;
4527
- }
4528
- function renderPrettyDiff(payload) {
4529
- const out = [];
4530
- const { expected, received } = payload;
4531
- if (expected === void 0 && received === void 0) {
4532
- return out;
4760
+ };
4761
+ var extractExpectedReceived = (details, lines) => {
4762
+ if (details) {
4763
+ for (const detail of details) {
4764
+ const dict = isObjectRecord(detail) ? detail : void 0;
4765
+ const matcher = dict && isObjectRecord(dict.matcherResult) ? dict.matcherResult : void 0;
4766
+ if (matcher) {
4767
+ const expectedValue = matcher.expected;
4768
+ const receivedValue = matcher.received;
4769
+ const matcherName = String(
4770
+ matcher.matcherName || ""
4771
+ );
4772
+ if (matcherName === "toHaveBeenCalledTimes" || matcherName === "toBeCalledTimes") {
4773
+ const getCallsCount = (actual) => {
4774
+ if (isObjectRecord(actual) && Array.isArray(actual.calls)) {
4775
+ return actual.calls.length;
4776
+ }
4777
+ if (typeof actual === "number") {
4778
+ return actual;
4779
+ }
4780
+ if (Array.isArray(actual)) {
4781
+ return actual.length;
4782
+ }
4783
+ return void 0;
4784
+ };
4785
+ const expectedNumber = getCallsCount(expectedValue);
4786
+ const actualValue = matcher.actual ?? receivedValue;
4787
+ const receivedNumber = getCallsCount(actualValue);
4788
+ if (expectedNumber !== void 0 || receivedNumber !== void 0) {
4789
+ return { expected: expectedNumber, received: receivedNumber };
4790
+ }
4791
+ }
4792
+ if (expectedValue !== void 0 && receivedValue !== void 0) {
4793
+ return { expected: expectedValue, received: receivedValue };
4794
+ }
4795
+ }
4796
+ }
4797
+ }
4798
+ if (lines && lines.length) {
4799
+ const expectedLines = [];
4800
+ const receivedLines = [];
4801
+ let mode = "none";
4802
+ for (const rawLine of lines) {
4803
+ const simple = stripAnsiSimple(rawLine);
4804
+ if (/^\s*Expected:/.test(simple)) {
4805
+ mode = "exp";
4806
+ expectedLines.push(simple.replace(/^\s*Expected:\s*/, ""));
4807
+ continue;
4808
+ }
4809
+ if (/^\s*Received:/.test(simple)) {
4810
+ mode = "rec";
4811
+ receivedLines.push(simple.replace(/^\s*Received:\s*/, ""));
4812
+ continue;
4813
+ }
4814
+ if (/^\s*[-+]\s/.test(simple)) {
4815
+ continue;
4816
+ }
4817
+ if (!simple.trim()) {
4818
+ mode = "none";
4819
+ } else if (mode === "exp") {
4820
+ expectedLines.push(simple);
4821
+ } else if (mode === "rec") {
4822
+ receivedLines.push(simple);
4823
+ }
4824
+ }
4825
+ if (expectedLines.length || receivedLines.length) {
4826
+ return { expected: expectedLines.join("\n"), received: receivedLines.join("\n") };
4827
+ }
4828
+ const unified = extractFromUnifiedDiff(lines);
4829
+ if (unified.expected !== void 0 || unified.received !== void 0) {
4830
+ return unified;
4831
+ }
4533
4832
  }
4534
- const expectedString = stringifyPrettierish(expected);
4535
- const receivedString = stringifyPrettierish(received);
4833
+ return {};
4834
+ };
4835
+ var buildPrettyDiffSection = (details, messageLines) => {
4836
+ const payload = extractExpectedReceived(details, messageLines);
4837
+ if (payload.expected === void 0 && payload.received === void 0) {
4838
+ return [];
4839
+ }
4840
+ const expectedString = stringifyPrettierish(payload.expected);
4841
+ const receivedString = stringifyPrettierish(payload.received);
4842
+ const out = [];
4843
+ const expectedLenLabel = Array.isArray(payload.expected) ? ansi.dim(` (len ${payload.expected.length})`) : "";
4844
+ out.push(` ${ansi.bold("Expected")}${expectedLenLabel}`);
4536
4845
  out.push(
4537
- ` ${ansi.bold("Expected")} ${ansi.dim(
4538
- expected && Array.isArray(expected) ? `(len ${expected.length})` : ""
4539
- )}`
4846
+ expectedString.split("\n").map((expectedLine) => ` ${Colors.Success(expectedLine)}`).join("\n")
4540
4847
  );
4541
- out.push(indentBlock(colorTokens.pass(expectedString)));
4848
+ const receivedLenLabel = Array.isArray(payload.received) ? ansi.dim(` (len ${payload.received.length})`) : "";
4849
+ out.push(` ${ansi.bold("Received")}${receivedLenLabel}`);
4542
4850
  out.push(
4543
- ` ${ansi.bold("Received")} ${ansi.dim(
4544
- received && Array.isArray(received) ? `(len ${received.length})` : ""
4545
- )}`
4851
+ receivedString.split("\n").map((receivedLine) => ` ${Colors.Failure(receivedLine)}`).join("\n")
4546
4852
  );
4547
- out.push(indentBlock(colorTokens.fail(receivedString)));
4548
- if (isArrayOfPrimitives(expected) && isArrayOfPrimitives(received)) {
4549
- const expectedSet = new Set(expected.map((element) => String(element)));
4550
- const receivedSet = new Set(received.map((element) => String(element)));
4551
- const missing = [...expectedSet].filter((element) => !receivedSet.has(element));
4552
- const unexpected = [...receivedSet].filter((element) => !expectedSet.has(element));
4853
+ if (isArrayOfPrimitives(payload.expected) && isArrayOfPrimitives(payload.received)) {
4854
+ const expectedSet = new Set(
4855
+ payload.expected.map((element) => String(element))
4856
+ );
4857
+ const receivedSet = new Set(
4858
+ payload.received.map((element) => String(element))
4859
+ );
4860
+ const missing = Array.from(expectedSet).filter((element) => !receivedSet.has(element));
4861
+ const unexpected = Array.from(receivedSet).filter((element) => !expectedSet.has(element));
4553
4862
  const parts = [];
4554
4863
  if (missing.length) {
4555
4864
  parts.push(
@@ -4562,67 +4871,85 @@ function renderPrettyDiff(payload) {
4562
4871
  );
4563
4872
  }
4564
4873
  if (parts.length) {
4565
- out.push(` ${ansi.dim("Difference:")} ${colorTokens.fail(parts.join(ansi.dim(" | ")))}`);
4874
+ out.push(` ${ansi.dim("Difference:")} ${Colors.Failure(parts.join(ansi.dim(" | ")))}`);
4566
4875
  }
4567
4876
  }
4568
4877
  out.push("");
4569
4878
  return out;
4570
- }
4571
- function pickPrimaryMessage(candidateMessageLines, details) {
4572
- const extracted = extractAssertionMessage(candidateMessageLines);
4573
- if (extracted.length) {
4574
- return extracted;
4575
- }
4576
- const errorLine = details.messages.find(
4577
- (lineText) => /\b(?:Error|TypeError|ReferenceError|SyntaxError|RangeError|AssertionError)\b/.test(lineText)
4879
+ };
4880
+ var buildMessageSection = (messageLines, details, _ctx, opts) => {
4881
+ const out = [];
4882
+ const lines = messageLines.map((lineText) => stripAnsiSimple(lineText));
4883
+ const hintIdx = lines.findIndex(
4884
+ (candidate) => /expect\(.+?\)\.(?:to|not\.)/.test(candidate) || /\b(?:AssertionError|Error):/.test(candidate)
4578
4885
  );
4579
- if (errorLine) {
4580
- return [errorLine];
4581
- }
4582
- const firstNonEmpty = details.messages.find((lineText) => lineText.trim().length);
4583
- if (firstNonEmpty) {
4584
- return [firstNonEmpty];
4585
- }
4586
- return [];
4587
- }
4588
- function colorUnifiedDiffLine(simple) {
4589
- if (/^\s*-\s/.test(simple)) {
4590
- return colorTokens.fail(simple);
4886
+ const acc = [];
4887
+ if (hintIdx >= 0) {
4888
+ acc.push(lines[hintIdx]);
4591
4889
  }
4592
- if (/^\s*\+\s/.test(simple)) {
4593
- return colorTokens.pass(simple);
4890
+ const pushBlock = (start) => {
4891
+ acc.push(lines[start]);
4892
+ for (let i = start + 1; i < lines.length; i += 1) {
4893
+ const candidate = lines[i];
4894
+ if (!candidate.trim() || isStackLine(candidate)) {
4895
+ break;
4896
+ }
4897
+ acc.push(candidate);
4898
+ }
4899
+ };
4900
+ const expectedIdx = lines.findIndex((lineText) => /^\s*Expected:/.test(lineText));
4901
+ const receivedIdx = lines.findIndex((lineText) => /^\s*Received:/.test(lineText));
4902
+ const diffIdx = lines.findIndex(
4903
+ (lineText) => /^\s*(?:- Expected|\+ Received|Difference:)/.test(lineText)
4904
+ );
4905
+ if (expectedIdx >= 0) {
4906
+ pushBlock(expectedIdx);
4594
4907
  }
4595
- return simple;
4596
- }
4597
- var findCodeFrameStart = (lines) => lines.findIndex((line) => /^\s*(>?\s*\d+\s*\|)/.test(stripAnsiSimple(line)));
4598
- var deepestProjectLoc = (stackLines, projectHint) => {
4599
- const idx = findLastProjectFrameIndex(stackLines, projectHint);
4600
- return idx >= 0 ? stackLocation(stackLines[idx]) : null;
4601
- };
4602
- var buildCodeFrameSection = (messageLines, ctx, synthLoc) => {
4603
- const lines = [];
4604
- const start = findCodeFrameStart(messageLines);
4605
- if (start >= 0) {
4606
- lines.push(...renderCodeFrame(messageLines, start), "");
4607
- return lines;
4908
+ if (receivedIdx >= 0) {
4909
+ pushBlock(receivedIdx);
4608
4910
  }
4609
- if (ctx.showStacks && synthLoc) {
4610
- lines.push(...renderSourceCodeFrame(synthLoc.file, synthLoc.line), "");
4911
+ if (diffIdx >= 0) {
4912
+ pushBlock(diffIdx);
4611
4913
  }
4612
- return lines;
4613
- };
4614
- var buildMessageSection = (messageLines, details, ctx, opts) => {
4615
- const out = [];
4616
- const primary = pickPrimaryMessage(messageLines, details);
4617
- const filtered = opts?.suppressDiff ? primary.filter((raw) => {
4914
+ const filtered = opts?.suppressDiff ? acc.filter((raw) => {
4618
4915
  const simple = stripAnsiSimple(raw);
4619
4916
  return !/^\s*(Expected:|Received:|Difference:)\b/.test(simple) && !/^\s*[-+]\s/.test(simple) && !/^\s*(Array\s*\[|Object\s*\{)/.test(simple);
4620
- }) : primary;
4621
- if (filtered.length) {
4622
- const label = labelForMessage(filtered);
4917
+ }) : acc;
4918
+ const hasOnlyBareError = filtered.length === 0 || filtered.length === 1 && /^\s*(?:Error|AssertionError):?\s*$/.test(filtered[0] ?? "");
4919
+ const fallbackLines = [];
4920
+ if (hasOnlyBareError) {
4921
+ const startFrom = hintIdx >= 0 ? hintIdx + 1 : 0;
4922
+ for (let i = startFrom; i < lines.length; i += 1) {
4923
+ const candidate = lines[i];
4924
+ if (!candidate.trim()) {
4925
+ break;
4926
+ }
4927
+ if (isStackLine(candidate)) {
4928
+ break;
4929
+ }
4930
+ fallbackLines.push(candidate);
4931
+ }
4932
+ if (fallbackLines.length === 0 && details && details.messages && details.messages.length) {
4933
+ fallbackLines.push(
4934
+ ...details.messages.map((messageText) => stripAnsiSimple(messageText)).filter((messageText) => messageText.trim().length > 0).slice(0, 6)
4935
+ );
4936
+ }
4937
+ }
4938
+ if (filtered.length > 0) {
4939
+ const label = (() => {
4940
+ const joined = filtered.join(" ");
4941
+ const matchResult = joined.match(/\b(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError)\b/) || joined.match(/\bError\b/);
4942
+ if (matchResult) {
4943
+ const typeName = matchResult[1] ?? "Error";
4944
+ return `${typeName}:`;
4945
+ }
4946
+ return /expect\(.+?\)\.(?:to|not\.)/.test(joined) ? "Assertion:" : "Message:";
4947
+ })();
4623
4948
  out.push(` ${ansi.bold(label)}`);
4624
- for (const lineText of filtered) {
4625
- out.push(` ${ansi.yellow(colorUnifiedDiffLine(lineText))}`);
4949
+ const body = hasOnlyBareError ? fallbackLines : filtered;
4950
+ for (const lineText of body) {
4951
+ const colored = /^\s*-\s/.test(lineText) ? Colors.Failure(lineText) : /^\s*\+\s/.test(lineText) ? Colors.Success(lineText) : lineText;
4952
+ out.push(` ${ansi.yellow(colored)}`);
4626
4953
  }
4627
4954
  if (opts?.stackPreview && opts.stackPreview.length) {
4628
4955
  for (const frame of opts.stackPreview) {
@@ -4633,32 +4960,85 @@ var buildMessageSection = (messageLines, details, ctx, opts) => {
4633
4960
  }
4634
4961
  return out;
4635
4962
  };
4636
- function isConsoleEntry(candidate) {
4637
- return typeof candidate === "object" && candidate !== null;
4638
- }
4639
- var buildConsoleSection = (maybeConsole) => {
4640
- const out = [];
4641
- if (!Array.isArray(maybeConsole)) {
4642
- return out;
4963
+ var linesFromDetails = (details) => {
4964
+ const stacks = [];
4965
+ const messages = [];
4966
+ if (!details) {
4967
+ return { stacks, messages };
4643
4968
  }
4644
- const entries = maybeConsole.filter(isConsoleEntry);
4645
- const errorsOnly = entries.filter((entry) => {
4646
- const val = entry?.type;
4647
- return String(val ?? "").toLowerCase() === "error";
4648
- });
4649
- const scored = errorsOnly.map((entry) => {
4650
- const raw = entry?.message;
4651
- const msg = Array.isArray(raw) ? raw.map(String).join(" ") : typeof raw === "string" ? raw : String(raw ?? "");
4652
- return { msg, score: msg.length };
4653
- }).filter((item) => item.msg.trim().length > 0).sort((left, right) => right.score - left.score).slice(0, MAX_CONSOLE_ERRORS_TO_SHOW);
4654
- if (scored.length) {
4655
- out.push(ansi.dim(" Console errors:"));
4656
- for (const item of scored) {
4657
- out.push(` ${ansi.dim("\u2022")} ${item.msg}`);
4969
+ const pushMaybe = (value, bucket) => {
4970
+ if (typeof value === "string" && value.trim()) {
4971
+ bucket.push(...value.split(/\r?\n/));
4972
+ }
4973
+ };
4974
+ const visitDeep = (value, depth) => {
4975
+ if (depth > 3 || value == null) {
4976
+ return;
4977
+ }
4978
+ if (typeof value === "string") {
4979
+ pushMaybe(value, messages);
4980
+ return;
4981
+ }
4982
+ if (typeof value !== "object") {
4983
+ return;
4984
+ }
4985
+ const obj = value;
4986
+ if (typeof obj.message === "string") {
4987
+ pushMaybe(obj.message, messages);
4988
+ }
4989
+ if (typeof obj.stack === "string") {
4990
+ pushMaybe(obj.stack, stacks);
4991
+ }
4992
+ if (typeof obj.expected === "string") {
4993
+ pushMaybe(obj.expected, messages);
4994
+ }
4995
+ if (typeof obj.received === "string") {
4996
+ pushMaybe(obj.received, messages);
4997
+ }
4998
+ const arrays = ["errors", "causes", "aggregatedErrors"];
4999
+ for (const key of arrays) {
5000
+ const arr = obj[key];
5001
+ if (Array.isArray(arr)) {
5002
+ for (const element of arr) {
5003
+ visitDeep(element, depth + 1);
5004
+ }
5005
+ }
5006
+ }
5007
+ const nestedCandidates = ["error", "cause", "matcherResult"];
5008
+ for (const key of nestedCandidates) {
5009
+ if (obj[key] && typeof obj[key] === "object") {
5010
+ visitDeep(obj[key], depth + 1);
5011
+ }
5012
+ }
5013
+ };
5014
+ for (const detail of details) {
5015
+ if (typeof detail === "string") {
5016
+ if (/\s+at\s.+\(.+:\d+:\d+\)/.test(detail)) {
5017
+ pushMaybe(detail, stacks);
5018
+ } else {
5019
+ pushMaybe(detail, messages);
5020
+ }
5021
+ } else if (isObjectRecord(detail)) {
5022
+ pushMaybe(detail.stack, stacks);
5023
+ pushMaybe(detail.message, messages);
5024
+ const err = isObjectRecord(detail.error) ? detail.error : void 0;
5025
+ if (err) {
5026
+ pushMaybe(err.stack, stacks);
5027
+ pushMaybe(err.message, messages);
5028
+ }
5029
+ const matcher = isObjectRecord(detail.matcherResult) ? detail.matcherResult : void 0;
5030
+ if (matcher) {
5031
+ pushMaybe(matcher.stack, stacks);
5032
+ pushMaybe(matcher.message, messages);
5033
+ pushMaybe(matcher.expected, messages);
5034
+ pushMaybe(matcher.received, messages);
5035
+ }
5036
+ if (messages.length === 0 && stacks.length === 0) {
5037
+ visitDeep(detail, 0);
5038
+ }
4658
5039
  }
4659
- out.push("");
4660
5040
  }
4661
- return out;
5041
+ return { stacks, messages };
4662
5042
  };
4663
5043
  var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
4664
5044
  const out = [];
@@ -4667,13 +5047,18 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
4667
5047
  out.push(` ${ansi.dim("(hidden by TEST_CLI_STACKS=)")}`, "");
4668
5048
  return out;
4669
5049
  }
4670
- const tail = renderStackTail(mergedForStack, ctx.projectHint, 4);
5050
+ const onlyStack = mergedForStack.filter(
5051
+ (lineText) => isStackLine(stripAnsiSimple(lineText))
5052
+ );
5053
+ const tail = onlyStack.slice(-4);
4671
5054
  if (tail.length) {
4672
- out.push(...tail);
5055
+ for (const frameLine of tail) {
5056
+ out.push(` ${colorStackLine(String(frameLine), ctx.projectHint)}`);
5057
+ }
4673
5058
  const loc = deepestProjectLoc(mergedForStack, ctx.projectHint);
4674
5059
  if (loc) {
4675
5060
  const href = preferredEditorHref(loc.file, loc.line, ctx.editorCmd);
4676
- out.push(` ${ansi.dim("at")} ${osc8(`${path9.basename(loc.file)}:${loc.line}`, href)}`);
5061
+ out.push(` ${ansi.dim("at")} ${osc8(`${loc.file.split("/").pop()}:${loc.line}`, href)}`);
4677
5062
  }
4678
5063
  out.push("");
4679
5064
  return out;
@@ -4688,171 +5073,460 @@ var buildStackSection = (mergedForStack, ctx, fallbackLoc) => {
4688
5073
  out.push(` ${ansi.dim("(no stack provided)")}`, "");
4689
5074
  return out;
4690
5075
  };
4691
- var buildFileBadgeLine = (rel, failedCount) => failedCount > 0 ? `${colorTokens.failPill("FAIL")} ${ansi.white(rel)}` : `${colorTokens.passPill("PASS")} ${ansi.white(rel)}`;
4692
- var buildPerFileOverview = (rel, assertions) => {
5076
+ var MAX_CONSOLE_ERRORS_TO_SHOW = 3;
5077
+ var isConsoleEntry = (candidate) => typeof candidate === "object" && candidate !== null;
5078
+ var buildConsoleSection = (maybeConsole) => {
4693
5079
  const out = [];
4694
- out.push(`${ansi.magenta(rel)} ${ansi.dim(`(${assertions.length})`)}`);
4695
- for (const assertion of assertions) {
4696
- const name = assertion.fullName;
4697
- if (assertion.status === "passed") {
4698
- out.push(` ${colorTokens.pass("\u2713")} ${ansi.dim(name)}`);
4699
- } else if (assertion.status === "todo") {
4700
- out.push(` ${colorTokens.todo("\u2610")} ${ansi.dim(name)} ${colorTokens.todo("[todo]")}`);
4701
- } else if (assertion.status === "pending") {
4702
- out.push(` ${colorTokens.skip("\u2193")} ${ansi.dim(name)} ${colorTokens.skip("[skipped]")}`);
4703
- } else {
4704
- out.push(` ${colorTokens.fail("\xD7")} ${ansi.white(name)}`);
5080
+ if (!Array.isArray(maybeConsole)) {
5081
+ return out;
5082
+ }
5083
+ const entries = maybeConsole.filter(isConsoleEntry);
5084
+ const errorsOnly = entries.filter((entry) => String(entry?.type ?? "").toLowerCase() === "error");
5085
+ const scored = errorsOnly.map((entry) => {
5086
+ const raw = entry?.message;
5087
+ const msg = Array.isArray(raw) ? raw.map(String).join(" ") : typeof raw === "string" ? raw : String(raw ?? "");
5088
+ return { msg, score: msg.length };
5089
+ }).filter((item) => item.msg.trim().length > 0).sort((left, right) => right.score - left.score).slice(0, MAX_CONSOLE_ERRORS_TO_SHOW);
5090
+ if (scored.length) {
5091
+ out.push(ansi.dim(" Console errors:"));
5092
+ for (const item of scored) {
5093
+ out.push(` ${ansi.dim("\u2022")} ${item.msg}`);
4705
5094
  }
5095
+ out.push("");
4706
5096
  }
4707
- out.push("");
4708
5097
  return out;
4709
5098
  };
4710
- var formatJestOutputVitest = (raw, opts) => {
4711
- const showStacks = Boolean(env.TEST_CLI_STACKS);
4712
- const cwd = (opts?.cwd ?? process.cwd()).replace(/\\/g, "/");
4713
- const projectHint = new RegExp(
4714
- `(${cwd.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")})|(/gigworx-node/)`
5099
+ var buildFallbackMessageBlock = (messageLines, details) => {
5100
+ const normalize2 = (arr) => arr.map((lineText) => stripAnsiSimple(lineText)).filter((line) => line.trim().length > 0);
5101
+ const normalized = normalize2(messageLines);
5102
+ const informative = normalized.filter((line) => !/^\s*(?:Error|AssertionError):?\s*$/.test(line));
5103
+ if (informative.length > 0) {
5104
+ return [];
5105
+ }
5106
+ const errorIdx = normalized.findIndex(
5107
+ (line) => /(TypeError|ReferenceError|SyntaxError|RangeError|AssertionError|Error):?/.test(line)
4715
5108
  );
4716
- const onlyFailures = Boolean(opts?.onlyFailures);
4717
- const lines = raw.split(/\r?\n/);
5109
+ const collected = [];
5110
+ if (errorIdx >= 0) {
5111
+ for (let i = errorIdx; i < normalized.length && collected.length < 8; i += 1) {
5112
+ const ln = normalized[i];
5113
+ if (!ln.trim()) {
5114
+ break;
5115
+ }
5116
+ if (isStackLine(ln)) {
5117
+ break;
5118
+ }
5119
+ collected.push(ln);
5120
+ }
5121
+ }
5122
+ const fromDetails = collected.length > 0 ? [] : normalize2(details.messages).slice(0, 6);
5123
+ const linesToShow = collected.length > 0 ? collected : fromDetails;
5124
+ if (linesToShow.length === 0) {
5125
+ return [];
5126
+ }
4718
5127
  const out = [];
4719
- const seenFailures = /* @__PURE__ */ new Set();
4720
- const seenFiles = /* @__PURE__ */ new Set();
4721
- for (let lineIndex = 0; lineIndex < lines.length; ) {
4722
- const ln = stripAnsiSimple(lines[lineIndex]);
4723
- if (/^\s*●\s+/.test(ln)) {
4724
- const title = ln.replace(/^\s*●\s+/, "").trim();
4725
- const block = [lines[lineIndex]];
4726
- let scanIndex = lineIndex + 1;
4727
- while (scanIndex < lines.length) {
4728
- const scanLine = stripAnsiSimple(lines[scanIndex]);
4729
- const nextIsStart = /^\s*●\s+/.test(scanLine) || /^\s*(PASS|FAIL)\s/.test(scanLine) || /^\s*Test Suites:/.test(scanLine);
4730
- if (nextIsStart && stripAnsiSimple(lines[scanIndex - 1] ?? "").trim() === "") {
4731
- break;
4732
- }
4733
- block.push(lines[scanIndex]);
4734
- scanIndex += 1;
5128
+ out.push(` ${ansi.bold("Message:")}`);
5129
+ for (const lineText of linesToShow) {
5130
+ out.push(` ${ansi.yellow(lineText)}`);
5131
+ }
5132
+ out.push("");
5133
+ return out;
5134
+ };
5135
+ var buildThrownSection = (details) => {
5136
+ const toLines = (value) => {
5137
+ if (value == null) {
5138
+ return [];
5139
+ }
5140
+ if (typeof value === "string") {
5141
+ return value.split(/\r?\n/);
5142
+ }
5143
+ try {
5144
+ return JSON.stringify(value, null, 2).split(/\r?\n/);
5145
+ } catch {
5146
+ return [String(value)];
5147
+ }
5148
+ };
5149
+ const candidates = [];
5150
+ for (const d of details) {
5151
+ const obj = d && typeof d === "object" ? d : null;
5152
+ if (obj && obj.error && typeof obj.error === "object") {
5153
+ const err = obj.error;
5154
+ if (typeof err.name === "string") {
5155
+ candidates.push(`name: ${err.name}`);
4735
5156
  }
4736
- const codeFrameStart = block.findIndex(
4737
- (candidateLine) => /^\s*(>?\s*\d+\s*\|)/.test(stripAnsiSimple(candidateLine))
4738
- );
4739
- const location = firstTestLocation(block, projectHint);
4740
- const rel = location ? location.split(":")[0].replace(/\\/g, "/").replace(`${cwd}/`, "") : "";
4741
- const key = `${rel}|${title}`;
4742
- if (seenFailures.has(key)) {
4743
- lineIndex = scanIndex;
4744
- continue;
5157
+ if (typeof err.message === "string") {
5158
+ candidates.push(`message: ${err.message}`);
4745
5159
  }
4746
- seenFailures.add(key);
4747
- out.push(drawFailLine());
4748
- const header = `${colorTokens.fail("\xD7")} ${ansi.white(rel ? `${rel} > ${title}` : title)}`;
4749
- out.push(header);
4750
- const linesBlock = block.map(String);
4751
- const collapsedForSrc = collapseStacks(linesBlock.slice(0));
4752
- if (codeFrameStart >= 0) {
4753
- out.push("");
4754
- out.push(...renderCodeFrame(linesBlock, codeFrameStart));
4755
- out.push("");
4756
- } else if (showStacks) {
4757
- const deepestIdxForSrc = findLastProjectFrameIndex(collapsedForSrc, projectHint);
4758
- const locForSrc = deepestIdxForSrc >= 0 ? stackLocation(collapsedForSrc[deepestIdxForSrc]) : null;
4759
- if (locForSrc) {
4760
- out.push("");
4761
- out.push(...renderSourceCodeFrame(locForSrc.file, locForSrc.line));
4762
- out.push("");
4763
- }
4764
- }
4765
- const payload = extractExpectedReceived(void 0, linesBlock);
4766
- const hasPretty = payload.expected !== void 0 || payload.received !== void 0;
4767
- out.push(...renderPrettyDiff(payload));
4768
- const detailsForMsg = linesFromDetails(void 0);
4769
- const collapsedForTail = collapseStacks(linesBlock.slice(0));
4770
- const stackPreview = showStacks ? firstProjectFrames(collapsedForTail, projectHint, 2) : [];
4771
- out.push(
4772
- ...buildMessageSection(
4773
- linesBlock,
4774
- detailsForMsg,
4775
- { projectHint, editorCmd: opts?.editorCmd, showStacks },
4776
- { suppressDiff: hasPretty, stackPreview }
4777
- )
4778
- );
4779
- if (showStacks && stackPreview.length === 0) {
4780
- const collapsed = collapseStacks(linesBlock.slice(0));
4781
- out.push(
4782
- ...buildStackSection(collapsed, {
4783
- projectHint,
4784
- editorCmd: opts?.editorCmd,
4785
- showStacks
4786
- })
4787
- );
5160
+ if (typeof err.code === "string" || typeof err.code === "number") {
5161
+ candidates.push(`code: ${String(err.code)}`);
5162
+ }
5163
+ if (typeof err.cause === "string") {
5164
+ candidates.push(`cause: ${err.cause}`);
5165
+ }
5166
+ if (err.cause && typeof err.cause === "object") {
5167
+ candidates.push("cause:");
5168
+ candidates.push(...toLines(err.cause));
5169
+ }
5170
+ const rest = { ...err };
5171
+ delete rest.name;
5172
+ delete rest.message;
5173
+ delete rest.code;
5174
+ delete rest.stack;
5175
+ if (Object.keys(rest).length > 0) {
5176
+ candidates.push("details:");
5177
+ candidates.push(...toLines(rest));
4788
5178
  }
4789
- out.push(drawFailLine());
4790
- out.push("");
4791
- lineIndex = scanIndex;
4792
- continue;
4793
5179
  }
4794
- const passFail = ln.match(/^\s*(PASS|FAIL)\s+(.+)$/);
4795
- if (passFail) {
4796
- const badge = passFail[1];
4797
- const fileAbs = passFail[2];
4798
- const rel = fileAbs.replace(/\\/g, "/").replace(`${cwd}/`, "");
5180
+ }
5181
+ if (!candidates.length) {
5182
+ return [];
5183
+ }
5184
+ const out = [];
5185
+ out.push(` ${ansi.bold("Thrown:")}`);
5186
+ for (const line of candidates.slice(0, 50)) {
5187
+ out.push(` ${ansi.yellow(line)}`);
5188
+ }
5189
+ out.push("");
5190
+ return out;
5191
+ };
5192
+ var mkPrettyFns = () => ({
5193
+ drawRule,
5194
+ drawFailLine,
5195
+ renderRunLine,
5196
+ buildPerFileOverview,
5197
+ buildFileBadgeLine,
5198
+ extractBridgePath,
5199
+ buildCodeFrameSection,
5200
+ buildMessageSection,
5201
+ buildPrettyDiffSection,
5202
+ buildStackSection,
5203
+ deepestProjectLoc,
5204
+ findCodeFrameStart,
5205
+ linesFromDetails,
5206
+ buildFallbackMessageBlock,
5207
+ buildThrownSection
5208
+ });
5209
+
5210
+ // src/lib/formatter/render.ts
5211
+ var relPath = (abs, cwd) => abs.replace(/\\/g, "/").replace(`${cwd}/`, "");
5212
+ var renderChunks = (chunks, ctx, fns, opts) => {
5213
+ const out = [];
5214
+ const seenFiles = /* @__PURE__ */ new Set();
5215
+ const seenFailures = /* @__PURE__ */ new Set();
5216
+ const onlyFailures = Boolean(opts?.onlyFailures);
5217
+ let currentRelFile = null;
5218
+ const escapeRegExp = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5219
+ for (const ch of chunks) {
5220
+ if (ch.tag === "PassFail") {
5221
+ const rel = relPath(ch.rel, ctx.cwd);
4799
5222
  if (seenFiles.has(rel)) {
4800
- lineIndex += 1;
4801
5223
  continue;
4802
5224
  }
4803
- seenFiles.add(rel);
4804
- if (!(onlyFailures && badge === "PASS")) {
4805
- const pill = badge === "PASS" ? colorTokens.passPill("PASS") : colorTokens.failPill("FAIL");
4806
- out.push(`${pill} ${ansi.white(rel)}`);
5225
+ seenFiles.add(rel);
5226
+ currentRelFile = rel;
5227
+ if (!(onlyFailures && ch.badge === "PASS")) {
5228
+ out.push(fns.buildFileBadgeLine(rel, ch.badge === "FAIL" ? 1 : 0));
5229
+ }
5230
+ continue;
5231
+ }
5232
+ if (ch.tag === "FailureBlock") {
5233
+ out.push(fns.drawFailLine());
5234
+ const location = firstTestLocation(ch.lines, ctx.projectHint);
5235
+ const rel = location ? relPath(location.split(":")[0] ?? "", ctx.cwd) : "";
5236
+ const headerText = rel ? `${rel} > ${ch.title}` : ch.title;
5237
+ out.push(`${Colors.Failure("\xD7")} ${ansi.white(headerText)}`);
5238
+ const codeStart = fns.findCodeFrameStart(ch.lines);
5239
+ const collapsedForSrc = collapseStacks(ch.lines.slice(0));
5240
+ const deepestLoc = fns.deepestProjectLoc(collapsedForSrc, ctx.projectHint);
5241
+ let effectiveLoc = deepestLoc;
5242
+ if (!effectiveLoc && currentRelFile) {
5243
+ try {
5244
+ const abs = path9.resolve(ctx.cwd, currentRelFile);
5245
+ const source = ctx.readSource(abs);
5246
+ const testName = (() => {
5247
+ const parts = ch.title.split(">");
5248
+ return (parts[parts.length - 1] || ch.title).trim();
5249
+ })();
5250
+ const itRe = new RegExp(
5251
+ String.raw`\b(?:it|test)\s*\(\s*['\"]${escapeRegExp(testName)}['\"]`
5252
+ );
5253
+ let index = source.findIndex((line) => itRe.test(line));
5254
+ if (index < 0) {
5255
+ index = source.findIndex((line) => /\bexpect\s*\(/.test(line));
5256
+ } else {
5257
+ const windowEnd = Math.min(source.length, index + 80);
5258
+ for (let i = index; i < windowEnd; i += 1) {
5259
+ if (/\bexpect\s*\(/.test(source[i])) {
5260
+ index = i;
5261
+ break;
5262
+ }
5263
+ }
5264
+ }
5265
+ if (index >= 0) {
5266
+ effectiveLoc = { file: abs.replace(/\\/g, "/"), line: index + 1 };
5267
+ }
5268
+ } catch {
5269
+ }
5270
+ }
5271
+ if (codeStart >= 0) {
5272
+ out.push("", ...fns.buildCodeFrameSection(ch.lines, ctx, effectiveLoc), "");
5273
+ } else {
5274
+ out.push("", ...fns.buildCodeFrameSection(ch.lines, ctx, effectiveLoc), "");
5275
+ }
5276
+ const pretty = fns.buildPrettyDiffSection(void 0, ch.lines);
5277
+ out.push(...pretty);
5278
+ const hasPretty = pretty.length > 0;
5279
+ const details = fns.linesFromDetails(void 0);
5280
+ const minimal = (() => {
5281
+ const plain = ch.lines.map((ln) => stripAnsiSimple(ln));
5282
+ const hint = plain.findIndex(
5283
+ (lineText) => /expect\(.+?\)\.(?:to|not\.)/.test(lineText) || /\bError:?\b/.test(lineText)
5284
+ );
5285
+ const acc = [];
5286
+ const start = hint >= 0 ? hint : 0;
5287
+ for (let i = start; i < plain.length; i += 1) {
5288
+ const ln = plain[i];
5289
+ if (!ln.trim()) {
5290
+ break;
5291
+ }
5292
+ if (isStackLine(ln)) {
5293
+ break;
5294
+ }
5295
+ acc.push(ln);
5296
+ }
5297
+ return acc;
5298
+ })();
5299
+ const collapsedForTail = collapseStacks(ch.lines.slice(0));
5300
+ const stackPreview = ctx.showStacks ? collapsedForTail.filter((ln) => isStackLine(stripAnsiSimple(ln))).filter((ln) => ctx.projectHint.test(stripAnsiSimple(ln))).slice(0, 2).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`) : [];
5301
+ out.push(
5302
+ ...fns.buildMessageSection(minimal.length ? minimal : ch.lines, details, ctx, {
5303
+ suppressDiff: hasPretty,
5304
+ stackPreview
5305
+ })
5306
+ );
5307
+ if (minimal.length === 0 && fns.buildFallbackMessageBlock) {
5308
+ out.push(...fns.buildFallbackMessageBlock(ch.lines, { messages: details.messages }));
5309
+ }
5310
+ const consoleInline = (() => {
5311
+ const plain = ch.lines.map((ln) => stripAnsiSimple(ln));
5312
+ const cand = plain.filter((ln) => /\bconsole\.(error|warn)\s*\(/i.test(ln) || /^\s*Error:/.test(ln)).map((ln) => ln.trim()).filter((ln) => ln.length > 0).sort((a, b) => b.length - a.length).slice(0, 3);
5313
+ return cand;
5314
+ })();
5315
+ if (consoleInline.length > 0) {
5316
+ out.push(ansi.dim(" Console errors:"), ...consoleInline.map((ln) => ` ${ln}`), "");
5317
+ }
5318
+ if (ctx.showStacks && fns.buildStackSection && stackPreview.length === 0) {
5319
+ const collapsed = collapseStacks(ch.lines.slice(0));
5320
+ out.push(...fns.buildStackSection(collapsed, ctx));
5321
+ }
5322
+ out.push(fns.drawFailLine(), "");
5323
+ if (rel) {
5324
+ seenFailures.add(`${rel}|${ch.title}`);
4807
5325
  }
4808
- lineIndex += 1;
4809
5326
  continue;
4810
5327
  }
4811
- if (/^\s*(Test Suites:|Tests:|Snapshots:|Time:|Ran all)/.test(ln)) {
4812
- out.push(lines[lineIndex]);
4813
- lineIndex += 1;
5328
+ if (ch.tag === "Summary") {
5329
+ out.push(ch.line);
4814
5330
  continue;
4815
5331
  }
4816
- if (isStackLine(ln)) {
4817
- if (showStacks) {
4818
- const kept = collapseStacks([lines[lineIndex]]);
4819
- out.push(...kept);
5332
+ if (ch.tag === "Stack") {
5333
+ if (ctx.showStacks) {
5334
+ out.push(ch.line);
4820
5335
  }
4821
- lineIndex += 1;
4822
5336
  continue;
4823
5337
  }
4824
- out.push(lines[lineIndex]);
4825
- lineIndex += 1;
5338
+ if (!onlyFailures) {
5339
+ out.push(ch.line);
5340
+ }
4826
5341
  }
4827
- const rendered = out.join("\n");
4828
- const hadParsedTests = seenFiles.size > 0 || seenFailures.size > 0 || out.some((lineText) => /^(?:\s*)(PASS|FAIL)\b/.test(stripAnsiSimple(lineText)));
4829
- if (!hadParsedTests) {
4830
- const bridgePath = extractBridgePath(raw, cwd);
4831
- if (bridgePath && fs4.existsSync(bridgePath)) {
4832
- try {
4833
- const json = JSON.parse(fs4.readFileSync(bridgePath, "utf8"));
4834
- const bridge = coerceJestJsonToBridge(json);
4835
- const renderedFromJson = renderVitestFromJestJSON(bridge, opts);
4836
- const prefix = out.join("\n");
4837
- return prefix ? `${prefix}
4838
- ${renderedFromJson}` : renderedFromJson;
4839
- } catch {
4840
- }
5342
+ const hadParsed = seenFiles.size > 0 || seenFailures.size > 0 || out.some((lineText) => /^(?:\s*)(PASS|FAIL)\b/.test(stripAnsiSimple(lineText)));
5343
+ return { text: out.join("\n"), hadParsed };
5344
+ };
5345
+
5346
+ // src/lib/formatter/context.ts
5347
+ var fs5 = __toESM(require("node:fs"), 1);
5348
+ var makeCtx = (opts, showStacks = false) => {
5349
+ const cwd = (opts?.cwd ?? process.cwd()).replace(/\\/g, "/");
5350
+ const width = Math.max(
5351
+ 40,
5352
+ process.stdout && process.stdout.columns || 80
5353
+ );
5354
+ const projectHint = new RegExp(
5355
+ `(${cwd.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")})|(/gigworx-node/)`
5356
+ );
5357
+ const readSource2 = (file) => {
5358
+ try {
5359
+ return fs5.readFileSync(file.replace(/\\/g, "/"), "utf8").split(/\r?\n/);
5360
+ } catch {
5361
+ return [];
5362
+ }
5363
+ };
5364
+ return { cwd, width, showStacks, projectHint, editorCmd: opts?.editorCmd, readSource: readSource2 };
5365
+ };
5366
+
5367
+ // src/lib/formatter/bridge.ts
5368
+ var fs6 = __toESM(require("node:fs"), 1);
5369
+ var path10 = __toESM(require("node:path"), 1);
5370
+ var import_json52 = __toESM(require_lib(), 1);
5371
+ var colorTokens2 = {
5372
+ pass: Colors.Success,
5373
+ fail: Colors.Failure,
5374
+ skip: Colors.Skip,
5375
+ todo: Colors.Todo,
5376
+ passPill: (text) => BackgroundColors.Success(ansi.white(` ${text} `)),
5377
+ failPill: (text) => BackgroundColors.Failure(ansi.white(` ${text} `))
5378
+ };
5379
+ var by = (keySelector) => (left, right) => keySelector(left) - keySelector(right);
5380
+ var isObject = (candidateValue) => !!candidateValue && typeof candidateValue === "object";
5381
+ var asHttpList = (candidateValue) => Array.isArray(candidateValue) ? candidateValue : [];
5382
+ var summarizeUrl = (method, url, route) => {
5383
+ const base = route || url || "";
5384
+ const qs = url && url.includes("?") ? ` ? ${url.split("?")[1]}` : "";
5385
+ return [method || "", base, qs].filter(Boolean).join(" ").trim();
5386
+ };
5387
+ var stripBridgeEventsFromConsole = (maybeConsole) => {
5388
+ if (!Array.isArray(maybeConsole)) {
5389
+ return maybeConsole;
5390
+ }
5391
+ return maybeConsole.filter((entry) => {
5392
+ try {
5393
+ const raw = Array.isArray(entry.message) ? entry.message.map(String).join(" ") : String(entry.message ?? "");
5394
+ return !raw.includes("[JEST-BRIDGE-EVENT]");
5395
+ } catch {
5396
+ return true;
4841
5397
  }
5398
+ });
5399
+ };
5400
+ var extractBridgePath2 = (raw, cwd) => {
5401
+ const matches = Array.from(
5402
+ raw.matchAll(/Test results written to:\s+([^\n\r]+jest-bridge-[^\s'"]+\.json)/g)
5403
+ );
5404
+ if (!matches.length) {
5405
+ return null;
4842
5406
  }
4843
- try {
4844
- const preview = rendered.split("\n").slice(0, 2).join("\n");
4845
- console.info(`formatJestOutputVitest: produced ${out.length} lines; preview:
4846
- ${preview}`);
4847
- } catch {
5407
+ const jsonPath = (matches[matches.length - 1][1] ?? "").trim().replace(/^["'`]|["'`]$/g, "");
5408
+ return path10.isAbsolute(jsonPath) ? jsonPath : path10.resolve(cwd, jsonPath).replace(/\\/g, "/");
5409
+ };
5410
+ var isTransportError = (msg) => {
5411
+ const lowercaseMessage = (msg ?? "").toLowerCase();
5412
+ return /\bsocket hang up\b|\beconnreset\b|\betimedout\b|\beconnrefused\b|\bwrite epipe\b/.test(
5413
+ lowercaseMessage
5414
+ );
5415
+ };
5416
+ var envNumber = (name, fallback) => {
5417
+ const parsed = Number(process.env[name]);
5418
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
5419
+ };
5420
+ var HEADLAMP_HTTP_WINDOW_MS = () => envNumber("HEADLAMP_HTTP_WINDOW_MS", 3e3);
5421
+ var HEADLAMP_HTTP_STRICT_WINDOW_MS = () => envNumber("HEADLAMP_HTTP_STRICT_WINDOW_MS", 600);
5422
+ var HEADLAMP_HTTP_MIN_SCORE = () => envNumber("HEADLAMP_HTTP_MIN_SCORE", 1200);
5423
+ var HEADLAMP_HTTP_DIFF_LIMIT = () => envNumber("HEADLAMP_HTTP_DIFF_LIMIT", 6);
5424
+ var HEADLAMP_HTTP_SHOW_MISS = () => process.env.HEADLAMP_HTTP_MISS === "1";
5425
+ var eventsNear = (http, ts, testPath, windowMs = HEADLAMP_HTTP_WINDOW_MS()) => {
5426
+ if (typeof ts !== "number" || !Number.isFinite(ts)) {
5427
+ return [];
5428
+ }
5429
+ return http.filter((e) => {
5430
+ const timeOk = typeof e.timestampMs === "number" && Math.abs(e.timestampMs - ts) <= windowMs;
5431
+ const pathOk = !testPath || e.testPath === testPath;
5432
+ return timeOk && pathOk;
5433
+ });
5434
+ };
5435
+ var parseMethodPathFromTitle = (title) => {
5436
+ if (!title) {
5437
+ return {};
5438
+ }
5439
+ const matchResult = title.match(/\b(GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)\s+([^\s)]+)/i);
5440
+ return matchResult ? { method: matchResult[1]?.toUpperCase(), path: matchResult[2] } : {};
5441
+ };
5442
+ var isHttpStatusNumber = (statusNumber) => typeof statusNumber === "number" && statusNumber >= 100 && statusNumber <= 599;
5443
+ var hasStatusSemantics = (assertionLike) => {
5444
+ if (!assertionLike) {
5445
+ return false;
5446
+ }
5447
+ if (isHttpStatusNumber(assertionLike.expectedNumber) || isHttpStatusNumber(assertionLike.receivedNumber)) {
5448
+ return true;
4848
5449
  }
4849
- return rendered;
5450
+ const combinedRaw = `${assertionLike.matcher ?? ""} ${assertionLike.message ?? ""}`;
5451
+ const combinedMessage = combinedRaw.toLowerCase();
5452
+ return /\bstatus(code)?\b|\btohaves(tatus|tatuscode)\b/.test(combinedMessage);
4850
5453
  };
4851
- var isBridgeJSONLike = (candidate) => {
4852
- const candidateValue = candidate;
4853
- return typeof candidateValue === "object" && candidateValue !== null && "aggregated" in candidateValue;
5454
+ var fileSuggestsHttp = (relPath2) => /(?:^|\/)(routes?|api|controllers?|e2e|integration)(?:\/|\.test\.)/i.test(relPath2);
5455
+ var inferHttpNumbersFromText = (lines) => {
5456
+ const text = lines.join("\n");
5457
+ const match = text.match(/Expected:\s*(\d{3})[\s\S]*?Received:\s*(\d{3})/i);
5458
+ if (match) {
5459
+ return { expectedNumber: Number(match[1]), receivedNumber: Number(match[2]) };
5460
+ }
5461
+ return {};
5462
+ };
5463
+ var titleSuggestsHttp = (title) => {
5464
+ const { method, path: parsedPath } = parseMethodPathFromTitle(title);
5465
+ return Boolean(method || parsedPath && parsedPath.startsWith("/"));
5466
+ };
5467
+ var isHttpRelevant = (ctx) => {
5468
+ const assertionCtx = ctx.assertion;
5469
+ return ctx.hasTransportSignal || ctx.httpCountInSameTest > 0 || titleSuggestsHttp(ctx.title) || hasStatusSemantics(assertionCtx) || fileSuggestsHttp(ctx.relPath);
5470
+ };
5471
+ var routeSimilarityScore = (hint, evt) => {
5472
+ if (!hint.path && !hint.method) {
5473
+ return 0;
5474
+ }
5475
+ const methodOk = hint.method && evt.method ? Number(hint.method === evt.method) : 0;
5476
+ const route = evt.route || evt.url || "";
5477
+ if (!route) {
5478
+ return methodOk * 10;
5479
+ }
5480
+ if (hint.path && route === hint.path) {
5481
+ return 500 + methodOk * 50;
5482
+ }
5483
+ if (hint.path && route.endsWith(hint.path)) {
5484
+ return 300 + methodOk * 50;
5485
+ }
5486
+ if (hint.path && route.includes(hint.path)) {
5487
+ return 200 + methodOk * 50;
5488
+ }
5489
+ return methodOk * 10;
5490
+ };
5491
+ var scoreHttpForAssertion = (assertion, titleHint) => (candidateEvent) => {
5492
+ const tsA = assertion.timestampMs;
5493
+ const tsH = candidateEvent.timestampMs;
5494
+ const window = isTransportError(assertion.message) ? HEADLAMP_HTTP_STRICT_WINDOW_MS() : HEADLAMP_HTTP_WINDOW_MS();
5495
+ const timeScore = typeof tsA === "number" && typeof tsH === "number" ? Math.max(0, window - Math.abs(tsA - tsH)) : 0;
5496
+ const statusScore = typeof assertion.receivedNumber === "number" && candidateEvent.statusCode === assertion.receivedNumber ? 1500 : typeof assertion.expectedNumber === "number" && candidateEvent.statusCode === assertion.expectedNumber ? 1200 : (candidateEvent.statusCode ?? 0) >= 400 ? 800 : 0;
5497
+ const routeScore = routeSimilarityScore(titleHint, candidateEvent);
5498
+ const specificity = candidateEvent.route ? 80 : candidateEvent.url ? 40 : 0;
5499
+ return timeScore + statusScore + routeScore + specificity;
5500
+ };
5501
+ var pickRelevantHttp = (assertion, http, ctx) => {
5502
+ const hint = parseMethodPathFromTitle(ctx.title);
5503
+ const nameMatches = (leftName, rightName) => !!leftName && !!rightName && (leftName === rightName || leftName.includes(rightName) || rightName.includes(leftName));
5504
+ const sameTest = (leftCtx, rightCtx) => !!leftCtx && !!rightCtx && leftCtx.testPath === rightCtx.testPath && nameMatches(leftCtx.currentTestName, rightCtx.currentTestName);
5505
+ const strictPool = http.filter(
5506
+ (httpEvent) => sameTest(assertion, httpEvent) || sameTest(ctx, httpEvent)
5507
+ );
5508
+ const windowMs = isTransportError(assertion.message) ? HEADLAMP_HTTP_STRICT_WINDOW_MS() : HEADLAMP_HTTP_WINDOW_MS();
5509
+ let pool = strictPool;
5510
+ if (!pool.length) {
5511
+ pool = http.filter(
5512
+ (e) => e.testPath === ctx.testPath && typeof assertion.timestampMs === "number" && typeof e.timestampMs === "number" && Math.abs(e.timestampMs - assertion.timestampMs) <= windowMs
5513
+ );
5514
+ }
5515
+ if (!pool.length) {
5516
+ pool = http.filter(
5517
+ (e) => typeof assertion.timestampMs === "number" && typeof e.timestampMs === "number" && Math.abs(e.timestampMs - assertion.timestampMs) <= windowMs
5518
+ );
5519
+ }
5520
+ if (!pool.length) {
5521
+ return void 0;
5522
+ }
5523
+ const scored = pool.map((httpEvent) => ({ h: httpEvent, s: scoreHttpForAssertion(assertion, hint)(httpEvent) })).sort((leftScore, rightScore) => rightScore.s - leftScore.s);
5524
+ const [best] = scored;
5525
+ const threshold = isTransportError(assertion.message) ? Math.max(HEADLAMP_HTTP_MIN_SCORE(), 1400) : HEADLAMP_HTTP_MIN_SCORE();
5526
+ return best && best.s >= threshold ? best.h : void 0;
4854
5527
  };
4855
- function coerceJestJsonToBridge(raw) {
5528
+ var isBridgeJSONLike = (candidateValue) => !!candidateValue && typeof candidateValue === "object" && "aggregated" in candidateValue;
5529
+ var coerceJestJsonToBridge = (raw) => {
4856
5530
  if (isBridgeJSONLike(raw)) {
4857
5531
  return raw;
4858
5532
  }
@@ -4862,18 +5536,21 @@ function coerceJestJsonToBridge(raw) {
4862
5536
  }
4863
5537
  return {
4864
5538
  startTime: Number(j.startTime ?? Date.now()),
4865
- testResults: j.testResults.map((testFileResult) => ({
4866
- testFilePath: testFileResult.testFilePath || testFileResult.name || "",
4867
- status: testFileResult.status,
4868
- failureMessage: testFileResult.failureMessage || "",
4869
- failureDetails: testFileResult.failureDetails ?? [],
4870
- testResults: (testFileResult.assertionResults || []).map((assertion) => ({
5539
+ testResults: j.testResults.map((tr) => ({
5540
+ testFilePath: tr.testFilePath || tr.name || "",
5541
+ status: tr.status,
5542
+ failureMessage: tr.failureMessage || "",
5543
+ failureDetails: tr.failureDetails ?? [],
5544
+ testExecError: tr.testExecError ?? null,
5545
+ console: tr.console ?? null,
5546
+ testResults: (tr.assertionResults || []).map((assertion) => ({
4871
5547
  title: assertion.title,
4872
5548
  fullName: assertion.fullName || [...assertion.ancestorTitles || [], assertion.title].join(" "),
4873
5549
  status: assertion.status,
4874
5550
  duration: assertion.duration || 0,
4875
5551
  location: assertion.location ?? null,
4876
- failureMessages: assertion.failureMessages || []
5552
+ failureMessages: assertion.failureMessages || [],
5553
+ failureDetails: assertion.failureDetails || []
4877
5554
  }))
4878
5555
  })),
4879
5556
  aggregated: {
@@ -4889,21 +5566,20 @@ function coerceJestJsonToBridge(raw) {
4889
5566
  success: j.success
4890
5567
  }
4891
5568
  };
4892
- }
4893
- var vitestFooter = (agg, _startedAt, durationMs) => {
5569
+ };
5570
+ var vitestFooter = (agg, durationMs) => {
4894
5571
  const files = [
4895
- agg.numFailedTestSuites ? colorTokens.fail(`${agg.numFailedTestSuites} failed`) : "",
4896
- agg.numPassedTestSuites ? colorTokens.pass(`${agg.numPassedTestSuites} passed`) : "",
4897
- agg.numPendingTests ? colorTokens.skip(`${agg.numPendingTests} skipped`) : ""
5572
+ agg.numFailedTestSuites ? colorTokens2.fail(`${agg.numFailedTestSuites} failed`) : "",
5573
+ agg.numPassedTestSuites ? colorTokens2.pass(`${agg.numPassedTestSuites} passed`) : "",
5574
+ agg.numPendingTests ? colorTokens2.skip(`${agg.numPendingTests} skipped`) : ""
4898
5575
  ].filter(Boolean).join(ansi.dim(" | "));
4899
5576
  const tests = [
4900
- agg.numFailedTests ? colorTokens.fail(`${agg.numFailedTests} failed`) : "",
4901
- agg.numPassedTests ? colorTokens.pass(`${agg.numPassedTests} passed`) : "",
4902
- agg.numPendingTests ? colorTokens.skip(`${agg.numPendingTests} skipped`) : "",
4903
- agg.numTodoTests ? colorTokens.todo(`${agg.numTodoTests} todo`) : ""
5577
+ agg.numFailedTests ? colorTokens2.fail(`${agg.numFailedTests} failed`) : "",
5578
+ agg.numPassedTests ? colorTokens2.pass(`${agg.numPassedTests} passed`) : "",
5579
+ agg.numPendingTests ? colorTokens2.skip(`${agg.numPendingTests} skipped`) : "",
5580
+ agg.numTodoTests ? colorTokens2.todo(`${agg.numTodoTests} todo`) : ""
4904
5581
  ].filter(Boolean).join(ansi.dim(" | "));
4905
- const durMs = typeof durationMs === "number" ? durationMs : typeof agg.runTimeMs === "number" ? agg.runTimeMs : void 0;
4906
- const time = durMs != null ? `${Math.max(0, Math.round(durMs))}ms` : "";
5582
+ const time = durationMs != null ? `${Math.max(0, Math.round(durationMs))}ms` : typeof agg.runTimeMs === "number" ? `${Math.max(0, Math.round(agg.runTimeMs))}ms` : "";
4907
5583
  const thread = ansi.dim("(in thread 0ms, 0.00%)");
4908
5584
  return [
4909
5585
  `${ansi.bold("Test Files")} ${files} ${ansi.dim(`(${agg.numTotalTestSuites})`)}`,
@@ -4911,20 +5587,14 @@ var vitestFooter = (agg, _startedAt, durationMs) => {
4911
5587
  `${ansi.bold("Time")} ${time} ${thread}`
4912
5588
  ].join("\n");
4913
5589
  };
4914
- function renderVitestFromJestJSON(data, opts) {
4915
- const cwd = (opts?.cwd ?? process.cwd()).replace(/\\/g, "/");
4916
- const projectHint = new RegExp(
4917
- `(${cwd.replace(/[.*+?^${}()|[\\]\\\\]/g, "\\$&")})|(/gigworx-node/)`
4918
- );
4919
- const ctx = { projectHint, editorCmd: opts?.editorCmd, showStacks: true };
4920
- const onlyFailures = Boolean(opts?.onlyFailures);
5590
+ var renderVitestFromJestJSON = (data, ctx, opts) => {
4921
5591
  const out = [];
5592
+ const onlyFailures = Boolean(opts?.onlyFailures);
4922
5593
  if (!onlyFailures) {
4923
- out.push(renderRunLine(cwd));
4924
- out.push("");
5594
+ out.push(`${BackgroundColors.Run(ansi.white(" RUN "))} ${ansi.dim(ctx.cwd)}`, "");
4925
5595
  }
4926
5596
  for (const file of data.testResults) {
4927
- const rel = file.testFilePath.replace(/\\/g, "/").replace(`${cwd}/`, "");
5597
+ const rel = file.testFilePath.replace(/\\/g, "/").replace(`${ctx.cwd}/`, "");
4928
5598
  const failed = file.testResults.filter((assertion) => assertion.status === "failed");
4929
5599
  if (!onlyFailures) {
4930
5600
  out.push(...buildPerFileOverview(rel, file.testResults));
@@ -4932,79 +5602,490 @@ function renderVitestFromJestJSON(data, opts) {
4932
5602
  if (!(onlyFailures && failed.length === 0)) {
4933
5603
  out.push(buildFileBadgeLine(rel, failed.length));
4934
5604
  }
4935
- if (file.failureMessage && failed.length === 0) {
5605
+ let httpSorted = [];
5606
+ let assertionEvents = [];
5607
+ {
5608
+ const parseBridge = (consoleEntries) => {
5609
+ const http = [];
5610
+ const assertions = [];
5611
+ if (!Array.isArray(consoleEntries)) {
5612
+ return { http, assertions };
5613
+ }
5614
+ for (const entry of consoleEntries) {
5615
+ const rec = entry;
5616
+ const rawMsgVal = rec && typeof rec.message !== "undefined" ? rec.message : "";
5617
+ const raw = Array.isArray(rawMsgVal) ? rawMsgVal.map(String).join(" ") : String(rawMsgVal ?? "");
5618
+ if (!raw.includes("[JEST-BRIDGE-EVENT]")) {
5619
+ continue;
5620
+ }
5621
+ const jsonText = raw.split("[JEST-BRIDGE-EVENT]").pop()?.trim() ?? "";
5622
+ try {
5623
+ const evt = import_json52.default.parse(jsonText);
5624
+ const type = evt?.type;
5625
+ if (type === "httpResponse") {
5626
+ const timestampMs = Number(evt.timestampMs ?? Date.now());
5627
+ http.push({
5628
+ kind: "response",
5629
+ timestampMs,
5630
+ method: evt.method,
5631
+ url: evt.url,
5632
+ route: evt.route,
5633
+ statusCode: evt.statusCode,
5634
+ durationMs: evt.durationMs,
5635
+ contentType: evt.contentType,
5636
+ requestId: evt.requestId,
5637
+ json: evt.json,
5638
+ bodyPreview: evt.bodyPreview,
5639
+ testPath: evt.testPath,
5640
+ currentTestName: evt.currentTestName
5641
+ });
5642
+ } else if (type === "httpAbort") {
5643
+ http.push({
5644
+ kind: "abort",
5645
+ timestampMs: Number(evt.timestampMs ?? Date.now()),
5646
+ method: evt.method,
5647
+ url: evt.url,
5648
+ route: evt.route,
5649
+ durationMs: evt.durationMs,
5650
+ testPath: evt.testPath,
5651
+ currentTestName: evt.currentTestName
5652
+ });
5653
+ } else if (type === "httpResponseBatch") {
5654
+ const list = asHttpList(evt?.events);
5655
+ for (const item of list) {
5656
+ const anyItem = item;
5657
+ http.push({
5658
+ timestampMs: Number(anyItem.timestampMs ?? Date.now()),
5659
+ method: anyItem.method,
5660
+ url: anyItem.url,
5661
+ route: anyItem.route,
5662
+ statusCode: anyItem.statusCode,
5663
+ durationMs: anyItem.durationMs,
5664
+ contentType: anyItem.contentType,
5665
+ requestId: anyItem.requestId,
5666
+ json: anyItem.json,
5667
+ bodyPreview: anyItem.bodyPreview,
5668
+ testPath: evt.testPath,
5669
+ currentTestName: evt.currentTestName
5670
+ });
5671
+ }
5672
+ } else if (type === "assertionFailure") {
5673
+ assertions.push({
5674
+ timestampMs: typeof evt.timestampMs === "number" ? evt.timestampMs : void 0,
5675
+ matcher: evt.matcher,
5676
+ expectedNumber: typeof evt.expectedNumber === "number" ? evt.expectedNumber : void 0,
5677
+ receivedNumber: typeof evt.receivedNumber === "number" ? evt.receivedNumber : void 0,
5678
+ message: typeof evt.message === "string" ? evt.message : void 0,
5679
+ stack: typeof evt.stack === "string" ? evt.stack : void 0,
5680
+ testPath: evt.testPath,
5681
+ currentTestName: evt.currentTestName,
5682
+ expectedPreview: typeof evt.expectedPreview === "string" ? evt.expectedPreview : void 0,
5683
+ actualPreview: typeof evt.actualPreview === "string" ? evt.actualPreview : void 0
5684
+ });
5685
+ }
5686
+ } catch {
5687
+ }
5688
+ }
5689
+ return { http, assertions };
5690
+ };
5691
+ const parsed = parseBridge(file.console);
5692
+ httpSorted = [...parsed.http].sort(by((event) => event.timestampMs));
5693
+ assertionEvents = parsed.assertions;
5694
+ }
5695
+ const inSameCtx = (testPath, testName) => httpSorted.filter(
5696
+ (event) => event.testPath === testPath && event.currentTestName === testName
5697
+ );
5698
+ if (file.failureMessage || file.testExecError) {
4936
5699
  const lines = file.failureMessage.split(/\r?\n/);
4937
- const details = linesFromDetails(file.failureDetails);
4938
- const mergedForStack = collapseStacks([...lines, ...details.stacks]);
4939
- const synthLoc = deepestProjectLoc(mergedForStack, projectHint);
5700
+ const combinedDetails = (() => {
5701
+ const base = linesFromDetails(file.failureDetails);
5702
+ const exec = linesFromDetails(
5703
+ Array.isArray(file.testExecError) ? file.testExecError : [file.testExecError]
5704
+ );
5705
+ return {
5706
+ stacks: [...base.stacks, ...exec.stacks],
5707
+ messages: [...base.messages, ...exec.messages]
5708
+ };
5709
+ })();
5710
+ const mergedForStack = collapseStacks([...lines, ...combinedDetails.stacks]);
5711
+ const synthLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
4940
5712
  out.push(...buildCodeFrameSection(lines, ctx, synthLoc));
4941
- const payload = extractExpectedReceived(file.failureDetails, lines);
4942
- const hasPretty = payload.expected !== void 0 || payload.received !== void 0;
4943
- out.push(...renderPrettyDiff(payload));
4944
- const stackPreview = ctx.showStacks ? firstProjectFrames(mergedForStack, projectHint, 2) : [];
5713
+ const payloadPretty = buildPrettyDiffSection(file.failureDetails, lines);
5714
+ out.push(...payloadPretty);
5715
+ const hasPretty = payloadPretty.length > 0;
5716
+ const stackPreview = ctx.showStacks ? mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).filter((ln) => ctx.projectHint.test(stripAnsiSimple(ln))).slice(0, 2).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`) : [];
4945
5717
  out.push(
4946
- ...buildMessageSection(lines, details, ctx, {
5718
+ ...buildMessageSection(lines, combinedDetails, ctx, {
4947
5719
  suppressDiff: hasPretty,
4948
5720
  stackPreview
4949
5721
  })
4950
5722
  );
4951
- out.push(...buildConsoleSection(file.console ?? null));
5723
+ out.push(...buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null)));
4952
5724
  if (ctx.showStacks && stackPreview.length === 0) {
4953
- out.push(...buildStackSection(mergedForStack, ctx));
5725
+ const tail = mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
5726
+ if (tail.length) {
5727
+ out.push(ansi.dim(" Stack:"), ...tail, "");
5728
+ }
4954
5729
  }
4955
5730
  }
4956
- for (const failedAssertion of failed) {
5731
+ for (const assertion of failed) {
4957
5732
  out.push(drawFailLine());
4958
- const header = `${rel} > ${failedAssertion.fullName}`;
4959
- const messagesArray = failedAssertion.failureMessages.length > 0 ? failedAssertion.failureMessages : [""];
4960
- const details = linesFromDetails(file.failureDetails);
5733
+ const header = `${rel} > ${assertion.fullName}`;
5734
+ const messagesArray = (() => {
5735
+ if (assertion.failureMessages && assertion.failureMessages.length > 0) {
5736
+ return assertion.failureMessages;
5737
+ }
5738
+ if (file.failureMessage && file.failureMessage.trim().length > 0) {
5739
+ return file.failureMessage.split(/\r?\n/);
5740
+ }
5741
+ const linesFromMatcher = linesFromDetails(
5742
+ assertion.failureDetails || file.failureDetails
5743
+ ).messages;
5744
+ if (Array.isArray(linesFromMatcher) && linesFromMatcher.length > 0) {
5745
+ return linesFromMatcher;
5746
+ }
5747
+ return [""];
5748
+ })();
5749
+ const details = linesFromDetails(assertion.failureDetails || file.failureDetails);
5750
+ const matcherMsg = (() => {
5751
+ try {
5752
+ const arr = assertion.failureDetails || file.failureDetails;
5753
+ if (!arr) {
5754
+ return [];
5755
+ }
5756
+ for (const detailEntry of arr) {
5757
+ const obj = detailEntry && typeof detailEntry === "object" ? detailEntry : null;
5758
+ const mr = obj && obj.matcherResult && typeof obj.matcherResult === "object" ? obj.matcherResult : null;
5759
+ if (mr && typeof mr.message === "string" && mr.message.trim()) {
5760
+ const name = typeof mr.matcherName === "string" ? mr.matcherName : "";
5761
+ const matcherHeader = name ? ` ${ansi.bold("Matcher:")} ${ansi.yellow(name)}` : "";
5762
+ const bodyHeader = ` ${ansi.bold("Message:")}`;
5763
+ const body = String(mr.message).split(/\r?\n/).slice(0, 6).map((ln) => ` ${ansi.yellow(ln)}`);
5764
+ return [matcherHeader, bodyHeader, ...body, ""].filter(Boolean);
5765
+ }
5766
+ }
5767
+ } catch {
5768
+ }
5769
+ return [];
5770
+ })();
4961
5771
  const mergedForStack = collapseStacks([...messagesArray, ...details.stacks]);
4962
- const deepestLoc = deepestProjectLoc(mergedForStack, projectHint);
4963
- const locLink = deepestLoc && (() => {
4964
- const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, opts?.editorCmd);
4965
- const base = `${path9.basename(deepestLoc.file)}:${deepestLoc.line}`;
5772
+ const deepestLoc = deepestProjectLoc(mergedForStack, ctx.projectHint);
5773
+ const locLink = deepestLoc ? (() => {
5774
+ const href = preferredEditorHref(deepestLoc.file, deepestLoc.line, ctx.editorCmd);
5775
+ const base = `${deepestLoc.file.split("/").pop()}:${deepestLoc.line}`;
4966
5776
  return osc8(base, href);
4967
- })();
5777
+ })() : void 0;
5778
+ const bullet = (text) => `${Colors.Failure("\xD7")} ${ansi.white(text)}`;
4968
5779
  const headerLine = `${ansi.white(header)}${locLink ? ` ${ansi.dim(`(${locLink})`)}` : ""}`;
4969
- const bullet = (text) => `${colorTokens.fail("\xD7")} ${ansi.white(text)}`;
4970
5780
  out.push(bullet(headerLine));
4971
5781
  const msgLines = messagesArray.join("\n").split("\n");
4972
- const assertFallback = deepestLoc || failedAssertion.location && {
4973
- file: file.testFilePath,
4974
- line: failedAssertion.location.line
4975
- };
4976
- out.push("", ...buildCodeFrameSection(msgLines, ctx, assertFallback), "");
4977
- const payload = extractExpectedReceived(file.failureDetails, msgLines);
4978
- const hasPretty = payload.expected !== void 0 || payload.received !== void 0;
4979
- out.push(...renderPrettyDiff(payload));
4980
- const stackPreview = ctx.showStacks ? firstProjectFrames(mergedForStack, projectHint, 2) : [];
5782
+ const assertFallback = deepestLoc || assertion.location && { file: file.testFilePath, line: assertion.location.line };
5783
+ out.push("", ...buildCodeFrameSection(msgLines, ctx, assertFallback || void 0), "");
5784
+ const pretty = buildPrettyDiffSection(
5785
+ assertion.failureDetails || file.failureDetails,
5786
+ msgLines
5787
+ );
5788
+ out.push(...pretty);
5789
+ const hasPretty = pretty.length > 0;
5790
+ const stackPreview = ctx.showStacks ? mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).filter((ln) => ctx.projectHint.test(stripAnsiSimple(ln))).slice(0, 2).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`) : [];
5791
+ if (matcherMsg.length) {
5792
+ out.push(...matcherMsg);
5793
+ }
4981
5794
  out.push(
4982
5795
  ...buildMessageSection(msgLines, details, ctx, { suppressDiff: hasPretty, stackPreview })
4983
5796
  );
4984
- if (ctx.showStacks && stackPreview.length === 0) {
4985
- out.push(
4986
- ...buildStackSection(
4987
- mergedForStack,
4988
- ctx,
4989
- failedAssertion.location ? { file: file.testFilePath, line: failedAssertion.location.line } : null
4990
- )
5797
+ {
5798
+ const HEADLAMP_HTTP_DIFF_LIMIT_LOCAL = () => HEADLAMP_HTTP_DIFF_LIMIT();
5799
+ const safeParseJSON = (text) => {
5800
+ try {
5801
+ return text ? import_json52.default.parse(text) : void 0;
5802
+ } catch {
5803
+ return void 0;
5804
+ }
5805
+ };
5806
+ const jsonDiff = (expected, actual, limit = HEADLAMP_HTTP_DIFF_LIMIT_LOCAL()) => {
5807
+ const outChanges = [];
5808
+ const queue = [];
5809
+ queue.push({
5810
+ pathSoFar: "$",
5811
+ expectedValue: expected,
5812
+ actualValue: actual
5813
+ });
5814
+ while (queue.length && outChanges.length < limit) {
5815
+ const { pathSoFar, expectedValue, actualValue } = queue.shift();
5816
+ const expectedIsObj = expectedValue && typeof expectedValue === "object";
5817
+ const actualIsObj = actualValue && typeof actualValue === "object";
5818
+ if (!expectedIsObj && !actualIsObj) {
5819
+ if (JSON.stringify(expectedValue) !== JSON.stringify(actualValue)) {
5820
+ outChanges.push({
5821
+ kind: "changed",
5822
+ path: pathSoFar,
5823
+ preview: `${String(expectedValue)} \u2192 ${String(actualValue)}`
5824
+ });
5825
+ }
5826
+ } else if (expectedIsObj && !actualIsObj) {
5827
+ outChanges.push({
5828
+ kind: "changed",
5829
+ path: pathSoFar,
5830
+ preview: "[object] \u2192 primitive"
5831
+ });
5832
+ } else if (!expectedIsObj && actualIsObj) {
5833
+ outChanges.push({
5834
+ kind: "changed",
5835
+ path: pathSoFar,
5836
+ preview: "primitive \u2192 [object]"
5837
+ });
5838
+ } else {
5839
+ const expectedKeys = new Set(Object.keys(expectedValue));
5840
+ const actualKeys = new Set(Object.keys(actualValue));
5841
+ for (const key of expectedKeys) {
5842
+ if (!actualKeys.has(key) && outChanges.length < limit) {
5843
+ outChanges.push({ kind: "removed", path: `${pathSoFar}.${key}` });
5844
+ }
5845
+ }
5846
+ for (const key of actualKeys) {
5847
+ if (!expectedKeys.has(key) && outChanges.length < limit) {
5848
+ outChanges.push({ kind: "added", path: `${pathSoFar}.${key}` });
5849
+ }
5850
+ }
5851
+ for (const key of expectedKeys) {
5852
+ if (actualKeys.has(key) && outChanges.length < limit) {
5853
+ queue.push({
5854
+ pathSoFar: `${pathSoFar}.${key}`,
5855
+ expectedValue: expectedValue[key],
5856
+ actualValue: actualValue[key]
5857
+ });
5858
+ }
5859
+ }
5860
+ }
5861
+ }
5862
+ return outChanges;
5863
+ };
5864
+ const importantMessages = (json) => {
5865
+ const msgs = [];
5866
+ try {
5867
+ const obj = isObject(json) ? json : {};
5868
+ const pushMaybe = (candidate) => {
5869
+ if (typeof candidate === "string" && candidate.trim()) {
5870
+ msgs.push(candidate);
5871
+ }
5872
+ };
5873
+ pushMaybe(obj.displayMessage);
5874
+ pushMaybe(obj.message);
5875
+ if (Array.isArray(obj.errors)) {
5876
+ for (const element of obj.errors) {
5877
+ pushMaybe(isObject(element) ? element.message : void 0);
5878
+ }
5879
+ }
5880
+ if (Array.isArray(obj.data)) {
5881
+ for (const element of obj.data) {
5882
+ pushMaybe(isObject(element) ? element.message : void 0);
5883
+ }
5884
+ }
5885
+ } catch {
5886
+ }
5887
+ return msgs.slice(0, 2);
5888
+ };
5889
+ const nameMatches = (leftName, rightName) => !!leftName && !!rightName && (leftName === rightName || leftName.includes(rightName) || rightName.includes(leftName));
5890
+ const corresponding = assertionEvents.find(
5891
+ (aevt) => aevt.testPath === file.testFilePath && nameMatches(aevt.currentTestName, assertion.title)
5892
+ ) ?? assertion;
5893
+ const perTestSlice = inSameCtx(file.testFilePath, assertion.title);
5894
+ const nearByTime = eventsNear(
5895
+ httpSorted,
5896
+ corresponding?.timestampMs,
5897
+ file.testFilePath
4991
5898
  );
5899
+ const hasAbort = perTestSlice.some((event) => event.kind === "abort");
5900
+ const hasTransport = isTransportError(corresponding?.message) || hasAbort;
5901
+ const httpLikely = isHttpRelevant({
5902
+ assertion: corresponding,
5903
+ title: assertion.fullName,
5904
+ relPath: rel,
5905
+ httpCountInSameTest: perTestSlice.length || nearByTime.length,
5906
+ hasTransportSignal: hasTransport
5907
+ });
5908
+ if (!httpLikely) {
5909
+ } else {
5910
+ const expPreview = corresponding?.expectedPreview;
5911
+ const actPreview = corresponding?.actualPreview;
5912
+ const parsedExpected = safeParseJSON(expPreview);
5913
+ const parsedActual = safeParseJSON(actPreview);
5914
+ let corr = corresponding;
5915
+ if (!isHttpStatusNumber(corr.expectedNumber) && !isHttpStatusNumber(corr.receivedNumber)) {
5916
+ const inferred = inferHttpNumbersFromText(msgLines);
5917
+ if (isHttpStatusNumber(inferred.expectedNumber) || isHttpStatusNumber(inferred.receivedNumber)) {
5918
+ corr = { ...corr, ...inferred };
5919
+ }
5920
+ }
5921
+ const relevant = pickRelevantHttp(
5922
+ {
5923
+ timestampMs: corr?.timestampMs,
5924
+ expectedNumber: corr?.expectedNumber,
5925
+ receivedNumber: corr?.receivedNumber,
5926
+ matcher: corr?.matcher,
5927
+ message: corr?.message,
5928
+ stack: corr?.stack,
5929
+ testPath: file.testFilePath,
5930
+ currentTestName: assertion.title
5931
+ },
5932
+ httpSorted,
5933
+ {
5934
+ testPath: file.testFilePath,
5935
+ currentTestName: assertion.title,
5936
+ title: assertion.fullName
5937
+ }
5938
+ );
5939
+ if (hasTransport) {
5940
+ const tsBase = corresponding?.timestampMs ?? 0;
5941
+ const abortCandidates = perTestSlice.filter((event) => event.kind === "abort").sort((leftEvent, rightEvent) => {
5942
+ const deltaLeft = Math.abs(tsBase - (leftEvent.timestampMs ?? 0));
5943
+ const deltaRight = Math.abs(tsBase - (rightEvent.timestampMs ?? 0));
5944
+ return deltaLeft - deltaRight;
5945
+ });
5946
+ const [nearestAbort] = abortCandidates;
5947
+ if (nearestAbort) {
5948
+ out.push(
5949
+ " HTTP:",
5950
+ `
5951
+ ${summarizeUrl(nearestAbort.method, nearestAbort.url, nearestAbort.route)} ${ansi.dim("->")} ${ansi.yellow("connection aborted")}`,
5952
+ (() => {
5953
+ const ms = nearestAbort.durationMs;
5954
+ return ms != null ? ` ${ansi.dim(`(${ms}ms)`)} ` : "";
5955
+ })(),
5956
+ "\n"
5957
+ );
5958
+ } else if (relevant) {
5959
+ } else if (HEADLAMP_HTTP_SHOW_MISS()) {
5960
+ out.push(
5961
+ " HTTP:",
5962
+ `
5963
+ ${ansi.dim("Transport error; no matching HTTP exchange in window.")}`,
5964
+ "\n"
5965
+ );
5966
+ }
5967
+ }
5968
+ if (!hasTransport && relevant) {
5969
+ const parts = [];
5970
+ const where = summarizeUrl(relevant.method, relevant.url, relevant.route);
5971
+ const line1 = [
5972
+ " HTTP:",
5973
+ `
5974
+ ${where} ${ansi.dim("->")} ${relevant.statusCode ?? "?"}`,
5975
+ (() => {
5976
+ const ms = relevant.durationMs;
5977
+ return typeof ms === "number" ? ` ${ansi.dim(`(${ms}ms)`)} ` : " ";
5978
+ })(),
5979
+ relevant.contentType ? ansi.dim(`(${relevant.contentType})`) : "",
5980
+ relevant.requestId ? ansi.dim(` reqId=${relevant.requestId}`) : ""
5981
+ ].join("");
5982
+ const expVsAct = (() => {
5983
+ if (typeof corresponding?.expectedNumber === "number" || typeof corresponding?.receivedNumber === "number") {
5984
+ const exp = corresponding?.expectedNumber != null ? String(corresponding.expectedNumber) : "?";
5985
+ const got = corresponding?.receivedNumber != null ? String(corresponding.receivedNumber) : String(relevant.statusCode ?? "?");
5986
+ return `
5987
+ Expected: ${ansi.yellow(exp)} Received: ${ansi.yellow(got)}`;
5988
+ }
5989
+ return "";
5990
+ })();
5991
+ const whyLines = importantMessages(relevant.json).map((msg) => `
5992
+ Why: ${ansi.white(msg)}`).slice(0, 1).join("");
5993
+ const diffLines = (() => {
5994
+ const rightActual = parsedActual ?? relevant.json;
5995
+ if (!parsedExpected || !rightActual) {
5996
+ return "";
5997
+ }
5998
+ const changes = jsonDiff(parsedExpected, rightActual);
5999
+ if (!changes.length) {
6000
+ return "";
6001
+ }
6002
+ const head = "\n Diff:";
6003
+ const body = changes.map((change) => {
6004
+ const marker = change.kind === "added" ? "+" : change.kind === "removed" ? "-" : "~";
6005
+ const previewText = change.preview ? `: ${ansi.dim(change.preview)}` : "";
6006
+ return `
6007
+ ${marker} ${change.path}${previewText}`;
6008
+ }).join("");
6009
+ return head + body;
6010
+ })();
6011
+ parts.push(line1, expVsAct, whyLines, diffLines, "\n");
6012
+ out.push(...parts.filter(Boolean));
6013
+ } else if (!hasTransport && !relevant && HEADLAMP_HTTP_SHOW_MISS()) {
6014
+ out.push(
6015
+ " HTTP:",
6016
+ `
6017
+ ${ansi.dim("No relevant HTTP exchange found. (HEADLAMP_HTTP_MISS=0 to hide)")}`,
6018
+ "\n"
6019
+ );
6020
+ }
6021
+ }
4992
6022
  }
4993
- out.push(drawFailLine());
4994
- out.push("");
6023
+ const minimalInfo = msgLines.every((ln) => !ln.trim());
6024
+ if (minimalInfo) {
6025
+ try {
6026
+ out.push(...buildThrownSection(assertion.failureDetails || []));
6027
+ } catch {
6028
+ }
6029
+ }
6030
+ out.push(...buildConsoleSection(stripBridgeEventsFromConsole(file.console ?? null)));
6031
+ if (ctx.showStacks && stackPreview.length === 0) {
6032
+ const tail = mergedForStack.filter((ln) => isStackLine(stripAnsiSimple(ln))).slice(-4).map((ln) => ` ${colorStackLine(String(ln), ctx.projectHint)}`);
6033
+ if (tail.length) {
6034
+ out.push(ansi.dim(" Stack:"), ...tail, "");
6035
+ }
6036
+ }
6037
+ out.push(drawFailLine(), "");
4995
6038
  }
4996
6039
  }
4997
6040
  const failedCount = data.aggregated.numFailedTests;
4998
- out.push(drawRule(colorTokens.failPill(` Failed Tests ${failedCount} `)));
6041
+ out.push(drawRule(BackgroundColors.Failure(ansi.white(` Failed Tests ${failedCount} `))));
4999
6042
  out.push("");
5000
- const footer = vitestFooter(
5001
- data.aggregated,
5002
- data.aggregated?.startTime ?? data.startTime,
5003
- data.aggregated?.runTimeMs
5004
- );
5005
- return `${out.join("\n")}
5006
- ${footer}`;
5007
- }
6043
+ out.push(vitestFooter(data.aggregated));
6044
+ return out.join("\n");
6045
+ };
6046
+ var tryBridgeFallback = (raw, ctx, opts) => {
6047
+ const bridgeJsonPath = extractBridgePath2(raw, ctx.cwd);
6048
+ if (!bridgeJsonPath || !fs6.existsSync(bridgeJsonPath)) {
6049
+ return null;
6050
+ }
6051
+ try {
6052
+ const json = import_json52.default.parse(fs6.readFileSync(bridgeJsonPath, "utf8"));
6053
+ const bridge = coerceJestJsonToBridge(json);
6054
+ return renderVitestFromJestJSON(bridge, ctx, opts);
6055
+ } catch {
6056
+ return null;
6057
+ }
6058
+ };
6059
+
6060
+ // src/lib/formatJestOutputVitest.ts
6061
+ var formatJestOutputVitest = (raw, opts) => pipe(
6062
+ { raw, opts },
6063
+ (state) => ({
6064
+ ...state,
6065
+ ctx: makeCtx(state.opts, /\bFAIL\b/.test(stripAnsiSimple(state.raw)))
6066
+ }),
6067
+ (state) => ({ ...state, chunks: parseChunks(state.raw) }),
6068
+ (state) => ({
6069
+ ...state,
6070
+ rendered: renderChunks(state.chunks, state.ctx, mkPrettyFns(), {
6071
+ onlyFailures: Boolean(state.opts?.onlyFailures)
6072
+ })
6073
+ }),
6074
+ (state) => {
6075
+ if (state.rendered.hadParsed) {
6076
+ return state.rendered.text;
6077
+ }
6078
+ const fallback = tryBridgeFallback(state.raw, state.ctx, {
6079
+ onlyFailures: Boolean(state.opts?.onlyFailures)
6080
+ });
6081
+ if (!fallback) {
6082
+ return state.rendered.text;
6083
+ }
6084
+ const prefix = state.rendered.text;
6085
+ return prefix ? `${prefix}
6086
+ ${fallback}` : fallback;
6087
+ }
6088
+ );
5008
6089
 
5009
6090
  // src/lib/program.ts
5010
6091
  var jestBin = "./node_modules/.bin/jest";
@@ -5049,7 +6130,7 @@ var mergeLcov = async () => {
5049
6130
  try {
5050
6131
  const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
5051
6132
  for (const entry of entries) {
5052
- const full = path10.join(dir, entry.name);
6133
+ const full = path11.join(dir, entry.name);
5053
6134
  if (entry.isDirectory()) {
5054
6135
  out.push(...collectLcovs(full));
5055
6136
  } else if (entry.isFile() && entry.name === "lcov.info") {
@@ -5061,8 +6142,8 @@ var mergeLcov = async () => {
5061
6142
  return out;
5062
6143
  };
5063
6144
  try {
5064
- const jestRoot = path10.join("coverage", "jest");
5065
- const candidates = [path10.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
6145
+ const jestRoot = path11.join("coverage", "jest");
6146
+ const candidates = [path11.join(jestRoot, "lcov.info"), ...collectLcovs(jestRoot)].map((candidatePath) => path11.resolve(candidatePath)).filter((absolutePath, index, arr) => arr.indexOf(absolutePath) === index);
5066
6147
  for (const filePath of candidates) {
5067
6148
  try {
5068
6149
  const content = await readOrEmpty(filePath);
@@ -5102,7 +6183,7 @@ var emitMergedCoverage = async (ui, opts) => {
5102
6183
  try {
5103
6184
  const entries = fsSync3.readdirSync(dir, { withFileTypes: true });
5104
6185
  for (const entry of entries) {
5105
- const full = path10.join(dir, entry.name);
6186
+ const full = path11.join(dir, entry.name);
5106
6187
  if (entry.isDirectory()) {
5107
6188
  out.push(...listJsons(full));
5108
6189
  } else if (entry.isFile() && entry.name === "coverage-final.json") {
@@ -5113,11 +6194,11 @@ var emitMergedCoverage = async (ui, opts) => {
5113
6194
  }
5114
6195
  return out;
5115
6196
  };
5116
- const coverageRoot = path10.join("coverage", "jest");
6197
+ const coverageRoot = path11.join("coverage", "jest");
5117
6198
  const jsonCandidates = [
5118
- path10.join(coverageRoot, "coverage-final.json"),
6199
+ path11.join(coverageRoot, "coverage-final.json"),
5119
6200
  ...listJsons(coverageRoot)
5120
- ].map((candidatePath) => path10.resolve(candidatePath)).filter((absolutePath, index, arr) => {
6201
+ ].map((candidatePath) => path11.resolve(candidatePath)).filter((absolutePath, index, arr) => {
5121
6202
  const isFirst = arr.indexOf(absolutePath) === index;
5122
6203
  const exists = fsSync3.existsSync(absolutePath);
5123
6204
  return isFirst && exists;
@@ -5179,7 +6260,7 @@ var emitMergedCoverage = async (ui, opts) => {
5179
6260
  executedTests: opts.executedTests ?? []
5180
6261
  });
5181
6262
  const context = LibReport.createContext({
5182
- dir: path10.resolve("coverage", "merged"),
6263
+ dir: path11.resolve("coverage", "merged"),
5183
6264
  coverageMap: filteredMap,
5184
6265
  defaultSummarizer: "nested"
5185
6266
  });
@@ -5247,8 +6328,8 @@ var emitMergedCoverage = async (ui, opts) => {
5247
6328
  for (const reporter of reporters) {
5248
6329
  reporter.execute(context);
5249
6330
  }
5250
- const textPath = path10.resolve("coverage", "merged", "coverage.txt");
5251
- const summaryPath = path10.resolve("coverage", "merged", "coverage-summary.txt");
6331
+ const textPath = path11.resolve("coverage", "merged", "coverage.txt");
6332
+ const summaryPath = path11.resolve("coverage", "merged", "coverage-summary.txt");
5252
6333
  const filesToPrint = [];
5253
6334
  if (fsSync3.existsSync(textPath)) {
5254
6335
  filesToPrint.push(textPath);
@@ -5347,11 +6428,57 @@ var program = async () => {
5347
6428
  return [];
5348
6429
  }
5349
6430
  };
6431
+ if (mode === "branch") {
6432
+ const resolveDefaultBranch = async () => {
6433
+ const candidates = [];
6434
+ try {
6435
+ const sym = await collect("git", ["symbolic-ref", "refs/remotes/origin/HEAD"]);
6436
+ const headRef = sym.find((ln) => ln.includes("refs/remotes/origin/"));
6437
+ if (headRef) {
6438
+ const m = /refs\/remotes\/(.+)/.exec(headRef);
6439
+ if (m && m[1]) {
6440
+ candidates.push(m[1]);
6441
+ }
6442
+ }
6443
+ } catch {
6444
+ }
6445
+ candidates.push("origin/main", "origin/master");
6446
+ for (const cand of candidates) {
6447
+ const exists = await collect("git", ["rev-parse", "--verify", cand]);
6448
+ if (exists.length > 0) {
6449
+ return cand;
6450
+ }
6451
+ }
6452
+ return void 0;
6453
+ };
6454
+ const defaultBranch = await resolveDefaultBranch();
6455
+ const mergeBase = defaultBranch ? (await collect("git", ["merge-base", "HEAD", defaultBranch]))[0] : void 0;
6456
+ const diffBase = mergeBase ?? "HEAD^";
6457
+ const branchDiff = await collect("git", [
6458
+ "diff",
6459
+ "--name-only",
6460
+ "--diff-filter=ACMRTUXB",
6461
+ diffBase,
6462
+ "HEAD"
6463
+ ]);
6464
+ const stagedNow = await collect("git", [
6465
+ "diff",
6466
+ "--name-only",
6467
+ "--diff-filter=ACMRTUXB",
6468
+ "--cached"
6469
+ ]);
6470
+ const unstagedNow = await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]);
6471
+ const untrackedNow = await collect("git", ["ls-files", "--others", "--exclude-standard"]);
6472
+ const rels2 = Array.from(
6473
+ /* @__PURE__ */ new Set([...branchDiff, ...stagedNow, ...unstagedNow, ...untrackedNow])
6474
+ );
6475
+ return rels2.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
6476
+ }
5350
6477
  const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
5351
6478
  const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
5352
6479
  const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
5353
6480
  const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
5354
- return rels.map((rel) => path10.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
6481
+ return rels.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
5355
6482
  };
5356
6483
  const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
5357
6484
  const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
@@ -5376,18 +6503,18 @@ var program = async () => {
5376
6503
  if (!token) {
5377
6504
  continue;
5378
6505
  }
5379
- const isAbs = path10.isAbsolute(token);
6506
+ const isAbs = path11.isAbsolute(token);
5380
6507
  const looksLikeRelPath = /[\\/]/.test(token);
5381
6508
  let candidateFromRoot;
5382
6509
  if (token.startsWith("/")) {
5383
- candidateFromRoot = path10.join(repoRoot, token.slice(1));
6510
+ candidateFromRoot = path11.join(repoRoot, token.slice(1));
5384
6511
  } else if (looksLikeRelPath) {
5385
- candidateFromRoot = path10.join(repoRoot, token);
6512
+ candidateFromRoot = path11.join(repoRoot, token);
5386
6513
  } else {
5387
6514
  candidateFromRoot = void 0;
5388
6515
  }
5389
6516
  const tryPushIfProd = (absPath) => {
5390
- const norm = path10.resolve(absPath).replace(/\\/g, "/");
6517
+ const norm = path11.resolve(absPath).replace(/\\/g, "/");
5391
6518
  const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
5392
6519
  if (!isTest && fsSync3.existsSync(norm)) {
5393
6520
  results.add(norm);
@@ -5409,7 +6536,7 @@ var program = async () => {
5409
6536
  }),
5410
6537
  timeoutMs: 4e3
5411
6538
  });
5412
- const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path10.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
6539
+ const matches = out.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((rel) => path11.resolve(repoRoot, rel).replace(/\\/g, "/")).filter(
5413
6540
  (abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
5414
6541
  );
5415
6542
  matches.forEach((abs) => results.add(abs));
@@ -5430,8 +6557,8 @@ var program = async () => {
5430
6557
  const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
5431
6558
  const projectConfigs = [];
5432
6559
  try {
5433
- const baseCfg = path10.resolve("jest.config.js");
5434
- const tsCfg = path10.resolve("jest.ts.config.js");
6560
+ const baseCfg = path11.resolve("jest.config.js");
6561
+ const tsCfg = path11.resolve("jest.ts.config.js");
5435
6562
  if (fsSync3.existsSync(baseCfg)) {
5436
6563
  projectConfigs.push(baseCfg);
5437
6564
  }
@@ -5448,7 +6575,7 @@ var program = async () => {
5448
6575
  );
5449
6576
  const prodSelections2 = expandedProdSelections;
5450
6577
  for (const cfg of projectConfigs) {
5451
- const cfgCwd = path10.dirname(cfg);
6578
+ const cfgCwd = path11.dirname(cfg);
5452
6579
  const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
5453
6580
  cwd: cfgCwd
5454
6581
  });
@@ -5461,7 +6588,7 @@ var program = async () => {
5461
6588
  });
5462
6589
  } catch (err) {
5463
6590
  if (isDebug()) {
5464
- console.warn(`direct selection failed for project ${path10.basename(cfg)}: ${String(err)}`);
6591
+ console.warn(`direct selection failed for project ${path11.basename(cfg)}: ${String(err)}`);
5465
6592
  }
5466
6593
  }
5467
6594
  perProjectFiles.set(cfg, directPerProject);
@@ -5473,7 +6600,7 @@ var program = async () => {
5473
6600
  )} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
5474
6601
  );
5475
6602
  for (const cfg of projectConfigs) {
5476
- const cfgCwd = path10.dirname(cfg);
6603
+ const cfgCwd = path11.dirname(cfg);
5477
6604
  const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
5478
6605
  cwd: cfgCwd
5479
6606
  });
@@ -5488,13 +6615,13 @@ var program = async () => {
5488
6615
  );
5489
6616
  const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
5490
6617
  const absFiles = candidates.map(
5491
- (candidatePath) => path10.isAbsolute(candidatePath) ? candidatePath : path10.join(repoRootForDiscovery, candidatePath)
6618
+ (candidatePath) => path11.isAbsolute(candidatePath) ? candidatePath : path11.join(repoRootForDiscovery, candidatePath)
5492
6619
  ).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
5493
6620
  const onlyOwned = await filterCandidatesForProject(
5494
6621
  cfg,
5495
6622
  jestDiscoveryArgs,
5496
6623
  absFiles,
5497
- path10.dirname(cfg)
6624
+ path11.dirname(cfg)
5498
6625
  );
5499
6626
  perProjectFiltered.set(cfg, onlyOwned);
5500
6627
  }
@@ -5506,7 +6633,7 @@ var program = async () => {
5506
6633
  if (selectionHasPaths && prodSelections.length > 0) {
5507
6634
  console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
5508
6635
  const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
5509
- const selectionKey = prodSelections.map((absPath) => path10.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
6636
+ const selectionKey = prodSelections.map((absPath) => path11.relative(repoRootForRefinement, absPath).replace(/\\/g, "/")).sort((firstPath, secondPath) => firstPath.localeCompare(secondPath)).join("|");
5510
6637
  const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
5511
6638
  const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
5512
6639
  const rgMatches = await cachedRelated2({
@@ -5536,7 +6663,7 @@ var program = async () => {
5536
6663
  cfg,
5537
6664
  jestDiscoveryArgs,
5538
6665
  rgCandidates,
5539
- path10.dirname(cfg)
6666
+ path11.dirname(cfg)
5540
6667
  );
5541
6668
  perProjectFromRg.set(cfg, owned);
5542
6669
  }
@@ -5551,9 +6678,9 @@ var program = async () => {
5551
6678
  } else {
5552
6679
  const repoRootForScan = repoRootForDiscovery;
5553
6680
  const toSeeds = (abs) => {
5554
- const rel = path10.relative(repoRootForScan, abs).replace(/\\/g, "/");
6681
+ const rel = path11.relative(repoRootForScan, abs).replace(/\\/g, "/");
5555
6682
  const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
5556
- const base = path10.basename(withoutExt);
6683
+ const base = path11.basename(withoutExt);
5557
6684
  const segs = withoutExt.split("/");
5558
6685
  const tail2 = segs.slice(-2).join("/");
5559
6686
  return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
@@ -5568,8 +6695,8 @@ var program = async () => {
5568
6695
  }
5569
6696
  };
5570
6697
  const resolveLocalImport = (fromFile, spec) => {
5571
- const baseDir = path10.dirname(fromFile);
5572
- const cand = path10.resolve(baseDir, spec);
6698
+ const baseDir = path11.dirname(fromFile);
6699
+ const cand = path11.resolve(baseDir, spec);
5573
6700
  const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
5574
6701
  for (const ext of exts) {
5575
6702
  const full = ext ? `${cand}${ext}` : cand;
@@ -5578,7 +6705,7 @@ var program = async () => {
5578
6705
  }
5579
6706
  }
5580
6707
  for (const ext of exts) {
5581
- const full = path10.join(cand, `index${ext}`);
6708
+ const full = path11.join(cand, `index${ext}`);
5582
6709
  if (fsSync3.existsSync(full)) {
5583
6710
  return full;
5584
6711
  }
@@ -5632,7 +6759,7 @@ var program = async () => {
5632
6759
  cfg,
5633
6760
  jestDiscoveryArgs,
5634
6761
  keptCandidates,
5635
- path10.dirname(cfg)
6762
+ path11.dirname(cfg)
5636
6763
  );
5637
6764
  perProjectFromScan.set(cfg, owned);
5638
6765
  }
@@ -5658,24 +6785,41 @@ var program = async () => {
5658
6785
  }
5659
6786
  if (effectiveJestFiles.length === 0) {
5660
6787
  const repoRoot = repoRootForRefinement;
6788
+ if (jestFiles.length === 0) {
6789
+ try {
6790
+ const allAcross = [];
6791
+ for (const cfg of projectConfigs) {
6792
+ const cfgCwd = path11.dirname(cfg);
6793
+ const listed = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
6794
+ cwd: cfgCwd
6795
+ });
6796
+ allAcross.push(...listed);
6797
+ }
6798
+ const uniqAll = Array.from(new Set(allAcross.map((p) => p.replace(/\\/g, "/"))));
6799
+ if (uniqAll.length > 0) {
6800
+ jestFiles = uniqAll;
6801
+ }
6802
+ } catch {
6803
+ }
6804
+ }
5661
6805
  const seeds = prodSelections.map(
5662
- (abs) => path10.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
6806
+ (abs) => path11.relative(repoRoot, abs).replace(/\\/g, "/").replace(/\.(m?[tj]sx?)$/i, "")
5663
6807
  ).flatMap((rel) => {
5664
- const base = path10.basename(rel);
6808
+ const base = path11.basename(rel);
5665
6809
  const segments = rel.split("/");
5666
6810
  return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
5667
6811
  });
5668
6812
  const includesSeed = (text) => seeds.some((seed) => text.includes(seed));
5669
6813
  const tryReadFile = async (absPath) => {
5670
6814
  try {
5671
- return await fs5.readFile(absPath, "utf8");
6815
+ return await fs7.readFile(absPath, "utf8");
5672
6816
  } catch {
5673
6817
  return "";
5674
6818
  }
5675
6819
  };
5676
6820
  const resolveLocalImport = (fromFile, spec) => {
5677
- const baseDir = path10.dirname(fromFile);
5678
- const candidate = path10.resolve(baseDir, spec);
6821
+ const baseDir = path11.dirname(fromFile);
6822
+ const candidate = path11.resolve(baseDir, spec);
5679
6823
  const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
5680
6824
  for (const ext of extensions) {
5681
6825
  const fullPath = ext ? `${candidate}${ext}` : candidate;
@@ -5684,7 +6828,7 @@ var program = async () => {
5684
6828
  }
5685
6829
  }
5686
6830
  for (const ext of extensions) {
5687
- const fullPath = path10.join(candidate, `index${ext}`);
6831
+ const fullPath = path11.join(candidate, `index${ext}`);
5688
6832
  if (fsSync3.existsSync(fullPath)) {
5689
6833
  return fullPath;
5690
6834
  }
@@ -5841,10 +6985,10 @@ var program = async () => {
5841
6985
  };
5842
6986
  const prodSeedsForRun = (() => {
5843
6987
  const changedAbs = (changedSelectionAbs ?? []).map(
5844
- (absPath) => path10.resolve(absPath).replace(/\\/g, "/")
6988
+ (absPath) => path11.resolve(absPath).replace(/\\/g, "/")
5845
6989
  );
5846
6990
  const selAbs = selectionPathsAugmented.map(
5847
- (pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
6991
+ (pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
5848
6992
  );
5849
6993
  return (changedAbs.length ? changedAbs : selAbs).filter(
5850
6994
  (abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
@@ -5859,29 +7003,50 @@ var program = async () => {
5859
7003
  const cfg = projectsToRun[projIndex];
5860
7004
  const files = perProjectFiltered.get(cfg) ?? [];
5861
7005
  if (files.length === 0) {
5862
- console.info(`Project ${path10.basename(cfg)}: 0 matching tests after filter; skipping.`);
7006
+ console.info(`Project ${path11.basename(cfg)}: 0 matching tests after filter; skipping.`);
5863
7007
  continue;
5864
7008
  }
5865
7009
  files.forEach(
5866
- (absTestPath) => executedTestFilesSet.add(path10.resolve(absTestPath).replace(/\\/g, "/"))
7010
+ (absTestPath) => executedTestFilesSet.add(path11.resolve(absTestPath).replace(/\\/g, "/"))
5867
7011
  );
5868
- const outJson = path10.join(
7012
+ const outJson = path11.join(
5869
7013
  os2.tmpdir(),
5870
7014
  `jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
5871
7015
  );
5872
- const reporterPath = path10.resolve("scripts/jest-vitest-bridge.cjs");
7016
+ const reporterPath = path11.resolve("scripts/jest-vitest-bridge.cjs");
5873
7017
  try {
5874
- if (!fsSync3.existsSync(reporterPath)) {
5875
- fsSync3.mkdirSync(path10.dirname(reporterPath), { recursive: true });
7018
+ const needsWrite = (() => {
7019
+ try {
7020
+ const existing = fsSync3.readFileSync(reporterPath, "utf8");
7021
+ return existing !== JEST_BRIDGE_REPORTER_SOURCE;
7022
+ } catch {
7023
+ return true;
7024
+ }
7025
+ })();
7026
+ if (needsWrite) {
7027
+ fsSync3.mkdirSync(path11.dirname(reporterPath), { recursive: true });
5876
7028
  fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
5877
7029
  }
7030
+ const envPath = path11.resolve("scripts/jest-bridge-env.cjs");
7031
+ try {
7032
+ const existingEnv = fsSync3.readFileSync(envPath, "utf8");
7033
+ if (existingEnv !== JEST_BRIDGE_ENV_SOURCE) {
7034
+ fsSync3.writeFileSync(envPath, JEST_BRIDGE_ENV_SOURCE, "utf8");
7035
+ }
7036
+ } catch {
7037
+ try {
7038
+ fsSync3.mkdirSync(path11.dirname(envPath), { recursive: true });
7039
+ } catch {
7040
+ }
7041
+ fsSync3.writeFileSync(envPath, JEST_BRIDGE_ENV_SOURCE, "utf8");
7042
+ }
5878
7043
  } catch (ensureReporterError) {
5879
7044
  console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
5880
7045
  }
5881
- const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) => path10.relative(repoRootForDiscovery, pathToken).replace(/\\\\/g, "/")).filter((rel) => rel && !/^\.+\//.test(rel)).map((rel) => rel.startsWith("./") ? rel : `./${rel}`);
7046
+ const selectedFilesForCoverage = selectionPathsAugmented.filter((pathToken) => /[\\/]/.test(pathToken)).filter((pathToken) => !looksLikeTestPath(pathToken)).map((pathToken) => path11.relative(repoRootForDiscovery, pathToken).replace(/\\\\/g, "/")).filter((rel) => rel && !/^\.+\//.test(rel)).map((rel) => rel.startsWith("./") ? rel : `./${rel}`);
5882
7047
  const coverageFromArgs = [];
5883
- for (const relPath of selectedFilesForCoverage) {
5884
- coverageFromArgs.push("--collectCoverageFrom", relPath);
7048
+ for (const relPath2 of selectedFilesForCoverage) {
7049
+ coverageFromArgs.push("--collectCoverageFrom", relPath2);
5885
7050
  }
5886
7051
  const { code, output } = await runWithCapture(
5887
7052
  babelNodeBin,
@@ -5891,17 +7056,16 @@ var program = async () => {
5891
7056
  jestBin,
5892
7057
  "--config",
5893
7058
  cfg,
7059
+ "--testLocationInResults",
5894
7060
  "--runTestsByPath",
5895
7061
  `--reporters=${reporterPath}`,
5896
- "--silent",
5897
7062
  "--colors",
5898
- "--json",
5899
- "--outputFile",
5900
- outJson,
7063
+ "--env",
7064
+ path11.resolve("scripts/jest-bridge-env.cjs"),
5901
7065
  ...sanitizedJestRunArgs,
5902
7066
  ...collectCoverage ? [
5903
7067
  "--coverageDirectory",
5904
- path10.join("coverage", "jest", path10.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
7068
+ path11.join("coverage", "jest", path11.basename(cfg).replace(/[^a-zA-Z0-9_.-]+/g, "_"))
5905
7069
  ] : [],
5906
7070
  ...coverageFromArgs,
5907
7071
  "--passWithNoTests",
@@ -5934,17 +7098,23 @@ var program = async () => {
5934
7098
  ...bridge,
5935
7099
  testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
5936
7100
  };
5937
- pretty = renderVitestFromJestJSON(reordered, {
5938
- cwd: repoRootForDiscovery,
5939
- ...editorCmd !== void 0 ? { editorCmd } : {},
5940
- onlyFailures
5941
- });
7101
+ pretty = renderVitestFromJestJSON(
7102
+ reordered,
7103
+ makeCtx(
7104
+ { cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
7105
+ /\bFAIL\b/.test(stripAnsiSimple(output))
7106
+ ),
7107
+ { onlyFailures }
7108
+ );
5942
7109
  } catch {
5943
- pretty = renderVitestFromJestJSON(bridge, {
5944
- cwd: repoRootForDiscovery,
5945
- ...editorCmd !== void 0 ? { editorCmd } : {},
5946
- onlyFailures
5947
- });
7110
+ pretty = renderVitestFromJestJSON(
7111
+ bridge,
7112
+ makeCtx(
7113
+ { cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
7114
+ /\bFAIL\b/.test(stripAnsiSimple(output))
7115
+ ),
7116
+ { onlyFailures }
7117
+ );
5948
7118
  }
5949
7119
  if (debug) {
5950
7120
  const preview = pretty.split("\n").slice(0, 3).join("\n");
@@ -5958,18 +7128,31 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
5958
7128
  console.info(String(jsonErr));
5959
7129
  console.info(`fallback: raw output lines=${output.split(/\r?\n/).length}`);
5960
7130
  }
5961
- const renderOpts = {
7131
+ pretty = formatJestOutputVitest(output, {
5962
7132
  cwd: repoRootForDiscovery,
5963
7133
  ...editorCmd !== void 0 ? { editorCmd } : {},
5964
7134
  onlyFailures
5965
- };
5966
- pretty = formatJestOutputVitest(output, renderOpts);
7135
+ });
5967
7136
  if (debug) {
5968
7137
  const preview = pretty.split("\n").slice(0, 3).join("\n");
5969
7138
  console.info(`pretty preview (text):
5970
7139
  ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
5971
7140
  }
5972
7141
  }
7142
+ try {
7143
+ const looksSparse = /\n\s*Error:\s*\n/.test(pretty) && !/(Message:|Thrown:|Events:|Console errors:)/.test(pretty);
7144
+ if (looksSparse) {
7145
+ const rawAlso = formatJestOutputVitest(output, {
7146
+ cwd: repoRootForDiscovery,
7147
+ ...editorCmd !== void 0 ? { editorCmd } : {},
7148
+ onlyFailures
7149
+ });
7150
+ const merged = `${stripFooter(pretty)}
7151
+ ${stripFooter(rawAlso)}`.trimEnd();
7152
+ pretty = merged;
7153
+ }
7154
+ } catch {
7155
+ }
5973
7156
  pretty = stripFooter(pretty);
5974
7157
  if (pretty.trim().length > 0) {
5975
7158
  process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
@@ -6008,10 +7191,10 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
6008
7191
  try {
6009
7192
  const prodSeeds = (() => {
6010
7193
  const changedAbs = (changedSelectionAbs ?? []).map(
6011
- (absPath) => path10.resolve(absPath).replace(/\\/g, "/")
7194
+ (absPath) => path11.resolve(absPath).replace(/\\/g, "/")
6012
7195
  );
6013
7196
  const selAbs = selectionPathsAugmented.map(
6014
- (pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
7197
+ (pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
6015
7198
  );
6016
7199
  return (changedAbs.length ? changedAbs : selAbs).filter(
6017
7200
  (abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
@@ -6025,11 +7208,18 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
6025
7208
  unified.testResults = ordered;
6026
7209
  } catch {
6027
7210
  }
6028
- const text = renderVitestFromJestJSON(unified, {
6029
- cwd: repoRootForDiscovery,
6030
- ...editorCmd !== void 0 ? { editorCmd } : {},
6031
- onlyFailures
6032
- });
7211
+ const showStacks = Boolean(unified.aggregated?.numFailedTests > 0);
7212
+ let text = renderVitestFromJestJSON(
7213
+ unified,
7214
+ makeCtx(
7215
+ { cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
7216
+ showStacks
7217
+ ),
7218
+ { onlyFailures }
7219
+ );
7220
+ if (onlyFailures) {
7221
+ text = text.split(/\r?\n/).filter((line) => !/^\s*PASS\b/.test(stripAnsiSimple(line))).join("\n");
7222
+ }
6033
7223
  if (text.trim().length > 0) {
6034
7224
  process.stdout.write(text.endsWith("\n") ? text : `${text}
6035
7225
  `);