@effect-app/vue-components 3.2.0 → 4.0.0-beta.0
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/dist/types/components/OmegaForm/OmegaAutoGen.vue.d.ts +1 -1
- package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +11 -13
- package/dist/types/components/OmegaForm/useOmegaForm.d.ts +6 -4
- package/dist/types/utils/index.d.ts +4 -3
- package/dist/vue-components.es.js +13 -14
- package/dist/vue-components.es10.js +109 -115
- package/dist/vue-components.es11.js +1 -1
- package/dist/vue-components.es12.js +290 -341
- package/dist/vue-components.es17.js +723 -4
- package/dist/vue-components.es18.js +140 -9
- package/dist/vue-components.es19.js +4 -55
- package/dist/vue-components.es2.js +17 -18
- package/dist/vue-components.es20.js +11 -68
- package/dist/vue-components.es21.js +3 -6
- package/dist/vue-components.es22.js +24 -6
- package/dist/vue-components.es23.js +4 -3
- package/dist/vue-components.es24.js +8 -3
- package/dist/vue-components.es25.js +55 -2
- package/dist/vue-components.es26.js +69 -2
- package/dist/vue-components.es27.js +6 -2
- package/dist/vue-components.es28.js +6 -2
- package/dist/vue-components.es29.js +3 -17
- package/dist/vue-components.es3.js +9 -9
- package/dist/vue-components.es30.js +3 -192
- package/dist/vue-components.es31.js +4 -0
- package/dist/vue-components.es32.js +2 -42
- package/dist/vue-components.es33.js +1 -1
- package/dist/vue-components.es34.js +1 -1
- package/dist/vue-components.es35.js +17 -111
- package/dist/vue-components.es36.js +40 -0
- package/dist/vue-components.es37.js +4 -7
- package/dist/vue-components.es38.js +82 -31
- package/dist/vue-components.es39.js +54 -0
- package/dist/vue-components.es40.js +561 -4
- package/dist/vue-components.es41.js +40 -22
- package/dist/vue-components.es42.js +27 -5
- package/dist/vue-components.es43.js +5 -21
- package/dist/vue-components.es44.js +39 -29
- package/dist/vue-components.es45.js +313 -21
- package/dist/vue-components.es46.js +31 -12
- package/dist/vue-components.es47.js +4 -5
- package/dist/vue-components.es48.js +23 -18
- package/dist/vue-components.es49.js +74 -8
- package/dist/vue-components.es50.js +98 -30
- package/dist/vue-components.es51.js +2 -48
- package/dist/vue-components.es52.js +317 -25
- package/dist/vue-components.es53.js +64 -11
- package/dist/vue-components.es54.js +2 -65
- package/dist/vue-components.es55.js +2 -56
- package/dist/vue-components.es56.js +110 -16
- package/dist/vue-components.es58.js +7 -29
- package/dist/vue-components.es59.js +31 -41
- package/dist/vue-components.es61.js +190 -42
- package/dist/vue-components.es63.js +6 -0
- package/dist/vue-components.es64.js +103 -0
- package/dist/vue-components.es65.js +4 -0
- package/dist/vue-components.es66.js +23 -0
- package/dist/vue-components.es67.js +84 -0
- package/dist/vue-components.es68.js +14 -0
- package/dist/vue-components.es69.js +115 -0
- package/dist/vue-components.es7.js +1 -1
- package/dist/vue-components.es70.js +5 -0
- package/dist/vue-components.es71.js +34 -0
- package/dist/vue-components.es72.js +4 -0
- package/dist/vue-components.es73.js +4 -0
- package/dist/vue-components.es74.js +17 -0
- package/dist/vue-components.es75.js +72 -0
- package/dist/vue-components.es76.js +25 -0
- package/dist/vue-components.es77.js +7 -0
- package/dist/vue-components.es78.js +23 -0
- package/dist/vue-components.es79.js +32 -0
- package/dist/vue-components.es80.js +24 -0
- package/dist/vue-components.es81.js +14 -0
- package/dist/vue-components.es82.js +7 -0
- package/dist/vue-components.es83.js +21 -0
- package/dist/vue-components.es84.js +11 -0
- package/dist/vue-components.es85.js +33 -0
- package/dist/vue-components.es86.js +50 -0
- package/dist/vue-components.es87.js +28 -0
- package/dist/vue-components.es88.js +17 -0
- package/dist/vue-components.es89.js +18 -0
- package/dist/vue-components.es90.js +10 -0
- package/dist/vue-components.es91.js +13 -0
- package/dist/vue-components.es92.js +67 -0
- package/dist/vue-components.es93.js +58 -0
- package/dist/vue-components.es94.js +19 -0
- package/dist/{vue-components.es57.js → vue-components.es95.js} +3 -3
- package/dist/vue-components.es96.js +31 -0
- package/dist/vue-components.es97.js +44 -0
- package/dist/vue-components.es99.js +46 -0
- package/package.json +25 -24
- package/src/components/OmegaForm/OmegaAutoGen.vue +11 -10
- package/src/components/OmegaForm/OmegaErrorsInternal.vue +3 -2
- package/src/components/OmegaForm/OmegaFormStuff.ts +249 -274
- package/src/components/OmegaForm/OmegaInternalInput.vue +1 -1
- package/src/components/OmegaForm/useOmegaForm.ts +27 -28
- package/src/utils/index.ts +7 -7
- /package/dist/{vue-components.es62.js → vue-components.es100.js} +0 -0
- /package/dist/{vue-components.es60.js → vue-components.es98.js} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import
|
|
1
|
+
import type * as Effect from "effect/Effect"
|
|
2
|
+
import * as AST from "effect/SchemaAST"
|
|
2
3
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
3
|
-
import { getMetadataFromSchema } from "@effect-app/vue/form"
|
|
4
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
5
|
import { isObject } from "@vueuse/core"
|
|
6
|
-
import
|
|
6
|
+
import * as S from "effect/Schema"
|
|
7
7
|
import { getTransformationFrom, useIntl } from "../../utils"
|
|
8
8
|
import { type OmegaFieldInternalApi } from "./InputProps"
|
|
9
9
|
import { type OF, type OmegaFormReturn } from "./useOmegaForm"
|
|
@@ -145,7 +145,7 @@ export type FormProps<From, To> =
|
|
|
145
145
|
formApi: OmegaFormParams<From, To>
|
|
146
146
|
meta: any
|
|
147
147
|
value: To
|
|
148
|
-
}) => Promise<any> |
|
|
148
|
+
}) => Promise<any> | Effect.Effect<unknown, any, never>
|
|
149
149
|
}
|
|
150
150
|
|
|
151
151
|
export type OmegaFormParams<From, To> = FormApi<
|
|
@@ -262,7 +262,7 @@ export type SelectFieldMeta = BaseFieldMeta & {
|
|
|
262
262
|
export type MultipleFieldMeta = BaseFieldMeta & {
|
|
263
263
|
type: "multiple"
|
|
264
264
|
members: any[] // TODO: should be non empty array?
|
|
265
|
-
rest:
|
|
265
|
+
rest: readonly AST.AST[]
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
export type BooleanFieldMeta = BaseFieldMeta & {
|
|
@@ -301,25 +301,23 @@ export type CreateMeta =
|
|
|
301
301
|
}
|
|
302
302
|
& (
|
|
303
303
|
| {
|
|
304
|
-
propertySignatures: readonly
|
|
304
|
+
propertySignatures: readonly AST.PropertySignature[]
|
|
305
305
|
property?: never
|
|
306
306
|
}
|
|
307
307
|
| {
|
|
308
308
|
propertySignatures?: never
|
|
309
|
-
property:
|
|
309
|
+
property: AST.AST
|
|
310
310
|
}
|
|
311
311
|
)
|
|
312
312
|
|
|
313
|
-
const getNullableOrUndefined = (property:
|
|
314
|
-
return
|
|
315
|
-
|
|
316
|
-
&& property.types.find((_) => _._tag === "UndefinedKeyword" || _ === S.Null.ast)
|
|
317
|
-
)
|
|
313
|
+
const getNullableOrUndefined = (property: AST.AST) => {
|
|
314
|
+
if (!AST.isUnion(property)) return false
|
|
315
|
+
return property.types.find((_) => AST.isUndefined(_) || _ === S.Null.ast)
|
|
318
316
|
}
|
|
319
317
|
|
|
320
|
-
export const isNullableOrUndefined = (property: false |
|
|
321
|
-
if (!property || !
|
|
322
|
-
if (property.types.find((_) => _
|
|
318
|
+
export const isNullableOrUndefined = (property: false | AST.AST | undefined) => {
|
|
319
|
+
if (!property || !AST.isUnion(property)) return false
|
|
320
|
+
if (property.types.find((_) => AST.isUndefined(_))) {
|
|
323
321
|
return "undefined"
|
|
324
322
|
}
|
|
325
323
|
if (property.types.find((_) => _ === S.Null.ast)) return "null"
|
|
@@ -327,10 +325,10 @@ export const isNullableOrUndefined = (property: false | S.AST.AST | undefined) =
|
|
|
327
325
|
}
|
|
328
326
|
|
|
329
327
|
// Helper function to recursively unwrap nested unions (e.g., S.NullOr(S.NullOr(X)) -> X)
|
|
330
|
-
const unwrapNestedUnions = (types: readonly
|
|
331
|
-
const result:
|
|
328
|
+
const unwrapNestedUnions = (types: readonly AST.AST[]): readonly AST.AST[] => {
|
|
329
|
+
const result: AST.AST[] = []
|
|
332
330
|
for (const type of types) {
|
|
333
|
-
if (
|
|
331
|
+
if (AST.isUnion(type)) {
|
|
334
332
|
// Recursively unwrap nested unions
|
|
335
333
|
const unwrapped = unwrapNestedUnions(type.types)
|
|
336
334
|
result.push(...unwrapped)
|
|
@@ -349,24 +347,23 @@ export const createMeta = <T = any>(
|
|
|
349
347
|
// this calls createMeta recursively, so wrapped transformations are also unwrapped
|
|
350
348
|
// BUT: check for Int title annotation first - S.Int and branded Int have title "Int" or "int"
|
|
351
349
|
// and we don't want to lose that information by unwrapping
|
|
352
|
-
if (property && property
|
|
353
|
-
const titleOnTransform =
|
|
354
|
-
.AST
|
|
355
|
-
.getAnnotation(property, S.AST.TitleAnnotationId)
|
|
356
|
-
.pipe(Option.getOrElse(() => ""))
|
|
350
|
+
if (property && AST.isDeclaration(property)) {
|
|
351
|
+
const titleOnTransform = property.annotations?.title ?? ""
|
|
357
352
|
|
|
358
353
|
// only unwrap if this is NOT an Int type
|
|
359
354
|
if (titleOnTransform !== "Int" && titleOnTransform !== "int") {
|
|
355
|
+
// In v4, Declaration doesn't have a 'from' property
|
|
356
|
+
// Just return the property as-is
|
|
360
357
|
return createMeta<T>({
|
|
361
358
|
parent,
|
|
362
359
|
meta,
|
|
363
|
-
property
|
|
360
|
+
property
|
|
364
361
|
})
|
|
365
362
|
}
|
|
366
363
|
// if it's Int, fall through to process it with the Int type
|
|
367
364
|
}
|
|
368
365
|
|
|
369
|
-
if (property
|
|
366
|
+
if (property && AST.isObjects(property)) {
|
|
370
367
|
return createMeta<T>({
|
|
371
368
|
meta,
|
|
372
369
|
propertySignatures: property.propertySignatures
|
|
@@ -378,6 +375,10 @@ export const createMeta = <T = any>(
|
|
|
378
375
|
const key = parent ? `${parent}.${p.name.toString()}` : p.name.toString()
|
|
379
376
|
const nullableOrUndefined = isNullableOrUndefined(p.type)
|
|
380
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
|
+
|
|
381
382
|
// Determine if this field should be required:
|
|
382
383
|
// - For nullable discriminated unions, only _tag should be non-required
|
|
383
384
|
// - All other fields should calculate their required status normally
|
|
@@ -394,18 +395,18 @@ export const createMeta = <T = any>(
|
|
|
394
395
|
}
|
|
395
396
|
|
|
396
397
|
const typeToProcess = p.type
|
|
397
|
-
if (
|
|
398
|
+
if (AST.isUnion(p.type)) {
|
|
398
399
|
// First unwrap any nested unions, then filter out null/undefined
|
|
399
400
|
const unwrappedTypes = unwrapNestedUnions(p.type.types)
|
|
400
401
|
const nonNullTypes = unwrappedTypes
|
|
401
402
|
.filter(
|
|
402
|
-
(t) => t
|
|
403
|
+
(t) => !AST.isUndefined(t) && !AST.isNull(t)
|
|
403
404
|
)
|
|
404
405
|
// unwraps class (Class are transformations)
|
|
405
406
|
.map(getTransformationFrom)
|
|
406
407
|
|
|
407
408
|
const hasStructMembers = nonNullTypes.some(
|
|
408
|
-
(t) =>
|
|
409
|
+
(t) => AST.isObjects(t)
|
|
409
410
|
)
|
|
410
411
|
|
|
411
412
|
if (hasStructMembers) {
|
|
@@ -421,7 +422,7 @@ export const createMeta = <T = any>(
|
|
|
421
422
|
|
|
422
423
|
// Process each non-null type and merge their metadata
|
|
423
424
|
for (const nonNullType of nonNullTypes) {
|
|
424
|
-
if (
|
|
425
|
+
if (AST.isObjects(nonNullType)) {
|
|
425
426
|
// For discriminated unions (multiple branches):
|
|
426
427
|
// - If the parent union is nullable, only _tag should be non-required
|
|
427
428
|
// - All other fields maintain their normal required status based on their own types
|
|
@@ -438,8 +439,8 @@ export const createMeta = <T = any>(
|
|
|
438
439
|
}
|
|
439
440
|
}
|
|
440
441
|
} else {
|
|
441
|
-
// Check if any of the union types are arrays
|
|
442
|
-
const arrayTypes = nonNullTypes.filter(
|
|
442
|
+
// Check if any of the union types are arrays
|
|
443
|
+
const arrayTypes = nonNullTypes.filter(AST.isArrays)
|
|
443
444
|
if (arrayTypes.length > 0) {
|
|
444
445
|
const arrayType = arrayTypes[0] // Take the first array type
|
|
445
446
|
|
|
@@ -454,8 +455,8 @@ export const createMeta = <T = any>(
|
|
|
454
455
|
// If the array has struct elements, also create metadata for their properties
|
|
455
456
|
if (arrayType.rest && arrayType.rest.length > 0) {
|
|
456
457
|
const restElement = arrayType.rest[0]
|
|
457
|
-
if (
|
|
458
|
-
for (const prop of restElement.
|
|
458
|
+
if (AST.isObjects(restElement)) {
|
|
459
|
+
for (const prop of restElement.propertySignatures) {
|
|
459
460
|
const propKey = `${key}.${prop.name.toString()}`
|
|
460
461
|
|
|
461
462
|
const propMeta = createMeta<T>({
|
|
@@ -472,15 +473,13 @@ export const createMeta = <T = any>(
|
|
|
472
473
|
acc[propKey as NestedKeyOf<T>] = propMeta as FieldMeta
|
|
473
474
|
|
|
474
475
|
if (
|
|
475
|
-
propMeta.type === "multiple" &&
|
|
476
|
+
propMeta.type === "multiple" && AST.isArrays(prop.type) && prop
|
|
476
477
|
.type
|
|
477
478
|
.rest && prop.type.rest.length > 0
|
|
478
479
|
) {
|
|
479
480
|
const nestedRestElement = prop.type.rest[0]
|
|
480
|
-
if (
|
|
481
|
-
|
|
482
|
-
) {
|
|
483
|
-
for (const nestedProp of nestedRestElement.type.propertySignatures) {
|
|
481
|
+
if (AST.isObjects(nestedRestElement)) {
|
|
482
|
+
for (const nestedProp of nestedRestElement.propertySignatures) {
|
|
484
483
|
const nestedPropKey = `${propKey}.${nestedProp.name.toString()}`
|
|
485
484
|
|
|
486
485
|
const nestedPropMeta = createMeta<T>({
|
|
@@ -516,7 +515,7 @@ export const createMeta = <T = any>(
|
|
|
516
515
|
} else {
|
|
517
516
|
// Unwrap transformations (like ExtendedClass) to check for propertySignatures
|
|
518
517
|
const unwrappedTypeToProcess = getTransformationFrom(typeToProcess)
|
|
519
|
-
if (
|
|
518
|
+
if (AST.isObjects(unwrappedTypeToProcess)) {
|
|
520
519
|
Object.assign(
|
|
521
520
|
acc,
|
|
522
521
|
createMeta<T>({
|
|
@@ -525,24 +524,23 @@ export const createMeta = <T = any>(
|
|
|
525
524
|
meta: { required: isRequired, nullableOrUndefined }
|
|
526
525
|
})
|
|
527
526
|
)
|
|
528
|
-
} else if (
|
|
527
|
+
} else if (AST.isArrays(p.type)) {
|
|
529
528
|
// Check if it has struct elements
|
|
530
529
|
const hasStructElements = p.type.rest.length > 0
|
|
531
|
-
&& p.type.rest[0]
|
|
532
|
-
&& "propertySignatures" in p.type.rest[0].type
|
|
530
|
+
&& AST.isObjects(p.type.rest[0])
|
|
533
531
|
|
|
534
532
|
if (hasStructElements) {
|
|
535
533
|
// For arrays with struct elements, only create meta for nested fields, not the array itself
|
|
536
|
-
const elementType = p.type.rest[0]
|
|
537
|
-
if (
|
|
534
|
+
const elementType = p.type.rest[0]
|
|
535
|
+
if (AST.isObjects(elementType)) {
|
|
538
536
|
// Process each property in the array element
|
|
539
537
|
for (const prop of elementType.propertySignatures) {
|
|
540
538
|
const propKey = `${key}.${prop.name.toString()}`
|
|
541
539
|
|
|
542
540
|
// Check if the property is another array
|
|
543
|
-
if (
|
|
544
|
-
const nestedElementType = prop.type.rest[0]
|
|
545
|
-
if (
|
|
541
|
+
if (AST.isArrays(prop.type) && prop.type.rest.length > 0) {
|
|
542
|
+
const nestedElementType = prop.type.rest[0]
|
|
543
|
+
if (AST.isObjects(nestedElementType)) {
|
|
546
544
|
// Array with struct elements - process nested fields
|
|
547
545
|
for (const nestedProp of nestedElementType.propertySignatures) {
|
|
548
546
|
const nestedKey = `${propKey}.${nestedProp.name.toString()}`
|
|
@@ -594,10 +592,9 @@ export const createMeta = <T = any>(
|
|
|
594
592
|
parent: key,
|
|
595
593
|
property: p.type,
|
|
596
594
|
meta: {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
nullableOrUndefined
|
|
595
|
+
required: isRequired,
|
|
596
|
+
nullableOrUndefined,
|
|
597
|
+
...(isIntField && { refinement: "int" })
|
|
601
598
|
}
|
|
602
599
|
})
|
|
603
600
|
|
|
@@ -615,14 +612,14 @@ export const createMeta = <T = any>(
|
|
|
615
612
|
meta["required"] = !nullableOrUndefined
|
|
616
613
|
}
|
|
617
614
|
|
|
618
|
-
if (
|
|
615
|
+
if (AST.isUnion(property)) {
|
|
619
616
|
// First unwrap any nested unions, then filter out null/undefined
|
|
620
617
|
const unwrappedTypes = unwrapNestedUnions(property.types)
|
|
621
618
|
const nonNullType = unwrappedTypes.find(
|
|
622
|
-
(t) => t
|
|
619
|
+
(t) => !AST.isUndefined(t) && !AST.isNull(t)
|
|
623
620
|
)!
|
|
624
621
|
|
|
625
|
-
if (
|
|
622
|
+
if (AST.isObjects(nonNullType)) {
|
|
626
623
|
return createMeta<T>({
|
|
627
624
|
propertySignatures: nonNullType.propertySignatures,
|
|
628
625
|
parent,
|
|
@@ -630,7 +627,7 @@ export const createMeta = <T = any>(
|
|
|
630
627
|
})
|
|
631
628
|
}
|
|
632
629
|
|
|
633
|
-
if (unwrappedTypes.every(
|
|
630
|
+
if (unwrappedTypes.every(AST.isLiteral)) {
|
|
634
631
|
return {
|
|
635
632
|
...meta,
|
|
636
633
|
type: "select",
|
|
@@ -648,7 +645,7 @@ export const createMeta = <T = any>(
|
|
|
648
645
|
} as FieldMeta
|
|
649
646
|
}
|
|
650
647
|
|
|
651
|
-
if (
|
|
648
|
+
if (AST.isArrays(property)) {
|
|
652
649
|
return {
|
|
653
650
|
...meta,
|
|
654
651
|
type: "multiple",
|
|
@@ -657,28 +654,23 @@ export const createMeta = <T = any>(
|
|
|
657
654
|
} as FieldMeta
|
|
658
655
|
}
|
|
659
656
|
|
|
660
|
-
const JSONAnnotation =
|
|
661
|
-
.AST
|
|
662
|
-
.getAnnotation(
|
|
663
|
-
property,
|
|
664
|
-
S.AST.JSONSchemaAnnotationId
|
|
665
|
-
)
|
|
666
|
-
.pipe(Option.getOrElse(() => ({}))) as Record<string, unknown>
|
|
657
|
+
const JSONAnnotation = (property.annotations?.jsonSchema ?? {}) as Record<string, unknown>
|
|
667
658
|
|
|
668
659
|
meta = { ...JSONAnnotation, ...meta }
|
|
669
660
|
|
|
670
661
|
// check the title annotation BEFORE following "from" to detect refinements like S.Int
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
.
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
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
|
+
}
|
|
682
674
|
|
|
683
675
|
// if this is S.Int (a refinement), set the type and skip following "from"
|
|
684
676
|
// otherwise we'd lose the "Int" information and get "number" instead
|
|
@@ -686,16 +678,15 @@ export const createMeta = <T = any>(
|
|
|
686
678
|
meta["type"] = "number"
|
|
687
679
|
meta["refinement"] = "int"
|
|
688
680
|
// don't follow "from" for Int refinements
|
|
689
|
-
} else if ("from" in property) {
|
|
690
|
-
return createMeta<T>({
|
|
691
|
-
parent,
|
|
692
|
-
meta,
|
|
693
|
-
property: property.from
|
|
694
|
-
})
|
|
695
681
|
} else {
|
|
696
682
|
meta["type"] = titleType
|
|
697
683
|
}
|
|
698
684
|
|
|
685
|
+
// Always ensure required is set before returning
|
|
686
|
+
if (!Object.hasOwnProperty.call(meta, "required")) {
|
|
687
|
+
meta["required"] = !nullableOrUndefined
|
|
688
|
+
}
|
|
689
|
+
|
|
699
690
|
return meta as FieldMeta
|
|
700
691
|
}
|
|
701
692
|
|
|
@@ -720,30 +711,27 @@ const flattenMeta = <T>(meta: MetaRecord<T> | FieldMeta, parentKey: string = "")
|
|
|
720
711
|
return result
|
|
721
712
|
}
|
|
722
713
|
|
|
723
|
-
const
|
|
724
|
-
|
|
714
|
+
const _schemaFromAst = (ast: AST.AST): S.Schema<any> => S.make(ast)
|
|
715
|
+
|
|
716
|
+
const metadataFromAst = <_From, To>(
|
|
717
|
+
schema: any // v4 Schema type is complex, use any for now
|
|
725
718
|
): { meta: MetaRecord<To>; defaultValues: Record<string, any>; unionMeta: Record<string, MetaRecord<To>> } => {
|
|
726
719
|
const ast = schema.ast
|
|
727
720
|
const newMeta: MetaRecord<To> = {}
|
|
728
721
|
const defaultValues: Record<string, any> = {}
|
|
729
722
|
const unionMeta: Record<string, MetaRecord<To>> = {}
|
|
730
723
|
|
|
731
|
-
if (ast._tag === "Transformation" || ast._tag === "Refinement") {
|
|
732
|
-
return metadataFromAst(S.make(ast.from))
|
|
733
|
-
}
|
|
734
|
-
|
|
735
724
|
// Handle root-level Union types (discriminated unions)
|
|
736
|
-
if (ast
|
|
737
|
-
const
|
|
738
|
-
const types = unionAst.types || []
|
|
725
|
+
if (AST.isUnion(ast)) {
|
|
726
|
+
const types = ast.types
|
|
739
727
|
|
|
740
728
|
// Filter out null/undefined types and unwrap transformations
|
|
741
729
|
const nonNullTypes = types
|
|
742
|
-
.filter((t: any) => t
|
|
730
|
+
.filter((t: any) => !AST.isUndefined(t) && !AST.isNull(t))
|
|
743
731
|
.map(getTransformationFrom)
|
|
744
732
|
|
|
745
733
|
// Check if this is a discriminated union (all members are structs)
|
|
746
|
-
const allStructs = nonNullTypes.every((t: any) =>
|
|
734
|
+
const allStructs = nonNullTypes.every((t: any) => AST.isObjects(t))
|
|
747
735
|
|
|
748
736
|
if (allStructs && nonNullTypes.length > 0) {
|
|
749
737
|
// Extract discriminator values from each union member
|
|
@@ -751,14 +739,14 @@ const metadataFromAst = <From, To>(
|
|
|
751
739
|
|
|
752
740
|
// Store metadata for each union member by its tag value
|
|
753
741
|
for (const memberType of nonNullTypes) {
|
|
754
|
-
if (
|
|
742
|
+
if (AST.isObjects(memberType)) {
|
|
755
743
|
// Find the discriminator field (usually _tag)
|
|
756
744
|
const tagProp = memberType.propertySignatures.find(
|
|
757
745
|
(p: any) => p.name.toString() === "_tag"
|
|
758
746
|
)
|
|
759
747
|
|
|
760
748
|
let tagValue: string | null = null
|
|
761
|
-
if (tagProp &&
|
|
749
|
+
if (tagProp && AST.isLiteral(tagProp.type)) {
|
|
762
750
|
tagValue = tagProp.type.literal as string
|
|
763
751
|
discriminatorValues.push(tagValue)
|
|
764
752
|
}
|
|
@@ -791,7 +779,7 @@ const metadataFromAst = <From, To>(
|
|
|
791
779
|
}
|
|
792
780
|
}
|
|
793
781
|
|
|
794
|
-
if (
|
|
782
|
+
if (AST.isObjects(ast)) {
|
|
795
783
|
const meta = createMeta<To>({
|
|
796
784
|
propertySignatures: ast.propertySignatures
|
|
797
785
|
})
|
|
@@ -821,15 +809,15 @@ const metadataFromAst = <From, To>(
|
|
|
821
809
|
}
|
|
822
810
|
|
|
823
811
|
export const duplicateSchema = <From, To>(
|
|
824
|
-
schema: S.
|
|
812
|
+
schema: S.Codec<To, From, never>
|
|
825
813
|
) => {
|
|
826
|
-
return
|
|
814
|
+
return schema
|
|
827
815
|
}
|
|
828
816
|
|
|
829
|
-
export const generateMetaFromSchema = <
|
|
830
|
-
schema:
|
|
817
|
+
export const generateMetaFromSchema = <_From, To>(
|
|
818
|
+
schema: any // v4 Schema type is complex, use any for now
|
|
831
819
|
): {
|
|
832
|
-
schema:
|
|
820
|
+
schema: any
|
|
833
821
|
meta: MetaRecord<To>
|
|
834
822
|
unionMeta: Record<string, MetaRecord<To>>
|
|
835
823
|
} => {
|
|
@@ -845,170 +833,167 @@ export const generateInputStandardSchemaFromFieldMeta = (
|
|
|
845
833
|
if (!trans) {
|
|
846
834
|
trans = useIntl().trans
|
|
847
835
|
}
|
|
848
|
-
let schema: S.Schema<any
|
|
836
|
+
let schema: S.Schema<any>
|
|
837
|
+
|
|
849
838
|
switch (meta.type) {
|
|
850
|
-
case "string":
|
|
851
|
-
schema = S.String
|
|
852
|
-
message: () => trans("validation.empty")
|
|
853
|
-
})
|
|
839
|
+
case "string": {
|
|
840
|
+
schema = S.String
|
|
854
841
|
|
|
842
|
+
// Apply format-specific schemas
|
|
855
843
|
if (meta.format === "email") {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
S.
|
|
859
|
-
|
|
860
|
-
|
|
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
|
+
)
|
|
861
850
|
)
|
|
862
851
|
}
|
|
863
852
|
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
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
|
+
}
|
|
873
864
|
}
|
|
874
865
|
|
|
875
866
|
if (typeof meta.maxLength === "number") {
|
|
876
|
-
schema = schema.
|
|
877
|
-
|
|
878
|
-
trans("validation.string.maxLength", {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
}
|
|
883
|
-
if (typeof meta.minLength === "number") {
|
|
884
|
-
schema = schema.pipe(S.minLength(meta.minLength)).annotations({
|
|
885
|
-
message: () =>
|
|
886
|
-
trans("validation.string.minLength", {
|
|
887
|
-
minLength: meta.minLength
|
|
888
|
-
})
|
|
889
|
-
})
|
|
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
|
+
)
|
|
890
873
|
}
|
|
891
874
|
break
|
|
875
|
+
}
|
|
892
876
|
|
|
893
|
-
case "number":
|
|
877
|
+
case "number": {
|
|
894
878
|
if (meta.refinement === "int") {
|
|
895
|
-
schema = S
|
|
896
|
-
.Number
|
|
897
|
-
.annotations({
|
|
898
|
-
message: () => trans("validation.empty")
|
|
899
|
-
})
|
|
900
|
-
.pipe(
|
|
901
|
-
S.int({ message: (issue) => trans("validation.integer.expected", { actualValue: String(issue.actual) }) })
|
|
902
|
-
)
|
|
879
|
+
schema = S.Int
|
|
903
880
|
} else {
|
|
904
|
-
schema = S.Number
|
|
905
|
-
message: () => trans("validation.number.expected", { actualValue: "NaN" })
|
|
906
|
-
})
|
|
907
|
-
|
|
908
|
-
if (meta.required) {
|
|
909
|
-
schema.annotations({
|
|
910
|
-
message: () => trans("validation.empty")
|
|
911
|
-
})
|
|
912
|
-
}
|
|
881
|
+
schema = S.Number
|
|
913
882
|
}
|
|
914
883
|
|
|
884
|
+
// Apply numeric validations
|
|
915
885
|
if (typeof meta.minimum === "number") {
|
|
916
|
-
schema = schema.
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
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
|
+
)
|
|
923
896
|
}
|
|
897
|
+
|
|
924
898
|
if (typeof meta.maximum === "number") {
|
|
925
|
-
schema = schema.
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
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
|
+
)
|
|
932
909
|
}
|
|
910
|
+
|
|
933
911
|
if (typeof meta.exclusiveMinimum === "number") {
|
|
934
|
-
schema = schema.
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
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
|
+
)
|
|
941
922
|
}
|
|
923
|
+
|
|
942
924
|
if (typeof meta.exclusiveMaximum === "number") {
|
|
943
|
-
schema = schema.
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
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
|
+
)
|
|
950
935
|
}
|
|
951
936
|
break
|
|
952
|
-
|
|
953
|
-
schema = S.Literal(...meta.members as [any]).annotations({
|
|
954
|
-
message: () => ({
|
|
955
|
-
message: trans("validation.not_a_valid", {
|
|
956
|
-
type: "select",
|
|
957
|
-
message: meta.members.join(", ")
|
|
958
|
-
}),
|
|
959
|
-
override: true
|
|
960
|
-
})
|
|
961
|
-
})
|
|
937
|
+
}
|
|
962
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
|
+
}
|
|
963
949
|
break
|
|
950
|
+
}
|
|
964
951
|
|
|
965
|
-
case "multiple":
|
|
966
|
-
schema = S.Array(S.String)
|
|
967
|
-
message: () =>
|
|
968
|
-
trans("validation.not_a_valid", {
|
|
969
|
-
type: "multiple",
|
|
970
|
-
message: meta.members.join(", ")
|
|
971
|
-
})
|
|
972
|
-
})
|
|
952
|
+
case "multiple": {
|
|
953
|
+
schema = S.Array(S.String)
|
|
973
954
|
break
|
|
955
|
+
}
|
|
974
956
|
|
|
975
|
-
case "boolean":
|
|
957
|
+
case "boolean": {
|
|
976
958
|
schema = S.Boolean
|
|
977
959
|
break
|
|
960
|
+
}
|
|
978
961
|
|
|
979
|
-
case "unknown":
|
|
962
|
+
case "unknown": {
|
|
980
963
|
schema = S.Unknown
|
|
981
964
|
break
|
|
965
|
+
}
|
|
982
966
|
|
|
983
|
-
default:
|
|
984
|
-
|
|
985
|
-
console.warn(`Unhandled field type: ${meta}`)
|
|
967
|
+
default: {
|
|
968
|
+
console.warn(`Unhandled field type: ${(meta as any).type}`)
|
|
986
969
|
schema = S.Unknown
|
|
987
970
|
break
|
|
971
|
+
}
|
|
988
972
|
}
|
|
973
|
+
|
|
974
|
+
// Wrap in union with null/undefined if not required
|
|
989
975
|
if (!meta.required) {
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
schema.pipe(
|
|
993
|
-
S.annotations({
|
|
994
|
-
message: () => trans("validation.empty")
|
|
995
|
-
})
|
|
996
|
-
)
|
|
976
|
+
// v4 Union takes an array of schemas
|
|
977
|
+
schema = S.Union([schema, S.Null, S.Undefined])
|
|
997
978
|
}
|
|
998
|
-
|
|
999
|
-
return
|
|
979
|
+
|
|
980
|
+
return S.toStandardSchemaV1(schema as any)
|
|
1000
981
|
}
|
|
1001
982
|
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
) =>
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
983
|
+
// TODO: Fix v4 migration - nullableInput transformation needs proper type handling
|
|
984
|
+
// export const nullableInput = <A>(
|
|
985
|
+
// schema: S.Schema<A>,
|
|
986
|
+
// defaultValue: () => A
|
|
987
|
+
// ): S.Schema<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
|
+
// )
|
|
1012
997
|
|
|
1013
998
|
export type OmegaAutoGenMeta<
|
|
1014
999
|
From extends Record<PropertyKey, any>,
|
|
@@ -1054,11 +1039,11 @@ export function deepMerge(target: any, source: any) {
|
|
|
1054
1039
|
|
|
1055
1040
|
// Type definitions for schemas with fields and members
|
|
1056
1041
|
type SchemaWithFields = {
|
|
1057
|
-
fields: Record<string, S.
|
|
1042
|
+
fields: Record<string, S.Top>
|
|
1058
1043
|
}
|
|
1059
1044
|
|
|
1060
1045
|
type SchemaWithMembers = {
|
|
1061
|
-
members: readonly S.
|
|
1046
|
+
members: readonly S.Top[]
|
|
1062
1047
|
}
|
|
1063
1048
|
|
|
1064
1049
|
// Type guards to check schema types
|
|
@@ -1075,11 +1060,7 @@ export const defaultsValueFromSchema = (
|
|
|
1075
1060
|
schema: S.Schema<any>,
|
|
1076
1061
|
record: Record<string, any> = {}
|
|
1077
1062
|
): any => {
|
|
1078
|
-
const ast
|
|
1079
|
-
|
|
1080
|
-
if (ast?.defaultValue) {
|
|
1081
|
-
return ast.defaultValue()
|
|
1082
|
-
}
|
|
1063
|
+
const ast = schema.ast
|
|
1083
1064
|
|
|
1084
1065
|
if (isNullableOrUndefined(schema.ast) === "null") {
|
|
1085
1066
|
return null
|
|
@@ -1088,7 +1069,35 @@ export const defaultsValueFromSchema = (
|
|
|
1088
1069
|
return undefined
|
|
1089
1070
|
}
|
|
1090
1071
|
|
|
1091
|
-
//
|
|
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.Schema<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
|
|
1092
1101
|
if (hasFields(schema)) {
|
|
1093
1102
|
// Process fields and extract default values
|
|
1094
1103
|
const result: Record<string, any> = {}
|
|
@@ -1148,52 +1157,18 @@ export const defaultsValueFromSchema = (
|
|
|
1148
1157
|
}
|
|
1149
1158
|
|
|
1150
1159
|
if (Object.keys(record).length === 0) {
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
const fromSchema = S.make(schema.ast.from)
|
|
1157
|
-
return defaultsValueFromSchema(fromSchema, record)
|
|
1158
|
-
}
|
|
1159
|
-
case "TypeLiteral": {
|
|
1160
|
-
// Process TypeLiteral fields directly to build the result object
|
|
1161
|
-
const result: Record<string, any> = { ...record }
|
|
1162
|
-
|
|
1163
|
-
for (const prop of ast.propertySignatures) {
|
|
1164
|
-
const key = prop.name.toString()
|
|
1165
|
-
const propType = prop.type
|
|
1166
|
-
|
|
1167
|
-
// Check if the property type itself is a Transformation with defaultValue
|
|
1168
|
-
if (propType._tag === "Transformation" && propType.defaultValue) {
|
|
1169
|
-
result[key] = propType.defaultValue()
|
|
1170
|
-
continue
|
|
1171
|
-
}
|
|
1172
|
-
|
|
1173
|
-
// Check if property type has defaultValue directly on the AST
|
|
1174
|
-
if (propType.defaultValue) {
|
|
1175
|
-
result[key] = propType.defaultValue()
|
|
1176
|
-
continue
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
// Create a schema from the property type and get its defaults
|
|
1180
|
-
const propSchema = S.make(propType)
|
|
1181
|
-
|
|
1182
|
-
// Recursively process the property - don't pas for prop processing
|
|
1183
|
-
// to allow proper unwrapping of nested structures
|
|
1184
|
-
const propValue = defaultsValueFromSchema(propSchema, record[key] || {})
|
|
1185
|
-
|
|
1186
|
-
if (propValue !== undefined) {
|
|
1187
|
-
result[key] = propValue
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
return result
|
|
1192
|
-
}
|
|
1193
|
-
case "StringKeyword":
|
|
1194
|
-
return ""
|
|
1195
|
-
case "BooleanKeyword":
|
|
1196
|
-
return false
|
|
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
|
|
1197
1165
|
}
|
|
1198
1166
|
}
|
|
1167
|
+
|
|
1168
|
+
if (AST.isString(ast)) {
|
|
1169
|
+
return ""
|
|
1170
|
+
}
|
|
1171
|
+
if (AST.isBoolean(ast)) {
|
|
1172
|
+
return false
|
|
1173
|
+
}
|
|
1199
1174
|
}
|