Skip to content

Commit

Permalink
Add support for nested ZodEffects
Browse files Browse the repository at this point in the history
  • Loading branch information
sassanh committed Nov 5, 2024
1 parent d79dbb2 commit 873a776
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 4 deletions.
65 changes: 65 additions & 0 deletions packages/uniforms-bridge-zod/__tests__/ZodBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,29 @@ describe('ZodBridge', () => {
expect(error?.issues?.[0]?.message).toBe(errorMessage);
});

it('works with chained refined schema', () => {
const firstErrorMessage = 'Different values';
const secondErrorMessage = 'Different moduloes of 2 and 3';

const schema = object({
a: number(),
b: number(),
})
.refine(({ a, b }) => a === b, {
message: firstErrorMessage,
path: ['b'],
})
.refine(({ a, b }) => a % 2 === b % 3, {
message: secondErrorMessage,
path: ['b'],
});

const bridge = new ZodBridge({ schema });
const error = bridge.getValidator()({ a: 1, b: 2 });
expect(error?.issues?.[0]?.message).toBe(firstErrorMessage);
expect(error?.issues?.[1]?.message).toBe(secondErrorMessage);
});

it('works with super refined schema', () => {
const errorMessage = 'Different values';

Expand All @@ -108,6 +131,37 @@ describe('ZodBridge', () => {
const error = bridge.getValidator()({ a: 'a', b: 'b' });
expect(error?.issues?.[0]?.message).toBe(errorMessage);
});

it('works with chained super refined schema', () => {
const firstErrorMessage = 'Different values';
const secondErrorMessage = 'Different moduloes of 2 and 3';

const schema = object({
a: number(),
b: number(),
})
.superRefine((val, ctx) => {
if (val.a !== val.b) {
ctx.addIssue({
code: ZodIssueCode.custom,
message: firstErrorMessage,
});
}
})
.superRefine((val, ctx) => {
if (val.a % 2 !== val.b % 3) {
ctx.addIssue({
code: ZodIssueCode.custom,
message: secondErrorMessage,
});
}
});

const bridge = new ZodBridge({ schema });
const error = bridge.getValidator()({ a: 1, b: 2 });
expect(error?.issues?.[0]?.message).toBe(firstErrorMessage);
expect(error?.issues?.[1]?.message).toBe(secondErrorMessage);
});
});

describe('#getErrorMessage', () => {
Expand Down Expand Up @@ -244,6 +298,17 @@ describe('ZodBridge', () => {
const bridge = new ZodBridge({ schema });
expect(bridge.getField('')).toBe(schema._def.schema);
});

it('works with nested ZodEffects', () => {
const schema = object({})
.refine(data => data)
.refine(data => data)
.refine(data => data);
const bridge = new ZodBridge({ schema });
expect(bridge.getField('')).toBe(
schema._def.schema._def.schema._def.schema,
);
});
});

describe('#getInitialValue', () => {
Expand Down
20 changes: 16 additions & 4 deletions packages/uniforms-bridge-zod/src/ZodBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,15 +55,27 @@ type Option<Value> = {
value: Value;
};

type BuildTuple<L extends number, T extends any[] = []> = T['length'] extends L
? T
: BuildTuple<L, [...T, any]>;

type Decrement<N extends number> =
BuildTuple<N> extends [any, ...infer R] ? R['length'] : never;

type NestedZodEffect<
T extends ZodObject<any>,
Depth extends number = 20,
> = Depth extends 0 ? T : ZodEffects<T | NestedZodEffect<T, Decrement<Depth>>>;

export default class ZodBridge<T extends ZodRawShape> extends Bridge {
schema: ZodObject<T> | ZodEffects<ZodObject<T>>;
schema: ZodObject<T> | NestedZodEffect<ZodObject<T>>;
provideDefaultLabelFromFieldName: boolean;

constructor({
schema,
provideDefaultLabelFromFieldName = true,
}: {
schema: ZodObject<T> | ZodEffects<ZodObject<T>>;
schema: ZodObject<T> | NestedZodEffect<ZodObject<T>>;
provideDefaultLabelFromFieldName?: boolean;
}) {
super();
Expand Down Expand Up @@ -108,8 +120,8 @@ export default class ZodBridge<T extends ZodRawShape> extends Bridge {
getField(name: string) {
let field: ZodType = this.schema;

if (this.schema instanceof ZodEffects) {
field = this.schema._def.schema;
while (field instanceof ZodEffects) {
field = field.innerType();
}

for (const key of joinName(null, name)) {
Expand Down

0 comments on commit 873a776

Please sign in to comment.