zodselect 1.2.6 → 1.2.8

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.
@@ -12,7 +12,7 @@ type Push<T extends any[], V> = [...T, V];
12
12
  type ReapplyOptionalNullable<T, U extends z.ZodType> = T extends ZodOptional<ZodNullable<ZodType>> ? ZodOptional<ZodNullable<U>> : T extends ZodNullable<ZodOptional<ZodType>> ? ZodNullable<ZodOptional<U>> : T extends ZodOptional<ZodType> ? ZodOptional<U> : T extends ZodNullable<ZodType> ? ZodNullable<U> : U;
13
13
  export type RefinedSchema<T extends ZodType<object> | ZodUnion, TShape extends RefineSchema<T, TIsSimple>, TIsSimple extends boolean> = T extends ZodUnion ? RefinedUnionSchema<T, TShape> : T extends ZodType<object> ? RefinedTypeSchema<z.infer<T>, TShape> : never;
14
14
  export type RefinedTypeSchema<T extends object, TShape, TDepth extends number = 0> = TDepth extends keyof DepthLimit ? ZodObject<{
15
- [K in keyof T & keyof TShape]: TShape[K] extends (schema: infer S) => ZodType ? ReturnType<TShape[K]> : TShape[K] extends ZodType ? TShape[K] : TShape[K] extends boolean ? ZodifyField<T, K> : TShape[K] extends object ? Exclude<T[K], null | undefined> extends Array<infer U> ? [U] extends [object] ? ApplyOptionalNullable<T[K], z.ZodArray<RefinedVariants<U, TShape[K], NextDepth<TDepth>>>> : Zodify<T[K]> : Exclude<T[K], null | undefined> extends object ? ApplyOptionalNullable<T[K], RefinedVariants<Exclude<T[K], null | undefined>, TShape[K], NextDepth<TDepth>>> : ZodNever : ZodNever;
15
+ [K in keyof T & keyof TShape]: TShape[K] extends (schema: infer S) => ZodType ? ReturnType<TShape[K]> : TShape[K] extends ZodType ? TShape[K] : TShape[K] extends boolean ? ZodifyField<T, K> : TShape[K] extends object ? Exclude<T[K], null | undefined> extends Array<infer U> ? [Extract<U, object>] extends [never] ? Zodify<T[K]> : ApplyOptionalNullable<T[K], z.ZodArray<RefinedVariants<Extract<U, object>, TShape[K], NextDepth<TDepth>>>> : [Extract<Exclude<T[K], null | undefined>, object>] extends [never] ? ZodNever : ApplyOptionalNullable<T[K], RefinedVariants<Extract<Exclude<T[K], null | undefined>, object>, TShape[K], NextDepth<TDepth>>> : ZodNever;
16
16
  }, core.$strict> : any;
