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
package/src/guards.ts
CHANGED
|
@@ -16,18 +16,24 @@
|
|
|
16
16
|
* @packageDocumentation
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
-
import { type
|
|
20
|
-
import { z } from 'zod/v4';
|
|
19
|
+
import { type z } from 'zod/v4';
|
|
21
20
|
|
|
22
21
|
import type {
|
|
23
|
-
AssertionFailure,
|
|
24
22
|
AssertionPart,
|
|
25
23
|
PhraseLiteralChoice,
|
|
26
24
|
} from './assertion/assertion-types.js';
|
|
27
|
-
import type {
|
|
25
|
+
import type {
|
|
26
|
+
AssertionParts,
|
|
27
|
+
Constructor,
|
|
28
|
+
ExpectItExecutor,
|
|
29
|
+
PhraseLiteral,
|
|
30
|
+
ZodTypeMap,
|
|
31
|
+
} from './types.js';
|
|
28
32
|
|
|
29
33
|
import { kExpectIt } from './constant.js';
|
|
30
34
|
|
|
35
|
+
const { isArray } = Array;
|
|
36
|
+
|
|
31
37
|
/**
|
|
32
38
|
* Returns `true` if the given value looks like a Zod v4 schema, determined by
|
|
33
39
|
* the presence of an internal {@link z.core.$ZodTypeDef} field.
|
|
@@ -43,6 +49,7 @@ export function isZodType<T extends keyof ZodTypeMap>(
|
|
|
43
49
|
value: unknown,
|
|
44
50
|
type: T,
|
|
45
51
|
): value is ZodTypeMap[T];
|
|
52
|
+
|
|
46
53
|
/**
|
|
47
54
|
* Returns `true` if the given value looks like a Zod v4 schema, determined by
|
|
48
55
|
* the presence of an internal {@link z.core.$ZodTypeDef} field.
|
|
@@ -65,8 +72,12 @@ export function isZodType<T extends keyof ZodTypeMap>(
|
|
|
65
72
|
typeof value.def === 'object' &&
|
|
66
73
|
'type' in value.def;
|
|
67
74
|
|
|
68
|
-
if (!isValid)
|
|
69
|
-
|
|
75
|
+
if (!isValid) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
if (type === undefined) {
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
70
81
|
|
|
71
82
|
return (value as z.ZodType).def.type === type;
|
|
72
83
|
}
|
|
@@ -74,16 +85,18 @@ export function isZodType<T extends keyof ZodTypeMap>(
|
|
|
74
85
|
/**
|
|
75
86
|
* Type guard for a plain object.
|
|
76
87
|
*
|
|
88
|
+
* @function
|
|
77
89
|
* @param value Value to test
|
|
78
90
|
* @returns `true` if the value is a plain object, `false` otherwise
|
|
79
91
|
*/
|
|
80
92
|
export const isObject = (value: unknown): value is NonNullable<object> => {
|
|
81
|
-
return typeof value === 'object' && value !== null && !
|
|
93
|
+
return typeof value === 'object' && value !== null && !isArray(value);
|
|
82
94
|
};
|
|
83
95
|
|
|
84
96
|
/**
|
|
85
97
|
* Returns `true` if the given value is a {@link z.ZodPromise} schema.
|
|
86
98
|
*
|
|
99
|
+
* @function
|
|
87
100
|
* @param value - Value to test
|
|
88
101
|
* @returns `true` if the value is a `ZodPromise` schema; `false` otherwise
|
|
89
102
|
*/
|
|
@@ -93,6 +106,7 @@ export const isZodPromise = (value: unknown): value is z.ZodPromise =>
|
|
|
93
106
|
/**
|
|
94
107
|
* Checks if a value is "promise-like", meaning it is a "thenable" object.
|
|
95
108
|
*
|
|
109
|
+
* @function
|
|
96
110
|
* @param value - Value to test
|
|
97
111
|
* @returns `true` if the value is promise-like, `false` otherwise
|
|
98
112
|
*/
|
|
@@ -114,6 +128,7 @@ export const isPromiseLike = (value: unknown): value is PromiseLike<unknown> =>
|
|
|
114
128
|
* This may be the only way we can determine, at runtime, if a function is a
|
|
115
129
|
* constructor without actually calling it. I am unsure if this only works for
|
|
116
130
|
* classes.
|
|
131
|
+
* @function
|
|
117
132
|
* @param fn - Function to test
|
|
118
133
|
* @returns Whether the function is constructable
|
|
119
134
|
*/
|
|
@@ -123,7 +138,7 @@ export const isConstructible = (fn: unknown): fn is Constructor => {
|
|
|
123
138
|
}
|
|
124
139
|
try {
|
|
125
140
|
// this will throw if there is no `[[construct]]` slot.. or so I've heard.
|
|
126
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
141
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, custom/require-function-tag-in-arrow-functions
|
|
127
142
|
new new Proxy(fn as any, { construct: () => ({}) })();
|
|
128
143
|
return true;
|
|
129
144
|
} catch {
|
|
@@ -134,6 +149,7 @@ export const isConstructible = (fn: unknown): fn is Constructor => {
|
|
|
134
149
|
/**
|
|
135
150
|
* Type guard for a boolean value
|
|
136
151
|
*
|
|
152
|
+
* @function
|
|
137
153
|
* @param value Value to check
|
|
138
154
|
* @returns `true` if the value is a boolean, `false` otherwise
|
|
139
155
|
*/
|
|
@@ -143,42 +159,17 @@ export const isBoolean = (value: unknown): value is boolean =>
|
|
|
143
159
|
/**
|
|
144
160
|
* Type guard for a function value
|
|
145
161
|
*
|
|
162
|
+
* @function
|
|
146
163
|
* @param value Value to check
|
|
147
164
|
* @returns `true` if the value is a function, `false` otherwise
|
|
148
165
|
*/
|
|
149
166
|
export const isFunction = (value: unknown): value is (...args: any[]) => any =>
|
|
150
167
|
typeof value === 'function';
|
|
151
168
|
|
|
152
|
-
const AssertionFailureSchema: z.ZodType<AssertionFailure> = z.object({
|
|
153
|
-
actual: z
|
|
154
|
-
.unknown()
|
|
155
|
-
.optional()
|
|
156
|
-
.describe('The actual value or description of what actually occurred'),
|
|
157
|
-
expected: z
|
|
158
|
-
.unknown()
|
|
159
|
-
.optional()
|
|
160
|
-
.describe(
|
|
161
|
-
'The expected value or description of what was expected to occur',
|
|
162
|
-
),
|
|
163
|
-
message: z
|
|
164
|
-
.string()
|
|
165
|
-
.optional()
|
|
166
|
-
.describe('A human-readable message describing the failure'),
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
/**
|
|
170
|
-
* Type guard for a {@link AssertionFailure} object
|
|
171
|
-
*
|
|
172
|
-
* @param value Value to check
|
|
173
|
-
* @returns `true` if the value is an `AssertionFailure`, `false` otherwise
|
|
174
|
-
* @internal
|
|
175
|
-
*/
|
|
176
|
-
export const isAssertionFailure = (value: unknown): value is AssertionFailure =>
|
|
177
|
-
AssertionFailureSchema.safeParse(value).success;
|
|
178
|
-
|
|
179
169
|
/**
|
|
180
170
|
* Type guard for a string value
|
|
181
171
|
*
|
|
172
|
+
* @function
|
|
182
173
|
* @param value Value to check
|
|
183
174
|
* @returns `true` if the value is a string, `false` otherwise
|
|
184
175
|
*/
|
|
@@ -188,27 +179,20 @@ export const isString = (value: unknown): value is string =>
|
|
|
188
179
|
/**
|
|
189
180
|
* Type guard for a non-null object value
|
|
190
181
|
*
|
|
182
|
+
* @function
|
|
191
183
|
* @param value Value to check
|
|
192
184
|
* @returns `true` if the value is an object and not null, `false` otherwise
|
|
193
185
|
*/
|
|
194
186
|
export const isNonNullObject = (value: unknown): value is object =>
|
|
195
187
|
typeof value === 'object' && value !== null;
|
|
196
188
|
|
|
197
|
-
/**
|
|
198
|
-
* Type guard for a null or non-object value
|
|
199
|
-
*
|
|
200
|
-
* @param value Value to check
|
|
201
|
-
* @returns `true` if the value is null or not an object, `false` otherwise
|
|
202
|
-
*/
|
|
203
|
-
export const isNullOrNonObject = (value: unknown): value is null | Primitive =>
|
|
204
|
-
typeof value !== 'object' || value === null;
|
|
205
|
-
|
|
206
189
|
/**
|
|
207
190
|
* Type guard for a valid WeakKey (object, function, or symbol).
|
|
208
191
|
*
|
|
209
192
|
* WeakMaps and WeakSets can only use objects (including functions) or symbols
|
|
210
193
|
* as keys, not primitives like strings, numbers, booleans, null, or undefined.
|
|
211
194
|
*
|
|
195
|
+
* @function
|
|
212
196
|
* @param value Value to check
|
|
213
197
|
* @returns `true` if the value is a valid WeakKey (object, function, or
|
|
214
198
|
* symbol), `false` otherwise
|
|
@@ -221,25 +205,40 @@ export const isWeakKey = (value: unknown): value is WeakKey =>
|
|
|
221
205
|
/**
|
|
222
206
|
* Type guard for a {@link PhraseLiteralChoice}, which is a tuple of strings.
|
|
223
207
|
*
|
|
208
|
+
* @function
|
|
224
209
|
* @param value Assertion part to check
|
|
225
210
|
* @returns `true` if the part is a `PhraseLiteralChoice`, `false` otherwise
|
|
226
211
|
* @internal
|
|
227
212
|
*/
|
|
228
213
|
export const isPhraseLiteralChoice = (
|
|
229
|
-
value:
|
|
214
|
+
value: unknown,
|
|
230
215
|
): value is PhraseLiteralChoice =>
|
|
231
|
-
|
|
216
|
+
isArray(value) && value.every(isPhraseLiteral);
|
|
232
217
|
|
|
233
218
|
/**
|
|
234
219
|
* Type guard for a {@link PhraseLiteral}, which is just a string that does not
|
|
235
220
|
* begin with `not `.
|
|
236
221
|
*
|
|
222
|
+
* @function
|
|
237
223
|
* @param value Assertion part to check
|
|
238
224
|
* @returns `true` if the part is a `PhraseLiteral`, `false` otherwise
|
|
239
225
|
* @internal
|
|
240
226
|
*/
|
|
241
|
-
export const isPhraseLiteral = (value:
|
|
242
|
-
isString(value) && !value.startsWith('not ');
|
|
227
|
+
export const isPhraseLiteral = (value: unknown): value is PhraseLiteral =>
|
|
228
|
+
isString(value) && !value.startsWith('not ') && value !== 'and';
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Type guard for a {@link PhraseLiteral} or {@link PhraseLiteralChoice}.
|
|
232
|
+
*
|
|
233
|
+
* @function
|
|
234
|
+
* @param value Value to check
|
|
235
|
+
* @returns `true` if the value is a `PhraseLiteral` or `PhraseLiteralChoice`,
|
|
236
|
+
* `false` otherwise
|
|
237
|
+
*/
|
|
238
|
+
export const isPhrase = (
|
|
239
|
+
value: unknown,
|
|
240
|
+
): value is PhraseLiteral | PhraseLiteralChoice =>
|
|
241
|
+
isPhraseLiteral(value) || isPhraseLiteralChoice(value);
|
|
243
242
|
|
|
244
243
|
/**
|
|
245
244
|
* Generic type guard for instanceof checks.
|
|
@@ -260,6 +259,7 @@ export const isPhraseLiteral = (value: AssertionPart): value is string =>
|
|
|
260
259
|
* ```
|
|
261
260
|
*
|
|
262
261
|
* @template T - The constructor type to check against
|
|
262
|
+
* @function
|
|
263
263
|
* @param value - Value to test
|
|
264
264
|
* @param ctor - Constructor function to check instanceof
|
|
265
265
|
* @returns `true` if the value is an instance of the constructor, `false`
|
|
@@ -292,6 +292,7 @@ export const isA = <T extends Constructor>(
|
|
|
292
292
|
* }
|
|
293
293
|
* ```
|
|
294
294
|
*
|
|
295
|
+
* @function
|
|
295
296
|
* @param value - Value to test
|
|
296
297
|
* @returns `true` if the value is an Error instance, `false` otherwise
|
|
297
298
|
*/
|
|
@@ -318,6 +319,7 @@ export const isError = (value: unknown): value is Error => isA(value, Error);
|
|
|
318
319
|
* ```
|
|
319
320
|
*
|
|
320
321
|
* @template Subject - The subject type that the executor function operates on
|
|
322
|
+
* @function
|
|
321
323
|
* @param value - Value to test
|
|
322
324
|
* @returns `true` if the value is an ExpectItExecutor function, `false`
|
|
323
325
|
* otherwise
|
|
@@ -327,3 +329,27 @@ export const isExpectItExecutor = <Subject extends z.ZodType = z.ZodUnknown>(
|
|
|
327
329
|
): value is ExpectItExecutor<Subject> => {
|
|
328
330
|
return isFunction(value) && kExpectIt in value && value[kExpectIt] === true;
|
|
329
331
|
};
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Type guard for an {@link AssertionPart}, which can be a {@link PhraseLiteral},
|
|
335
|
+
* {@link PhraseLiteralChoice}, or a Zod schema.
|
|
336
|
+
*
|
|
337
|
+
* @function
|
|
338
|
+
* @param value Value to check
|
|
339
|
+
* @returns `true` if the value is an `AssertionPart`, `false` otherwise
|
|
340
|
+
* @internal
|
|
341
|
+
*/
|
|
342
|
+
export const isAssertionPart = (value: unknown): value is AssertionPart =>
|
|
343
|
+
isPhraseLiteral(value) || isPhraseLiteralChoice(value) || isZodType(value);
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Type guard for {@link AssertionParts}, which is an array of
|
|
347
|
+
* {@link AssertionPart}.
|
|
348
|
+
*
|
|
349
|
+
* @function
|
|
350
|
+
* @param value Value to check
|
|
351
|
+
* @returns `true` if the value is an `AssertionParts`, `false` otherwise
|
|
352
|
+
* @internal
|
|
353
|
+
*/
|
|
354
|
+
export const isAssertionParts = (value: unknown): value is AssertionParts =>
|
|
355
|
+
isArray(value) && !!value.length && value.every(isAssertionPart);
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal schemas
|
|
3
|
+
*
|
|
4
|
+
* @internal
|
|
5
|
+
* @packageDocumentation
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from 'zod/v4';
|
|
9
|
+
|
|
10
|
+
import type {
|
|
11
|
+
AssertionFailure,
|
|
12
|
+
AssertionMetadata,
|
|
13
|
+
AssertionParseRequest,
|
|
14
|
+
} from './types.js';
|
|
15
|
+
|
|
16
|
+
import { isZodType } from './guards.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Schema for internal assertion metadata.
|
|
20
|
+
*
|
|
21
|
+
* Used by documentation tooling.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
export const AssertionMetadataSchema: z.ZodType<AssertionMetadata> = z
|
|
25
|
+
.looseObject({
|
|
26
|
+
anchor: z.string().describe('Anchor ID for linking to this assertion.'),
|
|
27
|
+
category: z
|
|
28
|
+
.enum([
|
|
29
|
+
'collections',
|
|
30
|
+
'date',
|
|
31
|
+
'equality',
|
|
32
|
+
'error',
|
|
33
|
+
'function',
|
|
34
|
+
'numeric',
|
|
35
|
+
'object',
|
|
36
|
+
'other',
|
|
37
|
+
'primitives',
|
|
38
|
+
'promise',
|
|
39
|
+
'strings',
|
|
40
|
+
])
|
|
41
|
+
.describe('Category to map to page of logically grouped assertions'),
|
|
42
|
+
redirect: z
|
|
43
|
+
.string()
|
|
44
|
+
.optional()
|
|
45
|
+
.describe(
|
|
46
|
+
'Redirect for assertion to its documentation page, including anchor',
|
|
47
|
+
),
|
|
48
|
+
})
|
|
49
|
+
.describe(
|
|
50
|
+
'Metadata associated with an assertion, for internal use by documentation tooling.',
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Schema for {@link AssertionFailure}.
|
|
55
|
+
*
|
|
56
|
+
* @internal
|
|
57
|
+
*/
|
|
58
|
+
|
|
59
|
+
const AssertionFailureSchema: z.ZodType<AssertionFailure> = z
|
|
60
|
+
.object({
|
|
61
|
+
actual: z
|
|
62
|
+
.unknown()
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('The actual value or description of what actually occurred'),
|
|
65
|
+
expected: z
|
|
66
|
+
.unknown()
|
|
67
|
+
.optional()
|
|
68
|
+
.describe(
|
|
69
|
+
'The expected value or description of what was expected to occur',
|
|
70
|
+
),
|
|
71
|
+
message: z
|
|
72
|
+
.string()
|
|
73
|
+
.optional()
|
|
74
|
+
.describe('A human-readable message describing the failure'),
|
|
75
|
+
})
|
|
76
|
+
.describe('Potential return type of an assertion implementation function');
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* @internal
|
|
80
|
+
*/
|
|
81
|
+
const ZodTypeSchema = z
|
|
82
|
+
.custom<z.ZodType>(isZodType, {
|
|
83
|
+
error: 'Must be a Zod schema',
|
|
84
|
+
})
|
|
85
|
+
.describe('A Zod schema within AssertionParts');
|
|
86
|
+
|
|
87
|
+
/** @internal */
|
|
88
|
+
const BaseAssertionParseRequestSchema = z.object({
|
|
89
|
+
subject: z.unknown().describe('The subject value to be validated'),
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* @internal
|
|
94
|
+
*/
|
|
95
|
+
const AssertionParseRequestSchema: z.ZodType<AssertionParseRequest> = z.union([
|
|
96
|
+
z.object({
|
|
97
|
+
...BaseAssertionParseRequestSchema.shape,
|
|
98
|
+
schema: ZodTypeSchema.describe('The sync Zod schema to validate against'),
|
|
99
|
+
}),
|
|
100
|
+
z.object({
|
|
101
|
+
...BaseAssertionParseRequestSchema.shape,
|
|
102
|
+
asyncSchema: ZodTypeSchema.describe(
|
|
103
|
+
'The async Zod schema to validate against',
|
|
104
|
+
),
|
|
105
|
+
}),
|
|
106
|
+
]);
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* @internal
|
|
110
|
+
*/
|
|
111
|
+
const PhraseLiteralSchema = z
|
|
112
|
+
.stringFormat('PhraseLiteral', (value) => !value.startsWith('not '), {
|
|
113
|
+
error: 'Phrase literals may not begin with "not "',
|
|
114
|
+
})
|
|
115
|
+
.min(1, { error: 'Phrase literals must be at least 1 character long' })
|
|
116
|
+
.describe('A phrase literal within AssertionParts');
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* @internal
|
|
120
|
+
*/
|
|
121
|
+
const PhraseLiteralChoiceSchema = z
|
|
122
|
+
.array(PhraseLiteralSchema)
|
|
123
|
+
.min(1, { error: 'Phrase literal choices must have at least one option' })
|
|
124
|
+
.describe(
|
|
125
|
+
'A choice of phrase literals, represented as an array of strings, within AssertionParts',
|
|
126
|
+
);
|
|
127
|
+
/**
|
|
128
|
+
* @internal
|
|
129
|
+
*/
|
|
130
|
+
const AssertionImplSchemaSync = z
|
|
131
|
+
.union([
|
|
132
|
+
ZodTypeSchema,
|
|
133
|
+
z.function({
|
|
134
|
+
input: z.tuple([z.unknown()], z.unknown()),
|
|
135
|
+
output: z.union([
|
|
136
|
+
z.void(),
|
|
137
|
+
z.boolean(),
|
|
138
|
+
ZodTypeSchema,
|
|
139
|
+
AssertionFailureSchema,
|
|
140
|
+
AssertionParseRequestSchema,
|
|
141
|
+
]),
|
|
142
|
+
}),
|
|
143
|
+
])
|
|
144
|
+
.describe('A synchronous assertion implementation function');
|
|
145
|
+
|
|
146
|
+
const AssertionImplSchemaAsync = z
|
|
147
|
+
.union([
|
|
148
|
+
ZodTypeSchema,
|
|
149
|
+
z.function({
|
|
150
|
+
input: z.tuple([z.unknown()], z.unknown()),
|
|
151
|
+
output: z.union([
|
|
152
|
+
z.void(),
|
|
153
|
+
z.boolean(),
|
|
154
|
+
ZodTypeSchema,
|
|
155
|
+
AssertionFailureSchema,
|
|
156
|
+
AssertionParseRequestSchema,
|
|
157
|
+
z.promise(z.void()),
|
|
158
|
+
z.promise(z.boolean()),
|
|
159
|
+
z.promise(ZodTypeSchema),
|
|
160
|
+
z.promise(AssertionFailureSchema),
|
|
161
|
+
z.promise(AssertionParseRequestSchema),
|
|
162
|
+
]),
|
|
163
|
+
}),
|
|
164
|
+
])
|
|
165
|
+
.describe('An async assertion implementation function');
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @internal
|
|
169
|
+
*/
|
|
170
|
+
const AssertionPartsSchema = z
|
|
171
|
+
.array(
|
|
172
|
+
z.union([PhraseLiteralSchema, PhraseLiteralChoiceSchema, ZodTypeSchema]),
|
|
173
|
+
)
|
|
174
|
+
.min(1, { error: 'At least one part is required for an assertion' })
|
|
175
|
+
.refine(
|
|
176
|
+
(parts) => {
|
|
177
|
+
// Special validation for 'and': it can only appear if followed by a ZodType
|
|
178
|
+
for (let i = 0; i < parts.length; i++) {
|
|
179
|
+
if (parts[i] === 'and') {
|
|
180
|
+
// 'and' must be followed by another part, and that part must be a ZodType
|
|
181
|
+
if (i === parts.length - 1 || !isZodType(parts[i + 1])) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return true;
|
|
187
|
+
},
|
|
188
|
+
{ error: '"and" can only appear when followed by a Zod schema' },
|
|
189
|
+
)
|
|
190
|
+
.describe('Assertion "parts" which define the input of an assertion');
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Type guard for a {@link AssertionFailure}.
|
|
194
|
+
*
|
|
195
|
+
* This cannot live in `guards.ts` because it would create a cycle.
|
|
196
|
+
*
|
|
197
|
+
* @function
|
|
198
|
+
* @param value Value to check
|
|
199
|
+
* @returns `true` if value is an AssertionFailure
|
|
200
|
+
* @internal
|
|
201
|
+
*/
|
|
202
|
+
export const isAssertionFailure = (
|
|
203
|
+
value: unknown,
|
|
204
|
+
): value is AssertionFailure => {
|
|
205
|
+
return AssertionFailureSchema.safeParse(value).success;
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @function
|
|
210
|
+
*/
|
|
211
|
+
export const isAssertionParseRequest = (
|
|
212
|
+
value: unknown,
|
|
213
|
+
): value is AssertionParseRequest => {
|
|
214
|
+
return AssertionParseRequestSchema.safeParse(value).success;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @internal
|
|
219
|
+
*/
|
|
220
|
+
export const CreateAssertionInputSchema = z
|
|
221
|
+
.tuple([
|
|
222
|
+
AssertionPartsSchema,
|
|
223
|
+
AssertionImplSchemaSync,
|
|
224
|
+
z.optional(AssertionMetadataSchema),
|
|
225
|
+
])
|
|
226
|
+
.describe('Parameters for createAssertion()');
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @internal
|
|
230
|
+
*/
|
|
231
|
+
export const CreateAssertionInputSchemaAsync = z
|
|
232
|
+
.tuple([
|
|
233
|
+
AssertionPartsSchema,
|
|
234
|
+
AssertionImplSchemaAsync,
|
|
235
|
+
z.optional(AssertionMetadataSchema),
|
|
236
|
+
])
|
|
237
|
+
.describe('Parameters for createAsyncAssertion()');
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* @function
|
|
241
|
+
* @param value
|
|
242
|
+
* @returns
|
|
243
|
+
* @knipignore
|
|
244
|
+
*/
|
|
245
|
+
export const isMetadata = (value: unknown): value is AssertionMetadata =>
|
|
246
|
+
AssertionMetadataSchema.safeParse(value).success;
|
package/src/schema.ts
CHANGED
|
@@ -50,6 +50,8 @@ import {
|
|
|
50
50
|
type MutableOrReadonly,
|
|
51
51
|
} from './types.js';
|
|
52
52
|
|
|
53
|
+
const { getPrototypeOf, prototype: objectPrototype } = Object;
|
|
54
|
+
|
|
53
55
|
/**
|
|
54
56
|
* A Zod schema that validates JavaScript constructible functions.
|
|
55
57
|
*
|
|
@@ -386,7 +388,7 @@ export const WrappedPromiseLikeSchema = z
|
|
|
386
388
|
*/
|
|
387
389
|
export const DictionarySchema = z
|
|
388
390
|
.custom<Record<PropertyKey, unknown>>(
|
|
389
|
-
(value) => isNonNullObject(value) &&
|
|
391
|
+
(value) => isNonNullObject(value) && getPrototypeOf(value) === null,
|
|
390
392
|
)
|
|
391
393
|
.describe('Object with null prototype')
|
|
392
394
|
.register(BupkisRegistry, { name: 'dictionary' });
|
|
@@ -450,7 +452,7 @@ export const NullProtoObjectSchema = DictionarySchema;
|
|
|
450
452
|
* @group Schema
|
|
451
453
|
*/
|
|
452
454
|
export const AsyncFunctionSchema = FunctionSchema.refine(
|
|
453
|
-
(value) =>
|
|
455
|
+
(value) => objectPrototype.toString.call(value) === '[object AsyncFunction]',
|
|
454
456
|
)
|
|
455
457
|
.describe('Function declared with the `async` keyword')
|
|
456
458
|
.register(BupkisRegistry, { name: 'async-function' });
|
package/src/use.ts
CHANGED
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
type UseFn,
|
|
28
28
|
} from './types.js';
|
|
29
29
|
|
|
30
|
+
const { assign } = Object;
|
|
31
|
+
|
|
30
32
|
/**
|
|
31
33
|
* Creates an `expect.it()` factory function for generating embeddable assertion
|
|
32
34
|
* executors.
|
|
@@ -60,6 +62,7 @@ import {
|
|
|
60
62
|
*
|
|
61
63
|
* @template SyncAssertions - Array of synchronous assertion objects that define
|
|
62
64
|
* the available assertion logic for the embeddable functions
|
|
65
|
+
* @function
|
|
63
66
|
* @param expect - The underlying expect function that will execute the
|
|
64
67
|
* assertions when the returned executors are called
|
|
65
68
|
* @returns A factory function that creates {@link ExpectItExecutor} instances
|
|
@@ -72,8 +75,11 @@ import {
|
|
|
72
75
|
const createExpectIt = <SyncAssertions extends AnySyncAssertions>(
|
|
73
76
|
expect: any,
|
|
74
77
|
): ExpectIt<SyncAssertions> => {
|
|
78
|
+
/**
|
|
79
|
+
* @function
|
|
80
|
+
*/
|
|
75
81
|
const expectIt = (...args: readonly unknown[]) => {
|
|
76
|
-
const func =
|
|
82
|
+
const func = assign(
|
|
77
83
|
(subject: unknown) => {
|
|
78
84
|
const allArgs = [subject, ...args];
|
|
79
85
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
@@ -121,6 +127,7 @@ const createExpectIt = <SyncAssertions extends AnySyncAssertions>(
|
|
|
121
127
|
*
|
|
122
128
|
* @template AsyncAssertions - Array of asynchronous assertion objects that
|
|
123
129
|
* define the available assertion logic for the embeddable async functions
|
|
130
|
+
* @function
|
|
124
131
|
* @param expectAsync - The underlying expectAsync function that will execute
|
|
125
132
|
* the assertions when the returned executors are called
|
|
126
133
|
* @returns A factory function that creates {@link ExpectItExecutorAsync}
|
|
@@ -134,8 +141,11 @@ const createExpectIt = <SyncAssertions extends AnySyncAssertions>(
|
|
|
134
141
|
const createExpectItAsync = <AsyncAssertions extends AnyAsyncAssertions>(
|
|
135
142
|
expectAsync: any,
|
|
136
143
|
): ExpectItAsync<AsyncAssertions> => {
|
|
144
|
+
/**
|
|
145
|
+
* @function
|
|
146
|
+
*/
|
|
137
147
|
const expectItAsync = (...args: readonly unknown[]) => {
|
|
138
|
-
const func =
|
|
148
|
+
const func = assign(
|
|
139
149
|
async (subject: unknown) => {
|
|
140
150
|
const allArgs = [subject, ...args];
|
|
141
151
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
|
@@ -210,6 +220,7 @@ const createExpectItAsync = <AsyncAssertions extends AnyAsyncAssertions>(
|
|
|
210
220
|
* available in the composed functions
|
|
211
221
|
* @template AsyncAssertions - Array of base asynchronous assertions that will
|
|
212
222
|
* be available in the composed functions
|
|
223
|
+
* @function
|
|
213
224
|
* @param syncAssertions - Base synchronous assertions to include in all
|
|
214
225
|
* composed expect functions
|
|
215
226
|
* @param asyncAssertions - Base asynchronous assertions to include in all
|
|
@@ -223,15 +234,18 @@ const createExpectItAsync = <AsyncAssertions extends AnyAsyncAssertions>(
|
|
|
223
234
|
* @see {@link FilterAsyncAssertions} for how async assertions are extracted
|
|
224
235
|
* @see {@link Concat} for how assertion arrays are combined
|
|
225
236
|
*/
|
|
226
|
-
export
|
|
237
|
+
export const createUse = <
|
|
227
238
|
const SyncAssertions extends AnySyncAssertions,
|
|
228
239
|
const AsyncAssertions extends AnyAsyncAssertions,
|
|
229
240
|
>(
|
|
230
241
|
syncAssertions: SyncAssertions,
|
|
231
242
|
asyncAssertions: AsyncAssertions,
|
|
232
|
-
): UseFn<SyncAssertions, AsyncAssertions> {
|
|
243
|
+
): UseFn<SyncAssertions, AsyncAssertions> => {
|
|
233
244
|
const syncAssertionsIn = syncAssertions ?? [];
|
|
234
245
|
const asyncAssertionsIn = asyncAssertions ?? [];
|
|
246
|
+
/**
|
|
247
|
+
* @function
|
|
248
|
+
*/
|
|
235
249
|
const use: UseFn<SyncAssertions, AsyncAssertions> = <
|
|
236
250
|
AllAssertions extends readonly AnyAssertion[],
|
|
237
251
|
FilteredSyncAssertions extends FilterSyncAssertions<AllAssertions>,
|
|
@@ -256,12 +270,12 @@ export function createUse<
|
|
|
256
270
|
const expectFunction = createExpectSyncFunction(allSyncAssertions);
|
|
257
271
|
const expectAsyncFunction = createExpectAsyncFunction(allAsyncAssertions);
|
|
258
272
|
|
|
259
|
-
const expect =
|
|
273
|
+
const expect = assign(
|
|
260
274
|
expectFunction,
|
|
261
275
|
createBaseExpect(allSyncAssertions, allAsyncAssertions, 'sync'),
|
|
262
276
|
{ it: createExpectIt(expectFunction) },
|
|
263
277
|
);
|
|
264
|
-
const expectAsync =
|
|
278
|
+
const expectAsync = assign(
|
|
265
279
|
expectAsyncFunction,
|
|
266
280
|
createBaseExpect(allSyncAssertions, allAsyncAssertions, 'async'),
|
|
267
281
|
{ it: createExpectItAsync(expectAsyncFunction) },
|
|
@@ -276,4 +290,4 @@ export function createUse<
|
|
|
276
290
|
};
|
|
277
291
|
};
|
|
278
292
|
return use;
|
|
279
|
-
}
|
|
293
|
+
};
|