bupkis 0.1.2 → 0.3.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 (198) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/README.md +16 -16
  3. package/dist/commonjs/assertion/assertion-async.d.ts +2 -1
  4. package/dist/commonjs/assertion/assertion-async.d.ts.map +1 -1
  5. package/dist/commonjs/assertion/assertion-async.js +84 -2
  6. package/dist/commonjs/assertion/assertion-async.js.map +1 -1
  7. package/dist/commonjs/assertion/assertion-sync.d.ts +1 -1
  8. package/dist/commonjs/assertion/assertion-sync.d.ts.map +1 -1
  9. package/dist/commonjs/assertion/assertion-sync.js +5 -1
  10. package/dist/commonjs/assertion/assertion-sync.js.map +1 -1
  11. package/dist/commonjs/assertion/assertion-types.d.ts +39 -84
  12. package/dist/commonjs/assertion/assertion-types.d.ts.map +1 -1
  13. package/dist/commonjs/assertion/assertion.d.ts +1 -1
  14. package/dist/commonjs/assertion/assertion.d.ts.map +1 -1
  15. package/dist/commonjs/assertion/assertion.js +1 -14
  16. package/dist/commonjs/assertion/assertion.js.map +1 -1
  17. package/dist/commonjs/assertion/create.d.ts +5 -33
  18. package/dist/commonjs/assertion/create.d.ts.map +1 -1
  19. package/dist/commonjs/assertion/create.js +17 -6
  20. package/dist/commonjs/assertion/create.js.map +1 -1
  21. package/dist/commonjs/assertion/impl/async.d.ts +122 -21
  22. package/dist/commonjs/assertion/impl/async.d.ts.map +1 -1
  23. package/dist/commonjs/assertion/impl/async.js +114 -90
  24. package/dist/commonjs/assertion/impl/async.js.map +1 -1
  25. package/dist/commonjs/assertion/impl/callback.d.ts +104 -0
  26. package/dist/commonjs/assertion/impl/callback.d.ts.map +1 -0
  27. package/dist/commonjs/assertion/impl/callback.js +694 -0
  28. package/dist/commonjs/assertion/impl/callback.js.map +1 -0
  29. package/dist/commonjs/assertion/impl/index.d.ts +1 -1
  30. package/dist/commonjs/assertion/impl/index.d.ts.map +1 -1
  31. package/dist/commonjs/assertion/impl/index.js.map +1 -1
  32. package/dist/commonjs/assertion/impl/sync-esoteric.js +1 -1
  33. package/dist/commonjs/assertion/impl/sync-esoteric.js.map +1 -1
  34. package/dist/commonjs/assertion/impl/sync-parametric.d.ts +37 -34
  35. package/dist/commonjs/assertion/impl/sync-parametric.d.ts.map +1 -1
  36. package/dist/commonjs/assertion/impl/sync-parametric.js +32 -47
  37. package/dist/commonjs/assertion/impl/sync-parametric.js.map +1 -1
  38. package/dist/commonjs/assertion/impl/sync.d.ts +105 -58
  39. package/dist/commonjs/assertion/impl/sync.d.ts.map +1 -1
  40. package/dist/commonjs/assertion/impl/sync.js +4 -1
  41. package/dist/commonjs/assertion/impl/sync.js.map +1 -1
  42. package/dist/commonjs/bootstrap.d.ts +199 -85
  43. package/dist/commonjs/bootstrap.d.ts.map +1 -1
  44. package/dist/commonjs/bootstrap.js +19 -10
  45. package/dist/commonjs/bootstrap.js.map +1 -1
  46. package/dist/commonjs/constant.js +7 -1
  47. package/dist/commonjs/constant.js.map +1 -1
  48. package/dist/commonjs/error.d.ts +32 -5
  49. package/dist/commonjs/error.d.ts.map +1 -1
  50. package/dist/commonjs/error.js +60 -5
  51. package/dist/commonjs/error.js.map +1 -1
  52. package/dist/commonjs/expect.d.ts +130 -3
  53. package/dist/commonjs/expect.d.ts.map +1 -1
  54. package/dist/commonjs/expect.js +116 -1
  55. package/dist/commonjs/expect.js.map +1 -1
  56. package/dist/commonjs/guards.d.ts +45 -20
  57. package/dist/commonjs/guards.d.ts.map +1 -1
  58. package/dist/commonjs/guards.js +56 -40
  59. package/dist/commonjs/guards.js.map +1 -1
  60. package/dist/commonjs/index.d.ts +241 -86
  61. package/dist/commonjs/index.d.ts.map +1 -1
  62. package/dist/commonjs/index.js +44 -42
  63. package/dist/commonjs/index.js.map +1 -1
  64. package/dist/commonjs/metadata.d.ts +1 -27
  65. package/dist/commonjs/metadata.d.ts.map +1 -1
  66. package/dist/commonjs/metadata.js +16 -15
  67. package/dist/commonjs/metadata.js.map +1 -1
  68. package/dist/commonjs/schema.d.ts +76 -33
  69. package/dist/commonjs/schema.d.ts.map +1 -1
  70. package/dist/commonjs/schema.js +77 -34
  71. package/dist/commonjs/schema.js.map +1 -1
  72. package/dist/commonjs/types.d.ts +480 -39
  73. package/dist/commonjs/types.d.ts.map +1 -1
  74. package/dist/commonjs/types.js +12 -2
  75. package/dist/commonjs/types.js.map +1 -1
  76. package/dist/commonjs/util.d.ts +72 -49
  77. package/dist/commonjs/util.d.ts.map +1 -1
  78. package/dist/commonjs/util.js +175 -155
  79. package/dist/commonjs/util.js.map +1 -1
  80. package/dist/commonjs/value-to-schema.d.ts +122 -0
  81. package/dist/commonjs/value-to-schema.d.ts.map +1 -0
  82. package/dist/commonjs/value-to-schema.js +309 -0
  83. package/dist/commonjs/value-to-schema.js.map +1 -0
  84. package/dist/esm/assertion/assertion-async.d.ts +2 -1
  85. package/dist/esm/assertion/assertion-async.d.ts.map +1 -1
  86. package/dist/esm/assertion/assertion-async.js +85 -3
  87. package/dist/esm/assertion/assertion-async.js.map +1 -1
  88. package/dist/esm/assertion/assertion-sync.d.ts +1 -1
  89. package/dist/esm/assertion/assertion-sync.d.ts.map +1 -1
  90. package/dist/esm/assertion/assertion-sync.js +6 -2
  91. package/dist/esm/assertion/assertion-sync.js.map +1 -1
  92. package/dist/esm/assertion/assertion-types.d.ts +39 -84
  93. package/dist/esm/assertion/assertion-types.d.ts.map +1 -1
  94. package/dist/esm/assertion/assertion.d.ts +1 -1
  95. package/dist/esm/assertion/assertion.d.ts.map +1 -1
  96. package/dist/esm/assertion/assertion.js +1 -14
  97. package/dist/esm/assertion/assertion.js.map +1 -1
  98. package/dist/esm/assertion/create.d.ts +5 -33
  99. package/dist/esm/assertion/create.d.ts.map +1 -1
  100. package/dist/esm/assertion/create.js +14 -4
  101. package/dist/esm/assertion/create.js.map +1 -1
  102. package/dist/esm/assertion/impl/async.d.ts +122 -21
  103. package/dist/esm/assertion/impl/async.d.ts.map +1 -1
  104. package/dist/esm/assertion/impl/async.js +113 -89
  105. package/dist/esm/assertion/impl/async.js.map +1 -1
  106. package/dist/esm/assertion/impl/callback.d.ts +104 -0
  107. package/dist/esm/assertion/impl/callback.d.ts.map +1 -0
  108. package/dist/esm/assertion/impl/callback.js +691 -0
  109. package/dist/esm/assertion/impl/callback.js.map +1 -0
  110. package/dist/esm/assertion/impl/index.d.ts +1 -1
  111. package/dist/esm/assertion/impl/index.d.ts.map +1 -1
  112. package/dist/esm/assertion/impl/index.js +1 -1
  113. package/dist/esm/assertion/impl/index.js.map +1 -1
  114. package/dist/esm/assertion/impl/sync-esoteric.js +2 -2
  115. package/dist/esm/assertion/impl/sync-esoteric.js.map +1 -1
  116. package/dist/esm/assertion/impl/sync-parametric.d.ts +37 -34
  117. package/dist/esm/assertion/impl/sync-parametric.d.ts.map +1 -1
  118. package/dist/esm/assertion/impl/sync-parametric.js +32 -47
  119. package/dist/esm/assertion/impl/sync-parametric.js.map +1 -1
  120. package/dist/esm/assertion/impl/sync.d.ts +105 -58
  121. package/dist/esm/assertion/impl/sync.d.ts.map +1 -1
  122. package/dist/esm/assertion/impl/sync.js +3 -1
  123. package/dist/esm/assertion/impl/sync.js.map +1 -1
  124. package/dist/esm/bootstrap.d.ts +199 -85
  125. package/dist/esm/bootstrap.d.ts.map +1 -1
  126. package/dist/esm/bootstrap.js +19 -10
  127. package/dist/esm/bootstrap.js.map +1 -1
  128. package/dist/esm/constant.js +6 -0
  129. package/dist/esm/constant.js.map +1 -1
  130. package/dist/esm/error.d.ts +32 -5
  131. package/dist/esm/error.d.ts.map +1 -1
  132. package/dist/esm/error.js +59 -5
  133. package/dist/esm/error.js.map +1 -1
  134. package/dist/esm/expect.d.ts +130 -3
  135. package/dist/esm/expect.d.ts.map +1 -1
  136. package/dist/esm/expect.js +117 -2
  137. package/dist/esm/expect.js.map +1 -1
  138. package/dist/esm/guards.d.ts +45 -20
  139. package/dist/esm/guards.d.ts.map +1 -1
  140. package/dist/esm/guards.js +48 -31
  141. package/dist/esm/guards.js.map +1 -1
  142. package/dist/esm/index.d.ts +241 -86
  143. package/dist/esm/index.d.ts.map +1 -1
  144. package/dist/esm/index.js +46 -7
  145. package/dist/esm/index.js.map +1 -1
  146. package/dist/esm/metadata.d.ts +1 -27
  147. package/dist/esm/metadata.d.ts.map +1 -1
  148. package/dist/esm/metadata.js +2 -1
  149. package/dist/esm/metadata.js.map +1 -1
  150. package/dist/esm/schema.d.ts +76 -33
  151. package/dist/esm/schema.d.ts.map +1 -1
  152. package/dist/esm/schema.js +77 -34
  153. package/dist/esm/schema.js.map +1 -1
  154. package/dist/esm/types.d.ts +480 -39
  155. package/dist/esm/types.d.ts.map +1 -1
  156. package/dist/esm/types.js +12 -2
  157. package/dist/esm/types.js.map +1 -1
  158. package/dist/esm/util.d.ts +72 -49
  159. package/dist/esm/util.d.ts.map +1 -1
  160. package/dist/esm/util.js +159 -153
  161. package/dist/esm/util.js.map +1 -1
  162. package/dist/esm/value-to-schema.d.ts +122 -0
  163. package/dist/esm/value-to-schema.d.ts.map +1 -0
  164. package/dist/esm/value-to-schema.js +305 -0
  165. package/dist/esm/value-to-schema.js.map +1 -0
  166. package/package.json +94 -17
  167. package/src/assertion/assertion-async.ts +113 -3
  168. package/src/assertion/assertion-sync.ts +5 -2
  169. package/src/assertion/assertion-types.ts +52 -45
  170. package/src/assertion/assertion.ts +2 -17
  171. package/src/assertion/create.ts +16 -65
  172. package/src/assertion/impl/async.ts +132 -92
  173. package/src/assertion/impl/callback.ts +882 -0
  174. package/src/assertion/impl/index.ts +1 -1
  175. package/src/assertion/impl/sync-esoteric.ts +2 -2
  176. package/src/assertion/impl/sync-parametric.ts +41 -49
  177. package/src/assertion/impl/sync.ts +3 -0
  178. package/src/bootstrap.ts +21 -11
  179. package/src/constant.ts +8 -0
  180. package/src/error.ts +75 -4
  181. package/src/expect.ts +275 -20
  182. package/src/guards.ts +74 -69
  183. package/src/index.ts +72 -11
  184. package/src/metadata.ts +3 -4
  185. package/src/schema.ts +80 -36
  186. package/src/types.ts +625 -72
  187. package/src/util.ts +174 -222
  188. package/src/value-to-schema.ts +464 -0
  189. package/dist/commonjs/api.d.ts +0 -93
  190. package/dist/commonjs/api.d.ts.map +0 -1
  191. package/dist/commonjs/api.js +0 -8
  192. package/dist/commonjs/api.js.map +0 -1
  193. package/dist/esm/api.d.ts +0 -93
  194. package/dist/esm/api.d.ts.map +0 -1
  195. package/dist/esm/api.js +0 -7
  196. package/dist/esm/api.js.map +0 -1
  197. package/src/api.ts +0 -149
  198. package/src/schema.md +0 -15
