@buildnbuzz/buzzform 0.1.0 → 0.1.1
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/LICENSE +21 -21
- package/README.md +146 -138
- package/dist/{adapter-BT9v2OVg.d.mts → adapter-nQW28cyO.d.mts} +8 -2
- package/dist/{adapter-BT9v2OVg.d.ts → adapter-nQW28cyO.d.ts} +8 -2
- package/dist/chunk-63LF7K4O.mjs +171 -0
- package/dist/chunk-63LF7K4O.mjs.map +1 -0
- package/dist/chunk-HWDQN57Q.mjs +423 -0
- package/dist/chunk-HWDQN57Q.mjs.map +1 -0
- package/dist/{chunk-DDDGBPVU.mjs → chunk-IMJ5FRK5.mjs} +1 -1
- package/dist/chunk-IMJ5FRK5.mjs.map +1 -0
- package/dist/index.d.mts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +95 -176
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +12 -12
- package/dist/index.mjs.map +1 -1
- package/dist/rhf.d.mts +1 -1
- package/dist/rhf.d.ts +1 -1
- package/dist/rhf.js.map +1 -1
- package/dist/rhf.mjs +1 -1
- package/dist/rhf.mjs.map +1 -1
- package/dist/schema.d.mts +5 -32
- package/dist/schema.d.ts +5 -32
- package/dist/schema.js +160 -171
- package/dist/schema.js.map +1 -1
- package/dist/schema.mjs +18 -12
- package/dist/{utils-BgwyUFGB.d.mts → utils-CS2VrTJU.d.ts} +64 -51
- package/dist/{utils-DVLpbOoW.d.ts → utils-Dzp_68i3.d.mts} +64 -51
- package/dist/zod.d.mts +6 -24
- package/dist/zod.d.ts +6 -24
- package/dist/zod.js +151 -17
- package/dist/zod.js.map +1 -1
- package/dist/zod.mjs +69 -16
- package/dist/zod.mjs.map +1 -1
- package/package.json +4 -3
- package/dist/chunk-DDDGBPVU.mjs.map +0 -1
- package/dist/chunk-K42S5YX3.mjs +0 -599
- package/dist/chunk-K42S5YX3.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { F as Field, V as ValidationContext, K as FieldType, A as ArrayHelpers } from './adapter-
|
|
2
|
+
import { F as Field, T as TextField, E as EmailField, P as PasswordField, o as TextareaField, N as NumberField, D as DateField, p as DatetimeField, r as SelectField, s as CheckboxField, t as SwitchField, u as RadioField, w as TagsField, x as UploadField, G as GroupField, y as ArrayField, z as RowField, I as TabsField, J as CollapsibleField, V as ValidationContext, K as FieldType, i as ValidationFn, A as ArrayHelpers } from './adapter-nQW28cyO.mjs';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Maps a BuzzForm field definition to its corresponding Zod type.
|
|
@@ -105,85 +105,98 @@ type SchemaBuilderMap = {
|
|
|
105
105
|
type InferSchema<T extends z.ZodTypeAny> = z.infer<T>;
|
|
106
106
|
|
|
107
107
|
/**
|
|
108
|
-
*
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
* Strict field typing utilities for compile-time validation.
|
|
109
|
+
*/
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Maps field type literals to their corresponding interface.
|
|
113
|
+
*/
|
|
114
|
+
interface FieldTypeMap {
|
|
115
|
+
text: TextField;
|
|
116
|
+
email: EmailField;
|
|
117
|
+
password: PasswordField;
|
|
118
|
+
textarea: TextareaField;
|
|
119
|
+
number: NumberField;
|
|
120
|
+
date: DateField;
|
|
121
|
+
datetime: DatetimeField;
|
|
122
|
+
select: SelectField;
|
|
123
|
+
checkbox: CheckboxField;
|
|
124
|
+
switch: SwitchField;
|
|
125
|
+
radio: RadioField;
|
|
126
|
+
tags: TagsField;
|
|
127
|
+
upload: UploadField;
|
|
128
|
+
group: GroupField;
|
|
129
|
+
array: ArrayField;
|
|
130
|
+
row: RowField;
|
|
131
|
+
tabs: TabsField;
|
|
132
|
+
collapsible: CollapsibleField;
|
|
133
|
+
}
|
|
134
|
+
type FieldTypeLiteral = keyof FieldTypeMap;
|
|
135
|
+
/**
|
|
136
|
+
* Resolves a field object to its strict interface based on the `type` property.
|
|
137
|
+
*/
|
|
138
|
+
type StrictFieldByType<T> = T extends {
|
|
139
|
+
type: infer Type extends FieldTypeLiteral;
|
|
140
|
+
} ? FieldTypeMap[Type] : T extends Field ? T : never;
|
|
141
|
+
/**
|
|
142
|
+
* Validates an array of fields, ensuring each matches its declared type's interface.
|
|
143
|
+
*/
|
|
144
|
+
type StrictFieldArray<T extends readonly unknown[]> = {
|
|
145
|
+
[K in keyof T]: StrictFieldByType<T[K]>;
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Creates a Zod schema from field definitions with strict type validation.
|
|
112
150
|
*
|
|
113
151
|
* @example
|
|
114
|
-
* const
|
|
115
|
-
* { type: 'email', name: 'email', required: true },
|
|
152
|
+
* const schema = createSchema([
|
|
153
|
+
* { type: 'email', name: 'email', required: true },
|
|
116
154
|
* { type: 'password', name: 'password', minLength: 8 },
|
|
117
155
|
* ]);
|
|
118
156
|
*
|
|
119
|
-
* type
|
|
120
|
-
* // { email: string; password: string }
|
|
121
|
-
*
|
|
122
|
-
* // Use with useForm:
|
|
123
|
-
* const form = useForm({ schema: loginSchema });
|
|
124
|
-
*
|
|
125
|
-
* // Access fields for rendering:
|
|
126
|
-
* <FormRenderer fields={loginSchema.fields} />
|
|
157
|
+
* type FormData = z.infer<typeof schema>;
|
|
127
158
|
*/
|
|
128
|
-
declare function createSchema<const T extends readonly Field[]>(fields:
|
|
129
|
-
[K in keyof T]: T[K] extends Field ? T[K] : Field;
|
|
130
|
-
}]): z.ZodObject<FieldsToShape<T>> & {
|
|
159
|
+
declare function createSchema<const T extends readonly Field[]>(fields: StrictFieldArray<T> & T): z.ZodObject<FieldsToShape<T>> & {
|
|
131
160
|
fields: T;
|
|
132
161
|
};
|
|
133
162
|
|
|
134
163
|
/**
|
|
135
|
-
* Converts
|
|
136
|
-
*
|
|
164
|
+
* Converts field definitions to a Zod schema.
|
|
165
|
+
*
|
|
166
|
+
* Note: Custom validation (field.validate) is handled by the zodResolver,
|
|
167
|
+
* not at the schema level. This ensures custom validators run even when
|
|
168
|
+
* other fields have errors.
|
|
137
169
|
*/
|
|
138
170
|
declare function fieldsToZodSchema<T extends readonly Field[]>(fields: T): z.ZodObject<FieldsToShape<T>>;
|
|
139
171
|
|
|
140
|
-
/**
|
|
141
|
-
* A validation function that can be extracted from a field.
|
|
142
|
-
*/
|
|
143
172
|
type ExtractableValidationFn = (value: unknown, context: ValidationContext) => true | string | Promise<true | string>;
|
|
144
173
|
interface ExtractedValidationConfig {
|
|
145
|
-
/** The validation function (if any) */
|
|
146
174
|
fn?: ExtractableValidationFn;
|
|
147
|
-
/** Whether this is a live validation */
|
|
148
175
|
isLive: boolean;
|
|
149
|
-
/** Debounce milliseconds for live validation */
|
|
150
176
|
debounceMs?: number;
|
|
151
177
|
}
|
|
152
|
-
/**
|
|
153
|
-
* Extracts validation function and config from the unified validate property.
|
|
154
|
-
*/
|
|
155
178
|
declare function extractValidationConfig(validate?: unknown): ExtractedValidationConfig;
|
|
179
|
+
interface FieldValidator {
|
|
180
|
+
path: string;
|
|
181
|
+
fn: ValidationFn;
|
|
182
|
+
}
|
|
156
183
|
/**
|
|
157
|
-
*
|
|
158
|
-
* Standardizes the pattern across all field types.
|
|
184
|
+
* Recursively collects all field validators from a field array.
|
|
159
185
|
*/
|
|
160
|
-
declare function
|
|
186
|
+
declare function collectFieldValidators(fields: readonly Field[], basePath?: string): FieldValidator[];
|
|
161
187
|
/**
|
|
162
|
-
*
|
|
163
|
-
* Different field types have different "empty" representations.
|
|
188
|
+
* Gets the parent object containing the field at the given path.
|
|
164
189
|
*/
|
|
165
|
-
declare function
|
|
190
|
+
declare function getSiblingData(data: Record<string, unknown>, path: string): Record<string, unknown>;
|
|
166
191
|
/**
|
|
167
|
-
*
|
|
168
|
-
* Empty/null/undefined → undefined, otherwise Number().
|
|
192
|
+
* Gets a value at a dot-notation path.
|
|
169
193
|
*/
|
|
194
|
+
declare function getValueByPath(data: Record<string, unknown>, path: string): unknown;
|
|
195
|
+
declare function makeOptional(schema: z.ZodTypeAny, fieldType: FieldType): z.ZodTypeAny;
|
|
170
196
|
declare function coerceToNumber(val: unknown): number | undefined;
|
|
171
|
-
/**
|
|
172
|
-
* Coerces a value to a Date.
|
|
173
|
-
* Handles strings, numbers, and Date objects.
|
|
174
|
-
*/
|
|
175
197
|
declare function coerceToDate(val: unknown): Date | undefined;
|
|
176
|
-
/**
|
|
177
|
-
* Gets a human-readable error message for a regex pattern.
|
|
178
|
-
*/
|
|
179
198
|
declare function getPatternErrorMessage(pattern: string | RegExp): string;
|
|
180
|
-
/**
|
|
181
|
-
* Checks if a value is a File-like object.
|
|
182
|
-
*/
|
|
183
199
|
declare function isFileLike(value: unknown): value is File;
|
|
184
|
-
/**
|
|
185
|
-
* Validates file type against accept pattern.
|
|
186
|
-
*/
|
|
187
200
|
declare function isFileTypeAccepted(file: File, accept: string): boolean;
|
|
188
201
|
|
|
189
202
|
/**
|
|
@@ -230,4 +243,4 @@ declare function setNestedValue<T extends Record<string, unknown>>(obj: T, path:
|
|
|
230
243
|
*/
|
|
231
244
|
declare function formatBytes(bytes: number, decimals?: number): string;
|
|
232
245
|
|
|
233
|
-
export { type FieldToZod as F, type InferSchema as I, type SchemaBuilder as S, type FieldsToShape as a, type SchemaBuilderMap as b, createSchema as c,
|
|
246
|
+
export { type FieldToZod as F, type InferSchema as I, type SchemaBuilder as S, type FieldsToShape as a, type SchemaBuilderMap as b, createSchema as c, coerceToNumber as d, extractValidationConfig as e, fieldsToZodSchema as f, coerceToDate as g, getPatternErrorMessage as h, isFileLike as i, isFileTypeAccepted as j, createArrayHelpers as k, generateFieldId as l, makeOptional as m, getNestedValue as n, formatBytes as o, collectFieldValidators as p, getSiblingData as q, getValueByPath as r, setNestedValue as s, type FieldValidator as t };
|
package/dist/zod.d.mts
CHANGED
|
@@ -1,32 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { ZodSchema, z } from 'zod';
|
|
3
|
-
import { e as Resolver } from './adapter-
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export { ZodType as ZodSchema, z } from 'zod';
|
|
3
|
+
import { e as Resolver } from './adapter-nQW28cyO.mjs';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a validation resolver from a Zod schema.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - `{ errors }` if validation fails (with field-level error messages)
|
|
12
|
-
*
|
|
13
|
-
* @param schema - A Zod schema to validate against
|
|
14
|
-
* @returns A Resolver function compatible with BuzzForm adapters
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* import { z } from '@buildnbuzz/buzzform/zod';
|
|
18
|
-
* import { zodResolver } from '@buildnbuzz/buzzform';
|
|
19
|
-
*
|
|
20
|
-
* const schema = z.object({
|
|
21
|
-
* email: z.string().email('Invalid email'),
|
|
22
|
-
* age: z.number().min(18, 'Must be at least 18'),
|
|
23
|
-
* });
|
|
24
|
-
*
|
|
25
|
-
* const form = useRhf({
|
|
26
|
-
* resolver: zodResolver(schema),
|
|
27
|
-
* defaultValues: { email: '', age: 0 },
|
|
28
|
-
* });
|
|
9
|
+
* Custom field validators (field.validate) are run separately from the base schema
|
|
10
|
+
* to ensure they execute even when other fields have errors.
|
|
29
11
|
*/
|
|
30
|
-
declare function zodResolver<TData>(schema:
|
|
12
|
+
declare function zodResolver<TData>(schema: z.ZodType<TData>): Resolver<TData>;
|
|
31
13
|
|
|
32
14
|
export { zodResolver };
|
package/dist/zod.d.ts
CHANGED
|
@@ -1,32 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { ZodSchema, z } from 'zod';
|
|
3
|
-
import { e as Resolver } from './adapter-
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export { ZodType as ZodSchema, z } from 'zod';
|
|
3
|
+
import { e as Resolver } from './adapter-nQW28cyO.js';
|
|
4
4
|
import 'react';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Creates a validation resolver from a Zod schema.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* - `{ errors }` if validation fails (with field-level error messages)
|
|
12
|
-
*
|
|
13
|
-
* @param schema - A Zod schema to validate against
|
|
14
|
-
* @returns A Resolver function compatible with BuzzForm adapters
|
|
15
|
-
*
|
|
16
|
-
* @example
|
|
17
|
-
* import { z } from '@buildnbuzz/buzzform/zod';
|
|
18
|
-
* import { zodResolver } from '@buildnbuzz/buzzform';
|
|
19
|
-
*
|
|
20
|
-
* const schema = z.object({
|
|
21
|
-
* email: z.string().email('Invalid email'),
|
|
22
|
-
* age: z.number().min(18, 'Must be at least 18'),
|
|
23
|
-
* });
|
|
24
|
-
*
|
|
25
|
-
* const form = useRhf({
|
|
26
|
-
* resolver: zodResolver(schema),
|
|
27
|
-
* defaultValues: { email: '', age: 0 },
|
|
28
|
-
* });
|
|
9
|
+
* Custom field validators (field.validate) are run separately from the base schema
|
|
10
|
+
* to ensure they execute even when other fields have errors.
|
|
29
11
|
*/
|
|
30
|
-
declare function zodResolver<TData>(schema:
|
|
12
|
+
declare function zodResolver<TData>(schema: z.ZodType<TData>): Resolver<TData>;
|
|
31
13
|
|
|
32
14
|
export { zodResolver };
|
package/dist/zod.js
CHANGED
|
@@ -20,30 +20,158 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/resolvers/zod.ts
|
|
21
21
|
var zod_exports = {};
|
|
22
22
|
__export(zod_exports, {
|
|
23
|
-
z: () =>
|
|
23
|
+
z: () => import_zod2.z,
|
|
24
24
|
zodResolver: () => zodResolver
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(zod_exports);
|
|
27
|
+
|
|
28
|
+
// src/schema/helpers.ts
|
|
27
29
|
var import_zod = require("zod");
|
|
30
|
+
function extractValidationConfig(validate) {
|
|
31
|
+
if (!validate) {
|
|
32
|
+
return { fn: void 0, isLive: false };
|
|
33
|
+
}
|
|
34
|
+
if (typeof validate === "function") {
|
|
35
|
+
return { fn: validate, isLive: false };
|
|
36
|
+
}
|
|
37
|
+
if (typeof validate === "object" && "fn" in validate) {
|
|
38
|
+
const obj = validate;
|
|
39
|
+
const fn = typeof obj.fn === "function" ? obj.fn : void 0;
|
|
40
|
+
if (!obj.live) {
|
|
41
|
+
return { fn, isLive: false };
|
|
42
|
+
}
|
|
43
|
+
const debounceMs = typeof obj.live === "object" ? obj.live.debounceMs : void 0;
|
|
44
|
+
return { fn, isLive: true, debounceMs };
|
|
45
|
+
}
|
|
46
|
+
return { fn: void 0, isLive: false };
|
|
47
|
+
}
|
|
48
|
+
function collectFieldValidators(fields, basePath = "") {
|
|
49
|
+
const validators = [];
|
|
50
|
+
for (const field of fields) {
|
|
51
|
+
if ("name" in field && field.name) {
|
|
52
|
+
const fieldPath = basePath ? `${basePath}.${field.name}` : field.name;
|
|
53
|
+
if ("validate" in field && field.validate) {
|
|
54
|
+
const config = extractValidationConfig(field.validate);
|
|
55
|
+
if (config.fn) {
|
|
56
|
+
validators.push({
|
|
57
|
+
path: fieldPath,
|
|
58
|
+
fn: config.fn
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
if (field.type === "group" && "fields" in field) {
|
|
63
|
+
validators.push(...collectFieldValidators(field.fields, fieldPath));
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (field.type === "row" && "fields" in field) {
|
|
67
|
+
validators.push(...collectFieldValidators(field.fields, basePath));
|
|
68
|
+
}
|
|
69
|
+
if (field.type === "collapsible" && "fields" in field) {
|
|
70
|
+
validators.push(...collectFieldValidators(field.fields, basePath));
|
|
71
|
+
}
|
|
72
|
+
if (field.type === "tabs" && "tabs" in field) {
|
|
73
|
+
for (const tab of field.tabs) {
|
|
74
|
+
const tabPath = tab.name ? basePath ? `${basePath}.${tab.name}` : tab.name : basePath;
|
|
75
|
+
validators.push(...collectFieldValidators(tab.fields, tabPath));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return validators;
|
|
80
|
+
}
|
|
81
|
+
function getSiblingData(data, path) {
|
|
82
|
+
const parts = path.split(".");
|
|
83
|
+
if (parts.length <= 1) {
|
|
84
|
+
return data;
|
|
85
|
+
}
|
|
86
|
+
const parentParts = parts.slice(0, -1);
|
|
87
|
+
let current = data;
|
|
88
|
+
for (const part of parentParts) {
|
|
89
|
+
if (current && typeof current === "object" && current !== null) {
|
|
90
|
+
current = current[part];
|
|
91
|
+
} else {
|
|
92
|
+
return {};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (current && typeof current === "object" && current !== null) {
|
|
96
|
+
return current;
|
|
97
|
+
}
|
|
98
|
+
return {};
|
|
99
|
+
}
|
|
100
|
+
function getValueByPath(data, path) {
|
|
101
|
+
const parts = path.split(".");
|
|
102
|
+
let current = data;
|
|
103
|
+
for (const part of parts) {
|
|
104
|
+
if (current && typeof current === "object" && current !== null) {
|
|
105
|
+
current = current[part];
|
|
106
|
+
} else {
|
|
107
|
+
return void 0;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return current;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/resolvers/zod.ts
|
|
114
|
+
var import_zod2 = require("zod");
|
|
28
115
|
function zodResolver(schema) {
|
|
116
|
+
const schemaWithFields = schema;
|
|
117
|
+
const fieldValidators = schemaWithFields.fields ? collectFieldValidators(schemaWithFields.fields) : [];
|
|
29
118
|
return async (values) => {
|
|
119
|
+
const errors = {};
|
|
120
|
+
let parsedValues;
|
|
30
121
|
try {
|
|
31
|
-
|
|
32
|
-
return {
|
|
33
|
-
values: parsed,
|
|
34
|
-
errors: {}
|
|
35
|
-
};
|
|
122
|
+
parsedValues = await schema.parseAsync(values);
|
|
36
123
|
} catch (error) {
|
|
37
124
|
if (isZodError(error)) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
125
|
+
Object.assign(errors, mapZodErrors(error));
|
|
126
|
+
} else {
|
|
127
|
+
throw error;
|
|
42
128
|
}
|
|
43
|
-
throw error;
|
|
44
129
|
}
|
|
130
|
+
if (fieldValidators.length > 0) {
|
|
131
|
+
const customErrors = await runFieldValidators(
|
|
132
|
+
fieldValidators,
|
|
133
|
+
values
|
|
134
|
+
);
|
|
135
|
+
for (const [path, error] of Object.entries(customErrors)) {
|
|
136
|
+
if (!errors[path]) {
|
|
137
|
+
errors[path] = error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (Object.keys(errors).length === 0 && parsedValues !== void 0) {
|
|
142
|
+
return { values: parsedValues, errors: {} };
|
|
143
|
+
}
|
|
144
|
+
return { values: {}, errors };
|
|
45
145
|
};
|
|
46
146
|
}
|
|
147
|
+
async function runFieldValidators(validators, data) {
|
|
148
|
+
const errors = {};
|
|
149
|
+
await Promise.all(
|
|
150
|
+
validators.map(async ({ path, fn }) => {
|
|
151
|
+
const value = getValueByPath(data, path);
|
|
152
|
+
const siblingData = getSiblingData(data, path);
|
|
153
|
+
try {
|
|
154
|
+
const result = await fn(value, {
|
|
155
|
+
data,
|
|
156
|
+
siblingData,
|
|
157
|
+
path: path.split(".")
|
|
158
|
+
});
|
|
159
|
+
if (result !== true) {
|
|
160
|
+
errors[path] = {
|
|
161
|
+
type: "custom",
|
|
162
|
+
message: typeof result === "string" ? result : "Validation failed"
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
} catch (error) {
|
|
166
|
+
errors[path] = {
|
|
167
|
+
type: "custom",
|
|
168
|
+
message: error instanceof Error ? error.message : "Validation error"
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
})
|
|
172
|
+
);
|
|
173
|
+
return errors;
|
|
174
|
+
}
|
|
47
175
|
function mapZodErrors(error) {
|
|
48
176
|
const errors = {};
|
|
49
177
|
for (const issue of error.issues) {
|
|
@@ -63,18 +191,24 @@ function issuePath(issue) {
|
|
|
63
191
|
function issueType(issue) {
|
|
64
192
|
switch (issue.code) {
|
|
65
193
|
case "invalid_type":
|
|
66
|
-
if (issue.received === "undefined") return "required";
|
|
194
|
+
if ("received" in issue && issue.received === "undefined") return "required";
|
|
67
195
|
return "type";
|
|
68
196
|
case "too_small":
|
|
69
|
-
|
|
197
|
+
if ("origin" in issue && issue.origin === "string") return "minLength";
|
|
198
|
+
return "min";
|
|
70
199
|
case "too_big":
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
200
|
+
if ("origin" in issue && issue.origin === "string") return "maxLength";
|
|
201
|
+
return "max";
|
|
202
|
+
case "invalid_format": {
|
|
203
|
+
const formatIssue = issue;
|
|
204
|
+
if (formatIssue.format === "regex") return "pattern";
|
|
205
|
+
if (typeof formatIssue.format === "string") return formatIssue.format;
|
|
206
|
+
return "pattern";
|
|
207
|
+
}
|
|
74
208
|
case "custom":
|
|
75
209
|
return "custom";
|
|
76
210
|
default:
|
|
77
|
-
return issue.code;
|
|
211
|
+
return issue.code ?? "validation";
|
|
78
212
|
}
|
|
79
213
|
}
|
|
80
214
|
function isZodError(error) {
|
package/dist/zod.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resolvers/zod.ts"],"sourcesContent":["import type { ZodSchema, ZodError, ZodIssue } from 'zod';\r\nimport type { Resolver, FieldError, ResolverResult } from '../types';\r\n\r\n// =============================================================================\r\n// ZOD RESOLVER\r\n// =============================================================================\r\n\r\n/**\r\n * Creates a validation resolver from a Zod schema.\r\n * \r\n * The resolver validates form values against the schema and returns:\r\n * - `{ values }` if validation passes (with transformed/parsed data)\r\n * - `{ errors }` if validation fails (with field-level error messages)\r\n * \r\n * @param schema - A Zod schema to validate against\r\n * @returns A Resolver function compatible with BuzzForm adapters\r\n * \r\n * @example\r\n * import { z } from '@buildnbuzz/buzzform/zod';\r\n * import { zodResolver } from '@buildnbuzz/buzzform';\r\n * \r\n * const schema = z.object({\r\n * email: z.string().email('Invalid email'),\r\n * age: z.number().min(18, 'Must be at least 18'),\r\n * });\r\n * \r\n * const form = useRhf({\r\n * resolver: zodResolver(schema),\r\n * defaultValues: { email: '', age: 0 },\r\n * });\r\n */\r\nexport function zodResolver<TData>(\r\n schema: ZodSchema<TData>\r\n): Resolver<TData> {\r\n return async (values: TData): Promise<ResolverResult<TData>> => {\r\n try {\r\n // Parse and validate - this also transforms the data\r\n const parsed = await schema.parseAsync(values);\r\n\r\n return {\r\n values: parsed,\r\n errors: {},\r\n };\r\n } catch (error) {\r\n // Handle Zod validation errors\r\n if (isZodError(error)) {\r\n return {\r\n values: {} as TData,\r\n errors: mapZodErrors(error),\r\n };\r\n }\r\n\r\n // Re-throw unexpected errors\r\n throw error;\r\n }\r\n };\r\n}\r\n\r\n// =============================================================================\r\n// ERROR MAPPING\r\n// =============================================================================\r\n\r\n/**\r\n * Maps Zod validation errors to our FieldError format.\r\n * Handles nested paths (e.g., \"address.city\", \"items.0.name\").\r\n */\r\nfunction mapZodErrors(error: ZodError): Record<string, FieldError> {\r\n const errors: Record<string, FieldError> = {};\r\n\r\n for (const issue of error.issues) {\r\n const path = issuePath(issue);\r\n\r\n // Only set the first error for each path\r\n if (!errors[path]) {\r\n errors[path] = {\r\n type: issueType(issue),\r\n message: issue.message,\r\n };\r\n }\r\n }\r\n\r\n return errors;\r\n}\r\n\r\n/**\r\n * Convert Zod issue path to dot-notation string.\r\n * ['address', 'city'] → 'address.city'\r\n * ['items', 0, 'name'] → 'items.0.name'\r\n */\r\nfunction issuePath(issue: ZodIssue): string {\r\n return issue.path.map(String).join('.');\r\n}\r\n\r\n/**\r\n * Map Zod issue code to a simpler type string.\r\n */\r\nfunction issueType(issue: ZodIssue): string {\r\n switch (issue.code) {\r\n case 'invalid_type':\r\n if (issue.received === 'undefined') return 'required';\r\n return 'type';\r\n case 'too_small':\r\n return issue.type === 'string' ? 'minLength' : 'min';\r\n case 'too_big':\r\n return issue.type === 'string' ? 'maxLength' : 'max';\r\n case 'invalid_string':\r\n return issue.validation?.toString() || 'pattern';\r\n case 'custom':\r\n return 'custom';\r\n default:\r\n return issue.code;\r\n }\r\n}\r\n\r\n/**\r\n * Type guard to check if an error is a ZodError.\r\n */\r\nfunction isZodError(error: unknown): error is ZodError {\r\n return (\r\n typeof error === 'object' &&\r\n error !== null &&\r\n 'issues' in error &&\r\n Array.isArray((error as ZodError).issues)\r\n );\r\n}\r\n\r\n// =============================================================================\r\n// RE-EXPORTS FOR CONVENIENCE\r\n// =============================================================================\r\n\r\nexport type { ZodSchema } from 'zod';\r\nexport { z } from 'zod';"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAmIA,iBAAkB;AApGX,SAAS,YACZ,QACe;AACf,SAAO,OAAO,WAAkD;AAC5D,QAAI;AAEA,YAAM,SAAS,MAAM,OAAO,WAAW,MAAM;AAE7C,aAAO;AAAA,QACH,QAAQ;AAAA,QACR,QAAQ,CAAC;AAAA,MACb;AAAA,IACJ,SAAS,OAAO;AAEZ,UAAI,WAAW,KAAK,GAAG;AACnB,eAAO;AAAA,UACH,QAAQ,CAAC;AAAA,UACT,QAAQ,aAAa,KAAK;AAAA,QAC9B;AAAA,MACJ;AAGA,YAAM;AAAA,IACV;AAAA,EACJ;AACJ;AAUA,SAAS,aAAa,OAA6C;AAC/D,QAAM,SAAqC,CAAC;AAE5C,aAAW,SAAS,MAAM,QAAQ;AAC9B,UAAM,OAAO,UAAU,KAAK;AAG5B,QAAI,CAAC,OAAO,IAAI,GAAG;AACf,aAAO,IAAI,IAAI;AAAA,QACX,MAAM,UAAU,KAAK;AAAA,QACrB,SAAS,MAAM;AAAA,MACnB;AAAA,IACJ;AAAA,EACJ;AAEA,SAAO;AACX;AAOA,SAAS,UAAU,OAAyB;AACxC,SAAO,MAAM,KAAK,IAAI,MAAM,EAAE,KAAK,GAAG;AAC1C;AAKA,SAAS,UAAU,OAAyB;AACxC,UAAQ,MAAM,MAAM;AAAA,IAChB,KAAK;AACD,UAAI,MAAM,aAAa,YAAa,QAAO;AAC3C,aAAO;AAAA,IACX,KAAK;AACD,aAAO,MAAM,SAAS,WAAW,cAAc;AAAA,IACnD,KAAK;AACD,aAAO,MAAM,SAAS,WAAW,cAAc;AAAA,IACnD,KAAK;AACD,aAAO,MAAM,YAAY,SAAS,KAAK;AAAA,IAC3C,KAAK;AACD,aAAO;AAAA,IACX;AACI,aAAO,MAAM;AAAA,EACrB;AACJ;AAKA,SAAS,WAAW,OAAmC;AACnD,SACI,OAAO,UAAU,YACjB,UAAU,QACV,YAAY,SACZ,MAAM,QAAS,MAAmB,MAAM;AAEhD;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/resolvers/zod.ts","../src/schema/helpers.ts"],"sourcesContent":["import { type z } from 'zod';\nimport type { Resolver, FieldError, ResolverResult, Field } from '../types';\nimport { collectFieldValidators, getSiblingData, getValueByPath, type FieldValidator } from '../schema/helpers';\n\n// =============================================================================\n// ZOD RESOLVER\n// =============================================================================\n\ntype ZodIssue = z.core.$ZodIssue;\ntype ZodError = z.ZodError;\n\n// Schema with attached fields from createSchema()\ntype SchemaWithFields = z.ZodType & { fields?: readonly Field[] };\n\n/**\n * Creates a validation resolver from a Zod schema.\n * \n * Custom field validators (field.validate) are run separately from the base schema\n * to ensure they execute even when other fields have errors.\n */\nexport function zodResolver<TData>(\n schema: z.ZodType<TData>\n): Resolver<TData> {\n // Extract field validators from schema.fields (if present)\n const schemaWithFields = schema as SchemaWithFields;\n const fieldValidators = schemaWithFields.fields\n ? collectFieldValidators(schemaWithFields.fields)\n : [];\n\n return async (values: TData): Promise<ResolverResult<TData>> => {\n const errors: Record<string, FieldError> = {};\n let parsedValues: TData | undefined;\n\n // Phase 1: Run base schema validation\n try {\n parsedValues = await schema.parseAsync(values);\n } catch (error) {\n if (isZodError(error)) {\n Object.assign(errors, mapZodErrors(error));\n } else {\n throw error;\n }\n }\n\n // Phase 2: Run custom field validators (always runs, even if base fails)\n if (fieldValidators.length > 0) {\n const customErrors = await runFieldValidators(\n fieldValidators,\n values as Record<string, unknown>\n );\n // Merge, but don't overwrite existing errors\n for (const [path, error] of Object.entries(customErrors)) {\n if (!errors[path]) {\n errors[path] = error;\n }\n }\n }\n\n // Return result\n if (Object.keys(errors).length === 0 && parsedValues !== undefined) {\n return { values: parsedValues, errors: {} };\n }\n\n return { values: {} as TData, errors };\n };\n}\n\n/**\n * Run all field validators and collect errors.\n */\nasync function runFieldValidators(\n validators: FieldValidator[],\n data: Record<string, unknown>\n): Promise<Record<string, FieldError>> {\n const errors: Record<string, FieldError> = {};\n\n await Promise.all(\n validators.map(async ({ path, fn }) => {\n const value = getValueByPath(data, path);\n const siblingData = getSiblingData(data, path);\n\n try {\n const result = await fn(value, {\n data,\n siblingData,\n path: path.split('.'),\n });\n\n if (result !== true) {\n errors[path] = {\n type: 'custom',\n message: typeof result === 'string' ? result : 'Validation failed',\n };\n }\n } catch (error) {\n errors[path] = {\n type: 'custom',\n message: error instanceof Error ? error.message : 'Validation error',\n };\n }\n })\n );\n\n return errors;\n}\n\n// =============================================================================\n// ERROR MAPPING\n// =============================================================================\n\nfunction mapZodErrors(error: ZodError): Record<string, FieldError> {\n const errors: Record<string, FieldError> = {};\n\n for (const issue of error.issues) {\n const path = issuePath(issue);\n if (!errors[path]) {\n errors[path] = {\n type: issueType(issue),\n message: issue.message,\n };\n }\n }\n\n return errors;\n}\n\nfunction issuePath(issue: ZodIssue): string {\n return issue.path.map(String).join('.');\n}\n\nfunction issueType(issue: ZodIssue): string {\n switch (issue.code) {\n case 'invalid_type':\n if ('received' in issue && issue.received === 'undefined') return 'required';\n return 'type';\n case 'too_small':\n if ('origin' in issue && issue.origin === 'string') return 'minLength';\n return 'min';\n case 'too_big':\n if ('origin' in issue && issue.origin === 'string') return 'maxLength';\n return 'max';\n case 'invalid_format': {\n const formatIssue = issue as { format?: string };\n if (formatIssue.format === 'regex') return 'pattern';\n if (typeof formatIssue.format === 'string') return formatIssue.format;\n return 'pattern';\n }\n case 'custom':\n return 'custom';\n default:\n return issue.code ?? 'validation';\n }\n}\n\nfunction isZodError(error: unknown): error is ZodError {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'issues' in error &&\n Array.isArray((error as ZodError).issues)\n );\n}\n\n// =============================================================================\n// RE-EXPORTS\n// =============================================================================\n\nexport type { ZodType as ZodSchema } from 'zod';\nexport { z } from 'zod';","import { z } from 'zod';\nimport type { Field, FieldType, ValidationContext, ValidationFn } from '../types';\n\n// =============================================================================\n// VALIDATION CONFIG EXTRACTION\n// =============================================================================\n\ntype ExtractableValidationFn = (\n value: unknown,\n context: ValidationContext\n) => true | string | Promise<true | string>;\n\nexport interface ExtractedValidationConfig {\n fn?: ExtractableValidationFn;\n isLive: boolean;\n debounceMs?: number;\n}\n\nexport function extractValidationConfig(\n validate?: unknown\n): ExtractedValidationConfig {\n if (!validate) {\n return { fn: undefined, isLive: false };\n }\n\n if (typeof validate === 'function') {\n return { fn: validate as ExtractableValidationFn, isLive: false };\n }\n\n if (typeof validate === 'object' && 'fn' in validate) {\n const obj = validate as { fn?: unknown; live?: boolean | { debounceMs?: number } };\n const fn = typeof obj.fn === 'function' ? obj.fn as ExtractableValidationFn : undefined;\n\n if (!obj.live) {\n return { fn, isLive: false };\n }\n\n const debounceMs = typeof obj.live === 'object' ? obj.live.debounceMs : undefined;\n return { fn, isLive: true, debounceMs };\n }\n\n return { fn: undefined, isLive: false };\n}\n\n// =============================================================================\n// FIELD VALIDATOR COLLECTION\n// =============================================================================\n\nexport interface FieldValidator {\n path: string;\n fn: ValidationFn;\n}\n\n/**\n * Recursively collects all field validators from a field array.\n */\nexport function collectFieldValidators(\n fields: readonly Field[],\n basePath: string = ''\n): FieldValidator[] {\n const validators: FieldValidator[] = [];\n\n for (const field of fields) {\n if ('name' in field && field.name) {\n const fieldPath = basePath ? `${basePath}.${field.name}` : field.name;\n\n if ('validate' in field && field.validate) {\n const config = extractValidationConfig(field.validate);\n if (config.fn) {\n validators.push({\n path: fieldPath,\n fn: config.fn as ValidationFn,\n });\n }\n }\n\n if (field.type === 'group' && 'fields' in field) {\n validators.push(...collectFieldValidators(field.fields, fieldPath));\n }\n }\n\n // Layout fields pass through without adding to path\n if (field.type === 'row' && 'fields' in field) {\n validators.push(...collectFieldValidators(field.fields, basePath));\n }\n if (field.type === 'collapsible' && 'fields' in field) {\n validators.push(...collectFieldValidators(field.fields, basePath));\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const tabPath = tab.name\n ? (basePath ? `${basePath}.${tab.name}` : tab.name)\n : basePath;\n validators.push(...collectFieldValidators(tab.fields, tabPath));\n }\n }\n }\n\n return validators;\n}\n\n// =============================================================================\n// SIBLING DATA EXTRACTION\n// =============================================================================\n\n/**\n * Gets the parent object containing the field at the given path.\n */\nexport function getSiblingData(\n data: Record<string, unknown>,\n path: string\n): Record<string, unknown> {\n const parts = path.split('.');\n\n if (parts.length <= 1) {\n return data;\n }\n\n const parentParts = parts.slice(0, -1);\n let current: unknown = data;\n\n for (const part of parentParts) {\n if (current && typeof current === 'object' && current !== null) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return {};\n }\n }\n\n if (current && typeof current === 'object' && current !== null) {\n return current as Record<string, unknown>;\n }\n\n return {};\n}\n\n/**\n * Gets a value at a dot-notation path.\n */\nexport function getValueByPath(\n data: Record<string, unknown>,\n path: string\n): unknown {\n const parts = path.split('.');\n let current: unknown = data;\n\n for (const part of parts) {\n if (current && typeof current === 'object' && current !== null) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n\n return current;\n}\n\n/**\n * Creates a superRefine that runs all field validators with full form context.\n */\nexport function createRootValidationRefinement(\n validators: FieldValidator[]\n): (data: Record<string, unknown>, ctx: z.RefinementCtx) => Promise<void> {\n return async (data, ctx) => {\n const validationPromises = validators.map(async ({ path, fn }) => {\n const value = getValueByPath(data, path);\n const siblingData = getSiblingData(data, path);\n\n try {\n const result = await fn(value, {\n data,\n siblingData,\n path: path.split('.'),\n });\n\n if (result !== true) {\n ctx.addIssue({\n code: 'custom',\n path: path.split('.'),\n message: typeof result === 'string' ? result : 'Validation failed',\n });\n }\n } catch (error) {\n ctx.addIssue({\n code: 'custom',\n path: path.split('.'),\n message: error instanceof Error ? error.message : 'Validation error',\n });\n }\n });\n\n await Promise.all(validationPromises);\n };\n}\n\n// =============================================================================\n// OPTIONAL HANDLING\n// =============================================================================\n\nexport function makeOptional(\n schema: z.ZodTypeAny,\n fieldType: FieldType\n): z.ZodTypeAny {\n switch (fieldType) {\n case 'text':\n case 'textarea':\n case 'email':\n case 'password':\n return schema.optional().or(z.literal(''));\n\n case 'number':\n case 'date':\n case 'select':\n case 'radio':\n return schema.optional().nullable();\n\n case 'checkbox':\n case 'switch':\n return schema;\n\n case 'tags':\n case 'array':\n return schema.optional().default([]);\n\n case 'upload':\n return schema.optional().nullable();\n\n default:\n return schema.optional();\n }\n}\n\n// =============================================================================\n// COERCION HELPERS\n// =============================================================================\n\nexport function coerceToNumber(val: unknown): number | undefined {\n if (val === '' || val === null || val === undefined) {\n return undefined;\n }\n const num = Number(val);\n return isNaN(num) ? undefined : num;\n}\n\nexport function coerceToDate(val: unknown): Date | undefined {\n if (val === '' || val === null || val === undefined) {\n return undefined;\n }\n if (val instanceof Date) {\n return isNaN(val.getTime()) ? undefined : val;\n }\n if (typeof val === 'string' || typeof val === 'number') {\n const d = new Date(val);\n return isNaN(d.getTime()) ? undefined : d;\n }\n return undefined;\n}\n\n// =============================================================================\n// PATTERN VALIDATION\n// =============================================================================\n\nconst PATTERN_MESSAGES: Record<string, string> = {\n '^[a-zA-Z0-9_]+$': 'Only letters, numbers, and underscores allowed',\n '^[a-z0-9-]+$': 'Only lowercase letters, numbers, and hyphens allowed',\n '^\\\\S+@\\\\S+\\\\.\\\\S+$': 'Invalid email format',\n '^https?://': 'Must start with http:// or https://',\n};\n\nexport function getPatternErrorMessage(pattern: string | RegExp): string {\n const patternStr = typeof pattern === 'string' ? pattern : pattern.source;\n return PATTERN_MESSAGES[patternStr] || `Must match pattern: ${patternStr}`;\n}\n\n// =============================================================================\n// FILE VALIDATION HELPERS\n// =============================================================================\n\nexport function isFileLike(value: unknown): value is File {\n return (\n typeof value === 'object' &&\n value !== null &&\n 'name' in value &&\n 'size' in value &&\n 'type' in value\n );\n}\n\nexport function isFileTypeAccepted(\n file: File,\n accept: string\n): boolean {\n if (accept === '*' || !accept) return true;\n\n const acceptTypes = accept.split(',').map(t => t.trim().toLowerCase());\n const fileType = file.type.toLowerCase();\n const fileName = file.name.toLowerCase();\n\n return acceptTypes.some(acceptType => {\n if (acceptType.endsWith('/*')) {\n const category = acceptType.replace('/*', '');\n return fileType.startsWith(category + '/');\n }\n if (acceptType.startsWith('.')) {\n return fileName.endsWith(acceptType);\n }\n return fileType === acceptType;\n });\n}\n"],"mappings":"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","names":["import_zod"]}
|
package/dist/zod.mjs
CHANGED
|
@@ -1,24 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collectFieldValidators,
|
|
3
|
+
getSiblingData,
|
|
4
|
+
getValueByPath
|
|
5
|
+
} from "./chunk-63LF7K4O.mjs";
|
|
6
|
+
|
|
1
7
|
// src/resolvers/zod.ts
|
|
2
8
|
import { z } from "zod";
|
|
3
9
|
function zodResolver(schema) {
|
|
10
|
+
const schemaWithFields = schema;
|
|
11
|
+
const fieldValidators = schemaWithFields.fields ? collectFieldValidators(schemaWithFields.fields) : [];
|
|
4
12
|
return async (values) => {
|
|
13
|
+
const errors = {};
|
|
14
|
+
let parsedValues;
|
|
5
15
|
try {
|
|
6
|
-
|
|
7
|
-
return {
|
|
8
|
-
values: parsed,
|
|
9
|
-
errors: {}
|
|
10
|
-
};
|
|
16
|
+
parsedValues = await schema.parseAsync(values);
|
|
11
17
|
} catch (error) {
|
|
12
18
|
if (isZodError(error)) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
Object.assign(errors, mapZodErrors(error));
|
|
20
|
+
} else {
|
|
21
|
+
throw error;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
if (fieldValidators.length > 0) {
|
|
25
|
+
const customErrors = await runFieldValidators(
|
|
26
|
+
fieldValidators,
|
|
27
|
+
values
|
|
28
|
+
);
|
|
29
|
+
for (const [path, error] of Object.entries(customErrors)) {
|
|
30
|
+
if (!errors[path]) {
|
|
31
|
+
errors[path] = error;
|
|
32
|
+
}
|
|
17
33
|
}
|
|
18
|
-
throw error;
|
|
19
34
|
}
|
|
35
|
+
if (Object.keys(errors).length === 0 && parsedValues !== void 0) {
|
|
36
|
+
return { values: parsedValues, errors: {} };
|
|
37
|
+
}
|
|
38
|
+
return { values: {}, errors };
|
|
20
39
|
};
|
|
21
40
|
}
|
|
41
|
+
async function runFieldValidators(validators, data) {
|
|
42
|
+
const errors = {};
|
|
43
|
+
await Promise.all(
|
|
44
|
+
validators.map(async ({ path, fn }) => {
|
|
45
|
+
const value = getValueByPath(data, path);
|
|
46
|
+
const siblingData = getSiblingData(data, path);
|
|
47
|
+
try {
|
|
48
|
+
const result = await fn(value, {
|
|
49
|
+
data,
|
|
50
|
+
siblingData,
|
|
51
|
+
path: path.split(".")
|
|
52
|
+
});
|
|
53
|
+
if (result !== true) {
|
|
54
|
+
errors[path] = {
|
|
55
|
+
type: "custom",
|
|
56
|
+
message: typeof result === "string" ? result : "Validation failed"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
} catch (error) {
|
|
60
|
+
errors[path] = {
|
|
61
|
+
type: "custom",
|
|
62
|
+
message: error instanceof Error ? error.message : "Validation error"
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
})
|
|
66
|
+
);
|
|
67
|
+
return errors;
|
|
68
|
+
}
|
|
22
69
|
function mapZodErrors(error) {
|
|
23
70
|
const errors = {};
|
|
24
71
|
for (const issue of error.issues) {
|
|
@@ -38,18 +85,24 @@ function issuePath(issue) {
|
|
|
38
85
|
function issueType(issue) {
|
|
39
86
|
switch (issue.code) {
|
|
40
87
|
case "invalid_type":
|
|
41
|
-
if (issue.received === "undefined") return "required";
|
|
88
|
+
if ("received" in issue && issue.received === "undefined") return "required";
|
|
42
89
|
return "type";
|
|
43
90
|
case "too_small":
|
|
44
|
-
|
|
91
|
+
if ("origin" in issue && issue.origin === "string") return "minLength";
|
|
92
|
+
return "min";
|
|
45
93
|
case "too_big":
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
94
|
+
if ("origin" in issue && issue.origin === "string") return "maxLength";
|
|
95
|
+
return "max";
|
|
96
|
+
case "invalid_format": {
|
|
97
|
+
const formatIssue = issue;
|
|
98
|
+
if (formatIssue.format === "regex") return "pattern";
|
|
99
|
+
if (typeof formatIssue.format === "string") return formatIssue.format;
|
|
100
|
+
return "pattern";
|
|
101
|
+
}
|
|
49
102
|
case "custom":
|
|
50
103
|
return "custom";
|
|
51
104
|
default:
|
|
52
|
-
return issue.code;
|
|
105
|
+
return issue.code ?? "validation";
|
|
53
106
|
}
|
|
54
107
|
}
|
|
55
108
|
function isZodError(error) {
|