@effect-app/vue-components 4.0.0-beta.2 → 4.0.0-beta.200
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 +36 -8
- package/dist/reset.css +52 -0
- package/dist/types/components/CommandButton.vue.d.ts +6 -4
- package/dist/types/components/OmegaForm/OmegaArray.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaAutoGen.vue.d.ts +2 -2
- package/dist/types/components/OmegaForm/OmegaErrorsInternal.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaFormInput.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaInput.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaInternalInput.vue.d.ts +2 -1
- package/dist/types/components/OmegaForm/OmegaWrapper.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/createUseFormWithCustomInput.d.ts +2 -2
- package/dist/types/components/OmegaForm/errors.d.ts +33 -0
- package/dist/types/components/OmegaForm/getOmegaStore.d.ts +1 -1
- package/dist/types/components/OmegaForm/hocs.d.ts +3 -0
- package/dist/types/components/OmegaForm/index.d.ts +13 -3
- package/dist/types/components/OmegaForm/inputs.d.ts +4 -0
- package/dist/types/components/OmegaForm/meta/checks.d.ts +4 -0
- package/dist/types/components/OmegaForm/meta/createMeta.d.ts +32 -0
- package/dist/types/components/OmegaForm/meta/defaults.d.ts +2 -0
- package/dist/types/components/OmegaForm/meta/redacted.d.ts +2 -0
- package/dist/types/components/OmegaForm/meta/types.d.ts +56 -0
- package/dist/types/components/OmegaForm/meta/walker.d.ts +18 -0
- package/dist/types/components/OmegaForm/persistency.d.ts +58 -0
- package/dist/types/components/OmegaForm/submit.d.ts +60 -0
- package/dist/types/components/OmegaForm/types.d.ts +281 -0
- package/dist/types/components/OmegaForm/useOmegaForm.d.ts +7 -215
- package/dist/types/components/OmegaForm/validation/localized.d.ts +10 -0
- package/dist/types/index.d.ts +0 -1
- package/dist/types/utils/index.d.ts +6 -7
- package/dist/vue-components.es.js +29 -44
- package/dist/vue-components10.es.js +5 -0
- package/dist/vue-components11.es.js +20 -0
- package/dist/vue-components12.es.js +49 -0
- package/dist/vue-components13.es.js +128 -0
- package/dist/vue-components14.es.js +65 -0
- package/dist/vue-components15.es.js +60 -0
- package/dist/vue-components16.es.js +22 -0
- package/dist/vue-components17.es.js +5 -0
- package/dist/vue-components18.es.js +80 -0
- package/dist/vue-components19.es.js +92 -0
- package/dist/vue-components2.es.js +11 -0
- package/dist/vue-components20.es.js +73 -0
- package/dist/vue-components21.es.js +12 -0
- package/dist/vue-components22.es.js +56 -0
- package/dist/vue-components23.es.js +5 -0
- package/dist/vue-components24.es.js +44 -0
- package/dist/vue-components25.es.js +5 -0
- package/dist/vue-components26.es.js +84 -0
- package/dist/vue-components28.es.js +8 -0
- package/dist/vue-components29.es.js +9 -0
- package/dist/vue-components3.es.js +86 -0
- package/dist/vue-components30.es.js +269 -0
- package/dist/vue-components32.es.js +8 -0
- package/dist/vue-components33.es.js +73 -0
- package/dist/vue-components34.es.js +5 -0
- package/dist/vue-components35.es.js +52 -0
- package/dist/vue-components36.es.js +5 -0
- package/dist/vue-components37.es.js +24 -0
- package/dist/vue-components38.es.js +5 -0
- package/dist/vue-components39.es.js +59 -0
- package/dist/vue-components4.es.js +5 -0
- package/dist/vue-components40.es.js +5 -0
- package/dist/vue-components41.es.js +12 -0
- package/dist/vue-components42.es.js +22 -0
- package/dist/vue-components44.es.js +9 -0
- package/dist/vue-components45.es.js +4 -0
- package/dist/vue-components46.es.js +38 -0
- package/dist/vue-components47.es.js +27 -0
- package/dist/vue-components48.es.js +28 -0
- package/dist/vue-components49.es.js +7 -0
- package/dist/vue-components5.es.js +24 -0
- package/dist/vue-components50.es.js +18 -0
- package/dist/vue-components51.es.js +36 -0
- package/dist/vue-components52.es.js +18 -0
- package/dist/vue-components53.es.js +21 -0
- package/dist/vue-components54.es.js +30 -0
- package/dist/vue-components55.es.js +7 -0
- package/dist/vue-components56.es.js +9 -0
- package/dist/vue-components57.es.js +38 -0
- package/dist/vue-components58.es.js +25 -0
- package/dist/vue-components59.es.js +128 -0
- package/dist/vue-components6.es.js +13 -0
- package/dist/vue-components60.es.js +24 -0
- package/dist/vue-components61.es.js +21 -0
- package/dist/vue-components62.es.js +9 -0
- package/dist/vue-components63.es.js +19 -0
- package/dist/vue-components64.es.js +5 -0
- package/dist/vue-components65.es.js +29 -0
- package/dist/vue-components66.es.js +5 -0
- package/dist/vue-components67.es.js +29 -0
- package/dist/vue-components68.es.js +6 -0
- package/dist/vue-components69.es.js +18 -0
- package/dist/vue-components7.es.js +13 -0
- package/dist/vue-components70.es.js +40 -0
- package/dist/vue-components71.es.js +81 -0
- package/dist/vue-components72.es.js +33 -0
- package/dist/vue-components73.es.js +19 -0
- package/dist/vue-components74.es.js +48 -0
- package/dist/vue-components8.es.js +35 -0
- package/dist/vue-components9.es.js +47 -0
- package/package.json +35 -31
- package/src/components/CommandButton.vue +55 -7
- package/src/components/OmegaForm/OmegaArray.vue +2 -4
- package/src/components/OmegaForm/OmegaAutoGen.vue +27 -31
- package/src/components/OmegaForm/OmegaErrorsInternal.vue +3 -4
- package/src/components/OmegaForm/OmegaFormInput.vue +1 -1
- package/src/components/OmegaForm/OmegaInput.vue +7 -36
- package/src/components/OmegaForm/OmegaInputVuetify.vue +5 -2
- package/src/components/OmegaForm/OmegaInternalInput.vue +21 -11
- package/src/components/OmegaForm/OmegaTaggedUnion.vue +2 -1
- package/src/components/OmegaForm/OmegaTaggedUnionInternal.vue +1 -1
- package/src/components/OmegaForm/OmegaWrapper.vue +1 -1
- package/src/components/OmegaForm/blockDialog.ts +18 -6
- package/src/components/OmegaForm/createUseFormWithCustomInput.ts +2 -1
- package/src/components/OmegaForm/errors.ts +136 -0
- package/src/components/OmegaForm/getOmegaStore.ts +1 -1
- package/src/components/OmegaForm/hocs.ts +19 -0
- package/src/components/OmegaForm/index.ts +16 -4
- package/src/components/OmegaForm/inputs.ts +22 -0
- package/src/components/OmegaForm/meta/checks.ts +81 -0
- package/src/components/OmegaForm/meta/createMeta.ts +138 -0
- package/src/components/OmegaForm/meta/defaults.ts +132 -0
- package/src/components/OmegaForm/meta/redacted.ts +66 -0
- package/src/components/OmegaForm/meta/types.ts +78 -0
- package/src/components/OmegaForm/meta/walker.ts +248 -0
- package/src/components/OmegaForm/persistency.ts +247 -0
- package/src/components/OmegaForm/submit.ts +128 -0
- package/src/components/OmegaForm/types.ts +751 -0
- package/src/components/OmegaForm/useOmegaForm.ts +58 -895
- package/src/components/OmegaForm/validation/localized.ts +202 -0
- package/src/index.ts +0 -1
- package/src/reset.css +52 -0
- package/src/utils/index.ts +9 -10
- package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +0 -157
- package/dist/types/constants/index.d.ts +0 -1
- package/dist/vue-components.es10.js +0 -237
- package/dist/vue-components.es100.js +0 -4
- package/dist/vue-components.es11.js +0 -32
- package/dist/vue-components.es12.js +0 -439
- package/dist/vue-components.es13.js +0 -49
- package/dist/vue-components.es14.js +0 -4
- package/dist/vue-components.es15.js +0 -4
- package/dist/vue-components.es16.js +0 -725
- package/dist/vue-components.es17.js +0 -143
- package/dist/vue-components.es18.js +0 -6
- package/dist/vue-components.es19.js +0 -13
- package/dist/vue-components.es2.js +0 -30
- package/dist/vue-components.es20.js +0 -5
- package/dist/vue-components.es21.js +0 -26
- package/dist/vue-components.es22.js +0 -6
- package/dist/vue-components.es23.js +0 -10
- package/dist/vue-components.es24.js +0 -57
- package/dist/vue-components.es25.js +0 -71
- package/dist/vue-components.es26.js +0 -8
- package/dist/vue-components.es27.js +0 -8
- package/dist/vue-components.es28.js +0 -5
- package/dist/vue-components.es29.js +0 -5
- package/dist/vue-components.es3.js +0 -16
- package/dist/vue-components.es30.js +0 -4
- package/dist/vue-components.es31.js +0 -4
- package/dist/vue-components.es32.js +0 -4
- package/dist/vue-components.es33.js +0 -4
- package/dist/vue-components.es34.js +0 -19
- package/dist/vue-components.es35.js +0 -13
- package/dist/vue-components.es36.js +0 -320
- package/dist/vue-components.es37.js +0 -563
- package/dist/vue-components.es38.js +0 -29
- package/dist/vue-components.es39.js +0 -54
- package/dist/vue-components.es4.js +0 -52
- package/dist/vue-components.es40.js +0 -66
- package/dist/vue-components.es41.js +0 -6
- package/dist/vue-components.es42.js +0 -6
- package/dist/vue-components.es43.js +0 -26
- package/dist/vue-components.es44.js +0 -77
- package/dist/vue-components.es45.js +0 -42
- package/dist/vue-components.es46.js +0 -316
- package/dist/vue-components.es47.js +0 -101
- package/dist/vue-components.es48.js +0 -33
- package/dist/vue-components.es49.js +0 -4
- package/dist/vue-components.es5.js +0 -52
- package/dist/vue-components.es50.js +0 -4
- package/dist/vue-components.es51.js +0 -4
- package/dist/vue-components.es52.js +0 -113
- package/dist/vue-components.es54.js +0 -9
- package/dist/vue-components.es55.js +0 -34
- package/dist/vue-components.es57.js +0 -194
- package/dist/vue-components.es59.js +0 -40
- package/dist/vue-components.es6.js +0 -69
- package/dist/vue-components.es60.js +0 -85
- package/dist/vue-components.es61.js +0 -43
- package/dist/vue-components.es62.js +0 -7
- package/dist/vue-components.es63.js +0 -6
- package/dist/vue-components.es64.js +0 -25
- package/dist/vue-components.es65.js +0 -7
- package/dist/vue-components.es66.js +0 -23
- package/dist/vue-components.es67.js +0 -32
- package/dist/vue-components.es68.js +0 -24
- package/dist/vue-components.es69.js +0 -14
- package/dist/vue-components.es7.js +0 -83
- package/dist/vue-components.es70.js +0 -7
- package/dist/vue-components.es71.js +0 -21
- package/dist/vue-components.es72.js +0 -11
- package/dist/vue-components.es73.js +0 -33
- package/dist/vue-components.es74.js +0 -50
- package/dist/vue-components.es75.js +0 -28
- package/dist/vue-components.es76.js +0 -103
- package/dist/vue-components.es77.js +0 -84
- package/dist/vue-components.es78.js +0 -23
- package/dist/vue-components.es79.js +0 -14
- package/dist/vue-components.es8.js +0 -63
- package/dist/vue-components.es80.js +0 -115
- package/dist/vue-components.es81.js +0 -5
- package/dist/vue-components.es82.js +0 -34
- package/dist/vue-components.es83.js +0 -4
- package/dist/vue-components.es84.js +0 -4
- package/dist/vue-components.es85.js +0 -18
- package/dist/vue-components.es86.js +0 -17
- package/dist/vue-components.es87.js +0 -72
- package/dist/vue-components.es88.js +0 -10
- package/dist/vue-components.es89.js +0 -4
- package/dist/vue-components.es9.js +0 -21
- package/dist/vue-components.es90.js +0 -17
- package/dist/vue-components.es91.js +0 -13
- package/dist/vue-components.es92.js +0 -67
- package/dist/vue-components.es93.js +0 -58
- package/dist/vue-components.es94.js +0 -19
- package/dist/vue-components.es95.js +0 -35
- package/dist/vue-components.es96.js +0 -31
- package/dist/vue-components.es97.js +0 -44
- package/dist/vue-components.es98.js +0 -4
- package/dist/vue-components.es99.js +0 -46
- package/src/components/OmegaForm/OmegaFormStuff.ts +0 -1174
- package/src/constants/index.ts +0 -1
|
@@ -1,1174 +0,0 @@
|
|
|
1
|
-
import type * as Effect from "effect/Effect"
|
|
2
|
-
import * as AST from "effect/SchemaAST"
|
|
3
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
4
|
-
import { type DeepKeys, type DeepValue, type FieldAsyncValidateOrFn, type FieldValidateOrFn, type FormApi, type FormAsyncValidateOrFn, type FormOptions, type FormState, type FormValidateOrFn, type StandardSchemaV1, type VueFormApi } from "@tanstack/vue-form"
|
|
5
|
-
import { isObject } from "@vueuse/core"
|
|
6
|
-
import * as S from "effect/Schema"
|
|
7
|
-
import { getTransformationFrom, useIntl } from "../../utils"
|
|
8
|
-
import { type OmegaFieldInternalApi } from "./InputProps"
|
|
9
|
-
import { type OF, type OmegaFormReturn } from "./useOmegaForm"
|
|
10
|
-
|
|
11
|
-
export type FieldPath<T> = unknown extends T ? string
|
|
12
|
-
// technically we cannot have primitive at the root
|
|
13
|
-
: T extends string | boolean | number | null | undefined | symbol | bigint ? ""
|
|
14
|
-
// technically we cannot have array at the root
|
|
15
|
-
: T extends ReadonlyArray<infer U> ? FieldPath_<U, `[${number}]`>
|
|
16
|
-
: {
|
|
17
|
-
[K in keyof T]: FieldPath_<T[K], `${K & string}`>
|
|
18
|
-
}[keyof T]
|
|
19
|
-
|
|
20
|
-
export type FieldPath_<T, Path extends string> = unknown extends T ? string
|
|
21
|
-
: T extends string | boolean | number | null | undefined | symbol | bigint ? Path
|
|
22
|
-
: T extends ReadonlyArray<infer U> ? FieldPath_<U, `${Path}[${number}]`> | Path
|
|
23
|
-
: {
|
|
24
|
-
[K in keyof T]: FieldPath_<T[K], `${Path}.${K & string}`>
|
|
25
|
-
}[keyof T]
|
|
26
|
-
|
|
27
|
-
export type BaseProps<From, TName extends FieldPath<From>> = {
|
|
28
|
-
/**
|
|
29
|
-
* Will fallback to i18n when not specified.
|
|
30
|
-
* Can also be provided via #label slot for custom HTML labels.
|
|
31
|
-
* When using the slot, it receives bindings: { required, id, label }
|
|
32
|
-
*/
|
|
33
|
-
label?: string
|
|
34
|
-
validators?: FieldValidators<From>
|
|
35
|
-
// Use FlexibleArrayPath: if name contains [], just use TName; otherwise intersect with Leaves<From>
|
|
36
|
-
name: TName
|
|
37
|
-
/**
|
|
38
|
-
* Optional class to apply to the input element.
|
|
39
|
-
* - If a string is provided, it will be used instead of the general class
|
|
40
|
-
* - If null is provided, no class will be applied (neither inputClass nor general class)
|
|
41
|
-
* - If undefined (not provided), the general class will be used
|
|
42
|
-
*/
|
|
43
|
-
inputClass?: string | null
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type TypesWithOptions = "radio" | "select" | "multiple" | "autocomplete" | "autocompletemultiple"
|
|
47
|
-
export type DefaultTypeProps = {
|
|
48
|
-
type?: TypeOverride
|
|
49
|
-
options?: undefined
|
|
50
|
-
} | {
|
|
51
|
-
type?: TypesWithOptions
|
|
52
|
-
// TODO: options should depend on `type`, but since there is auto-type, we can't currently enforce it.
|
|
53
|
-
// hence we allow it also for type? (undefined) atm
|
|
54
|
-
options?: {
|
|
55
|
-
title: string
|
|
56
|
-
value: unknown
|
|
57
|
-
}[]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export type OmegaInputPropsBase<
|
|
61
|
-
From extends Record<PropertyKey, any>,
|
|
62
|
-
To extends Record<PropertyKey, any>,
|
|
63
|
-
Name extends DeepKeys<From>
|
|
64
|
-
> = {
|
|
65
|
-
form: OF<From, To> & {
|
|
66
|
-
meta: MetaRecord<From>
|
|
67
|
-
i18nNamespace?: string
|
|
68
|
-
}
|
|
69
|
-
} & BaseProps<From, Name>
|
|
70
|
-
|
|
71
|
-
export type OmegaInputProps<
|
|
72
|
-
From extends Record<PropertyKey, any>,
|
|
73
|
-
To extends Record<PropertyKey, any>,
|
|
74
|
-
Name extends DeepKeys<From>,
|
|
75
|
-
TypeProps = DefaultTypeProps
|
|
76
|
-
> = {
|
|
77
|
-
form: OmegaFormReturn<From, To, TypeProps> & {
|
|
78
|
-
meta: MetaRecord<From>
|
|
79
|
-
i18nNamespace?: string
|
|
80
|
-
}
|
|
81
|
-
} & BaseProps<From, Name>
|
|
82
|
-
|
|
83
|
-
export type OmegaArrayProps<
|
|
84
|
-
From extends Record<PropertyKey, any>,
|
|
85
|
-
To extends Record<PropertyKey, any>,
|
|
86
|
-
Name extends DeepKeys<From>
|
|
87
|
-
> =
|
|
88
|
-
& Omit<
|
|
89
|
-
OmegaInputProps<From, To, Name>,
|
|
90
|
-
"validators" | "options" | "label" | "type" | "items" | "name"
|
|
91
|
-
>
|
|
92
|
-
& {
|
|
93
|
-
name: DeepKeys<From>
|
|
94
|
-
defaultItems?: DeepValue<From, DeepKeys<From>>
|
|
95
|
-
// deprecated items, caused bugs in state update, use defaultItems instead. It's not a simple Never, because Volar explodes
|
|
96
|
-
items?: "please use `defaultItems` instead"
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export type TypeOverride =
|
|
100
|
-
| "string"
|
|
101
|
-
| "text"
|
|
102
|
-
| "number"
|
|
103
|
-
| "select"
|
|
104
|
-
| "multiple"
|
|
105
|
-
| "boolean"
|
|
106
|
-
| "radio"
|
|
107
|
-
| "autocomplete"
|
|
108
|
-
| "autocompletemultiple"
|
|
109
|
-
| "switch"
|
|
110
|
-
| "range"
|
|
111
|
-
| "password"
|
|
112
|
-
| "email"
|
|
113
|
-
| "date"
|
|
114
|
-
|
|
115
|
-
export interface OmegaError {
|
|
116
|
-
label: string
|
|
117
|
-
inputId: string
|
|
118
|
-
errors: readonly string[]
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export type FormProps<From, To> =
|
|
122
|
-
& Omit<
|
|
123
|
-
FormOptions<
|
|
124
|
-
From,
|
|
125
|
-
FormValidateOrFn<From> | undefined,
|
|
126
|
-
FormValidateOrFn<From> | undefined,
|
|
127
|
-
StandardSchemaV1<From, To>,
|
|
128
|
-
FormValidateOrFn<From> | undefined,
|
|
129
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
130
|
-
FormValidateOrFn<From> | undefined,
|
|
131
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
132
|
-
FormValidateOrFn<From> | undefined,
|
|
133
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
134
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
135
|
-
Record<string, any> | undefined // TODO
|
|
136
|
-
>,
|
|
137
|
-
| "onSubmit"
|
|
138
|
-
| "defaultValues"
|
|
139
|
-
>
|
|
140
|
-
& {
|
|
141
|
-
// when defaultValues are allowed to be undefined, then they should also be allowed to be partial
|
|
142
|
-
// this fixes validator issues where a defaultValue of "" leads to "requires at least 1 character", while manually emptying the field changes it to "is required"
|
|
143
|
-
defaultValues?: Partial<From>
|
|
144
|
-
onSubmit?: (props: {
|
|
145
|
-
formApi: OmegaFormParams<From, To>
|
|
146
|
-
meta: any
|
|
147
|
-
value: To
|
|
148
|
-
}) => Promise<any> | Effect.Effect<unknown, any, never>
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
export type OmegaFormParams<From, To> = FormApi<
|
|
152
|
-
From,
|
|
153
|
-
FormValidateOrFn<From> | undefined,
|
|
154
|
-
FormValidateOrFn<From> | undefined,
|
|
155
|
-
StandardSchemaV1<From, To>,
|
|
156
|
-
FormValidateOrFn<From> | undefined,
|
|
157
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
158
|
-
FormValidateOrFn<From> | undefined,
|
|
159
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
160
|
-
FormValidateOrFn<From> | undefined,
|
|
161
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
162
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
163
|
-
Record<string, any> | undefined
|
|
164
|
-
>
|
|
165
|
-
|
|
166
|
-
export type OmegaFormState<From, To> = FormState<
|
|
167
|
-
From,
|
|
168
|
-
FormValidateOrFn<From> | undefined,
|
|
169
|
-
FormValidateOrFn<From> | undefined,
|
|
170
|
-
StandardSchemaV1<From, To>,
|
|
171
|
-
FormValidateOrFn<From> | undefined,
|
|
172
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
173
|
-
FormValidateOrFn<From> | undefined,
|
|
174
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
175
|
-
FormValidateOrFn<From> | undefined,
|
|
176
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
177
|
-
FormAsyncValidateOrFn<From> | undefined
|
|
178
|
-
>
|
|
179
|
-
|
|
180
|
-
// TODO: stitch TSubmitMeta somehow
|
|
181
|
-
export type OmegaFormApi<From, To, TSubmitMeta = Record<string, any> | undefined> =
|
|
182
|
-
& OmegaFormParams<From, To>
|
|
183
|
-
& VueFormApi<
|
|
184
|
-
From,
|
|
185
|
-
FormValidateOrFn<From> | undefined,
|
|
186
|
-
FormValidateOrFn<From> | undefined,
|
|
187
|
-
StandardSchemaV1<From, To>,
|
|
188
|
-
FormValidateOrFn<From> | undefined,
|
|
189
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
190
|
-
FormValidateOrFn<From> | undefined,
|
|
191
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
192
|
-
FormValidateOrFn<From> | undefined,
|
|
193
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
194
|
-
FormAsyncValidateOrFn<From> | undefined,
|
|
195
|
-
TSubmitMeta
|
|
196
|
-
>
|
|
197
|
-
|
|
198
|
-
export type FormComponent<T, S> = VueFormApi<
|
|
199
|
-
T,
|
|
200
|
-
FormValidateOrFn<T> | undefined,
|
|
201
|
-
FormValidateOrFn<T> | undefined,
|
|
202
|
-
StandardSchemaV1<T, S>,
|
|
203
|
-
FormValidateOrFn<T> | undefined,
|
|
204
|
-
FormAsyncValidateOrFn<T> | undefined,
|
|
205
|
-
FormValidateOrFn<T> | undefined,
|
|
206
|
-
FormAsyncValidateOrFn<T> | undefined,
|
|
207
|
-
FormValidateOrFn<T> | undefined,
|
|
208
|
-
FormAsyncValidateOrFn<T> | undefined,
|
|
209
|
-
FormAsyncValidateOrFn<T> | undefined,
|
|
210
|
-
Record<string, any> | undefined
|
|
211
|
-
>
|
|
212
|
-
|
|
213
|
-
export type FormType<
|
|
214
|
-
From extends Record<PropertyKey, any>,
|
|
215
|
-
To extends Record<PropertyKey, any>,
|
|
216
|
-
Name extends DeepKeys<From>
|
|
217
|
-
> = OmegaFormApi<From, To> & {
|
|
218
|
-
Field: OmegaFieldInternalApi<From, Name>
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export type PrefixFromDepth<
|
|
222
|
-
K extends string | number,
|
|
223
|
-
_TDepth extends any[]
|
|
224
|
-
> = K
|
|
225
|
-
|
|
226
|
-
export type NestedKeyOf<T> = DeepKeys<T>
|
|
227
|
-
|
|
228
|
-
export type FieldValidators<T> = {
|
|
229
|
-
onChangeAsync?: FieldAsyncValidateOrFn<T, any, any>
|
|
230
|
-
onChange?: FieldValidateOrFn<T, any, any>
|
|
231
|
-
onBlur?: FieldValidateOrFn<T, any, any>
|
|
232
|
-
onBlurAsync?: FieldAsyncValidateOrFn<T, any, any>
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
// Field metadata type definitions
|
|
236
|
-
export type BaseFieldMeta = {
|
|
237
|
-
required: boolean
|
|
238
|
-
nullableOrUndefined?: false | "undefined" | "null"
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
export type StringFieldMeta = BaseFieldMeta & {
|
|
242
|
-
type: "string"
|
|
243
|
-
maxLength?: number
|
|
244
|
-
minLength?: number
|
|
245
|
-
format?: string
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
export type NumberFieldMeta = BaseFieldMeta & {
|
|
249
|
-
type: "number"
|
|
250
|
-
minimum?: number
|
|
251
|
-
maximum?: number
|
|
252
|
-
exclusiveMinimum?: number
|
|
253
|
-
exclusiveMaximum?: number
|
|
254
|
-
refinement?: "int"
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
export type SelectFieldMeta = BaseFieldMeta & {
|
|
258
|
-
type: "select"
|
|
259
|
-
members: any[] // TODO: should be non empty array?
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
export type MultipleFieldMeta = BaseFieldMeta & {
|
|
263
|
-
type: "multiple"
|
|
264
|
-
members: any[] // TODO: should be non empty array?
|
|
265
|
-
rest: readonly AST.AST[]
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
export type BooleanFieldMeta = BaseFieldMeta & {
|
|
269
|
-
type: "boolean"
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
export type UnknownFieldMeta = BaseFieldMeta & {
|
|
273
|
-
type: "unknown"
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export type FieldMeta =
|
|
277
|
-
| StringFieldMeta
|
|
278
|
-
| NumberFieldMeta
|
|
279
|
-
| SelectFieldMeta
|
|
280
|
-
| MultipleFieldMeta
|
|
281
|
-
| BooleanFieldMeta
|
|
282
|
-
| UnknownFieldMeta
|
|
283
|
-
|
|
284
|
-
export type MetaRecord<T = string> = {
|
|
285
|
-
[K in NestedKeyOf<T>]?: FieldMeta
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
export type FilterItems = {
|
|
289
|
-
items: readonly [string, ...string[]]
|
|
290
|
-
message:
|
|
291
|
-
| string
|
|
292
|
-
| Effect.Effect<string, never, never>
|
|
293
|
-
| { readonly message: string | Effect.Effect<string> }
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
export type CreateMeta =
|
|
297
|
-
& {
|
|
298
|
-
parent?: string
|
|
299
|
-
meta?: Record<string, any>
|
|
300
|
-
nullableOrUndefined?: false | "undefined" | "null"
|
|
301
|
-
}
|
|
302
|
-
& (
|
|
303
|
-
| {
|
|
304
|
-
propertySignatures: readonly AST.PropertySignature[]
|
|
305
|
-
property?: never
|
|
306
|
-
}
|
|
307
|
-
| {
|
|
308
|
-
propertySignatures?: never
|
|
309
|
-
property: AST.AST
|
|
310
|
-
}
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
const getNullableOrUndefined = (property: AST.AST) => {
|
|
314
|
-
if (!AST.isUnion(property)) return false
|
|
315
|
-
return property.types.find((_) => AST.isUndefined(_) || _ === S.Null.ast)
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export const isNullableOrUndefined = (property: false | AST.AST | undefined) => {
|
|
319
|
-
if (!property || !AST.isUnion(property)) return false
|
|
320
|
-
if (property.types.find((_) => AST.isUndefined(_))) {
|
|
321
|
-
return "undefined"
|
|
322
|
-
}
|
|
323
|
-
if (property.types.find((_) => _ === S.Null.ast)) return "null"
|
|
324
|
-
return false
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Helper function to recursively unwrap nested unions (e.g., S.NullOr(S.NullOr(X)) -> X)
|
|
328
|
-
const unwrapNestedUnions = (types: readonly AST.AST[]): readonly AST.AST[] => {
|
|
329
|
-
const result: AST.AST[] = []
|
|
330
|
-
for (const type of types) {
|
|
331
|
-
if (AST.isUnion(type)) {
|
|
332
|
-
// Recursively unwrap nested unions
|
|
333
|
-
const unwrapped = unwrapNestedUnions(type.types)
|
|
334
|
-
result.push(...unwrapped)
|
|
335
|
-
} else {
|
|
336
|
-
result.push(type)
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
return result
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
export const createMeta = <T = any>(
|
|
343
|
-
{ meta = {}, parent = "", property, propertySignatures }: CreateMeta,
|
|
344
|
-
acc: Partial<MetaRecord<T>> = {}
|
|
345
|
-
): MetaRecord<T> | FieldMeta => {
|
|
346
|
-
// unwraps class (Class are transformations)
|
|
347
|
-
// this calls createMeta recursively, so wrapped transformations are also unwrapped
|
|
348
|
-
// BUT: check for Int title annotation first - S.Int and branded Int have title "Int" or "int"
|
|
349
|
-
// and we don't want to lose that information by unwrapping
|
|
350
|
-
if (property && AST.isDeclaration(property)) {
|
|
351
|
-
const titleOnTransform = property.annotations?.title ?? ""
|
|
352
|
-
|
|
353
|
-
// only unwrap if this is NOT an Int type
|
|
354
|
-
if (titleOnTransform !== "Int" && titleOnTransform !== "int") {
|
|
355
|
-
// In v4, Declaration doesn't have a 'from' property
|
|
356
|
-
// Just return the property as-is
|
|
357
|
-
return createMeta<T>({
|
|
358
|
-
parent,
|
|
359
|
-
meta,
|
|
360
|
-
property
|
|
361
|
-
})
|
|
362
|
-
}
|
|
363
|
-
// if it's Int, fall through to process it with the Int type
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
if (property && AST.isObjects(property)) {
|
|
367
|
-
return createMeta<T>({
|
|
368
|
-
meta,
|
|
369
|
-
propertySignatures: property.propertySignatures
|
|
370
|
-
})
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
if (propertySignatures) {
|
|
374
|
-
for (const p of propertySignatures) {
|
|
375
|
-
const key = parent ? `${parent}.${p.name.toString()}` : p.name.toString()
|
|
376
|
-
const nullableOrUndefined = isNullableOrUndefined(p.type)
|
|
377
|
-
|
|
378
|
-
// Check if this property has title "Int" or "int" annotation (from Int brand wrapper)
|
|
379
|
-
const propertyTitle = p.type.annotations?.title ?? ""
|
|
380
|
-
const isIntField = propertyTitle === "Int" || propertyTitle === "int"
|
|
381
|
-
|
|
382
|
-
// Determine if this field should be required:
|
|
383
|
-
// - For nullable discriminated unions, only _tag should be non-required
|
|
384
|
-
// - All other fields should calculate their required status normally
|
|
385
|
-
let isRequired: boolean
|
|
386
|
-
if (meta._isNullableDiscriminatedUnion && p.name.toString() === "_tag") {
|
|
387
|
-
// _tag in a nullable discriminated union is not required
|
|
388
|
-
isRequired = false
|
|
389
|
-
} else if (meta.required === false) {
|
|
390
|
-
// Explicitly set to non-required (legacy behavior for backwards compatibility)
|
|
391
|
-
isRequired = false
|
|
392
|
-
} else {
|
|
393
|
-
// Calculate from the property itself
|
|
394
|
-
isRequired = !nullableOrUndefined
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
const typeToProcess = p.type
|
|
398
|
-
if (AST.isUnion(p.type)) {
|
|
399
|
-
// First unwrap any nested unions, then filter out null/undefined
|
|
400
|
-
const unwrappedTypes = unwrapNestedUnions(p.type.types)
|
|
401
|
-
const nonNullTypes = unwrappedTypes
|
|
402
|
-
.filter(
|
|
403
|
-
(t) => !AST.isUndefined(t) && !AST.isNull(t)
|
|
404
|
-
)
|
|
405
|
-
// unwraps class (Class are transformations)
|
|
406
|
-
.map(getTransformationFrom)
|
|
407
|
-
|
|
408
|
-
const hasStructMembers = nonNullTypes.some(
|
|
409
|
-
(t) => AST.isObjects(t)
|
|
410
|
-
)
|
|
411
|
-
|
|
412
|
-
if (hasStructMembers) {
|
|
413
|
-
// Only create parent meta for non-NullOr unions to avoid duplicates
|
|
414
|
-
if (!nullableOrUndefined) {
|
|
415
|
-
const parentMeta = createMeta<T>({
|
|
416
|
-
parent: key,
|
|
417
|
-
property: p.type,
|
|
418
|
-
meta: { required: isRequired, nullableOrUndefined }
|
|
419
|
-
})
|
|
420
|
-
acc[key as NestedKeyOf<T>] = parentMeta as FieldMeta
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// Process each non-null type and merge their metadata
|
|
424
|
-
for (const nonNullType of nonNullTypes) {
|
|
425
|
-
if (AST.isObjects(nonNullType)) {
|
|
426
|
-
// For discriminated unions (multiple branches):
|
|
427
|
-
// - If the parent union is nullable, only _tag should be non-required
|
|
428
|
-
// - All other fields maintain their normal required status based on their own types
|
|
429
|
-
const isNullableDiscriminatedUnion = nullableOrUndefined && nonNullTypes.length > 1
|
|
430
|
-
|
|
431
|
-
Object.assign(
|
|
432
|
-
acc,
|
|
433
|
-
createMeta<T>({
|
|
434
|
-
parent: key,
|
|
435
|
-
propertySignatures: nonNullType.propertySignatures,
|
|
436
|
-
meta: isNullableDiscriminatedUnion ? { _isNullableDiscriminatedUnion: true } : {}
|
|
437
|
-
})
|
|
438
|
-
)
|
|
439
|
-
}
|
|
440
|
-
}
|
|
441
|
-
} else {
|
|
442
|
-
// Check if any of the union types are arrays
|
|
443
|
-
const arrayTypes = nonNullTypes.filter(AST.isArrays)
|
|
444
|
-
if (arrayTypes.length > 0) {
|
|
445
|
-
const arrayType = arrayTypes[0] // Take the first array type
|
|
446
|
-
|
|
447
|
-
acc[key as NestedKeyOf<T>] = {
|
|
448
|
-
type: "multiple",
|
|
449
|
-
members: arrayType.elements,
|
|
450
|
-
rest: arrayType.rest,
|
|
451
|
-
required: isRequired,
|
|
452
|
-
nullableOrUndefined
|
|
453
|
-
} as FieldMeta
|
|
454
|
-
|
|
455
|
-
// If the array has struct elements, also create metadata for their properties
|
|
456
|
-
if (arrayType.rest && arrayType.rest.length > 0) {
|
|
457
|
-
const restElement = arrayType.rest[0]
|
|
458
|
-
if (AST.isObjects(restElement)) {
|
|
459
|
-
for (const prop of restElement.propertySignatures) {
|
|
460
|
-
const propKey = `${key}.${prop.name.toString()}`
|
|
461
|
-
|
|
462
|
-
const propMeta = createMeta<T>({
|
|
463
|
-
parent: propKey,
|
|
464
|
-
property: prop.type,
|
|
465
|
-
meta: {
|
|
466
|
-
required: !isNullableOrUndefined(prop.type),
|
|
467
|
-
nullableOrUndefined: isNullableOrUndefined(prop.type)
|
|
468
|
-
}
|
|
469
|
-
})
|
|
470
|
-
|
|
471
|
-
// add to accumulator if valid
|
|
472
|
-
if (propMeta && typeof propMeta === "object" && "type" in propMeta) {
|
|
473
|
-
acc[propKey as NestedKeyOf<T>] = propMeta as FieldMeta
|
|
474
|
-
|
|
475
|
-
if (
|
|
476
|
-
propMeta.type === "multiple" && AST.isArrays(prop.type) && prop
|
|
477
|
-
.type
|
|
478
|
-
.rest && prop.type.rest.length > 0
|
|
479
|
-
) {
|
|
480
|
-
const nestedRestElement = prop.type.rest[0]
|
|
481
|
-
if (AST.isObjects(nestedRestElement)) {
|
|
482
|
-
for (const nestedProp of nestedRestElement.propertySignatures) {
|
|
483
|
-
const nestedPropKey = `${propKey}.${nestedProp.name.toString()}`
|
|
484
|
-
|
|
485
|
-
const nestedPropMeta = createMeta<T>({
|
|
486
|
-
parent: nestedPropKey,
|
|
487
|
-
property: nestedProp.type,
|
|
488
|
-
meta: {
|
|
489
|
-
required: !isNullableOrUndefined(nestedProp.type),
|
|
490
|
-
nullableOrUndefined: isNullableOrUndefined(nestedProp.type)
|
|
491
|
-
}
|
|
492
|
-
})
|
|
493
|
-
|
|
494
|
-
// add to accumulator if valid
|
|
495
|
-
if (nestedPropMeta && typeof nestedPropMeta === "object" && "type" in nestedPropMeta) {
|
|
496
|
-
acc[nestedPropKey as NestedKeyOf<T>] = nestedPropMeta as FieldMeta
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
}
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
} else {
|
|
506
|
-
// If no struct members and no arrays, process as regular union
|
|
507
|
-
const newMeta = createMeta<T>({
|
|
508
|
-
parent: key,
|
|
509
|
-
property: p.type,
|
|
510
|
-
meta: { required: isRequired, nullableOrUndefined }
|
|
511
|
-
})
|
|
512
|
-
acc[key as NestedKeyOf<T>] = newMeta as FieldMeta
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
} else {
|
|
516
|
-
// Unwrap transformations (like ExtendedClass) to check for propertySignatures
|
|
517
|
-
const unwrappedTypeToProcess = getTransformationFrom(typeToProcess)
|
|
518
|
-
if (AST.isObjects(unwrappedTypeToProcess)) {
|
|
519
|
-
Object.assign(
|
|
520
|
-
acc,
|
|
521
|
-
createMeta<T>({
|
|
522
|
-
parent: key,
|
|
523
|
-
propertySignatures: unwrappedTypeToProcess.propertySignatures,
|
|
524
|
-
meta: { required: isRequired, nullableOrUndefined }
|
|
525
|
-
})
|
|
526
|
-
)
|
|
527
|
-
} else if (AST.isArrays(p.type)) {
|
|
528
|
-
// Check if it has struct elements
|
|
529
|
-
const hasStructElements = p.type.rest.length > 0
|
|
530
|
-
&& AST.isObjects(p.type.rest[0])
|
|
531
|
-
|
|
532
|
-
if (hasStructElements) {
|
|
533
|
-
// For arrays with struct elements, only create meta for nested fields, not the array itself
|
|
534
|
-
const elementType = p.type.rest[0]
|
|
535
|
-
if (AST.isObjects(elementType)) {
|
|
536
|
-
// Process each property in the array element
|
|
537
|
-
for (const prop of elementType.propertySignatures) {
|
|
538
|
-
const propKey = `${key}.${prop.name.toString()}`
|
|
539
|
-
|
|
540
|
-
// Check if the property is another array
|
|
541
|
-
if (AST.isArrays(prop.type) && prop.type.rest.length > 0) {
|
|
542
|
-
const nestedElementType = prop.type.rest[0]
|
|
543
|
-
if (AST.isObjects(nestedElementType)) {
|
|
544
|
-
// Array with struct elements - process nested fields
|
|
545
|
-
for (const nestedProp of nestedElementType.propertySignatures) {
|
|
546
|
-
const nestedKey = `${propKey}.${nestedProp.name.toString()}`
|
|
547
|
-
const nestedMeta = createMeta<T>({
|
|
548
|
-
parent: nestedKey,
|
|
549
|
-
property: nestedProp.type,
|
|
550
|
-
meta: {
|
|
551
|
-
required: !isNullableOrUndefined(nestedProp.type),
|
|
552
|
-
nullableOrUndefined: isNullableOrUndefined(nestedProp.type)
|
|
553
|
-
}
|
|
554
|
-
})
|
|
555
|
-
acc[nestedKey as NestedKeyOf<T>] = nestedMeta as FieldMeta
|
|
556
|
-
}
|
|
557
|
-
} else {
|
|
558
|
-
// Array with primitive elements - create meta for the array itself
|
|
559
|
-
acc[propKey as NestedKeyOf<T>] = {
|
|
560
|
-
type: "multiple",
|
|
561
|
-
members: prop.type.elements,
|
|
562
|
-
rest: prop.type.rest,
|
|
563
|
-
required: !isNullableOrUndefined(prop.type),
|
|
564
|
-
nullableOrUndefined: isNullableOrUndefined(prop.type)
|
|
565
|
-
} as FieldMeta
|
|
566
|
-
}
|
|
567
|
-
} else {
|
|
568
|
-
const fieldMeta = createMeta<T>({
|
|
569
|
-
parent: propKey,
|
|
570
|
-
property: prop.type,
|
|
571
|
-
meta: {
|
|
572
|
-
required: !isNullableOrUndefined(prop.type),
|
|
573
|
-
nullableOrUndefined: isNullableOrUndefined(prop.type)
|
|
574
|
-
}
|
|
575
|
-
})
|
|
576
|
-
acc[propKey as NestedKeyOf<T>] = fieldMeta as FieldMeta
|
|
577
|
-
}
|
|
578
|
-
}
|
|
579
|
-
}
|
|
580
|
-
} else {
|
|
581
|
-
// For arrays with primitive elements, create the array meta
|
|
582
|
-
acc[key as NestedKeyOf<T>] = {
|
|
583
|
-
type: "multiple",
|
|
584
|
-
members: p.type.elements,
|
|
585
|
-
rest: p.type.rest,
|
|
586
|
-
required: isRequired,
|
|
587
|
-
nullableOrUndefined
|
|
588
|
-
} as FieldMeta
|
|
589
|
-
}
|
|
590
|
-
} else {
|
|
591
|
-
const newMeta = createMeta<T>({
|
|
592
|
-
parent: key,
|
|
593
|
-
property: p.type,
|
|
594
|
-
meta: {
|
|
595
|
-
required: isRequired,
|
|
596
|
-
nullableOrUndefined,
|
|
597
|
-
...(isIntField && { refinement: "int" })
|
|
598
|
-
}
|
|
599
|
-
})
|
|
600
|
-
|
|
601
|
-
acc[key as NestedKeyOf<T>] = newMeta as FieldMeta
|
|
602
|
-
}
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
return acc
|
|
606
|
-
}
|
|
607
|
-
|
|
608
|
-
if (property) {
|
|
609
|
-
const nullableOrUndefined = getNullableOrUndefined(property)
|
|
610
|
-
|
|
611
|
-
if (!Object.hasOwnProperty.call(meta, "required")) {
|
|
612
|
-
meta["required"] = !nullableOrUndefined
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
if (AST.isUnion(property)) {
|
|
616
|
-
// First unwrap any nested unions, then filter out null/undefined
|
|
617
|
-
const unwrappedTypes = unwrapNestedUnions(property.types)
|
|
618
|
-
const nonNullType = unwrappedTypes.find(
|
|
619
|
-
(t) => !AST.isUndefined(t) && !AST.isNull(t)
|
|
620
|
-
)!
|
|
621
|
-
|
|
622
|
-
if (AST.isObjects(nonNullType)) {
|
|
623
|
-
return createMeta<T>({
|
|
624
|
-
propertySignatures: nonNullType.propertySignatures,
|
|
625
|
-
parent,
|
|
626
|
-
meta
|
|
627
|
-
})
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
if (unwrappedTypes.every(AST.isLiteral)) {
|
|
631
|
-
return {
|
|
632
|
-
...meta,
|
|
633
|
-
type: "select",
|
|
634
|
-
members: unwrappedTypes.map((t) => t.literal)
|
|
635
|
-
} as FieldMeta
|
|
636
|
-
}
|
|
637
|
-
|
|
638
|
-
return {
|
|
639
|
-
...meta,
|
|
640
|
-
...createMeta<T>({
|
|
641
|
-
parent,
|
|
642
|
-
meta,
|
|
643
|
-
property: nonNullType
|
|
644
|
-
})
|
|
645
|
-
} as FieldMeta
|
|
646
|
-
}
|
|
647
|
-
|
|
648
|
-
if (AST.isArrays(property)) {
|
|
649
|
-
return {
|
|
650
|
-
...meta,
|
|
651
|
-
type: "multiple",
|
|
652
|
-
members: property.elements,
|
|
653
|
-
rest: property.rest
|
|
654
|
-
} as FieldMeta
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
const JSONAnnotation = (property.annotations?.jsonSchema ?? {}) as Record<string, unknown>
|
|
658
|
-
|
|
659
|
-
meta = { ...JSONAnnotation, ...meta }
|
|
660
|
-
|
|
661
|
-
// check the title annotation BEFORE following "from" to detect refinements like S.Int
|
|
662
|
-
let titleType = property.annotations?.title ?? "unknown"
|
|
663
|
-
|
|
664
|
-
// Detect basic types from AST if no title annotation
|
|
665
|
-
if (titleType === "unknown") {
|
|
666
|
-
if (AST.isString(property)) {
|
|
667
|
-
titleType = "string"
|
|
668
|
-
} else if (AST.isNumber(property)) {
|
|
669
|
-
titleType = "number"
|
|
670
|
-
} else if (AST.isBoolean(property)) {
|
|
671
|
-
titleType = "boolean"
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
// if this is S.Int (a refinement), set the type and skip following "from"
|
|
676
|
-
// otherwise we'd lose the "Int" information and get "number" instead
|
|
677
|
-
if (titleType === "Int" || titleType === "int") {
|
|
678
|
-
meta["type"] = "number"
|
|
679
|
-
meta["refinement"] = "int"
|
|
680
|
-
// don't follow "from" for Int refinements
|
|
681
|
-
} else {
|
|
682
|
-
meta["type"] = titleType
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// Always ensure required is set before returning
|
|
686
|
-
if (!Object.hasOwnProperty.call(meta, "required")) {
|
|
687
|
-
meta["required"] = !nullableOrUndefined
|
|
688
|
-
}
|
|
689
|
-
|
|
690
|
-
return meta as FieldMeta
|
|
691
|
-
}
|
|
692
|
-
|
|
693
|
-
return acc
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
// Helper to flatten nested meta structure into dot-notation keys
|
|
697
|
-
const flattenMeta = <T>(meta: MetaRecord<T> | FieldMeta, parentKey: string = ""): MetaRecord<T> => {
|
|
698
|
-
const result: MetaRecord<T> = {}
|
|
699
|
-
|
|
700
|
-
for (const key in meta) {
|
|
701
|
-
const value = (meta as any)[key]
|
|
702
|
-
const newKey = parentKey ? `${parentKey}.${key}` : key
|
|
703
|
-
|
|
704
|
-
if (value && typeof value === "object" && "type" in value) {
|
|
705
|
-
result[newKey as DeepKeys<T>] = value as FieldMeta
|
|
706
|
-
} else if (value && typeof value === "object") {
|
|
707
|
-
Object.assign(result, flattenMeta<T>(value, newKey))
|
|
708
|
-
}
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
return result
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
const _schemaFromAst = (ast: AST.AST): S.Codec<any> => S.make(ast)
|
|
715
|
-
|
|
716
|
-
const metadataFromAst = <_From, To>(
|
|
717
|
-
schema: any // v4 Schema type is complex, use any for now
|
|
718
|
-
): { meta: MetaRecord<To>; defaultValues: Record<string, any>; unionMeta: Record<string, MetaRecord<To>> } => {
|
|
719
|
-
const ast = schema.ast
|
|
720
|
-
const newMeta: MetaRecord<To> = {}
|
|
721
|
-
const defaultValues: Record<string, any> = {}
|
|
722
|
-
const unionMeta: Record<string, MetaRecord<To>> = {}
|
|
723
|
-
|
|
724
|
-
// Handle root-level Union types (discriminated unions)
|
|
725
|
-
if (AST.isUnion(ast)) {
|
|
726
|
-
const types = ast.types
|
|
727
|
-
|
|
728
|
-
// Filter out null/undefined types and unwrap transformations
|
|
729
|
-
const nonNullTypes = types
|
|
730
|
-
.filter((t: any) => !AST.isUndefined(t) && !AST.isNull(t))
|
|
731
|
-
.map(getTransformationFrom)
|
|
732
|
-
|
|
733
|
-
// Check if this is a discriminated union (all members are structs)
|
|
734
|
-
const allStructs = nonNullTypes.every((t: any) => AST.isObjects(t))
|
|
735
|
-
|
|
736
|
-
if (allStructs && nonNullTypes.length > 0) {
|
|
737
|
-
// Extract discriminator values from each union member
|
|
738
|
-
const discriminatorValues: any[] = []
|
|
739
|
-
|
|
740
|
-
// Store metadata for each union member by its tag value
|
|
741
|
-
for (const memberType of nonNullTypes) {
|
|
742
|
-
if (AST.isObjects(memberType)) {
|
|
743
|
-
// Find the discriminator field (usually _tag)
|
|
744
|
-
const tagProp = memberType.propertySignatures.find(
|
|
745
|
-
(p: any) => p.name.toString() === "_tag"
|
|
746
|
-
)
|
|
747
|
-
|
|
748
|
-
let tagValue: string | null = null
|
|
749
|
-
if (tagProp && AST.isLiteral(tagProp.type)) {
|
|
750
|
-
tagValue = tagProp.type.literal as string
|
|
751
|
-
discriminatorValues.push(tagValue)
|
|
752
|
-
}
|
|
753
|
-
|
|
754
|
-
// Create metadata for this member's properties
|
|
755
|
-
const memberMeta = createMeta<To>({
|
|
756
|
-
propertySignatures: memberType.propertySignatures
|
|
757
|
-
})
|
|
758
|
-
|
|
759
|
-
// Store per-tag metadata for reactive lookup
|
|
760
|
-
if (tagValue) {
|
|
761
|
-
unionMeta[tagValue] = flattenMeta<To>(memberMeta)
|
|
762
|
-
}
|
|
763
|
-
|
|
764
|
-
// Merge into result (for backward compatibility)
|
|
765
|
-
Object.assign(newMeta, memberMeta)
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
// Create metadata for the discriminator field
|
|
770
|
-
if (discriminatorValues.length > 0) {
|
|
771
|
-
newMeta["_tag" as DeepKeys<To>] = {
|
|
772
|
-
type: "select",
|
|
773
|
-
members: discriminatorValues,
|
|
774
|
-
required: true
|
|
775
|
-
} as FieldMeta
|
|
776
|
-
}
|
|
777
|
-
|
|
778
|
-
return { meta: newMeta, defaultValues, unionMeta }
|
|
779
|
-
}
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
if (AST.isObjects(ast)) {
|
|
783
|
-
const meta = createMeta<To>({
|
|
784
|
-
propertySignatures: ast.propertySignatures
|
|
785
|
-
})
|
|
786
|
-
|
|
787
|
-
if (Object.values(meta).every((value) => value && "type" in value)) {
|
|
788
|
-
return { meta: meta as MetaRecord<To>, defaultValues, unionMeta }
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
const flattenObject = (
|
|
792
|
-
obj: Record<string, any>,
|
|
793
|
-
parentKey: string = ""
|
|
794
|
-
) => {
|
|
795
|
-
for (const key in obj) {
|
|
796
|
-
const newKey = parentKey ? `${parentKey}.${key}` : key
|
|
797
|
-
if (obj[key] && typeof obj[key] === "object" && "type" in obj[key]) {
|
|
798
|
-
newMeta[newKey as DeepKeys<To>] = obj[key] as FieldMeta
|
|
799
|
-
} else if (obj[key] && typeof obj[key] === "object") {
|
|
800
|
-
flattenObject(obj[key], newKey)
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
flattenObject(meta)
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
return { meta: newMeta, defaultValues, unionMeta }
|
|
809
|
-
}
|
|
810
|
-
|
|
811
|
-
export const duplicateSchema = <From, To>(
|
|
812
|
-
schema: S.Codec<To, From, never>
|
|
813
|
-
) => {
|
|
814
|
-
return schema
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
export const generateMetaFromSchema = <_From, To>(
|
|
818
|
-
schema: any // v4 Schema type is complex, use any for now
|
|
819
|
-
): {
|
|
820
|
-
schema: any
|
|
821
|
-
meta: MetaRecord<To>
|
|
822
|
-
unionMeta: Record<string, MetaRecord<To>>
|
|
823
|
-
} => {
|
|
824
|
-
const { meta, unionMeta } = metadataFromAst(schema)
|
|
825
|
-
|
|
826
|
-
return { schema, meta, unionMeta }
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
export const generateInputStandardSchemaFromFieldMeta = (
|
|
830
|
-
meta: FieldMeta,
|
|
831
|
-
trans?: ReturnType<typeof useIntl>["trans"]
|
|
832
|
-
): StandardSchemaV1<any, any> => {
|
|
833
|
-
if (!trans) {
|
|
834
|
-
trans = useIntl().trans
|
|
835
|
-
}
|
|
836
|
-
let schema: S.Codec<any>
|
|
837
|
-
|
|
838
|
-
switch (meta.type) {
|
|
839
|
-
case "string": {
|
|
840
|
-
schema = S.String
|
|
841
|
-
|
|
842
|
-
// Apply format-specific schemas
|
|
843
|
-
if (meta.format === "email") {
|
|
844
|
-
// v4 doesn't have S.Email, use pattern validation
|
|
845
|
-
schema = S.String.check(
|
|
846
|
-
S.makeFilter(
|
|
847
|
-
(s) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s) || trans("validation.email.invalid"),
|
|
848
|
-
{ title: "email format" }
|
|
849
|
-
)
|
|
850
|
-
)
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
// Apply length validations
|
|
854
|
-
if (meta.required || typeof meta.minLength === "number") {
|
|
855
|
-
const minLen = meta.required ? Math.max(1, meta.minLength || 0) : (meta.minLength || 0)
|
|
856
|
-
if (minLen > 0) {
|
|
857
|
-
schema = schema.check(
|
|
858
|
-
S.makeFilter(
|
|
859
|
-
(s) => s.length >= minLen || trans("validation.string.minLength", { minLength: minLen }),
|
|
860
|
-
{ title: `minLength(${minLen})` }
|
|
861
|
-
)
|
|
862
|
-
)
|
|
863
|
-
}
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
if (typeof meta.maxLength === "number") {
|
|
867
|
-
schema = schema.check(
|
|
868
|
-
S.makeFilter(
|
|
869
|
-
(s) => s.length <= meta.maxLength! || trans("validation.string.maxLength", { maxLength: meta.maxLength }),
|
|
870
|
-
{ title: `maxLength(${meta.maxLength})` }
|
|
871
|
-
)
|
|
872
|
-
)
|
|
873
|
-
}
|
|
874
|
-
break
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
case "number": {
|
|
878
|
-
if (meta.refinement === "int") {
|
|
879
|
-
schema = S.Int
|
|
880
|
-
} else {
|
|
881
|
-
schema = S.Number
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
// Apply numeric validations
|
|
885
|
-
if (typeof meta.minimum === "number") {
|
|
886
|
-
schema = schema.check(
|
|
887
|
-
S.makeFilter(
|
|
888
|
-
(n) =>
|
|
889
|
-
n >= meta.minimum! || trans(
|
|
890
|
-
meta.minimum === 0 ? "validation.number.positive" : "validation.number.min",
|
|
891
|
-
{ minimum: meta.minimum, isExclusive: false }
|
|
892
|
-
),
|
|
893
|
-
{ title: `>=${meta.minimum}` }
|
|
894
|
-
)
|
|
895
|
-
)
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
if (typeof meta.maximum === "number") {
|
|
899
|
-
schema = schema.check(
|
|
900
|
-
S.makeFilter(
|
|
901
|
-
(n) =>
|
|
902
|
-
n <= meta.maximum! || trans("validation.number.max", {
|
|
903
|
-
maximum: meta.maximum,
|
|
904
|
-
isExclusive: false
|
|
905
|
-
}),
|
|
906
|
-
{ title: `<=${meta.maximum}` }
|
|
907
|
-
)
|
|
908
|
-
)
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
if (typeof meta.exclusiveMinimum === "number") {
|
|
912
|
-
schema = schema.check(
|
|
913
|
-
S.makeFilter(
|
|
914
|
-
(n) =>
|
|
915
|
-
n > meta.exclusiveMinimum! || trans(
|
|
916
|
-
meta.exclusiveMinimum === 0 ? "validation.number.positive" : "validation.number.min",
|
|
917
|
-
{ minimum: meta.exclusiveMinimum, isExclusive: true }
|
|
918
|
-
),
|
|
919
|
-
{ title: `>${meta.exclusiveMinimum}` }
|
|
920
|
-
)
|
|
921
|
-
)
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
if (typeof meta.exclusiveMaximum === "number") {
|
|
925
|
-
schema = schema.check(
|
|
926
|
-
S.makeFilter(
|
|
927
|
-
(n) =>
|
|
928
|
-
n < meta.exclusiveMaximum! || trans("validation.number.max", {
|
|
929
|
-
maximum: meta.exclusiveMaximum,
|
|
930
|
-
isExclusive: true
|
|
931
|
-
}),
|
|
932
|
-
{ title: `<${meta.exclusiveMaximum}` }
|
|
933
|
-
)
|
|
934
|
-
)
|
|
935
|
-
}
|
|
936
|
-
break
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
case "select": {
|
|
940
|
-
// Use Literal for select options
|
|
941
|
-
if (meta.members.length === 0) {
|
|
942
|
-
schema = S.Unknown
|
|
943
|
-
} else if (meta.members.length === 1) {
|
|
944
|
-
schema = S.Literal(meta.members[0])
|
|
945
|
-
} else {
|
|
946
|
-
// v4 Union accepts an array of schemas
|
|
947
|
-
schema = S.Union(meta.members.map((m) => S.Literal(m)))
|
|
948
|
-
}
|
|
949
|
-
break
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
case "multiple": {
|
|
953
|
-
schema = S.Array(S.String)
|
|
954
|
-
break
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
case "boolean": {
|
|
958
|
-
schema = S.Boolean
|
|
959
|
-
break
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
case "unknown": {
|
|
963
|
-
schema = S.Unknown
|
|
964
|
-
break
|
|
965
|
-
}
|
|
966
|
-
|
|
967
|
-
default: {
|
|
968
|
-
console.warn(`Unhandled field type: ${(meta as any).type}`)
|
|
969
|
-
schema = S.Unknown
|
|
970
|
-
break
|
|
971
|
-
}
|
|
972
|
-
}
|
|
973
|
-
|
|
974
|
-
// Wrap in union with null/undefined if not required
|
|
975
|
-
if (!meta.required) {
|
|
976
|
-
// v4 Union takes an array of schemas
|
|
977
|
-
schema = S.Union([schema, S.Null, S.Undefined])
|
|
978
|
-
}
|
|
979
|
-
|
|
980
|
-
return S.toStandardSchemaV1(schema as any)
|
|
981
|
-
}
|
|
982
|
-
|
|
983
|
-
// TODO: Fix v4 migration - nullableInput transformation needs proper type handling
|
|
984
|
-
// export const nullableInput = <A>(
|
|
985
|
-
// schema: S.Codec<A>,
|
|
986
|
-
// defaultValue: () => A
|
|
987
|
-
// ): S.Codec<A> =>
|
|
988
|
-
// S.NullOr(schema).pipe(
|
|
989
|
-
// S.decodeTo(
|
|
990
|
-
// schema,
|
|
991
|
-
// SchemaTransformation.transform({
|
|
992
|
-
// decode: (input: A | null) => input ?? defaultValue(),
|
|
993
|
-
// encode: (output: A) => output
|
|
994
|
-
// })
|
|
995
|
-
// )
|
|
996
|
-
// )
|
|
997
|
-
|
|
998
|
-
export type OmegaAutoGenMeta<
|
|
999
|
-
From extends Record<PropertyKey, any>,
|
|
1000
|
-
To extends Record<PropertyKey, any>,
|
|
1001
|
-
Name extends DeepKeys<From>
|
|
1002
|
-
> = Omit<OmegaInputProps<From, To, Name>, "form">
|
|
1003
|
-
|
|
1004
|
-
const supportedInputs = [
|
|
1005
|
-
"button",
|
|
1006
|
-
"checkbox",
|
|
1007
|
-
"color",
|
|
1008
|
-
"date",
|
|
1009
|
-
"email",
|
|
1010
|
-
"number",
|
|
1011
|
-
"password",
|
|
1012
|
-
"radio",
|
|
1013
|
-
"range",
|
|
1014
|
-
"search",
|
|
1015
|
-
"submit",
|
|
1016
|
-
"tel",
|
|
1017
|
-
"text",
|
|
1018
|
-
"time",
|
|
1019
|
-
"url"
|
|
1020
|
-
] as const
|
|
1021
|
-
export type SupportedInputs = typeof supportedInputs[number]
|
|
1022
|
-
export const getInputType = (input: string): SupportedInputs =>
|
|
1023
|
-
(supportedInputs as readonly string[]).includes(input) ? input as SupportedInputs : "text"
|
|
1024
|
-
|
|
1025
|
-
export function deepMerge(target: any, source: any) {
|
|
1026
|
-
const result = { ...target }
|
|
1027
|
-
for (const key in source) {
|
|
1028
|
-
if (Array.isArray(source[key])) {
|
|
1029
|
-
// Arrays should be copied directly, not deep merged
|
|
1030
|
-
result[key] = source[key]
|
|
1031
|
-
} else if (source[key] && isObject(source[key])) {
|
|
1032
|
-
result[key] = deepMerge(result[key], source[key])
|
|
1033
|
-
} else {
|
|
1034
|
-
result[key] = source[key]
|
|
1035
|
-
}
|
|
1036
|
-
}
|
|
1037
|
-
return result
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
// Type definitions for schemas with fields and members
|
|
1041
|
-
type SchemaWithFields = {
|
|
1042
|
-
fields: Record<string, S.Top>
|
|
1043
|
-
}
|
|
1044
|
-
|
|
1045
|
-
type SchemaWithMembers = {
|
|
1046
|
-
members: readonly S.Top[]
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
// Type guards to check schema types
|
|
1050
|
-
function hasFields(schema: any): schema is SchemaWithFields {
|
|
1051
|
-
return schema && "fields" in schema && typeof schema.fields === "object"
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
function hasMembers(schema: any): schema is SchemaWithMembers {
|
|
1055
|
-
return schema && "members" in schema && Array.isArray(schema.members)
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
// Internal implementation with WeakSet tracking
|
|
1059
|
-
export const defaultsValueFromSchema = (
|
|
1060
|
-
schema: S.Codec<any>,
|
|
1061
|
-
record: Record<string, any> = {}
|
|
1062
|
-
): any => {
|
|
1063
|
-
const ast = schema.ast
|
|
1064
|
-
|
|
1065
|
-
if (isNullableOrUndefined(schema.ast) === "null") {
|
|
1066
|
-
return null
|
|
1067
|
-
}
|
|
1068
|
-
if (isNullableOrUndefined(schema.ast) === "undefined") {
|
|
1069
|
-
return undefined
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
// Handle v4 Objects AST structure
|
|
1073
|
-
if (AST.isObjects(ast)) {
|
|
1074
|
-
const result: Record<string, any> = { ...record }
|
|
1075
|
-
|
|
1076
|
-
for (const prop of ast.propertySignatures) {
|
|
1077
|
-
const key = prop.name.toString()
|
|
1078
|
-
const propType = prop.type
|
|
1079
|
-
|
|
1080
|
-
// Get the property schema from the original schema's fields if available
|
|
1081
|
-
// This preserves schema wrappers like withDefaultConstructor
|
|
1082
|
-
let propSchema: S.Codec<any>
|
|
1083
|
-
if ((schema as any).fields && (schema as any).fields[key]) {
|
|
1084
|
-
propSchema = (schema as any).fields[key]
|
|
1085
|
-
} else {
|
|
1086
|
-
propSchema = S.make(propType)
|
|
1087
|
-
}
|
|
1088
|
-
|
|
1089
|
-
// Recursively process the property to get its defaults
|
|
1090
|
-
const propValue = defaultsValueFromSchema(propSchema, record[key] || {})
|
|
1091
|
-
|
|
1092
|
-
if (propValue !== undefined) {
|
|
1093
|
-
result[key] = propValue
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
return result
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
// v3 compatible fields extraction
|
|
1101
|
-
if (hasFields(schema)) {
|
|
1102
|
-
// Process fields and extract default values
|
|
1103
|
-
const result: Record<string, any> = {}
|
|
1104
|
-
|
|
1105
|
-
for (const [key, fieldSchema] of Object.entries(schema.fields)) {
|
|
1106
|
-
// Check if this field has a defaultValue in its AST
|
|
1107
|
-
const fieldAst = (fieldSchema as any)?.ast
|
|
1108
|
-
if (fieldAst?.defaultValue) {
|
|
1109
|
-
try {
|
|
1110
|
-
result[key] = fieldAst.defaultValue()
|
|
1111
|
-
continue
|
|
1112
|
-
} catch {
|
|
1113
|
-
// If defaultValue() throws, fall through to recursive processing
|
|
1114
|
-
}
|
|
1115
|
-
}
|
|
1116
|
-
|
|
1117
|
-
// Recursively process the field
|
|
1118
|
-
const fieldValue = defaultsValueFromSchema(fieldSchema as any, record[key] || {})
|
|
1119
|
-
if (fieldValue !== undefined) {
|
|
1120
|
-
result[key] = fieldValue
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
|
|
1124
|
-
return { ...result, ...record }
|
|
1125
|
-
}
|
|
1126
|
-
|
|
1127
|
-
// Check if schema has fields in from (for ExtendedClass and similar transformations)
|
|
1128
|
-
if ((schema as any)?.from && hasFields((schema as any).from)) {
|
|
1129
|
-
return defaultsValueFromSchema((schema as any).from, record)
|
|
1130
|
-
}
|
|
1131
|
-
|
|
1132
|
-
if (hasMembers(schema)) {
|
|
1133
|
-
// Merge all member fields, giving precedence to fields with default values
|
|
1134
|
-
const mergedMembers = schema.members.reduce((acc, member) => {
|
|
1135
|
-
if (hasFields(member)) {
|
|
1136
|
-
// Check each field and give precedence to ones with default values
|
|
1137
|
-
Object.entries(member.fields).forEach(([key, fieldSchema]) => {
|
|
1138
|
-
const fieldAst: any = fieldSchema.ast
|
|
1139
|
-
const existingFieldAst: any = acc[key]?.ast
|
|
1140
|
-
|
|
1141
|
-
// If field doesn't exist yet, or new field has default and existing doesn't, use new field
|
|
1142
|
-
if (!acc[key] || (fieldAst?.defaultValue && !existingFieldAst?.defaultValue)) {
|
|
1143
|
-
acc[key] = fieldSchema
|
|
1144
|
-
}
|
|
1145
|
-
// If both have defaults or neither have defaults, keep the first one (existing)
|
|
1146
|
-
})
|
|
1147
|
-
return acc
|
|
1148
|
-
}
|
|
1149
|
-
return acc
|
|
1150
|
-
}, {} as Record<string, any>)
|
|
1151
|
-
|
|
1152
|
-
// Use reduce to properly accumulate the merged fields
|
|
1153
|
-
return Object.entries(mergedMembers).reduce((acc, [key, value]) => {
|
|
1154
|
-
acc[key] = defaultsValueFromSchema(value, record[key] || {})
|
|
1155
|
-
return acc
|
|
1156
|
-
}, record)
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
if (Object.keys(record).length === 0) {
|
|
1160
|
-
// Check for constructor defaults in v4's context
|
|
1161
|
-
if (ast.context?.defaultValue) {
|
|
1162
|
-
// In v4, defaultValue is an Encoding type, not directly callable
|
|
1163
|
-
// For now, skip complex default extraction
|
|
1164
|
-
// TODO: properly extract default from encoding chain
|
|
1165
|
-
}
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
if (AST.isString(ast)) {
|
|
1169
|
-
return ""
|
|
1170
|
-
}
|
|
1171
|
-
if (AST.isBoolean(ast)) {
|
|
1172
|
-
return false
|
|
1173
|
-
}
|
|
1174
|
-
}
|