diff --git a/.changeset/polite-crews-camp.md b/.changeset/polite-crews-camp.md new file mode 100644 index 000000000..e68fa0006 --- /dev/null +++ b/.changeset/polite-crews-camp.md @@ -0,0 +1,5 @@ +--- +"@effect-app/vue-components": patch +--- + +feat: Enhance OmegaForm with union metadata handling and nested meta flattening diff --git a/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts b/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts index d9ab6e27b..2004a6d79 100644 --- a/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts +++ b/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts @@ -681,12 +681,31 @@ export const createMeta = ( return acc } +// Helper to flatten nested meta structure into dot-notation keys +const flattenMeta = (meta: MetaRecord | FieldMeta, parentKey: string = ""): MetaRecord => { + const result: MetaRecord = {} + + for (const key in meta) { + const value = (meta as any)[key] + const newKey = parentKey ? `${parentKey}.${key}` : key + + if (value && typeof value === "object" && "type" in value) { + result[newKey as DeepKeys] = value as FieldMeta + } else if (value && typeof value === "object") { + Object.assign(result, flattenMeta(value, newKey)) + } + } + + return result +} + const metadataFromAst = ( schema: S.Schema -): { meta: MetaRecord; defaultValues: Record } => { +): { meta: MetaRecord; defaultValues: Record; unionMeta: Record> } => { const ast = schema.ast const newMeta: MetaRecord = {} const defaultValues: Record = {} + const unionMeta: Record> = {} if (ast._tag === "Transformation" || ast._tag === "Refinement") { return metadataFromAst(S.make(ast.from)) @@ -709,7 +728,7 @@ const metadataFromAst = ( // Extract discriminator values from each union member const discriminatorValues: any[] = [] - // Merge metadata from all union members + // Store metadata for each union member by its tag value for (const memberType of nonNullTypes) { if ("propertySignatures" in memberType) { // Find the discriminator field (usually _tag) @@ -717,8 +736,10 @@ const metadataFromAst = ( (p: any) => p.name.toString() === "_tag" ) + let tagValue: string | null = null if (tagProp && S.AST.isLiteral(tagProp.type)) { - discriminatorValues.push(tagProp.type.literal) + tagValue = tagProp.type.literal as string + discriminatorValues.push(tagValue) } // Create metadata for this member's properties @@ -726,7 +747,12 @@ const metadataFromAst = ( propertySignatures: memberType.propertySignatures }) - // Merge into result + // Store per-tag metadata for reactive lookup + if (tagValue) { + unionMeta[tagValue] = flattenMeta(memberMeta) + } + + // Merge into result (for backward compatibility) Object.assign(newMeta, memberMeta) } } @@ -740,7 +766,7 @@ const metadataFromAst = ( } as FieldMeta } - return { meta: newMeta, defaultValues } + return { meta: newMeta, defaultValues, unionMeta } } } @@ -750,7 +776,7 @@ const metadataFromAst = ( }) if (Object.values(meta).every((value) => value && "type" in value)) { - return { meta: meta as MetaRecord, defaultValues } + return { meta: meta as MetaRecord, defaultValues, unionMeta } } const flattenObject = ( @@ -770,7 +796,7 @@ const metadataFromAst = ( flattenObject(meta) } - return { meta: newMeta, defaultValues } + return { meta: newMeta, defaultValues, unionMeta } } export const duplicateSchema = ( @@ -784,16 +810,20 @@ export const generateMetaFromSchema = ( ): { schema: S.Schema meta: MetaRecord + unionMeta: Record> } => { - const { meta } = metadataFromAst(schema) + const { meta, unionMeta } = metadataFromAst(schema) - return { schema, meta } + return { schema, meta, unionMeta } } export const generateInputStandardSchemaFromFieldMeta = ( - meta: FieldMeta + meta: FieldMeta, + trans?: ReturnType["trans"] ): StandardSchemaV1 => { - const { trans } = useIntl() + if (!trans) { + trans = useIntl().trans + } let schema: S.Schema switch (meta.type) { case "string": @@ -850,7 +880,6 @@ export const generateInputStandardSchemaFromFieldMeta = ( }) } if (typeof meta.minimum === "number") { - console.log("pippocazzo", meta) schema = schema.pipe(S.greaterThanOrEqualTo(meta.minimum)).annotations({ message: () => trans(meta.minimum === 0 ? "validation.number.positive" : "validation.number.min", { diff --git a/packages/vue-components/src/components/OmegaForm/OmegaInput.vue b/packages/vue-components/src/components/OmegaForm/OmegaInput.vue index d37f204c0..2bf17aa00 100644 --- a/packages/vue-components/src/components/OmegaForm/OmegaInput.vue +++ b/packages/vue-components/src/components/OmegaForm/OmegaInput.vue @@ -1,6 +1,7 @@