schema-components 1.29.0 → 2.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +38 -16
  2. package/dist/core/adapter.d.mts +213 -3
  3. package/dist/core/adapter.mjs +1 -1
  4. package/dist/core/constraintHint.d.mts +15 -0
  5. package/dist/core/constraintHint.mjs +24 -0
  6. package/dist/core/constraints.d.mts +2 -2
  7. package/dist/core/constraints.mjs +1 -1
  8. package/dist/core/diagnostics.d.mts +1 -1
  9. package/dist/core/errors.d.mts +1 -1
  10. package/dist/core/fieldOrder.d.mts +1 -1
  11. package/dist/core/formats.d.mts +1 -1
  12. package/dist/core/idPath.d.mts +35 -5
  13. package/dist/core/idPath.mjs +79 -7
  14. package/dist/core/inferValue.d.mts +2 -0
  15. package/dist/core/inferValue.mjs +1 -0
  16. package/dist/core/limits.d.mts +1 -1
  17. package/dist/core/limits.mjs +5 -0
  18. package/dist/core/merge.d.mts +12 -1
  19. package/dist/core/merge.mjs +66 -3
  20. package/dist/core/normalise.d.mts +1 -1
  21. package/dist/core/normalise.mjs +1 -1
  22. package/dist/core/openapi30.mjs +1 -1
  23. package/dist/core/ref.d.mts +1 -1
  24. package/dist/core/refChain.d.mts +3 -4
  25. package/dist/core/refChain.mjs +2 -3
  26. package/dist/core/renderer.d.mts +199 -2
  27. package/dist/core/swagger2.d.mts +1 -1
  28. package/dist/core/swagger2.mjs +1 -1
  29. package/dist/core/typeInference.d.mts +3 -3
  30. package/dist/core/types.d.mts +1 -1
  31. package/dist/core/unionMatch.d.mts +1 -1
  32. package/dist/core/uri.d.mts +12 -4
  33. package/dist/core/uri.mjs +30 -4
  34. package/dist/core/walkBuilders.d.mts +18 -6
  35. package/dist/core/walkBuilders.mjs +3 -1
  36. package/dist/core/walker.d.mts +1 -1
  37. package/dist/core/walker.mjs +5 -0
  38. package/dist/{diagnostics-ByEzkjrA.d.mts → diagnostics-BTrm3O6J.d.mts} +1 -1
  39. package/dist/{errors-D8JndRwI.d.mts → errors-Dki7tji4.d.mts} +1 -1
  40. package/dist/html/a11y.d.mts +3 -7
  41. package/dist/html/a11y.mjs +1 -16
  42. package/dist/html/renderToHtml.d.mts +22 -9
  43. package/dist/html/renderToHtml.mjs +2 -1
  44. package/dist/html/renderToHtmlStream.d.mts +24 -11
  45. package/dist/html/renderToHtmlStream.mjs +2 -1
  46. package/dist/html/renderers.d.mts +2 -33
  47. package/dist/html/renderers.mjs +39 -91
  48. package/dist/html/streamRenderers.d.mts +3 -3
  49. package/dist/html/streamRenderers.mjs +13 -8
  50. package/dist/inferValue-PPXWJpbN.d.mts +77 -0
  51. package/dist/{limits-DswmqWuy.d.mts → limits-x4OiyJxh.d.mts} +5 -0
  52. package/dist/{normalise-Db1xaxgx.mjs → normalise-DB-Xtjmn.mjs} +43 -2
  53. package/dist/openapi/ApiCallbacks.d.mts +1 -1
  54. package/dist/openapi/ApiLinks.d.mts +1 -1
  55. package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
  56. package/dist/openapi/ApiSecurity.d.mts +1 -1
  57. package/dist/openapi/ApiSecurity.mjs +21 -8
  58. package/dist/openapi/bundle.d.mts +31 -0
  59. package/dist/openapi/components.d.mts +41 -10
  60. package/dist/openapi/components.mjs +19 -13
  61. package/dist/openapi/parser.d.mts +13 -13
  62. package/dist/openapi/parser.mjs +12 -12
  63. package/dist/openapi/resolve.d.mts +38 -49
  64. package/dist/openapi/resolve.mjs +62 -56
  65. package/dist/react/SchemaComponent.d.mts +19 -95
  66. package/dist/react/SchemaComponent.mjs +12 -1
  67. package/dist/react/SchemaView.d.mts +11 -7
  68. package/dist/react/SchemaView.mjs +3 -1
  69. package/dist/react/a11y.d.mts +74 -7
  70. package/dist/react/a11y.mjs +67 -6
  71. package/dist/react/fieldPath.d.mts +16 -1
  72. package/dist/react/fieldPath.mjs +25 -1
  73. package/dist/react/fieldShell.d.mts +49 -0
  74. package/dist/react/fieldShell.mjs +37 -0
  75. package/dist/react/headless.d.mts +1 -1
  76. package/dist/react/headlessRenderers.d.mts +2 -2
  77. package/dist/react/headlessRenderers.mjs +123 -54
  78. package/dist/{ref-CPh8rKQ3.d.mts → ref-DdsbekXX.d.mts} +33 -1
  79. package/dist/themes/mantine.d.mts +36 -20
  80. package/dist/themes/mantine.mjs +179 -150
  81. package/dist/themes/mui.d.mts +47 -21
  82. package/dist/themes/mui.mjs +259 -222
  83. package/dist/themes/radix.d.mts +38 -23
  84. package/dist/themes/radix.mjs +208 -180
  85. package/dist/themes/shadcn.d.mts +6 -3
  86. package/dist/themes/shadcn.mjs +93 -93
  87. package/dist/{types-C2Ay1FEh.d.mts → types-BrYbjC7_.d.mts} +7 -0
  88. package/package.json +5 -1
  89. package/dist/adapter-DcWi4XXn.d.mts +0 -223
  90. package/dist/renderer-OaOz-n6-.d.mts +0 -185
