schema-components 1.28.2 → 2.0.0

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 (105) hide show
  1. package/README.md +38 -16
  2. package/dist/core/adapter.d.mts +213 -3
  3. package/dist/core/adapter.mjs +21 -2
  4. package/dist/core/constraintHint.d.mts +15 -0
  5. package/dist/core/constraintHint.mjs +24 -0
  6. package/dist/core/constraints.d.mts +34 -2
  7. package/dist/core/constraints.mjs +33 -1
  8. package/dist/core/cssClasses.d.mts +1 -0
  9. package/dist/core/diagnostics.d.mts +1 -1
  10. package/dist/core/errors.d.mts +1 -1
  11. package/dist/core/errors.mjs +22 -12
  12. package/dist/core/fieldOrder.d.mts +1 -1
  13. package/dist/core/formats.d.mts +7 -1
  14. package/dist/core/formats.mjs +6 -0
  15. package/dist/core/idPath.d.mts +35 -5
  16. package/dist/core/idPath.mjs +79 -7
  17. package/dist/core/inferValue.d.mts +2 -0
  18. package/dist/core/inferValue.mjs +1 -0
  19. package/dist/core/limits.d.mts +1 -1
  20. package/dist/core/limits.mjs +6 -0
  21. package/dist/core/merge.d.mts +22 -1
  22. package/dist/core/merge.mjs +66 -3
  23. package/dist/core/normalise.d.mts +17 -2
  24. package/dist/core/normalise.mjs +1 -1
  25. package/dist/core/openapi30.mjs +1 -1
  26. package/dist/core/openapiConstants.d.mts +1 -0
  27. package/dist/core/ref.d.mts +1 -1
  28. package/dist/core/refChain.d.mts +3 -4
  29. package/dist/core/refChain.mjs +2 -3
  30. package/dist/core/renderer.d.mts +199 -2
  31. package/dist/core/renderer.mjs +5 -0
  32. package/dist/core/swagger2.d.mts +1 -1
  33. package/dist/core/swagger2.mjs +1 -1
  34. package/dist/core/typeInference.d.mts +3 -3
  35. package/dist/core/types.d.mts +1 -1
  36. package/dist/core/types.mjs +17 -0
  37. package/dist/core/unionMatch.d.mts +1 -1
  38. package/dist/core/uri.d.mts +12 -4
  39. package/dist/core/uri.mjs +30 -4
  40. package/dist/core/version.d.mts +1 -1
  41. package/dist/core/walkBuilders.d.mts +63 -6
  42. package/dist/core/walkBuilders.mjs +33 -1
  43. package/dist/core/walker.d.mts +14 -1
  44. package/dist/core/walker.mjs +18 -0
  45. package/dist/{diagnostics-Cbwak-ZX.d.mts → diagnostics-BTrm3O6J.d.mts} +9 -1
  46. package/dist/{errors-DQSIK4n1.d.mts → errors-Dki7tji4.d.mts} +23 -13
  47. package/dist/html/a11y.d.mts +3 -7
  48. package/dist/html/a11y.mjs +1 -16
  49. package/dist/html/html.d.mts +11 -0
  50. package/dist/html/html.mjs +11 -0
  51. package/dist/html/renderToHtml.d.mts +45 -12
  52. package/dist/html/renderToHtml.mjs +20 -4
  53. package/dist/html/renderToHtmlStream.d.mts +63 -18
  54. package/dist/html/renderToHtmlStream.mjs +34 -8
  55. package/dist/html/renderers.d.mts +6 -31
  56. package/dist/html/renderers.mjs +45 -91
  57. package/dist/html/streamRenderers.d.mts +31 -3
  58. package/dist/html/streamRenderers.mjs +41 -8
  59. package/dist/inferValue-PPXWJpbN.d.mts +77 -0
  60. package/dist/{limits-DJhgx5Ay.d.mts → limits-x4OiyJxh.d.mts} +6 -0
  61. package/dist/{normalise-Db1xaxgx.mjs → normalise-DB-Xtjmn.mjs} +43 -2
  62. package/dist/openapi/ApiCallbacks.d.mts +13 -1
  63. package/dist/openapi/ApiCallbacks.mjs +7 -0
  64. package/dist/openapi/ApiLinks.d.mts +13 -1
  65. package/dist/openapi/ApiLinks.mjs +7 -0
  66. package/dist/openapi/ApiResponseHeaders.d.mts +13 -1
  67. package/dist/openapi/ApiResponseHeaders.mjs +7 -0
  68. package/dist/openapi/ApiSecurity.d.mts +14 -1
  69. package/dist/openapi/ApiSecurity.mjs +29 -8
  70. package/dist/openapi/bundle.d.mts +31 -0
  71. package/dist/openapi/components.d.mts +135 -20
  72. package/dist/openapi/components.mjs +90 -15
  73. package/dist/openapi/parser.d.mts +140 -13
  74. package/dist/openapi/parser.mjs +84 -12
  75. package/dist/openapi/resolve.d.mts +42 -47
  76. package/dist/openapi/resolve.mjs +62 -56
  77. package/dist/react/SchemaComponent.d.mts +90 -88
  78. package/dist/react/SchemaComponent.mjs +74 -2
  79. package/dist/react/SchemaErrorBoundary.d.mts +18 -1
  80. package/dist/react/SchemaErrorBoundary.mjs +13 -1
  81. package/dist/react/SchemaView.d.mts +39 -11
  82. package/dist/react/SchemaView.mjs +23 -6
  83. package/dist/react/a11y.d.mts +74 -7
  84. package/dist/react/a11y.mjs +67 -6
  85. package/dist/react/fieldPath.d.mts +16 -1
  86. package/dist/react/fieldPath.mjs +25 -1
  87. package/dist/react/fieldShell.d.mts +49 -0
  88. package/dist/react/fieldShell.mjs +37 -0
  89. package/dist/react/headless.d.mts +1 -1
  90. package/dist/react/headlessRenderers.d.mts +13 -2
  91. package/dist/react/headlessRenderers.mjs +134 -54
  92. package/dist/{ref-TdeMfaV_.d.mts → ref-DdsbekXX.d.mts} +33 -1
  93. package/dist/themes/mantine.d.mts +54 -12
  94. package/dist/themes/mantine.mjs +195 -140
  95. package/dist/themes/mui.d.mts +64 -11
  96. package/dist/themes/mui.mjs +277 -213
  97. package/dist/themes/radix.d.mts +67 -15
  98. package/dist/themes/radix.mjs +235 -170
  99. package/dist/themes/shadcn.d.mts +25 -1
  100. package/dist/themes/shadcn.mjs +112 -91
  101. package/dist/{types-BTB73MB8.d.mts → types-BrYbjC7_.d.mts} +30 -0
  102. package/dist/{version-ZzL5R6cS.d.mts → version-DL8U5RuA.d.mts} +6 -0
  103. package/package.json +8 -1
  104. package/dist/adapter-DqlAnZ_w.d.mts +0 -172
  105. package/dist/renderer-Ul9taFYp.d.mts +0 -169
