@volverjs/form-vue 1.0.0-beta.2 → 1.0.0-beta.20

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/src/types.ts CHANGED
@@ -1,156 +1,177 @@
1
- import type { Component, DeepReadonly, Ref, WatchStopHandle } from 'vue'
2
- import type { z, AnyZodObject, ZodEffects, inferFormattedError } from 'zod'
1
+ import type { Component, DeepReadonly, Ref, RendererElement, RendererNode, VNode, WatchStopHandle } from 'vue'
2
+ import type { TypeOf, z } from 'zod'
3
3
  import type { IgnoredUpdater } from '@vueuse/core'
4
4
  import type { FormFieldType, FormStatus } from './enums'
5
5
 
6
6
  export type FormSchema =
7
- | AnyZodObject
8
- | ZodEffects<AnyZodObject>
9
- | ZodEffects<ZodEffects<AnyZodObject>>
7
+ | z.AnyZodObject
8
+ | z.ZodEffects<z.AnyZodObject>
9
+ | z.ZodEffects<z.ZodEffects<z.AnyZodObject>>
10
10
 
11
11
  export type FormFieldComponentOptions = {
12
- lazyLoad?: boolean
13
- sideEffects?: (type: `${FormFieldType}`) => Promise<void> | void
12
+ lazyLoad?: boolean
13
+ sideEffects?: (type: `${FormFieldType}`) => Promise<void> | void
14
14
  }
15
15
 
16
16
  export type FormComponentOptions<Schema> = {
17
- updateThrottle?: number
18
- continuosValidation?: boolean
19
- template?: Schema extends FormSchema ? FormTemplate<Schema> : never
20
- onUpdate?: Schema extends FormSchema
21
- ? (data: Partial<z.infer<Schema> | undefined>) => void
22
- : never
23
- onSubmit?: Schema extends FormSchema
24
- ? (data: z.infer<Schema>) => void
25
- : never
26
- onInvalid?: Schema extends FormSchema
27
- ? (error: inferFormattedError<Schema, string>) => void
28
- : never
29
- onValid?: Schema extends FormSchema
30
- ? (data: z.infer<Schema>) => void
31
- : never
17
+ updateThrottle?: number
18
+ continuousValidation?: boolean
19
+ readonly?: boolean
20
+ template?: Schema extends FormSchema ? FormTemplate<Schema> : never
21
+ onUpdate?: Schema extends FormSchema
22
+ ? (data?: Partial<z.infer<Schema>>) => void
23
+ : never
24
+ onSubmit?: Schema extends FormSchema
25
+ ? (data?: z.infer<Schema>) => void
26
+ : never
27
+ onReset?: Schema extends FormSchema ? (data?: z.infer<Schema>) => void : never
28
+ onInvalid?: Schema extends FormSchema
29
+ ? (error?: z.inferFormattedError<Schema>) => void
30
+ : never
31
+ onValid?: Schema extends FormSchema
32
+ ? (data?: z.infer<Schema>) => void
33
+ : never
32
34
  }
33
35
 
34
36
  export type FormComposableOptions<Schema> = FormFieldComponentOptions &
35
- FormComponentOptions<Schema>
37
+ FormComponentOptions<Schema>
36
38
 
37
39
  type FormPluginOptionsSchema = {
38
- schema?: FormSchema
40
+ schema?: FormSchema
39
41
  }
40
42
 
41
43
  export type FormPluginOptions = FormPluginOptionsSchema &
42
- FormComposableOptions<FormPluginOptionsSchema['schema']>
44
+ FormComposableOptions<FormPluginOptionsSchema['schema']>
43
45
 
