mirror of
https://github.com/vercel-labs/json-render.git
synced 2026-10-02 03:54:41 +08:00
autoFixSpec prunes children references to undefined elements
Dangling references are the dominant remaining first-attempt validation failure in benchmarks, and models frequently fail to repair them even given the exact error (observed: three repair turns, same dangling footer each time). The renderer already skips missing children at runtime, so pruning yields the identical rendered output while letting the spec validate. Each removal is reported in fixes.
This commit is contained in:
@@ -148,6 +148,35 @@ describe("validateSpec", () => {
|
||||
// =============================================================================
|
||||
|
||||
describe("autoFixSpec", () => {
|
||||
it("prunes children references to undefined elements", () => {
|
||||
const spec: Spec = {
|
||||
root: "root",
|
||||
elements: {
|
||||
root: { type: "Card", props: {}, children: ["text", "ghost"] },
|
||||
text: { type: "Text", props: { text: "hi" }, children: [] },
|
||||
},
|
||||
};
|
||||
const { spec: fixed, fixes } = autoFixSpec(spec);
|
||||
expect(fixed.elements.root!.children).toEqual(["text"]);
|
||||
expect(fixes).toEqual([
|
||||
'Removed reference to undefined element "ghost" from children of "root".',
|
||||
]);
|
||||
expect(validateSpec(fixed).valid).toBe(true);
|
||||
});
|
||||
|
||||
it("leaves intact children untouched", () => {
|
||||
const spec: Spec = {
|
||||
root: "root",
|
||||
elements: {
|
||||
root: { type: "Card", props: {}, children: ["text"] },
|
||||
text: { type: "Text", props: { text: "hi" }, children: [] },
|
||||
},
|
||||
};
|
||||
const { spec: fixed, fixes } = autoFixSpec(spec);
|
||||
expect(fixed.elements.root!.children).toEqual(["text"]);
|
||||
expect(fixes).toEqual([]);
|
||||
});
|
||||
|
||||
it("moves visible from props to element level", () => {
|
||||
const spec: Spec = {
|
||||
root: "root",
|
||||
|
||||
@@ -277,6 +277,23 @@ export function autoFixSpec(spec: Spec): {
|
||||
fixedElements[key] = fixed;
|
||||
}
|
||||
|
||||
// Drop references to elements that were never defined. The renderer skips
|
||||
// missing children at runtime, so pruning produces the same rendered output
|
||||
// while letting the spec pass validation instead of hard-failing.
|
||||
for (const [key, element] of Object.entries(fixedElements)) {
|
||||
if (!element.children || element.children.length === 0) continue;
|
||||
const present = element.children.filter((child) => child in fixedElements);
|
||||
if (present.length === element.children.length) continue;
|
||||
for (const child of element.children) {
|
||||
if (!(child in fixedElements)) {
|
||||
fixes.push(
|
||||
`Removed reference to undefined element "${child}" from children of "${key}".`,
|
||||
);
|
||||
}
|
||||
}
|
||||
fixedElements[key] = { ...element, children: present };
|
||||
}
|
||||
|
||||
return {
|
||||
spec: { root: spec.root, elements: fixedElements, state: spec.state },
|
||||
fixes,
|
||||
|
||||
Reference in New Issue
Block a user