fix(editor): restore build after toGraph signature change + client/backend numeric parity

This commit is contained in:
Claude
2026-08-30 11:06:09 +00:00
parent b1dae49171
commit a131dbf198
3 changed files with 52 additions and 2 deletions

View File

@@ -123,4 +123,44 @@ describe("toGraph — schema-typed coercion on save", () => {
);
expect(g.nodes[0].config.status).toBe(200);
});
it("hex literals on integer fields are not coerced (backend rejects them too)", () => {
const g = toGraph(
[{
id: "n1", type: "vc",
position: { x: 0, y: 0 },
data: { typeId: "test.numberfield", config: { status: "0x1F" } },
}],
[],
[numberNodeType],
);
// Kept as string so backend surfaces the parse error at run time.
expect(g.nodes[0].config.status).toBe("0x1F");
});
it("scientific-notation strings on integer fields are not coerced (backend rejects them)", () => {
const g = toGraph(
[{
id: "n1", type: "vc",
position: { x: 0, y: 0 },
data: { typeId: "test.numberfield", config: { status: "1e2" } },
}],
[],
[numberNodeType],
);
expect(g.nodes[0].config.status).toBe("1e2");
});
it("scientific-notation strings on number fields ARE coerced (backend accepts them)", () => {
const g = toGraph(
[{
id: "n1", type: "vc",
position: { x: 0, y: 0 },
data: { typeId: "test.numberfield", config: { ratio: "1e2" } },
}],
[],
[numberNodeType],
);
expect(g.nodes[0].config.ratio).toBe(100);
});
});

View File

@@ -79,11 +79,21 @@ export function coerceConfigForSave(
}
switch (prop.type) {
case "integer": {
// Match backend long.TryParse(NumberStyles.Integer): sign + digits,
// optional leading/trailing whitespace. No hex, no scientific.
if (!/^\s*-?\d+\s*$/.test(value)) { out[name] = value; break; }
const n = Number(value);
out[name] = Number.isInteger(n) ? n : value;
out[name] = Number.isSafeInteger(n) ? n : value;
break;
}
case "number": {
// Match backend double.TryParse(NumberStyles.Float): sign + digits +
// optional fractional + optional exponent, optional whitespace.
// Rejects hex (`0x…`). Backend Float style accepts scientific
// notation, so we do too here.
if (!/^\s*-?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?\s*$/.test(value)) {
out[name] = value; break;
}
const n = Number(value);
out[name] = Number.isFinite(n) ? n : value;
break;

View File

@@ -70,7 +70,7 @@ export default function EditorPage() {
() =>
apiFetch<void>(`/api/workflows/${id}`, {
method: "PUT",
body: { name: wf.data!.name, graph: toGraph(nodes, edges) },
body: { name: wf.data!.name, graph: toGraph(nodes, edges, nts.data ?? []) },
}),
{ onSuccess: () => id && invalidate(qk.workflow(id)) },
);