44
46
  export type InjectedFormData<Schema extends FormSchema> = {
45
- formData: Ref<Partial<z.infer<Schema>> | undefined>
46
- errors: Readonly<
47
- Ref<DeepReadonly<z.inferFormattedError<Schema>> | undefined>
48
- >
49
- submit: () => Promise<boolean>
50
- validate: () => Promise<boolean>
51
- ignoreUpdates: IgnoredUpdater
52
- stopUpdatesWatch: WatchStopHandle
53
- status: Readonly<Ref<FormStatus | undefined>>
54
- invalid: Readonly<Ref<boolean>>
47
+ formData: Ref<Partial<z.infer<Schema>> | undefined>
48
+ errors: Readonly<
49
+ Ref<DeepReadonly<z.inferFormattedError<Schema>> | undefined>
50
+ >
51
+ submit: () => Promise<boolean>
52
+ validate: (formData?: Partial<z.infer<Schema>>, fields?: Set<string>) => Promise<boolean>
53
+ clear: () => void
54
+ reset: () => void
55
+ ignoreUpdates: IgnoredUpdater
56
+ stopUpdatesWatch: WatchStopHandle
57
+ status: Readonly<Ref<FormStatus | undefined>>
58
+ invalid: Readonly<Ref<boolean>>
59
+ readonly: Ref<boolean>
55
60
  }
56
61
 
57
62
  export type InjectedFormWrapperData<Schema extends FormSchema> = {
58
- name: Ref<string>
59
- fields: Ref<Set<string>>
60
- errors: Ref<Map<string, z.inferFormattedError<Schema, string>>>
63
+ name: Ref<string>
64
+ fields: Ref<Set<string>>
65
+ errors: Ref<Map<string, z.inferFormattedError<Schema>>>
61
66
  }
62
67
 
63
68
  export type InjectedFormFieldData<Schema extends FormSchema> = {
64
- name: Ref<string>
65
- errors: Readonly<Ref<DeepReadonly<z.inferFormattedError<Schema>>>>
69
+ name: Ref<string>
70
+ errors: Readonly<Ref<DeepReadonly<z.inferFormattedError<Schema>>>>
66
71
  }
67
72
 
68
73
  export type Primitive =
69
- | null
70
- | undefined
71
- | string
72
- | number
73
- | boolean
74
- | symbol
75
- | bigint
76
-
77
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
74
+ | null
75
+ | undefined
76
+ | string
77
+ | number
78
+ | boolean
79
+ | symbol
80
+ | bigint
81
+
78
82
  type IsTuple<T extends readonly any[]> = number extends T['length']
79
- ? false
80
- : true
83
+ ? false
84
+ : true
81
85
 
82
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
83
86
  type TupleKeys<T extends readonly any[]> = Exclude<keyof T, keyof any[]>
84
87
 
85
88
  export type PathConcat<
86
- TKey extends string | number,
87
- TValue,
89
+ TKey extends string | number,
90
+ TValue,
88
91
  > = TValue extends Primitive ? `${TKey}` : `${TKey}` | `${TKey}.${Path<TValue>}`
89
92
 
90
93
  export type Path<T> = T extends readonly (infer V)[]
91
- ? IsTuple<T> extends true
92
- ? {
93
- [K in TupleKeys<T>]-?: PathConcat<K & string, T[K]>
94
- }[TupleKeys<T>]
95
- : PathConcat<number, V>
96
- : {
97
- [K in keyof T]-?: PathConcat<K & string, T[K]>
98
- }[keyof T]
99
-
100
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
94
+ ? IsTuple<T> extends true
95
+ ? {
96
+ [K in TupleKeys<T>]-?: PathConcat<K & string, T[K]>
97
+ }[TupleKeys<T>]
98
+ : PathConcat<number, V>
99
+ : {
100
+ [K in keyof T]-?: PathConcat<K & string, T[K]>
101
+ }[keyof T]
102
+
101
103
  export type PathValue<T, TPath extends Path<T> | Path<T>[]> = T extends any
