@zod-utils/core 1.2.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -77,6 +77,63 @@ type Discriminator<TSchema extends z$1.ZodType, TDiscriminatorKey extends Discri
77
77
  key: TDiscriminatorKey;
78
78
  value: TDiscriminatorValue;
79
79
  };
80
+ type Primitive = string | number | boolean | null | undefined | symbol | bigint;
81
+ type NonZeroDigit = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9;
82
+ type PathsHint<T, Prefix extends string = ''> = T extends Primitive ? never : T extends (infer E)[] ? (Prefix extends '' ? never : Prefix) | `${Prefix}.0` | PathsHint<E, `${Prefix}.0`> : T extends object ? {
83
+ [K in keyof T & string]: (Prefix extends '' ? K : `${Prefix}.${K}`) | PathsHint<T[K], Prefix extends '' ? K : `${Prefix}.${K}`>;
84
+ }[keyof T & string] : never;
85
+ type NonZeroIndex = `${NonZeroDigit}` | `${NonZeroDigit}${number}`;
86
+ type PathsLoose<T, Prefix extends string = ''> = T extends Primitive ? never : T extends (infer E)[] ? (Prefix extends '' ? never : Prefix) | `${Prefix}.${NonZeroIndex}` | PathsLoose<E, `${Prefix}.${NonZeroIndex}`> : T extends object ? {
87
+ [K in keyof T & string]: (Prefix extends '' ? K : `${Prefix}.${K}`) | PathsLoose<T[K], Prefix extends '' ? K : `${Prefix}.${K}`>;
88
+ }[keyof T & string] : never;
89
+ /**
90
+ * Generates all valid dot-notation paths for a given type.
91
+ * Supports nested objects and arrays with numeric indices.
92
+ *
93
+ * @example
94
+ * ```typescript
95
+ * type User = { name: string; address: { city: string } };
96
+ * type UserPaths = Paths<User>;
97
+ * // "name" | "address" | "address.city"
98
+ * ```
99
+ */
100
+ type Paths<T> = PathsHint<T> | PathsLoose<T>;
101
+ /**
102
+ * Extracts fields common to all variants in a union type.
103
+ *
104
+ * Uses `Pick<T, keyof T>` to normalize union types by extracting only
105
+ * the keys that exist across all union members.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * type A = { mode: 'create'; name: string };
110
+ * type B = { mode: 'edit'; id: number };
111
+ * type Common = CommonFields<A | B>;
112
+ * // { mode: 'create' | 'edit' }
113
+ * ```
114
+ */
115
+ type CommonFields<T> = Pick<T, keyof T>;
116
+ /**
117
+ * Generates valid dot-notation paths for fields in a discriminated union variant.
118
+ *
119
+ * Given a schema and discriminator value, extracts all possible field paths
120
+ * (including nested paths) for that specific variant.
121
+ *
122
+ * @example
123
+ * ```typescript
124
+ * const schema = z.discriminatedUnion('mode', [
125
+ * z.object({ mode: z.literal('create'), name: z.string() }),
126
+ * z.object({ mode: z.literal('edit'), id: z.number() }),
127
+ * ]);
128
+ *
129
+ * type CreatePaths = ValidPaths<typeof schema, 'mode', 'create'>;
130
+ * // "mode" | "name"
131
+ *
132
+ * type EditPaths = ValidPaths<typeof schema, 'mode', 'edit'>;
133
+ * // "mode" | "id"
134
+ * ```
135
+ */
136
+ type ValidPaths<TSchema extends z$1.ZodType, TDiscriminatorKey extends DiscriminatorKey<TSchema>, TDiscriminatorValue extends DiscriminatorValue<TSchema, TDiscriminatorKey>> = Paths<CommonFields<Extract<Required<z$1.input<TSchema>>, TDiscriminatorKey extends never ? z$1.input<TSchema> : TDiscriminatorValue extends never ? z$1.input<TSchema> : Simplify<Record<TDiscriminatorKey, TDiscriminatorValue>>>>>;
80
137
 
