fix: address Copilot review round 21 — seed a nested object's own union branch
collectSchemaDefaults recursed only when a nested object declared `properties` directly, so one keeping its fields on a composition branch was skipped — while SchemaForm rendered that branch and displayed its read-only discriminator. The constant was shown and never submitted, and the server rejected the call. The recursion now gates on declaresAnyFields. Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
d334710d6f
commit
92e485ab82
2 changed files with 40 additions and 1 deletions
|
|
@ -457,6 +457,37 @@ describe("root composition (#2123)", () => {
|
|||
expect(Object.hasOwn(seeded, "__proto__")).toBe(true);
|
||||
});
|
||||
|
||||
it("seeds defaults from a nested object's own union branch", () => {
|
||||
// The nested form renders that branch, so its read-only discriminator has
|
||||
// to reach the submitted values too.
|
||||
expect(
|
||||
collectSchemaDefaults({
|
||||
type: "object",
|
||||
properties: {
|
||||
config: {
|
||||
type: "object",
|
||||
anyOf: [
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
kind: { type: "string", const: "email" },
|
||||
address: { type: "string" },
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "object",
|
||||
properties: {
|
||||
kind: { type: "string", const: "sms" },
|
||||
phone: { type: "string" },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
).toEqual({ config: { kind: "email" } });
|
||||
});
|
||||
|
||||
it("re-applies a nested object's constants", () => {
|
||||
// The overlay replaces the whole nested object rather than merging into it,
|
||||
// so a link naming `{ config: { kind: "sms" } }` would otherwise slip past
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import {
|
|||
} from "@inspector/core/json/nullableUnion.js";
|
||||
import {
|
||||
branchAcceptsValues,
|
||||
declaresAnyFields,
|
||||
resolveRootUnion,
|
||||
selectBranchIndex,
|
||||
} from "@inspector/core/json/rootUnion.js";
|
||||
|
|
@ -176,7 +177,14 @@ export function collectSchemaDefaults(
|
|||
seed(fieldName, fieldSchema.const);
|
||||
} else if (fieldSchema.default !== undefined) {
|
||||
seed(fieldName, fieldSchema.default);
|
||||
} else if (fieldSchema.type === "object" && fieldSchema.properties) {
|
||||
} else if (
|
||||
fieldSchema.type === "object" &&
|
||||
// Not `fieldSchema.properties`: a nested object can keep its fields on a
|
||||
// composition branch too, and `SchemaForm` renders that branch — so
|
||||
// skipping it here would leave its read-only discriminator displayed but
|
||||
// never submitted, and the server would reject the call (#2123).
|
||||
declaresAnyFields(fieldSchema)
|
||||
) {
|
||||
const nested = collectSchemaDefaults(fieldSchema);
|
||||
if (Object.keys(nested).length > 0) {
|
||||
seed(fieldName, nested);
|
||||
|
|
|
|||
Loading…
Reference in a new issue