@@ -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,50 +175,37 @@ 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
- const shadcnResolver = buildResolver();
178
+ /**
179
+ * Component resolver mapping schema field types to shadcn/ui components.
180
+ *
181
+ * Pass to `SchemaProvider` to render every `<SchemaComponent>` /
182
+ * `<SchemaView>` in the subtree with shadcn/ui inputs, selects, and
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.
188
+ *
189
+ * Requires `shadcn/ui` components installed in the consuming project.
190
+ *
191
+ * @group Themes
192
+ * @example
193
+ * ```tsx
194
+ * import { SchemaProvider } from "schema-components/react/SchemaComponent";
195
+ * import { shadcnResolver } from "schema-components/themes/shadcn";
196
+ *
197
+ * <SchemaProvider resolver={shadcnResolver}>
198
+ * <SchemaComponent schema={userSchema} value={user} onChange={setUser} />
199
+ * </SchemaProvider>
200
+ * ```
201
+ */
202
+ const shadcnResolver = {
203
+ string: renderStringInput,
204
+ number: renderNumberInput,
205
+ boolean: renderBooleanInput,
206
+ enum: renderEnumInput,
207
+ object: renderObjectContainer,
208
+ array: renderArrayContainer
209
+ };
189
210
  //#endregion
190
211
  export { shadcnResolver };
@@ -26,6 +26,12 @@ interface SchemaMeta {
26
26
  /** Arbitrary UI hints passed through to theme adapters. */
27
27
  [key: string]: unknown;
28
28
  }
