@autometa/assertions 1.0.0-rc.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/dist/index.cjs ADDED
@@ -0,0 +1,815 @@
1
+ 'use strict';
2
+
3
+ var util = require('util');
4
+ var expectUtils = require('@jest/expect-utils');
5
+ var jestDiff = require('jest-diff');
6
+ var jestMatcherUtils = require('jest-matcher-utils');
7
+
8
+ // src/assertion-error.ts
9
+ var EnsureError = class extends Error {
10
+ constructor(details) {
11
+ const formattedMessage = buildMessage(details);
12
+ super(formattedMessage);
13
+ this.name = "EnsureError";
14
+ this.matcher = details.matcher;
15
+ this.actual = details.actual;
16
+ this.expected = details.expected;
17
+ }
18
+ };
19
+ function buildMessage({ matcher, message, actual, expected, receivedLabel }) {
20
+ const parts = [message];
21
+ const extras = [];
22
+ if (typeof expected !== "undefined" && !containsSection(message, "Expected:")) {
23
+ extras.push(`Expected: ${formatValue(expected)}`);
24
+ }
25
+ if (typeof actual !== "undefined") {
26
+ const label = receivedLabel ? `Received ${receivedLabel}` : "Received";
27
+ if (!containsSection(message, `${label}:`)) {
28
+ extras.push(`${label}: ${formatValue(actual)}`);
29
+ }
30
+ }
31
+ if (!containsSection(message, "Matcher:")) {
32
+ extras.push(`Matcher: ${matcher}`);
33
+ }
34
+ if (extras.length > 0) {
35
+ parts.push("", ...extras);
36
+ }
37
+ return parts.join("\n");
38
+ }
39
+ function formatValue(value) {
40
+ return util.inspect(value, { depth: 4, maxArrayLength: 10, breakLength: 60, sorted: true });
41
+ }
42
+ function containsSection(message, label) {
43
+ return message.split("\n").some((line) => line.trimStart().startsWith(label));
44
+ }
45
+ var MATCHER_CALL = "ensure(received)";
46
+ var EQUALITY_TESTERS = [expectUtils.iterableEquality];
47
+ var SUBSET_TESTERS = [expectUtils.iterableEquality, expectUtils.subsetEquality];
48
+
49
+ // src/core/context.ts
50
+ function shouldFail(pass, negated) {
51
+ return negated ? pass : !pass;
52
+ }
53
+ function buildFailureMessage(matcher, baseMessage, options = {}) {
54
+ const sections = [`${MATCHER_CALL}.${matcher}(expected)`, baseMessage];
55
+ if (Object.prototype.hasOwnProperty.call(options, "expected")) {
56
+ sections.push(`Expected: ${jestMatcherUtils.printExpected(options.expected)}`);
57
+ }
58
+ if (Object.prototype.hasOwnProperty.call(options, "actual")) {
59
+ const label = options.actualLabel ?? "Received";
60
+ sections.push(`${label}: ${jestMatcherUtils.printReceived(options.actual)}`);
61
+ }
62
+ if (options.extra) {
63
+ for (const extra of options.extra) {
64
+ if (extra && extra.trim().length > 0) {
65
+ sections.push(extra);
66
+ }
67
+ }
68
+ }
69
+ if (options.diff && options.diff.trim().length > 0) {
70
+ sections.push(options.diff);
71
+ }
72
+ return sections.join("\n\n");
73
+ }
74
+ function formatDiff(expected, actual) {
75
+ const difference = jestDiff.diff(expected, actual, { expand: false });
76
+ return difference && difference.trim().length > 0 ? difference : void 0;
77
+ }
78
+ function formatMissingList(title, values) {
79
+ if (values.length === 0) {
80
+ return "";
81
+ }
82
+ const items = values.map((value) => ` - ${jestMatcherUtils.printExpected(value)}`).join("\n");
83
+ return `${title}
84
+ ${items}`;
85
+ }
86
+
87
+ // src/core/predicates.ts
88
+ function isRecord(candidate) {
89
+ return typeof candidate === "object" && candidate !== null;
90
+ }
91
+ function isIterable(candidate) {
92
+ return typeof candidate?.[Symbol.iterator] === "function";
93
+ }
94
+ function hasLengthProperty(candidate) {
95
+ return typeof candidate?.length === "number";
96
+ }
97
+
98
+ // src/matchers/collections.ts
99
+ function assertObjectContaining(ctx, shape) {
100
+ const isObject = isRecord(ctx.value);
101
+ if (!isObject) {
102
+ if (!ctx.negated) {
103
+ ctx.fail("toBeObjectContaining", {
104
+ message: buildFailureMessage("toBeObjectContaining", "Expected value to be an object", {
105
+ actual: ctx.value
106
+ }),
107
+ actual: ctx.value
108
+ });
109
+ }
110
+ return;
111
+ }
112
+ const pass = expectUtils.equals(ctx.value, shape, SUBSET_TESTERS);
113
+ if (shouldFail(pass, ctx.negated)) {
114
+ const baseMessage = ctx.negated ? "Expected object not to match the provided subset" : "Object does not match the provided subset";
115
+ ctx.fail("toBeObjectContaining", {
116
+ message: buildFailureMessage("toBeObjectContaining", baseMessage, {
117
+ expected: shape,
118
+ actual: ctx.value,
119
+ diff: formatDiff(shape, ctx.value)
120
+ }),
121
+ expected: shape,
122
+ actual: ctx.value
123
+ });
124
+ }
125
+ }
126
+ function assertArrayContaining(ctx, expected) {
127
+ if (!Array.isArray(ctx.value)) {
128
+ if (!ctx.negated) {
129
+ ctx.fail("toBeArrayContaining", {
130
+ message: buildFailureMessage("toBeArrayContaining", "Expected value to be an array", {
131
+ actual: ctx.value
132
+ }),
133
+ actual: ctx.value
134
+ });
135
+ }
136
+ return ctx.value;
137
+ }
138
+ const actual = ctx.value;
139
+ const missing = expected.filter(
140
+ (item) => !actual.some((entry) => expectUtils.equals(entry, item, EQUALITY_TESTERS))
141
+ );
142
+ const pass = missing.length === 0;
143
+ if (shouldFail(pass, ctx.negated)) {
144
+ const baseMessage = ctx.negated ? "Expected array not to contain the provided elements" : "Array is missing expected elements";
145
+ ctx.fail("toBeArrayContaining", {
146
+ message: buildFailureMessage("toBeArrayContaining", baseMessage, {
147
+ expected,
148
+ actual,
149
+ extra: [formatMissingList("Missing elements:", missing)],
150
+ diff: formatDiff(expected, actual)
151
+ }),
152
+ expected,
153
+ actual
154
+ });
155
+ }
156
+ return actual;
157
+ }
158
+ function assertContainEqual(ctx, expected) {
159
+ if (!Array.isArray(ctx.value)) {
160
+ if (!ctx.negated) {
161
+ ctx.fail("toContainEqual", {
162
+ message: buildFailureMessage("toContainEqual", "Expected value to be an array", {
163
+ actual: ctx.value
164
+ }),
165
+ actual: ctx.value
166
+ });
167
+ }
168
+ return ctx.value;
169
+ }
170
+ const actual = ctx.value;
171
+ const pass = actual.some((entry) => expectUtils.equals(entry, expected, EQUALITY_TESTERS));
172
+ if (shouldFail(pass, ctx.negated)) {
173
+ const baseMessage = ctx.negated ? "Expected array not to contain the provided element" : "Array is missing the expected element";
174
+ ctx.fail("toContainEqual", {
175
+ message: buildFailureMessage("toContainEqual", baseMessage, {
176
+ expected,
177
+ actual,
178
+ diff: formatDiff(expected, actual)
179
+ }),
180
+ expected,
181
+ actual
182
+ });
183
+ }
184
+ return actual;
185
+ }
186
+ function assertIterableContaining(ctx, expected) {
187
+ if (!isIterable(ctx.value)) {
188
+ if (!ctx.negated) {
189
+ ctx.fail("toBeIterableContaining", {
190
+ message: buildFailureMessage("toBeIterableContaining", "Expected value to be iterable", {
191
+ actual: ctx.value
192
+ }),
193
+ actual: ctx.value
194
+ });
195
+ }
196
+ return ctx.value;
197
+ }
198
+ const entries = Array.from(ctx.value);
199
+ const missing = expected.filter(
200
+ (item) => !entries.some((entry) => expectUtils.equals(entry, item, EQUALITY_TESTERS))
201
+ );
202
+ const pass = missing.length === 0;
203
+ if (shouldFail(pass, ctx.negated)) {
204
+ const baseMessage = ctx.negated ? "Expected iterable not to contain the provided elements" : "Iterable is missing expected elements";
205
+ ctx.fail("toBeIterableContaining", {
206
+ message: buildFailureMessage("toBeIterableContaining", baseMessage, {
207
+ expected,
208
+ actual: entries,
209
+ extra: [formatMissingList("Missing elements:", missing)]
210
+ }),
211
+ expected,
212
+ actual: entries
213
+ });
214
+ }
215
+ return ctx.value;
216
+ }
217
+ function assertHasLength(ctx, expected) {
218
+ if (!hasLengthProperty(ctx.value)) {
219
+ if (!ctx.negated) {
220
+ ctx.fail("toHaveLength", {
221
+ message: buildFailureMessage("toHaveLength", "Expected value to have a numeric length property", {
222
+ actual: ctx.value
223
+ }),
224
+ actual: ctx.value
225
+ });
226
+ }
227
+ return NaN;
228
+ }
229
+ const actualLength = ctx.value.length;
230
+ const pass = actualLength === expected;
231
+ if (shouldFail(pass, ctx.negated)) {
232
+ const baseMessage = ctx.negated ? `Expected length to differ from ${expected}` : "Length does not match expectation";
233
+ ctx.fail("toHaveLength", {
234
+ message: buildFailureMessage("toHaveLength", baseMessage, {
235
+ expected,
236
+ actual: actualLength,
237
+ diff: formatDiff(expected, actualLength)
238
+ }),
239
+ expected,
240
+ actual: actualLength
241
+ });
242
+ }
243
+ return actualLength;
244
+ }
245
+ function assertToBe(ctx, expected) {
246
+ const pass = Object.is(ctx.value, expected);
247
+ if (ctx.negated ? pass : !pass) {
248
+ const baseMessage = ctx.negated ? "Expected values not to be strictly equal" : "Expected values to be strictly equal";
249
+ ctx.fail("toBe", {
250
+ message: buildFailureMessage("toBe", baseMessage, {
251
+ actual: ctx.value,
252
+ expected,
253
+ diff: formatDiff(expected, ctx.value)
254
+ }),
255
+ actual: ctx.value,
256
+ expected
257
+ });
258
+ }
259
+ }
260
+ function assertToEqual(ctx, expected) {
261
+ const pass = expectUtils.equals(ctx.value, expected, EQUALITY_TESTERS);
262
+ if (ctx.negated ? pass : !pass) {
263
+ const baseMessage = ctx.negated ? "Expected values not to be deeply equal" : "Expected values to be deeply equal";
264
+ ctx.fail("toEqual", {
265
+ message: buildFailureMessage("toEqual", baseMessage, {
266
+ actual: ctx.value,
267
+ expected,
268
+ diff: formatDiff(expected, ctx.value)
269
+ }),
270
+ actual: ctx.value,
271
+ expected
272
+ });
273
+ }
274
+ }
275
+ function assertToStrictEqual(ctx, expected) {
276
+ const pass = expectUtils.equals(ctx.value, expected, EQUALITY_TESTERS, true);
277
+ if (ctx.negated ? pass : !pass) {
278
+ const baseMessage = ctx.negated ? "Expected values not to be strictly equal (including prototypes and property definitions)" : "Expected values to be strictly equal (including prototypes and property definitions)";
279
+ ctx.fail("toStrictEqual", {
280
+ message: buildFailureMessage("toStrictEqual", baseMessage, {
281
+ actual: ctx.value,
282
+ expected,
283
+ diff: formatDiff(expected, ctx.value)
284
+ }),
285
+ actual: ctx.value,
286
+ expected
287
+ });
288
+ }
289
+ }
290
+
291
+ // src/matchers/instance.ts
292
+ function assertToBeInstanceOf(ctx, ctor) {
293
+ if (typeof ctor !== "function") {
294
+ ctx.fail("toBeInstanceOf", {
295
+ message: buildFailureMessage("toBeInstanceOf", "Constructor must be a callable function", {
296
+ expected: ctor
297
+ }),
298
+ expected: ctor
299
+ });
300
+ }
301
+ const pass = ctx.value instanceof ctor;
302
+ if (ctx.negated ? pass : !pass) {
303
+ const label = ctor.name || "<anonymous>";
304
+ const baseMessage = ctx.negated ? `Expected value not to be an instance of ${label}` : `Expected value to be an instance of ${label}`;
305
+ ctx.fail("toBeInstanceOf", {
306
+ message: buildFailureMessage("toBeInstanceOf", baseMessage, {
307
+ expected: ctor,
308
+ actual: ctx.value
309
+ }),
310
+ expected: ctor,
311
+ actual: ctx.value
312
+ });
313
+ }
314
+ return ctx.value;
315
+ }
316
+
317
+ // src/matchers/nullish.ts
318
+ var NIL_MESSAGE = "Value is null or undefined";
319
+ function assertToBeDefined(ctx) {
320
+ const isDefined = ctx.value !== null && typeof ctx.value !== "undefined";
321
+ if (ctx.negated ? isDefined : !isDefined) {
322
+ const baseMessage = ctx.negated ? "Expected value to be null or undefined" : NIL_MESSAGE;
323
+ ctx.fail("toBeDefined", {
324
+ message: buildFailureMessage("toBeDefined", baseMessage, {
325
+ actual: ctx.value
326
+ }),
327
+ actual: ctx.value
328
+ });
329
+ }
330
+ return ctx.value;
331
+ }
332
+ function assertToBeUndefined(ctx) {
333
+ const isUndefined = typeof ctx.value === "undefined";
334
+ if (ctx.negated ? isUndefined : !isUndefined) {
335
+ const baseMessage = ctx.negated ? "Expected value not to be undefined" : "Expected value to be undefined";
336
+ ctx.fail("toBeUndefined", {
337
+ message: buildFailureMessage("toBeUndefined", baseMessage, {
338
+ actual: ctx.value
339
+ }),
340
+ actual: ctx.value
341
+ });
342
+ }
343
+ return void 0;
344
+ }
345
+ function assertToBeNull(ctx) {
346
+ const isNull = ctx.value === null;
347
+ if (ctx.negated ? isNull : !isNull) {
348
+ const baseMessage = ctx.negated ? "Expected value not to be null" : "Expected value to be null";
349
+ ctx.fail("toBeNull", {
350
+ message: buildFailureMessage("toBeNull", baseMessage, {
351
+ actual: ctx.value
352
+ }),
353
+ actual: ctx.value
354
+ });
355
+ }
356
+ return null;
357
+ }
358
+
359
+ // src/matchers/numeric.ts
360
+ function requireFiniteNumber(ctx, matcher) {
361
+ const value = ctx.value;
362
+ if (typeof value !== "number" || !Number.isFinite(value)) {
363
+ ctx.fail(matcher, {
364
+ message: buildFailureMessage(
365
+ matcher,
366
+ "Expected value to be a finite number",
367
+ { actual: value }
368
+ ),
369
+ actual: value,
370
+ expected: "finite number"
371
+ });
372
+ }
373
+ return value;
374
+ }
375
+ function requireFiniteExpected(ctx, matcher, expected, name = "expected") {
376
+ if (typeof expected !== "number" || !Number.isFinite(expected)) {
377
+ ctx.fail(matcher, {
378
+ message: buildFailureMessage(
379
+ matcher,
380
+ `Expected ${name} to be a finite number`,
381
+ { actual: expected }
382
+ ),
383
+ actual: expected,
384
+ expected: "finite number"
385
+ });
386
+ }
387
+ }
388
+ function assertToBeGreaterThan(ctx, expected) {
389
+ const actual = requireFiniteNumber(ctx, "toBeGreaterThan");
390
+ requireFiniteExpected(ctx, "toBeGreaterThan", expected);
391
+ const pass = actual > expected;
392
+ if (shouldFail(pass, ctx.negated)) {
393
+ const baseMessage = ctx.negated ? `Expected value not to be greater than ${expected}` : `Expected value to be greater than ${expected}`;
394
+ ctx.fail("toBeGreaterThan", {
395
+ message: buildFailureMessage("toBeGreaterThan", baseMessage, {
396
+ expected,
397
+ actual
398
+ }),
399
+ actual,
400
+ expected
401
+ });
402
+ }
403
+ return actual;
404
+ }
405
+ function assertToBeGreaterThanOrEqual(ctx, expected) {
406
+ const actual = requireFiniteNumber(ctx, "toBeGreaterThanOrEqual");
407
+ requireFiniteExpected(
408
+ ctx,
409
+ "toBeGreaterThanOrEqual",
410
+ expected
411
+ );
412
+ const pass = actual >= expected;
413
+ if (shouldFail(pass, ctx.negated)) {
414
+ const baseMessage = ctx.negated ? `Expected value not to be greater than or equal to ${expected}` : `Expected value to be greater than or equal to ${expected}`;
415
+ ctx.fail("toBeGreaterThanOrEqual", {
416
+ message: buildFailureMessage("toBeGreaterThanOrEqual", baseMessage, {
417
+ expected,
418
+ actual
419
+ }),
420
+ actual,
421
+ expected
422
+ });
423
+ }
424
+ return actual;
425
+ }
426
+ function assertToBeLessThan(ctx, expected) {
427
+ const actual = requireFiniteNumber(ctx, "toBeLessThan");
428
+ requireFiniteExpected(ctx, "toBeLessThan", expected);
429
+ const pass = actual < expected;
430
+ if (shouldFail(pass, ctx.negated)) {
431
+ const baseMessage = ctx.negated ? `Expected value not to be less than ${expected}` : `Expected value to be less than ${expected}`;
432
+ ctx.fail("toBeLessThan", {
433
+ message: buildFailureMessage("toBeLessThan", baseMessage, {
434
+ expected,
435
+ actual
436
+ }),
437
+ actual,
438
+ expected
439
+ });
440
+ }
441
+ return actual;
442
+ }
443
+ function assertToBeLessThanOrEqual(ctx, expected) {
444
+ const actual = requireFiniteNumber(ctx, "toBeLessThanOrEqual");
445
+ requireFiniteExpected(
446
+ ctx,
447
+ "toBeLessThanOrEqual",
448
+ expected
449
+ );
450
+ const pass = actual <= expected;
451
+ if (shouldFail(pass, ctx.negated)) {
452
+ const baseMessage = ctx.negated ? `Expected value not to be less than or equal to ${expected}` : `Expected value to be less than or equal to ${expected}`;
453
+ ctx.fail("toBeLessThanOrEqual", {
454
+ message: buildFailureMessage("toBeLessThanOrEqual", baseMessage, {
455
+ expected,
456
+ actual
457
+ }),
458
+ actual,
459
+ expected
460
+ });
461
+ }
462
+ return actual;
463
+ }
464
+ function assertToBeCloseTo(ctx, expected, precision = 2) {
465
+ const actual = requireFiniteNumber(ctx, "toBeCloseTo");
466
+ requireFiniteExpected(ctx, "toBeCloseTo", expected);
467
+ if (!Number.isInteger(precision) || precision < 0 || precision > 20) {
468
+ ctx.fail("toBeCloseTo", {
469
+ message: buildFailureMessage(
470
+ "toBeCloseTo",
471
+ "Expected precision to be an integer between 0 and 20",
472
+ { actual: precision }
473
+ ),
474
+ actual: precision,
475
+ expected: "integer between 0 and 20"
476
+ });
477
+ }
478
+ const tolerance = Math.pow(10, -precision) / 2;
479
+ const difference = Math.abs(actual - expected);
480
+ const epsilon = Number.EPSILON * Math.max(1, Math.abs(actual), Math.abs(expected)) * 2;
481
+ const pass = difference <= tolerance + epsilon;
482
+ if (shouldFail(pass, ctx.negated)) {
483
+ const baseMessage = ctx.negated ? `Expected value not to be close to ${expected} (precision ${precision})` : `Expected value to be close to ${expected} (precision ${precision})`;
484
+ ctx.fail("toBeCloseTo", {
485
+ message: buildFailureMessage("toBeCloseTo", baseMessage, {
486
+ expected,
487
+ actual,
488
+ extra: [
489
+ `Difference: ${difference}`,
490
+ `Tolerance: ${tolerance}`
491
+ ]
492
+ }),
493
+ actual,
494
+ expected
495
+ });
496
+ }
497
+ return actual;
498
+ }
499
+
500
+ // src/matchers/truthiness.ts
501
+ function assertToBeTruthy(ctx) {
502
+ const pass = Boolean(ctx.value);
503
+ if (ctx.negated ? pass : !pass) {
504
+ const baseMessage = ctx.negated ? "Expected value to be falsy" : "Expected value to be truthy";
505
+ ctx.fail("toBeTruthy", {
506
+ message: buildFailureMessage("toBeTruthy", baseMessage, {
507
+ actual: ctx.value
508
+ }),
509
+ actual: ctx.value
510
+ });
511
+ }
512
+ }
513
+ function assertToBeFalsy(ctx) {
514
+ const pass = !ctx.value;
515
+ if (ctx.negated ? pass : !pass) {
516
+ const baseMessage = ctx.negated ? "Expected value to be truthy" : "Expected value to be falsy";
517
+ ctx.fail("toBeFalsy", {
518
+ message: buildFailureMessage("toBeFalsy", baseMessage, {
519
+ actual: ctx.value
520
+ }),
521
+ actual: ctx.value
522
+ });
523
+ }
524
+ }
525
+
526
+ // src/ensure.ts
527
+ function ensure(value, options = {}) {
528
+ const state = {
529
+ value,
530
+ negated: false,
531
+ ...options.label !== void 0 ? { label: options.label } : {}
532
+ };
533
+ return new EnsureChainImpl(state);
534
+ }
535
+ var EnsureChainImpl = class _EnsureChainImpl {
536
+ constructor(state) {
537
+ this.state = state;
538
+ }
539
+ get value() {
540
+ return this.state.value;
541
+ }
542
+ get not() {
543
+ const toggled = !this.state.negated;
544
+ const nextState = {
545
+ value: this.state.value,
546
+ negated: toggled,
547
+ ...this.state.label !== void 0 ? { label: this.state.label } : {}
548
+ };
549
+ return new _EnsureChainImpl(
550
+ nextState
551
+ );
552
+ }
553
+ toBe(expected) {
554
+ assertToBe(this.createContext(), expected);
555
+ return this;
556
+ }
557
+ toEqual(expected) {
558
+ assertToEqual(this.createContext(), expected);
559
+ return this;
560
+ }
561
+ toStrictEqual(expected) {
562
+ assertToStrictEqual(this.createContext(), expected);
563
+ return this;
564
+ }
565
+ toBeDefined() {
566
+ const defined = assertToBeDefined(this.createContext());
567
+ const next = this.state.negated ? this : this.rewrap(defined);
568
+ return next;
569
+ }
570
+ toBeUndefined() {
571
+ const result = assertToBeUndefined(this.createContext());
572
+ const next = this.state.negated ? this : this.rewrap(result);
573
+ return next;
574
+ }
575
+ toBeNull() {
576
+ const result = assertToBeNull(this.createContext());
577
+ const next = this.state.negated ? this : this.rewrap(result);
578
+ return next;
579
+ }
580
+ toBeTruthy() {
581
+ assertToBeTruthy(this.createContext());
582
+ return this;
583
+ }
584
+ toBeFalsy() {
585
+ assertToBeFalsy(this.createContext());
586
+ return this;
587
+ }
588
+ toBeGreaterThan(expected) {
589
+ const actual = assertToBeGreaterThan(this.createContext(), expected);
590
+ const next = this.state.negated ? this : this.rewrap(actual);
591
+ return next;
592
+ }
593
+ toBeGreaterThanOrEqual(expected) {
594
+ const actual = assertToBeGreaterThanOrEqual(this.createContext(), expected);
595
+ const next = this.state.negated ? this : this.rewrap(actual);
596
+ return next;
597
+ }
598
+ toBeLessThan(expected) {
599
+ const actual = assertToBeLessThan(this.createContext(), expected);
600
+ const next = this.state.negated ? this : this.rewrap(actual);
601
+ return next;
602
+ }
603
+ toBeLessThanOrEqual(expected) {
604
+ const actual = assertToBeLessThanOrEqual(this.createContext(), expected);
605
+ const next = this.state.negated ? this : this.rewrap(actual);
606
+ return next;
607
+ }
608
+ toBeCloseTo(expected, precision) {
609
+ const actual = assertToBeCloseTo(this.createContext(), expected, precision);
610
+ const next = this.state.negated ? this : this.rewrap(actual);
611
+ return next;
612
+ }
613
+ toBeInstanceOf(ctor) {
614
+ const instance = assertToBeInstanceOf(this.createContext(), ctor);
615
+ const next = this.state.negated ? this : this.rewrap(instance);
616
+ return next;
617
+ }
618
+ toBeObjectContaining(shape) {
619
+ assertObjectContaining(this.createContext(), shape);
620
+ return this;
621
+ }
622
+ toBeArrayContaining(expected) {
623
+ const array = assertArrayContaining(this.createContext(), expected);
624
+ const next = this.state.negated ? this : this.rewrap(array);
625
+ return next;
626
+ }
627
+ toContainEqual(expected) {
628
+ const array = assertContainEqual(this.createContext(), expected);
629
+ const next = this.state.negated ? this : this.rewrap(array);
630
+ return next;
631
+ }
632
+ toBeIterableContaining(expected) {
633
+ const iterable = assertIterableContaining(this.createContext(), expected);
634
+ const next = this.state.negated ? this : this.rewrap(iterable);
635
+ return next;
636
+ }
637
+ toHaveLength(expected) {
638
+ assertHasLength(this.createContext(), expected);
639
+ const next = this.state.negated ? this : this.rewrap(this.state.value);
640
+ return next;
641
+ }
642
+ createContext() {
643
+ return {
644
+ value: this.state.value,
645
+ negated: this.state.negated,
646
+ fail: (matcher, details) => this.fail(matcher, details),
647
+ ...this.state.label !== void 0 ? { label: this.state.label } : {}
648
+ };
649
+ }
650
+ rewrap(value) {
651
+ const nextState = {
652
+ value,
653
+ negated: this.state.negated,
654
+ ...this.state.label !== void 0 ? { label: this.state.label } : {}
655
+ };
656
+ return new _EnsureChainImpl(
657
+ nextState
658
+ );
659
+ }
660
+ fail(matcher, details) {
661
+ const errorDetails = {
662
+ matcher,
663
+ message: details.message,
664
+ ...details.actual !== void 0 ? { actual: details.actual } : {},
665
+ ...details.expected !== void 0 ? { expected: details.expected } : {},
666
+ ...this.state.label !== void 0 ? { receivedLabel: this.state.label } : {}
667
+ };
668
+ throw new EnsureError(errorDetails);
669
+ }
670
+ };
671
+
672
+ // src/plugins.ts
673
+ function createEnsureFactory(ensureFn, plugins) {
674
+ const withAlways = (invoker, always) => {
675
+ Object.defineProperty(invoker, "always", {
676
+ value: always,
677
+ enumerable: false,
678
+ configurable: false,
679
+ writable: false
680
+ });
681
+ return invoker;
682
+ };
683
+ const positiveEnsure = withAlways(ensureFn, ensureFn);
684
+ const pluginEntries = Object.keys(plugins).map((key) => {
685
+ const plugin = plugins[key];
686
+ if (!plugin) {
687
+ throw new Error(`Assertion plugin "${String(key)}" is not defined.`);
688
+ }
689
+ const factory = plugin({ ensure: positiveEnsure, isNot: false });
690
+ return [key, factory];
691
+ });
692
+ const negatedEnsureFn = (value, options) => {
693
+ return ensureFn(value, options).not;
694
+ };
695
+ const negativeEnsure = withAlways(negatedEnsureFn, ensureFn);
696
+ const negativePluginEntries = Object.keys(plugins).map((key) => {
697
+ const plugin = plugins[key];
698
+ if (!plugin) {
699
+ throw new Error(`Assertion plugin "${String(key)}" is not defined.`);
700
+ }
701
+ const factory = plugin({ ensure: negativeEnsure, isNot: true });
702
+ return [key, factory];
703
+ });
704
+ return (world) => {
705
+ const facade = (value, options) => ensureFn(value, options);
706
+ Object.defineProperty(facade, "world", {
707
+ value: world,
708
+ enumerable: false,
709
+ configurable: false,
710
+ writable: false
711
+ });
712
+ for (const [key, buildFacet] of pluginEntries) {
713
+ const facet = buildFacet(world);
714
+ Object.defineProperty(facade, key, {
715
+ value: facet,
716
+ enumerable: true,
717
+ configurable: false,
718
+ writable: false
719
+ });
720
+ }
721
+ const notFacade = {};
722
+ for (const [key, buildFacet] of negativePluginEntries) {
723
+ const facet = buildFacet(world);
724
+ Object.defineProperty(notFacade, key, {
725
+ value: facet,
726
+ enumerable: true,
727
+ configurable: false,
728
+ writable: false
729
+ });
730
+ }
731
+ Object.defineProperty(facade, "not", {
732
+ value: notFacade,
733
+ enumerable: true,
734
+ configurable: false,
735
+ writable: false
736
+ });
737
+ return facade;
738
+ };
739
+ }
740
+ function createDefaultEnsureFactory() {
741
+ return createEnsureFactory(ensure, {});
742
+ }
743
+
744
+ // src/plugins/runtime-assertions-plugin.ts
745
+ var runtimeAssertionsPlugin = () => ({ ensure: ensure2 }) => (world) => {
746
+ const defaultTableLabel = "step data table";
747
+ const defaultDocstringLabel = "step docstring";
748
+ function table(shape, options) {
749
+ return world.runtime.getTable(shape, options);
750
+ }
751
+ function consumeTable(shape, options) {
752
+ return world.runtime.consumeTable(shape, options);
753
+ }
754
+ function requireTable(shape, options) {
755
+ const { label, ...tableOptions } = options ?? {};
756
+ const table2 = consumeTable(shape, tableOptions);
757
+ return ensure2.always(table2, {
758
+ label: label ?? `Expected ${shape} ${defaultTableLabel} to be attached to the current step.`
759
+ }).toBeDefined().value;
760
+ }
761
+ function consumeRawTable(options) {
762
+ const tableInstance = consumeTable("headerless", options);
763
+ return tableInstance?.raw();
764
+ }
765
+ function requireRawTable(options) {
766
+ const { label, ...tableOptions } = options ?? {};
767
+ const raw = consumeRawTable(tableOptions);
768
+ return ensure2.always(raw, {
769
+ label: label ?? `Expected ${defaultTableLabel} to be attached to the current step.`
770
+ }).toBeDefined().value;
771
+ }
772
+ return {
773
+ hasTable(options) {
774
+ ensure2(world.runtime.hasTable, {
775
+ label: options?.label ?? `${defaultTableLabel} is present`
776
+ }).toBeTruthy();
777
+ },
778
+ hasDocstring(options) {
779
+ ensure2(world.runtime.hasDocstring, {
780
+ label: options?.label ?? `${defaultDocstringLabel} is present`
781
+ }).toBeTruthy();
782
+ },
783
+ docstring() {
784
+ return world.runtime.getDocstring();
785
+ },
786
+ consumeDocstring() {
787
+ return world.runtime.consumeDocstring();
788
+ },
789
+ requireDocstring(options) {
790
+ const docstring = world.runtime.consumeDocstring();
791
+ return ensure2.always(docstring, {
792
+ label: options?.label ?? `Expected ${defaultDocstringLabel} to be attached to the current step.`
793
+ }).toBeDefined().value;
794
+ },
795
+ table,
796
+ consumeTable,
797
+ requireTable,
798
+ rawTable() {
799
+ return world.runtime.getRawTable();
800
+ },
801
+ consumeRawTable,
802
+ requireRawTable,
803
+ stepMetadata() {
804
+ return world.runtime.getStepMetadata();
805
+ }
806
+ };
807
+ };
808
+
809
+ exports.EnsureError = EnsureError;
810
+ exports.createDefaultEnsureFactory = createDefaultEnsureFactory;
811
+ exports.createEnsureFactory = createEnsureFactory;
812
+ exports.ensure = ensure;
813
+ exports.runtimeAssertionsPlugin = runtimeAssertionsPlugin;
814
+ //# sourceMappingURL=out.js.map
815
+ //# sourceMappingURL=index.cjs.map