81
138
  /**
82
139
  * Extracts the default value from a Zod field, recursively unwrapping optional, nullable, and union layers.
@@ -213,11 +270,200 @@ declare function getSchemaDefaults<TSchema extends z.ZodType, TDiscriminatorKey
213
270
  discriminator?: Discriminator<TSchema, TDiscriminatorKey, TDiscriminatorValue>;
214
271
  }): Simplify<Partial<z.input<TSchema>>>;
215
272
 
216
- declare function extractFieldFromSchema<TSchema extends z$1.ZodType, TName extends keyof Extract<Required<z$1.input<TSchema>>, Record<TDiscriminatorKey, TDiscriminatorValue>>, TDiscriminatorKey extends DiscriminatorKey<TSchema>, TDiscriminatorValue extends DiscriminatorValue<TSchema, TDiscriminatorKey>>({ schema, fieldName, discriminator, }: {
273
+ /**
274
+ * Recursively extracts the exact schema type from a discriminated union based on the discriminator value.
275
+ *
276
+ * This advanced TypeScript utility type walks through a union's options tuple at compile-time,
277
+ * checking each schema against the discriminator field and value, and returns the exact matching
278
+ * schema type (not a union of all options).
279
+ *
280
+ * **How it works:**
281
+ * 1. Extracts the options tuple from the union using `infer Options`
282
+ * 2. Destructure into head (`First`) and tail (`Rest`) using tuple pattern matching
283
+ * 3. Checks if `First` is a ZodObject with the matching discriminator field and value
284
+ * 4. If match found, returns `First` (the exact schema type)
285
+ * 5. If no match, recursively processes `Rest` until a match is found or list is exhausted
286
+ *
287
+ * **Type narrowing magic:**
288
+ * - Input: `z.discriminatedUnion('type', [SchemaA, SchemaB, SchemaC])`
289
+ * - Discriminator value: `'a'` (matches SchemaA)
290
+ * - Output: `SchemaA` (exact type, not `SchemaA | SchemaB | SchemaC`)
291
+ *
292
+ * @template TSchema - The ZodUnion or ZodDiscriminatedUnion type
293
+ * @template TDiscriminatorKey - The discriminator field name (e.g., "type", "mode")
294
+ * @template TDiscriminatorValue - The specific discriminator value (e.g., "create", "edit")
295
+ * @returns The exact matching schema type, or `never` if no match found
296
+ *
297
+ * @example
298
+ * ```typescript
299
+ * const schema = z.discriminatedUnion('mode', [
300
+ * z.object({ mode: z.literal('create'), name: z.string() }),
301
+ * z.object({ mode: z.literal('edit'), id: z.number() }),
302
+ * ]);
303
+ *
304
+ * // Exact type: z.object({ mode: z.literal('create'), name: z.string() })
305
+ * type CreateSchema = ExtractZodUnionMember<typeof schema, 'mode', 'create'>;
306
+ * ```
307
+ */
308
+ type ExtractZodUnionMember<TSchema extends z$1.ZodUnion | z$1.ZodDiscriminatedUnion, TDiscriminatorKey extends DiscriminatorKey<TSchema>, TDiscriminatorValue extends z$1.input<TSchema>[TDiscriminatorKey] & util.Literal> = TSchema extends z$1.ZodUnion<infer Options> ? Options extends readonly [
309
+ infer First extends z$1.ZodTypeAny,
310
+ ...infer Rest extends z$1.ZodTypeAny[]
311
+ ] ? First extends z$1.ZodObject<infer Shape> ? TDiscriminatorKey extends keyof Shape ? Shape[TDiscriminatorKey] extends z$1.ZodLiteral<TDiscriminatorValue> | z$1.ZodDefault<z$1.ZodLiteral<TDiscriminatorValue>> ? First : Rest extends [] ? never : TDiscriminatorValue extends $InferUnionInput<Rest[number]>[TDiscriminatorKey] ? ExtractZodUnionMember<z$1.ZodUnion<Rest>, TDiscriminatorKey, TDiscriminatorValue> : never : Rest extends [] ? never : TDiscriminatorValue extends $InferUnionInput<Rest[number]>[TDiscriminatorKey] ? ExtractZodUnionMember<z$1.ZodUnion<Rest>, TDiscriminatorKey, TDiscriminatorValue> : never : never : never : never;
312
+ /**
313
+ * Extracts a specific schema option from a discriminated union based on the discriminator field value.
314
+ *
315
+ * This function finds and returns the **exact matching schema** from a `ZodDiscriminatedUnion` by
316
+ * comparing the discriminator field value. It's used internally by {@link getSchemaDefaults} to
317
+ * extract defaults from the correct schema variant in a discriminated union.
318
+ *
319
+ * **Key feature:** Returns the **exact schema type**, not a union of all options, thanks to the
320
+ * {@link ExtractZodUnionMember} recursive type utility. This enables precise type narrowing at
321
+ * compile-time based on the discriminator value.
322
+ *
323
+ * **How it works:**
324
+ * 1. Iterates through all options in the discriminated union at runtime
325
+ * 2. For each option, validates it's a ZodObject and checks if the discriminator field matches
326
+ * 3. Returns the first matching schema with its exact type narrowed at compile-time
327
+ * 4. Returns `undefined` if no match found or if option is not a ZodObject
328
+ *
329
+ * @template TSchema - The ZodUnion or ZodDiscriminatedUnion schema type
330
+ * @template TDiscriminatorKey - The discriminator field name (string key of the inferred union type)
331
+ * @template TDiscriminatorValue - The specific discriminator value to match (literal type)
332
+ * @param params - Parameters object
333
+ * @param params.schema - The discriminated union schema to search
334
+ * @param params.discriminatorKey - The discriminator field name (e.g., "mode", "type")
335
+ * @param params.discriminatorValue - The discriminator value to match (e.g., "create", "edit")
336
+ * @returns The exact matching schema option (with precise type), or `undefined` if not found
337
+ *
338
+ * @example
339
+ * Basic discriminated union - create/edit mode
340
+ * ```typescript
341
+ * const userSchema = z.discriminatedUnion('mode', [
342
+ * z.object({
343
+ * mode: z.literal('create'),
344
+ * name: z.string(),
345
+ * age: z.number().optional(),
346
+ * }),
347
+ * z.object({
348
+ * mode: z.literal('edit'),
349
+ * id: z.number(),
350
+ * name: z.string().optional(),
351
+ * }),
352
+ * ]);
353
+ *
354
+ * // Extract the "create" schema
355
+ * const createSchema = extractDiscriminatedSchema({
356
+ * schema: userSchema,
357
+ * discriminatorKey: 'mode',
358
+ * discriminatorValue: 'create',
359
+ * });
360
+ * // Result: z.object({ mode: z.literal('create'), name: z.string(), age: z.number().optional() })
361
+ *
362
+ * // Extract the "edit" schema
363
+ * const editSchema = extractDiscriminatedSchema({
364
+ * schema: userSchema,
365
+ * discriminatorKey: 'mode',
366
+ * discriminatorValue: 'edit',
367
+ * });
368
+ * // Result: z.object({ mode: z.literal('edit'), id: z.number(), name: z.string().optional() })
369
+ * ```
370
+ *
371
+ * @example
372
+ * Type-based discrimination
373
+ * ```typescript
374
+ * const eventSchema = z.discriminatedUnion('type', [
375
+ * z.object({ type: z.literal('click'), x: z.number(), y: z.number() }),
376
+ * z.object({ type: z.literal('keypress'), key: z.string() }),
377
+ * ]);
378
+ *
379
+ * const clickSchema = extractDiscriminatedSchema({
380
+ * schema: eventSchema,
381
+ * discriminatorKey: 'type',
382
+ * discriminatorValue: 'click',
383
+ * });
384
+ * // Result: z.object({ type: z.literal('click'), x: z.number(), y: z.number() })
385
+ * ```
386
+ *
387
+ * @example
388
+ * Invalid discriminator value
389
+ * ```typescript
390
+ * const schema = z.discriminatedUnion('mode', [
391
+ * z.object({ mode: z.literal('create'), name: z.string() }),
392
+ * ]);
393
+ *
394
+ * const result = extractDiscriminatedSchema({
395
+ * schema,
396
+ * discriminatorKey: 'mode',
397
+ * discriminatorValue: 'invalid', // doesn't match any option
398
+ * });
399
+ * // Result: undefined
400
+ * ```
401
+ *
402
+ * @example
403
+ * Type narrowing demonstration
404
+ * ```typescript
405
+ * const schema = z.discriminatedUnion('mode', [
406
+ * z.object({ mode: z.literal('create'), name: z.string(), age: z.number() }),
407
+ * z.object({ mode: z.literal('edit'), id: z.number(), bio: z.string() }),
408
+ * ]);
409
+ *
410
+ * const createSchema = extractDiscriminatedSchema({
411
+ * schema,
412
+ * discriminatorKey: 'mode',
413
+ * discriminatorValue: 'create',
414
+ * });
415
+ *
416
+ * // Type is EXACTLY: z.object({ mode: z.literal('create'), name: z.string(), age: z.number() })
417
+ * // NOT: z.object({ mode: ..., ... }) | z.object({ mode: ..., ... }) | undefined
418
+ *
419
+ * if (createSchema) {
420
+ * createSchema.shape.age; // ✅ TypeScript knows 'age' exists
421
+ * createSchema.shape.name; // ✅ TypeScript knows 'name' exists
422
+ * // createSchema.shape.id; // ❌ TypeScript error: 'id' doesn't exist on 'create' schema
423
+ * }
424
+ * ```
425
+ *
426
+ * @see {@link getSchemaDefaults} for usage with discriminated unions
427
+ * @see {@link ExtractZodUnionMember} for the type-level extraction logic
428
+ * @since 0.6.0
429
+ */
430
+ declare const extractDiscriminatedSchema: <TSchema extends z$1.ZodType, TDiscriminatorKey extends DiscriminatorKey<TSchema>, TDiscriminatorValue extends DiscriminatorValue<TSchema, TDiscriminatorKey>, ReturnType extends TSchema extends z$1.ZodDiscriminatedUnion ? ExtractZodUnionMember<TSchema, TDiscriminatorKey, TDiscriminatorValue> : never>({ schema, key, value, }: {
431
+ schema: TSchema;
432
+ } & Discriminator<TSchema, TDiscriminatorKey, TDiscriminatorValue>) => ReturnType;
433
+
434
+ type Split<S extends string> = S extends `${infer Head}.${infer Tail}` ? [Head, ...Split<Tail>] : [S];
435
+ type IsNumeric<S extends string> = S extends `${number}` ? true : false;
436
+ type Unwrap<T> = T extends z$1.ZodOptional<infer U> ? Unwrap<U> : T extends z$1.ZodNullable<infer U> ? Unwrap<U> : T extends z$1.ZodDefault<infer U> ? Unwrap<U> : T;
437
+ type NavigateZod<T, Path extends string[]> = Path extends [
438
+ infer First extends string,
439
+ ...infer Rest extends string[]
440
+ ] ? Unwrap<T> extends z$1.ZodObject<infer Shape> ? First extends keyof Shape ? Rest extends [] ? Shape[First] : NavigateZod<Shape[First], Rest> : never : Unwrap<T> extends z$1.ZodArray<infer Element> ? IsNumeric<First> extends true ? Rest extends [] ? Element : NavigateZod<Element, Rest> : never : never : T;
441
+ type ExtractZodByPath<Schema, Path extends string> = NavigateZod<Schema, Split<Path>>;
442
+ declare function extractFieldFromSchema<TSchema extends z$1.ZodType, TPath extends ValidPaths<TSchema, TDiscriminatorKey, TDiscriminatorValue>, TDiscriminatorKey extends DiscriminatorKey<TSchema>, TDiscriminatorValue extends DiscriminatorValue<TSchema, TDiscriminatorKey>>({ schema, name, discriminator, }: {
217
443
  schema: TSchema;
218
- fieldName: TName;
444
+ name: TPath;
219
445
  discriminator?: Discriminator<TSchema, TDiscriminatorKey, TDiscriminatorValue>;
220
- }): z$1.ZodType<unknown, unknown, z$1.core.$ZodTypeInternals<unknown, unknown>> | undefined;
446
+ }): (ExtractZodByPath<TSchema, TPath> & z$1.ZodType) | undefined;
447
+ /**
448
+ * Extends a Zod field with a transformation while preserving its metadata.
449
+ *
450
+ * This is useful when you want to add validations or transformations to a field
451
+ * but keep the original metadata (like translationKey) intact.
452
+ *
453
+ * @param field - The original Zod field
454
+ * @param transform - A function that transforms the field
455
+ * @returns The transformed field with preserved metadata
456
+ *
457
+ * @example
458
+ * ```typescript
459
+ * const baseField = z.string().meta({ translationKey: 'user.field.name' });
460
+ *
461
+ * // Add min/max validation while keeping the translationKey
462
+ * const extendedField = extendWithMeta(baseField, (f) => f.min(3).max(100));
463
+ * extendedField.meta(); // { translationKey: 'user.field.name' }
464
+ * ```
465
+ */
466
+ declare function extendWithMeta<T extends z$1.ZodType, R extends z$1.ZodType>(field: T, transform: (f: T) => R): R;
221
467
 
