@volverjs/form-vue 1.0.0 → 1.1.0-beta.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/README.md +33 -9
- package/dist/VvForm.d.ts +29 -30
- package/dist/VvFormField.d.ts +14 -15
- package/dist/VvFormFieldsGroup.d.ts +14 -15
- package/dist/VvFormTemplate.d.ts +3 -4
- package/dist/VvFormWrapper.d.ts +13 -14
- package/dist/index.d.ts +160 -160
- package/dist/index.es.js +3958 -600
- package/dist/index.umd.js +3 -1
- package/dist/types.d.ts +32 -24
- package/dist/utils.d.ts +11 -3
- package/package.json +7 -7
- package/src/VvForm.ts +24 -23
- package/src/VvFormField.ts +9 -8
- package/src/VvFormFieldsGroup.ts +13 -12
- package/src/VvFormTemplate.ts +10 -4
- package/src/VvFormWrapper.ts +8 -7
- package/src/index.ts +3 -8
- package/src/types.ts +57 -25
- package/src/utils.ts +200 -40
package/src/utils.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
2
|
ZodDefault,
|
|
4
3
|
ZodObject,
|
|
5
4
|
ZodEffects,
|
|
@@ -8,40 +7,180 @@ import {
|
|
|
8
7
|
ZodOptional,
|
|
9
8
|
ZodRecord,
|
|
10
9
|
ZodArray,
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
import
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
ZodError,
|
|
11
|
+
} from 'zod/v3'
|
|
12
|
+
import {
|
|
13
|
+
$ZodError,
|
|
14
|
+
safeParse as z4SafeParse,
|
|
15
|
+
safeParseAsync as z4SafeParseAsync,
|
|
16
|
+
formatError as z4FormatError,
|
|
17
|
+
} from 'zod/v4/core'
|
|
18
|
+
import { toJSONSchema as z4toJSONSchema } from 'zod/v4'
|
|
19
|
+
import type * as z3 from 'zod/v3'
|
|
20
|
+
import type * as z4 from 'zod/v4/core'
|
|
21
|
+
import type { FormSchema, InferSchema, VvZodError, ZodIssue } from './types'
|
|
22
|
+
|
|
23
|
+
// Helper function to get the inner type of a Zod v3 schema
|
|
24
|
+
const getZod3SchemaInnerType = <Type extends z3.ZodTypeAny>(
|
|
25
|
+
schema:
|
|
26
|
+
| Type
|
|
27
|
+
| z3.ZodEffects<Type>
|
|
28
|
+
| z3.ZodEffects<ZodEffects<Type>>
|
|
29
|
+
| z3.ZodOptional<Type>,
|
|
30
|
+
) => {
|
|
31
|
+
let toReturn = schema
|
|
32
|
+
while (toReturn instanceof ZodEffects) {
|
|
33
|
+
toReturn = toReturn.innerType()
|
|
34
|
+
}
|
|
35
|
+
if (toReturn instanceof ZodOptional) {
|
|
36
|
+
toReturn = toReturn._def.innerType
|
|
37
|
+
}
|
|
38
|
+
return toReturn
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Helper function to check if a Zod v3 schema is optional
|
|
42
|
+
const isZod3SchemaOptional = <Type extends z3.ZodTypeAny>(
|
|
43
|
+
schema:
|
|
44
|
+
| Type
|
|
45
|
+
| z3.ZodEffects<Type>
|
|
46
|
+
| z3.ZodEffects<ZodEffects<Type>>
|
|
47
|
+
| z3.ZodOptional<Type>
|
|
48
|
+
| z3.ZodNullable<Type>,
|
|
49
|
+
) => {
|
|
50
|
+
let toReturn = schema
|
|
51
|
+
while (toReturn instanceof ZodEffects) {
|
|
52
|
+
toReturn = toReturn.innerType()
|
|
53
|
+
}
|
|
54
|
+
if (toReturn instanceof ZodOptional) {
|
|
55
|
+
return true
|
|
56
|
+
}
|
|
57
|
+
if (toReturn instanceof ZodNullable) {
|
|
58
|
+
return true
|
|
59
|
+
}
|
|
60
|
+
return false
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Helper function to determine the type of a value
|
|
64
|
+
function getValueType(value: unknown) {
|
|
65
|
+
if (Array.isArray(value)) {
|
|
66
|
+
return 'array'
|
|
67
|
+
}
|
|
68
|
+
if (value === null) {
|
|
69
|
+
return 'null'
|
|
70
|
+
}
|
|
71
|
+
return typeof value
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Helper function to check if a value matches a schema type
|
|
75
|
+
function isValueCompatibleWithSchema(value: unknown, subSchema: z4.JSONSchema.JSONSchema): boolean {
|
|
76
|
+
const valueType = getValueType(value)
|
|
77
|
+
|
|
78
|
+
if (subSchema.type) {
|
|
79
|
+
return subSchema.type === valueType
|
|
80
|
+
|| (subSchema.type === 'integer' && valueType === 'number' && Number.isInteger(value as number))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// If no type specified, assume compatibility
|
|
84
|
+
return true
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function defaultObjectByJSONSchema(schema: z4.JSONSchema.JSONSchema, original?: unknown): unknown {
|
|
88
|
+
// Handle anyOf - find the best matching schema without unnecessary recursion
|
|
89
|
+
if (schema.anyOf && Array.isArray(schema.anyOf)) {
|
|
90
|
+
if (original !== undefined) {
|
|
91
|
+
// First pass: find exact type match
|
|
92
|
+
for (const subSchema of schema.anyOf) {
|
|
93
|
+
if (isValueCompatibleWithSchema(original, subSchema as z4.JSONSchema.JSONSchema)) {
|
|
94
|
+
return defaultObjectByJSONSchema(subSchema as z4.JSONSchema.JSONSchema, original)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// Second pass: try first schema that doesn't explicitly conflict
|
|
98
|
+
for (const subSchema of schema.anyOf) {
|
|
99
|
+
const subSchemaTyped = subSchema as z4.JSONSchema.JSONSchema
|
|
100
|
+
if (!subSchemaTyped.type || subSchemaTyped.type === 'object') {
|
|
101
|
+
return defaultObjectByJSONSchema(subSchemaTyped, original)
|
|
102
|
+
}
|
|
103
|
+
}
|
|
22
104
|
}
|
|
23
|
-
|
|
24
|
-
|
|
105
|
+
// Fallback to first schema
|
|
106
|
+
return defaultObjectByJSONSchema(schema.anyOf[0] as z4.JSONSchema.JSONSchema, original)
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Early return for non-object types
|
|
110
|
+
if (schema.type !== 'object' || !schema.properties) {
|
|
111
|
+
switch (schema.type) {
|
|
112
|
+
case 'string':
|
|
113
|
+
return typeof original === 'string' ? original : schema.default
|
|
114
|
+
case 'number':
|
|
115
|
+
case 'integer':
|
|
116
|
+
return typeof original === 'number' ? original : schema.default
|
|
117
|
+
case 'boolean':
|
|
118
|
+
return typeof original === 'boolean' ? original : schema.default
|
|
119
|
+
case 'null':
|
|
120
|
+
return original === null ? original : schema.default
|
|
121
|
+
case 'array':
|
|
122
|
+
if (Array.isArray(original) && schema.items) {
|
|
123
|
+
return original.map(item => defaultObjectByJSONSchema(schema.items as z4.JSONSchema.JSONSchema, item))
|
|
124
|
+
}
|
|
125
|
+
return schema.default
|
|
126
|
+
default:
|
|
127
|
+
return schema.default
|
|
25
128
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Object handling with optimizations
|
|
132
|
+
const properties = schema.properties as Record<string, z4.JSONSchema.JSONSchema>
|
|
133
|
+
const isOriginalObject = original && typeof original === 'object' && !Array.isArray(original)
|
|
134
|
+
const originalObj = isOriginalObject ? original as Record<string, unknown> : undefined
|
|
135
|
+
|
|
136
|
+
// Initialize result object more efficiently
|
|
137
|
+
const toReturn: Record<string, unknown> = {}
|
|
138
|
+
|
|
139
|
+
// Process schema properties first
|
|
140
|
+
for (const key in properties) {
|
|
141
|
+
const originalValue = originalObj?.[key]
|
|
142
|
+
toReturn[key] = defaultObjectByJSONSchema(properties[key], originalValue)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Handle additional properties after schema properties
|
|
146
|
+
if (originalObj && schema.additionalProperties !== false) {
|
|
147
|
+
const schemaKeys = new Set(Object.keys(properties))
|
|
148
|
+
|
|
149
|
+
for (const [key, value] of Object.entries(originalObj)) {
|
|
150
|
+
if (!schemaKeys.has(key)) {
|
|
151
|
+
// Allow any additional properties as-is
|
|
152
|
+
toReturn[key] = value
|
|
153
|
+
}
|
|
38
154
|
}
|
|
39
|
-
|
|
40
|
-
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return toReturn
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export const isZod4Schema = (schema: z3.ZodTypeAny | z4.$ZodType): schema is z4.$ZodType => {
|
|
161
|
+
if ('_zod' in schema) {
|
|
162
|
+
return true
|
|
163
|
+
}
|
|
164
|
+
return false
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema, original: Partial<InferSchema<Schema>> & Record<string, unknown> = {}): Partial<InferSchema<Schema>> {
|
|
168
|
+
// zod v4
|
|
169
|
+
if (isZod4Schema(schema)) {
|
|
170
|
+
const jsonSchema = z4toJSONSchema(schema)
|
|
171
|
+
if (jsonSchema.type !== 'object' || !jsonSchema.properties) {
|
|
172
|
+
return original
|
|
41
173
|
}
|
|
42
|
-
|
|
174
|
+
const parse = z4SafeParse(schema, original)
|
|
175
|
+
return defaultObjectByJSONSchema(jsonSchema, parse.success ? parse.data : original) as Partial<InferSchema<Schema>>
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// zod v3
|
|
179
|
+
const innerType = getZod3SchemaInnerType(schema)
|
|
180
|
+
|
|
181
|
+
if (!(innerType instanceof ZodObject)) {
|
|
182
|
+
return original
|
|
43
183
|
}
|
|
44
|
-
const innerType = getSchemaInnerType<AnyZodObject>(schema)
|
|
45
184
|
const unknownKeys
|
|
46
185
|
= innerType instanceof ZodObject
|
|
47
186
|
? innerType._def.unknownKeys === 'passthrough'
|
|
@@ -49,12 +188,12 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
|
|
|
49
188
|
return {
|
|
50
189
|
...(unknownKeys ? original : {}),
|
|
51
190
|
...Object.fromEntries(
|
|
52
|
-
(Object.entries(innerType.shape) as [string, ZodTypeAny][]).map(
|
|
191
|
+
('shape' in innerType ? Object.entries(innerType.shape) as [string, z3.ZodTypeAny][] : []).map(
|
|
53
192
|
([key, subSchema]) => {
|
|
54
193
|
const originalValue = original[key]
|
|
55
|
-
const isOptional =
|
|
56
|
-
let innerType =
|
|
57
|
-
let defaultValue: Partial<
|
|
194
|
+
const isOptional = isZod3SchemaOptional(subSchema)
|
|
195
|
+
let innerType = getZod3SchemaInnerType(subSchema)
|
|
196
|
+
let defaultValue: Partial<InferSchema<Schema>> | undefined
|
|
58
197
|
if (innerType instanceof ZodDefault) {
|
|
59
198
|
defaultValue = innerType._def.defaultValue()
|
|
60
199
|
innerType = innerType._def.innerType
|
|
@@ -79,7 +218,7 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
|
|
|
79
218
|
&& Array.isArray(originalValue)
|
|
80
219
|
&& originalValue.length
|
|
81
220
|
) {
|
|
82
|
-
const arrayType =
|
|
221
|
+
const arrayType = getZod3SchemaInnerType(innerType._def.type)
|
|
83
222
|
if (arrayType instanceof ZodObject) {
|
|
84
223
|
return [
|
|
85
224
|
key,
|
|
@@ -90,17 +229,17 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
|
|
|
90
229
|
? element
|
|
91
230
|
: undefined) as Partial<
|
|
92
231
|
typeof arrayType
|
|
93
|
-
|
|
232
|
+
>,
|
|
94
233
|
),
|
|
95
234
|
),
|
|
96
235
|
]
|
|
97
236
|
}
|
|
98
237
|
}
|
|
99
238
|
if (innerType instanceof ZodRecord && originalValue) {
|
|
100
|
-
const valueType =
|
|
239
|
+
const valueType = getZod3SchemaInnerType(innerType._def.valueType)
|
|
101
240
|
if (valueType instanceof ZodObject) {
|
|
102
241
|
return [key, Object.keys(originalValue).reduce((acc: Record<string, unknown>, recordKey: string) => {
|
|
103
|
-
acc[recordKey] = defaultObjectBySchema(valueType,
|
|
242
|
+
acc[recordKey] = defaultObjectBySchema(valueType, originalValue[recordKey])
|
|
104
243
|
return acc
|
|
105
244
|
}, {})]
|
|
106
245
|
}
|
|
@@ -112,7 +251,7 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
|
|
|
112
251
|
innerType,
|
|
113
252
|
originalValue
|
|
114
253
|
&& typeof originalValue === 'object'
|
|
115
|
-
?
|
|
254
|
+
? originalValue
|
|
116
255
|
: defaultValue,
|
|
117
256
|
),
|
|
118
257
|
]
|
|
@@ -121,5 +260,26 @@ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema,
|
|
|
121
260
|
},
|
|
122
261
|
),
|
|
123
262
|
),
|
|
124
|
-
} as Partial<
|
|
263
|
+
} as Partial<InferSchema<Schema>>
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export const safeParseAsync = <T extends FormSchema>(schema: T, data: any) => {
|
|
267
|
+
if (isZod4Schema(schema)) {
|
|
268
|
+
return z4SafeParseAsync(schema, data)
|
|
269
|
+
}
|
|
270
|
+
return schema.safeParseAsync(data)
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export const formatError = <T extends FormSchema>(schema: T, error: VvZodError<T>) => {
|
|
274
|
+
if (isZod4Schema(schema)) {
|
|
275
|
+
return z4FormatError(error as z4.$ZodError<T>)
|
|
276
|
+
}
|
|
277
|
+
return (error as z3.ZodError<T>).format()
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
export const formatIssues = (schema: FormSchema, issues: ZodIssue[]) => {
|
|
281
|
+
if (isZod4Schema(schema)) {
|
|
282
|
+
return z4FormatError(new $ZodError(issues as z4.$ZodIssue[]))
|
|
283
|
+
}
|
|
284
|
+
return new ZodError(issues as z3.ZodIssue[]).format()
|
|
125
285
|
}
|