@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.
Files changed (99) hide show
  1. package/dist/types/components/OmegaForm/OmegaAutoGen.vue.d.ts +1 -1
  2. package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +11 -13
  3. package/dist/types/components/OmegaForm/useOmegaForm.d.ts +6 -4
  4. package/dist/types/utils/index.d.ts +4 -3
  5. package/dist/vue-components.es.js +13 -14
  6. package/dist/vue-components.es10.js +109 -115
  7. package/dist/vue-components.es11.js +1 -1
  8. package/dist/vue-components.es12.js +290 -341
  9. package/dist/vue-components.es17.js +723 -4
  10. package/dist/vue-components.es18.js +140 -9
  11. package/dist/vue-components.es19.js +4 -55
  12. package/dist/vue-components.es2.js +17 -18
  13. package/dist/vue-components.es20.js +11 -68
  14. package/dist/vue-components.es21.js +3 -6
  15. package/dist/vue-components.es22.js +24 -6
  16. package/dist/vue-components.es23.js +4 -3
  17. package/dist/vue-components.es24.js +8 -3
  18. package/dist/vue-components.es25.js +55 -2
  19. package/dist/vue-components.es26.js +69 -2
  20. package/dist/vue-components.es27.js +6 -2
  21. package/dist/vue-components.es28.js +6 -2
  22. package/dist/vue-components.es29.js +3 -17
  23. package/dist/vue-components.es3.js +9 -9
  24. package/dist/vue-components.es30.js +3 -192
  25. package/dist/vue-components.es31.js +4 -0
  26. package/dist/vue-components.es32.js +2 -42
  27. package/dist/vue-components.es33.js +1 -1
  28. package/dist/vue-components.es34.js +1 -1
  29. package/dist/vue-components.es35.js +17 -111
  30. package/dist/vue-components.es36.js +40 -0
  31. package/dist/vue-components.es37.js +4 -7
  32. package/dist/vue-components.es38.js +82 -31
  33. package/dist/vue-components.es39.js +54 -0
  34. package/dist/vue-components.es40.js +561 -4
  35. package/dist/vue-components.es41.js +40 -22
  36. package/dist/vue-components.es42.js +27 -5
  37. package/dist/vue-components.es43.js +5 -21
  38. package/dist/vue-components.es44.js +39 -29
  39. package/dist/vue-components.es45.js +313 -21
  40. package/dist/vue-components.es46.js +31 -12
  41. package/dist/vue-components.es47.js +4 -5
  42. package/dist/vue-components.es48.js +23 -18
  43. package/dist/vue-components.es49.js +74 -8
  44. package/dist/vue-components.es50.js +98 -30
  45. package/dist/vue-components.es51.js +2 -48
  46. package/dist/vue-components.es52.js +317 -25
  47. package/dist/vue-components.es53.js +64 -11
  48. package/dist/vue-components.es54.js +2 -65
  49. package/dist/vue-components.es55.js +2 -56
  50. package/dist/vue-components.es56.js +110 -16
  51. package/dist/vue-components.es58.js +7 -29
  52. package/dist/vue-components.es59.js +31 -41
  53. package/dist/vue-components.es61.js +190 -42
  54. package/dist/vue-components.es63.js +6 -0
  55. package/dist/vue-components.es64.js +103 -0
  56. package/dist/vue-components.es65.js +4 -0
  57. package/dist/vue-components.es66.js +23 -0
  58. package/dist/vue-components.es67.js +84 -0
  59. package/dist/vue-components.es68.js +14 -0
  60. package/dist/vue-components.es69.js +115 -0
  61. package/dist/vue-components.es7.js +1 -1
  62. package/dist/vue-components.es70.js +5 -0
  63. package/dist/vue-components.es71.js +34 -0
  64. package/dist/vue-components.es72.js +4 -0
  65. package/dist/vue-components.es73.js +4 -0
  66. package/dist/vue-components.es74.js +17 -0
  67. package/dist/vue-components.es75.js +72 -0
  68. package/dist/vue-components.es76.js +25 -0
  69. package/dist/vue-components.es77.js +7 -0
  70. package/dist/vue-components.es78.js +23 -0
  71. package/dist/vue-components.es79.js +32 -0
  72. package/dist/vue-components.es80.js +24 -0
  73. package/dist/vue-components.es81.js +14 -0
  74. package/dist/vue-components.es82.js +7 -0
  75. package/dist/vue-components.es83.js +21 -0
  76. package/dist/vue-components.es84.js +11 -0
  77. package/dist/vue-components.es85.js +33 -0
  78. package/dist/vue-components.es86.js +50 -0
  79. package/dist/vue-components.es87.js +28 -0
  80. package/dist/vue-components.es88.js +17 -0
  81. package/dist/vue-components.es89.js +18 -0
  82. package/dist/vue-components.es90.js +10 -0
  83. package/dist/vue-components.es91.js +13 -0
  84. package/dist/vue-components.es92.js +67 -0
  85. package/dist/vue-components.es93.js +58 -0
  86. package/dist/vue-components.es94.js +19 -0
  87. package/dist/{vue-components.es57.js → vue-components.es95.js} +3 -3
  88. package/dist/vue-components.es96.js +31 -0
  89. package/dist/vue-components.es97.js +44 -0
  90. package/dist/vue-components.es99.js +46 -0
  91. package/package.json +25 -24
  92. package/src/components/OmegaForm/OmegaAutoGen.vue +11 -10
  93. package/src/components/OmegaForm/OmegaErrorsInternal.vue +3 -2
  94. package/src/components/OmegaForm/OmegaFormStuff.ts +249 -274
  95. package/src/components/OmegaForm/OmegaInternalInput.vue +1 -1
  96. package/src/components/OmegaForm/useOmegaForm.ts +27 -28
  97. package/src/utils/index.ts +7 -7
  98. /package/dist/{vue-components.es62.js → vue-components.es100.js} +0 -0
  99. /package/dist/{vue-components.es60.js → vue-components.es98.js} +0 -0