222
468
  /**
223
469
  * Type representing a Zod type that has an unwrap method
@@ -551,165 +797,5 @@ type ZodUnionCheck = $ZodCheckLessThanDef | $ZodCheckGreaterThanDef | $ZodCheckM
551
797
  * @since 0.4.0
552
798
  */
553
799
  declare function getFieldChecks<T extends z$1.ZodTypeAny>(field: T): Array<ZodUnionCheck>;
554
- /**
555
- * Recursively extracts the exact schema type from a discriminated union based on the discriminator value.
556
- *
557
- * This advanced TypeScript utility type walks through a union's options tuple at compile-time,
558
- * checking each schema against the discriminator field and value, and returns the exact matching
559
- * schema type (not a union of all options).
560
- *
561
- * **How it works:**
562
- * 1. Extracts the options tuple from the union using `infer Options`
563
- * 2. Destructure into head (`First`) and tail (`Rest`) using tuple pattern matching
564
- * 3. Checks if `First` is a ZodObject with the matching discriminator field and value
565
- * 4. If match found, returns `First` (the exact schema type)
566
- * 5. If no match, recursively processes `Rest` until a match is found or list is exhausted
567
- *
568
- * **Type narrowing magic:**
569
- * - Input: `z.discriminatedUnion('type', [SchemaA, SchemaB, SchemaC])`
570
- * - Discriminator value: `'a'` (matches SchemaA)
571
- * - Output: `SchemaA` (exact type, not `SchemaA | SchemaB | SchemaC`)
572
- *
573
- * @template TSchema - The ZodUnion or ZodDiscriminatedUnion type
574
- * @template TDiscriminatorKey - The discriminator field name (e.g., "type", "mode")
575
- * @template TDiscriminatorValue - The specific discriminator value (e.g., "create", "edit")
576
- * @returns The exact matching schema type, or `never` if no match found
577
- *
578
- * @example
579
- * ```typescript
580
- * const schema = z.discriminatedUnion('mode', [
581
- * z.object({ mode: z.literal('create'), name: z.string() }),
582
- * z.object({ mode: z.literal('edit'), id: z.number() }),
583
- * ]);
584
- *
585
- * // Exact type: z.object({ mode: z.literal('create'), name: z.string() })
586
- * type CreateSchema = ExtractZodUnionMember<typeof schema, 'mode', 'create'>;
587
- * ```
588
- */
589
- type ExtractZodUnionMember<TSchema extends z$1.ZodUnion | z$1.ZodDiscriminatedUnion, TDiscriminatorKey extends DiscriminatorKey<TSchema>, TDiscriminatorValue extends z$1.input<TSchema>[TDiscriminatorKey] & util.Literal> = TSchema extends z$1.ZodUnion<infer Options> ? Options extends readonly [
590
- infer First extends z$1.ZodTypeAny,
591
- ...infer Rest extends z$1.ZodTypeAny[]
592
- ] ? First extends z$1.ZodObject<infer Shape> ? TDiscriminatorKey extends keyof Shape ? Shape[TDiscriminatorKey] extends z$1.ZodLiteral<TDiscriminatorValue> | z$1.ZodDefault<z$1.ZodLiteral<TDiscriminatorValue>> ? First : Rest extends [] ? never : TDiscriminatorValue extends $InferUnionInput<Rest[number]>[TDiscriminatorKey] ? ExtractZodUnionMember<z$1.ZodUnion<Rest>, TDiscriminatorKey, TDiscriminatorValue> : never : Rest extends [] ? never : TDiscriminatorValue extends $InferUnionInput<Rest[number]>[TDiscriminatorKey] ? ExtractZodUnionMember<z$1.ZodUnion<Rest>, TDiscriminatorKey, TDiscriminatorValue> : never : never : never : never;
593
- /**
594
- * Extracts a specific schema option from a discriminated union based on the discriminator field value.
595
- *
596
- * This function finds and returns the **exact matching schema** from a `ZodDiscriminatedUnion` by
597
- * comparing the discriminator field value. It's used internally by {@link getSchemaDefaults} to
598
- * extract defaults from the correct schema variant in a discriminated union.
599
- *
600
- * **Key feature:** Returns the **exact schema type**, not a union of all options, thanks to the
601
- * {@link ExtractZodUnionMember} recursive type utility. This enables precise type narrowing at
602
- * compile-time based on the discriminator value.
603
- *
604
- * **How it works:**
605
- * 1. Iterates through all options in the discriminated union at runtime
606
- * 2. For each option, validates it's a ZodObject and checks if the discriminator field matches
607
- * 3. Returns the first matching schema with its exact type narrowed at compile-time
608
- * 4. Returns `undefined` if no match found or if option is not a ZodObject
609
- *
610
- * @template TSchema - The ZodUnion or ZodDiscriminatedUnion schema type
611
- * @template TDiscriminatorKey - The discriminator field name (string key of the inferred union type)
612
- * @template TDiscriminatorValue - The specific discriminator value to match (literal type)
613
- * @param params - Parameters object
614
- * @param params.schema - The discriminated union schema to search
615
- * @param params.discriminatorKey - The discriminator field name (e.g., "mode", "type")
616
- * @param params.discriminatorValue - The discriminator value to match (e.g., "create", "edit")
617
- * @returns The exact matching schema option (with precise type), or `undefined` if not found
618
- *
619
- * @example
620
- * Basic discriminated union - create/edit mode
621
- * ```typescript
622
- * const userSchema = z.discriminatedUnion('mode', [
623
- * z.object({
624
- * mode: z.literal('create'),
625
- * name: z.string(),
626
- * age: z.number().optional(),
627
- * }),
628
- * z.object({
629
- * mode: z.literal('edit'),
630
- * id: z.number(),
631
- * name: z.string().optional(),
632
- * }),
633
- * ]);
634
- *
635
- * // Extract the "create" schema
636
- * const createSchema = extractDiscriminatedSchema({
637
- * schema: userSchema,
638
- * discriminatorKey: 'mode',
639
- * discriminatorValue: 'create',
640
- * });
641
- * // Result: z.object({ mode: z.literal('create'), name: z.string(), age: z.number().optional() })
642
- *
643
- * // Extract the "edit" schema
644
- * const editSchema = extractDiscriminatedSchema({
645
- * schema: userSchema,
646
- * discriminatorKey: 'mode',
647
- * discriminatorValue: 'edit',
648
- * });
649
- * // Result: z.object({ mode: z.literal('edit'), id: z.number(), name: z.string().optional() })
650
- * ```
651
- *
652
- * @example
653
- * Type-based discrimination
654
- * ```typescript
655
- * const eventSchema = z.discriminatedUnion('type', [
656
- * z.object({ type: z.literal('click'), x: z.number(), y: z.number() }),
657
- * z.object({ type: z.literal('keypress'), key: z.string() }),
658
- * ]);
659
- *
660
- * const clickSchema = extractDiscriminatedSchema({
661
- * schema: eventSchema,
662
- * discriminatorKey: 'type',
663
- * discriminatorValue: 'click',
664
- * });
665
- * // Result: z.object({ type: z.literal('click'), x: z.number(), y: z.number() })
666
- * ```
667
- *
668
- * @example
669
- * Invalid discriminator value
670
- * ```typescript
671
- * const schema = z.discriminatedUnion('mode', [
672
- * z.object({ mode: z.literal('create'), name: z.string() }),
673
- * ]);
674
- *
675
- * const result = extractDiscriminatedSchema({
676
- * schema,
677
- * discriminatorKey: 'mode',
678
- * discriminatorValue: 'invalid', // doesn't match any option
679
- * });
680
- * // Result: undefined
681
- * ```
682
- *
683
- * @example
684
- * Type narrowing demonstration
685
- * ```typescript
686
- * const schema = z.discriminatedUnion('mode', [
687
- * z.object({ mode: z.literal('create'), name: z.string(), age: z.number() }),
688
- * z.object({ mode: z.literal('edit'), id: z.number(), bio: z.string() }),
689
- * ]);
690
- *
691
- * const createSchema = extractDiscriminatedSchema({
692
- * schema,
693
- * discriminatorKey: 'mode',
694
- * discriminatorValue: 'create',
695
- * });
696
- *
697
- * // Type is EXACTLY: z.object({ mode: z.literal('create'), name: z.string(), age: z.number() })
698
- * // NOT: z.object({ mode: ..., ... }) | z.object({ mode: ..., ... }) | undefined
699
- *
700
- * if (createSchema) {
701
- * createSchema.shape.age; // ✅ TypeScript knows 'age' exists
702
- * createSchema.shape.name; // ✅ TypeScript knows 'name' exists
703
- * // createSchema.shape.id; // ❌ TypeScript error: 'id' doesn't exist on 'create' schema
704
- * }
705
- * ```
706
- *
707
- * @see {@link getSchemaDefaults} for usage with discriminated unions
708
- * @see {@link ExtractZodUnionMember} for the type-level extraction logic
709
- * @since 0.6.0
710
- */
711
- declare const extractDiscriminatedSchema: <TSchema extends z$1.ZodType, TDiscriminatorKey extends DiscriminatorKey<TSchema>, TDiscriminatorValue extends DiscriminatorValue<TSchema, TDiscriminatorKey>, ReturnType extends TSchema extends z$1.ZodDiscriminatedUnion ? ExtractZodUnionMember<TSchema, TDiscriminatorKey, TDiscriminatorValue> : never>({ schema, key, value, }: {
712
- schema: TSchema;
713
- } & Discriminator<TSchema, TDiscriminatorKey, TDiscriminatorValue>) => ReturnType;
714
800
 