@@ -2,7 +2,7 @@ import { toRecord } from "../core/guards.mjs";
2
2
  import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
3
3
  import { displayJsonValue } from "../core/walkBuilders.mjs";
4
4
  import { inputId, toReactNode } from "../react/headlessRenderers.mjs";
5
- import { headlessResolver } from "../react/headless.mjs";
5
+ import { FieldShell } from "../react/fieldShell.mjs";
6
6
  import { jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region src/themes/shadcn.tsx
8
8
  function isString(value) {
@@ -20,27 +20,23 @@ function renderStringInput(props) {
20
20
  className: "text-sm",
21
21
  children: strValue || "—"
22
22
  });
23
- if (props.writeOnly) return /* @__PURE__ */ jsx("input", {
24
- id,
25
- type: props.constraints.format === "email" ? "email" : "text",
26
- className,
27
- placeholder: typeof props.meta.description === "string" ? props.meta.description : void 0,
28
- value: "",
29
- onChange: (e) => {
30
- props.onChange(e.target.value);
31
- }
32
- });
33
- return /* @__PURE__ */ jsx("input", {
34
- id,
35
- type: props.constraints.format === "email" ? "email" : "text",
36
- className,
37
- value: strValue,
38
- onChange: (e) => {
39
- props.onChange(e.target.value);
40
- },
41
- placeholder: typeof props.meta.description === "string" ? props.meta.description : void 0,
42
- minLength: props.constraints.minLength,
43
- maxLength: props.constraints.maxLength
23
+ const placeholder = typeof props.meta.description === "string" ? props.meta.description : void 0;
24
+ return /* @__PURE__ */ jsx(FieldShell, {
25
+ props,
26
+ inputId: id,
27
+ children: (aria) => /* @__PURE__ */ jsx("input", {
28
+ id,
29
+ type: props.constraints.format === "email" ? "email" : "text",
30
+ className,
31
+ placeholder,
32
+ value: props.writeOnly ? "" : strValue,
33
+ onChange: (e) => {
34
+ props.onChange(e.target.value);
35
+ },
36
+ minLength: props.constraints.minLength,
37
+ maxLength: props.constraints.maxLength,
38
+ ...aria
39
+ })
44
40
  });
45
41
  }
46
42
  function renderNumberInput(props) {
@@ -58,16 +54,21 @@ function renderNumberInput(props) {
58
54
  children: props.value.toLocaleString()
59
55
  });
60
56
  }
61
- return /* @__PURE__ */ jsx("input", {
62
- id,
63
- type: "number",
64
- className,
65
- value: props.writeOnly ? "" : typeof props.value === "number" ? props.value : "",
66
- onChange: (e) => {
67
- props.onChange(Number(e.target.value));
68
- },
69
- min: props.constraints.minimum,
70
- max: props.constraints.maximum
57
+ return /* @__PURE__ */ jsx(FieldShell, {
58
+ props,
59
+ inputId: id,
60
+ children: (aria) => /* @__PURE__ */ jsx("input", {
61
+ id,
62
+ type: "number",
63
+ className,
64
+ value: props.writeOnly ? "" : typeof props.value === "number" ? props.value : "",
65
+ onChange: (e) => {
66
+ props.onChange(Number(e.target.value));
67
+ },
68
+ min: props.constraints.minimum,
69
+ max: props.constraints.maximum,
70
+ ...aria
71
+ })
71
72
  });
72
73
  }
73
74
  function renderBooleanInput(props) {
@@ -85,14 +86,52 @@ function renderBooleanInput(props) {
85
86
  children: props.value ? "Yes" : "No"
86
87
  });
87
88
  }
88
- return /* @__PURE__ */ jsx("input", {
89
+ return /* @__PURE__ */ jsx(FieldShell, {
90
+ props,
91
+ inputId: id,
92
+ children: (aria) => /* @__PURE__ */ jsx("input", {
93
+ id,
94
+ type: "checkbox",
95
+ className,
96
+ checked: props.writeOnly ? false : props.value === true,
97
+ onChange: (e) => {
98
+ props.onChange(e.target.checked);
99
+ },
100
+ ...aria
101
+ })
102
+ });
103
+ }
104
+ function renderEnumInput(props) {
105
+ const id = inputId(props.path);
106
+ const className = buildClassNames("flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm", "focus:outline-none focus:ring-1 focus:ring-ring", "disabled:cursor-not-allowed disabled:opacity-50");
107
+ const enumValue = typeof props.value === "string" ? props.value : "";
108
+ if (props.readOnly) return /* @__PURE__ */ jsx("span", {
89
109
  id,
90
- type: "checkbox",
91
- className,
92
- checked: props.writeOnly ? false : props.value === true,
93
- onChange: (e) => {
94
- props.onChange(e.target.checked);
95
- }
110
+ className: "text-sm",
111
+ children: enumValue || "—"
112
+ });
113
+ return /* @__PURE__ */ jsx(FieldShell, {
114
+ props,
115
+ inputId: id,
116
+ children: (aria) => /* @__PURE__ */ jsxs("select", {
117
+ id,
118
+ className,
119
+ value: props.writeOnly ? "" : enumValue,
120
+ onChange: (e) => {
121
+ props.onChange(e.target.value);
122
+ },
123
+ ...aria,
124
+ children: [/* @__PURE__ */ jsxs("option", {
125
+ value: "",
126
+ children: ["Select", "…"]
127
+ }), props.tree.type === "enum" ? props.tree.enumValues.map((v) => {
128
+ const display = displayJsonValue(v);
129
+ return /* @__PURE__ */ jsx("option", {
130
+ value: display,
131
+ children: display
132
+ }, display);
133
+ }) : null]
134
+ })
96
135
  });
97
136
  }
98
137
  function renderObjectContainer(props) {
@@ -106,20 +145,15 @@ function renderObjectContainer(props) {
106
145
  children: props.meta.description
107
146
  }), sortFieldsByOrder(fields).map(([key, field]) => {
108
147
  const childValue = toRecord(obj)[key];
109
- const childId = inputId(`${props.path}.${key}`);
110
148
  const childOnChange = (v) => {
111
149
  const updated = {};
112
150
  for (const [k, val] of Object.entries(obj)) updated[k] = val;
113
151
  updated[key] = v;
114
152
  props.onChange(updated);
115
153
  };
116
- return /* @__PURE__ */ jsxs("div", {
154
+ return /* @__PURE__ */ jsx("div", {
117
155
  className: "space-y-1",
118
- children: [/* @__PURE__ */ jsx("label", {
119
- htmlFor: childId,
120
- className: "text-sm font-medium leading-none",
121
- children: field.meta.description ?? key
122
- }), toReactNode(props.renderChild(field, childValue, childOnChange, key))]
156
+ children: toReactNode(props.renderChild(field, childValue, childOnChange, key))
123
157
  }, key);
124
158
  })]
125
159
  });
@@ -141,57 +175,16 @@ function renderArrayContainer(props) {
141
175
  })
