headlamp 0.1.10 → 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(
@@ -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;
5157
+ if (typeof err.message === "string") {
5158
+ candidates.push(`message: ${err.message}`);
5159
+ }
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));
5178
+ }
5179
+ }
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);
5222
+ if (seenFiles.has(rel)) {
4744
5223
  continue;
4745
5224
  }
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) : [];
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)}`) : [];
4771
5301
  out.push(
4772
- ...buildMessageSection(
4773
- linesBlock,
4774
- detailsForMsg,
4775
- { projectHint, editorCmd: opts?.editorCmd, showStacks },
4776
- { suppressDiff: hasPretty, stackPreview }
4777
- )
5302
+ ...fns.buildMessageSection(minimal.length ? minimal : ch.lines, details, ctx, {
5303
+ suppressDiff: hasPretty,
5304
+ stackPreview
5305
+ })
4778
5306
  );
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
- );
5307
+ if (minimal.length === 0 && fns.buildFallbackMessageBlock) {
5308
+ out.push(...fns.buildFallbackMessageBlock(ch.lines, { messages: details.messages }));
4788
5309
  }
4789
- out.push(drawFailLine());
4790
- out.push("");
4791
- lineIndex = scanIndex;
4792
- continue;
4793
- }
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}/`, "");
4799
- if (seenFiles.has(rel)) {
4800
- lineIndex += 1;
4801
- continue;
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}`), "");
4802
5317
  }
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)}`);
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 [];
4841
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;
4842
5390
  }
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 {
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;
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;
5406
+ }
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;
4848
5446
  }
4849
- return rendered;
5447
+ if (isHttpStatusNumber(assertionLike.expectedNumber) || isHttpStatusNumber(assertionLike.receivedNumber)) {
5448
+ return true;
5449
+ }
5450
+ const combinedRaw = `${assertionLike.matcher ?? ""} ${assertionLike.message ?? ""}`;
5451
+ const combinedMessage = combinedRaw.toLowerCase();
5452
+ return /\bstatus(code)?\b|\btohaves(tatus|tatuscode)\b/.test(combinedMessage);
5453
+ };
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;
4850
5490
  };
4851
- var isBridgeJSONLike = (candidate) => {
4852
- const candidateValue = candidate;
4853
- return typeof candidateValue === "object" && candidateValue !== null && "aggregated" in candidateValue;
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);
@@ -5391,13 +6472,13 @@ var program = async () => {
5391
6472
  const rels2 = Array.from(
5392
6473
  /* @__PURE__ */ new Set([...branchDiff, ...stagedNow, ...unstagedNow, ...untrackedNow])
5393
6474
  );
5394
- return rels2.map((rel) => path10.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
6475
+ return rels2.map((rel) => path11.resolve(cwd, rel).replace(/\\/g, "/")).filter((abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/"));
5395
6476
  }
5396
6477
  const staged = mode === "staged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB", "--cached"]) : [];
5397
6478
  const unstagedTracked = mode === "unstaged" || mode === "all" ? await collect("git", ["diff", "--name-only", "--diff-filter=ACMRTUXB"]) : [];
5398
6479
  const untracked = mode === "unstaged" || mode === "all" ? await collect("git", ["ls-files", "--others", "--exclude-standard"]) : [];
5399
6480
  const rels = Array.from(/* @__PURE__ */ new Set([...staged, ...unstagedTracked, ...untracked]));
5400
- 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/"));
5401
6482
  };
5402
6483
  const repoRootForChanged = workspaceRoot ?? await findRepoRoot();
5403
6484
  const changedSelectionAbs = changed ? await getChangedFiles(changed, repoRootForChanged) : [];