715
- export { type Discriminator, type DiscriminatorKey, type DiscriminatorValue, type Simplify, type ZodUnionCheck, canUnwrap, extractDefaultValue, extractDiscriminatedSchema, extractFieldFromSchema, getFieldChecks, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, tryStripNullishOnly };
801
+ export { type CommonFields, type Discriminator, type DiscriminatorKey, type DiscriminatorValue, type ExtractZodByPath, type Paths, type Simplify, type ValidPaths, type ZodUnionCheck, canUnwrap, extendWithMeta, extractDefaultValue, extractDiscriminatedSchema, extractFieldFromSchema, getFieldChecks, getPrimitiveType, getSchemaDefaults, removeDefault, requiresValidInput, tryStripNullishOnly };
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var z2 = require('zod');
3
+ var z3 = require('zod');
4
4
 
5
5
  function _interopNamespace(e) {
6
6
  if (e && e.__esModule) return e;
@@ -20,7 +20,7 @@ function _interopNamespace(e) {
20
20
  return Object.freeze(n);
21
21
  }
22
22
 
23
- var z2__namespace = /*#__PURE__*/_interopNamespace(z2);
23
+ var z3__namespace = /*#__PURE__*/_interopNamespace(z3);
24
24
 
25
25
  var __defProp = Object.defineProperty;
26
26
  var __getOwnPropSymbols = Object.getOwnPropertySymbols;
@@ -38,14 +38,32 @@ var __spreadValues = (a, b) => {
38
38
  }
39
39
  return a;
40
40
  };