@@ -0,0 +1,464 @@
1
+ import { z } from 'zod/v4';
2
+
3
+ import {
4
+ isNonNullObject,
5
+ isObject,
6
+ isPromiseLike,
7
+ isString,
8
+ isZodType,
9
+ } from './guards.js';
10
+ import {
11
+ RegExpSchema,
12
+ StrongMapSchema,
13
+ StrongSetSchema,
14
+ WrappedPromiseLikeSchema,
15
+ } from './schema.js';
16
+
17
+ /**
18
+ * Recursively converts an arbitrary value to a Zod v4 schema that would
19
+ * validate values with the same structure.
20
+ *
21
+ * This function analyzes the runtime value and generates a corresponding Zod
22
+ * schema that captures the value's structure and type information. It handles
23
+ * primitives, objects, arrays, functions, and various built-in types, with
24
+ * support for circular reference detection.
25
+ *
26
+ * @example
27
+ *
28
+ * ```typescript
29
+ * // Primitive types
30
+ * valueToSchema('hello'); // z.string()
31
+ * valueToSchema(42); // z.number()
32
+ * valueToSchema(true); // z.boolean()
33
+ *
34
+ * // Objects
35
+ * valueToSchema({ name: 'John', age: 30 });
36
+ * // z.object({ name: z.string(), age: z.number() })
37
+ *
38
+ * // Arrays
39
+ * valueToSchema(['a', 'b', 'c']); // z.array(z.string())
40
+ * valueToSchema([1, 'mixed']); // z.array(z.union([z.number(), z.string()]))
41
+ *
42
+ * // Nested structures
43
+ * valueToSchema({ users: [{ name: 'John' }] });
44
+ * // z.object({ users: z.array(z.object({ name: z.string() })) })
45
+ * ```
46
+ *
47
+ * @param value - The value to convert to a schema
48
+ * @param options - Configuration options for schema generation
49
+ * @param visited - Internal WeakSet for circular reference detection
50
+ * @returns A Zod schema that validates values matching the input's structure.
51
+ * This value is unfortunately untyped due to the complexity involved. But the
52
+ * schema works!
53
+ */
54
+
55
+ export const valueToSchema = (
56
+ value: unknown,
57
+ options: ValueToSchemaOptions = {},
58
+ visited = new WeakSet<object>(),
59
+ ): z.ZodType<any> => {
60
+ const {
61
+ _currentDepth = 0,
62
+ literalEmptyObjects = false,
63
+ literalPrimitives = false,
64
+ literalRegExp = false,
65
+ literalTuples = false,
66
+ maxDepth = 10,
67
+ noMixedArrays = false,
68
+ strict = false,
69
+ } = options;
70
+
71
+ // Prevent infinite recursion
72
+ if (_currentDepth >= maxDepth) {
73
+ return z.unknown();
74
+ }
75
+
76
+ // Handle primitives
77
+ if (value === null) {
78
+ return z.null();
79
+ }
80
+
81
+ if (value === undefined) {
82
+ return literalPrimitives
83
+ ? z.custom<undefined>((val: unknown) => val === undefined, {
84
+ message: 'Expected undefined',
85
+ })
86
+ : z.undefined();
87
+ }
88
+ if (Number.isNaN(value as number)) {
89
+ return z.nan();
90
+ }
91
+ if (value === Infinity || value === -Infinity) {
92
+ return z.literal(value);
93
+ }
94
+
95
+ const valueType = typeof value;
96
+
97
+ switch (valueType) {
98
+ case 'bigint':
99
+ return literalPrimitives ? z.literal(value as bigint) : z.bigint();
100
+ case 'boolean':
101
+ return literalPrimitives ? z.literal(value as boolean) : z.boolean();
102
+ case 'function':
103
+ return z.function();
104
+ case 'number':
105
+ return literalPrimitives ? z.literal(value as number) : z.number();
106
+ case 'string':
107
+ return literalPrimitives ? z.literal(value as string) : z.string();
108
+ case 'symbol':
109
+ return z.symbol();
110
+ }
111
+
112
+ // Handle objects
113
+ if (typeof value === 'object' && value !== null) {
114
+ // Check for circular references
115
+ if (visited.has(value)) {
116
+ // Return a recursive schema reference or unknown for circular refs
117
+ return z.unknown();
118
+ }
119
+
120
+ visited.add(value);
121
+
122
+ try {
123
+ // Check for objects with own __proto__ property - these can cause unexpected behavior
124
+ if (Object.hasOwn(value, '__proto__')) {
125
+ throw new TypeError(
126
+ 'Objects with an own "__proto__" property are not supported by valueToSchema',
127
+ );
128
+ }
129
+
130
+ // Handle built-in object types
131
+ if (value instanceof Date) {
132
+ // Check if it's a valid date
133
+ if (isNaN(value.getTime())) {
134
+ // For invalid dates, use a literal or custom validator
135
+ return z.custom<Date>(
136
+ (val) => val instanceof Date && isNaN(val.getTime()),
137
+ {
138
+ message: 'Expected an invalid Date',
139
+ },
140
+ );
141
+ }
142
+ return z.date();
143
+ }
144
+
145
+ if (value instanceof RegExp) {
146
+ if (literalRegExp) {
147
+ return RegExpSchema;
148
+ }
149
+ return z.coerce.string().regex(value);
150
+ }
151
+
152
+ if (value instanceof Map) {
153
+ return StrongMapSchema;
154
+ }
155
+
156
+ if (value instanceof Set) {
157
+ return StrongSetSchema;
158
+ }
159
+
160
+ if (value instanceof WeakMap) {
161
+ return z.instanceof(WeakMap);
162
+ }
163
+
164
+ if (value instanceof WeakSet) {
165
+ return z.instanceof(WeakSet);
166
+ }
167
+
168
+ if (value instanceof Error) {
169
+ return z.instanceof(Error);
170
+ }
171
+
172
+ if (isPromiseLike(value)) {
173
+ return WrappedPromiseLikeSchema;
174
+ }
175
+
176
+ // Handle arrays
177
+ if (Array.isArray(value)) {
178
+ // For arrays, we need to preserve undefined values while allowing
179
+ // other elements to use the original literalPrimitives setting
180
+ const filteredValue = value; // Always process all elements
181
+
182
+ if (filteredValue.length === 0) {
183
+ // For empty arrays, use z.tuple() if literalTuples is enabled
184
+ if (literalTuples) {
185
+ return z.tuple([]);
186
+ }
187
+ return z.array(z.never());
188
+ }
189
+
190
+ const elementSchemas = filteredValue.map((item) => {
191
+ // Use literal mode for undefined values to preserve them exactly,
192
+ // but use the original setting for other values
193
+ const itemLiteralPrimitives =
194
+ item === undefined ? true : literalPrimitives;
195
+
196
+ return valueToSchema(
197
+ item,
198
+ {
199
+ ...options,
200
+ _currentDepth: _currentDepth + 1,
201
+ literalPrimitives: itemLiteralPrimitives,
202
+ },
203
+ visited,
204
+ );
205
+ });
206
+
207
+ // Use z.tuple() if literalTuples is enabled
208
+ if (literalTuples) {
209
+ return z.tuple(elementSchemas as [z.ZodType, ...z.ZodType[]]);
210
+ }
211
+
212
+ if (!noMixedArrays) {
213
+ // Helper function to generate structural keys for schemas
214
+ const getSchemaKey = <T extends z.core.SomeType | z.ZodType>(
215
+ zodType: T,
216
+ ): string => {
217
+ const schema = zodType as z.ZodType;
218
+ if (isZodType(schema, 'literal')) {
219
+ return `${schema.constructor.name}:${String(schema.def.values)}`;
220
+ }
221
+
222
+ if (isZodType(schema, 'array')) {
223
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
224
+ const elementKey = getSchemaKey((schema.def as any).element);
225
+ return `ZodArray<${elementKey}>`;
226
+ }
227
+
228
+ if (isZodType(schema, 'object')) {
229
+ // For objects, create a key based on the property keys and their types
230
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
231
+ const shape = (schema.def as any).shape as Record<
232
+ string,
233
+ z.ZodType
234
+ >;
235
+ const shapeKeys = Object.keys(shape)
236
+ .sort()
237
+ .map((key) => {
238
+ const propSchema = shape[key]!;
239
+ return `${key}:${getSchemaKey(propSchema)}`;
240
+ });
241
+ return `ZodObject<{${shapeKeys.join(',')}}>`;
242
+ }
243
+
244
+ if (isZodType(schema, 'union')) {
245
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
246
+ const optionKeys = ((schema.def as any).options as z.ZodType[])
247
+ .map((option) => getSchemaKey(option))
248
+ .sort();
249
+ return `ZodUnion<[${optionKeys.join(',')}]>`;
250
+ }
251
+
252
+ // For other types, use the constructor name
253
+ return schema.constructor.name;
254
+ };
255
+
256
+ const seenSchemaKeys = new Set<string>();
257
+ const uniqueSchemas: z.ZodType[] = [];
258
+
259
+ for (const schema of elementSchemas) {
260
+ const schemaKey = getSchemaKey(schema);
261
+
262
+ if (!seenSchemaKeys.has(schemaKey)) {
263
+ seenSchemaKeys.add(schemaKey);
264
+ uniqueSchemas.push(schema);
265
+ }
266
+ }
267
+
268
+ if (uniqueSchemas.length === 1) {
269
+ return z.array(uniqueSchemas[0]!);
270
+ } else {
271
+ return z.array(
272
+ z.union(uniqueSchemas as [z.ZodType, z.ZodType, ...z.ZodType[]]),
273
+ );
274
+ }
275
+ } else {
276
+ // Use the first element's schema for all elements
277
+ return z.array(elementSchemas[0]!);
278
+ }
279
+ }
280
+
281
+ // Handle plain objects
282
+ if (isNonNullObject(value)) {
283
+ const schemaShape: Record<string, z.ZodType<any>> = {};
284
+ const undefinedKeys: string[] = [];
285
+
286
+ for (const [key, val] of Object.entries(value)) {
287
+ if (isString(key)) {
288
+ // Skip undefined values unless we're in literalPrimitives mode
289
+ // This prevents objects with only undefined values from matching any object
290
+ if (val === undefined && !literalPrimitives) {
291
+ continue;
292
+ }
293
+
294
+ if (val === undefined && literalPrimitives) {
295
+ // Track keys that should have undefined values
296
+ undefinedKeys.push(key);
297
+ schemaShape[key] = z.undefined();
298
+ } else {
299
+ schemaShape[key] = valueToSchema(
300
+ val,
301
+ {
302
+ ...options,
303
+ _currentDepth: _currentDepth + 1,
304
+ },
305
+ visited,
306
+ );
307
+ }
308
+ }
309
+ }
310
+
311
+ // Create the base object schema
312
+ const baseSchema = strict
313
+ ? z.strictObject(schemaShape)
314
+ : z.looseObject(schemaShape);
315
+
316
+ // If we have undefined keys in literalPrimitives mode, add validation to ensure they exist
317
+ if (undefinedKeys.length > 0 && literalPrimitives) {
318
+ return baseSchema.superRefine((data, ctx) => {
319
+ if (typeof data !== 'object' || data === null) {
320
+ ctx.addIssue({
321
+ code: z.ZodIssueCode.custom,
322
+ message: 'Expected an object',
323
+ });
324
+ return;
325
+ }
326
+
327
+ const obj = data as Record<string, unknown>;
328
+ for (const key of undefinedKeys) {
329
+ if (!Object.hasOwn(obj, key)) {
330
+ ctx.addIssue({
331
+ code: z.ZodIssueCode.custom,
332
+ message: `Expected property "${key}" to exist with value undefined`,
333
+ path: [key],
334
+ });
335
+ }
336
+ }
337
+ });
338
+ }
339
+
340
+ // Check if this is an empty object and literalEmptyObjects is enabled
341
+ if (Object.keys(schemaShape).length === 0 && literalEmptyObjects) {
342
+ // Create a schema that only matches empty objects
343
+ return z.custom<Record<string, never>>(
344
+ (val) => isObject(val) && Object.keys(val).length === 0,
345
+ {
346
+ message: 'Expected an empty object with no own properties',
347
+ },
348
+ );
349
+ }
350
+
351
+ return baseSchema;
352
+ }
353
+
354
+ // Handle other object types (ArrayBuffer, etc.)
355
+ return z.custom<object>(
356
+ (val) => typeof val === 'object' && val !== null,
357
+ { message: 'Expected an object' },
358
+ );
359
+ } finally {
360
+ visited.delete(value);
361
+ }
362
+ }
363
+
364
+ // Fallback for unknown types
365
+ return z.unknown();
366
+ };
367
+
368
+ /**
369
+ * Options for {@link valueToSchema}
370
+ */
371
+ export interface ValueToSchemaOptions {
372
+ /**
373
+ * Current depth (internal)
374
+ *
375
+ * @internal
376
+ */
377
+ _currentDepth?: number;
378
+
379
+ /**
380
+ * If `true`, treat empty objects `{}` as literal empty objects that only
381
+ * match objects with zero own properties
382
+ *
383
+ * @defaultValue false
384
+ */
385
+ literalEmptyObjects?: boolean;
386
+
387
+ /**
388
+ * If `true`, use literal schema for primitive values instead of type schema
389
+ *
390
+ * @defaultValue false
391
+ */
392
+ literalPrimitives?: boolean;
393
+
394
+ /**
395
+ * If `true`, treat `RegExp` literals as `RegExp` literals; otherwise treat as
396
+ * strings and attempt match
397
+ *
398
+ * @defaultValue false
399
+ */
400
+ literalRegExp?: boolean;
401
+
402
+ /**
403
+ * If `true`, treat arrays as tuples wherever possible.
404
+ *
405
+ * Implies `false` for {@link noMixedArrays}.
406
+ *
407
+ * @defaultValue false
408
+ */
409
+ literalTuples?: boolean;
410
+
411
+ /**
412
+ * Maximum nesting depth to prevent stack overflow
413
+ *
414
+ * @defaultValue 10
415
+ */
416
+ maxDepth?: number;
417
+
418
+ /**
419
+ * Whether to allow mixed types in arrays
420
+ *
421
+ * If {@link literalTuples} is `true`, this option is ignored and treated as
422
+ * `false`.
423
+ *
424
+ * @defaultValue false
425
+ */
426
+ noMixedArrays?: boolean;
427
+
428
+ /**
429
+ * If `true`, will disallow unknown properties in parsed objects
430
+ *
431
+ * @defaultValue false
432
+ */
433
+ strict?: boolean;
434
+ }
435
+
436
+ /**
437
+ * Predefined options for {@link valueToSchema} optimized for object satisfaction
438
+ * checks.
439
+ *
440
+ * Uses literal primitives and tuples for exact matching while allowing extra
441
+ * properties.
442
+ */
443
+ export const valueToSchemaOptionsForSatisfies = Object.freeze({
444
+ literalEmptyObjects: true,
445
+ literalPrimitives: true,
446
+ literalRegExp: false,
447
+ literalTuples: true,
448
+ strict: false,
449
+ } as const) satisfies ValueToSchemaOptions;
450
+
451
+ /**
452
+ * Predefined options for {@link valueToSchema} optimized for deep equality
453
+ * checks.
454
+ *
455
+ * Uses literal primitives, regexp, and tuples with strict validation for exact
456
+ * matching.
457
+ */
458
+ export const valueToSchemaOptionsForDeepEqual = Object.freeze({
459
+ literalEmptyObjects: true,
460
+ literalPrimitives: true,
461
+ literalRegExp: true,
462
+ literalTuples: true,
463
+ strict: true,
464
+ } as const) satisfies ValueToSchemaOptions;
@@ -1,93 +0,0 @@
1
- /**
2
- * Contains the main API types
3
- *
4
- * @packageDocumentation
5
- */
6
- import type { TupleToUnion, UnionToIntersection } from 'type-fest';
7
- import type { AnyAsyncAssertion, AnyAsyncAssertions, AnySyncAssertion, AnySyncAssertions, BuiltinAsyncAssertions, BuiltinSyncAssertions } from './assertion/assertion-types.js';
8
- import type { createAssertion, createAsyncAssertion } from './assertion/create.js';
9
- import { type InferredExpectSlots, type MutableOrReadonly, type UseFn } from './types.js';
10
- /**
11
- * Base set of properties included in both {@link Expect} and {@link ExpectAsync}.
12
- */
13
- export interface BaseExpect {
14
- /**
15
- * Creates a new synchronous assertion.
16
- */
17
- createAssertion: typeof createAssertion;
18
- /**
19
- * Creates a new asynchronous assertion.
20
- */
21
- createAsyncAssertion: typeof createAsyncAssertion;
22
- /**
23
- * Fails immediately with optional `reason`.
24
- *
25
- * @param reason Reason for failure
26
- * @throws {AssertionError}
27
- */
28
- fail(this: void, reason?: string): never;
29
- }
30
- /**
31
- * The main synchronous assertion function.
32
- *
33
- * Contains properties in {@link ExpectSyncProps}.
34
- *
35
- * @template T All synchronous assertions available
36
- * @template U All asynchronous assertions available; for use in
37
- * {@link ExpectSyncProps.use}
38
- * @useDeclaredType
39
- * @see {@link expect}
40
- */
41
- export type Expect<T extends AnySyncAssertions = BuiltinSyncAssertions, U extends AnyAsyncAssertions = BuiltinAsyncAssertions> = ExpectFunction<T> & ExpectSyncProps<T, U>;
42
- /**
43
- * The main asynchronous assertion function.
44
- *
45
- * Contains properties in {@link ExpectSyncProps}.
46
- *
47
- * @useDeclaredType
48
- * @see {@link expectAsync}
49
- */
50
- export type ExpectAsync<T extends AnyAsyncAssertions = BuiltinAsyncAssertions, U extends AnySyncAssertions = BuiltinSyncAssertions> = ExpectAsyncFunction<T> & ExpectAsyncProps<T, U>;
51
- /**
52
- * All function overloads for `expectAsync()`; part of {@link ExpectAsync}.
53
- */
54
- export type ExpectAsyncFunction<T extends AnyAsyncAssertions = BuiltinAsyncAssertions> = UnionToIntersection<TupleToUnion<{
55
- [K in keyof T]: T[K] extends AnyAsyncAssertion ? (...args: MutableOrReadonly<InferredExpectSlots<T[K]['parts']>>) => Promise<void> : never;
56
- }>>;
57
- /**
58
- * Properties available on `expectAsync()`; part of {@link ExpectAsync}.
59
- */
60
- export interface ExpectAsyncProps<T extends AnyAsyncAssertions, U extends AnySyncAssertions> extends BaseExpect {
61
- /**
62
- * Tuple of all assertions available in this `expect()`.
63
- */
64
- assertions: T;
65
- /**
66
- * Function to add more assertions to this `expect()`, returning a new
67
- * `expect()` and `expectAsync()` pair with the combined assertions.
68
- */
69
- use: UseFn<U, T>;
70
- }
71
- /**
72
- * All function overloads for `expect()`; part of {@link Expect}.
73
- *
74
- * @useDeclaredType
75
- */
76
- export type ExpectFunction<T extends AnySyncAssertions = BuiltinSyncAssertions> = UnionToIntersection<TupleToUnion<{
77
- [K in keyof T]: T[K] extends AnySyncAssertion ? (...args: MutableOrReadonly<InferredExpectSlots<T[K]['parts']>>) => void : never;
78
- }>>;
79
- /**
80
- * Properties for `expect()`; part of {@link Expect}.
81
- */
82
- export interface ExpectSyncProps<T extends AnySyncAssertions, U extends AnyAsyncAssertions> extends BaseExpect {
83
- /**
84
- * Tuple of all assertions available in this `expect()`.
85
- */
86
- assertions: T;
87
- /**
88
- * Function to add more assertions to this `expect()`, returning a new
89
- * `expect()` and `expectAsync()` pair with the combined assertions.
90
- */
91
- use: UseFn<T, U>;
92
- }
93
- //# sourceMappingURL=api.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEnE,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACrB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACX,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC;;OAEG;IACH,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAClD;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1C;AAED;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,MAAM,CAChB,CAAC,SAAS,iBAAiB,GAAG,qBAAqB,EACnD,CAAC,SAAS,kBAAkB,GAAG,sBAAsB,IACnD,cAAc,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE9C;;;;;;;GAOG;AAEH,MAAM,MAAM,WAAW,CACrB,CAAC,SAAS,kBAAkB,GAAG,sBAAsB,EACrD,CAAC,SAAS,iBAAiB,GAAG,qBAAqB,IACjD,mBAAmB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEpD;;GAEG;AAEH,MAAM,MAAM,mBAAmB,CAC7B,CAAC,SAAS,kBAAkB,GAAG,sBAAsB,IACnD,mBAAmB,CACrB,YAAY,CAAC;KACV,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,iBAAiB,GAC1C,CACE,GAAG,IAAI,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAC3D,OAAO,CAAC,IAAI,CAAC,GAClB,KAAK;CACV,CAAC,CACH,CAAC;AAEF;;GAEG;AAEH,MAAM,WAAW,gBAAgB,CAC/B,CAAC,SAAS,kBAAkB,EAC5B,CAAC,SAAS,iBAAiB,CAC3B,SAAQ,UAAU;IAClB;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC;IACd;;;OAGG;IACH,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,CACxB,CAAC,SAAS,iBAAiB,GAAG,qBAAqB,IACjD,mBAAmB,CACrB,YAAY,CAAC;KACV,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,gBAAgB,GACzC,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,GACxE,KAAK;CACV,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,eAAe,CAC9B,CAAC,SAAS,iBAAiB,EAC3B,CAAC,SAAS,kBAAkB,CAC5B,SAAQ,UAAU;IAClB;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC;IAEd;;;OAGG;IACH,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAClB"}
@@ -1,8 +0,0 @@
1
- "use strict";
2
- /**
3
- * Contains the main API types
4
- *
5
- * @packageDocumentation
6
- */
7
- Object.defineProperty(exports, "__esModule", { value: true });
8
- //# sourceMappingURL=api.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":";AAAA;;;;GAIG"}
package/dist/esm/api.d.ts DELETED
@@ -1,93 +0,0 @@
1
- /**
2
- * Contains the main API types
3
- *
4
- * @packageDocumentation
5
- */
6
- import type { TupleToUnion, UnionToIntersection } from 'type-fest';
7
- import type { AnyAsyncAssertion, AnyAsyncAssertions, AnySyncAssertion, AnySyncAssertions, BuiltinAsyncAssertions, BuiltinSyncAssertions } from './assertion/assertion-types.js';
8
- import type { createAssertion, createAsyncAssertion } from './assertion/create.js';
9
- import { type InferredExpectSlots, type MutableOrReadonly, type UseFn } from './types.js';
10
- /**
11
- * Base set of properties included in both {@link Expect} and {@link ExpectAsync}.
12
- */
13
- export interface BaseExpect {
14
- /**
15
- * Creates a new synchronous assertion.
16
- */
17
- createAssertion: typeof createAssertion;
18
- /**
19
- * Creates a new asynchronous assertion.
20
- */
21
- createAsyncAssertion: typeof createAsyncAssertion;
22
- /**
23
- * Fails immediately with optional `reason`.
24
- *
25
- * @param reason Reason for failure
26
- * @throws {AssertionError}
27
- */
28
- fail(this: void, reason?: string): never;
29
- }
30
- /**
31
- * The main synchronous assertion function.
32
- *
33
- * Contains properties in {@link ExpectSyncProps}.
34
- *
35
- * @template T All synchronous assertions available
36
- * @template U All asynchronous assertions available; for use in
37
- * {@link ExpectSyncProps.use}
38
- * @useDeclaredType
39
- * @see {@link expect}
40
- */
41
- export type Expect<T extends AnySyncAssertions = BuiltinSyncAssertions, U extends AnyAsyncAssertions = BuiltinAsyncAssertions> = ExpectFunction<T> & ExpectSyncProps<T, U>;
42
- /**
43
- * The main asynchronous assertion function.
44
- *
45
- * Contains properties in {@link ExpectSyncProps}.
46
- *
47
- * @useDeclaredType
48
- * @see {@link expectAsync}
49
- */
50
- export type ExpectAsync<T extends AnyAsyncAssertions = BuiltinAsyncAssertions, U extends AnySyncAssertions = BuiltinSyncAssertions> = ExpectAsyncFunction<T> & ExpectAsyncProps<T, U>;
51
- /**
52
- * All function overloads for `expectAsync()`; part of {@link ExpectAsync}.
53
- */
54
- export type ExpectAsyncFunction<T extends AnyAsyncAssertions = BuiltinAsyncAssertions> = UnionToIntersection<TupleToUnion<{
55
- [K in keyof T]: T[K] extends AnyAsyncAssertion ? (...args: MutableOrReadonly<InferredExpectSlots<T[K]['parts']>>) => Promise<void> : never;
56
- }>>;
57
- /**
58
- * Properties available on `expectAsync()`; part of {@link ExpectAsync}.
59
- */
60
- export interface ExpectAsyncProps<T extends AnyAsyncAssertions, U extends AnySyncAssertions> extends BaseExpect {
61
- /**
62
- * Tuple of all assertions available in this `expect()`.
63
- */
64
- assertions: T;
65
- /**
66
- * Function to add more assertions to this `expect()`, returning a new
67
- * `expect()` and `expectAsync()` pair with the combined assertions.
68
- */
69
- use: UseFn<U, T>;
70
- }
71
- /**
72
- * All function overloads for `expect()`; part of {@link Expect}.
73
- *
74
- * @useDeclaredType
75
- */
76
- export type ExpectFunction<T extends AnySyncAssertions = BuiltinSyncAssertions> = UnionToIntersection<TupleToUnion<{
77
- [K in keyof T]: T[K] extends AnySyncAssertion ? (...args: MutableOrReadonly<InferredExpectSlots<T[K]['parts']>>) => void : never;
78
- }>>;
79
- /**
80
- * Properties for `expect()`; part of {@link Expect}.
81
- */
82
- export interface ExpectSyncProps<T extends AnySyncAssertions, U extends AnyAsyncAssertions> extends BaseExpect {
83
- /**
84
- * Tuple of all assertions available in this `expect()`.
85
- */
86
- assertions: T;
87
- /**
88
- * Function to add more assertions to this `expect()`, returning a new
89
- * `expect()` and `expectAsync()` pair with the combined assertions.
90
- */
91
- use: UseFn<T, U>;
92
- }
93
- //# sourceMappingURL=api.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEnE,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,sBAAsB,EACtB,qBAAqB,EACtB,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EACV,eAAe,EACf,oBAAoB,EACrB,MAAM,uBAAuB,CAAC;AAI/B,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,KAAK,EACX,MAAM,YAAY,CAAC;AAEpB;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB;;OAEG;IACH,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC;;OAEG;IACH,oBAAoB,EAAE,OAAO,oBAAoB,CAAC;IAClD;;;;;OAKG;IACH,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC1C;AAED;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,MAAM,CAChB,CAAC,SAAS,iBAAiB,GAAG,qBAAqB,EACnD,CAAC,SAAS,kBAAkB,GAAG,sBAAsB,IACnD,cAAc,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE9C;;;;;;;GAOG;AAEH,MAAM,MAAM,WAAW,CACrB,CAAC,SAAS,kBAAkB,GAAG,sBAAsB,EACrD,CAAC,SAAS,iBAAiB,GAAG,qBAAqB,IACjD,mBAAmB,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAEpD;;GAEG;AAEH,MAAM,MAAM,mBAAmB,CAC7B,CAAC,SAAS,kBAAkB,GAAG,sBAAsB,IACnD,mBAAmB,CACrB,YAAY,CAAC;KACV,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,iBAAiB,GAC1C,CACE,GAAG,IAAI,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAC3D,OAAO,CAAC,IAAI,CAAC,GAClB,KAAK;CACV,CAAC,CACH,CAAC;AAEF;;GAEG;AAEH,MAAM,WAAW,gBAAgB,CAC/B,CAAC,SAAS,kBAAkB,EAC5B,CAAC,SAAS,iBAAiB,CAC3B,SAAQ,UAAU;IAClB;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC;IACd;;;OAGG;IACH,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,MAAM,cAAc,CACxB,CAAC,SAAS,iBAAiB,GAAG,qBAAqB,IACjD,mBAAmB,CACrB,YAAY,CAAC;KACV,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,gBAAgB,GACzC,CAAC,GAAG,IAAI,EAAE,iBAAiB,CAAC,mBAAmB,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,IAAI,GACxE,KAAK;CACV,CAAC,CACH,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,eAAe,CAC9B,CAAC,SAAS,iBAAiB,EAC3B,CAAC,SAAS,kBAAkB,CAC5B,SAAQ,UAAU;IAClB;;OAEG;IACH,UAAU,EAAE,CAAC,CAAC;IAEd;;;OAGG;IACH,GAAG,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;CAClB"}
package/dist/esm/api.js DELETED
@@ -1,7 +0,0 @@
1
- /**
2
- * Contains the main API types
3
- *
4
- * @packageDocumentation
5
- */
6
- export {};
7
- //# sourceMappingURL=api.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/api.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}