142
176
  });
143
177
  }
144
- function renderEnumInput(props) {
145
- const id = inputId(props.path);
146
- const className = buildClassNames("flex h-9 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm", "focus:outline-none focus:ring-1 focus:ring-ring", "disabled:cursor-not-allowed disabled:opacity-50");
147
- const enumValue = typeof props.value === "string" ? props.value : "";
148
- if (props.readOnly) return /* @__PURE__ */ jsx("span", {
149
- id,
150
- className: "text-sm",
151
- children: enumValue || "—"
152
- });
153
- return /* @__PURE__ */ jsxs("select", {
154
- id,
155
- className,
156
- value: props.writeOnly ? "" : enumValue,
157
- onChange: (e) => {
158
- props.onChange(e.target.value);
159
- },
160
- children: [/* @__PURE__ */ jsxs("option", {
161
- value: "",
162
- children: ["Select", "…"]
163
- }), props.tree.type === "enum" ? props.tree.enumValues.map((v) => {
164
- const display = displayJsonValue(v);
165
- return /* @__PURE__ */ jsx("option", {
166
- value: display,
167
- children: display
168
- }, display);
169
- }) : null]
170
- });
171
- }
172
- function buildResolver() {
173
- const resolver = {
174
- string: renderStringInput,
175
- number: renderNumberInput,
176
- boolean: renderBooleanInput,
177
- enum: renderEnumInput,
178
- object: renderObjectContainer,
179
- array: renderArrayContainer
180
- };
181
- if (headlessResolver.literal !== void 0) resolver.literal = headlessResolver.literal;
182
- if (headlessResolver.union !== void 0) resolver.union = headlessResolver.union;
183
- if (headlessResolver.record !== void 0) resolver.record = headlessResolver.record;
184
- if (headlessResolver.file !== void 0) resolver.file = headlessResolver.file;
185
- if (headlessResolver.unknown !== void 0) resolver.unknown = headlessResolver.unknown;
186
- return resolver;
187
- }
188
178
  /**
189
179
  * Component resolver mapping schema field types to shadcn/ui components.
190
180
  *
191
181
  * Pass to `SchemaProvider` to render every `<SchemaComponent>` /
192
182
  * `<SchemaView>` in the subtree with shadcn/ui inputs, selects, and
193
- * cards. Built on top of the headless resolver so any field types the
194
- * theme does not override fall back to plain HTML.
183
+ * cards. Returns only the keys this theme overrides the runtime
184
+ * `mergeResolvers` call inside `<SchemaComponent>` / `<SchemaView>`
185
+ * fills unset keys from `headlessResolver`, so variants like literal,
186
+ * union, discriminatedUnion, record, file, and unknown still render via
187
+ * the headless fallback.
195
188
  *
196
189
  * Requires `shadcn/ui` components installed in the consuming project.
197
190
  *
@@ -206,6 +199,13 @@ function buildResolver() {
206
199
  * </SchemaProvider>
207
200
  * ```
208
201
  */