@@ -5422,18 +6503,18 @@ var program = async () => {
5422
6503
  if (!token) {
5423
6504
  continue;
5424
6505
  }
5425
- const isAbs = path10.isAbsolute(token);
6506
+ const isAbs = path11.isAbsolute(token);
5426
6507
  const looksLikeRelPath = /[\\/]/.test(token);
5427
6508
  let candidateFromRoot;
5428
6509
  if (token.startsWith("/")) {
5429
- candidateFromRoot = path10.join(repoRoot, token.slice(1));
6510
+ candidateFromRoot = path11.join(repoRoot, token.slice(1));
5430
6511
  } else if (looksLikeRelPath) {
5431
- candidateFromRoot = path10.join(repoRoot, token);
6512
+ candidateFromRoot = path11.join(repoRoot, token);
5432
6513
  } else {
5433
6514
  candidateFromRoot = void 0;
5434
6515
  }
5435
6516
  const tryPushIfProd = (absPath) => {
5436
- const norm = path10.resolve(absPath).replace(/\\/g, "/");
6517
+ const norm = path11.resolve(absPath).replace(/\\/g, "/");
5437
6518
  const isTest = /(^|\/)tests?\//i.test(norm) || /\.(test|spec)\.[tj]sx?$/i.test(norm);
5438
6519
  if (!isTest && fsSync3.existsSync(norm)) {
5439
6520
  results.add(norm);
@@ -5455,7 +6536,7 @@ var program = async () => {
5455
6536
  }),
5456
6537
  timeoutMs: 4e3
5457
6538
  });
5458
- 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(
5459
6540
  (abs) => !abs.includes("/node_modules/") && !abs.includes("/coverage/") && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
5460
6541
  );
5461
6542
  matches.forEach((abs) => results.add(abs));
@@ -5476,8 +6557,8 @@ var program = async () => {
5476
6557
  const jestDiscoveryArgs = selectionIncludesProdPaths ? stripPathTokens(jest) : jest;
5477
6558
  const projectConfigs = [];
5478
6559
  try {
5479
- const baseCfg = path10.resolve("jest.config.js");
5480
- 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");
5481
6562
  if (fsSync3.existsSync(baseCfg)) {
5482
6563
  projectConfigs.push(baseCfg);
5483
6564
  }
@@ -5494,7 +6575,7 @@ var program = async () => {
5494
6575
  );
5495
6576
  const prodSelections2 = expandedProdSelections;
5496
6577
  for (const cfg of projectConfigs) {
5497
- const cfgCwd = path10.dirname(cfg);
6578
+ const cfgCwd = path11.dirname(cfg);
5498
6579
  const allTests = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
5499
6580
  cwd: cfgCwd
5500
6581
  });
@@ -5507,7 +6588,7 @@ var program = async () => {
5507
6588
  });
5508
6589
  } catch (err) {
5509
6590
  if (isDebug()) {
5510
- 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)}`);
5511
6592
  }
5512
6593
  }
5513
6594
  perProjectFiles.set(cfg, directPerProject);
@@ -5519,7 +6600,7 @@ var program = async () => {
5519
6600
  )} | related=${selectionIncludesProdPaths} | cwd=${repoRootForDiscovery}`
5520
6601
  );
5521
6602
  for (const cfg of projectConfigs) {
5522
- const cfgCwd = path10.dirname(cfg);
6603
+ const cfgCwd = path11.dirname(cfg);
5523
6604
  const files = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
5524
6605
  cwd: cfgCwd
5525
6606
  });
@@ -5534,13 +6615,13 @@ var program = async () => {
5534
6615
  );
5535
6616
  const candidates = selectionHasPaths && selectionLooksLikeTest ? selectionTestPaths : files;
5536
6617
  const absFiles = candidates.map(
5537
- (candidatePath) => path10.isAbsolute(candidatePath) ? candidatePath : path10.join(repoRootForDiscovery, candidatePath)
6618
+ (candidatePath) => path11.isAbsolute(candidatePath) ? candidatePath : path11.join(repoRootForDiscovery, candidatePath)
5538
6619
  ).map((absolutePath) => absolutePath.replace(/\\/g, "/"));
5539
6620
  const onlyOwned = await filterCandidatesForProject(
5540
6621
  cfg,
5541
6622
  jestDiscoveryArgs,
5542
6623
  absFiles,
5543
- path10.dirname(cfg)
6624
+ path11.dirname(cfg)
5544
6625
  );
5545
6626
  perProjectFiltered.set(cfg, onlyOwned);
5546
6627
  }
