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.
Files changed (215) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +19 -2
  3. package/dist/commonjs/assertion/assertion-async.d.ts.map +1 -1
  4. package/dist/commonjs/assertion/assertion-async.js +37 -7
  5. package/dist/commonjs/assertion/assertion-async.js.map +1 -1
  6. package/dist/commonjs/assertion/assertion-sync.d.ts.map +1 -1
  7. package/dist/commonjs/assertion/assertion-sync.js +32 -8
  8. package/dist/commonjs/assertion/assertion-sync.js.map +1 -1
  9. package/dist/commonjs/assertion/assertion-types.d.ts +37 -31
  10. package/dist/commonjs/assertion/assertion-types.d.ts.map +1 -1
  11. package/dist/commonjs/assertion/assertion-types.js +0 -32
  12. package/dist/commonjs/assertion/assertion-types.js.map +1 -1
  13. package/dist/commonjs/assertion/assertion.d.ts +3 -21
  14. package/dist/commonjs/assertion/assertion.d.ts.map +1 -1
  15. package/dist/commonjs/assertion/assertion.js +42 -27
  16. package/dist/commonjs/assertion/assertion.js.map +1 -1
  17. package/dist/commonjs/assertion/create.d.ts +2 -0
  18. package/dist/commonjs/assertion/create.d.ts.map +1 -1
  19. package/dist/commonjs/assertion/create.js +38 -42
  20. package/dist/commonjs/assertion/create.js.map +1 -1
  21. package/dist/commonjs/assertion/impl/assertion-util.d.ts +16 -4
  22. package/dist/commonjs/assertion/impl/assertion-util.d.ts.map +1 -1
  23. package/dist/commonjs/assertion/impl/assertion-util.js +20 -15
  24. package/dist/commonjs/assertion/impl/assertion-util.js.map +1 -1
  25. package/dist/commonjs/assertion/impl/async-parametric.d.ts +63 -11
  26. package/dist/commonjs/assertion/impl/async-parametric.d.ts.map +1 -1
  27. package/dist/commonjs/assertion/impl/async-parametric.js +89 -52
  28. package/dist/commonjs/assertion/impl/async-parametric.js.map +1 -1
  29. package/dist/commonjs/assertion/impl/async.d.ts +116 -12
  30. package/dist/commonjs/assertion/impl/async.d.ts.map +1 -1
  31. package/dist/commonjs/assertion/impl/async.js +1 -1
  32. package/dist/commonjs/assertion/impl/sync-basic.d.ts.map +1 -1
  33. package/dist/commonjs/assertion/impl/sync-basic.js +6 -4
  34. package/dist/commonjs/assertion/impl/sync-basic.js.map +1 -1
  35. package/dist/commonjs/assertion/impl/sync-collection.d.ts.map +1 -1
  36. package/dist/commonjs/assertion/impl/sync-collection.js +24 -14
  37. package/dist/commonjs/assertion/impl/sync-collection.js.map +1 -1
  38. package/dist/commonjs/assertion/impl/sync-esoteric.d.ts +1 -5
  39. package/dist/commonjs/assertion/impl/sync-esoteric.d.ts.map +1 -1
  40. package/dist/commonjs/assertion/impl/sync-esoteric.js +11 -13
  41. package/dist/commonjs/assertion/impl/sync-esoteric.js.map +1 -1
  42. package/dist/commonjs/assertion/impl/sync-parametric.d.ts +27 -7
  43. package/dist/commonjs/assertion/impl/sync-parametric.d.ts.map +1 -1
  44. package/dist/commonjs/assertion/impl/sync-parametric.js +75 -51
  45. package/dist/commonjs/assertion/impl/sync-parametric.js.map +1 -1
  46. package/dist/commonjs/assertion/impl/sync.d.ts +54 -22
  47. package/dist/commonjs/assertion/impl/sync.d.ts.map +1 -1
  48. package/dist/commonjs/assertion/impl/sync.js +1 -1
  49. package/dist/commonjs/assertion/impl/sync.js.map +1 -1
  50. package/dist/commonjs/assertion/index.d.ts +1 -1
  51. package/dist/commonjs/assertion/index.d.ts.map +1 -1
  52. package/dist/commonjs/assertion/index.js +0 -1
  53. package/dist/commonjs/assertion/index.js.map +1 -1
  54. package/dist/commonjs/assertion/slotify.d.ts +1 -13
  55. package/dist/commonjs/assertion/slotify.d.ts.map +1 -1
  56. package/dist/commonjs/assertion/slotify.js +49 -16
  57. package/dist/commonjs/assertion/slotify.js.map +1 -1
  58. package/dist/commonjs/bootstrap.d.ts +85 -17
  59. package/dist/commonjs/bootstrap.d.ts.map +1 -1
  60. package/dist/commonjs/bootstrap.js +1 -0
  61. package/dist/commonjs/bootstrap.js.map +1 -1
  62. package/dist/commonjs/diff.d.ts +51 -0
  63. package/dist/commonjs/diff.d.ts.map +1 -0
  64. package/dist/commonjs/diff.js +279 -0
  65. package/dist/commonjs/diff.js.map +1 -0
  66. package/dist/commonjs/error.d.ts +37 -18
  67. package/dist/commonjs/error.d.ts.map +1 -1
  68. package/dist/commonjs/error.js +44 -30
  69. package/dist/commonjs/error.js.map +1 -1
  70. package/dist/commonjs/expect.d.ts.map +1 -1
  71. package/dist/commonjs/expect.js +131 -78
  72. package/dist/commonjs/expect.js.map +1 -1
  73. package/dist/commonjs/guards.d.ts +24 -10
  74. package/dist/commonjs/guards.d.ts.map +1 -1
  75. package/dist/commonjs/guards.js +56 -39
  76. package/dist/commonjs/guards.js.map +1 -1
  77. package/dist/commonjs/index.d.ts +85 -17
  78. package/dist/commonjs/index.d.ts.map +1 -1
  79. package/dist/commonjs/internal-schema.d.ts +25 -0
  80. package/dist/commonjs/internal-schema.d.ts.map +1 -0
  81. package/dist/commonjs/internal-schema.js +209 -0
  82. package/dist/commonjs/internal-schema.js.map +1 -0
  83. package/dist/commonjs/schema.d.ts.map +1 -1
  84. package/dist/commonjs/schema.js +3 -2
  85. package/dist/commonjs/schema.js.map +1 -1
  86. package/dist/commonjs/use.js +22 -8
  87. package/dist/commonjs/use.js.map +1 -1
  88. package/dist/commonjs/util.d.ts +1 -0
  89. package/dist/commonjs/util.d.ts.map +1 -1
  90. package/dist/commonjs/util.js +14 -10
  91. package/dist/commonjs/util.js.map +1 -1
  92. package/dist/commonjs/value-to-schema.d.ts +1 -0
  93. package/dist/commonjs/value-to-schema.d.ts.map +1 -1
  94. package/dist/commonjs/value-to-schema.js +19 -12
  95. package/dist/commonjs/value-to-schema.js.map +1 -1
  96. package/dist/esm/assertion/assertion-async.d.ts.map +1 -1
  97. package/dist/esm/assertion/assertion-async.js +37 -7
  98. package/dist/esm/assertion/assertion-async.js.map +1 -1
  99. package/dist/esm/assertion/assertion-sync.d.ts.map +1 -1
  100. package/dist/esm/assertion/assertion-sync.js +32 -8
  101. package/dist/esm/assertion/assertion-sync.js.map +1 -1
  102. package/dist/esm/assertion/assertion-types.d.ts +37 -31
  103. package/dist/esm/assertion/assertion-types.d.ts.map +1 -1
  104. package/dist/esm/assertion/assertion-types.js +1 -31
  105. package/dist/esm/assertion/assertion-types.js.map +1 -1
  106. package/dist/esm/assertion/assertion.d.ts +3 -21
  107. package/dist/esm/assertion/assertion.d.ts.map +1 -1
  108. package/dist/esm/assertion/assertion.js +42 -27
  109. package/dist/esm/assertion/assertion.js.map +1 -1
  110. package/dist/esm/assertion/create.d.ts +2 -0
  111. package/dist/esm/assertion/create.d.ts.map +1 -1
  112. package/dist/esm/assertion/create.js +37 -41
  113. package/dist/esm/assertion/create.js.map +1 -1
  114. package/dist/esm/assertion/impl/assertion-util.d.ts +16 -4
  115. package/dist/esm/assertion/impl/assertion-util.d.ts.map +1 -1
  116. package/dist/esm/assertion/impl/assertion-util.js +20 -15
  117. package/dist/esm/assertion/impl/assertion-util.js.map +1 -1
  118. package/dist/esm/assertion/impl/async-parametric.d.ts +63 -11
  119. package/dist/esm/assertion/impl/async-parametric.d.ts.map +1 -1
  120. package/dist/esm/assertion/impl/async-parametric.js +89 -52
  121. package/dist/esm/assertion/impl/async-parametric.js.map +1 -1
  122. package/dist/esm/assertion/impl/async.d.ts +116 -12
  123. package/dist/esm/assertion/impl/async.d.ts.map +1 -1
  124. package/dist/esm/assertion/impl/async.js +2 -2
  125. package/dist/esm/assertion/impl/async.js.map +1 -1
  126. package/dist/esm/assertion/impl/sync-basic.d.ts.map +1 -1
  127. package/dist/esm/assertion/impl/sync-basic.js +6 -4
  128. package/dist/esm/assertion/impl/sync-basic.js.map +1 -1
  129. package/dist/esm/assertion/impl/sync-collection.d.ts.map +1 -1
  130. package/dist/esm/assertion/impl/sync-collection.js +24 -14
  131. package/dist/esm/assertion/impl/sync-collection.js.map +1 -1
  132. package/dist/esm/assertion/impl/sync-esoteric.d.ts +1 -5
  133. package/dist/esm/assertion/impl/sync-esoteric.d.ts.map +1 -1
  134. package/dist/esm/assertion/impl/sync-esoteric.js +11 -13
  135. package/dist/esm/assertion/impl/sync-esoteric.js.map +1 -1
  136. package/dist/esm/assertion/impl/sync-parametric.d.ts +27 -7
  137. package/dist/esm/assertion/impl/sync-parametric.d.ts.map +1 -1
  138. package/dist/esm/assertion/impl/sync-parametric.js +75 -51
  139. package/dist/esm/assertion/impl/sync-parametric.js.map +1 -1
  140. package/dist/esm/assertion/impl/sync.d.ts +54 -22
  141. package/dist/esm/assertion/impl/sync.d.ts.map +1 -1
  142. package/dist/esm/assertion/impl/sync.js +2 -2
  143. package/dist/esm/assertion/impl/sync.js.map +1 -1
  144. package/dist/esm/assertion/index.d.ts +1 -1
  145. package/dist/esm/assertion/index.d.ts.map +1 -1
  146. package/dist/esm/assertion/index.js +0 -1
  147. package/dist/esm/assertion/index.js.map +1 -1
  148. package/dist/esm/assertion/slotify.d.ts +1 -13
  149. package/dist/esm/assertion/slotify.d.ts.map +1 -1
  150. package/dist/esm/assertion/slotify.js +50 -17
  151. package/dist/esm/assertion/slotify.js.map +1 -1
  152. package/dist/esm/bootstrap.d.ts +85 -17
  153. package/dist/esm/bootstrap.d.ts.map +1 -1
  154. package/dist/esm/bootstrap.js +1 -0
  155. package/dist/esm/bootstrap.js.map +1 -1
  156. package/dist/esm/diff.d.ts +51 -0
  157. package/dist/esm/diff.d.ts.map +1 -0
  158. package/dist/esm/diff.js +273 -0
  159. package/dist/esm/diff.js.map +1 -0
  160. package/dist/esm/error.d.ts +37 -18
  161. package/dist/esm/error.d.ts.map +1 -1
  162. package/dist/esm/error.js +41 -27
  163. package/dist/esm/error.js.map +1 -1
  164. package/dist/esm/expect.d.ts.map +1 -1
  165. package/dist/esm/expect.js +133 -80
  166. package/dist/esm/expect.js.map +1 -1
  167. package/dist/esm/guards.d.ts +24 -10
  168. package/dist/esm/guards.d.ts.map +1 -1
  169. package/dist/esm/guards.js +52 -36
  170. package/dist/esm/guards.js.map +1 -1
  171. package/dist/esm/index.d.ts +85 -17
  172. package/dist/esm/index.d.ts.map +1 -1
  173. package/dist/esm/internal-schema.d.ts +25 -0
  174. package/dist/esm/internal-schema.d.ts.map +1 -0
  175. package/dist/esm/internal-schema.js +203 -0
  176. package/dist/esm/internal-schema.js.map +1 -0
  177. package/dist/esm/schema.d.ts.map +1 -1
  178. package/dist/esm/schema.js +3 -2
  179. package/dist/esm/schema.js.map +1 -1
  180. package/dist/esm/use.js +19 -6
  181. package/dist/esm/use.js.map +1 -1
  182. package/dist/esm/util.d.ts +1 -0
  183. package/dist/esm/util.d.ts.map +1 -1
  184. package/dist/esm/util.js +14 -10
  185. package/dist/esm/util.js.map +1 -1
  186. package/dist/esm/value-to-schema.d.ts +1 -0
  187. package/dist/esm/value-to-schema.d.ts.map +1 -1
  188. package/dist/esm/value-to-schema.js +20 -13
  189. package/dist/esm/value-to-schema.js.map +1 -1
  190. package/package.json +29 -11
  191. package/src/assertion/assertion-async.ts +42 -14
  192. package/src/assertion/assertion-sync.ts +40 -17
  193. package/src/assertion/assertion-types.ts +55 -45
  194. package/src/assertion/assertion.ts +49 -32
  195. package/src/assertion/create.ts +46 -65
  196. package/src/assertion/impl/assertion-util.ts +31 -18
  197. package/src/assertion/impl/async-parametric.ts +93 -52
  198. package/src/assertion/impl/async.ts +2 -2
  199. package/src/assertion/impl/sync-basic.ts +7 -4
  200. package/src/assertion/impl/sync-collection.ts +34 -14
  201. package/src/assertion/impl/sync-esoteric.ts +17 -13
  202. package/src/assertion/impl/sync-parametric.ts +79 -52
  203. package/src/assertion/impl/sync.ts +2 -2
  204. package/src/assertion/index.ts +1 -1
  205. package/src/assertion/slotify.ts +67 -21
  206. package/src/bootstrap.ts +1 -0
  207. package/src/diff.ts +343 -0
  208. package/src/error.ts +66 -31
  209. package/src/expect.ts +195 -129
  210. package/src/guards.ts +74 -48
  211. package/src/internal-schema.ts +246 -0
  212. package/src/schema.ts +4 -2
  213. package/src/use.ts +21 -7
  214. package/src/util.ts +15 -12
  215. package/src/value-to-schema.ts +21 -13