209
- const shadcnResolver = buildResolver();
202
+ const shadcnResolver = {
203
+ string: renderStringInput,
204
+ number: renderNumberInput,
205
+ boolean: renderBooleanInput,
206
+ enum: renderEnumInput,
207
+ object: renderObjectContainer,
208
+ array: renderArrayContainer
209
+ };
210
210
  //#endregion
211
211
  export { shadcnResolver };
@@ -130,6 +130,13 @@ interface StringField extends FieldBase {
130
130
  interface NumberField extends FieldBase {
131
131
  type: "number";
132
132
  constraints: NumberConstraints;
133
+ /**
134
+ * True when the underlying schema declared `type: "integer"` rather
135
+ * than `type: "number"`. Renderers consult this to set HTML
136
+ * `inputmode="numeric"` and `step="1"` (for whole-number editing)
137
+ * instead of `inputmode="decimal"`.
138
+ */
139
+ isInteger: boolean;
133
140
  }
134
141
  interface BooleanField extends FieldBase {
135
142
  type: "boolean";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "schema-components",
3
- "version": "1.29.0",
3
+ "version": "2.0.1",
4
4
  "description": "React components that render UI from Zod schemas, JSON Schema, and OpenAPI documents",
5
5
  "type": "module",
6
6
  "exports": {
@@ -90,7 +90,11 @@
90
90
  "@vitest/coverage-v8": "4.1.5",
91
91
  "eslint": "10.3.0",
92
92
  "eslint-config-prettier": "10.1.8",
93
+ "eslint-plugin-import": "2.32.0",
94
+ "eslint-plugin-jsx-a11y": "6.10.2",
95
+ "eslint-plugin-no-only-tests": "3.4.0",
93
96
  "eslint-plugin-prettier": "5.5.5",
97
+ "eslint-plugin-tsdoc": "0.5.2",
94
98
  "happy-dom": "20.9.0",
95
99
  "prettier": "3.8.3",
96
100
  "react": "19.2.6",
@@ -1,223 +0,0 @@
1
- import { m as JsonObject, w as SchemaMeta } from "./types-C2Ay1FEh.mjs";
2
- import { i as DiagnosticsOptions } from "./diagnostics-ByEzkjrA.mjs";
3
-
4
- //#region src/core/adapter.d.ts
5
- /**
6
- * Permissive input alias accepted by {@link normaliseSchema}. Every
7
- * supported source (Zod 4 schema, plain JSON Schema, OpenAPI document)
8
- * is reachable through `Record<string, unknown>`, so consumers can
9
- * accept the union without committing to a specific shape at the API
10
- * boundary.
11
- *
12
- * @group Adapter
13
- */
14
- type SchemaInput = Record<string, unknown>;
15
- /**
16
- * Classification produced by {@link detectSchemaKind} when inspecting a
17
- * runtime schema input.
18
- *
19
- * @group Adapter
20
- */
21
- type SchemaKind = "zod4" | "zod3" | "jsonSchema" | "openapi" | "unsupported-schema-lib";
22
- /**
23
- * Classify a runtime schema input by structural markers — Zod 4, Zod 3,
24
- * OpenAPI document, plain JSON Schema, or an unsupported third-party
25
- * schema library.
26
- *
27
- * - `zod4` — has a `_zod` marker (further validation that `_zod.def` is a
28
- * non-null object happens inside `normaliseZod4`).
29
- * - `zod3` — has `_def` and no `_zod`. The `typeName` field is no longer
30
- * required: any `_def` without `_zod` is treated as a probable Zod 3
31
- * schema. Third-party libraries that expose `_def` without `_zod` are
32
- * nearly always Zod 3 forks; surfacing the migration message is the
33
- * correct response.
34
- * - `openapi` — has `openapi` or `swagger` at the root.
35
- * - `unsupported-schema-lib` — has `parse` and `safeParse` callables but
36
- * no `_zod` and no `_def` marker. This catches Standard Schema
37
- * implementations (valibot, arktype, etc.) that would otherwise flow
38
- * through as "malformed JSON Schema".
39
- * - `jsonSchema` — fallback for anything that does not match the above.
40
- *
41
- * @group Adapter
42
- */
43
- declare function detectSchemaKind(input: unknown): SchemaKind;
44
- /**
45
- * Wraps z.toJSONSchema() for a runtime-validated Zod schema.
46
- *
47
- * The _zod guard in normaliseZod4 has confirmed this is a valid Zod schema,
48
- * but TypeScript cannot represent "has _zod.def" as the $ZodType parameter
49
- * that z.toJSONSchema expects. This is the library boundary equivalent of
50
- * object → Record<string, unknown> — the type mismatch is genuinely unavoidable.
51
- *
52
- * # Options
53
- *
54
- * `z.toJSONSchema` is invoked with an explicit options object rather than
55
- * Zod's defaults so the conversion contract is pinned and stable:
56
- *
57
- * - `target: "draft-2020-12"` — matches the walker's draft target.
58
- * - `unrepresentable: "throw"` — keeps the unrepresentable-type rules in
59
- * the classifier table firing instead of silently emitting `{}`.
60
- * - `cycles: "ref"` — converts cyclic graphs into $ref pairs rather than
61
- * throwing. Cycles in user schemas surface through the walker's $ref
62
- * resolution rather than the adapter.
63
- * - `io` — selects which side of every transform / pipe / codec is
64
- * converted. Defaults to `"output"` (the OUTPUT side); pass `"input"`
65
- * to render the INPUT side instead. The input side is invisible to
66
- * the converted schema when `io: "output"` is in force, even though
67
- * `safeParse` on the same Zod schema consumes the input shape. For
68
- * transforms this divergence is fatal and the call throws via
69
- * `Transforms cannot be represented`; for `z.codec(...)` the call
70
- * succeeds but only the selected side is rendered. Consumers receive
71
- * a `zod-codec-output-only` diagnostic in the codec case so the
72
- * asymmetry is visible — see `screenPreConversion`.
73
- *
74
- * # Error classification
75
- *
76
- * Any exception thrown by z.toJSONSchema is classified into a
77
- * SchemaNormalisationError so the caller does not have to re-parse error
78
- * message strings. The classification covers:
79
- *
80
- * - Nested Zod 3 schemas inside a Zod 4 tree → zod3-unsupported.
81
- * Detected structurally (presence of `_def.typeName` markers anywhere
82
- * in the schema tree) so the check works across V8, JavaScriptCore,
83
- * and SpiderMonkey, none of which agree on the wording of
84
- * "Cannot read properties of undefined".
85
- * - Transforms → zod-transform-unsupported. This also catches `z.codec(…)`
86
- * because Zod implements codecs as a pipe + transform internally, so
87
- * they trip the same processor when round-tripping is forced. (Plain
88
- * `z.toJSONSchema(codec)` itself does NOT throw because Zod picks one
89
- * side of the codec; the static rejection in `typeInference.ts` is the
90
- * compile-time guard.)
91
- * - Dynamic catch values whose handler throws → zod-type-unrepresentable
92
- * with zodType "dynamic-catch".
93
- * - Unrepresentable types — bigint, date, map, set, symbol, function, custom,
94
- * undefined, void, NaN, and the literal-only forms `z.literal(undefined)`
95
- * ("undefined-literal") and `z.literal(<bigint>)` ("bigint-literal") →
96
- * zod-type-unrepresentable.
97
- * - The catch-all "Non-representable type encountered: <type>" fallback Zod
98
- * emits for any new schema kind without a registered processor →
99
- * zod-type-unrepresentable with zodType set to the offending def.type.
100
- * - Cycle detected (`cycles: "throw"`) → zod-cycle-detected.
101
- * - Duplicate schema id → zod-duplicate-id.
102
- * - "Unprocessed schema. This is a bug in Zod." → zod-conversion-bug.
103
- * - "Error converting schema to JSON." → zod-conversion-failed (explicit
104
- * classification rather than the generic fallback so the contract test
105
- * protects the prefix from drift).
106
- * - Anything else → zod-conversion-failed.
107
- *
108
- * The original error is preserved on each classified error via the `cause`
109
- * field so consumers can still inspect the Zod stack trace.
110
- */
111
- /**
112
- * Direction of the Zod transform / pipe / codec that
113
- * {@link normaliseSchema} should surface to the renderer.
114
- *
115
- * - `"output"` (default) — the server-facing side of every transform,
116
- * matching `z.toJSONSchema`'s default and the historic adapter
117
- * behaviour.
118
- * - `"input"` — the client-facing side; flips a `z.codec(...)` chain
119
- * so consumers can render its input shape.
120
- *
121
- * @group Adapter
122
- */
123
- type SchemaIoSide = "input" | "output";
124
- /**
125
- * True when `value` is a Zod schema implemented as a codec
126
- * (`z.codec(...)`). Detection looks for the `$ZodCodec` marker on the
127
- * schema's `_zod.traits` Set — the same structural check used by Zod
128
- * itself in `to-json-schema.ts`'s `isTransforming` helper.
129
- *
130
- * Promoted from a duplicated local helper in `react/SchemaComponent.tsx`
131
- * so the validation boundary inside `runValidation` can branch on
132
- * codec-vs-not-codec without re-implementing the trait check. The
133
- * shared helper anchors a single source of truth for codec detection:
134
- * any future change to Zod's trait naming flows through here, not
135
- * through two parallel copies.
136
- *
137
- * Returns `false` for non-objects, plain JSON Schema inputs, OpenAPI
138
- * documents, or Zod schemas of any other kind. This is structural
139
- * rather than nominal — a Zod 4 codec produced by any path that ends
140
- * up tagging `_zod.traits` with `$ZodCodec` is recognised, including
141
- * schemas wrapped by user-defined helpers.
142
- */
143
- declare function isCodecSchema(value: unknown): boolean;
144
- /**
145
- * Exposed for unit testing — lets the contract test enumerate every rule's
146
- * `prefix` value and assert mutual non-prefixing.
147
- */
148
- declare const __CLASSIFIER_RULES_FOR_TEST: readonly {
149
- readonly prefix: string;
150
- }[];
151
- /**
152
- * Result of {@link normaliseSchema}. Carries the canonical Draft 2020-12
153
- * JSON Schema the walker consumes, the optional original Zod schema
154
- * (used for validation), and the resolved root document so cross-document
155
- * `$ref`s can be dereferenced downstream.
156
- *
157
- * @group Adapter
158
- */
159
- interface NormalisedSchema {
160
- /** JSON Schema object — the authoritative schema for rendering. */
161
- jsonSchema: JsonObject;
162
- /** Original Zod schema, if input was Zod. Used for validation. */
163
- zodSchema?: unknown;
164
- /** Root-level metadata. */
165
- rootMeta: SchemaMeta | undefined;
166
- /** The root document for $ref resolution. */
167
- rootDocument: JsonObject;
168
- }
169
- /**
170
- * Options accepted by {@link normaliseSchema}.
171
- *
172
- * @group Adapter
173
- */
174
- interface NormaliseOptions {
175
- /** Diagnostics channel for surfacing silent fallbacks. */
176
- diagnostics?: DiagnosticsOptions;
177
- /**
178
- * Side of every transform / pipe / codec to render. Defaults to
179
- * `"output"`, matching `z.toJSONSchema`'s default and the
180
- * historic behaviour of the adapter. Passing `"input"` flips the
181
- * conversion so consumers rendering the input shape of a
182
- * `z.codec(...)` chain receive that side instead of the output
183
- * side. Only the Zod 4 branch consults this option — JSON Schema
184
- * and OpenAPI inputs are already a single canonical shape.
185
- */
186
- io?: SchemaIoSide;
187
- }
188
- /**
189
- * Normalise any supported schema input — Zod 4 schema, plain JSON
190
- * Schema (any draft), Swagger 2.0, OpenAPI 3.0 or 3.1 document — into
191
- * a canonical Draft 2020-12 {@link NormalisedSchema} the walker can
192
- * consume.
193
- *
194
- * Dispatches on {@link detectSchemaKind}, applies the appropriate
195
- * version normaliser, and returns the JSON Schema alongside the
196
- * original Zod schema (for validation) and the resolved root document
197
- * (for cross-document `$ref` resolution). Throws
198
- * `SchemaNormalisationError` for unsupported inputs (Zod 3, valibot,
199
- * arktype, codec or other unrepresentable Zod types).
200
- *
201
- * @group Adapter
202
- */
203
- declare function normaliseSchema(input: unknown, ref?: string, options?: NormaliseOptions): NormalisedSchema;
204
- /**
205
- * Surface root-level metadata from the JSON Schema into the `rootMeta`
206
- * shape consumed by the walker. Pulls `readOnly`, `writeOnly`,
207
- * `description`, `title`, `deprecated`, `examples`, and `default`
208
- * directly from the schema root.
209
- *
210
- * `examples` is forwarded only when present as an array (per JSON Schema
211
- * Draft 2020-12 — Draft 04's `example` singular is normalised upstream).
212
- * `default` is forwarded for any value the schema declares (any JSON
213
- * value, including `null` and `false`); the presence check uses `in`
214
- * so a literal `false` or `null` default is preserved.
215
- *
216
- * `examples` and `default` ride on the `[key: string]: unknown` index
217
- * signature of {@link SchemaMeta}. They are not declared as named fields
218
- * on `SchemaMeta` because that type lives in `types.ts` and is shared
219
- * with the walker; the index signature is the agreed extension point.
220
- */
221
- declare function extractRootMetaFromJson(jsonSchema: JsonObject): SchemaMeta | undefined;
222
- //#endregion
223
- export { SchemaKind as a, extractRootMetaFromJson as c, SchemaIoSide as i, isCodecSchema as l, NormalisedSchema as n, __CLASSIFIER_RULES_FOR_TEST as o, SchemaInput as r, detectSchemaKind as s, NormaliseOptions as t, normaliseSchema as u };