bupkis 0.6.0 → 0.7.2
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 +35 -0
- package/README.md +33 -30
- package/dist/commonjs/assertion/assertion-async.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion-async.js +4 -11
- 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 +3 -13
- package/dist/commonjs/assertion/assertion-sync.js.map +1 -1
- package/dist/commonjs/assertion/assertion.d.ts.map +1 -1
- package/dist/commonjs/assertion/assertion.js +3 -3
- package/dist/commonjs/assertion/assertion.js.map +1 -1
- package/dist/commonjs/assertion/create.d.ts.map +1 -1
- package/dist/commonjs/assertion/create.js +13 -12
- package/dist/commonjs/assertion/create.js.map +1 -1
- package/dist/commonjs/assertion/impl/async-parametric.d.ts +2 -2
- package/dist/commonjs/assertion/impl/async-parametric.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/async-parametric.js +5 -48
- package/dist/commonjs/assertion/impl/async-parametric.js.map +1 -1
- package/dist/commonjs/assertion/impl/async.d.ts +4 -4
- package/dist/commonjs/assertion/impl/sync-collection.js +1 -1
- package/dist/commonjs/assertion/impl/sync-collection.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync-parametric.d.ts +2 -2
- package/dist/commonjs/assertion/impl/sync-parametric.d.ts.map +1 -1
- package/dist/commonjs/assertion/impl/sync-parametric.js +14 -5
- package/dist/commonjs/assertion/impl/sync-parametric.js.map +1 -1
- package/dist/commonjs/assertion/impl/sync.d.ts +4 -4
- package/dist/commonjs/assertion/slotify.d.ts.map +1 -1
- package/dist/commonjs/assertion/slotify.js +4 -3
- package/dist/commonjs/assertion/slotify.js.map +1 -1
- package/dist/commonjs/bootstrap.d.ts +4 -4
- package/dist/commonjs/constant.js +7 -1
- package/dist/commonjs/constant.js.map +1 -1
- package/dist/commonjs/error.d.ts +134 -0
- package/dist/commonjs/error.d.ts.map +1 -1
- package/dist/commonjs/error.js +117 -1
- package/dist/commonjs/error.js.map +1 -1
- package/dist/commonjs/expect.d.ts +4 -2
- package/dist/commonjs/expect.d.ts.map +1 -1
- package/dist/commonjs/expect.js +19 -6
- package/dist/commonjs/expect.js.map +1 -1
- package/dist/commonjs/guards.d.ts.map +1 -1
- package/dist/commonjs/guards.js +4 -1
- package/dist/commonjs/guards.js.map +1 -1
- package/dist/commonjs/index.d.ts +6 -5
- package/dist/commonjs/index.d.ts.map +1 -1
- package/dist/commonjs/index.js +6 -3
- package/dist/commonjs/index.js.map +1 -1
- package/dist/commonjs/value-to-schema.d.ts.map +1 -1
- package/dist/commonjs/value-to-schema.js +3 -2
- 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 +5 -12
- 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 +7 -17
- package/dist/esm/assertion/assertion-sync.js.map +1 -1
- package/dist/esm/assertion/assertion.d.ts.map +1 -1
- package/dist/esm/assertion/assertion.js +6 -6
- package/dist/esm/assertion/assertion.js.map +1 -1
- package/dist/esm/assertion/create.d.ts.map +1 -1
- package/dist/esm/assertion/create.js +13 -12
- package/dist/esm/assertion/create.js.map +1 -1
- package/dist/esm/assertion/impl/async-parametric.d.ts +2 -2
- package/dist/esm/assertion/impl/async-parametric.d.ts.map +1 -1
- package/dist/esm/assertion/impl/async-parametric.js +5 -48
- package/dist/esm/assertion/impl/async-parametric.js.map +1 -1
- package/dist/esm/assertion/impl/async.d.ts +4 -4
- package/dist/esm/assertion/impl/sync-collection.js +1 -1
- package/dist/esm/assertion/impl/sync-collection.js.map +1 -1
- package/dist/esm/assertion/impl/sync-parametric.d.ts +2 -2
- package/dist/esm/assertion/impl/sync-parametric.d.ts.map +1 -1
- package/dist/esm/assertion/impl/sync-parametric.js +14 -5
- package/dist/esm/assertion/impl/sync-parametric.js.map +1 -1
- package/dist/esm/assertion/impl/sync.d.ts +4 -4
- package/dist/esm/assertion/slotify.d.ts.map +1 -1
- package/dist/esm/assertion/slotify.js +4 -3
- package/dist/esm/assertion/slotify.js.map +1 -1
- package/dist/esm/bootstrap.d.ts +4 -4
- package/dist/esm/constant.js +6 -0
- package/dist/esm/constant.js.map +1 -1
- package/dist/esm/error.d.ts +134 -0
- package/dist/esm/error.d.ts.map +1 -1
- package/dist/esm/error.js +110 -1
- package/dist/esm/error.js.map +1 -1
- package/dist/esm/expect.d.ts +4 -2
- package/dist/esm/expect.d.ts.map +1 -1
- package/dist/esm/expect.js +22 -9
- package/dist/esm/expect.js.map +1 -1
- package/dist/esm/guards.d.ts.map +1 -1
- package/dist/esm/guards.js +4 -1
- package/dist/esm/guards.js.map +1 -1
- package/dist/esm/index.d.ts +6 -5
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +2 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/value-to-schema.d.ts.map +1 -1
- package/dist/esm/value-to-schema.js +3 -2
- package/dist/esm/value-to-schema.js.map +1 -1
- package/package.json +17 -21
- package/src/assertion/assertion-async.ts +9 -18
- package/src/assertion/assertion-sync.ts +12 -24
- package/src/assertion/assertion.ts +7 -6
- package/src/assertion/create.ts +31 -12
- package/src/assertion/impl/async-parametric.ts +7 -49
- package/src/assertion/impl/sync-collection.ts +1 -1
- package/src/assertion/impl/sync-parametric.ts +19 -5
- package/src/assertion/slotify.ts +4 -3
- package/src/constant.ts +7 -0
- package/src/error.ts +188 -0
- package/src/expect.ts +31 -10
- package/src/guards.ts +4 -1
- package/src/index.ts +2 -1
- package/src/value-to-schema.ts +3 -2
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import Debug from 'debug';
|
|
2
1
|
import { inspect } from 'util';
|
|
3
2
|
import z from 'zod/v4';
|
|
4
3
|
|
|
5
4
|
import { kStringLiteral } from '../constant.js';
|
|
6
|
-
import { AssertionError } from '../error.js';
|
|
5
|
+
import { AssertionError, AssertionImplementationError } from '../error.js';
|
|
7
6
|
import {
|
|
8
7
|
isA,
|
|
9
8
|
isAssertionFailure,
|
|
@@ -26,7 +25,6 @@ import {
|
|
|
26
25
|
type ParsedValues,
|
|
27
26
|
} from './assertion-types.js';
|
|
28
27
|
import { BupkisAssertion } from './assertion.js';
|
|
29
|
-
const debug = Debug('bupkis:assertion:async');
|
|
30
28
|
|
|
31
29
|
export abstract class BupkisAssertionAsync<
|
|
32
30
|
Parts extends AssertionParts,
|
|
@@ -68,7 +66,6 @@ export abstract class BupkisAssertionAsync<
|
|
|
68
66
|
// unknown/any accept anything
|
|
69
67
|
// IMPORTANT: do not use a type guard here; it will break inference
|
|
70
68
|
if (slot.def.type === 'unknown' || slot.def.type === 'any') {
|
|
71
|
-
debug('Skipping unknown/any slot validation for arg', arg);
|
|
72
69
|
parsedValues.push(arg);
|
|
73
70
|
exactMatch = false;
|
|
74
71
|
continue;
|
|
@@ -143,8 +140,9 @@ export class BupkisAssertionFunctionAsync<
|
|
|
143
140
|
} else if (isError(result) && result instanceof z.ZodError) {
|
|
144
141
|
throw this.fromZodError(result, stackStartFn, parsedValues);
|
|
145
142
|
} else if (result as unknown) {
|
|
146
|
-
throw new
|
|
143
|
+
throw new AssertionImplementationError(
|
|
147
144
|
`Invalid return type from assertion ${this}; expected boolean, ZodType, or AssertionFailure`,
|
|
145
|
+
{ result },
|
|
148
146
|
);
|
|
149
147
|
}
|
|
150
148
|
}
|
|
@@ -182,19 +180,13 @@ export class BupkisAssertionSchemaAsync<
|
|
|
182
180
|
? parseResult.subjectValidationResult
|
|
183
181
|
: undefined;
|
|
184
182
|
|
|
185
|
-
if (cachedValidation) {
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
if (cachedValidation && !cachedValidation.success) {
|
|
184
|
+
// Subject validation failed during parseValuesAsync, throw the cached error
|
|
185
|
+
throw this.fromZodError(
|
|
186
|
+
cachedValidation.error,
|
|
187
|
+
stackStartFn,
|
|
188
|
+
parsedValues,
|
|
189
189
|
);
|
|
190
|
-
if (!cachedValidation.success) {
|
|
191
|
-
// Subject validation failed during parseValuesAsync, throw the cached error
|
|
192
|
-
throw this.fromZodError(
|
|
193
|
-
cachedValidation.error,
|
|
194
|
-
stackStartFn,
|
|
195
|
-
parsedValues,
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
190
|
}
|
|
199
191
|
|
|
200
192
|
// Fall back to standard validation if no cached result
|
|
@@ -258,7 +250,6 @@ export class BupkisAssertionSchemaAsync<
|
|
|
258
250
|
|
|
259
251
|
// Standard slot processing for non-optimized cases
|
|
260
252
|
if (slot.def.type === 'unknown' || slot.def.type === 'any') {
|
|
261
|
-
debug('Skipping unknown/any slot validation for arg', arg);
|
|
262
253
|
parsedValues.push(arg);
|
|
263
254
|
exactMatch = false;
|
|
264
255
|
continue;
|
|
@@ -6,18 +6,21 @@
|
|
|
6
6
|
* @see {@link AssertionSchemaSync} for schema-based assertions
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import createDebug from 'debug';
|
|
10
10
|
import { inspect } from 'util';
|
|
11
11
|
import { z } from 'zod/v4';
|
|
12
12
|
|
|
13
13
|
import { kStringLiteral } from '../constant.js';
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
AssertionError,
|
|
16
|
+
AssertionImplementationError,
|
|
17
|
+
UnexpectedAsyncError,
|
|
18
|
+
} from '../error.js';
|
|
15
19
|
import {
|
|
16
20
|
isAssertionFailure,
|
|
17
21
|
isBoolean,
|
|
18
22
|
isError,
|
|
19
23
|
isPromiseLike,
|
|
20
|
-
isZodPromise,
|
|
21
24
|
isZodType,
|
|
22
25
|
} from '../guards.js';
|
|
23
26
|
import { BupkisRegistry } from '../metadata.js';
|
|
@@ -36,7 +39,7 @@ import {
|
|
|
36
39
|
} from './assertion-types.js';
|
|
37
40
|
import { BupkisAssertion } from './assertion.js';
|
|
38
41
|
|
|
39
|
-
const debug =
|
|
42
|
+
const debug = createDebug('bupkis:assertion:sync');
|
|
40
43
|
|
|
41
44
|
/**
|
|
42
45
|
* Abstract class for synchronous assertions.
|
|
@@ -106,17 +109,11 @@ export abstract class BupkisAssertionSync<
|
|
|
106
109
|
// unknown/any accept anything
|
|
107
110
|
// IMPORTANT: do not use a type guard here
|
|
108
111
|
if (slot.def.type === 'unknown' || slot.def.type === 'any') {
|
|
109
|
-
// debug('Skipping unknown/any slot validation for arg', arg);
|
|
110
112
|
parsedValues.push(arg);
|
|
111
113
|
exactMatch = false;
|
|
112
114
|
continue;
|
|
113
115
|
}
|
|
114
|
-
|
|
115
|
-
if (isZodPromise(slot)) {
|
|
116
|
-
throw new TypeError(
|
|
117
|
-
`${this} expects a Promise for slot ${i}; use expectAsync() instead of expect()`,
|
|
118
|
-
);
|
|
119
|
-
}
|
|
116
|
+
|
|
120
117
|
const result = slot.safeParse(arg);
|
|
121
118
|
if (!result.success) {
|
|
122
119
|
return {
|
|
@@ -156,10 +153,10 @@ export class BupkisAssertionFunctionSync<
|
|
|
156
153
|
if (isPromiseLike(result)) {
|
|
157
154
|
// Avoid unhandled promise rejection
|
|
158
155
|
Promise.resolve(result).catch((err) => {
|
|
159
|
-
debug(
|
|
156
|
+
debug(`⚠️ Ate unhandled rejection from assertion %s: %O`, this, err);
|
|
160
157
|
});
|
|
161
158
|
|
|
162
|
-
throw new
|
|
159
|
+
throw new UnexpectedAsyncError(
|
|
163
160
|
`Assertion ${this} returned a Promise; use expectAsync() instead of expect()`,
|
|
164
161
|
);
|
|
165
162
|
}
|
|
@@ -183,8 +180,9 @@ export class BupkisAssertionFunctionSync<
|
|
|
183
180
|
} else if (isError(result) && result instanceof z.ZodError) {
|
|
184
181
|
throw this.fromZodError(result, stackStartFn, parsedValues);
|
|
185
182
|
} else if (result as unknown) {
|
|
186
|
-
throw new
|
|
183
|
+
throw new AssertionImplementationError(
|
|
187
184
|
`Invalid return type from assertion ${this}; expected boolean, ZodType, or AssertionFailure`,
|
|
185
|
+
{ result },
|
|
188
186
|
);
|
|
189
187
|
}
|
|
190
188
|
}
|
|
@@ -223,10 +221,6 @@ export class BupkisAssertionSchemaSync<
|
|
|
223
221
|
: undefined;
|
|
224
222
|
|
|
225
223
|
if (cachedValidation) {
|
|
226
|
-
debug(
|
|
227
|
-
'Using cached subject validation result from parseValues for %s',
|
|
228
|
-
this,
|
|
229
|
-
);
|
|
230
224
|
if (!cachedValidation.success) {
|
|
231
225
|
// Subject validation failed during parseValues, throw the cached error
|
|
232
226
|
throw this.fromZodError(
|
|
@@ -293,17 +287,11 @@ export class BupkisAssertionSchemaSync<
|
|
|
293
287
|
|
|
294
288
|
// Standard slot processing for non-optimized cases
|
|
295
289
|
if (slot.def.type === 'unknown' || slot.def.type === 'any') {
|
|
296
|
-
debug('Skipping unknown/any slot validation for arg', arg);
|
|
297
290
|
parsedValues.push(arg);
|
|
298
291
|
exactMatch = false;
|
|
299
292
|
continue;
|
|
300
293
|
}
|
|
301
294
|
|
|
302
|
-
if (isZodPromise(slot)) {
|
|
303
|
-
throw new TypeError(
|
|
304
|
-
`${this} expects a Promise for slot ${i}; use expectAsync() instead of expect()`,
|
|
305
|
-
);
|
|
306
|
-
}
|
|
307
295
|
const result = slot.safeParse(arg);
|
|
308
296
|
if (!result.success) {
|
|
309
297
|
return {
|
|
@@ -9,14 +9,14 @@
|
|
|
9
9
|
* @packageDocumentation
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import
|
|
12
|
+
import createDebug from 'debug';
|
|
13
13
|
import slug from 'slug';
|
|
14
14
|
import { type ArrayValues } from 'type-fest';
|
|
15
15
|
import { inspect } from 'util';
|
|
16
16
|
import { z } from 'zod/v4';
|
|
17
17
|
|
|
18
18
|
import { kStringLiteral } from '../constant.js';
|
|
19
|
-
import { AssertionError } from '../error.js';
|
|
19
|
+
import { AssertionError, InvalidMetadataError } from '../error.js';
|
|
20
20
|
import { BupkisRegistry } from '../metadata.js';
|
|
21
21
|
import {
|
|
22
22
|
type Assertion,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
type ParsedValues,
|
|
29
29
|
} from './assertion-types.js';
|
|
30
30
|
|
|
31
|
-
const debug =
|
|
31
|
+
const debug = createDebug('bupkis:assertion');
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* Modified charmap for {@link slug} to use underscores to replace hyphens (`-`;
|
|
@@ -64,7 +64,7 @@ export abstract class BupkisAssertion<
|
|
|
64
64
|
readonly impl: Impl,
|
|
65
65
|
) {
|
|
66
66
|
this.id = this.generateAssertionId();
|
|
67
|
-
debug('Created assertion %s', this);
|
|
67
|
+
debug('ℹ Created assertion %s', this);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
public metadata(): AssertionMetadata | undefined {
|
|
@@ -96,7 +96,7 @@ export abstract class BupkisAssertion<
|
|
|
96
96
|
: 'custom';
|
|
97
97
|
} catch (err) {
|
|
98
98
|
debug(
|
|
99
|
-
|
|
99
|
+
`⚠️ WARNING: Unable to extract custom class name from Zod type(did Zod's API change?): ${err}`,
|
|
100
100
|
);
|
|
101
101
|
repr = 'custom';
|
|
102
102
|
}
|
|
@@ -251,8 +251,9 @@ export abstract class BupkisAssertion<
|
|
|
251
251
|
}
|
|
252
252
|
} else {
|
|
253
253
|
/* c8 ignore next */
|
|
254
|
-
throw new
|
|
254
|
+
throw new InvalidMetadataError(
|
|
255
255
|
`Invalid metadata for slot ${slotIndex} with value ${inspect(rawArg)}`,
|
|
256
|
+
{ metadata: meta },
|
|
256
257
|
);
|
|
257
258
|
}
|
|
258
259
|
return true;
|
package/src/assertion/create.ts
CHANGED
|
@@ -75,6 +75,7 @@ import type {
|
|
|
75
75
|
AssertionParts,
|
|
76
76
|
} from './assertion-types.js';
|
|
77
77
|
|
|
78
|
+
import { AssertionImplementationError } from '../error.js';
|
|
78
79
|
import { isFunction, isString, isZodType } from '../guards.js';
|
|
79
80
|
import {
|
|
80
81
|
BupkisAssertionFunctionAsync,
|
|
@@ -107,20 +108,26 @@ export const createAssertion: CreateAssertionFn = <
|
|
|
107
108
|
metadata?: AssertionMetadata,
|
|
108
109
|
) => {
|
|
109
110
|
if (!Array.isArray(parts)) {
|
|
110
|
-
throw new
|
|
111
|
+
throw new AssertionImplementationError('First parameter must be an array');
|
|
111
112
|
}
|
|
112
113
|
if (parts.length === 0) {
|
|
113
|
-
throw new
|
|
114
|
+
throw new AssertionImplementationError(
|
|
115
|
+
'At least one value is required for an assertion',
|
|
116
|
+
);
|
|
114
117
|
}
|
|
115
118
|
if (
|
|
116
119
|
!parts.every(
|
|
117
120
|
(part) => isString(part) || Array.isArray(part) || isZodType(part),
|
|
118
121
|
)
|
|
119
122
|
) {
|
|
120
|
-
throw new
|
|
123
|
+
throw new AssertionImplementationError(
|
|
124
|
+
'All assertion parts must be strings or Zod schemas',
|
|
125
|
+
);
|
|
121
126
|
}
|
|
122
127
|
if (!impl) {
|
|
123
|
-
throw new
|
|
128
|
+
throw new AssertionImplementationError(
|
|
129
|
+
'An assertion implementation is required',
|
|
130
|
+
);
|
|
124
131
|
}
|
|
125
132
|
try {
|
|
126
133
|
const slots = slotify<Parts>(parts);
|
|
@@ -140,11 +147,17 @@ export const createAssertion: CreateAssertionFn = <
|
|
|
140
147
|
}
|
|
141
148
|
} catch (err) {
|
|
142
149
|
if (err instanceof z.ZodError) {
|
|
143
|
-
throw new
|
|
150
|
+
throw new AssertionImplementationError(
|
|
151
|
+
`Failed to slotify assertion parts: ${z.prettifyError(err)}`,
|
|
152
|
+
{ cause: err },
|
|
153
|
+
);
|
|
144
154
|
}
|
|
145
|
-
throw
|
|
155
|
+
throw new AssertionImplementationError(
|
|
156
|
+
`Failed to slotify assertion parts: ${err}`,
|
|
157
|
+
{ cause: err },
|
|
158
|
+
);
|
|
146
159
|
}
|
|
147
|
-
throw new
|
|
160
|
+
throw new AssertionImplementationError(
|
|
148
161
|
'Assertion implementation must be a function, Zod schema or Zod schema factory',
|
|
149
162
|
);
|
|
150
163
|
};
|
|
@@ -164,20 +177,26 @@ export const createAsyncAssertion: CreateAsyncAssertionFn = <
|
|
|
164
177
|
metadata?: AssertionMetadata,
|
|
165
178
|
) => {
|
|
166
179
|
if (!Array.isArray(parts)) {
|
|
167
|
-
throw new
|
|
180
|
+
throw new AssertionImplementationError('First parameter must be an array');
|
|
168
181
|
}
|
|
169
182
|
if (parts.length === 0) {
|
|
170
|
-
throw new
|
|
183
|
+
throw new AssertionImplementationError(
|
|
184
|
+
'At least one value is required for an assertion',
|
|
185
|
+
);
|
|
171
186
|
}
|
|
172
187
|
if (
|
|
173
188
|
!parts.every(
|
|
174
189
|
(part) => isString(part) || Array.isArray(part) || isZodType(part),
|
|
175
190
|
)
|
|
176
191
|
) {
|
|
177
|
-
throw new
|
|
192
|
+
throw new AssertionImplementationError(
|
|
193
|
+
'All assertion parts must be strings or Zod schemas',
|
|
194
|
+
);
|
|
178
195
|
}
|
|
179
196
|
if (!impl) {
|
|
180
|
-
throw new
|
|
197
|
+
throw new AssertionImplementationError(
|
|
198
|
+
'An assertion implementation is required',
|
|
199
|
+
);
|
|
181
200
|
}
|
|
182
201
|
const slots = slotify<Parts>(parts);
|
|
183
202
|
|
|
@@ -200,7 +219,7 @@ export const createAsyncAssertion: CreateAsyncAssertionFn = <
|
|
|
200
219
|
}
|
|
201
220
|
return assertion;
|
|
202
221
|
}
|
|
203
|
-
throw new
|
|
222
|
+
throw new AssertionImplementationError(
|
|
204
223
|
'Assertion implementation must be a function, Zod schema or Zod schema factory',
|
|
205
224
|
);
|
|
206
225
|
};
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { inspect } from 'node:util';
|
|
17
17
|
import { z } from 'zod/v4';
|
|
18
18
|
|
|
19
|
+
import { InvalidSchemaError } from '../../error.js';
|
|
19
20
|
import { isA, isNonNullObject, isString } from '../../guards.js';
|
|
20
21
|
import {
|
|
21
22
|
ConstructibleSchema,
|
|
@@ -266,8 +267,9 @@ export const functionRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
|
|
|
266
267
|
}
|
|
267
268
|
/* c8 ignore next 5 */
|
|
268
269
|
if (!schema) {
|
|
269
|
-
throw new
|
|
270
|
+
throw new InvalidSchemaError(
|
|
270
271
|
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
272
|
+
{ schema: param },
|
|
271
273
|
);
|
|
272
274
|
}
|
|
273
275
|
|
|
@@ -334,8 +336,9 @@ export const promiseRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
|
|
|
334
336
|
}
|
|
335
337
|
/* c8 ignore next 5 */
|
|
336
338
|
if (!schema) {
|
|
337
|
-
throw new
|
|
339
|
+
throw new InvalidSchemaError(
|
|
338
340
|
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
341
|
+
{ schema: param },
|
|
339
342
|
);
|
|
340
343
|
}
|
|
341
344
|
|
|
@@ -391,30 +394,8 @@ export const promiseFulfillWithValueSatisfyingAssertion = createAsyncAssertion(
|
|
|
391
394
|
)}`,
|
|
392
395
|
};
|
|
393
396
|
}
|
|
394
|
-
let schema: undefined | z.ZodType;
|
|
395
|
-
// TODO: can valueToSchema handle the first two conditional branches?
|
|
396
|
-
if (isString(param)) {
|
|
397
|
-
schema = z
|
|
398
|
-
.looseObject({
|
|
399
|
-
message: z.coerce.string().pipe(z.literal(param)),
|
|
400
|
-
})
|
|
401
|
-
.or(z.coerce.string().pipe(z.literal(param)));
|
|
402
|
-
} else if (isA(param, RegExp)) {
|
|
403
|
-
schema = z
|
|
404
|
-
.looseObject({
|
|
405
|
-
message: z.coerce.string().regex(param),
|
|
406
|
-
})
|
|
407
|
-
.or(z.coerce.string().regex(param));
|
|
408
|
-
} else if (isNonNullObject(param)) {
|
|
409
|
-
schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
410
|
-
}
|
|
411
|
-
/* c8 ignore next 5 */
|
|
412
|
-
if (!schema) {
|
|
413
|
-
throw new TypeError(
|
|
414
|
-
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
415
|
-
);
|
|
416
|
-
}
|
|
417
397
|
|
|
398
|
+
const schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
418
399
|
const result = schema.safeParse(value);
|
|
419
400
|
if (!result.success) {
|
|
420
401
|
return result.error;
|
|
@@ -468,30 +449,7 @@ export const functionFulfillWithValueSatisfyingAssertion = createAsyncAssertion(
|
|
|
468
449
|
};
|
|
469
450
|
}
|
|
470
451
|
|
|
471
|
-
|
|
472
|
-
// TODO: can valueToSchema handle the first two conditional branches?
|
|
473
|
-
if (isString(param)) {
|
|
474
|
-
schema = z
|
|
475
|
-
.looseObject({
|
|
476
|
-
message: z.coerce.string().pipe(z.literal(param)),
|
|
477
|
-
})
|
|
478
|
-
.or(z.coerce.string().pipe(z.literal(param)));
|
|
479
|
-
} else if (isA(param, RegExp)) {
|
|
480
|
-
schema = z
|
|
481
|
-
.looseObject({
|
|
482
|
-
message: z.coerce.string().regex(param),
|
|
483
|
-
})
|
|
484
|
-
.or(z.coerce.string().regex(param));
|
|
485
|
-
} else if (isNonNullObject(param)) {
|
|
486
|
-
schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
487
|
-
}
|
|
488
|
-
/* c8 ignore next 5 */
|
|
489
|
-
if (!schema) {
|
|
490
|
-
throw new TypeError(
|
|
491
|
-
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
492
|
-
);
|
|
493
|
-
}
|
|
494
|
-
|
|
452
|
+
const schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
495
453
|
const result = schema.safeParse(value);
|
|
496
454
|
if (!result.success) {
|
|
497
455
|
return result.error;
|
|
@@ -462,7 +462,7 @@ export const objectSizeAssertion = createAssertion(
|
|
|
462
462
|
const actual = Object.keys(subject).length;
|
|
463
463
|
if (actual !== expectedSize) {
|
|
464
464
|
return {
|
|
465
|
-
actual
|
|
465
|
+
actual,
|
|
466
466
|
expected: expectedSize,
|
|
467
467
|
message: `Expected object to have ${expectedSize} keys, but it has ${actual} keys`,
|
|
468
468
|
};
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { inspect } from 'node:util';
|
|
17
17
|
import { z } from 'zod/v4';
|
|
18
18
|
|
|
19
|
+
import { BupkisError, InvalidSchemaError } from '../../error.js';
|
|
19
20
|
import { isA, isError, isNonNullObject, isString } from '../../guards.js';
|
|
20
21
|
import {
|
|
21
22
|
ArrayLikeSchema,
|
|
@@ -146,7 +147,7 @@ export const typeOfAssertion = createAssertion(
|
|
|
146
147
|
return z.instanceof(WeakSet);
|
|
147
148
|
// c8 ignore next 2
|
|
148
149
|
default:
|
|
149
|
-
throw new
|
|
150
|
+
throw new BupkisError(`Unknown "type": "${type}"`);
|
|
150
151
|
}
|
|
151
152
|
},
|
|
152
153
|
);
|
|
@@ -274,7 +275,7 @@ export const numberCloseToAssertion = createAssertion(
|
|
|
274
275
|
if (diff > tolerance) {
|
|
275
276
|
return {
|
|
276
277
|
actual: subject,
|
|
277
|
-
expected
|
|
278
|
+
expected,
|
|
278
279
|
message: `Expected ${subject} to be close to ${expected} (within ${tolerance}), but difference was ${diff}`,
|
|
279
280
|
};
|
|
280
281
|
}
|
|
@@ -748,7 +749,10 @@ export const functionThrowsMatchingAssertion = createAssertion(
|
|
|
748
749
|
const schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
749
750
|
return schema.safeParse(error).success;
|
|
750
751
|
} else {
|
|
751
|
-
throw new
|
|
752
|
+
throw new InvalidSchemaError(
|
|
753
|
+
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
754
|
+
{ schema: param },
|
|
755
|
+
);
|
|
752
756
|
}
|
|
753
757
|
},
|
|
754
758
|
);
|
|
@@ -819,8 +823,9 @@ export const functionThrowsTypeSatisfyingAssertion = createAssertion(
|
|
|
819
823
|
schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
|
|
820
824
|
}
|
|
821
825
|
if (!schema) {
|
|
822
|
-
throw new
|
|
826
|
+
throw new InvalidSchemaError(
|
|
823
827
|
`Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
|
|
828
|
+
{ schema: param },
|
|
824
829
|
);
|
|
825
830
|
}
|
|
826
831
|
|
|
@@ -892,8 +897,17 @@ export const stringMatchesAssertion = createAssertion(
|
|
|
892
897
|
* @group Parametric Assertions (Sync)
|
|
893
898
|
*/
|
|
894
899
|
export const objectSatisfiesAssertion = createAssertion(
|
|
895
|
-
[
|
|
900
|
+
[
|
|
901
|
+
z.looseObject({}).nonoptional(),
|
|
902
|
+
['to satisfy', 'to be like', 'satisfies'],
|
|
903
|
+
z.any(),
|
|
904
|
+
],
|
|
896
905
|
(_subject, shape) => valueToSchema(shape, valueToSchemaOptionsForSatisfies),
|
|
906
|
+
{
|
|
907
|
+
anchor: 'object-to-satisfy-any',
|
|
908
|
+
category: 'object',
|
|
909
|
+
redirect: 'satisfies',
|
|
910
|
+
},
|
|
897
911
|
);
|
|
898
912
|
|
|
899
913
|
/**
|
package/src/assertion/slotify.ts
CHANGED
|
@@ -14,6 +14,7 @@ import { z } from 'zod/v4';
|
|
|
14
14
|
import type { AssertionParts, AssertionSlots } from './assertion-types.js';
|
|
15
15
|
|
|
16
16
|
import { kStringLiteral } from '../constant.js';
|
|
17
|
+
import { AssertionImplementationError } from '../error.js';
|
|
17
18
|
import {
|
|
18
19
|
isPhraseLiteral,
|
|
19
20
|
isPhraseLiteralChoice,
|
|
@@ -43,7 +44,7 @@ export const slotify = <const Parts extends AssertionParts>(
|
|
|
43
44
|
|
|
44
45
|
if (isPhraseLiteralChoice(part)) {
|
|
45
46
|
if (part.some((p) => p.startsWith('not '))) {
|
|
46
|
-
throw new
|
|
47
|
+
throw new AssertionImplementationError(
|
|
47
48
|
`PhraseLiteralChoice at parts[${index}] must not include phrases starting with "not ": ${inspect(
|
|
48
49
|
part,
|
|
49
50
|
)}`,
|
|
@@ -60,7 +61,7 @@ export const slotify = <const Parts extends AssertionParts>(
|
|
|
60
61
|
);
|
|
61
62
|
} else if (isPhraseLiteral(part)) {
|
|
62
63
|
if (part.startsWith('not ')) {
|
|
63
|
-
throw new
|
|
64
|
+
throw new AssertionImplementationError(
|
|
64
65
|
`PhraseLiteral at parts[${index}] must not start with "not ": ${inspect(
|
|
65
66
|
part,
|
|
66
67
|
)}`,
|
|
@@ -77,7 +78,7 @@ export const slotify = <const Parts extends AssertionParts>(
|
|
|
77
78
|
);
|
|
78
79
|
} else {
|
|
79
80
|
if (!isZodType(part)) {
|
|
80
|
-
throw new
|
|
81
|
+
throw new AssertionImplementationError(
|
|
81
82
|
`Expected Zod schema, phrase literal, or phrase literal choice at parts[${index}] but received ${inspect(
|
|
82
83
|
part,
|
|
83
84
|
)} (${typeof part})`,
|
package/src/constant.ts
CHANGED
|
@@ -77,3 +77,10 @@ export const kExpectIt: unique symbol = Symbol('bupkis-expect-it');
|
|
|
77
77
|
|
|
78
78
|
export const KEYPATH_REGEX =
|
|
79
79
|
/^[a-zA-Z_$][-a-zA-Z0-9_$]*(?:(?:\.[a-zA-Z_$][-a-zA-Z0-9_$]*)|(?:\[(?:\d+|"[^"]*"|'[^']*')\]))*$/;
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Symbol used to flag a function as a Bupkis-thrown error.
|
|
83
|
+
*
|
|
84
|
+
* @internal
|
|
85
|
+
*/
|
|
86
|
+
export const kBupkisError: unique symbol = Symbol('bupkis-error');
|