bupkis 0.7.2 → 0.9.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/CHANGELOG.md +15 -0
- package/README.md +19 -2
- package/dist/commonjs/assertion/assertion-async.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion-async.js +37 -7
- package/dist/commonjs/assertion/assertion-async.js.map +1 -1
- package/dist/commonjs/assertion/assertion-sync.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion-sync.js +32 -8
- package/dist/commonjs/assertion/assertion-sync.js.map +1 -1
- package/dist/commonjs/assertion/assertion-types.d.ts +37 -31
- package/dist/commonjs/assertion/assertion-types.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion-types.js +0 -32
- package/dist/commonjs/assertion/assertion-types.js.map +1 -1
- package/dist/commonjs/assertion/assertion.d.ts +3 -21
- package/dist/commonjs/assertion/assertion.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion.js +42 -27
- package/dist/commonjs/assertion/assertion.js.map +1 -1
- package/dist/commonjs/assertion/create.d.ts +2 -0
- package/dist/commonjs/assertion/create.d.ts.map +1 -1
- package/dist/commonjs/assertion/create.js +38 -42
- package/dist/commonjs/assertion/create.js.map +1 -1
- package/dist/commonjs/assertion/impl/assertion-util.d.ts +16 -4
- package/dist/commonjs/assertion/impl/assertion-util.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/assertion-util.js +20 -15
- package/dist/commonjs/assertion/impl/assertion-util.js.map +1 -1
- package/dist/commonjs/assertion/impl/async-parametric.d.ts +63 -11
- package/dist/commonjs/assertion/impl/async-parametric.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/async-parametric.js +89 -52
- package/dist/commonjs/assertion/impl/async-parametric.js.map +1 -1
- package/dist/commonjs/assertion/impl/async.d.ts +116 -12
- package/dist/commonjs/assertion/impl/async.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/async.js +1 -1
- package/dist/commonjs/assertion/impl/sync-basic.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync-basic.js +6 -4
- package/dist/commonjs/assertion/impl/sync-basic.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-collection.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync-collection.js +24 -14
- package/dist/commonjs/assertion/impl/sync-collection.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-esoteric.d.ts +1 -5
- package/dist/commonjs/assertion/impl/sync-esoteric.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync-esoteric.js +11 -13
- package/dist/commonjs/assertion/impl/sync-esoteric.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-parametric.d.ts +27 -7
- package/dist/commonjs/assertion/impl/sync-parametric.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync-parametric.js +75 -51
- package/dist/commonjs/assertion/impl/sync-parametric.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync.d.ts +54 -22
- package/dist/commonjs/assertion/impl/sync.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync.js +1 -1
- package/dist/commonjs/assertion/impl/sync.js.map +1 -1
- package/dist/commonjs/assertion/index.d.ts +1 -1
- package/dist/commonjs/assertion/index.d.ts.map +1 -1
- package/dist/commonjs/assertion/index.js +0 -1
- package/dist/commonjs/assertion/index.js.map +1 -1
- package/dist/commonjs/assertion/slotify.d.ts +1 -13
- package/dist/commonjs/assertion/slotify.d.ts.map +1 -1
- package/dist/commonjs/assertion/slotify.js +49 -16
- package/dist/commonjs/assertion/slotify.js.map +1 -1
- package/dist/commonjs/bootstrap.d.ts +85 -17
- package/dist/commonjs/bootstrap.d.ts.map +1 -1
- package/dist/commonjs/bootstrap.js +1 -0
- package/dist/commonjs/bootstrap.js.map +1 -1
- package/dist/commonjs/diff.d.ts +51 -0
- package/dist/commonjs/diff.d.ts.map +1 -0
- package/dist/commonjs/diff.js +279 -0
- package/dist/commonjs/diff.js.map +1 -0
- package/dist/commonjs/error.d.ts +37 -18
- package/dist/commonjs/error.d.ts.map +1 -1
- package/dist/commonjs/error.js +44 -30
- package/dist/commonjs/error.js.map +1 -1
- package/dist/commonjs/expect.d.ts.map +1 -1
- package/dist/commonjs/expect.js +131 -78
- package/dist/commonjs/expect.js.map +1 -1
- package/dist/commonjs/guards.d.ts +24 -10
- package/dist/commonjs/guards.d.ts.map +1 -1
- package/dist/commonjs/guards.js +56 -39
- package/dist/commonjs/guards.js.map +1 -1
- package/dist/commonjs/index.d.ts +85 -17
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/internal-schema.d.ts +25 -0
- package/dist/commonjs/internal-schema.d.ts.map +1 -0
- package/dist/commonjs/internal-schema.js +209 -0
- package/dist/commonjs/internal-schema.js.map +1 -0
- package/dist/commonjs/schema.d.ts.map +1 -1
- package/dist/commonjs/schema.js +3 -2
- package/dist/commonjs/schema.js.map +1 -1
- package/dist/commonjs/use.js +22 -8
- package/dist/commonjs/use.js.map +1 -1
- package/dist/commonjs/util.d.ts +1 -0
- package/dist/commonjs/util.d.ts.map +1 -1
- package/dist/commonjs/util.js +14 -10
- package/dist/commonjs/util.js.map +1 -1
- package/dist/commonjs/value-to-schema.d.ts +1 -0
- package/dist/commonjs/value-to-schema.d.ts.map +1 -1
- package/dist/commonjs/value-to-schema.js +19 -12
- package/dist/commonjs/value-to-schema.js.map +1 -1
- package/dist/esm/assertion/assertion-async.d.ts.map +1 -1
- package/dist/esm/assertion/assertion-async.js +37 -7
- package/dist/esm/assertion/assertion-async.js.map +1 -1
- package/dist/esm/assertion/assertion-sync.d.ts.map +1 -1
- package/dist/esm/assertion/assertion-sync.js +32 -8
- package/dist/esm/assertion/assertion-sync.js.map +1 -1
- package/dist/esm/assertion/assertion-types.d.ts +37 -31
- package/dist/esm/assertion/assertion-types.d.ts.map +1 -1
- package/dist/esm/assertion/assertion-types.js +1 -31
- package/dist/esm/assertion/assertion-types.js.map +1 -1
- package/dist/esm/assertion/assertion.d.ts +3 -21
- package/dist/esm/assertion/assertion.d.ts.map +1 -1
- package/dist/esm/assertion/assertion.js +42 -27
- package/dist/esm/assertion/assertion.js.map +1 -1
- package/dist/esm/assertion/create.d.ts +2 -0
- package/dist/esm/assertion/create.d.ts.map +1 -1
- package/dist/esm/assertion/create.js +37 -41
- package/dist/esm/assertion/create.js.map +1 -1
- package/dist/esm/assertion/impl/assertion-util.d.ts +16 -4
- package/dist/esm/assertion/impl/assertion-util.d.ts.map +1 -1
- package/dist/esm/assertion/impl/assertion-util.js +20 -15
- package/dist/esm/assertion/impl/assertion-util.js.map +1 -1
- package/dist/esm/assertion/impl/async-parametric.d.ts +63 -11
- package/dist/esm/assertion/impl/async-parametric.d.ts.map +1 -1
- package/dist/esm/assertion/impl/async-parametric.js +89 -52
- package/dist/esm/assertion/impl/async-parametric.js.map +1 -1
- package/dist/esm/assertion/impl/async.d.ts +116 -12
- package/dist/esm/assertion/impl/async.d.ts.map +1 -1
- package/dist/esm/assertion/impl/async.js +2 -2
- package/dist/esm/assertion/impl/async.js.map +1 -1
- package/dist/esm/assertion/impl/sync-basic.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync-basic.js +6 -4
- package/dist/esm/assertion/impl/sync-basic.js.map +1 -1
- package/dist/esm/assertion/impl/sync-collection.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync-collection.js +24 -14
- package/dist/esm/assertion/impl/sync-collection.js.map +1 -1
- package/dist/esm/assertion/impl/sync-esoteric.d.ts +1 -5
- package/dist/esm/assertion/impl/sync-esoteric.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync-esoteric.js +11 -13
- package/dist/esm/assertion/impl/sync-esoteric.js.map +1 -1
- package/dist/esm/assertion/impl/sync-parametric.d.ts +27 -7
- package/dist/esm/assertion/impl/sync-parametric.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync-parametric.js +75 -51
- package/dist/esm/assertion/impl/sync-parametric.js.map +1 -1
- package/dist/esm/assertion/impl/sync.d.ts +54 -22
- package/dist/esm/assertion/impl/sync.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync.js +2 -2
- package/dist/esm/assertion/impl/sync.js.map +1 -1
- package/dist/esm/assertion/index.d.ts +1 -1
- package/dist/esm/assertion/index.d.ts.map +1 -1
- package/dist/esm/assertion/index.js +0 -1
- package/dist/esm/assertion/index.js.map +1 -1
- package/dist/esm/assertion/slotify.d.ts +1 -13
- package/dist/esm/assertion/slotify.d.ts.map +1 -1
- package/dist/esm/assertion/slotify.js +50 -17
- package/dist/esm/assertion/slotify.js.map +1 -1
- package/dist/esm/bootstrap.d.ts +85 -17
- package/dist/esm/bootstrap.d.ts.map +1 -1
- package/dist/esm/bootstrap.js +1 -0
- package/dist/esm/bootstrap.js.map +1 -1
- package/dist/esm/diff.d.ts +51 -0
- package/dist/esm/diff.d.ts.map +1 -0
- package/dist/esm/diff.js +273 -0
- package/dist/esm/diff.js.map +1 -0
- package/dist/esm/error.d.ts +37 -18
- package/dist/esm/error.d.ts.map +1 -1
- package/dist/esm/error.js +41 -27
- package/dist/esm/error.js.map +1 -1
- package/dist/esm/expect.d.ts.map +1 -1
- package/dist/esm/expect.js +133 -80
- package/dist/esm/expect.js.map +1 -1
- package/dist/esm/guards.d.ts +24 -10
- package/dist/esm/guards.d.ts.map +1 -1
- package/dist/esm/guards.js +52 -36
- package/dist/esm/guards.js.map +1 -1
- package/dist/esm/index.d.ts +85 -17
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/internal-schema.d.ts +25 -0
- package/dist/esm/internal-schema.d.ts.map +1 -0
- package/dist/esm/internal-schema.js +203 -0
- package/dist/esm/internal-schema.js.map +1 -0
- package/dist/esm/schema.d.ts.map +1 -1
- package/dist/esm/schema.js +3 -2
- package/dist/esm/schema.js.map +1 -1
- package/dist/esm/use.js +19 -6
- package/dist/esm/use.js.map +1 -1
- package/dist/esm/util.d.ts +1 -0
- package/dist/esm/util.d.ts.map +1 -1
- package/dist/esm/util.js +14 -10
- package/dist/esm/util.js.map +1 -1
- package/dist/esm/value-to-schema.d.ts +1 -0
- package/dist/esm/value-to-schema.d.ts.map +1 -1
- package/dist/esm/value-to-schema.js +20 -13
- package/dist/esm/value-to-schema.js.map +1 -1
- package/package.json +29 -11
- package/src/assertion/assertion-async.ts +42 -14
- package/src/assertion/assertion-sync.ts +40 -17
- package/src/assertion/assertion-types.ts +55 -45
- package/src/assertion/assertion.ts +49 -32
- package/src/assertion/create.ts +46 -65
- package/src/assertion/impl/assertion-util.ts +31 -18
- package/src/assertion/impl/async-parametric.ts +93 -52
- package/src/assertion/impl/async.ts +2 -2
- package/src/assertion/impl/sync-basic.ts +7 -4
- package/src/assertion/impl/sync-collection.ts +34 -14
- package/src/assertion/impl/sync-esoteric.ts +17 -13
- package/src/assertion/impl/sync-parametric.ts +79 -52
- package/src/assertion/impl/sync.ts +2 -2
- package/src/assertion/index.ts +1 -1
- package/src/assertion/slotify.ts +67 -21
- package/src/bootstrap.ts +1 -0
- package/src/diff.ts +343 -0
- package/src/error.ts +66 -31
- package/src/expect.ts +195 -129
- package/src/guards.ts +74 -48
- package/src/internal-schema.ts +246 -0
- package/src/schema.ts +4 -2
- package/src/use.ts +21 -7
- package/src/util.ts +15 -12
- package/src/value-to-schema.ts +21 -13
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
import { inspect } from 'node:util';
|
|
17
17
|
import { z } from 'zod/v4';
|
|
18
18
|
|
|
19
|
-
import { BupkisError,
|
|
19
|
+
import { BupkisError, InvalidObjectSchemaError } from '../../error.js';
|
|
20
20
|
import { isA, isError, isNonNullObject, isString } from '../../guards.js';
|
|
21
21
|
import {
|
|
22
22
|
ArrayLikeSchema,
|
|
@@ -34,10 +34,13 @@ import {
|
|
|
34
34
|
import { createAssertion } from '../create.js';
|
|
35
35
|
import { trapError } from './assertion-util.js';
|
|
36
36
|
|
|
37
|
+
const { freeze } = Object;
|
|
38
|
+
const { abs } = Math;
|
|
39
|
+
|
|
37
40
|
/**
|
|
38
41
|
* For {@link typeOfAssertion}
|
|
39
42
|
*/
|
|
40
|
-
const knownTypes =
|
|
43
|
+
const knownTypes = freeze(
|
|
41
44
|
new Set([
|
|
42
45
|
'string',
|
|
43
46
|
'number',
|
|
@@ -271,7 +274,7 @@ export const numberWithinRangeAssertion = createAssertion(
|
|
|
271
274
|
export const numberCloseToAssertion = createAssertion(
|
|
272
275
|
[z.number(), 'to be close to', z.number(), z.number().optional()],
|
|
273
276
|
(subject, expected, tolerance = 1e-9) => {
|
|
274
|
-
const diff =
|
|
277
|
+
const diff = abs(subject - expected);
|
|
275
278
|
if (diff > tolerance) {
|
|
276
279
|
return {
|
|
277
280
|
actual: subject,
|
|
@@ -634,14 +637,19 @@ export const arrayDeepEqualAssertion = createAssertion(
|
|
|
634
637
|
export const functionThrowsAssertion = createAssertion(
|
|
635
638
|
[FunctionSchema, 'to throw'],
|
|
636
639
|
(subject) => {
|
|
637
|
-
const error = trapError(subject);
|
|
638
|
-
if (
|
|
640
|
+
const { error, result } = trapError(subject);
|
|
641
|
+
if (error === undefined) {
|
|
639
642
|
return {
|
|
640
|
-
actual:
|
|
643
|
+
actual: result,
|
|
641
644
|
message: `Expected function to throw, but it did not`,
|
|
642
645
|
};
|
|
643
646
|
}
|
|
644
647
|
},
|
|
648
|
+
{
|
|
649
|
+
anchor: 'function-to-throw-any',
|
|
650
|
+
category: 'function',
|
|
651
|
+
redirect: 'to-throw',
|
|
652
|
+
},
|
|
645
653
|
);
|
|
646
654
|
|
|
647
655
|
/**
|
|
@@ -671,21 +679,27 @@ export const functionThrowsAssertion = createAssertion(
|
|
|
671
679
|
export const functionThrowsTypeAssertion = createAssertion(
|
|
672
680
|
[FunctionSchema, ['to throw a', 'to throw an'], ConstructibleSchema],
|
|
673
681
|
(subject, ctor) => {
|
|
674
|
-
const error = trapError(subject);
|
|
675
|
-
if (
|
|
676
|
-
return
|
|
682
|
+
const { error, result } = trapError(subject);
|
|
683
|
+
if (error === undefined) {
|
|
684
|
+
return {
|
|
685
|
+
actual: result,
|
|
686
|
+
expected: `to throw instance of ${ctor.name}`,
|
|
687
|
+
message: 'Expected function to throw, but it did not',
|
|
688
|
+
};
|
|
677
689
|
}
|
|
678
|
-
if (!(error
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
690
|
+
if (!isA(error, ctor)) {
|
|
691
|
+
if (isNonNullObject(error)) {
|
|
692
|
+
const err = error as object;
|
|
693
|
+
return {
|
|
694
|
+
actual: err.constructor.name,
|
|
695
|
+
expected: ctor.name,
|
|
696
|
+
message: `Expected function to throw with an instance of ${ctor.name}, but it threw with a ${err.constructor.name}`,
|
|
697
|
+
};
|
|
684
698
|
}
|
|
685
699
|
return {
|
|
686
|
-
actual: error,
|
|
687
|
-
expected: ctor,
|
|
688
|
-
message,
|
|
700
|
+
actual: typeof error,
|
|
701
|
+
expected: ctor.name,
|
|
702
|
+
message: `Expected function to throw with an instance of ${ctor.name}, but it threw a value of type ${typeof error}: ${inspect(error)}`,
|
|
689
703
|
};
|
|
690
704
|
}
|
|
691
705
|
},
|
|
@@ -723,33 +737,41 @@ export const functionThrowsTypeAssertion = createAssertion(
|
|
|
723
737
|
*
|
|
724
738
|
* @group Parametric Assertions (Sync)
|
|
725
739
|
*/
|
|
726
|
-
export const
|
|
740
|
+
export const functionThrowsSatisfyingAssertion = createAssertion(
|
|
727
741
|
[FunctionSchema, ['to throw', 'to throw error satisfying'], z.any()],
|
|
728
742
|
(subject, param) => {
|
|
729
|
-
const error = trapError(subject);
|
|
730
|
-
if (
|
|
731
|
-
return
|
|
743
|
+
const { error, result } = trapError(subject);
|
|
744
|
+
if (error === undefined) {
|
|
745
|
+
return {
|
|
746
|
+
actual: result,
|
|
747
|
+
expected: 'to throw',
|
|
748
|
+
message: 'Expected function to throw, but it did not',
|
|
749
|
+
};
|
|
732
750
|
}
|
|
733
751
|
|
|
734
752
|
if (isString(param)) {
|
|
735
|
-
return
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
753
|
+
return {
|
|
754
|
+
schema: z
|
|
755
|
+
.looseObject({
|
|
756
|
+
message: z.coerce.string().pipe(z.literal(param)),
|
|
757
|
+
})
|
|
758
|
+
.or(z.coerce.string().pipe(z.literal(param))),
|
|
759
|
+
subject: error,
|
|
760
|
+
};
|
|
741
761
|
} else if (isA(param, RegExp)) {
|
|
742
|
-
return
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
762
|
+
return {
|
|
763
|
+
schema: z
|
|
764
|
+
.looseObject({
|
|
765
|
+
message: z.coerce.string().regex(param),
|
|
766
|
+
})
|
|
767
|
+
.or(z.coerce.string().regex(param)),
|
|
768
|
+
subject: error,
|
|
769
|
+
};
|
|
748
770
|
} else if (isNonNullObject(param)) {
|
|
749
771
|
const schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
750
|
-
return schema
|
|
772
|
+
return { schema, subject: error };
|
|
751
773
|
} else {
|
|
752
|
-
throw new
|
|
774
|
+
throw new InvalidObjectSchemaError(
|
|
753
775
|
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
754
776
|
{ schema: param },
|
|
755
777
|
);
|
|
@@ -795,7 +817,14 @@ export const functionThrowsTypeSatisfyingAssertion = createAssertion(
|
|
|
795
817
|
z.any(),
|
|
796
818
|
],
|
|
797
819
|
(subject, ctor, param) => {
|
|
798
|
-
const error = trapError(subject);
|
|
820
|
+
const { error, result } = trapError(subject);
|
|
821
|
+
if (error === undefined) {
|
|
822
|
+
return {
|
|
823
|
+
actual: result,
|
|
824
|
+
expected: `to throw instance of ${ctor.name}`,
|
|
825
|
+
message: 'Expected function to throw, but it did not',
|
|
826
|
+
};
|
|
827
|
+
}
|
|
799
828
|
if (!isA(error, ctor)) {
|
|
800
829
|
return {
|
|
801
830
|
actual: error,
|
|
@@ -808,31 +837,29 @@ export const functionThrowsTypeSatisfyingAssertion = createAssertion(
|
|
|
808
837
|
let schema: undefined | z.ZodType;
|
|
809
838
|
// TODO: can valueToSchema handle the first two conditional branches?
|
|
810
839
|
if (isString(param)) {
|
|
811
|
-
schema = z
|
|
812
|
-
.
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
.or(z.coerce.string().pipe(z.literal(param)));
|
|
840
|
+
schema = z.looseObject({
|
|
841
|
+
message: z.coerce.string().pipe(z.literal(param)),
|
|
842
|
+
});
|
|
843
|
+
// .or(z.coerce.string().pipe(z.literal(param)));
|
|
816
844
|
} else if (isA(param, RegExp)) {
|
|
817
|
-
schema = z
|
|
818
|
-
.
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
.or(z.coerce.string().regex(param));
|
|
845
|
+
schema = z.looseObject({
|
|
846
|
+
message: z.coerce.string().regex(param),
|
|
847
|
+
});
|
|
848
|
+
// .or(z.coerce.string().regex(param));
|
|
822
849
|
} else if (isNonNullObject(param)) {
|
|
823
850
|
schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
824
851
|
}
|
|
825
852
|
if (!schema) {
|
|
826
|
-
throw new
|
|
853
|
+
throw new InvalidObjectSchemaError(
|
|
827
854
|
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
828
855
|
{ schema: param },
|
|
829
856
|
);
|
|
830
857
|
}
|
|
831
858
|
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
}
|
|
859
|
+
return {
|
|
860
|
+
schema,
|
|
861
|
+
subject: error,
|
|
862
|
+
};
|
|
836
863
|
},
|
|
837
864
|
);
|
|
838
865
|
|
|
@@ -100,7 +100,7 @@ import {
|
|
|
100
100
|
errorMessageMatchingAssertion,
|
|
101
101
|
functionArityAssertion,
|
|
102
102
|
functionThrowsAssertion,
|
|
103
|
-
|
|
103
|
+
functionThrowsSatisfyingAssertion,
|
|
104
104
|
functionThrowsTypeAssertion,
|
|
105
105
|
functionThrowsTypeSatisfyingAssertion,
|
|
106
106
|
instanceOfAssertion,
|
|
@@ -215,7 +215,7 @@ export const SyncParametricAssertions = [
|
|
|
215
215
|
arrayDeepEqualAssertion,
|
|
216
216
|
functionThrowsAssertion,
|
|
217
217
|
functionThrowsTypeAssertion,
|
|
218
|
-
|
|
218
|
+
functionThrowsSatisfyingAssertion,
|
|
219
219
|
functionThrowsTypeSatisfyingAssertion,
|
|
220
220
|
stringIncludesAssertion,
|
|
221
221
|
stringMatchesAssertion,
|
package/src/assertion/index.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
export { BupkisRegistry } from '../metadata.js';
|
|
14
|
-
export * from './assertion-types.js';
|
|
14
|
+
export type * from './assertion-types.js';
|
|
15
15
|
export { BupkisAssertion } from './assertion.js';
|
|
16
16
|
export { createAssertion, createAsyncAssertion } from './create.js';
|
|
17
17
|
export * from './impl/async.js';
|
package/src/assertion/slotify.ts
CHANGED
|
@@ -11,11 +11,17 @@
|
|
|
11
11
|
import { inspect } from 'util';
|
|
12
12
|
import { z } from 'zod/v4';
|
|
13
13
|
|
|
14
|
-
import type {
|
|
14
|
+
import type {
|
|
15
|
+
AssertionParts,
|
|
16
|
+
AssertionSlots,
|
|
17
|
+
PhraseLiteral,
|
|
18
|
+
PhraseLiteralChoice,
|
|
19
|
+
} from './assertion-types.js';
|
|
15
20
|
|
|
16
21
|
import { kStringLiteral } from '../constant.js';
|
|
17
22
|
import { AssertionImplementationError } from '../error.js';
|
|
18
23
|
import {
|
|
24
|
+
isPhrase,
|
|
19
25
|
isPhraseLiteral,
|
|
20
26
|
isPhraseLiteralChoice,
|
|
21
27
|
isZodType,
|
|
@@ -30,35 +36,29 @@ import { BupkisRegistry } from '../metadata.js';
|
|
|
30
36
|
* processing string literals and Zod schemas, registering metadata for runtime
|
|
31
37
|
* introspection, and handling validation constraints such as preventing "not "
|
|
32
38
|
* prefixes in string literal parts.
|
|
39
|
+
* @function
|
|
33
40
|
* @param parts Assertion parts
|
|
34
41
|
* @returns Slots
|
|
42
|
+
* @internal
|
|
35
43
|
*/
|
|
36
44
|
export const slotify = <const Parts extends AssertionParts>(
|
|
37
45
|
parts: Parts,
|
|
38
46
|
): AssertionSlots<Parts> =>
|
|
39
47
|
parts.flatMap((part, index) => {
|
|
40
48
|
const result: z.ZodType[] = [];
|
|
41
|
-
if (index === 0 && (
|
|
49
|
+
if (index === 0 && isPhrase(part)) {
|
|
42
50
|
result.push(z.unknown().describe('subject'));
|
|
43
51
|
}
|
|
44
52
|
|
|
45
53
|
if (isPhraseLiteralChoice(part)) {
|
|
46
54
|
if (part.some((p) => p.startsWith('not '))) {
|
|
47
55
|
throw new AssertionImplementationError(
|
|
48
|
-
`PhraseLiteralChoice at parts[${index}] must not include phrases starting with "not ": ${inspect(
|
|
56
|
+
`PhraseLiteralChoice at parts[${index}] must not include phrases starting with "not "; refactor to be a positive assertion: ${inspect(
|
|
49
57
|
part,
|
|
50
58
|
)}`,
|
|
51
59
|
);
|
|
52
60
|
}
|
|
53
|
-
result.push(
|
|
54
|
-
z
|
|
55
|
-
.literal(part)
|
|
56
|
-
.brand('string-literal')
|
|
57
|
-
.register(BupkisRegistry, {
|
|
58
|
-
[kStringLiteral]: true,
|
|
59
|
-
values: part,
|
|
60
|
-
}),
|
|
61
|
-
);
|
|
61
|
+
result.push(createPhraseLiteralChoiceSchema(part));
|
|
62
62
|
} else if (isPhraseLiteral(part)) {
|
|
63
63
|
if (part.startsWith('not ')) {
|
|
64
64
|
throw new AssertionImplementationError(
|
|
@@ -67,15 +67,19 @@ export const slotify = <const Parts extends AssertionParts>(
|
|
|
67
67
|
)}`,
|
|
68
68
|
);
|
|
69
69
|
}
|
|
70
|
-
result.push(
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
result.push(createPhraseLiteralSchema(part));
|
|
71
|
+
} else if (typeof part === 'string' && part === 'and') {
|
|
72
|
+
// Special case: "and" is allowed when followed by a ZodType (for conjunctify)
|
|
73
|
+
if (index + 1 >= parts.length || !isZodType(parts[index + 1])) {
|
|
74
|
+
throw new AssertionImplementationError(
|
|
75
|
+
`"and" at parts[${index}] must be followed by a Zod schema but was followed by ${
|
|
76
|
+
index + 1 >= parts.length
|
|
77
|
+
? 'nothing'
|
|
78
|
+
: `${inspect(parts[index + 1])} (${typeof parts[index + 1]})`
|
|
79
|
+
}`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
result.push(createPhraseLiteralSchema(part));
|
|
79
83
|
} else {
|
|
80
84
|
if (!isZodType(part)) {
|
|
81
85
|
throw new AssertionImplementationError(
|
|
@@ -88,3 +92,45 @@ export const slotify = <const Parts extends AssertionParts>(
|
|
|
88
92
|
}
|
|
89
93
|
return result;
|
|
90
94
|
}) as unknown as AssertionSlots<Parts>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Creates a schema for a choice of phrase literals
|
|
98
|
+
*
|
|
99
|
+
* This schema is a branded literal schema to differentiate regular strings from
|
|
100
|
+
* phrases.
|
|
101
|
+
*
|
|
102
|
+
* @function
|
|
103
|
+
* @param part Phrase literal choice (tuple of strings)
|
|
104
|
+
* @returns Schema
|
|
105
|
+
*/
|
|
106
|
+
const createPhraseLiteralChoiceSchema = (
|
|
107
|
+
part: PhraseLiteralChoice,
|
|
108
|
+
): z.core.$ZodBranded<z.ZodLiteral<string>, 'string-literal'> =>
|
|
109
|
+
z
|
|
110
|
+
.literal(part)
|
|
111
|
+
.brand('string-literal')
|
|
112
|
+
.register(BupkisRegistry, {
|
|
113
|
+
[kStringLiteral]: true,
|
|
114
|
+
values: part,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Creates a schema for a single phrase literal
|
|
119
|
+
*
|
|
120
|
+
* This schema is a branded literal schema to differentiate regular strings from
|
|
121
|
+
* phrases.
|
|
122
|
+
*
|
|
123
|
+
* @function
|
|
124
|
+
* @param part Phrase literal (string)
|
|
125
|
+
* @returns Schema
|
|
126
|
+
*/
|
|
127
|
+
const createPhraseLiteralSchema = (
|
|
128
|
+
part: PhraseLiteral,
|
|
129
|
+
): z.core.$ZodBranded<z.ZodLiteral<string>, 'string-literal'> =>
|
|
130
|
+
z
|
|
131
|
+
.literal(part)
|
|
132
|
+
.brand('string-literal')
|
|
133
|
+
.register(BupkisRegistry, {
|
|
134
|
+
[kStringLiteral]: true,
|
|
135
|
+
value: part,
|
|
136
|
+
});
|
package/src/bootstrap.ts
CHANGED