@effect-app/vue-components 4.0.0-beta.2 → 4.0.0-beta.21

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 (101) hide show
  1. package/dist/types/components/OmegaForm/OmegaAutoGen.vue.d.ts +1 -1
  2. package/dist/types/components/OmegaForm/OmegaFormStuff.d.ts +11 -11
  3. package/dist/types/components/OmegaForm/useOmegaForm.d.ts +2 -4
  4. package/dist/types/utils/index.d.ts +3 -4
  5. package/dist/vue-components.es.js +14 -13
  6. package/dist/vue-components.es10.js +131 -129
  7. package/dist/vue-components.es11.js +2 -2
  8. package/dist/vue-components.es12.js +382 -340
  9. package/dist/vue-components.es16.js +4 -723
  10. package/dist/vue-components.es17.js +10 -140
  11. package/dist/vue-components.es18.js +55 -4
  12. package/dist/vue-components.es19.js +54 -11
  13. package/dist/vue-components.es2.js +18 -17
  14. package/dist/vue-components.es20.js +6 -3
  15. package/dist/vue-components.es21.js +6 -24
  16. package/dist/vue-components.es22.js +3 -4
  17. package/dist/vue-components.es23.js +3 -8
  18. package/dist/vue-components.es24.js +2 -55
  19. package/dist/vue-components.es25.js +2 -69
  20. package/dist/vue-components.es26.js +2 -6
  21. package/dist/vue-components.es27.js +2 -6
  22. package/dist/vue-components.es28.js +17 -3
  23. package/dist/vue-components.es29.js +11 -3
  24. package/dist/vue-components.es3.js +11 -10
  25. package/dist/vue-components.es30.js +29 -2
  26. package/dist/vue-components.es31.js +4 -2
  27. package/dist/vue-components.es32.js +1 -1
  28. package/dist/vue-components.es33.js +1 -1
  29. package/dist/vue-components.es34.js +111 -17
  30. package/dist/vue-components.es36.js +7 -318
  31. package/dist/vue-components.es37.js +31 -560
  32. package/dist/vue-components.es39.js +190 -50
  33. package/dist/vue-components.es41.js +4 -4
  34. package/dist/vue-components.es42.js +23 -4
  35. package/dist/vue-components.es43.js +5 -24
  36. package/dist/vue-components.es44.js +20 -74
  37. package/dist/vue-components.es45.js +29 -39
  38. package/dist/vue-components.es46.js +21 -313
  39. package/dist/vue-components.es47.js +11 -98
  40. package/dist/vue-components.es48.js +5 -31
  41. package/dist/vue-components.es49.js +19 -2
  42. package/dist/vue-components.es5.js +1 -1
  43. package/dist/vue-components.es50.js +9 -2
  44. package/dist/vue-components.es51.js +31 -2
  45. package/dist/vue-components.es52.js +47 -110
  46. package/dist/{vue-components.es75.js → vue-components.es53.js} +5 -5
  47. package/dist/vue-components.es54.js +11 -7
  48. package/dist/vue-components.es55.js +64 -31
  49. package/dist/{vue-components.es93.js → vue-components.es56.js} +1 -1
  50. package/dist/vue-components.es57.js +15 -190
  51. package/dist/{vue-components.es95.js → vue-components.es58.js} +3 -3
  52. package/dist/vue-components.es59.js +28 -37
  53. package/dist/vue-components.es60.js +39 -80
  54. package/dist/vue-components.es61.js +2 -41
  55. package/dist/vue-components.es62.js +44 -5
  56. package/dist/vue-components.es63.js +2 -4
  57. package/dist/vue-components.es7.js +35 -35
  58. package/package.json +10 -10
  59. package/src/components/OmegaForm/OmegaAutoGen.vue +25 -30
  60. package/src/components/OmegaForm/OmegaErrorsInternal.vue +2 -3
  61. package/src/components/OmegaForm/OmegaFormStuff.ts +311 -301
  62. package/src/components/OmegaForm/OmegaInternalInput.vue +3 -1
  63. package/src/components/OmegaForm/useOmegaForm.ts +30 -32
  64. package/src/utils/index.ts +4 -8
  65. package/dist/vue-components.es100.js +0 -4
  66. package/dist/vue-components.es35.js +0 -13
  67. package/dist/vue-components.es38.js +0 -29
  68. package/dist/vue-components.es40.js +0 -66
  69. package/dist/vue-components.es64.js +0 -25
  70. package/dist/vue-components.es65.js +0 -7
  71. package/dist/vue-components.es66.js +0 -23
  72. package/dist/vue-components.es67.js +0 -32
  73. package/dist/vue-components.es68.js +0 -24
  74. package/dist/vue-components.es69.js +0 -14
  75. package/dist/vue-components.es70.js +0 -7
  76. package/dist/vue-components.es71.js +0 -21
  77. package/dist/vue-components.es72.js +0 -11
  78. package/dist/vue-components.es73.js +0 -33
  79. package/dist/vue-components.es74.js +0 -50
  80. package/dist/vue-components.es76.js +0 -103
  81. package/dist/vue-components.es77.js +0 -84
  82. package/dist/vue-components.es78.js +0 -23
  83. package/dist/vue-components.es79.js +0 -14
  84. package/dist/vue-components.es80.js +0 -115
  85. package/dist/vue-components.es81.js +0 -5
  86. package/dist/vue-components.es82.js +0 -34
  87. package/dist/vue-components.es83.js +0 -4
  88. package/dist/vue-components.es84.js +0 -4
  89. package/dist/vue-components.es85.js +0 -18
  90. package/dist/vue-components.es86.js +0 -17
  91. package/dist/vue-components.es87.js +0 -72
  92. package/dist/vue-components.es88.js +0 -10
  93. package/dist/vue-components.es89.js +0 -4
  94. package/dist/vue-components.es90.js +0 -17
  95. package/dist/vue-components.es91.js +0 -13
  96. package/dist/vue-components.es92.js +0 -67
  97. package/dist/vue-components.es94.js +0 -19
  98. package/dist/vue-components.es96.js +0 -31
  99. package/dist/vue-components.es97.js +0 -44
  100. package/dist/vue-components.es98.js +0 -4
  101. package/dist/vue-components.es99.js +0 -46