102
- ? TPath extends `${infer K}.${infer R}`
103
- ? K extends keyof T
104
- ? R extends Path<T[K]>
105
- ? undefined extends T[K]
106
- ? PathValue<T[K], R> | undefined
107
- : PathValue<T[K], R>
108
- : never
109
- : K extends `${number}`
110
- ? T extends readonly (infer V)[]
111
- ? PathValue<V, R & Path<V>>
112
- : never
113
- : never
114
- : TPath extends keyof T
115
- ? T[TPath]
116
- : TPath extends `${number}`
117
- ? T extends readonly (infer V)[]
118
- ? V
119
- : never
120
- : never
121
- : never
104
+ ? TPath extends `${infer K}.${infer R}`
105
+ ? K extends keyof T
106
+ ? R extends Path<T[K]>
107
+ ? undefined extends T[K]
108
+ ? PathValue<T[K], R> | undefined
109
+ : PathValue<T[K], R>
110
+ : never
111
+ : K extends `${number}`
112
+ ? T extends readonly (infer V)[]
113
+ ? PathValue<V, R & Path<V>>
114
+ : never
115
+ : never
116
+ : TPath extends keyof T
117
+ ? T[TPath]
118
+ : TPath extends `${number}`
119
+ ? T extends readonly (infer V)[]
120
+ ? V
121
+ : never
122
+ : never
123
+ : never
122
124
 
123
125
  export type AnyBoolean<Schema extends FormSchema> =
124
- | boolean
125
- | Ref<boolean>
126
- | ((data?: InjectedFormData<Schema>) => boolean | Ref<boolean>)
126
+ | boolean
127
+ | Ref<boolean>
128
+ | ((data?: InjectedFormData<Schema>) => boolean | Ref<boolean>)
127
129
 
128
130
  export type SimpleFormTemplateItem<Schema extends FormSchema> = Record<
129
- string,
130
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
131
- any
131
+ string,
132
+ any
132
133
  > & {
133
- vvIs?: string | Component
134
- vvName?: Path<z.infer<Schema>>
135
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
136
- vvSlots?: Record<string, any>
137
- vvChildren?: Array<
138
- | SimpleFormTemplateItem<Schema>
139
- | ((data?: InjectedFormData<Schema>) => SimpleFormTemplateItem<Schema>)
140
- >
141
- vvIf?: AnyBoolean<Schema> | Path<z.infer<Schema>>
142
- vvElseIf?: AnyBoolean<Schema> | Path<z.infer<Schema>>
143
- vvType?: `${FormFieldType}`
144
- vvShowValid?: boolean
145
- vvContent?: string
146
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
147
- vvDefaultValue?: any
134
+ vvIs?: string | Component
135
+ vvName?: Path<z.infer<Schema>>
136
+ vvSlots?: Record<string, any>
137
+ vvChildren?:
138
+ | Array<
139
+ | SimpleFormTemplateItem<Schema>
140
+ | ((
141
+ data?: InjectedFormData<Schema>,
142
+ scope?: Record<string, unknown>,
143
+ ) => SimpleFormTemplateItem<Schema>)
144
+ >
145
+ | ((
146
+ data?: InjectedFormData<Schema>,
147
+ scope?: Record<string, unknown>,
148
+ ) => Array<
149
+ | SimpleFormTemplateItem<Schema>
150
+ | ((
151
+ data?: InjectedFormData<Schema>,
152
+ scope?: Record<string, unknown>,
153
+ ) => SimpleFormTemplateItem<Schema>)
154
+ >)
155
+ vvIf?: AnyBoolean<Schema> | Path<z.infer<Schema>>
156
+ vvElseIf?: AnyBoolean<Schema> | Path<z.infer<Schema>>
157
+ vvType?: `${FormFieldType}`
158
+ vvShowValid?: boolean
159
+ vvContent?: string
160
+ vvDefaultValue?: any
148
161
  }
149
162
 
150
163
  export type FormTemplateItem<Schema extends FormSchema> =
151
- | SimpleFormTemplateItem<Schema>
152
- | ((data?: InjectedFormData<Schema>) => SimpleFormTemplateItem<Schema>)
164
+ | SimpleFormTemplateItem<Schema>
165
+ | ((
166
+ data?: InjectedFormData<Schema>,
167
+ scope?: Record<string, unknown>,
168
+ ) => SimpleFormTemplateItem<Schema>)
153
169
 
154
170
  export type FormTemplate<Schema extends FormSchema> =
