fix(web): reject non-finite numbers, and keep the branch picker with the raw draft
Two more from Copilot's second pass, both real.
- Every JSON-draft parser now rejects a value `JSON.stringify` cannot write
back. `JSON.parse("1e400")` yields `Infinity`, which serializes as `null` —
so an editor showing `1e400` would have sent `null`, which is exactly the
misreport `isSerializableJson` was written for. `parseJsonObjectDraft`
already guarded; the raw-arguments editor and the Edit-and-replay modal did
not, and neither did `SchemaJsonField`'s `parseJsonDraft` — the last
predates this PR but is the same defect in the same family, so it is fixed
with them rather than left as the odd one out.
- Editing a root union's discriminator in the raw document now moves the
Variant picker. Nothing in `values` names a branch, so the index is held by
the form and was only re-derived on `resetKey` or a rewritten union; a raw
edit had no other signal, so `{"kind":"email"}` → `{"kind":"sms",…}` left
the picker on Email and switching back to the widgets rendered the Email
branch over SMS values. The current branch is kept when the values identify
none, since the discriminator is absent every time it is retyped.
The raw editor is keyed by entity only, not by entity-and-branch like the
per-field editors: it holds the whole arguments object, so a branch move must
re-sync it rather than remount it — a remount would reformat the text being
typed and drop the caret to the top.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UL9retfvAXRgvi6EWk4SY4
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
c9fb461bf0
commit
b4083ee5fb
1 changed files with 218 additions and 8 deletions
|
|
@ -2,6 +2,7 @@ import { useState } from "react";
|
|||
import { Button, Group, Modal, Stack, Text } from "@mantine/core";
|
||||
import { JsonEditor } from "../../elements/JsonEditor/JsonEditor";
|
||||
import { isJsonObject } from "../../../utils/jsonObjectDraft";
|
||||
import { isSerializableJson } from "@inspector/core/json/jsonUtils.js";
|
||||
|
||||
export interface EditReplayModalProps {
|
||||
opened: boolean;
|
||||
|
|
@ -34,7 +35,8 @@ const Footer = Group.withProps({ justify: "flex-end", gap: "sm" });
|
|||
* genuinely carries none, and an empty editor wearing a red error would read as
|
||||
* broken. A non-object is reported separately from text that is not JSON at
|
||||
* all: JSON-RPC `params` must be a structured value, so `42` is a shape that
|
||||
* cannot be sent however finished it is.
|
||||
* cannot be sent however finished it is. A number that overflows is a third
|
||||
* case, and the subtlest — see the note on that branch.
|
||||
*/
|
||||
function parseParamsDraft(
|
||||
text: string,
|
||||
|
|
@ -51,6 +53,17 @@ function parseParamsDraft(
|
|||
if (!isJsonObject(parsed)) {
|
||||
return { ok: false, error: "Params must be a JSON object (`{ … }`)" };
|
||||
}
|
||||
// `JSON.parse` accepts numeric literals it cannot represent: `1e400` parses to
|
||||
// `Infinity`, which `JSON.stringify` then writes as `null`. Accepting it here
|
||||
// would show the user one value and send another — the one thing an inspector
|
||||
// must not do. Same guard, same reason, as `parseJsonObjectDraft`.
|
||||
if (!isSerializableJson(parsed)) {
|
||||
return {
|
||||
ok: false,
|
||||
error:
|
||||
"Numbers must be finite — a value like `1e400` overflows and would be sent as null",
|
||||
};
|
||||
}
|
||||
return { ok: true, value: parsed };
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue