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/.changeset/twelve-moments-pull.md b/.changeset/twelve-moments-pull.md new file mode 100644 index 000000000..52b731e16 --- /dev/null +++ b/.changeset/twelve-moments-pull.md @@ -0,0 +1,5 @@ +--- +"@effect-app/vue-components": minor +--- + +chore: enhance metadata handling by adding unionDefaultValues to support default values for tagged schemas diff --git a/.changeset/twenty-dolls-bathe.md b/.changeset/twenty-dolls-bathe.md new file mode 100644 index 000000000..245021f23 --- /dev/null +++ b/.changeset/twenty-dolls-bathe.md @@ -0,0 +1,5 @@ +--- +"@effect-app/vue-components": patch +--- + +fix: Add key to component for reactivity and include translation in schema generation diff --git a/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts b/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts index d9ab6e27b..79712edb7 100644 --- a/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts +++ b/packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts @@ -356,6 +356,7 @@ export const createMeta = ( if (property?._tag === "TypeLiteral" && "propertySignatures" in property) { return createMeta({ + parent, // Pass parent to maintain the key prefix for nested structures meta, propertySignatures: property.propertySignatures }) @@ -404,7 +405,13 @@ export const createMeta = ( property: p.type, meta: { required: isRequired, nullableOrUndefined } }) - acc[key as NestedKeyOf] = parentMeta as FieldMeta + // If parentMeta is a MetaRecord (nested structure from ExtendedClass), merge it + // Otherwise assign as single FieldMeta + if (parentMeta && typeof parentMeta === "object" && !("type" in parentMeta)) { + Object.assign(acc, parentMeta) + } else { + acc[key as NestedKeyOf] = parentMeta as FieldMeta + } } // Process each non-null type and merge their metadata @@ -681,12 +688,37 @@ 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> + unionDefaultValues: Record> +} => { const ast = schema.ast const newMeta: MetaRecord = {} const defaultValues: Record = {} + const unionMeta: Record> = {} + const unionDefaultValues: Record> = {} if (ast._tag === "Transformation" || ast._tag === "Refinement") { return metadataFromAst(S.make(ast.from)) @@ -709,7 +741,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 +749,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 +760,15 @@ const metadataFromAst = ( propertySignatures: memberType.propertySignatures }) - // Merge into result + // Store per-tag metadata for reactive lookup + if (tagValue) { + unionMeta[tagValue] = flattenMeta(memberMeta) + // Create default values for this tag's schema + const memberSchema = S.make(memberType) + unionDefaultValues[tagValue] = defaultsValueFromSchema(memberSchema as any) + } + + // Merge into result (for backward compatibility) Object.assign(newMeta, memberMeta) } } @@ -740,7 +782,7 @@ const metadataFromAst = ( } as FieldMeta } - return { meta: newMeta, defaultValues } + return { meta: newMeta, defaultValues, unionMeta, unionDefaultValues } } } @@ -750,7 +792,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, unionDefaultValues } } const flattenObject = ( @@ -770,7 +812,7 @@ const metadataFromAst = ( flattenObject(meta) } - return { meta: newMeta, defaultValues } + return { meta: newMeta, defaultValues, unionMeta, unionDefaultValues } } export const duplicateSchema = ( @@ -784,16 +826,21 @@ export const generateMetaFromSchema = ( ): { schema: S.Schema meta: MetaRecord + unionMeta: Record> + unionDefaultValues: Record> } => { - const { meta } = metadataFromAst(schema) + const { meta, unionMeta, unionDefaultValues } = metadataFromAst(schema) - return { schema, meta } + return { schema, meta, unionMeta, unionDefaultValues } } 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 +897,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..856451c1a 100644 --- a/packages/vue-components/src/components/OmegaForm/OmegaInput.vue +++ b/packages/vue-components/src/components/OmegaForm/OmegaInput.vue @@ -1,6 +1,7 @@