29
+ /**
30
+ * Resolved editability state for a walked field. `presentation` renders
31
+ * as a read-only value, `input` as a write-only input (e.g. password
32
+ * fields), `editable` as a full input that round-trips through
33
+ * `onChange`. Produced by {@link resolveEditability}.
34
+ */
29
35
  type Editability = "presentation" | "input" | "editable";
30
36
  /**
31
37
  * Resolved editability state for a single field.
@@ -124,6 +130,13 @@ interface StringField extends FieldBase {
124
130
  interface NumberField extends FieldBase {
125
131
  type: "number";
126
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;
127
140
  }
128
141
  interface BooleanField extends FieldBase {
129
142
  type: "boolean";
@@ -285,22 +298,39 @@ interface UnknownField extends FieldBase {
285
298
  * Use `field.type` to narrow to a specific variant.
286
299
  */
287
300
  type WalkedField = StringField | NumberField | BooleanField | NullField | EnumField | LiteralField | ObjectField | ArrayField | TupleField | RecordField | UnionField | DiscriminatedUnionField | ConditionalField | NegationField | NeverField | FileField | UnknownField;
301
+ /** Type guard: narrows a `WalkedField` to its `string` variant. */
288
302
  declare function isStringField(field: WalkedField): field is StringField;
303
+ /** Type guard: narrows a `WalkedField` to its `number` variant. */
289
304
  declare function isNumberField(field: WalkedField): field is NumberField;
305
+ /** Type guard: narrows a `WalkedField` to its `boolean` variant. */
290
306
  declare function isBooleanField(field: WalkedField): field is BooleanField;
307
+ /** Type guard: narrows a `WalkedField` to its `null` variant. */
291
308
  declare function isNullField(field: WalkedField): field is NullField;
309
+ /** Type guard: narrows a `WalkedField` to its `enum` variant. */
292
310
  declare function isEnumField(field: WalkedField): field is EnumField;
311
+ /** Type guard: narrows a `WalkedField` to its `literal` variant. */
293
312
  declare function isLiteralField(field: WalkedField): field is LiteralField;
313
+ /** Type guard: narrows a `WalkedField` to its `object` variant. */
294
314
  declare function isObjectField(field: WalkedField): field is ObjectField;
315
+ /** Type guard: narrows a `WalkedField` to its `array` variant. */
295
316
  declare function isArrayField(field: WalkedField): field is ArrayField;
317
+ /** Type guard: narrows a `WalkedField` to its `tuple` variant. */
296
318
  declare function isTupleField(field: WalkedField): field is TupleField;
319
+ /** Type guard: narrows a `WalkedField` to its `record` variant. */
297
320
  declare function isRecordField(field: WalkedField): field is RecordField;
321
+ /** Type guard: narrows a `WalkedField` to its plain `union` variant. */
298
322
  declare function isUnionField(field: WalkedField): field is UnionField;
323
+ /** Type guard: narrows a `WalkedField` to its `discriminatedUnion` variant. */
299
324
  declare function isDiscriminatedUnionField(field: WalkedField): field is DiscriminatedUnionField;
325
+ /** Type guard: narrows a `WalkedField` to its `conditional` (if/then/else) variant. */
300
326
  declare function isConditionalField(field: WalkedField): field is ConditionalField;
327
+ /** Type guard: narrows a `WalkedField` to its `negation` (`not`) variant. */
301
328
  declare function isNegationField(field: WalkedField): field is NegationField;
329
+ /** Type guard: narrows a `WalkedField` to its `file` variant. */
302
330
  declare function isFileField(field: WalkedField): field is FileField;
331
+ /** Type guard: narrows a `WalkedField` to its `never` variant (false schema). */
303
332
  declare function isNeverField(field: WalkedField): field is NeverField;
333
+ /** Type guard: narrows a `WalkedField` to its `unknown` variant (permissive). */
304
334
  declare function isUnknownField(field: WalkedField): field is UnknownField;
305
335
  //#endregion