155
- | FormTemplateItem<Schema>[]
156
- | ((data?: InjectedFormData<Schema>) => FormTemplateItem<Schema>[])
171
+ | FormTemplateItem<Schema>[]
172
+ | ((
173
+ data?: InjectedFormData<Schema>,
174
+ scope?: Record<string, unknown>,
175
+ ) => FormTemplateItem<Schema>[])
176
+
177
+ export type RenderFunctionOutput = VNode<RendererNode, RendererElement, { [key: string]: any }>
package/src/utils.ts CHANGED
@@ -1,102 +1,130 @@
1
1
  import {
2
- type z,
3
- type AnyZodObject,
4
- type ZodTypeAny,
5
- ZodDefault,
6
- ZodObject,
7
- ZodEffects,
8
- ZodSchema,
9
- ZodNullable,
10
- ZodOptional,
11
- ZodArray,
2
+ type z,
3
+ type AnyZodObject,
4
+ type ZodTypeAny,
5
+ ZodDefault,
6
+ ZodObject,
7
+ ZodEffects,
8
+ ZodSchema,
9
+ ZodNullable,
10
+ ZodOptional,
11
+ ZodRecord,
12
+ ZodArray,
12
13
  } from 'zod'
13
14
  import type { FormSchema } from './types'
14
15
 