41
+ var extractDiscriminatedSchema = ({
42
+ schema,
43
+ key,
44
+ value
45
+ }) => {
46
+ if (!(schema instanceof z3.z.ZodDiscriminatedUnion)) {
47
+ return void 0;
48
+ }
49
+ return schema.options.find((option) => {
50
+ if (option instanceof z3.z.ZodObject) {
51
+ const targetField = option.shape[String(key)];
52
+ if (!targetField) return false;
53
+ const parseResult = targetField.safeParse(value);
54
+ return parseResult.success;
55
+ }
56
+ return false;
57
+ });
58
+ };
41
59
  function canUnwrap(field) {
42
60
  return "unwrap" in field && typeof field.unwrap === "function";
43
61
  }
44
62
  function tryStripNullishOnly(field) {
45
- if (field instanceof z2.z.ZodUnion) {
63
+ if (field instanceof z3.z.ZodUnion) {
46
64
  const unionOptions = [...field.def.options];
47
65
  const filteredOptions = unionOptions.filter(
48
- (option) => !(option instanceof z2.z.ZodNull) && !(option instanceof z2.z.ZodUndefined)
66
+ (option) => !(option instanceof z3.z.ZodNull) && !(option instanceof z3.z.ZodUndefined)
49
67
  );
50
68
  const firstOption = filteredOptions[0];
51
69
  if (firstOption && filteredOptions.length === 1) {
@@ -55,34 +73,34 @@ function tryStripNullishOnly(field) {
55
73
  return false;
56
74
  }
57
75
  var getPrimitiveType = (field) => {
58
- if (field instanceof z2.z.ZodArray) {
76
+ if (field instanceof z3.z.ZodArray) {
59
77
  return field;
60
78
  }
61
79
  if (canUnwrap(field)) {
62
80
  return getPrimitiveType(field.unwrap());
63
81
  }
64
- if (field instanceof z2.z.ZodUnion) {
82
+ if (field instanceof z3.z.ZodUnion) {
65
83
  const unwrapped = tryStripNullishOnly(field);
66
84
  if (unwrapped !== false) {
67
85
  return getPrimitiveType(unwrapped);
68
86
  }
69
87
  return field;
70
88
  }
71
- if (field instanceof z2.z.ZodPipe && field.def.in instanceof z2.z.ZodType) {
89
+ if (field instanceof z3.z.ZodPipe && field.def.in instanceof z3.z.ZodType) {
72
90
  return getPrimitiveType(field.def.in);
73
91
  }
74
92
  return field;
75
93
  };
76
94
  function removeDefault(field) {
77
- if (field instanceof z2.z.ZodDefault) {
95
+ if (field instanceof z3.z.ZodDefault) {
78
96
  return field.unwrap();
79
97
  }
80
- if ("innerType" in field.def && field.def.innerType instanceof z2.z.ZodType) {
98
+ if ("innerType" in field.def && field.def.innerType instanceof z3.z.ZodType) {
81
99
  const inner = removeDefault(field.def.innerType);
82
- if (field instanceof z2.z.ZodOptional) {
100
+ if (field instanceof z3.z.ZodOptional) {
83
101
  return inner.optional();
84
102
  }
85
- if (field instanceof z2.z.ZodNullable) {
103
+ if (field instanceof z3.z.ZodNullable) {
86
104
  return inner.nullable();
87
105
  }
88
106
  }
@@ -90,7 +108,7 @@ function removeDefault(field) {
90
108
  }
91
109
  var requiresValidInput = (field) => {
92
110
  const defaultRemovedField = removeDefault(field);
93
- if (!(defaultRemovedField instanceof z2.z.ZodType)) {
111
+ if (!(defaultRemovedField instanceof z3.z.ZodType)) {
94
112
  return false;
95
113
  }
96
114
  const undefinedResult = defaultRemovedField.safeParse(void 0).success;
@@ -105,41 +123,23 @@ function getFieldChecks(field) {
105
123
  const primitiveType = getPrimitiveType(field);
106
124
  return ((_a = primitiveType.def.checks) == null ? void 0 : _a.map((check) => check._zod.def)) || [];
107
125
  }
108
- var extractDiscriminatedSchema = ({
109
- schema,
110
- key,
111
- value
112
- }) => {
113
- if (!(schema instanceof z2.z.ZodDiscriminatedUnion)) {
114
- return void 0;
115
- }
116
- return schema.options.find((option) => {
117
- if (option instanceof z2.z.ZodObject) {
118
- const targetField = option.shape[String(key)];
119
- if (!targetField) return false;
120
- const parseResult = targetField.safeParse(value);
121
- return parseResult.success;
122
- }
123
- return false;
124
- });
125
- };
126
126
 
127
127
  // src/defaults.ts
128
128
  function extractDefaultValue(field) {
129
- if (field instanceof z2__namespace.ZodDefault) {
129
+ if (field instanceof z3__namespace.ZodDefault) {
130
130
  return field.def.defaultValue;
131
131
  }
132
132
  if (canUnwrap(field)) {
133
133
  return extractDefaultValue(field.unwrap());
134
134
  }
135
- if (field instanceof z2__namespace.ZodUnion) {
135
+ if (field instanceof z3__namespace.ZodUnion) {
136
136
  const unwrapped = tryStripNullishOnly(field);
137
137
  if (unwrapped !== false) {
138
138
  return extractDefaultValue(unwrapped);
139
139
  }
140
140
  return void 0;
141
141
  }
142
- if (field instanceof z2__namespace.ZodPipe && field.def.in instanceof z2__namespace.ZodType) {
142
+ if (field instanceof z3__namespace.ZodPipe && field.def.in instanceof z3__namespace.ZodType) {
143
143
  return extractDefaultValue(field.def.in);
144
144
  }
145
145
  return void 0;
@@ -147,13 +147,13 @@ function extractDefaultValue(field) {
147
147
  function getSchemaDefaults(schema, options) {
148
148
  const primitiveSchema = getPrimitiveType(schema);
149
149
  let targetSchema;
150
- if (primitiveSchema instanceof z2__namespace.ZodDiscriminatedUnion) {
150
+ if (primitiveSchema instanceof z3__namespace.ZodDiscriminatedUnion) {
151
151
  if (options == null ? void 0 : options.discriminator) {
152
152
  targetSchema = extractDiscriminatedSchema(__spreadValues({
153
153
  schema: primitiveSchema
154
154
  }, options.discriminator));
155
155
  }
156
- } else if (primitiveSchema instanceof z2__namespace.ZodObject) {
156
+ } else if (primitiveSchema instanceof z3__namespace.ZodObject) {
157
157
  targetSchema = primitiveSchema;
158
158
  }
159
159
  const defaults = {};
@@ -171,26 +171,50 @@ function getSchemaDefaults(schema, options) {
171
171
  }
172
172
  function extractFieldFromSchema({
173
173
  schema,
174
- fieldName,
174
+ name,
175
175
  discriminator
176
176
  }) {
177
- let targetSchema;
177
+ let currentSchema;
178
178
  const primitiveSchema = getPrimitiveType(schema);
179
- if (primitiveSchema instanceof z2.z.ZodDiscriminatedUnion) {
179
+ if (primitiveSchema instanceof z3.z.ZodDiscriminatedUnion) {
180
180
  if (discriminator) {
181
- targetSchema = extractDiscriminatedSchema(__spreadValues({
181
+ currentSchema = extractDiscriminatedSchema(__spreadValues({
182
182
  schema: primitiveSchema
183
183
  }, discriminator));
184
184
  }
185
- } else if (primitiveSchema instanceof z2.z.ZodObject) {
186
- targetSchema = primitiveSchema;
185
+ } else if (primitiveSchema instanceof z3.z.ZodObject) {
186
+ currentSchema = primitiveSchema;
187
+ }
188
+ if (!currentSchema) return void 0;
189
+ const segments = String(name).split(".");
190
+ for (const segment of segments) {
191
+ if (!currentSchema) return void 0;
192
+ const unwrapped = getPrimitiveType(currentSchema);
193
+ if (unwrapped instanceof z3.z.ZodObject) {
194
+ currentSchema = unwrapped.shape[segment];
195
+ } else if (unwrapped instanceof z3.z.ZodArray) {
196
+ if (/^\d+$/.test(segment) && unwrapped.element instanceof z3.z.ZodType) {
197
+ currentSchema = unwrapped.element;
198
+ } else {
199
+ return void 0;
200
+ }
201
+ } else {
202
+ return void 0;
203
+ }
187
204
  }
188
- if (!targetSchema) return void 0;
189
- const field = targetSchema.shape[String(fieldName)];
190
- return field;
205
+ return currentSchema;
206
+ }
207
+ function extendWithMeta(field, transform) {
208
+ const transformedField = transform(field);
209
+ const meta = field.meta();
210
+ if (!meta) {
211
+ return transformedField;
212
+ }
213
+ return transformedField.meta(__spreadValues({}, meta));
191
214
  }
192
215
 
193
216
  exports.canUnwrap = canUnwrap;
217
+ exports.extendWithMeta = extendWithMeta;
194
218
  exports.extractDefaultValue = extractDefaultValue;
195
219
  exports.extractDiscriminatedSchema = extractDiscriminatedSchema;
196
220
  exports.extractFieldFromSchema = extractFieldFromSchema;