306
336
  export { UnknownField as A, isNeverField as B, RecordField as C, StringField as D, StringConstraints as E, isDiscriminatedUnionField as F, isStringField as G, isNumberField as H, isEnumField as I, isUnknownField as J, isTupleField as K, isFileField as L, isArrayField as M, isBooleanField as N, TupleField as O, isConditionalField as P, isLiteralField as R, ObjectField as S, SchemaType as T, isObjectField as U, isNullField as V, isRecordField as W, resolveEditability as Y, NeverField as _, DiscriminatedUnionField as a, NumberField as b, FieldBase as c, FieldOverrides as d, FileConstraints as f, NegationField as g, LiteralField as h, ConditionalField as i, WalkedField as j, UnionField as k, FieldConstraints as l, JsonObject as m, ArrayField as n, Editability as o, FileField as p, isUnionField as q, BooleanField as r, EnumField as s, ArrayConstraints as t, FieldOverride as u, NullField as v, SchemaMeta as w, ObjectConstraints as x, NumberConstraints as y, isNegationField as z };
@@ -49,6 +49,12 @@ declare function inferJsonSchemaDraft(schema: Record<string, unknown>): JsonSche
49
49
  * triggered the inference, for diagnostic emission.
50
50
  */
51
51
  declare function inferJsonSchemaDraftWithReason(schema: Record<string, unknown>): InferredDraft;