@@ -5,33 +5,47 @@
5
5
  * @packageDocumentation
6
6
  */
7
7
 
8
+ type TrapResult =
9
+ | { error: unknown; result?: never }
10
+ | { error?: never; result: unknown };
11
+
8
12
  /**
9
13
  * Executes & traps a `Promise` rejected from an async function, capturing the
10
14
  * error.
11
15
  *
16
+ * @function
12
17
  * @param fn The function to execute that may throw an error or return a
13
18
  * `Promise`
14
- * @returns Rejection
19
+ * @returns Rejection or whatever was fulfilled
15
20
  */
16
- export const trapAsyncFnError = async (fn: () => unknown) => {
21
+ export const trapAsyncFnError = async (
22
+ fn: () => unknown,
23
+ ): Promise<TrapResult> => {
17
24
  try {
18
- await fn();
19
- } catch (err) {
20
- return err;
25
+ const result = await fn();
26
+ return { result };
27
+ } catch (error) {
28
+ return {
29
+ error: error ?? new TypeError(`Function rejected with undefined: ${fn}`),
30
+ };
21
31
  }
22
32
  };
23
33
 
24
34
  /**
25
35
  * Awaits & traps a Promise, capturing any rejection error.
26
36
  *
37
+ * @function
27
38
  * @param promise The `Promise` to trap
28
- * @returns Rejection
39
+ * @returns Result object
29
40
  */
30
- export const trapPromiseError = async (promise: PromiseLike<unknown>) => {
41
+ export const trapPromiseError = async (
42
+ promise: PromiseLike<unknown>,
43
+ ): Promise<TrapResult> => {
31
44
  try {
32
- await promise;
33
- } catch (err) {
34
- return err;
45
+ const result = await promise;
46
+ return { result };
47
+ } catch (error) {
48
+ return { error: error ?? new TypeError('Promise rejected with undefined') };
35
49
  }
36
50
  };
37
51
 
@@ -41,16 +55,15 @@ export const trapPromiseError = async (promise: PromiseLike<unknown>) => {
41
55
  *
42
56
  * @remarks
43
57
  * Avoids throwing `undefined` for some reason.
58
+ * @function
44
59
  * @param fn Function to execute
45
- * @returns Error
60
+ * @returns Result object
46
61
  */
47
- export const trapError = (fn: () => unknown): unknown => {
62
+ export const trapError = (fn: () => unknown): TrapResult => {
48
63
  try {
49
- fn();
50
- } catch (err) {
51
- if (err === undefined) {
52
- return new Error('Function threw undefined');
53
- }
54
- return err;
64
+ const result = fn();
65
+ return { result };
66
+ } catch (error) {
67
+ return { error: error ?? new TypeError(`Function threw undefined: ${fn}`) };
55
68
  }
56
69
  };
@@ -16,7 +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
+ import { InvalidObjectSchemaError } from '../../error.js';
20
20
  import { isA, isNonNullObject, isString } from '../../guards.js';
21
21
  import {
22
22
  ConstructibleSchema,
@@ -56,7 +56,7 @@ export const functionResolveAssertion = createAsyncAssertion(
56
56
  }
57
57
  },
58
58
  {
59
- anchor: 'to-resolve',
59
+ anchor: 'promise-to-resolve',
60
60
  category: 'promise',
61
61
  },
62
62
  );
@@ -86,6 +86,10 @@ export const promiseResolveAssertion = createAsyncAssertion(
86
86
  };
87
87
  }
88
88
  },
89
+ {
90
+ anchor: 'promise-to-resolve',
91
+ category: 'promise',
92
+ },
89
93
  );