@@ -1,9 +1,8 @@
1
- import type * as Effect from "effect/Effect"
2
- import * as AST from "effect/SchemaAST"
1
+ import { Effect, Option, type Record, S } from "effect-app"
3
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
4
3
  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
4
  import { isObject } from "@vueuse/core"
6
- import * as S from "effect/Schema"
5
+ import type * as Fiber from "effect/Fiber"
7
6
  import { getTransformationFrom, useIntl } from "../../utils"
8
7
  import { type OmegaFieldInternalApi } from "./InputProps"
9
8
  import { type OF, type OmegaFormReturn } from "./useOmegaForm"
@@ -145,7 +144,7 @@ export type FormProps<From, To> =
145
144
  formApi: OmegaFormParams<From, To>
146
145
  meta: any
147
146
  value: To
148
- }) => Promise<any> | Effect.Effect<unknown, any, never>
147
+ }) => Promise<any> | Fiber.Fiber<any, any> | Effect.Effect<unknown, any, never>
149
148
  }
150
149
 
151
150
  export type OmegaFormParams<From, To> = FormApi<
@@ -262,7 +261,7 @@ export type SelectFieldMeta = BaseFieldMeta & {
262
261
  export type MultipleFieldMeta = BaseFieldMeta & {
263
262
  type: "multiple"
264
263
  members: any[] // TODO: should be non empty array?
265
- rest: readonly AST.AST[]
264
+ rest: readonly S.AST.AST[]
266
265
  }
267
266
 
268
267
  export type BooleanFieldMeta = BaseFieldMeta & {
@@ -301,34 +300,46 @@ export type CreateMeta =
301
300
  }
302
301
  & (
303
302
  | {
304
- propertySignatures: readonly AST.PropertySignature[]
303
+ propertySignatures: readonly S.AST.PropertySignature[]
305
304
  property?: never
306
305
  }
307
306
  | {
308
307
  propertySignatures?: never
309
- property: AST.AST
308
+ property: S.AST.AST
310
309
  }
311
310
  )
312
311
 
313
- const getNullableOrUndefined = (property: AST.AST) => {
314
- if (!AST.isUnion(property)) return false
315
- return property.types.find((_) => AST.isUndefined(_) || _ === S.Null.ast)
312
+ const unwrapDeclaration = (property: S.AST.AST): S.AST.AST => {
313
+ let current = getTransformationFrom(property)
314
+
315
+ while (S.AST.isDeclaration(current) && current.typeParameters.length > 0) {
316
+ current = getTransformationFrom(current.typeParameters[0]!)
317
+ }
318
+
319
+ return current
316
320
  }
317
321
 
318
- export const isNullableOrUndefined = (property: false | AST.AST | undefined) => {
319
- if (!property || !AST.isUnion(property)) return false
320
- if (property.types.find((_) => AST.isUndefined(_))) {
322
+ const isNullishType = (property: S.AST.AST) => S.AST.isUndefined(property) || S.AST.isNull(property)
323
+
324
+ const getNullableOrUndefined = (property: S.AST.AST) =>
325
+ S.AST.isUnion(property)
326
+ ? property.types.find((_) => isNullishType(_))
327
+ : false
328
+
329
+ export const isNullableOrUndefined = (property: false | S.AST.AST | undefined) => {
330
+ if (!property || !S.AST.isUnion(property)) return false
331
+ if (property.types.find((_) => S.AST.isUndefined(_))) {
321
332
  return "undefined"
322
333
  }
323
- if (property.types.find((_) => _ === S.Null.ast)) return "null"
334
+ if (property.types.find((_) => S.AST.isNull(_))) return "null"
324
335
  return false
325
336
  }
326
337
 
327
338
  // 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[] = []
339
+ const unwrapNestedUnions = (types: readonly S.AST.AST[]): readonly S.AST.AST[] => {
340
+ const result: S.AST.AST[] = []
330
341
  for (const type of types) {
331
- if (AST.isUnion(type)) {
342
+ if (S.AST.isUnion(type)) {
332
343
  // Recursively unwrap nested unions
333
344
  const unwrapped = unwrapNestedUnions(type.types)
334
345
  result.push(...unwrapped)
@@ -339,31 +350,108 @@ const unwrapNestedUnions = (types: readonly AST.AST[]): readonly AST.AST[] => {
339
350
  return result
340
351
  }
341
352
 
353
+ const getNonNullTypes = (types: readonly S.AST.AST[]) =>
354
+ unwrapNestedUnions(types)
355
+ .map(unwrapDeclaration)
356
+ .filter((_) => !isNullishType(_))
357
+
358
+ const getJsonSchemaAnnotation = (property: S.AST.AST): Record<string, unknown> => {
359
+ const jsonSchema = S.AST.resolve(property)?.jsonSchema
360
+ return jsonSchema && typeof jsonSchema === "object" ? jsonSchema as Record<string, unknown> : {}
361
+ }
362
+
363
+ const getDefaultFromAst = (property: S.AST.AST) => {
364
+ const link = property.context?.defaultValue?.[0] as any
365
+
366
+ if (!link?.transformation?.decode?.run) {
367
+ return undefined
368
+ }
369
+
370
+ try {
371
+ const result = Effect.runSync(link.transformation.decode.run(Option.none())) as Option.Option<unknown>
372
+ return Option.isSome(result) ? result.value : undefined
373
+ } catch {
374
+ return undefined
375
+ }
376
+ }
377
+
378
+ const getCheckMetas = (property: S.AST.AST): Array<Record<string, any>> => {
379
+ const checks = property.checks ?? []
380
+
381
+ return checks.flatMap((check) => {
382
+ if (check._tag === "FilterGroup") {
383
+ return check.checks.flatMap((inner) => {
384
+ const meta = inner.annotations?.meta
385
+ return meta && typeof meta === "object" ? [meta as Record<string, any>] : []
386
+ })
387
+ }
388
+
389
+ const meta = check.annotations?.meta
390
+ return meta && typeof meta === "object" ? [meta as Record<string, any>] : []
391
+ })
392
+ }
393
+
394
+ const getFieldMetadataFromAst = (property: S.AST.AST) => {
395
+ const base: Partial<FieldMeta> & Record<string, unknown> = {
396
+ description: S.AST.resolveDescription(property)
397
+ }
398
+ const checks = getCheckMetas(property)
399
+
400
+ if (S.AST.isString(property)) {
401
+ base.type = "string"
402
+ for (const check of checks) {
403
+ switch (check._tag) {
404
+ case "isMinLength":
405
+ base.minLength = check.minLength
406
+ break
407
+ case "isMaxLength":
408
+ base.maxLength = check.maxLength
409
+ break
410
+ }
411
+ }
412
+
413
+ if (S.AST.resolveTitle(property) === "Email") {
414
+ base.format = "email"
415
+ }
416
+ } else if (S.AST.isNumber(property)) {
417
+ base.type = "number"
418
+ for (const check of checks) {
419
+ switch (check._tag) {
420
+ case "isInt":
421
+ base.refinement = "int"
422
+ break
423
+ case "isGreaterThanOrEqualTo":
424
+ base.minimum = check.minimum
425
+ break
426
+ case "isLessThanOrEqualTo":
427
+ base.maximum = check.maximum
428
+ break
429
+ case "isGreaterThan":
430
+ base.exclusiveMinimum = check.exclusiveMinimum
431
+ break
432
+ case "isLessThan":
433
+ base.exclusiveMaximum = check.exclusiveMaximum
434
+ break
435
+ }
436
+ }
437
+ } else if (S.AST.isBoolean(property)) {
438
+ base.type = "boolean"
439
+ } else {
440
+ base.type = "unknown"
441
+ }
442
+
443
+ return base
444
+ }
445
+
342
446
  export const createMeta = <T = any>(
343
447
  { meta = {}, parent = "", property, propertySignatures }: CreateMeta,
344
448
  acc: Partial<MetaRecord<T>> = {}
345
449
  ): 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
450
+ if (property) {
451
+ property = unwrapDeclaration(property)
364
452
  }
365
453
 
366
- if (property && AST.isObjects(property)) {
454
+ if (property && S.AST.isObjects(property)) {
367
455
  return createMeta<T>({
368
456
  meta,
369
457
  propertySignatures: property.propertySignatures
@@ -375,10 +463,6 @@ export const createMeta = <T = any>(
375
463
  const key = parent ? `${parent}.${p.name.toString()}` : p.name.toString()
376
464
  const nullableOrUndefined = isNullableOrUndefined(p.type)
377
465
 
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
466
  // Determine if this field should be required:
383
467
  // - For nullable discriminated unions, only _tag should be non-required
384
468
  // - All other fields should calculate their required status normally
@@ -394,20 +478,11 @@ export const createMeta = <T = any>(
394
478
  isRequired = !nullableOrUndefined
395
479
  }
396
480
 
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)
481
+ const typeToProcess = unwrapDeclaration(p.type)
482
+ if (S.AST.isUnion(p.type)) {
483
+ const nonNullTypes = getNonNullTypes(p.type.types)
407
484
 
408
- const hasStructMembers = nonNullTypes.some(
409
- (t) => AST.isObjects(t)
410
- )
485
+ const hasStructMembers = nonNullTypes.some(S.AST.isObjects)
411
486
 
412
487
  if (hasStructMembers) {
413
488
  // Only create parent meta for non-NullOr unions to avoid duplicates
@@ -422,7 +497,7 @@ export const createMeta = <T = any>(
422
497
 
423
498
  // Process each non-null type and merge their metadata
424
499
  for (const nonNullType of nonNullTypes) {
425
- if (AST.isObjects(nonNullType)) {
500
+ if (S.AST.isObjects(nonNullType)) {
426
501
  // For discriminated unions (multiple branches):
427
502
  // - If the parent union is nullable, only _tag should be non-required
428
503
  // - All other fields maintain their normal required status based on their own types
@@ -439,8 +514,7 @@ export const createMeta = <T = any>(
439
514
  }
440
515
  }
441
516
  } else {
442
- // Check if any of the union types are arrays
443
- const arrayTypes = nonNullTypes.filter(AST.isArrays)
517
+ const arrayTypes = nonNullTypes.filter(S.AST.isArrays)
444
518
  if (arrayTypes.length > 0) {
445
519
  const arrayType = arrayTypes[0] // Take the first array type
446
520
 
@@ -454,8 +528,8 @@ export const createMeta = <T = any>(
454
528
 
455
529
  // If the array has struct elements, also create metadata for their properties
456
530
  if (arrayType.rest && arrayType.rest.length > 0) {
457
- const restElement = arrayType.rest[0]
458
- if (AST.isObjects(restElement)) {
531
+ const restElement = unwrapDeclaration(arrayType.rest[0]!)
532
+ if (S.AST.isObjects(restElement)) {
459
533
  for (const prop of restElement.propertySignatures) {
460
534
  const propKey = `${key}.${prop.name.toString()}`
461
535
 
@@ -473,12 +547,12 @@ export const createMeta = <T = any>(
473
547
  acc[propKey as NestedKeyOf<T>] = propMeta as FieldMeta
474
548
 
475
549
  if (
476
- propMeta.type === "multiple" && AST.isArrays(prop.type) && prop
550
+ propMeta.type === "multiple" && S.AST.isArrays(prop.type) && prop
477
551
  .type
478
552
  .rest && prop.type.rest.length > 0
479
553
  ) {
480
- const nestedRestElement = prop.type.rest[0]
481
- if (AST.isObjects(nestedRestElement)) {
554
+ const nestedRestElement = unwrapDeclaration(prop.type.rest[0]!)
555
+ if (S.AST.isObjects(nestedRestElement)) {
482
556
  for (const nestedProp of nestedRestElement.propertySignatures) {
483
557
  const nestedPropKey = `${propKey}.${nestedProp.name.toString()}`
484
558
 
@@ -513,34 +587,32 @@ export const createMeta = <T = any>(
513
587
  }
514
588
  }
515
589
  } else {
516
- // Unwrap transformations (like ExtendedClass) to check for propertySignatures
517
- const unwrappedTypeToProcess = getTransformationFrom(typeToProcess)
518
- if (AST.isObjects(unwrappedTypeToProcess)) {
590
+ if (S.AST.isObjects(typeToProcess)) {
519
591
  Object.assign(
520
592
  acc,
521
593
  createMeta<T>({
522
594
  parent: key,
523
- propertySignatures: unwrappedTypeToProcess.propertySignatures,
595
+ propertySignatures: typeToProcess.propertySignatures,
524
596
  meta: { required: isRequired, nullableOrUndefined }
525
597
  })
526
598
  )
527
- } else if (AST.isArrays(p.type)) {
599
+ } else if (S.AST.isArrays(p.type)) {
528
600
  // Check if it has struct elements
529
601
  const hasStructElements = p.type.rest.length > 0
530
- && AST.isObjects(p.type.rest[0])
602
+ && S.AST.isObjects(unwrapDeclaration(p.type.rest[0]!))
531
603
 
532
604
  if (hasStructElements) {
533
605
  // 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)) {
606
+ const elementType = unwrapDeclaration(p.type.rest[0]!)
607
+ if (S.AST.isObjects(elementType)) {
536
608
  // Process each property in the array element
537
609
  for (const prop of elementType.propertySignatures) {
538
610
  const propKey = `${key}.${prop.name.toString()}`
539
611
 
540
612
  // 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)) {
613
+ if (S.AST.isArrays(prop.type) && prop.type.rest.length > 0) {
614
+ const nestedElementType = unwrapDeclaration(prop.type.rest[0]!)
615
+ if (S.AST.isObjects(nestedElementType)) {
544
616
  // Array with struct elements - process nested fields
545
617
  for (const nestedProp of nestedElementType.propertySignatures) {
546
618
  const nestedKey = `${propKey}.${nestedProp.name.toString()}`
@@ -592,9 +664,11 @@ export const createMeta = <T = any>(
592
664
  parent: key,
593
665
  property: p.type,
594
666
  meta: {
595
- required: isRequired,
596
- nullableOrUndefined,
597
- ...(isIntField && { refinement: "int" })
667
+ // an empty string is valid for a S.String field, so we should not mark it as required
668
+ // TODO: handle this better via the createMeta minLength parsing
669
+ required: isRequired
670
+ && (!S.AST.isString(typeToProcess) || !!getFieldMetadataFromAst(p.type).minLength),
671
+ nullableOrUndefined
598
672
  }
599
673
  })
600
674
 
@@ -607,19 +681,17 @@ export const createMeta = <T = any>(
607
681
 
608
682
  if (property) {
609
683
  const nullableOrUndefined = getNullableOrUndefined(property)
684
+ property = unwrapDeclaration(property)
610
685
 
611
686
  if (!Object.hasOwnProperty.call(meta, "required")) {
612
687
  meta["required"] = !nullableOrUndefined
613
688
  }
614
689
 
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
- )!
690
+ if (S.AST.isUnion(property)) {
691
+ const unwrappedTypes = unwrapNestedUnions(property.types).map(unwrapDeclaration)
692
+ const nonNullType = unwrappedTypes.find((t) => !isNullishType(t))!
621
693
 
622
- if (AST.isObjects(nonNullType)) {
694
+ if (S.AST.isObjects(nonNullType)) {
623
695
  return createMeta<T>({
624
696
  propertySignatures: nonNullType.propertySignatures,
625
697
  parent,
@@ -627,11 +699,11 @@ export const createMeta = <T = any>(
627
699
  })
628
700
  }
629
701
 
630
- if (unwrappedTypes.every(AST.isLiteral)) {
702
+ if (unwrappedTypes.every((_) => isNullishType(_) || S.AST.isLiteral(_))) {
631
703
  return {
632
704
  ...meta,
633
705
  type: "select",
634
- members: unwrappedTypes.map((t) => t.literal)
706
+ members: unwrappedTypes.filter(S.AST.isLiteral).map((t) => t.literal)
635
707
  } as FieldMeta
636
708
  }
637
709
 
@@ -645,7 +717,7 @@ export const createMeta = <T = any>(
645
717
  } as FieldMeta
646
718
  }
647
719
 
648
- if (AST.isArrays(property)) {
720
+ if (S.AST.isArrays(property)) {
649
721
  return {
650
722
  ...meta,
651
723
  type: "multiple",
@@ -654,38 +726,7 @@ export const createMeta = <T = any>(
654
726
  } as FieldMeta
655
727
  }
656
728
 
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
- }
729
+ meta = { ...getJsonSchemaAnnotation(property), ...getFieldMetadataFromAst(property), ...meta }
689
730
 
690
731
  return meta as FieldMeta
691
732
  }
@@ -711,27 +752,21 @@ const flattenMeta = <T>(meta: MetaRecord<T> | FieldMeta, parentKey: string = "")
711
752
  return result
712
753
  }
713
754
 
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
755
+ const metadataFromAst = <From, To>(
756
+ schema: S.Codec<To, From, never>
718
757
  ): { meta: MetaRecord<To>; defaultValues: Record<string, any>; unionMeta: Record<string, MetaRecord<To>> } => {
719
- const ast = schema.ast
758
+ const ast = unwrapDeclaration(schema.ast)
720
759
  const newMeta: MetaRecord<To> = {}
721
760
  const defaultValues: Record<string, any> = {}
722
761
  const unionMeta: Record<string, MetaRecord<To>> = {}
723
762
 
724
763
  // Handle root-level Union types (discriminated unions)
725
- if (AST.isUnion(ast)) {
726
- const types = ast.types
727
-
764
+ if (S.AST.isUnion(ast)) {
728
765
  // 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)
766
+ const nonNullTypes = getNonNullTypes(ast.types)
732
767
 
733
768
  // Check if this is a discriminated union (all members are structs)
734
- const allStructs = nonNullTypes.every((t: any) => AST.isObjects(t))
769
+ const allStructs = nonNullTypes.every(S.AST.isObjects)
735
770
 
736
771
  if (allStructs && nonNullTypes.length > 0) {
737
772
  // Extract discriminator values from each union member
@@ -739,14 +774,14 @@ const metadataFromAst = <_From, To>(
739
774
 
740
775
  // Store metadata for each union member by its tag value
741
776
  for (const memberType of nonNullTypes) {
742
- if (AST.isObjects(memberType)) {
777
+ if (S.AST.isObjects(memberType)) {
743
778
  // Find the discriminator field (usually _tag)
744
779
  const tagProp = memberType.propertySignatures.find(
745
- (p: any) => p.name.toString() === "_tag"
780
+ (p) => p.name.toString() === "_tag"
746
781
  )
747
782
 
748
783
  let tagValue: string | null = null
749
- if (tagProp && AST.isLiteral(tagProp.type)) {
784
+ if (tagProp && S.AST.isLiteral(tagProp.type)) {
750
785
  tagValue = tagProp.type.literal as string
751
786
  discriminatorValues.push(tagValue)
752
787
  }
@@ -779,7 +814,7 @@ const metadataFromAst = <_From, To>(
779
814
  }
780
815
  }
781
816
 
782
- if (AST.isObjects(ast)) {
817
+ if (S.AST.isObjects(ast)) {
783
818
  const meta = createMeta<To>({
784
819
  propertySignatures: ast.propertySignatures
785
820
  })
@@ -814,10 +849,10 @@ export const duplicateSchema = <From, To>(
814
849
  return schema
815
850
  }
816
851
 
817
- export const generateMetaFromSchema = <_From, To>(
818
- schema: any // v4 Schema type is complex, use any for now
852
+ export const generateMetaFromSchema = <From, To>(
853
+ schema: S.Codec<To, From, never>
819
854
  ): {
820
- schema: any
855
+ schema: S.Codec<To, From, never>
821
856
  meta: MetaRecord<To>
822
857
  unionMeta: Record<string, MetaRecord<To>>
823
858
  } => {
@@ -833,167 +868,138 @@ export const generateInputStandardSchemaFromFieldMeta = (
833
868
  if (!trans) {
834
869
  trans = useIntl().trans
835
870
  }
836
- let schema: S.Codec<any>
837
-
871
+ let schema: any
838
872
  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
- }
873
+ case "string":
874
+ schema = meta.format === "email"
875
+ ? S.Email.annotate({
876
+ message: trans("validation.email.invalid")
877
+ })
878
+ : S.String.annotate({
879
+ message: trans("validation.empty")
880
+ })
852
881
 
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
- }
882
+ if (meta.required) {
883
+ schema = schema.check(S.isMinLength(1, {
884
+ message: trans("validation.empty")
885
+ }))
864
886
  }
865
887
 
866
888
  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
- )
889
+ schema = schema.check(S.isMaxLength(meta.maxLength, {
890
+ message: trans("validation.string.maxLength", {
891
+ maxLength: meta.maxLength
892
+ })
893
+ }))
894
+ }
895
+ if (typeof meta.minLength === "number") {
896
+ schema = schema.check(S.isMinLength(meta.minLength, {
897
+ message: trans("validation.string.minLength", {
898
+ minLength: meta.minLength
899
+ })
900
+ }))
873
901
  }
874
902
  break
875
- }
876
903
 
877
- case "number": {
904
+ case "number":
878
905
  if (meta.refinement === "int") {
879
- schema = S.Int
906
+ schema = S
907
+ .Number
908
+ .annotate({
909
+ message: trans("validation.empty")
910
+ })
911
+ .check(S.isInt({
912
+ message: trans("validation.integer.expected", { actualValue: "NaN" })
913
+ }))
880
914
  } else {
881
- schema = S.Number
915
+ schema = S.Number.annotate({
916
+ message: trans("validation.number.expected", { actualValue: "NaN" })
917
+ })
918
+
919
+ if (meta.required) {
920
+ schema = schema.annotate({
921
+ message: trans("validation.empty")
922
+ })
923
+ }
882
924
  }
883
925
 
884
- // Apply numeric validations
885
926
  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
- )
927
+ schema = schema.check(S.isGreaterThanOrEqualTo(meta.minimum, {
928
+ message: trans(meta.minimum === 0 ? "validation.number.positive" : "validation.number.min", {
929
+ minimum: meta.minimum,
930
+ isExclusive: true
931
+ })
932
+ }))
896
933
  }
897
-
898
934
  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
- )
935
+ schema = schema.check(S.isLessThanOrEqualTo(meta.maximum, {
936
+ message: trans("validation.number.max", {
937
+ maximum: meta.maximum,
938
+ isExclusive: true
939
+ })
940
+ }))
909
941
  }
910
-
911
942
  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
- )
943
+ schema = schema.check(S.isGreaterThan(meta.exclusiveMinimum, {
944
+ message: trans(meta.exclusiveMinimum === 0 ? "validation.number.positive" : "validation.number.min", {
945
+ minimum: meta.exclusiveMinimum,
946
+ isExclusive: false
947
+ })
948
+ }))
922
949
  }
923
-
924
950
  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
- )
951
+ schema = schema.check(S.isLessThan(meta.exclusiveMaximum, {
952
+ message: trans("validation.number.max", {
953
+ maximum: meta.exclusiveMaximum,
954
+ isExclusive: false
955
+ })
956
+ }))
935
957
  }
936
958
  break
937
- }
959
+ case "select":
960
+ schema = S.Literals(meta.members as [any, ...any[]]).annotate({
961
+ message: trans("validation.not_a_valid", {
962
+ type: "select",
963
+ message: meta.members.join(", ")
964
+ })
965
+ })
938
966
 
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
967
  break
950
- }
951
968
 
952
- case "multiple": {
953
- schema = S.Array(S.String)
969
+ case "multiple":
970
+ schema = S.Array(S.String).annotate({
971
+ message: trans("validation.not_a_valid", {
972
+ type: "multiple",
973
+ message: meta.members.join(", ")
974
+ })
975
+ })
954
976
  break
955
- }
956
977
 
957
- case "boolean": {
978
+ case "boolean":
958
979
  schema = S.Boolean
959
980
  break
960
- }
961
981
 
962
- case "unknown": {
982
+ case "unknown":
963
983
  schema = S.Unknown
964
984
  break
965
- }
966
985
 
967
- default: {
968
- console.warn(`Unhandled field type: ${(meta as any).type}`)
986
+ default:
987
+ // For any unhandled types, use Unknown schema to prevent undefined errors
988
+ console.warn(`Unhandled field type: ${meta}`)
969
989
  schema = S.Unknown
970
990
  break
971
- }
972
991
  }
973
-
974
- // Wrap in union with null/undefined if not required
975
992
  if (!meta.required) {
976
- // v4 Union takes an array of schemas
977
- schema = S.Union([schema, S.Null, S.Undefined])
993
+ schema = S.NullishOr(schema)
978
994
  }
979
-
980
- return S.toStandardSchemaV1(schema as any)
995
+ const result = S.toStandardSchemaV1(schema as any)
996
+ return result
981
997
  }
982
998
 
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
- // )
999
+ export const nullableInput = <A, I, R>(
1000
+ schema: S.Codec<A, I, R>,
1001
+ _defaultValue: () => A
1002
+ ) => S.NullOr(schema) as any
997
1003
 
998
1004
  export type OmegaAutoGenMeta<
999
1005
  From extends Record<PropertyKey, any>,
@@ -1039,11 +1045,11 @@ export function deepMerge(target: any, source: any) {
1039
1045
 
1040
1046
  // Type definitions for schemas with fields and members
1041
1047
  type SchemaWithFields = {
1042
- fields: Record<string, S.Top>
1048
+ fields: Record<string, S.Schema<any>>
1043
1049
  }
1044
1050
 
1045
1051
  type SchemaWithMembers = {
1046
- members: readonly S.Top[]
1052
+ members: readonly S.Schema<any>[]
1047
1053
  }
1048
1054
 
1049
1055
  // Type guards to check schema types
@@ -1057,10 +1063,15 @@ function hasMembers(schema: any): schema is SchemaWithMembers {
1057
1063
 
1058
1064
  // Internal implementation with WeakSet tracking
1059
1065
  export const defaultsValueFromSchema = (
1060
- schema: S.Codec<any>,
1066
+ schema: S.Schema<any>,
1061
1067
  record: Record<string, any> = {}
1062
1068
  ): any => {
1063
1069
  const ast = schema.ast
1070
+ const defaultValue = getDefaultFromAst(ast)
1071
+
1072
+ if (defaultValue !== undefined) {
1073
+ return defaultValue
1074
+ }
1064
1075
 
1065
1076
  if (isNullableOrUndefined(schema.ast) === "null") {
1066
1077
  return null
@@ -1069,35 +1080,7 @@ export const defaultsValueFromSchema = (
1069
1080
  return undefined
1070
1081
  }
1071
1082
 
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
1083
+ // Check if schema has fields directly
1101
1084
  if (hasFields(schema)) {
1102
1085
  // Process fields and extract default values
1103
1086
  const result: Record<string, any> = {}
@@ -1149,6 +1132,10 @@ export const defaultsValueFromSchema = (
1149
1132
  return acc
1150
1133
  }, {} as Record<string, any>)
1151
1134
 
1135
+ if (Object.keys(mergedMembers).length === 0) {
1136
+ return Object.keys(record).length > 0 ? record : undefined
1137
+ }
1138
+
1152
1139
  // Use reduce to properly accumulate the merged fields
1153
1140
  return Object.entries(mergedMembers).reduce((acc, [key, value]) => {
1154
1141
  acc[key] = defaultsValueFromSchema(value, record[key] || {})
@@ -1157,18 +1144,41 @@ export const defaultsValueFromSchema = (
1157
1144
  }
1158
1145
 
1159
1146
  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
1147
+ if (S.AST.isObjects(ast)) {
1148
+ // Process TypeLiteral fields directly to build the result object
1149
+ const result: Record<string, any> = { ...record }
1150
+
1151
+ for (const prop of ast.propertySignatures) {
1152
+ const key = prop.name.toString()
1153
+ const propType = prop.type
1154
+
1155
+ const propDefault = getDefaultFromAst(propType)
1156
+ if (propDefault !== undefined) {
1157
+ result[key] = propDefault
1158
+ continue
1159
+ }
1160
+
1161
+ // Create a schema from the property type and get its defaults
1162
+ const propSchema = S.make(propType)
1163
+
1164
+ // Recursively process the property - don't pas for prop processing
1165
+ // to allow proper unwrapping of nested structures
1166
+ const propValue = defaultsValueFromSchema(propSchema, record[key] || {})
1167
+
1168
+ if (propValue !== undefined) {
1169
+ result[key] = propValue
1170
+ }
1171
+ }
1172
+
1173
+ return result
1165
1174
  }
1166
- }
1167
1175
 
1168
- if (AST.isString(ast)) {
1169
- return ""
1170
- }
1171
- if (AST.isBoolean(ast)) {
1172
- return false
1176
+ if (S.AST.isString(ast)) {
1177
+ return ""
1178
+ }
1179
+
1180
+ if (S.AST.isBoolean(ast)) {
1181
+ return false
1182
+ }
1173
1183
  }
1174
1184
  }