52
+ /**
53
+ * Parsed OpenAPI version triple (e.g. `{ major: 3, minor: 1, patch: 0 }`).
54
+ * Produced by `detectOpenApiVersion` so downstream helpers can switch on
55
+ * the canonical numeric form rather than re-parsing the raw `openapi` /
56
+ * `swagger` string.
57
+ */
52
58
  interface OpenApiVersionInfo {
53
59
  major: number;
54
60
  minor: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "schema-components",
3
- "version": "1.28.2",
3
+ "version": "2.0.0",
4
4
  "description": "React components that render UI from Zod schemas, JSON Schema, and OpenAPI documents",
5
5
  "type": "module",
6
6
  "exports": {
@@ -41,6 +41,7 @@
41
41
  "_test:coverage": "vitest run --project=unit --coverage",
42
42
  "_build": "tsdown && cp src/html/styles.css dist/html/styles.css",
43
43
  "_typedoc": "typedoc",
44
+ "_api-urls": "node scripts/build-api-urls.mjs",
44
45
  "_readme": "node scripts/build-readme-inventory.mjs",
45
46
  "typecheck": "turbo run _typecheck",
46
47
  "lint": "turbo run _lint",
@@ -51,6 +52,7 @@
51
52
  "validate": "turbo run _validate",
52
53
  "build": "turbo run _build",
53
54
  "typedoc": "turbo run _typedoc",
55
+ "api-urls": "turbo run _api-urls",
54
56
  "readme": "turbo run _readme"
55
57
  },
56
58
  "keywords": [
@@ -88,6 +90,9 @@
88
90
  "@vitest/coverage-v8": "4.1.5",
89
91
  "eslint": "10.3.0",
90
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",
91
96
  "eslint-plugin-prettier": "5.5.5",
92
97
  "happy-dom": "20.9.0",
93
98
  "prettier": "3.8.3",
@@ -96,6 +101,8 @@
96
101
  "tsdown": "0.22.0",
97
102
  "tslib": "2.8.1",
98
103
  "typedoc": "0.28.19",
104
+ "typedoc-material-theme": "1.4.1",
105
+ "typedoc-plugin-mermaid": "1.12.0",
99
106
  "typedoc-plugin-missing-exports": "4.1.3",
100
107
  "typescript": "6.0.3",
101
108
  "typescript-eslint": "8.59.2",
@@ -1,172 +0,0 @@
1
- import { m as JsonObject, w as SchemaMeta } from "./types-BTB73MB8.mjs";
2
- import { i as DiagnosticsOptions } from "./diagnostics-Cbwak-ZX.mjs";
3
-
4
- //#region src/core/adapter.d.ts
5
- type SchemaInput = Record<string, unknown>;
6
- type SchemaKind = "zod4" | "zod3" | "jsonSchema" | "openapi" | "unsupported-schema-lib";
7
- /**
8
- * Classify the input schema by its structural markers.
9
- *
10
- * - `zod4` — has a `_zod` marker (further validation that `_zod.def` is a
11
- * non-null object happens inside `normaliseZod4`).
12
- * - `zod3` — has `_def` and no `_zod`. The `typeName` field is no longer
13
- * required: any `_def` without `_zod` is treated as a probable Zod 3
14
- * schema. Third-party libraries that expose `_def` without `_zod` are
15
- * nearly always Zod 3 forks; surfacing the migration message is the
16
- * correct response.
17
- * - `openapi` — has `openapi` or `swagger` at the root.
18
- * - `unsupported-schema-lib` — has `parse` and `safeParse` callables but
19
- * no `_zod` and no `_def` marker. This catches Standard Schema
20
- * implementations (valibot, arktype, etc.) that would otherwise flow
21
- * through as "malformed JSON Schema".
22
- * - `jsonSchema` — fallback for anything that does not match the above.
23
- */
24
- declare function detectSchemaKind(input: unknown): SchemaKind;
25
- /**
26
- * Wraps z.toJSONSchema() for a runtime-validated Zod schema.
27
- *
28
- * The _zod guard in normaliseZod4 has confirmed this is a valid Zod schema,
29
- * but TypeScript cannot represent "has _zod.def" as the $ZodType parameter
30
- * that z.toJSONSchema expects. This is the library boundary equivalent of
31
- * object → Record<string, unknown> — the type mismatch is genuinely unavoidable.
32
- *
33
- * # Options
34
- *
35
- * `z.toJSONSchema` is invoked with an explicit options object rather than
36
- * Zod's defaults so the conversion contract is pinned and stable:
37
- *
38
- * - `target: "draft-2020-12"` — matches the walker's draft target.
39
- * - `unrepresentable: "throw"` — keeps the unrepresentable-type rules in
40
- * the classifier table firing instead of silently emitting `{}`.
41
- * - `cycles: "ref"` — converts cyclic graphs into $ref pairs rather than
42
- * throwing. Cycles in user schemas surface through the walker's $ref
43
- * resolution rather than the adapter.
44
- * - `io` — selects which side of every transform / pipe / codec is
45
- * converted. Defaults to `"output"` (the OUTPUT side); pass `"input"`
46
- * to render the INPUT side instead. The input side is invisible to
47
- * the converted schema when `io: "output"` is in force, even though
48
- * `safeParse` on the same Zod schema consumes the input shape. For
49
- * transforms this divergence is fatal and the call throws via
50
- * `Transforms cannot be represented`; for `z.codec(...)` the call
51
- * succeeds but only the selected side is rendered. Consumers receive
52
- * a `zod-codec-output-only` diagnostic in the codec case so the
53
- * asymmetry is visible — see `screenPreConversion`.
54
- *
55
- * # Error classification
56
- *
57
- * Any exception thrown by z.toJSONSchema is classified into a
58
- * SchemaNormalisationError so the caller does not have to re-parse error
59
- * message strings. The classification covers:
60
- *
61
- * - Nested Zod 3 schemas inside a Zod 4 tree → zod3-unsupported.
62
- * Detected structurally (presence of `_def.typeName` markers anywhere
63
- * in the schema tree) so the check works across V8, JavaScriptCore,
64
- * and SpiderMonkey, none of which agree on the wording of
65
- * "Cannot read properties of undefined".
66
- * - Transforms → zod-transform-unsupported. This also catches `z.codec(…)`
67
- * because Zod implements codecs as a pipe + transform internally, so
68
- * they trip the same processor when round-tripping is forced. (Plain
69
- * `z.toJSONSchema(codec)` itself does NOT throw because Zod picks one
70
- * side of the codec; the static rejection in `typeInference.ts` is the
71
- * compile-time guard.)
72
- * - Dynamic catch values whose handler throws → zod-type-unrepresentable
73
- * with zodType "dynamic-catch".
74
- * - Unrepresentable types — bigint, date, map, set, symbol, function, custom,
75
- * undefined, void, NaN, and the literal-only forms `z.literal(undefined)`
76
- * ("undefined-literal") and `z.literal(<bigint>)` ("bigint-literal") →
77
- * zod-type-unrepresentable.
78
- * - The catch-all "Non-representable type encountered: <type>" fallback Zod
79
- * emits for any new schema kind without a registered processor →
80
- * zod-type-unrepresentable with zodType set to the offending def.type.
81
- * - Cycle detected (`cycles: "throw"`) → zod-cycle-detected.
82
- * - Duplicate schema id → zod-duplicate-id.
83
- * - "Unprocessed schema. This is a bug in Zod." → zod-conversion-bug.
84
- * - "Error converting schema to JSON." → zod-conversion-failed (explicit
85
- * classification rather than the generic fallback so the contract test
86
- * protects the prefix from drift).
87
- * - Anything else → zod-conversion-failed.
88
- *
89
- * The original error is preserved on each classified error via the `cause`
90
- * field so consumers can still inspect the Zod stack trace.
91
- */
92
- /**
93
- * IO side passed to the internal `callToJsonSchema` helper. The Zod runtime accepts
94
- * `"input" | "output"` for the corresponding `io` option on
95
- * `z.toJSONSchema`. Defaults to `"output"` everywhere in the adapter
96
- * pipeline; the parameter exists so a future renderer or component
97
- * (currently SchemaComponent — see TODO below) can request the input
98
- * side without forking the helper.
99
- */
100
- type SchemaIoSide = "input" | "output";
101
- /**
102
- * True when `value` is a Zod schema implemented as a codec
103
- * (`z.codec(...)`). Detection looks for the `$ZodCodec` marker on the
104
- * schema's `_zod.traits` Set — the same structural check used by Zod
105
- * itself in `to-json-schema.ts`'s `isTransforming` helper.
106
- *
107
- * Promoted from a duplicated local helper in `react/SchemaComponent.tsx`
108
- * so the validation boundary inside `runValidation` can branch on
109
- * codec-vs-not-codec without re-implementing the trait check. The
110
- * shared helper anchors a single source of truth for codec detection:
111
- * any future change to Zod's trait naming flows through here, not
112
- * through two parallel copies.
113
- *
114
- * Returns `false` for non-objects, plain JSON Schema inputs, OpenAPI
115
- * documents, or Zod schemas of any other kind. This is structural
116
- * rather than nominal — a Zod 4 codec produced by any path that ends
117
- * up tagging `_zod.traits` with `$ZodCodec` is recognised, including
118
- * schemas wrapped by user-defined helpers.
119
- */
120
- declare function isCodecSchema(value: unknown): boolean;
121
- /**
122
- * Exposed for unit testing — lets the contract test enumerate every rule's
123
- * `prefix` value and assert mutual non-prefixing.
124
- */
125
- declare const __CLASSIFIER_RULES_FOR_TEST: readonly {
126
- readonly prefix: string;
127
- }[];
128
- interface NormalisedSchema {
129
- /** JSON Schema object — the authoritative schema for rendering. */
130
- jsonSchema: JsonObject;
131
- /** Original Zod schema, if input was Zod. Used for validation. */
132
- zodSchema?: unknown;
133
- /** Root-level metadata. */
134
- rootMeta: SchemaMeta | undefined;
135
- /** The root document for $ref resolution. */
136
- rootDocument: JsonObject;
137
- }
138
- interface NormaliseOptions {
139
- /** Diagnostics channel for surfacing silent fallbacks. */
140
- diagnostics?: DiagnosticsOptions;
141
- /**
142
- * Side of every transform / pipe / codec to render. Defaults to
143
- * `"output"`, matching `z.toJSONSchema`'s default and the
144
- * historic behaviour of the adapter. Passing `"input"` flips the
145
- * conversion so consumers rendering the input shape of a
146
- * `z.codec(...)` chain receive that side instead of the output
147
- * side. Only the Zod 4 branch consults this option — JSON Schema
148
- * and OpenAPI inputs are already a single canonical shape.
149
- */
150
- io?: SchemaIoSide;
151
- }
152
- declare function normaliseSchema(input: unknown, ref?: string, options?: NormaliseOptions): NormalisedSchema;
153
- /**
154
- * Surface root-level metadata from the JSON Schema into the `rootMeta`
155
- * shape consumed by the walker. Pulls `readOnly`, `writeOnly`,
156
- * `description`, `title`, `deprecated`, `examples`, and `default`
157
- * directly from the schema root.
158
- *
159
- * `examples` is forwarded only when present as an array (per JSON Schema
160
- * Draft 2020-12 — Draft 04's `example` singular is normalised upstream).
161
- * `default` is forwarded for any value the schema declares (any JSON
162
- * value, including `null` and `false`); the presence check uses `in`
163
- * so a literal `false` or `null` default is preserved.
164
- *
165
- * `examples` and `default` ride on the `[key: string]: unknown` index
166
- * signature of {@link SchemaMeta}. They are not declared as named fields
167
- * on `SchemaMeta` because that type lives in `types.ts` and is shared
168
- * with the walker; the index signature is the agreed extension point.
169
- */
170
- declare function extractRootMetaFromJson(jsonSchema: JsonObject): SchemaMeta | undefined;
171
- //#endregion
172
- 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 };