@@ -5552,7 +6633,7 @@ var program = async () => {
5552
6633
  if (selectionHasPaths && prodSelections.length > 0) {
5553
6634
  console.info(`rg related \u2192 prodSelections=${prodSelections.length} (starting)`);
5554
6635
  const repoRootForRefinement = workspaceRoot ?? await findRepoRoot();
5555
- 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("|");
5556
6637
  const { cachedRelated: cachedRelated2, findRelatedTestsFast: findRelatedTestsFast2, DEFAULT_TEST_GLOBS: DEFAULT_TEST_GLOBS2 } = await Promise.resolve().then(() => (init_fast_related(), fast_related_exports));
5557
6638
  const { DEFAULT_EXCLUDE: DEFAULT_EXCLUDE2 } = await Promise.resolve().then(() => (init_args(), args_exports));
5558
6639
  const rgMatches = await cachedRelated2({
@@ -5582,7 +6663,7 @@ var program = async () => {
5582
6663
  cfg,
5583
6664
  jestDiscoveryArgs,
5584
6665
  rgCandidates,
5585
- path10.dirname(cfg)
6666
+ path11.dirname(cfg)
5586
6667
  );
5587
6668
  perProjectFromRg.set(cfg, owned);
5588
6669
  }
@@ -5597,9 +6678,9 @@ var program = async () => {
5597
6678
  } else {
5598
6679
  const repoRootForScan = repoRootForDiscovery;
5599
6680
  const toSeeds = (abs) => {
5600
- const rel = path10.relative(repoRootForScan, abs).replace(/\\/g, "/");
6681
+ const rel = path11.relative(repoRootForScan, abs).replace(/\\/g, "/");
5601
6682
  const withoutExt = rel.replace(/\.(m?[tj]sx?)$/i, "");
5602
- const base = path10.basename(withoutExt);
6683
+ const base = path11.basename(withoutExt);
5603
6684
  const segs = withoutExt.split("/");
5604
6685
  const tail2 = segs.slice(-2).join("/");
5605
6686
  return Array.from(new Set([withoutExt, base, tail2].filter(Boolean)));
@@ -5614,8 +6695,8 @@ var program = async () => {
5614
6695
  }
5615
6696
  };
5616
6697
  const resolveLocalImport = (fromFile, spec) => {
5617
- const baseDir = path10.dirname(fromFile);
5618
- const cand = path10.resolve(baseDir, spec);
6698
+ const baseDir = path11.dirname(fromFile);
6699
+ const cand = path11.resolve(baseDir, spec);
5619
6700
  const exts = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
5620
6701
  for (const ext of exts) {
5621
6702
  const full = ext ? `${cand}${ext}` : cand;
@@ -5624,7 +6705,7 @@ var program = async () => {
5624
6705
  }
5625
6706
  }
5626
6707
  for (const ext of exts) {
5627
- const full = path10.join(cand, `index${ext}`);
6708
+ const full = path11.join(cand, `index${ext}`);
5628
6709
  if (fsSync3.existsSync(full)) {
5629
6710
  return full;
5630
6711
  }
@@ -5678,7 +6759,7 @@ var program = async () => {
5678
6759
  cfg,
5679
6760
  jestDiscoveryArgs,
5680
6761
  keptCandidates,
5681
- path10.dirname(cfg)
6762
+ path11.dirname(cfg)
5682
6763
  );
5683
6764
  perProjectFromScan.set(cfg, owned);
5684
6765
  }
@@ -5708,7 +6789,7 @@ var program = async () => {
5708
6789
  try {
5709
6790
  const allAcross = [];
5710
6791
  for (const cfg of projectConfigs) {
5711
- const cfgCwd = path10.dirname(cfg);
6792
+ const cfgCwd = path11.dirname(cfg);
5712
6793
  const listed = await discoverJestResilient([...jestDiscoveryArgs, "--config", cfg], {
5713
6794
  cwd: cfgCwd
5714
6795
  });
@@ -5722,23 +6803,23 @@ var program = async () => {
5722
6803
  }
5723
6804
  }
5724
6805
  const seeds = prodSelections.map(
5725
- (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, "")
5726
6807
  ).flatMap((rel) => {
5727
- const base = path10.basename(rel);
6808
+ const base = path11.basename(rel);
5728
6809
  const segments = rel.split("/");
5729
6810
  return Array.from(new Set([rel, base, segments.slice(-2).join("/")].filter(Boolean)));
5730
6811
  });
5731
6812
  const includesSeed = (text) => seeds.some((seed) => text.includes(seed));
5732
6813
  const tryReadFile = async (absPath) => {
5733
6814
  try {
5734
- return await fs5.readFile(absPath, "utf8");
6815
+ return await fs7.readFile(absPath, "utf8");
5735
6816
  } catch {
5736
6817
  return "";
5737
6818
  }
5738
6819
  };
5739
6820
  const resolveLocalImport = (fromFile, spec) => {
5740
- const baseDir = path10.dirname(fromFile);
5741
- const candidate = path10.resolve(baseDir, spec);
6821
+ const baseDir = path11.dirname(fromFile);
6822
+ const candidate = path11.resolve(baseDir, spec);
5742
6823
  const extensions = ["", ".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs", ".mts", ".cts"];
5743
6824
  for (const ext of extensions) {
5744
6825
  const fullPath = ext ? `${candidate}${ext}` : candidate;
@@ -5747,7 +6828,7 @@ var program = async () => {
5747
6828
  }
5748
6829
  }
5749
6830
  for (const ext of extensions) {
5750
- const fullPath = path10.join(candidate, `index${ext}`);
6831
+ const fullPath = path11.join(candidate, `index${ext}`);
5751
6832
  if (fsSync3.existsSync(fullPath)) {
5752
6833
  return fullPath;
5753
6834
  }
@@ -5904,10 +6985,10 @@ var program = async () => {
5904
6985
  };
5905
6986
  const prodSeedsForRun = (() => {
5906
6987
  const changedAbs = (changedSelectionAbs ?? []).map(
5907
- (absPath) => path10.resolve(absPath).replace(/\\/g, "/")
6988
+ (absPath) => path11.resolve(absPath).replace(/\\/g, "/")
5908
6989
  );
5909
6990
  const selAbs = selectionPathsAugmented.map(
5910
- (pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
6991
+ (pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
5911
6992
  );
5912
6993
  return (changedAbs.length ? changedAbs : selAbs).filter(
5913
6994
  (abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
@@ -5922,29 +7003,50 @@ var program = async () => {
5922
7003
  const cfg = projectsToRun[projIndex];
5923
7004
  const files = perProjectFiltered.get(cfg) ?? [];
5924
7005
  if (files.length === 0) {
5925
- 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.`);
5926
7007
  continue;
5927
7008
  }
5928
7009
  files.forEach(
5929
- (absTestPath) => executedTestFilesSet.add(path10.resolve(absTestPath).replace(/\\/g, "/"))
7010
+ (absTestPath) => executedTestFilesSet.add(path11.resolve(absTestPath).replace(/\\/g, "/"))
5930
7011
  );
5931
- const outJson = path10.join(
7012
+ const outJson = path11.join(
5932
7013
  os2.tmpdir(),
5933
7014
  `jest-bridge-${Date.now()}-${Math.random().toString(36).slice(2)}.json`
5934
7015
  );
5935
- const reporterPath = path10.resolve("scripts/jest-vitest-bridge.cjs");
7016
+ const reporterPath = path11.resolve("scripts/jest-vitest-bridge.cjs");
5936
7017
  try {
5937
- if (!fsSync3.existsSync(reporterPath)) {
5938
- 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 });
5939
7028
  fsSync3.writeFileSync(reporterPath, JEST_BRIDGE_REPORTER_SOURCE, "utf8");
5940
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
+ }
5941
7043
  } catch (ensureReporterError) {
5942
7044
  console.warn(`Unable to ensure jest bridge reporter: ${String(ensureReporterError)}`);
5943
7045
  }
5944
- 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}`);
5945
7047
  const coverageFromArgs = [];
5946
- for (const relPath of selectedFilesForCoverage) {
5947
- coverageFromArgs.push("--collectCoverageFrom", relPath);
7048
+ for (const relPath2 of selectedFilesForCoverage) {
7049
+ coverageFromArgs.push("--collectCoverageFrom", relPath2);
5948
7050
  }
5949
7051
  const { code, output } = await runWithCapture(
5950
7052
  babelNodeBin,
@@ -5954,17 +7056,16 @@ var program = async () => {
5954
7056
  jestBin,
5955
7057
  "--config",
5956
7058
  cfg,
7059
+ "--testLocationInResults",
5957
7060
  "--runTestsByPath",
5958
7061
  `--reporters=${reporterPath}`,
5959
- "--silent",
5960
7062
  "--colors",
5961
- "--json",
5962
- "--outputFile",
5963
- outJson,
7063
+ "--env",
7064
+ path11.resolve("scripts/jest-bridge-env.cjs"),
5964
7065
  ...sanitizedJestRunArgs,
5965
7066
  ...collectCoverage ? [
5966
7067
  "--coverageDirectory",
5967
- 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, "_"))
5968
7069
  ] : [],
5969
7070
  ...coverageFromArgs,
5970
7071
  "--passWithNoTests",
@@ -5997,17 +7098,23 @@ var program = async () => {
5997
7098
  ...bridge,
5998
7099
  testResults: sortTestResultsWithRank(fileRank, bridge.testResults).reverse()
5999
7100
  };
6000
- pretty = renderVitestFromJestJSON(reordered, {
6001
- cwd: repoRootForDiscovery,
6002
- ...editorCmd !== void 0 ? { editorCmd } : {},
6003
- onlyFailures
6004
- });
7101
+ pretty = renderVitestFromJestJSON(
7102
+ reordered,
7103
+ makeCtx(
7104
+ { cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
7105
+ /\bFAIL\b/.test(stripAnsiSimple(output))
7106
+ ),
7107
+ { onlyFailures }
7108
+ );
6005
7109
  } catch {
6006
- pretty = renderVitestFromJestJSON(bridge, {
6007
- cwd: repoRootForDiscovery,
6008
- ...editorCmd !== void 0 ? { editorCmd } : {},
6009
- onlyFailures
6010
- });
7110
+ pretty = renderVitestFromJestJSON(
7111
+ bridge,
7112
+ makeCtx(
7113
+ { cwd: repoRootForDiscovery, ...editorCmd !== void 0 ? { editorCmd } : {} },
7114
+ /\bFAIL\b/.test(stripAnsiSimple(output))
7115
+ ),
7116
+ { onlyFailures }
7117
+ );
6011
7118
  }
6012
7119
  if (debug) {
6013
7120
  const preview = pretty.split("\n").slice(0, 3).join("\n");
@@ -6021,18 +7128,31 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
6021
7128
  console.info(String(jsonErr));
6022
7129
  console.info(`fallback: raw output lines=${output.split(/\r?\n/).length}`);
6023
7130
  }
6024
- const renderOpts = {
7131
+ pretty = formatJestOutputVitest(output, {
6025
7132
  cwd: repoRootForDiscovery,
6026
7133
  ...editorCmd !== void 0 ? { editorCmd } : {},
6027
7134
  onlyFailures
6028
- };
6029
- pretty = formatJestOutputVitest(output, renderOpts);
7135
+ });
6030
7136
  if (debug) {
6031
7137
  const preview = pretty.split("\n").slice(0, 3).join("\n");
6032
7138
  console.info(`pretty preview (text):
6033
7139
  ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
6034
7140
  }
6035
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
+ }
6036
7156
  pretty = stripFooter(pretty);
6037
7157
  if (pretty.trim().length > 0) {
6038
7158
  process.stdout.write(pretty.endsWith("\n") ? pretty : `${pretty}
@@ -6071,10 +7191,10 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
6071
7191
  try {
6072
7192
  const prodSeeds = (() => {
6073
7193
  const changedAbs = (changedSelectionAbs ?? []).map(
6074
- (absPath) => path10.resolve(absPath).replace(/\\/g, "/")
7194
+ (absPath) => path11.resolve(absPath).replace(/\\/g, "/")
6075
7195
  );
6076
7196
  const selAbs = selectionPathsAugmented.map(
6077
- (pathToken) => path10.resolve(pathToken).replace(/\\/g, "/")
7197
+ (pathToken) => path11.resolve(pathToken).replace(/\\/g, "/")
6078
7198
  );
6079
7199
  return (changedAbs.length ? changedAbs : selAbs).filter(
6080
7200
  (abs) => /[\\/]/.test(abs) && !/(^|\/)tests?\//i.test(abs) && !/\.(test|spec)\.[tj]sx?$/i.test(abs)
@@ -6088,11 +7208,18 @@ ${preview}${pretty.includes("\n") ? "\n\u2026" : ""}`);
6088
7208
  unified.testResults = ordered;
6089
7209
  } catch {
6090
7210
  }
6091
- const text = renderVitestFromJestJSON(unified, {
6092
- cwd: repoRootForDiscovery,
6093
- ...editorCmd !== void 0 ? { editorCmd } : {},
6094
- onlyFailures
6095
- });
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
+ }
6096
7223
  if (text.trim().length > 0) {
6097
7224
  process.stdout.write(text.endsWith("\n") ? text : `${text}
6098
7225
  `);