Skip to content

Commit dc902a0

Browse files
authored
fixes optionalKey required handling in OmegaForm (#645)
1 parent a09497a commit dc902a0

2 files changed

Lines changed: 64 additions & 0 deletions

File tree

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { S } from "effect-app"
2+
import { describe, expect, it } from "vitest"
3+
import { generateMetaFromSchema } from "../../src/components/OmegaForm/OmegaFormStuff"
4+
5+
describe("optionalKey required handling", () => {
6+
it("should mark optionalKey fields as not required", () => {
7+
const schema = S.Struct({
8+
number: S.optionalKey(S.Int.pipe(S.check(S.isBetween({ minimum: 1, maximum: 20 })))),
9+
height: S.NonEmptyString100.pipe(S.check(S.isMinLength(10)))
10+
})
11+
12+
const { meta } = generateMetaFromSchema(schema)
13+
14+
// optionalKey field should NOT be required
15+
expect(meta.number?.required).toBe(false)
16+
17+
// regular field should still be required
18+
expect(meta.height?.required).toBe(true)
19+
})
20+
21+
it("should mark optionalKey with decodingDefault as not required", () => {
22+
const schema = S.Struct({
23+
name: S.optionalKey(S.String).pipe(S.withDecodingDefault(() => "defaultName")),
24+
age: S.NonEmptyString255
25+
})
26+
27+
const { meta } = generateMetaFromSchema(schema)
28+
29+
expect(meta.name?.required).toBe(false)
30+
expect(meta.age?.required).toBe(true)
31+
})
32+
33+
it("should handle optionalKey in tagged union branches", () => {
34+
const schema = S.Union([
35+
S.TaggedStruct("one", {
36+
a: S.Struct({
37+
number: S.optionalKey(S.Int.pipe(S.check(S.isBetween({ minimum: 1, maximum: 20 })))),
38+
height: S.NonEmptyString100.pipe(S.check(S.isMinLength(10))),
39+
z: S.NonEmptyString100.pipe(S.check(S.isMinLength(10)))
40+
})
41+
}),
42+
S.TaggedStruct("two", {
43+
a: S.Struct({
44+
number: S.optionalKey(S.Int.pipe(S.check(S.isBetween({ minimum: 1, maximum: 20 })))),
45+
height: S.NonEmptyString100.pipe(S.check(S.isMinLength(10))),
46+
y: S.NonEmptyString100.pipe(S.check(S.isMinLength(10)))
47+
})
48+
})
49+
])
50+
51+
const { meta } = generateMetaFromSchema(schema)
52+
53+
// optionalKey in both union branches should not be required
54+
expect(meta["a.number"]?.required).toBe(false)
55+
56+
// regular fields should be required
57+
expect(meta["a.height"]?.required).toBe(true)
58+
expect(meta["a.z"]?.required).toBe(true)
59+
expect(meta["a.y"]?.required).toBe(true)
60+
})
61+
})

packages/vue-components/src/components/OmegaForm/OmegaFormStuff.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,7 @@ export const createMeta = <T = any>(
521521

522522
// Determine if this field should be required:
523523
// - For nullable discriminated unions, only _tag should be non-required
524+
// - optionalKey fields are not required
524525
// - All other fields should calculate their required status normally
525526
let isRequired: boolean
526527
if (meta._isNullableDiscriminatedUnion && p.name.toString() === "_tag") {
@@ -529,6 +530,8 @@ export const createMeta = <T = any>(
529530
} else if (meta.required === false) {
530531
// Explicitly set to non-required (legacy behavior for backwards compatibility)
531532
isRequired = false
533+
} else if ((p.type as any).context?.isOptional) {
534+
isRequired = false
532535
} else {
533536
// Calculate from the property itself
534537
isRequired = !nullableOrUndefined

0 commit comments

Comments
 (0)