15
- export const defaultObjectBySchema = <Schema extends FormSchema>(
16
- schema: Schema,
17
- original: Partial<z.infer<Schema>> = {},
18
- ): Partial<z.infer<Schema>> => {
19
- const getInnerType = <Type extends ZodTypeAny>(
20
- schema:
21
- | Type
22
- | ZodEffects<Type>
23
- | ZodEffects<ZodEffects<Type>>
24
- | ZodOptional<Type>,
25
- ) => {
26
- let toReturn = schema
27
- while (toReturn instanceof ZodEffects) {
28
- toReturn = toReturn.innerType()
29
- }
30
- if (toReturn instanceof ZodOptional) {
31
- toReturn = toReturn._def.innerType
32
- }
33
- return toReturn
34
- }
35
- const innerType = getInnerType<AnyZodObject>(schema)
36
- const unknownKeys =
37
- innerType instanceof ZodObject
38
- ? innerType._def.unknownKeys === 'passthrough'
39
- : false
40
- return {
41
- ...(unknownKeys ? original : {}),
42
- ...Object.fromEntries(
43
- (Object.entries(innerType.shape) as [string, ZodTypeAny][]).map(
44
- ([key, subSchema]) => {
45
- const originalValue = original[key]
46
- let innerType = getInnerType(subSchema)
47
- let defaultValue: Partial<z.infer<Schema>> | undefined =
48
- undefined
49
- if (innerType instanceof ZodDefault) {
50
- defaultValue = innerType._def.defaultValue()
51
- innerType = innerType._def.innerType
52
- }
53
- if (
54
- originalValue === null &&
55
- innerType instanceof ZodNullable
56
- ) {
57
- return [key, originalValue]
58
- }
59
- if (innerType instanceof ZodSchema) {
60
- const parse = subSchema.safeParse(originalValue)
61
- if (parse.success) {
62
- return [key, parse.data ?? defaultValue]
63
- }
64
- }
65
- if (
66
- innerType instanceof ZodArray &&
67
- Array.isArray(originalValue) &&
68
- originalValue.length
69
- ) {
70
- const arrayType = getInnerType(innerType._def.type)
71
- if (arrayType instanceof ZodObject) {
72
- return [
73
- key,
74
- originalValue.map((element: unknown) =>
75
- defaultObjectBySchema(
76
- arrayType,
77
- element && typeof element === 'object'
78
- ? element
79
- : undefined,
80
- ),
81
- ) ?? defaultValue,
82
- ]
83
- }
84
- }
85
- if (innerType instanceof ZodObject) {
86
- return [
87
- key,
88
- defaultObjectBySchema(
89
- innerType,
90
- originalValue &&
91
- typeof originalValue === 'object'
92
- ? originalValue
93
- : defaultValue,
94
- ),
95
- ]
96
- }
97
- return [key, defaultValue]
98
- },
99
- ),
100
- ),
101
- } as Partial<z.infer<Schema>>
16
+ export function defaultObjectBySchema<Schema extends FormSchema>(schema: Schema, original: Partial<z.infer<Schema>> & Record<string, unknown> = {}): Partial<z.infer<Schema>> {
17
+ const getSchemaInnerType = <Type extends ZodTypeAny>(
18
+ schema:
19
+ | Type
20
+ | ZodEffects<Type>
21
+ | ZodEffects<ZodEffects<Type>>
22
+ | ZodOptional<Type>,
23
+ ) => {
24
+ let toReturn = schema
25
+ while (toReturn instanceof ZodEffects) {
26
+ toReturn = toReturn.innerType()
27
+ }
28
+ if (toReturn instanceof ZodOptional) {
29
+ toReturn = toReturn._def.innerType
30
+ }
31
+ return toReturn
32
+ }
33
+ const isSchemaOptional = <Type extends ZodTypeAny>(
34
+ schema:
35
+ | Type
36
+ | ZodEffects<Type>
37
+ | ZodEffects<ZodEffects<Type>>
38
+ | ZodOptional<Type>,
39
+ ) => {
40
+ let toReturn = schema
41
+ while (toReturn instanceof ZodEffects) {
42
+ toReturn = toReturn.innerType()
43
+ }
44
+ if (toReturn instanceof ZodOptional) {
45
+ return true
46
+ }
47
+ return false
48
+ }
49
+ const innerType = getSchemaInnerType<AnyZodObject>(schema)
50
+ const unknownKeys
51
+ = innerType instanceof ZodObject
52
+ ? innerType._def.unknownKeys === 'passthrough'
53
+ : false
54
+ return {
55
+ ...(unknownKeys ? original : {}),
56
+ ...Object.fromEntries(
57
+ (Object.entries(innerType.shape) as [string, ZodTypeAny][]).map(
58
+ ([key, subSchema]) => {
59
+ const originalValue = original[key]
60
+ const isOptional = isSchemaOptional(subSchema)
61
+ let innerType = getSchemaInnerType(subSchema)
62
+ let defaultValue: Partial<z.infer<Schema>> | undefined
63
+ if (innerType instanceof ZodDefault) {
64
+ defaultValue = innerType._def.defaultValue()
65
+ innerType = innerType._def.innerType
66
+ }
67
+ if (
68
+ originalValue === null
69
+ && innerType instanceof ZodNullable
70
+ ) {
71
+ return [key, originalValue]
72
+ }
73
+ if ((originalValue === undefined || originalValue === null) && isOptional) {
74
+ return [key, defaultValue]
75
+ }
76
+ if (innerType instanceof ZodSchema) {
77
+ const parse = subSchema.safeParse(originalValue)
78
+ if (parse.success) {
79
+ return [key, parse.data ?? defaultValue]
80
+ }
81
+ }
82
+ if (
83
+ innerType instanceof ZodArray
84
+ && Array.isArray(originalValue)
85
+ && originalValue.length
86
+ ) {
87
+ const arrayType = getSchemaInnerType(innerType._def.type)
88
+ if (arrayType instanceof ZodObject) {
89
+ return [
90
+ key,
91
+ originalValue.map((element: unknown) =>
92
+ defaultObjectBySchema(
93
+ arrayType,
94
+ (element && typeof element === 'object'
95
+ ? element
96
+ : undefined) as Partial<
97
+ typeof arrayType
98
+ >,
99
+ ),
100
+ ),
101
+ ]
102
+ }
103
+ }
104
+ if (innerType instanceof ZodRecord && originalValue) {
105
+ const valueType = getSchemaInnerType(innerType._def.valueType)
106
+ if (valueType instanceof ZodObject) {
107
+ return [key, Object.keys(originalValue).reduce((acc: Record<string, unknown>, recordKey: string) => {
108
+ acc[recordKey] = defaultObjectBySchema(valueType, originalValue[recordKey])
109
+ return acc
110
+ }, {})]
111
+ }
112
+ }
113
+ if (innerType instanceof ZodObject) {
114
+ return [
115
+ key,
116
+ defaultObjectBySchema(
117
+ innerType,
118
+ originalValue
119
+ && typeof originalValue === 'object'
120
+ ? originalValue
121
+ : defaultValue,
122
+ ),
123
+ ]
124
+ }
125
+ return [key, defaultValue]
126
+ },
127
+ ),
128
+ ),
129
+ } as Partial<z.infer<Schema>>
102
130
  }