@@ -1,9 +1,9 @@
1
- import { type Effect, Option, type Record, S } from "effect-app"
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 { type RuntimeFiber } from "effect/Fiber"
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> | RuntimeFiber<any, any> | Effect.Effect<RuntimeFiber<any, any>, any, never>
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: S.AST.Type[]
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 S.AST.PropertySignature[]
304
+ propertySignatures: readonly AST.PropertySignature[]
305
305
  property?: never
306
306
  }
307
307
  | {
308
308
  propertySignatures?: never
309
- property: S.AST.AST
309
+ property: AST.AST
310
310
  }
311
311
  )
312
312
 
313
- const getNullableOrUndefined = (property: S.AST.AST) => {
314
- return (
315
- S.AST.isUnion(property)
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 | S.AST.AST | undefined) => {
321
- if (!property || !S.AST.isUnion(property)) return false
322
- if (property.types.find((_) => _._tag === "UndefinedKeyword")) {
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 S.AST.AST[]): readonly S.AST.AST[] => {
331
- const result: S.AST.AST[] = []
328
+ const unwrapNestedUnions = (types: readonly AST.AST[]): readonly AST.AST[] => {
329
+ const result: AST.AST[] = []
332
330
  for (const type of types) {
333
- if (S.AST.isUnion(type)) {
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._tag === "Transformation") {
353
- const titleOnTransform = S
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: property.from
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?._tag === "TypeLiteral" && "propertySignatures" in 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 (S.AST.isUnion(p.type)) {
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._tag !== "UndefinedKeyword" && t !== S.Null.ast
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) => "propertySignatures" in 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 ("propertySignatures" in nonNullType) {
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 (TupleType)
442
- const arrayTypes = nonNullTypes.filter(S.AST.isTupleType)
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 (restElement.type._tag === "TypeLiteral" && "propertySignatures" in restElement.type) {
458
- for (const prop of restElement.type.propertySignatures) {
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" && S.AST.isTupleType(prop.type) && prop
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
- nestedRestElement.type._tag === "TypeLiteral" && "propertySignatures" in nestedRestElement.type
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 ("propertySignatures" in unwrappedTypeToProcess) {
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 (S.AST.isTupleType(p.type)) {
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].type._tag === "TypeLiteral"
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].type
537
- if (elementType._tag === "TypeLiteral" && "propertySignatures" in elementType) {
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 (S.AST.isTupleType(prop.type) && prop.type.rest.length > 0) {
544
- const nestedElementType = prop.type.rest[0].type
545
- if (nestedElementType._tag === "TypeLiteral" && "propertySignatures" in nestedElementType) {
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
- // an empty string is valid for a S.String field, so we should not mark it as required
598
- // TODO: handle this better via the createMeta minLength parsing
599
- required: isRequired && (p.type._tag !== "StringKeyword" || getMetadataFromSchema(p.type).minLength),
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 (S.AST.isUnion(property)) {
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._tag !== "UndefinedKeyword" && t !== S.Null.ast
619
+ (t) => !AST.isUndefined(t) && !AST.isNull(t)
623
620
  )!
624
621
 
625
- if ("propertySignatures" in nonNullType) {
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(S.AST.isLiteral)) {
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 (S.AST.isTupleType(property)) {
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 = S
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
- const titleType = S
672
- .AST
673
- .getAnnotation(
674
- property,
675
- S.AST.TitleAnnotationId
676
- )
677
- .pipe(
678
- Option.getOrElse(() => {
679
- return "unknown"
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 metadataFromAst = <From, To>(
724
- schema: S.Schema<To, From, never>
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._tag === "Union") {
737
- const unionAst = ast as any
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._tag !== "UndefinedKeyword" && t !== S.Null.ast)
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) => t._tag === "TypeLiteral" && "propertySignatures" in t)
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 ("propertySignatures" in memberType) {
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 && S.AST.isLiteral(tagProp.type)) {
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 ("propertySignatures" in ast) {
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.Schema<To, From, never>
812
+ schema: S.Codec<To, From, never>
825
813
  ) => {
826
- return S.extend(schema, S.Struct({}))
814
+ return schema
827
815
  }
828
816
 
829
- export const generateMetaFromSchema = <From, To>(
830
- schema: S.Schema<To, From, never>
817
+ export const generateMetaFromSchema = <_From, To>(
818
+ schema: any // v4 Schema type is complex, use any for now
831
819
  ): {
832
- schema: S.Schema<To, From, never>
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, any, never>
836
+ let schema: S.Schema<any>
837
+
849
838
  switch (meta.type) {
850
- case "string":
851
- schema = S.String.annotations({
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
- schema = S.compose(
857
- schema,
858
- S.Email.annotations({
859
- message: () => trans("validation.email.invalid")
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
- if (meta.required) {
865
- schema = schema
866
- .annotations({
867
- message: () => trans("validation.empty")
868
- })
869
- .pipe(S.minLength(1))
870
- .annotations({
871
- message: () => trans("validation.empty")
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.pipe(S.maxLength(meta.maxLength)).annotations({
877
- message: () =>
878
- trans("validation.string.maxLength", {
879
- maxLength: meta.maxLength
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.annotations({
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.pipe(S.greaterThanOrEqualTo(meta.minimum)).annotations({
917
- message: () =>
918
- trans(meta.minimum === 0 ? "validation.number.positive" : "validation.number.min", {
919
- minimum: meta.minimum,
920
- isExclusive: true
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.pipe(S.lessThanOrEqualTo(meta.maximum)).annotations({
926
- message: () =>
927
- trans("validation.number.max", {
928
- maximum: meta.maximum,
929
- isExclusive: true
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.pipe(S.greaterThan(meta.exclusiveMinimum)).annotations({
935
- message: () =>
936
- trans(meta.exclusiveMinimum === 0 ? "validation.number.positive" : "validation.number.min", {
937
- minimum: meta.exclusiveMinimum,
938
- isExclusive: false
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.pipe(S.lessThan(meta.exclusiveMaximum)).annotations({
944
- message: () =>
945
- trans("validation.number.max", {
946
- maximum: meta.exclusiveMaximum,
947
- isExclusive: false
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
- case "select":
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).annotations({
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
- // For any unhandled types, use Unknown schema to prevent undefined errors
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
- schema = S.NullishOr(schema)
991
- } else {
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
- const result = S.standardSchemaV1(schema)
999
- return result
979
+
980
+ return S.toStandardSchemaV1(schema as any)
1000
981
  }
1001
982
 
1002
- export const nullableInput = <A, I, R>(
1003
- schema: S.Schema<A, I, R>,
1004
- defaultValue: () => A
1005
- ) =>
1006
- S.NullOr(schema).pipe(
1007
- S.transform(S.typeSchema(schema), {
1008
- decode: (input) => input ?? defaultValue(),
1009
- encode: (input) => input
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.Schema<any>>
1042
+ fields: Record<string, S.Top>
1058
1043
  }
1059
1044
 
1060
1045
  type SchemaWithMembers = {
1061
- members: readonly S.Schema<any>[]
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: any = schema.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
- // Check if schema has fields directly
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
- switch (schema.ast._tag) {
1152
- case "Refinement":
1153
- return defaultsValueFromSchema(S.make(schema.ast.from), record)
1154
- case "Transformation": {
1155
- // For all transformations, just process the 'from' side to get the base defaults
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
  }