zodselect 1.2.3 → 1.2.4
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/refine-schema.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { core, z, ZodAny, ZodArray, ZodBoolean, ZodDate, ZodLiteral, ZodNever, ZodNullable, ZodNumber, ZodObject, ZodOptional, ZodRawShape, ZodString, ZodTuple, ZodType, ZodUnion, ZodUnknown } from 'zod';
|
|
2
2
|
import { IsAny, IsJsonType } from './types.js';
|
|
3
|
-
type ApplyOptionalNullable<T, U extends ZodType> = IsAny<T, U, undefined extends T ? null extends T ? ZodOptional<ZodNullable<U>> : ZodOptional<U> : null extends T ? ZodNullable<U> : U>;
|
|
3
|
+
type ApplyOptionalNullable<T, U extends ZodType> = IsAny<T, U, unknown extends T ? U : undefined extends T ? null extends T ? ZodOptional<ZodNullable<U>> : ZodOptional<U> : null extends T ? ZodNullable<U> : U>;
|
|
4
4
|
type DepthLimit = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
5
|
-
type InternalZodify<T, TDepth extends number = 0> = TDepth extends 9 ? ZodType : IsAny<T, ZodAny, T extends string ? string extends T ? ZodString : ZodLiteral<T> : T extends number ? ZodNumber : T extends boolean ? ZodBoolean : T extends Date ? ZodDate : unknown extends T ? ZodUnknown : T extends Array<infer U> ? ZodArray<Zodify<U, NextDepth<TDepth>>> : T extends object ? IsJsonType<T, true, ZodObject<{
|
|
5
|
+
type InternalZodify<T, TDepth extends number = 0> = TDepth extends 9 ? ZodType : IsAny<T, ZodAny, T extends string ? string extends T ? ZodString : ZodLiteral<T> : T extends number ? number extends T ? ZodNumber : ZodLiteral<T> : T extends boolean ? boolean extends T ? ZodBoolean : ZodLiteral<T> : T extends Date ? ZodDate : unknown extends T ? ZodUnknown : T extends Array<infer U> ? ZodArray<Zodify<U, NextDepth<TDepth>>> : T extends object ? IsJsonType<T, true, ZodObject<{
|
|
6
6
|
[K in keyof T]-?: Zodify<T[K], NextDepth<TDepth>>;
|
|
7
7
|
}, core.$strict>, ZodType<T>> : never>;
|
|
8
8
|
type IsTuple<T, TTrue = true, TFalse = false> = T extends [infer TFirst, infer TSecond, ...infer TRest] ? TTrue : TFalse;
|
|
@@ -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 ?
|
|
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<RefinedTypeSchema<U, TShape[K], NextDepth<TDepth>>>> : Zodify<T[K]> : Exclude<T[K], null | undefined> extends object ? ApplyOptionalNullable<T[K], RefinedTypeSchema<Exclude<T[K], null | undefined>, TShape[K], NextDepth<TDepth>>> : ZodNever : 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>>,
|
|
@@ -36,8 +36,10 @@ export type TuplifyUnion<T, TDepth extends number = 0, L = LastOf<T>, N = [T] ex
|
|
|
36
36
|
type UnionFieldType<T extends ZodType> = Exclude<z.infer<T>, null | undefined> extends Array<infer U> ? Exclude<U, null | undefined> extends object ? boolean | RefineObject<Extract<U, object>, true> : boolean : Exclude<z.infer<T>, null | undefined> extends object ? boolean | RefineObject<Exclude<z.infer<T>, null | undefined>, true> : boolean;
|
|
37
37
|
type UnionMergedShape<T extends ZodUnion> = UnionToIntersection<T['options'][number] extends ZodObject<infer Shape extends ZodRawShape> ? Shape : object>;
|
|
38
38
|
export type UnionToIntersection<U> = (U extends any ? (x: U) => void : never) extends (x: infer I) => void ? I : never;
|
|
39
|
-
export type Zodify<T, TDepth extends number = 0> = ApplyOptionalNullable<T, IsAny<T, ZodAny,
|
|
40
|
-
|
|
41
|
-
|
|
39
|
+
export type Zodify<T, TDepth extends number = 0> = ApplyOptionalNullable<T, IsAny<T, ZodAny, ZodifyLiteral<Exclude<T, null | undefined>, IsTuple<TuplifyUnion<Exclude<T, null | undefined>, TDepth>, ZodUnion<TuplifyUnion<Exclude<T, null | undefined>, TDepth>>, InternalZodify<Exclude<T, null | undefined>, TDepth>>>>>;
|
|
40
|
+
type ZodifyField<T, TKey extends keyof T> = unknown extends T[TKey] ? Partial<Pick<T, TKey>> extends Pick<T, TKey> ? ZodOptional<Zodify<T[TKey]>> : Zodify<T[TKey]> : Zodify<T[TKey]>;
|
|
41
|
+
type ZodifyLiteral<T, TElse> = [
|
|
42
|
+
T
|
|
43
|
+
] extends [boolean | number | string] ? [T] extends [boolean] ? boolean extends T ? ZodBoolean : ZodLiteral<T> : string extends T ? [T] extends [string] ? ZodString : TElse : number extends T ? [T] extends [number] ? ZodNumber : TElse : ZodLiteral<T> : TElse;
|
|
42
44
|
export declare function refineSchema<T extends ZodType<object> | ZodUnion, TShape extends RefineSchema<T, false>>(schema: T, shape: TShape): RefinedSchema<T, TShape, false>;
|
|
43
45
|
export {};
|
|
@@ -356,3 +356,46 @@ describe('.refineSchema()', () => {
|
|
|
356
356
|
deepStrictEqual(selected.map(s => refined.parse(s).stage), stage.options);
|
|
357
357
|
});
|
|
358
358
|
});
|
|
359
|
+
describe('.refineSchema() literal and unknown field types', () => {
|
|
360
|
+
// Regression tests for `Zodify` (refine-schema.ts) when a schema's fields are listed
|
|
361
|
+
// (e.g. via `buildSelectObject`) instead of selected whole. Before the fix a numeric
|
|
362
|
+
// literal union widened to `number` and a required `z.unknown()` field became
|
|
363
|
+
// optional, so the selected type no longer fit the source type. Runtime was
|
|
364
|
+
// unaffected; these assignments fail the type-check (`tsc`).
|
|
365
|
+
const question = z.object({
|
|
366
|
+
answer: z.object({ value: z.unknown() }),
|
|
367
|
+
flag: z.literal(true),
|
|
368
|
+
note: z.unknown().optional(),
|
|
369
|
+
scale: z.union([z.literal(5), z.literal(10)]),
|
|
370
|
+
steps: z.literal([3, 7]),
|
|
371
|
+
value: z.unknown()
|
|
372
|
+
});
|
|
373
|
+
const survey = z.object({
|
|
374
|
+
name: z.string(),
|
|
375
|
+
pages: z.array(z.object({ questions: z.array(question) }))
|
|
376
|
+
});
|
|
377
|
+
it('keeps a numeric literal union instead of widening it to number', () => {
|
|
378
|
+
const refined = refineSchema(survey, { pages: { questions: { scale: true, steps: true } } });
|
|
379
|
+
// With the bug these resolve to `number`, so the source type can't take them.
|
|
380
|
+
const scale = {}.scale;
|
|
381
|
+
const steps = {}.steps;
|
|
382
|
+
void scale;
|
|
383
|
+
void steps;
|
|
384
|
+
const parsed = refined.parse({ pages: [{ questions: [{ scale: 10, steps: 3 }] }] });
|
|
385
|
+
assert.equal(parsed.pages[0]?.questions[0]?.scale, 10);
|
|
386
|
+
throws(() => refined.parse({ pages: [{ questions: [{ scale: 7, steps: 3 }] }] }), ZodError);
|
|
387
|
+
});
|
|
388
|
+
it('keeps a boolean literal instead of widening it to boolean', () => {
|
|
389
|
+
const refined = refineSchema(survey, { pages: { questions: { flag: true } } });
|
|
390
|
+
const isFlag = {}.flag;
|
|
391
|
+
void isFlag;
|
|
392
|
+
throws(() => refined.parse({ pages: [{ questions: [{ flag: false }] }] }), ZodError);
|
|
393
|
+
});
|
|
394
|
+
it('keeps a required unknown field required', () => {
|
|
395
|
+
const refined = refineSchema(survey, { pages: { questions: { answer: true, note: true, value: true } } });
|
|
396
|
+
// With the bug `value` became an optional key; `note` must stay optional.
|
|
397
|
+
const selected = { answer: { value: 1 }, value: 'x' };
|
|
398
|
+
const questions = [selected];
|
|
399
|
+
deepStrictEqual(refined.parse({ pages: [{ questions }] }).pages[0]?.questions, questions);
|
|
400
|
+
});
|
|
401
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zodselect",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.4",
|
|
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",
|