17
17
  export type RefinedUnionSchema<T extends ZodUnion, TShape> = ZodUnion<T['options'] extends Readonly<[infer A, ...infer Rest]> ? Rest extends ZodType[] ? [
18
18
  ReapplyOptionalNullable<A, A extends ZodType<object> ? RefinedTypeSchema<z.infer<A>, TShape> : Extract<A, ZodType>>,
@@ -27,7 +27,7 @@ export type RefineObject<T extends object, TIsSimple extends boolean> = {
27
27
  [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]?: RefineType<T[K], TIsSimple>;
28
28
  };
29
29
  export type RefineSchema<T extends ZodType<object> | ZodUnion, TIsSimple extends boolean> = T extends ZodUnion ? RefineZodUnion<T> : T extends ZodType<object> ? RefineObject<z.infer<T>, TIsSimple> : never;
30
- type RefineType<T, TIsSimple extends boolean> = IsTuple<TuplifyUnion<Exclude<T, null | undefined>>, ([Exclude<Exclude<T, null | undefined>, object>] extends [never] ? RefineObject<Extract<Exclude<T, null | undefined>, object>, TIsSimple> : never) | Refinement<Zodify<T>, TIsSimple>, Exclude<T, null | undefined> extends string ? Refinement<ApplyOptionalNullable<T, ZodString>, TIsSimple> : Exclude<T, null | undefined> extends number ? Refinement<ApplyOptionalNullable<T, ZodNumber>, TIsSimple> : Exclude<T, null | undefined> extends boolean ? Refinement<ApplyOptionalNullable<T, ZodBoolean>, TIsSimple> : Exclude<T, null | undefined> extends Date ? Refinement<ApplyOptionalNullable<T, ZodDate>, TIsSimple> : Exclude<T, null | undefined> extends Array<infer U> ? Exclude<U, null | undefined> extends object ? Refinement<Zodify<T>, TIsSimple> | RefineObject<Extract<U, object>, TIsSimple> : Refinement<Zodify<T>, TIsSimple> : Exclude<T, null | undefined> extends object ? IsJsonType<Exclude<T, null | undefined>, false, Refinement<Zodify<T>, TIsSimple> | RefineObject<Extract<T, object>, TIsSimple>, Refinement<Zodify<T>, TIsSimple>> : unknown extends Exclude<T, null | undefined> ? Refinement<Zodify<T>, TIsSimple> : never>;
30
+ type RefineType<T, TIsSimple extends boolean> = IsTuple<TuplifyUnion<Exclude<T, null | undefined>>, ([Extract<Exclude<T, null | undefined>, object>] extends [never] ? never : RefineObject<Extract<Exclude<T, null | undefined>, object>, TIsSimple>) | Refinement<Zodify<T>, TIsSimple>, Exclude<T, null | undefined> extends string ? Refinement<ApplyOptionalNullable<T, ZodString>, TIsSimple> : Exclude<T, null | undefined> extends number ? Refinement<ApplyOptionalNullable<T, ZodNumber>, TIsSimple> : Exclude<T, null | undefined> extends boolean ? Refinement<ApplyOptionalNullable<T, ZodBoolean>, TIsSimple> : Exclude<T, null | undefined> extends Date ? Refinement<ApplyOptionalNullable<T, ZodDate>, TIsSimple> : Exclude<T, null | undefined> extends Array<infer U> ? [Extract<U, object>] extends [never] ? Refinement<Zodify<T>, TIsSimple> : Refinement<Zodify<T>, TIsSimple> | RefineObject<Extract<U, object>, TIsSimple> : Exclude<T, null | undefined> extends object ? IsJsonType<Exclude<T, null | undefined>, false, Refinement<Zodify<T>, TIsSimple> | RefineObject<Extract<T, object>, TIsSimple>, Refinement<Zodify<T>, TIsSimple>> : unknown extends Exclude<T, null | undefined> ? Refinement<Zodify<T>, TIsSimple> : never>;
31
31
  export type RefineZodTuple<T extends ZodTuple> = {
32
32
  [K in keyof UnionToIntersection<T['def']['items'][number] extends ZodObject<infer Shape extends ZodRawShape> ? Shape : object>]?: boolean;
33
33
  };
@@ -1,5 +1,5 @@
1
1
  import { z } from 'zod';
2
- import { getInnerType, isZodArray, isZodNullable, isZodObject, isZodOptional, isZodType, isZodUnion } from './utilities.js';
2
+ import { isZodArray, isZodCatch, isZodDefault, isZodLazy, isZodNullable, isZodObject, isZodOptional, isZodType, isZodUnion } from './utilities.js';
3
3
  // Main function to refine the schema
4
4
  export function refineSchema(schema, shape) {
5
5
  if (isZodObject(schema)) {
@@ -45,12 +45,12 @@ function refineSchemaField(fieldSchema, fieldShape) {
45
45
  else if (isZodNullable(fieldSchema)) {
46
46
  return refineSchemaField(fieldSchema.def.innerType, fieldShape).nullable();
47
47
  }
48
- else {
49
- const innerType = getInnerType(fieldSchema);
50
- // There are wrapper types we can't forward because the underlying object structures are changing.
51
- if (innerType !== fieldSchema) {
52
- return refineSchemaField(innerType, fieldShape);
53
- }
48
+ else if (isZodDefault(fieldSchema) || isZodCatch(fieldSchema)) {
49
+ // A default or catch is a whole value, which a picked part no longer fits, so it gives way to what it wraps.
50
+ return refineSchemaField(fieldSchema.def.innerType, fieldShape);
51
+ }
52
+ else if (isZodLazy(fieldSchema)) {
53
+ return refineSchemaField(fieldSchema.def.getter(), fieldShape);
54
54
  }
55
55
  return fieldSchema;
56
56
  }
@@ -128,6 +128,19 @@ describe('.refineSchema()', () => {
128
128
  });
129
129
  assert.equal(parsedWithoutNestedArray.nestedArray, undefined);
130
130
  });
131
+ it('keeps an array under a default, a catch or a lazy an array of the picked fields', () => {
132
+ const line = z.object({ id: z.string(), secret: z.string() });
133
+ const order = z.object({
134
+ caught: z.array(line).catch([]),
135
+ defaulted: z.array(line).default([]),
136
+ lazy: z.lazy(() => z.array(line))
137
+ });
138
+ const refined = refineSchema(order, { caught: { id: true }, defaulted: { id: true }, lazy: { id: true } });
139
+ const lines = [{ id: 'a', secret: 's' }];
140
+ deepStrictEqual(refined.parse({ caught: lines, defaulted: lines, lazy: lines }), { caught: [{ id: 'a' }], defaulted: [{ id: 'a' }], lazy: [{ id: 'a' }] });
141
+ assert.ok(refined.shape.defaulted instanceof z.ZodArray);
142
+ assert.ok(refined.shape.caught instanceof z.ZodArray);
143
+ });
131
144
  it('should handle custom fields', () => {
132
145
  const userSchema = z.object({
133
146
  address: z.custom().optional(),
@@ -88,9 +88,21 @@ describe('a field whose value is a union of objects', () => {
88
88
  name: true
89
89
  });
90
90
  });
91
- it('still refuses a nested select into a union with a plain variant, which would miss the plain value', () => {
92
- // @ts-expect-error `name` may be a string, so only the whole value can be selected.
91
+ it('accepts a nested select into the object variants of a union with a plain one, as a join read as its record is', () => {
93
92
  const select = { name: { en: true } };
94
- assert.ok(select);
93
+ const isTyped = true;
94
+ assert.ok(isTyped);
95
+ assert.deepEqual(refineSchema(policy, select).parse({ name: { en: 'Software' } }), { name: { en: 'Software' } });
96
+ });
97
+ it('accepts the select a screen builds by declaring a joined id as its record', () => {
98
+ const file = z.object({ _id: z.string(), filename: z.string() });
99
+ const attachment = z.object({ file: z.union([file, z.string()]), title: z.string().optional() });
100
+ const stored = z.object({ attachments: z.array(attachment).optional() });
101
+ const read = z.object({ attachments: z.array(attachment.extend({ file })).optional() });
102
+ const select = buildSelectObject(read);
103
+ const isTyped = true;
104
+ assert.ok(isTyped);
105
+ assert.deepEqual(select, { attachments: { file: { _id: true, filename: true }, title: true } });
106
+ assert.deepEqual(refineSchema(stored, select).parse({ attachments: [{ file: { _id: 'f1', filename: 'a.pdf' } }] }), { attachments: [{ file: { _id: 'f1', filename: 'a.pdf' } }] });
95
107
  });
96
108
  });
@@ -1,6 +1,8 @@
1
- import { ZodArray, ZodLazy, ZodNullable, ZodObject, ZodOptional, ZodRecord, ZodType, ZodUnion, ZodUnknown } from 'zod';
1
+ import { ZodArray, ZodCatch, ZodDefault, ZodLazy, ZodNullable, ZodObject, ZodOptional, ZodRecord, ZodType, ZodUnion, ZodUnknown } from 'zod';
2
2
  export declare function getInnerType(schema: ZodType, unwrapLazy?: boolean): ZodType;
3
3
  export declare function isZodArray(obj: unknown): obj is ZodArray<ZodType>;
4
+ export declare function isZodCatch(obj: unknown): obj is ZodCatch<ZodType>;
5
+ export declare function isZodDefault(obj: unknown): obj is ZodDefault<ZodType>;
4
6
  export declare function isZodLazy(obj: unknown): obj is ZodLazy;
5
7
  export declare function isZodNullable(obj: unknown): obj is ZodNullable<ZodType>;
6
8
  export declare function isZodObject(obj: unknown, isLoose?: boolean): obj is ZodObject;
package/dist/utilities.js CHANGED
@@ -17,6 +17,12 @@ export function getInnerType(schema, unwrapLazy = true) {
17
17
  export function isZodArray(obj) {
18
18
  return isZodType(obj) && (obj.def.type === 'array');
19
19
  }
20
+ export function isZodCatch(obj) {
21
+ return isZodType(obj) && (obj.def.type === 'catch');
22
+ }
23
+ export function isZodDefault(obj) {
24
+ return isZodType(obj) && (obj.def.type === 'default');
25
+ }
20
26
  export function isZodLazy(obj) {
21
27
  return isZodType(obj) && (obj.def.type === 'lazy');
22
28
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zodselect",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "Type-safe selection utility built on top of Zod. Allows for strongly typed field selection, schema merging, and runtime refinement for frontend or backend use.",
5
5
  "author": "SecureDataSystems",
6
6
  "license": "MIT",