@funktechno/multi-assert 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +113 -2
- package/dist/chunk-UP6HQ3WU.mjs +270 -0
- package/dist/chunk-UP6HQ3WU.mjs.map +1 -0
- package/dist/index.d.mts +33 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +299 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +13 -0
- package/dist/index.mjs.map +1 -0
- package/dist/jest.d.mts +24 -0
- package/dist/jest.d.ts +24 -0
- package/dist/jest.js +301 -0
- package/dist/jest.js.map +1 -0
- package/dist/jest.mjs +30 -0
- package/dist/jest.mjs.map +1 -0
- package/dist/types-BfMUWmjj.d.mts +49 -0
- package/dist/types-BfMUWmjj.d.ts +49 -0
- package/package.json +88 -4
package/dist/index.js
ADDED
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
MultiAssertError: () => MultiAssertError,
|
|
24
|
+
configure: () => configure,
|
|
25
|
+
multiAssert: () => multiAssert,
|
|
26
|
+
multiAssertAsync: () => multiAssertAsync
|
|
27
|
+
});
|
|
28
|
+
module.exports = __toCommonJS(index_exports);
|
|
29
|
+
|
|
30
|
+
// src/format.ts
|
|
31
|
+
var red = (s) => `\x1B[31m${s}\x1B[39m`;
|
|
32
|
+
var dim = (s) => `\x1B[2m${s}\x1B[22m`;
|
|
33
|
+
function shouldUseColor(color) {
|
|
34
|
+
if (color === true || color === false) return color;
|
|
35
|
+
if (typeof process === "undefined") return false;
|
|
36
|
+
const env = process.env ?? {};
|
|
37
|
+
return Boolean(process.stdout?.isTTY) && !env.NO_COLOR && !env.CI;
|
|
38
|
+
}
|
|
39
|
+
function summaryLine(failed, total, heading) {
|
|
40
|
+
const noun = total === 1 ? "assertion" : "assertions";
|
|
41
|
+
return `${failed} of ${total} ${noun} failed${heading ? ` (${heading})` : ""}`;
|
|
42
|
+
}
|
|
43
|
+
var INDENT = " ";
|
|
44
|
+
function formatFailures(failures, total, options) {
|
|
45
|
+
const paint = (fn, s) => options.color ? fn(s) : s;
|
|
46
|
+
const blocks = failures.map((failure) => {
|
|
47
|
+
const lines = failure.message.split("\n");
|
|
48
|
+
const title = failure.label ?? lines.shift() ?? "";
|
|
49
|
+
const out = [` ${paint(red, "\u2715")} ${failure.index}) ${title}`];
|
|
50
|
+
for (const line of lines) out.push(line ? `${INDENT}${line}` : "");
|
|
51
|
+
const frames = (options.frames.get(failure) ?? []).slice(0, options.stackFrames);
|
|
52
|
+
for (const frame of frames) out.push(paint(dim, `${INDENT}\u2192 ${frame}`));
|
|
53
|
+
return out.join("\n");
|
|
54
|
+
});
|
|
55
|
+
return `${summaryLine(failures.length, total, options.heading)}
|
|
56
|
+
|
|
57
|
+
${blocks.join("\n\n")}`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// src/MultiAssertError.ts
|
|
61
|
+
var MultiAssertError = class extends AggregateError {
|
|
62
|
+
constructor(errors, message, failures, total) {
|
|
63
|
+
super(errors, message);
|
|
64
|
+
this.name = "MultiAssertError";
|
|
65
|
+
const hidden = { enumerable: false, writable: false, configurable: true };
|
|
66
|
+
Object.defineProperties(this, {
|
|
67
|
+
failures: { value: failures, ...hidden },
|
|
68
|
+
total: { value: total, ...hidden },
|
|
69
|
+
passed: { value: total - failures.length, ...hidden }
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Keeps `name` and `message` so reporters that serialise errors with `toJSON` (Vitest) still
|
|
74
|
+
* show the summary, and adds the structured failures.
|
|
75
|
+
*/
|
|
76
|
+
toJSON() {
|
|
77
|
+
return {
|
|
78
|
+
name: this.name,
|
|
79
|
+
message: this.message,
|
|
80
|
+
passed: this.passed,
|
|
81
|
+
total: this.total,
|
|
82
|
+
failures: this.failures
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// src/normalize.ts
|
|
88
|
+
var ESC = String.fromCharCode(27);
|
|
89
|
+
var ANSI = new RegExp(`(?:${ESC}|\\\\u001b|\\\\x1b)\\[[0-9;?]*[A-Za-z]`, "g");
|
|
90
|
+
var stripAnsi = (text) => text.replace(ANSI, "");
|
|
91
|
+
var isObject = (value) => typeof value === "object" && value !== null;
|
|
92
|
+
function safeInspect(value, max = 500) {
|
|
93
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
94
|
+
let text;
|
|
95
|
+
try {
|
|
96
|
+
text = JSON.stringify(
|
|
97
|
+
value,
|
|
98
|
+
(_key, v) => {
|
|
99
|
+
if (typeof v === "bigint") return `${v}n`;
|
|
100
|
+
if (typeof v === "function") return `[Function ${v.name || "anonymous"}]`;
|
|
101
|
+
if (typeof v === "symbol") return v.toString();
|
|
102
|
+
if (isObject(v)) {
|
|
103
|
+
if (seen.has(v)) return "[Circular]";
|
|
104
|
+
seen.add(v);
|
|
105
|
+
}
|
|
106
|
+
return v;
|
|
107
|
+
},
|
|
108
|
+
2
|
|
109
|
+
) ?? String(value);
|
|
110
|
+
} catch {
|
|
111
|
+
text = String(value);
|
|
112
|
+
}
|
|
113
|
+
return text.length > max ? `${text.slice(0, max)}\u2026` : text;
|
|
114
|
+
}
|
|
115
|
+
var matcherAdapter = {
|
|
116
|
+
name: "matcher",
|
|
117
|
+
matches: (e) => isObject(e) && isObject(e.matcherResult),
|
|
118
|
+
normalize(e) {
|
|
119
|
+
const result = e.matcherResult;
|
|
120
|
+
let message = result.message;
|
|
121
|
+
if (typeof message === "function") message = message();
|
|
122
|
+
if (Array.isArray(message)) message = message.join("\n");
|
|
123
|
+
return {
|
|
124
|
+
message: typeof message === "string" ? message : String(e.message ?? ""),
|
|
125
|
+
actual: result.actual,
|
|
126
|
+
expected: result.expected,
|
|
127
|
+
operator: typeof result.name === "string" ? result.name : void 0
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
var assertionAdapter = {
|
|
132
|
+
name: "assertion",
|
|
133
|
+
matches: (e) => e instanceof Error && ("actual" in e || "expected" in e || "operator" in e || e.name === "AssertionError"),
|
|
134
|
+
normalize(e) {
|
|
135
|
+
const err = e;
|
|
136
|
+
return {
|
|
137
|
+
message: err.message,
|
|
138
|
+
actual: err.actual,
|
|
139
|
+
expected: err.expected,
|
|
140
|
+
operator: typeof err.operator === "string" ? err.operator : void 0
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
};
|
|
144
|
+
var errorAdapter = {
|
|
145
|
+
name: "error",
|
|
146
|
+
matches: (e) => e instanceof Error || isObject(e) && typeof e.message === "string",
|
|
147
|
+
normalize(e) {
|
|
148
|
+
const err = e;
|
|
149
|
+
const message = err.message ? `${err.name}: ${err.message}` : String(err.name ?? "Error");
|
|
150
|
+
return { message };
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
var otherAdapter = {
|
|
154
|
+
name: "other",
|
|
155
|
+
matches: () => true,
|
|
156
|
+
normalize: (e) => ({ message: `[non-Error thrown] ${safeInspect(e)}` })
|
|
157
|
+
};
|
|
158
|
+
var builtInAdapters = [
|
|
159
|
+
matcherAdapter,
|
|
160
|
+
assertionAdapter,
|
|
161
|
+
errorAdapter,
|
|
162
|
+
otherAdapter
|
|
163
|
+
];
|
|
164
|
+
function normalizeError(error, custom = []) {
|
|
165
|
+
const adapter = [...custom, ...builtInAdapters].find((a) => {
|
|
166
|
+
try {
|
|
167
|
+
return a.matches(error);
|
|
168
|
+
} catch {
|
|
169
|
+
return false;
|
|
170
|
+
}
|
|
171
|
+
});
|
|
172
|
+
const normalized = adapter.normalize(error);
|
|
173
|
+
return { ...normalized, message: stripAnsi(normalized.message) };
|
|
174
|
+
}
|
|
175
|
+
var OWN_FRAME = /[\\/]multi-assert[\\/](?:src|dist)[\\/]/;
|
|
176
|
+
var FRAME_LOCATION = /\(?((?:file:\/\/)?[^\s()]+?:\d+:\d+)\)?\s*$/;
|
|
177
|
+
function userFrames(stack) {
|
|
178
|
+
if (!stack) return [];
|
|
179
|
+
return stack.split("\n").filter((line) => /^\s*at /.test(line)).filter(
|
|
180
|
+
(line) => !line.includes("node_modules") && !line.includes("node:") && !OWN_FRAME.test(line)
|
|
181
|
+
).map((line) => FRAME_LOCATION.exec(line)?.[1]).filter((loc) => Boolean(loc)).map(relativize);
|
|
182
|
+
}
|
|
183
|
+
function relativize(location) {
|
|
184
|
+
const withoutScheme = location.replace(/^file:\/\//, "").replace(/^\/([A-Za-z]:)/, "$1");
|
|
185
|
+
const cwd = typeof process !== "undefined" && process.cwd ? process.cwd() : void 0;
|
|
186
|
+
if (!cwd) return withoutScheme;
|
|
187
|
+
const norm = (p) => p.replace(/\\/g, "/");
|
|
188
|
+
const base = norm(cwd).replace(/\/$/, "") + "/";
|
|
189
|
+
const loc = norm(withoutScheme);
|
|
190
|
+
return loc.toLowerCase().startsWith(base.toLowerCase()) ? loc.slice(base.length) : loc;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// src/multiAssert.ts
|
|
194
|
+
var defaults = {
|
|
195
|
+
rethrowSingle: true,
|
|
196
|
+
color: "auto",
|
|
197
|
+
stackFrames: 1,
|
|
198
|
+
adapters: []
|
|
199
|
+
};
|
|
200
|
+
function configure(options) {
|
|
201
|
+
Object.assign(defaults, options);
|
|
202
|
+
}
|
|
203
|
+
function toEntries(checks) {
|
|
204
|
+
const pairs = Array.isArray(checks) ? checks.map((c) => Array.isArray(c) ? [c[0], c[1]] : [void 0, c]) : Object.entries(checks ?? {});
|
|
205
|
+
return pairs.map(([label, fn], i) => {
|
|
206
|
+
if (typeof fn !== "function") {
|
|
207
|
+
throw new TypeError(
|
|
208
|
+
`multiAssert: check ${i + 1}${label ? ` ("${label}")` : ""} is not a function`
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
return { label, fn };
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
var isThenable = (value) => typeof value?.then === "function";
|
|
215
|
+
function captureSite(from) {
|
|
216
|
+
const holder = {};
|
|
217
|
+
const capture = Error.captureStackTrace;
|
|
218
|
+
if (capture) {
|
|
219
|
+
capture(holder, from);
|
|
220
|
+
return holder.stack;
|
|
221
|
+
}
|
|
222
|
+
return new Error().stack;
|
|
223
|
+
}
|
|
224
|
+
function finish(caught, total, options, site) {
|
|
225
|
+
if (caught.length === 0) return;
|
|
226
|
+
const settings = { ...defaults, ...options };
|
|
227
|
+
const [only] = caught;
|
|
228
|
+
if (caught.length === 1 && settings.rethrowSingle && only.error instanceof Error && !only.entry.label && !settings.message) {
|
|
229
|
+
throw only.error;
|
|
230
|
+
}
|
|
231
|
+
const frames = /* @__PURE__ */ new Map();
|
|
232
|
+
const failures = caught.map(({ entry, index, error: error2 }) => {
|
|
233
|
+
const normalized = normalizeError(error2, settings.adapters);
|
|
234
|
+
const failure = {
|
|
235
|
+
index,
|
|
236
|
+
label: entry.label,
|
|
237
|
+
message: normalized.message,
|
|
238
|
+
actual: normalized.actual,
|
|
239
|
+
expected: normalized.expected,
|
|
240
|
+
operator: normalized.operator
|
|
241
|
+
};
|
|
242
|
+
const list = userFrames(error2 instanceof Error ? error2.stack : void 0);
|
|
243
|
+
failure.location = list[0];
|
|
244
|
+
frames.set(failure, list);
|
|
245
|
+
return failure;
|
|
246
|
+
});
|
|
247
|
+
const message = formatFailures(failures, total, {
|
|
248
|
+
heading: settings.message,
|
|
249
|
+
color: shouldUseColor(settings.color),
|
|
250
|
+
stackFrames: settings.stackFrames,
|
|
251
|
+
frames
|
|
252
|
+
});
|
|
253
|
+
const error = new MultiAssertError(
|
|
254
|
+
caught.map((c) => c.error),
|
|
255
|
+
message,
|
|
256
|
+
failures,
|
|
257
|
+
total
|
|
258
|
+
);
|
|
259
|
+
const callSite = (site ?? "").split("\n").filter((l) => /^\s*at /.test(l));
|
|
260
|
+
error.stack = [`${error.name}: ${message}`, ...callSite].join("\n");
|
|
261
|
+
throw error;
|
|
262
|
+
}
|
|
263
|
+
function multiAssert(checks, options = {}) {
|
|
264
|
+
const entries = toEntries(checks);
|
|
265
|
+
const caught = [];
|
|
266
|
+
entries.forEach((entry, i) => {
|
|
267
|
+
try {
|
|
268
|
+
const result = entry.fn();
|
|
269
|
+
if (isThenable(result)) {
|
|
270
|
+
result.then(void 0, () => void 0);
|
|
271
|
+
throw new TypeError("check returned a Promise; use multiAssertAsync() for async checks");
|
|
272
|
+
}
|
|
273
|
+
} catch (error) {
|
|
274
|
+
caught.push({ entry, index: i + 1, error });
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
finish(caught, entries.length, options, caught.length ? captureSite(multiAssert) : void 0);
|
|
278
|
+
}
|
|
279
|
+
async function multiAssertAsync(checks, options = {}) {
|
|
280
|
+
const site = captureSite(multiAssertAsync);
|
|
281
|
+
const entries = toEntries(checks);
|
|
282
|
+
const caught = [];
|
|
283
|
+
for (const [i, entry] of entries.entries()) {
|
|
284
|
+
try {
|
|
285
|
+
await entry.fn();
|
|
286
|
+
} catch (error) {
|
|
287
|
+
caught.push({ entry, index: i + 1, error });
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
finish(caught, entries.length, options, site);
|
|
291
|
+
}
|
|
292
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
293
|
+
0 && (module.exports = {
|
|
294
|
+
MultiAssertError,
|
|
295
|
+
configure,
|
|
296
|
+
multiAssert,
|
|
297
|
+
multiAssertAsync
|
|
298
|
+
});
|
|
299
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/format.ts","../src/MultiAssertError.ts","../src/normalize.ts","../src/multiAssert.ts"],"sourcesContent":["export { multiAssert, multiAssertAsync, configure } from \"./multiAssert\";\nexport { MultiAssertError } from \"./MultiAssertError\";\nexport type {\n AsyncCheck,\n AsyncCheckFn,\n Check,\n CheckFn,\n ErrorAdapter,\n Failure,\n MultiAssertOptions,\n NormalizedError,\n} from \"./types\";\n","import type { Failure, MultiAssertOptions } from \"./types\";\n\nconst red = (s: string) => `\\u001b[31m${s}\\u001b[39m`;\nconst dim = (s: string) => `\\u001b[2m${s}\\u001b[22m`;\n\nexport function shouldUseColor(color: MultiAssertOptions[\"color\"]): boolean {\n if (color === true || color === false) return color;\n if (typeof process === \"undefined\") return false;\n const env = process.env ?? {};\n return Boolean(process.stdout?.isTTY) && !env.NO_COLOR && !env.CI;\n}\n\nexport function summaryLine(failed: number, total: number, heading?: string): string {\n const noun = total === 1 ? \"assertion\" : \"assertions\";\n return `${failed} of ${total} ${noun} failed${heading ? ` (${heading})` : \"\"}`;\n}\n\nconst INDENT = \" \";\n\nexport interface FormatOptions {\n heading?: string;\n color: boolean;\n stackFrames: number;\n frames: Map<Failure, string[]>;\n}\n\nexport function formatFailures(failures: Failure[], total: number, options: FormatOptions): string {\n const paint = (fn: (s: string) => string, s: string) => (options.color ? fn(s) : s);\n const blocks = failures.map((failure) => {\n const lines = failure.message.split(\"\\n\");\n const title = failure.label ?? lines.shift() ?? \"\";\n const out = [` ${paint(red, \"✕\")} ${failure.index}) ${title}`];\n for (const line of lines) out.push(line ? `${INDENT}${line}` : \"\");\n const frames = (options.frames.get(failure) ?? []).slice(0, options.stackFrames);\n for (const frame of frames) out.push(paint(dim, `${INDENT}→ ${frame}`));\n return out.join(\"\\n\");\n });\n return `${summaryLine(failures.length, total, options.heading)}\\n\\n${blocks.join(\"\\n\\n\")}`;\n}\n","import type { Failure } from \"./types\";\n\n/** Thrown when two or more checks in a group fail (or one fails and can't be rethrown as is). */\nexport class MultiAssertError extends AggregateError {\n declare readonly failures: Failure[];\n declare readonly passed: number;\n declare readonly total: number;\n\n constructor(errors: unknown[], message: string, failures: Failure[], total: number) {\n super(errors, message);\n this.name = \"MultiAssertError\";\n // Non-enumerable so reporters that dump an error's own properties (Vitest does) don't print\n // the same failures twice.\n const hidden = { enumerable: false, writable: false, configurable: true };\n Object.defineProperties(this, {\n failures: { value: failures, ...hidden },\n total: { value: total, ...hidden },\n passed: { value: total - failures.length, ...hidden },\n });\n }\n\n /**\n * Keeps `name` and `message` so reporters that serialise errors with `toJSON` (Vitest) still\n * show the summary, and adds the structured failures.\n */\n toJSON() {\n return {\n name: this.name,\n message: this.message,\n passed: this.passed,\n total: this.total,\n failures: this.failures,\n };\n }\n}\n","import type { ErrorAdapter, NormalizedError } from \"./types\";\n\nconst ESC = String.fromCharCode(27);\n/** Every ANSI CSI sequence, plus the already-escaped text form some reporters print. */\nconst ANSI = new RegExp(`(?:${ESC}|\\\\\\\\u001b|\\\\\\\\x1b)\\\\[[0-9;?]*[A-Za-z]`, \"g\");\n\nexport const stripAnsi = (text: string): string => text.replace(ANSI, \"\");\n\nconst isObject = (value: unknown): value is Record<string, any> =>\n typeof value === \"object\" && value !== null;\n\n/** Cycle-safe, truncated rendering for values that aren't Errors. */\nexport function safeInspect(value: unknown, max = 500): string {\n const seen = new WeakSet<object>();\n let text: string;\n try {\n text =\n JSON.stringify(\n value,\n (_key, v) => {\n if (typeof v === \"bigint\") return `${v}n`;\n if (typeof v === \"function\") return `[Function ${v.name || \"anonymous\"}]`;\n if (typeof v === \"symbol\") return v.toString();\n if (isObject(v)) {\n if (seen.has(v)) return \"[Circular]\";\n seen.add(v);\n }\n return v;\n },\n 2,\n ) ?? String(value);\n } catch {\n text = String(value);\n }\n return text.length > max ? `${text.slice(0, max)}…` : text;\n}\n\n/** Jest / Vitest / Playwright `expect` errors carry a `matcherResult`. */\nconst matcherAdapter: ErrorAdapter = {\n name: \"matcher\",\n matches: (e) => isObject(e) && isObject(e.matcherResult),\n normalize(e) {\n const result = (e as any).matcherResult;\n let message: unknown = result.message;\n if (typeof message === \"function\") message = message();\n if (Array.isArray(message)) message = message.join(\"\\n\");\n return {\n message: typeof message === \"string\" ? message : String((e as Error).message ?? \"\"),\n actual: result.actual,\n expected: result.expected,\n operator: typeof result.name === \"string\" ? result.name : undefined,\n };\n },\n};\n\n/** node:assert, chai, uvu and Vitest's chai-based errors expose actual / expected. */\nconst assertionAdapter: ErrorAdapter = {\n name: \"assertion\",\n matches: (e) =>\n e instanceof Error &&\n (\"actual\" in e || \"expected\" in e || \"operator\" in e || e.name === \"AssertionError\"),\n normalize(e) {\n const err = e as Error & { actual?: unknown; expected?: unknown; operator?: string };\n return {\n message: err.message,\n actual: err.actual,\n expected: err.expected,\n operator: typeof err.operator === \"string\" ? err.operator : undefined,\n };\n },\n};\n\nconst errorAdapter: ErrorAdapter = {\n name: \"error\",\n matches: (e) => e instanceof Error || (isObject(e) && typeof e.message === \"string\"),\n normalize(e) {\n const err = e as Error;\n const message = err.message ? `${err.name}: ${err.message}` : String(err.name ?? \"Error\");\n return { message };\n },\n};\n\nconst otherAdapter: ErrorAdapter = {\n name: \"other\",\n matches: () => true,\n normalize: (e) => ({ message: `[non-Error thrown] ${safeInspect(e)}` }),\n};\n\nexport const builtInAdapters: ErrorAdapter[] = [\n matcherAdapter,\n assertionAdapter,\n errorAdapter,\n otherAdapter,\n];\n\nexport function normalizeError(error: unknown, custom: ErrorAdapter[] = []): NormalizedError {\n const adapter = [...custom, ...builtInAdapters].find((a) => {\n try {\n return a.matches(error);\n } catch {\n return false;\n }\n }) as ErrorAdapter;\n const normalized = adapter.normalize(error);\n return { ...normalized, message: stripAnsi(normalized.message) };\n}\n\n/** Frames from this package's own source/dist, which should never be shown as a location. */\nconst OWN_FRAME = /[\\\\/]multi-assert[\\\\/](?:src|dist)[\\\\/]/;\nconst FRAME_LOCATION = /\\(?((?:file:\\/\\/)?[^\\s()]+?:\\d+:\\d+)\\)?\\s*$/;\n\nexport function userFrames(stack: string | undefined): string[] {\n if (!stack) return [];\n return stack\n .split(\"\\n\")\n .filter((line) => /^\\s*at /.test(line))\n .filter(\n (line) => !line.includes(\"node_modules\") && !line.includes(\"node:\") && !OWN_FRAME.test(line),\n )\n .map((line) => FRAME_LOCATION.exec(line)?.[1])\n .filter((loc): loc is string => Boolean(loc))\n .map(relativize);\n}\n\nfunction relativize(location: string): string {\n // file:///C:/x -> C:/x, but file:///home/x -> /home/x\n const withoutScheme = location.replace(/^file:\\/\\//, \"\").replace(/^\\/([A-Za-z]:)/, \"$1\");\n const cwd = typeof process !== \"undefined\" && process.cwd ? process.cwd() : undefined;\n if (!cwd) return withoutScheme;\n const norm = (p: string) => p.replace(/\\\\/g, \"/\");\n const base = norm(cwd).replace(/\\/$/, \"\") + \"/\";\n const loc = norm(withoutScheme);\n return loc.toLowerCase().startsWith(base.toLowerCase()) ? loc.slice(base.length) : loc;\n}\n","import { formatFailures, shouldUseColor } from \"./format\";\nimport { MultiAssertError } from \"./MultiAssertError\";\nimport { normalizeError, userFrames } from \"./normalize\";\nimport type {\n AsyncCheck,\n AsyncCheckFn,\n Check,\n CheckFn,\n Failure,\n MultiAssertOptions,\n} from \"./types\";\n\nconst defaults: Required<Omit<MultiAssertOptions, \"message\">> & { message?: string } = {\n rethrowSingle: true,\n color: \"auto\",\n stackFrames: 1,\n adapters: [],\n};\n\n/** Set defaults once, e.g. in a test setup file. */\nexport function configure(options: MultiAssertOptions): void {\n Object.assign(defaults, options);\n}\n\ninterface Entry<F> {\n label?: string;\n fn: F;\n}\n\nfunction toEntries<F extends () => unknown>(\n checks: Array<F | [string, F]> | Record<string, F>,\n): Entry<F>[] {\n const pairs: Array<[string | undefined, unknown]> = Array.isArray(checks)\n ? checks.map((c) => (Array.isArray(c) ? [c[0], c[1]] : [undefined, c]))\n : Object.entries(checks ?? {});\n return pairs.map(([label, fn], i) => {\n if (typeof fn !== \"function\") {\n throw new TypeError(\n `multiAssert: check ${i + 1}${label ? ` (\"${label}\")` : \"\"} is not a function`,\n );\n }\n return { label, fn: fn as F };\n });\n}\n\nconst isThenable = (value: unknown): value is PromiseLike<unknown> =>\n typeof (value as PromiseLike<unknown> | undefined)?.then === \"function\";\n\ninterface Caught {\n entry: Entry<unknown>;\n index: number;\n error: unknown;\n}\n\nfunction captureSite(from: (...args: any[]) => unknown): string | undefined {\n const holder: { stack?: string } = {};\n const capture = (Error as any).captureStackTrace as\n | ((target: object, ctor?: (...args: any[]) => unknown) => void)\n | undefined;\n if (capture) {\n capture(holder, from);\n return holder.stack;\n }\n return new Error().stack;\n}\n\nfunction finish(\n caught: Caught[],\n total: number,\n options: MultiAssertOptions,\n site: string | undefined,\n): void {\n if (caught.length === 0) return;\n const settings = { ...defaults, ...options };\n const [only] = caught;\n if (\n caught.length === 1 &&\n settings.rethrowSingle &&\n only.error instanceof Error &&\n !only.entry.label &&\n !settings.message\n ) {\n throw only.error;\n }\n\n const frames = new Map<Failure, string[]>();\n const failures = caught.map(({ entry, index, error }) => {\n const normalized = normalizeError(error, settings.adapters);\n const failure: Failure = {\n index,\n label: entry.label,\n message: normalized.message,\n actual: normalized.actual,\n expected: normalized.expected,\n operator: normalized.operator,\n };\n const list = userFrames(error instanceof Error ? error.stack : undefined);\n failure.location = list[0];\n frames.set(failure, list);\n return failure;\n });\n\n const message = formatFailures(failures, total, {\n heading: settings.message,\n color: shouldUseColor(settings.color),\n stackFrames: settings.stackFrames,\n frames,\n });\n const error = new MultiAssertError(\n caught.map((c) => c.error),\n message,\n failures,\n total,\n );\n // Point reporters at the test that called multiAssert, not at this package.\n const callSite = (site ?? \"\").split(\"\\n\").filter((l) => /^\\s*at /.test(l));\n // Standard `Name: message` header, so reporters that print the stack (Jest) show every failure.\n error.stack = [`${error.name}: ${message}`, ...callSite].join(\"\\n\");\n throw error;\n}\n\n/**\n * Runs every check instead of stopping at the first failure, then throws once with all failures\n * combined. Checks must be synchronous; use {@link multiAssertAsync} for async checks.\n */\nexport function multiAssert(\n checks: Check[] | Record<string, CheckFn>,\n options: MultiAssertOptions = {},\n): void {\n const entries = toEntries<CheckFn>(checks);\n const caught: Caught[] = [];\n entries.forEach((entry, i) => {\n try {\n const result = entry.fn();\n if (isThenable(result)) {\n // Avoid an unhandled rejection from a promise we are not going to await.\n result.then(undefined, () => undefined);\n throw new TypeError(\"check returned a Promise; use multiAssertAsync() for async checks\");\n }\n } catch (error) {\n caught.push({ entry, index: i + 1, error });\n }\n });\n finish(caught, entries.length, options, caught.length ? captureSite(multiAssert) : undefined);\n}\n\n/** Like {@link multiAssert}, but awaits each check in order. */\nexport async function multiAssertAsync(\n checks: AsyncCheck[] | Record<string, AsyncCheckFn>,\n options: MultiAssertOptions = {},\n): Promise<void> {\n const site = captureSite(multiAssertAsync);\n const entries = toEntries<AsyncCheckFn>(checks);\n const caught: Caught[] = [];\n for (const [i, entry] of entries.entries()) {\n try {\n await entry.fn();\n } catch (error) {\n caught.push({ entry, index: i + 1, error });\n }\n }\n finish(caught, entries.length, options, site);\n}\n"],"mappings":"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","names":["error"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/jest.d.mts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { MultiAssertOptions } from './index.mjs';
|
|
2
|
+
|
|
3
|
+
type Matcher<T> = ((received: T) => unknown) | [label: string, fn: (received: T) => unknown];
|
|
4
|
+
/** `expect(value).toPassAll([...])`: every check gets `value`, all failures are reported at once. */
|
|
5
|
+
declare const multiAssertMatchers: {
|
|
6
|
+
toPassAll<T>(received: T, checks: Matcher<T>[], options?: MultiAssertOptions): {
|
|
7
|
+
pass: boolean;
|
|
8
|
+
message: () => string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
interface ExpectLike {
|
|
12
|
+
extend(matchers: Record<string, unknown>): void;
|
|
13
|
+
}
|
|
14
|
+
/** Registers `toPassAll` on a Jest-compatible `expect` (Jest, Vitest, Playwright). */
|
|
15
|
+
declare function installMultiAssertMatchers(expectLike: ExpectLike): void;
|
|
16
|
+
declare global {
|
|
17
|
+
namespace jest {
|
|
18
|
+
interface Matchers<R, T = unknown> {
|
|
19
|
+
toPassAll(checks: Array<((received: T) => unknown) | [label: string, fn: (received: T) => unknown]>, options?: MultiAssertOptions): R;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { installMultiAssertMatchers, multiAssertMatchers };
|
package/dist/jest.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { MultiAssertOptions } from './index.js';
|
|
2
|
+
|
|
3
|
+
type Matcher<T> = ((received: T) => unknown) | [label: string, fn: (received: T) => unknown];
|
|
4
|
+
/** `expect(value).toPassAll([...])`: every check gets `value`, all failures are reported at once. */
|
|
5
|
+
declare const multiAssertMatchers: {
|
|
6
|
+
toPassAll<T>(received: T, checks: Matcher<T>[], options?: MultiAssertOptions): {
|
|
7
|
+
pass: boolean;
|
|
8
|
+
message: () => string;
|
|
9
|
+
};
|
|
10
|
+
};
|
|
11
|
+
interface ExpectLike {
|
|
12
|
+
extend(matchers: Record<string, unknown>): void;
|
|
13
|
+
}
|
|
14
|
+
/** Registers `toPassAll` on a Jest-compatible `expect` (Jest, Vitest, Playwright). */
|
|
15
|
+
declare function installMultiAssertMatchers(expectLike: ExpectLike): void;
|
|
16
|
+
declare global {
|
|
17
|
+
namespace jest {
|
|
18
|
+
interface Matchers<R, T = unknown> {
|
|
19
|
+
toPassAll(checks: Array<((received: T) => unknown) | [label: string, fn: (received: T) => unknown]>, options?: MultiAssertOptions): R;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export { installMultiAssertMatchers, multiAssertMatchers };
|