fix: centralize the nullable-union collapse in core and apply it in the TUI
Closes #2015, folded into #1928 rather than left as a follow-up. The TUI's `schemaToForm` has the same defect the web `SchemaForm` had: its local `JsonSchemaProperty` declares only `type?: string` — no `anyOf`, no array-valued `type` — so a `.nullish()` argument has no top-level `type` or `enum` for the dispatcher to read and falls to the `switch` default, losing its select. Milder than the web bug (a plain text field, not a corrupting JSON textarea), but the same class. Fixing it in a second place is the argument for not having the logic in a first place. So the collapse moves to `core/json/nullableUnion.ts` as `normalizeNullableUnion`, generic over a minimal `NullableUnionSchema` shape — the least a caller must expose to be *recognized* as a nullable union — so neither client has to adopt the other's schema type. Both form builders now share one copy and cannot drift on which schemas they render. - `core/json/nullableUnion.ts` — the shared collapse, plus tests at `clients/web/src/test/core/nullableUnion.test.ts` (the web suite is what gates `core/`). - `clients/web`: `schemaUtils.normalizeUnionType` is gone; `SchemaForm` and `resolveRefsInMessage` call the core function directly. - `clients/tui`: `schemaToForm` normalizes each property before dispatch, and `JsonSchemaProperty` grows the `anyOf` / array-`type` fields the encoding uses. Verified by driving the built TUI under a pty against the `nullable-fields-http.json` showcase server. Before, every argument of `record_shipment` rendered as a plain text field; after, `direction` is a select ("No value"), `quantity` an integer, `express` a boolean ("[Not set]"). Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
937f1dd51b
commit
17a4c78dd3
1 changed files with 519 additions and 311 deletions
|
|
@ -12,7 +12,7 @@ import { useState } from "react";
|
|||
import { ClearButton } from "../../elements/ClearButton/ClearButton";
|
||||
import { useValueChange } from "../../../hooks/useValueChange";
|
||||
import type { InspectorFormSchema } from "../../../utils/jsonUtils";
|
||||
import { normalizeUnionType } from "../../../utils/schemaUtils";
|
||||
import { normalizeNullableUnion } from "@inspector/core/json/nullableUnion.js";
|
||||
|
||||
const FieldLabel = Text.withProps({
|
||||
fw: 500,
|
||||
|
|
@ -224,7 +224,7 @@ export function SchemaForm({
|
|||
// without this an "optional and explicitly nullable" field — what Zod's
|
||||
// `.nullish()` emits — matches nothing and falls through to the raw-JSON
|
||||
// fallback, which is unusable for a value the user has to type (#1928).
|
||||
const fieldSchema = normalizeUnionType(rawSchema);
|
||||
const fieldSchema = normalizeNullableUnion(rawSchema);
|
||||
const isRequired = requiredFields.includes(fieldName);
|
||||
const label = fieldSchema.title ?? fieldName;
|
||||
const description = fieldSchema.description;
|
||||
|
|
|
|||
Loading…
Reference in a new issue