90
94
 
91
95
  /**
@@ -103,14 +107,14 @@ export const promiseResolveAssertion = createAsyncAssertion(
103
107
  export const functionRejectAssertion = createAsyncAssertion(
104
108
  [FunctionSchema, 'to reject'],
105
109
  async (subject) => {
106
- try {
107
- await subject();
110
+ const { error, result } = await trapAsyncFnError(subject);
111
+ if (error === undefined) {
108
112
  return {
109
113
  actual: 'function fulfilled',
110
- expected: 'function to reject',
111
- message: 'Expected function to reject, but it fulfilled instead',
114
+ expected: 'function rejected',
115
+ message: `Expected function to reject, but it fulfilled with ${inspect(result)}`,
112
116
  };
113
- } catch {}
117
+ }
114
118
  },
115
119
  );
116
120
 
@@ -129,14 +133,14 @@ export const functionRejectAssertion = createAsyncAssertion(
129
133
  export const promiseRejectAssertion = createAsyncAssertion(
130
134
  [WrappedPromiseLikeSchema, 'to reject'],
131
135
  async (subject) => {
132
- try {
133
- await subject;
136
+ const { error, result } = await trapPromiseError(subject);
137
+ if (error === undefined) {
134
138
  return {
135
- actual: 'function fulfilled',
136
- expected: 'function to reject',
137
- message: 'Expected function to reject, but it fulfilled instead',
139
+ actual: 'Promise fulfilled',
140
+ expected: 'Promise rejected',
141
+ message: `Expected Promise to reject, but it fulfilled with ${inspect(result)}`,
138
142
  };
139
- } catch {}
143
+ }
140
144
  },
141
145
  );
142
146
 
@@ -167,11 +171,29 @@ export const functionRejectWithTypeAssertion = createAsyncAssertion(
167
171
  ConstructibleSchema,
168
172
  ],
169
173
  async (subject, ctor) => {
170
- const error = await trapAsyncFnError(subject);
171
- if (!error) {
172
- return false;
174
+ const { error, result } = await trapAsyncFnError(subject);
175
+ if (error === undefined) {
176
+ return {
177
+ actual: 'function fulfilled',
178
+ expect: 'function rejected',
179
+ message: `Expected function to reject, but it fulfilled with ${inspect(result)}`,
180
+ };
181
+ }
182
+ if (!isA(error, ctor)) {
183
+ if (isNonNullObject(error)) {
184
+ const err = error as object;
185
+ return {
186
+ actual: err.constructor.name,
187
+ expected: ctor.name,
188
+ message: `Expected function to reject with an instance of ${ctor.name}, but it rejected with a ${err.constructor.name}`,
189
+ };
190
+ }
191
+ return {
192
+ actual: typeof error,
193
+ expected: ctor.name,
194
+ message: `Expected function to reject with an instance of ${ctor.name}, but it rejected with a value of type ${typeof error}: ${inspect(error)}`,
195
+ };
173
196
  }
174
- return isA(error, ctor);
175
197
  },
176
198
  );
177
199
 
@@ -202,11 +224,29 @@ export const promiseRejectWithTypeAssertion = createAsyncAssertion(
202
224
  ConstructibleSchema,
203
225
  ],
204
226
  async (subject, ctor) => {
205
- const error = await trapPromiseError(subject);
206
- if (!error) {
207
- return false;
227
+ const { error, result } = await trapPromiseError(subject);
228
+ if (error === undefined) {
229
+ return {
230
+ actual: 'Promise fulfilled',
231
+ expect: 'Promise rejected',
232
+ message: `Expected Promise to reject, but it fulfilled with ${inspect(result)}`,
233
+ };
234
+ }
235
+ if (!isA(error, ctor)) {
236
+ if (isNonNullObject(error)) {
237
+ const err = error as object;
238
+ return {
239
+ actual: err.constructor.name,
240
+ expected: ctor.name,
241
+ message: `Expected Promise to reject with an instance of ${ctor.name}, but it rejected with a ${err.constructor.name}`,
242
+ };
243
+ }
244
+ return {
245
+ actual: typeof error,
246
+ expected: ctor.name,
247
+ message: `Expected Promise to reject with an instance of ${ctor.name}, but it rejected with a value of type ${typeof error}: ${inspect(error)}`,
248
+ };
208
249
  }
209
- return isA(error, ctor);
210
250
  },
211
251
  );
212
252
 
@@ -239,12 +279,12 @@ export const promiseRejectWithTypeAssertion = createAsyncAssertion(
239
279
  export const functionRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
240
280
  [FunctionSchema, ['to reject with error satisfying'], z.any()],
241
281
  async (subject, param) => {
242
- const error = await trapAsyncFnError(subject);
243
- if (!error) {
282
+ const { error, result } = await trapAsyncFnError(subject);
283
+ if (error === undefined) {
244
284
  return {
245
285
  actual: 'function fulfilled',
246
286
  expect: 'function to reject',
247
- message: 'Expected function to reject, but it fulfilled instead',
287
+ message: `Expected function to reject, but it fulfilled with ${inspect(result)}`,
248
288
  };
249
289
  }
250
290
 
@@ -267,16 +307,16 @@ export const functionRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
267
307
  }
268
308
  /* c8 ignore next 5 */
269
309
  if (!schema) {
270
- throw new InvalidSchemaError(
310
+ throw new InvalidObjectSchemaError(
271
311
  `Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
272
312
  { schema: param },
273
313
  );
274
314
  }
275
315
 
276
- const result = schema.safeParse(error);
277
- if (!result.success) {
278
- return result.error;
279
- }
316
+ return {
317
+ schema,
318
+ subject: error,
319
+ };
280
320
  },
281
321
  );
282
322
 
@@ -309,12 +349,12 @@ export const functionRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
309
349
  export const promiseRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
310
350
  [WrappedPromiseLikeSchema, ['to reject with error satisfying'], z.any()],
311
351
  async (subject, param) => {
312
- const error = await trapPromiseError(subject);
313
- if (!error) {
352
+ const { error, result } = await trapPromiseError(subject);
353
+ if (error === undefined) {
314
354
  return {
315
- actual: 'promise fulfilled',
316
- expect: 'promise to reject',
317
- message: 'Expected promise to reject, but it fulfilled instead',
355
+ actual: 'Promise fulfilled',
356
+ expect: 'Promise rejected',
357
+ message: `Expected Promise to reject, but it fulfilled with ${inspect(result)}`,
318
358
  };
319
359
  }
320
360
  let schema: undefined | z.ZodType;
@@ -336,16 +376,16 @@ export const promiseRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
336
376
  }
337
377
  /* c8 ignore next 5 */
338
378
  if (!schema) {
339
- throw new InvalidSchemaError(
379
+ throw new InvalidObjectSchemaError(
340
380
  `Invalid parameter schema: ${inspect(param, { depth: 2 })}`,
341
381
  { schema: param },
342
382
  );
343
383
  }
344
384
 
345
- const result = schema.safeParse(error);
346
- if (!result.success) {
347
- return result.error;
348
- }
385
+ return {
386
+ schema,
387
+ subject: error,
388
+ };
349
389
  },
350
390
  );
351
391
 
@@ -375,7 +415,7 @@ export const promiseRejectWithErrorSatisfyingAssertion = createAsyncAssertion(
375
415
  *
376
416
  * @group Parametric Assertions (Async)
377
417
  */
378
- export const promiseFulfillWithValueSatisfyingAssertion = createAsyncAssertion(
418
+ export const promiseResolveWithValueSatisfyingAssertion = createAsyncAssertion(
379
419
  [
380
420
  WrappedPromiseLikeSchema,
381
421
  ['to fulfill with value satisfying', 'to resolve with value satisfying'],
@@ -387,19 +427,20 @@ export const promiseFulfillWithValueSatisfyingAssertion = createAsyncAssertion(
387
427
  value = await promise;
388
428
  } catch (err) {
389
429
  return {
390
- actual: err,
391
- expect: 'promise to fulfill',
392
- message: `Expected promise to not reject, but it rejected with ${inspect(
430
+ actual: 'Promise rejected',
431
+ expect: 'Promise to fulfill',
432
+ message: `Expected Promise to fulfill, but it rejected with ${inspect(
393
433
  err,
394
434
  )}`,
395
435
  };
396
436
  }
397
437
 
398
438
  const schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
399
- const result = schema.safeParse(value);
400
- if (!result.success) {
401
- return result.error;
402
- }
439
+
440
+ return {
441
+ schema,
442
+ subject: value,
443
+ };
403
444
  },
404
445
  );
405
446
 
@@ -442,7 +483,7 @@ export const functionFulfillWithValueSatisfyingAssertion = createAsyncAssertion(
442
483
  } catch (err) {
443
484
  return {
444
485
  actual: 'function rejected',
445
- expect: 'function to fulfill',
486
+ expect: 'function fulfilled',
446
487
  message: `Expected function to fulfill, but it rejected with ${inspect(
447
488
  err,
448
489
  )}`,
@@ -450,9 +491,9 @@ export const functionFulfillWithValueSatisfyingAssertion = createAsyncAssertion(
450
491
  }
451
492
 
452
493
  const schema = valueToSchema(param, valueToSchemaOptionsForSatisfies);
453
- const result = schema.safeParse(value);
454
- if (!result.success) {
455
- return result.error;
456
- }
494
+ return {
495
+ schema,
496
+ subject: value,
497
+ };
457
498
  },
458
499
  );
@@ -13,11 +13,11 @@ import {
13
13
  functionRejectWithErrorSatisfyingAssertion,
14
14
  functionRejectWithTypeAssertion,
15
15
  functionResolveAssertion,
16
- promiseFulfillWithValueSatisfyingAssertion,
17
16
  promiseRejectAssertion,
18
17
  promiseRejectWithErrorSatisfyingAssertion,
19
18
  promiseRejectWithTypeAssertion,
20
19
  promiseResolveAssertion,
20
+ promiseResolveWithValueSatisfyingAssertion,
21
21
  } from './async-parametric.js';
22
22
 
23
23
  /**
@@ -34,7 +34,7 @@ export const AsyncParametricAssertions = [
34
34
  promiseRejectWithTypeAssertion,
35
35
  functionRejectWithErrorSatisfyingAssertion,
36
36
  promiseRejectWithErrorSatisfyingAssertion,
37
- promiseFulfillWithValueSatisfyingAssertion,
37
+ promiseResolveWithValueSatisfyingAssertion,
38
38
  functionFulfillWithValueSatisfyingAssertion,
39
39
  ] as const;
40
40
 
@@ -27,6 +27,8 @@ import {
27
27
  } from '../../schema.js';
28
28
  import { createAssertion } from '../create.js';
29
29
 
30
+ const { ownKeys } = Reflect;
31
+
30
32
  /**
31
33
  * Asserts that the subject is a string value.
32
34
  *
@@ -39,7 +41,10 @@ import { createAssertion } from '../create.js';
39
41
  *
40
42
  * @group Basic Assertions
41
43
  */
42
- export const stringAssertion = createAssertion(['to be a string'], z.string());
44
+ export const stringAssertion = createAssertion(['to be a string'], z.string(), {
45
+ anchor: 'unknown-to-be-a-string',
46
+ category: 'primitives',
47
+ });
43
48
 
44
49
  /**
45
50
  * Asserts that the subject is a finite number value.
@@ -571,9 +576,7 @@ export const emptyArrayAssertion = createAssertion(
571
576
  */
572
577
  export const emptyObjectAssertion = createAssertion(
573
578
  [z.record(z.any(), z.unknown()), 'to be empty'],
574
- z
575
- .record(z.any(), z.unknown())
576
- .refine((obj) => Reflect.ownKeys(obj).length === 0),
579
+ z.record(z.any(), z.unknown()).refine((obj) => ownKeys(obj).length === 0),
577
580
  );
578
581
 
579
582
  /**
@@ -32,6 +32,8 @@ import {
32
32
  import { has } from '../../util.js';
33
33
  import { createAssertion } from '../create.js';
34
34
 
35
+ const { hasOwn, keys } = Object;
36
+
35
37
  /**
36
38
  * Asserts that a Map or WeakMap contains a specific key. For WeakMap, the key
37
39
  * must be an object.
@@ -101,7 +103,9 @@ export const mapContainsAssertion = createAssertion(
101
103
  export const mapSizeAssertion = createAssertion(
102
104
  [z.map(z.unknown(), z.unknown()), 'to have size', NonNegativeIntegerSchema],
103
105
  (subject, expectedSize): AssertionFailure | boolean => {
104
- if (subject.size === expectedSize) return true;
106
+ if (subject.size === expectedSize) {
107
+ return true;
108
+ }
105
109
  return {
106
110
  actual: subject.size,
107
111
  expected: expectedSize,
@@ -242,7 +246,9 @@ export const emptySetAssertion = createAssertion(
242
246
  export const arrayContainsAssertion = createAssertion(
243
247
  [z.array(z.any()), ['to contain', 'to include'], z.any()],
244
248
  (subject, value): AssertionFailure | boolean => {
245
- if (subject.includes(value)) return true;
249
+ if (subject.includes(value)) {
250
+ return true;
251
+ }
246
252
  return {
247
253
  actual: subject,
248
254
  expected: `array containing ${String(value)}`,
@@ -266,7 +272,9 @@ export const arrayContainsAssertion = createAssertion(
266
272
  export const arraySizeAssertion = createAssertion(
267
273
  [z.array(z.any()), 'to have size', NonNegativeIntegerSchema],
268
274
  (subject, expectedSize): AssertionFailure | boolean => {
269
- if (subject.length === expectedSize) return true;
275
+ if (subject.length === expectedSize) {
276
+ return true;
277
+ }
270
278
  return {
271
279
  actual: subject.length,
272
280
  expected: expectedSize,
@@ -339,7 +347,7 @@ export const objectKeysAssertion = createAssertion(
339
347
  z.array(z.string()).nonempty(),
340
348
  ],
341
349
  (subject, keys) => {
342
- const missing = keys.filter((k) => !Object.hasOwn(subject, k));
350
+ const missing = keys.filter((k) => !hasOwn(subject, k));
343
351
  if (missing.length > 0) {
344
352
  return {
345
353
  actual: `missing keys: ${missing.join(', ')}`,
@@ -439,7 +447,7 @@ export const objectExactKeyAssertion = createAssertion(
439
447
  ],
440
448
  (_, key) =>
441
449
  NonCollectionObjectSchema.transform((v) => ({ ...v })).refine(
442
- (value) => Object.hasOwn(value, key),
450
+ (value) => hasOwn(value, key),
443
451
  { error: `Expected object to have own exact key "${String(key)}"` },
444
452
  ),
445
453
  );
@@ -459,7 +467,7 @@ export const objectExactKeyAssertion = createAssertion(
459
467
  export const objectSizeAssertion = createAssertion(
460
468
  [z.looseObject({}), 'to have size', NonNegativeIntegerSchema],
461
469
  (subject, expectedSize) => {
462
- const actual = Object.keys(subject).length;
470
+ const actual = keys(subject).length;
463
471
  if (actual !== expectedSize) {
464
472
  return {
465
473
  actual,
@@ -713,9 +721,11 @@ export const setSymmetricDifferenceEqualityAssertion = createAssertion(
713
721
  export const mapKeyAssertion = createAssertion(
714
722
  [z.map(z.unknown(), z.unknown()), 'to have key', z.unknown()],
715
723
  (map, key): AssertionFailure | boolean => {
716
- if (map.has(key)) return true;
724
+ if (map.has(key)) {
725
+ return true;
726
+ }
717
727
  return {
718
- actual: Array.from(map.keys()),
728
+ actual: [...map.keys()],
719
729
  expected: key,
720
730
  message: `Expected Map to have key`,
721
731
  };
@@ -739,10 +749,12 @@ export const mapValueAssertion = createAssertion(
739
749
  [z.map(z.unknown(), z.unknown()), 'to have value', z.unknown()],
740
750
  (map, value): AssertionFailure | boolean => {
741
751
  for (const mapValue of map.values()) {
742
- if (mapValue === value) return true;
752
+ if (mapValue === value) {
753
+ return true;
754
+ }
743
755
  }
744
756
  return {
745
- actual: Array.from(map.values()),
757
+ actual: [...map.values()],
746
758
  expected: value,
747
759
  message: `Expected Map to have value`,
748
760
  };
@@ -781,7 +793,9 @@ export const mapEntryAssertion = createAssertion(
781
793
  // At this point, if it's a WeakMap, we know key is a WeakKey
782
794
  const actualValue =
783
795
  map instanceof WeakMap ? map.get(key as WeakKey) : map.get(key);
784
- if (actualValue === value) return true;
796
+ if (actualValue === value) {
797
+ return true;
798
+ }
785
799
 
786
800
  const hasKey =
787
801
  map instanceof WeakMap ? map.has(key as WeakKey) : map.has(key);
@@ -867,7 +881,9 @@ export const collectionSizeGreaterThanAssertion = createAssertion(
867
881
  NonNegativeIntegerSchema,
868
882
  ],
869
883
  (collection, minSize): AssertionFailure | boolean => {
870
- if (collection.size > minSize) return true;
884
+ if (collection.size > minSize) {
885
+ return true;
886
+ }
871
887
  return {
872
888
  actual: collection.size,
873
889
  expected: `size greater than ${minSize}`,
@@ -895,7 +911,9 @@ export const collectionSizeLessThanAssertion = createAssertion(
895
911
  NonNegativeIntegerSchema,
896
912
  ],
897
913
  (collection, maxSize): AssertionFailure | boolean => {
898
- if (collection.size < maxSize) return true;
914
+ if (collection.size < maxSize) {
915
+ return true;
916
+ }
899
917
  return {
900
918
  actual: collection.size,
901
919
  expected: `size less than ${maxSize}`,
@@ -924,7 +942,9 @@ export const collectionSizeBetweenAssertion = createAssertion(
924
942
  ],
925
943
  (collection, [min, max]): AssertionFailure | boolean => {
926
944
  const size = collection.size;
927
- if (size >= min && size <= max) return true;
945
+ if (size >= min && size <= max) {
946
+ return true;
947
+ }
928
948
  return {
929
949
  actual: size,
930
950
  expected: `size between ${min} and ${max} (inclusive)`,
@@ -12,9 +12,12 @@
12
12
 
13
13
  import { z } from 'zod/v4';
14
14
 
15
+ import { isNonNullObject } from '../../guards.js';
15
16
  import { DictionarySchema, PropertyKeySchema } from '../../schema.js';
16
17
  import { createAssertion } from '../create.js';
17
18
 
19
+ const { getOwnPropertyDescriptor, isExtensible, isFrozen, isSealed } = Object;
20
+
18
21
  /**
19
22
  * Asserts that an object has a null prototype (i.e.,
20
23
  * `Object.getPrototypeOf(obj) === null`).
@@ -72,7 +75,7 @@ export const enumerablePropertyAssertion = createAssertion(
72
75
  z.unknown().nonoptional(),
73
76
  ],
74
77
  (subject, obj) => {
75
- if (!Object.getOwnPropertyDescriptor(obj, subject)?.enumerable) {
78
+ if (!getOwnPropertyDescriptor(obj, subject)?.enumerable) {
76
79
  return {
77
80
  actual: false,
78
81
  expected: true,
@@ -112,15 +115,16 @@ export const enumerablePropertyAssertion = createAssertion(
112
115
  */
113
116
  export const enumerablePropertyAssertion2 = createAssertion(
114
117
  [z.unknown().nonoptional(), 'to have enumerable property', PropertyKeySchema],
115
- (subject, key) => {
116
- if (!Object.getOwnPropertyDescriptor(subject, key)?.enumerable) {
117
- return {
118
- actual: false,
119
- expected: true,
120
- message: `Expected property ${String(key)} to be enumerable`,
121
- };
122
- }
123
- },
118
+ (_subject, key) =>
119
+ z.custom(
120
+ (value) =>
121
+ isNonNullObject(value) &&
122
+ key in value &&
123
+ !!getOwnPropertyDescriptor(value, key)?.enumerable,
124
+ {
125
+ error: `Expected property "${String(key)}" to be enumerable`,
126
+ },
127
+ ),
124
128
  );
125
129
 
126
130
  /**
@@ -150,7 +154,7 @@ export const enumerablePropertyAssertion2 = createAssertion(
150
154
  */
151
155
  export const sealedAssertion = createAssertion(
152
156
  ['to be sealed'],
153
- z.any().refine((obj) => Object.isSealed(obj)),
157
+ z.any().refine((obj) => isSealed(obj)),
154
158
  );
155
159
 
156
160
  /**
@@ -181,7 +185,7 @@ export const sealedAssertion = createAssertion(
181
185
  * @group Esoteric Assertions
182
186
  */
183
187
  export const frozenAssertion = createAssertion(['to be frozen'], (subject) => {
184
- if (!Object.isFrozen(subject)) {
188
+ if (!isFrozen(subject)) {
185
189
  return {
186
190
  actual: false,
187
191
  expected: true,
@@ -221,5 +225,5 @@ export const frozenAssertion = createAssertion(['to be frozen'], (subject) => {
221
225
  */
222
226
  export const extensibleAssertion = createAssertion(
223
227
  ['to be extensible'],
224
- z.any().refine((obj) => Object.isExtensible(obj)),
228
+ z.any().refine((obj) => isExtensible(obj)),
225
229
  );