schema-components 1.12.10 → 1.13.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 (63) hide show
  1. package/README.md +31 -0
  2. package/dist/core/adapter.d.mts +1 -1
  3. package/dist/core/adapter.mjs +37 -8
  4. package/dist/core/constraints.d.mts +16 -0
  5. package/dist/core/constraints.mjs +138 -0
  6. package/dist/core/merge.d.mts +32 -0
  7. package/dist/core/merge.mjs +96 -0
  8. package/dist/core/normalise.d.mts +40 -0
  9. package/dist/core/normalise.mjs +171 -0
  10. package/dist/core/openapi30.d.mts +38 -0
  11. package/dist/core/openapi30.mjs +223 -0
  12. package/dist/core/ref.d.mts +25 -0
  13. package/dist/core/ref.mjs +86 -0
  14. package/dist/core/renderer.d.mts +2 -2
  15. package/dist/core/renderer.mjs +8 -0
  16. package/dist/core/swagger2.d.mts +10 -0
  17. package/dist/core/swagger2.mjs +294 -0
  18. package/dist/core/typeInference.d.mts +2 -0
  19. package/dist/core/typeInference.mjs +1 -0
  20. package/dist/core/types.d.mts +2 -3
  21. package/dist/core/types.mjs +55 -2
  22. package/dist/core/version.d.mts +2 -0
  23. package/dist/core/version.mjs +79 -0
  24. package/dist/core/walkBuilders.d.mts +52 -0
  25. package/dist/core/walkBuilders.mjs +152 -0
  26. package/dist/core/walker.d.mts +3 -10
  27. package/dist/core/walker.mjs +143 -231
  28. package/dist/html/a11y.d.mts +5 -4
  29. package/dist/html/renderToHtml.d.mts +3 -3
  30. package/dist/html/renderToHtml.mjs +23 -379
  31. package/dist/html/renderToHtmlStream.d.mts +29 -47
  32. package/dist/html/renderToHtmlStream.mjs +33 -305
  33. package/dist/html/renderers.d.mts +14 -0
  34. package/dist/html/renderers.mjs +406 -0
  35. package/dist/html/streamRenderers.d.mts +13 -0
  36. package/dist/html/streamRenderers.mjs +243 -0
  37. package/dist/openapi/components.d.mts +2 -1
  38. package/dist/openapi/parser.d.mts +59 -2
  39. package/dist/openapi/parser.mjs +189 -8
  40. package/dist/react/SchemaComponent.d.mts +4 -2
  41. package/dist/react/SchemaComponent.mjs +39 -85
  42. package/dist/react/SchemaView.d.mts +2 -1
  43. package/dist/react/SchemaView.mjs +21 -9
  44. package/dist/react/fieldPath.d.mts +20 -0
  45. package/dist/react/fieldPath.mjs +81 -0
  46. package/dist/react/headless.d.mts +2 -4
  47. package/dist/react/headless.mjs +3 -492
  48. package/dist/react/headlessRenderers.d.mts +23 -0
  49. package/dist/react/headlessRenderers.mjs +507 -0
  50. package/dist/renderer-DseHeliw.d.mts +160 -0
  51. package/dist/themes/mantine.d.mts +1 -1
  52. package/dist/themes/mantine.mjs +2 -1
  53. package/dist/themes/mui.d.mts +1 -1
  54. package/dist/themes/mui.mjs +2 -1
  55. package/dist/themes/radix.d.mts +1 -1
  56. package/dist/themes/radix.mjs +2 -1
  57. package/dist/themes/shadcn.d.mts +1 -1
  58. package/dist/themes/shadcn.mjs +10 -6
  59. package/dist/typeInference-CRPqVwKu.d.mts +299 -0
  60. package/dist/types-ag2jYLqQ.d.mts +261 -0
  61. package/dist/version-CLchheaH.d.mts +40 -0
  62. package/package.json +1 -1
  63. package/dist/types-BJzEgJdX.d.mts +0 -335
@@ -1,4 +1,4 @@
1
- import { l as JsonObject } from "../types-BJzEgJdX.mjs";
1
+ import { m as JsonObject } from "../types-ag2jYLqQ.mjs";
2
2
 
3
3
  //#region src/openapi/parser.d.ts
4
4
  interface OpenApiDocument {
@@ -28,6 +28,7 @@ interface ResponseInfo {
28
28
  description: string | undefined;
29
29
  contentTypes: string[];
30
30
  schema: JsonObject | undefined;
31
+ headers: Map<string, HeaderInfo>;
31
32
  }
32
33
  interface RequestBodyInfo {
33
34
  required: boolean;
@@ -35,11 +36,67 @@ interface RequestBodyInfo {
35
36
  contentTypes: string[];
36
37
  schema: JsonObject | undefined;
37
38
  }
39
+ interface SecurityRequirement {
40
+ name: string;
41
+ scopes: string[];
42
+ }
43
+ interface SecurityScheme {
44
+ type: string;
45
+ description: string | undefined;
46
+ name: string | undefined;
47
+ location: string | undefined;
48
+ scheme: string | undefined;
49
+ bearerFormat: string | undefined;
50
+ flows: JsonObject | undefined;
51
+ openIdConnectUrl: string | undefined;
52
+ }
53
+ interface HeaderInfo {
54
+ name: string;
55
+ description: string | undefined;
56
+ required: boolean;
57
+ deprecated: boolean;
58
+ schema: JsonObject | undefined;
59
+ }
60
+ interface WebhookInfo {
61
+ name: string;
62
+ operations: OperationInfo[];
63
+ }
64
+ interface ExternalDocs {
65
+ url: string;
66
+ description: string | undefined;
67
+ }
68
+ interface XmlInfo {
69
+ name: string | undefined;
70
+ namespace: string | undefined;
71
+ prefix: string | undefined;
72
+ attribute: boolean;
73
+ wrapped: boolean;
74
+ }
75
+ interface CallbackInfo {
76
+ name: string;
77
+ operations: OperationInfo[];
78
+ }
79
+ interface LinkInfo {
80
+ name: string;
81
+ operationId: string | undefined;
82
+ operationRef: string | undefined;
83
+ description: string | undefined;
84
+ parameters: Map<string, string>;
85
+ requestBody: string | undefined;
86
+ }
38
87
  declare function parseOpenApiDocument(doc: JsonObject): OpenApiDocument;
39
88
  declare function getSchema(parsed: OpenApiDocument, ref: string): JsonObject | undefined;
40
89
  declare function listOperations(parsed: OpenApiDocument): OperationInfo[];
41
90
  declare function getParameters(parsed: OpenApiDocument, path: string, method: string): ParameterInfo[];
42
91
  declare function getRequestBody(parsed: OpenApiDocument, path: string, method: string): RequestBodyInfo | undefined;
43
92
  declare function getResponses(parsed: OpenApiDocument, path: string, method: string): ResponseInfo[];
93
+ declare function getSecurityRequirements(parsed: OpenApiDocument, path: string, method: string): SecurityRequirement[];
94
+ declare function getSecuritySchemes(parsed: OpenApiDocument): Map<string, SecurityScheme>;
95
+ declare function getResponseHeaders(response: JsonObject): Map<string, HeaderInfo>;
96
+ declare function listWebhooks(parsed: OpenApiDocument): WebhookInfo[];
97
+ declare function getExternalDocs(obj: JsonObject): ExternalDocs | undefined;
98
+ declare function getXmlInfo(schema: JsonObject): XmlInfo | undefined;
99
+ declare function listCallbacks(parsed: OpenApiDocument, path: string, method: string): CallbackInfo[];
100
+ declare function getLinks(parsed: OpenApiDocument, path: string, method: string, statusCode: string): LinkInfo[];
44
101
  //#endregion
45
- export { OpenApiDocument, OperationInfo, ParameterInfo, ParameterLocation, RequestBodyInfo, ResponseInfo, getParameters, getRequestBody, getResponses, getSchema, listOperations, parseOpenApiDocument };
102
+ export { CallbackInfo, ExternalDocs, HeaderInfo, LinkInfo, OpenApiDocument, OperationInfo, ParameterInfo, ParameterLocation, RequestBodyInfo, ResponseInfo, SecurityRequirement, SecurityScheme, WebhookInfo, XmlInfo, getExternalDocs, getLinks, getParameters, getRequestBody, getResponseHeaders, getResponses, getSchema, getSecurityRequirements, getSecuritySchemes, getXmlInfo, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
@@ -35,12 +35,29 @@ const METHODS = [
35
35
  "patch",
36
36
  "delete"
37
37
  ];
38
+ /**
39
+ * Resolve a path item, following a `$ref` to `components/pathItems/<Name>`
40
+ * (OpenAPI 3.1) if present. Returns `undefined` when the value is not a
41
+ * path item, the ref is malformed, or the target does not resolve.
42
+ */
43
+ function resolvePathItem(parsed, pathItem) {
44
+ if (!isObject(pathItem)) return void 0;
45
+ const ref = getString(pathItem, "$ref");
46
+ if (ref === void 0) return pathItem;
47
+ return resolveRefInDoc(parsed.doc, ref) ?? void 0;
48
+ }
49
+ function lookupPathItem(parsed, path) {
50
+ const resolved = resolvePathItem(parsed, getProperty(getProperty(parsed.doc, "paths"), path));
51
+ if (resolved !== void 0) return resolved;
52
+ return resolvePathItem(parsed, getProperty(getProperty(parsed.doc, "webhooks"), path));
53
+ }
38
54
  function listOperations(parsed) {
39
55
  const operations = [];
40
56
  const paths = getProperty(parsed.doc, "paths");
41
57
  if (!isObject(paths)) return operations;
42
- for (const [path, pathItem] of Object.entries(paths)) {
43
- if (!isObject(pathItem)) continue;
58
+ for (const [path, rawPathItem] of Object.entries(paths)) {
59
+ const pathItem = resolvePathItem(parsed, rawPathItem);
60
+ if (pathItem === void 0) continue;
44
61
  for (const method of METHODS) {
45
62
  const operation = getProperty(pathItem, method);
46
63
  if (!isObject(operation)) continue;
@@ -58,8 +75,8 @@ function listOperations(parsed) {
58
75
  return operations;
59
76
  }
60
77
  function getParameters(parsed, path, method) {
61
- const pathItem = getProperty(getProperty(parsed.doc, "paths"), path);
62
- if (!isObject(pathItem)) return [];
78
+ const pathItem = lookupPathItem(parsed, path);
79
+ if (pathItem === void 0) return [];
63
80
  const operation = getProperty(pathItem, method);
64
81
  if (!isObject(operation)) return [];
65
82
  const pathParams = extractParameterList(getProperty(pathItem, "parameters"));
@@ -99,7 +116,7 @@ function resolveParam(param) {
99
116
  return param;
100
117
  }
101
118
  function getRequestBody(parsed, path, method) {
102
- const requestBody = getProperty(getProperty(getProperty(getProperty(parsed.doc, "paths"), path), method), "requestBody");
119
+ const requestBody = getProperty(getProperty(lookupPathItem(parsed, path), method), "requestBody");
103
120
  if (!isObject(requestBody)) return void 0;
104
121
  const content = getProperty(requestBody, "content");
105
122
  if (!isObject(content)) return {
@@ -118,7 +135,7 @@ function getRequestBody(parsed, path, method) {
118
135
  };
119
136
  }
120
137
  function getResponses(parsed, path, method) {
121
- const responses = getProperty(getProperty(getProperty(getProperty(parsed.doc, "paths"), path), method), "responses");
138
+ const responses = getProperty(getProperty(lookupPathItem(parsed, path), method), "responses");
122
139
  if (!isObject(responses)) return [];
123
140
  const result = [];
124
141
  for (const [statusCode, response] of Object.entries(responses)) {
@@ -126,11 +143,13 @@ function getResponses(parsed, path, method) {
126
143
  const content = getProperty(response, "content");
127
144
  const contentTypes = isObject(content) ? Object.keys(content) : [];
128
145
  const schema = isObject(content) ? extractSchemaFromContent(content) : void 0;
146
+ const headers = getResponseHeaders(response);
129
147
  result.push({
130
148
  statusCode,
131
149
  description: getString(response, "description"),
132
150
  contentTypes,
133
- schema
151
+ schema,
152
+ headers
134
153
  });
135
154
  }
136
155
  return result;
@@ -155,5 +174,167 @@ function resolveRefInDoc(doc, ref) {
155
174
  }
156
175
  return isObject(current) ? current : void 0;
157
176
  }
177
+ function getSecurityRequirements(parsed, path, method) {
178
+ const opSecurity = getProperty(getProperty(lookupPathItem(parsed, path), method), "security");
179
+ const globalSecurity = getProperty(parsed.doc, "security");
180
+ const securityArray = Array.isArray(opSecurity) ? opSecurity : Array.isArray(globalSecurity) ? globalSecurity : [];
181
+ const result = [];
182
+ for (const entry of securityArray) {
183
+ if (!isObject(entry)) continue;
184
+ for (const [name, scopes] of Object.entries(entry)) result.push({
185
+ name,
186
+ scopes: Array.isArray(scopes) ? scopes.filter((s) => typeof s === "string") : []
187
+ });
188
+ }
189
+ return result;
190
+ }
191
+ function getSecuritySchemes(parsed) {
192
+ const result = /* @__PURE__ */ new Map();
193
+ const securitySchemes = getProperty(getProperty(parsed.doc, "components"), "securitySchemes");
194
+ if (!isObject(securitySchemes)) return result;
195
+ for (const [name, scheme] of Object.entries(securitySchemes)) {
196
+ if (!isObject(scheme)) continue;
197
+ const flowsProp = getProperty(scheme, "flows");
198
+ result.set(name, {
199
+ type: getString(scheme, "type") ?? "",
200
+ description: getString(scheme, "description"),
201
+ name: getString(scheme, "name"),
202
+ location: getString(scheme, "in"),
203
+ scheme: getString(scheme, "scheme"),
204
+ bearerFormat: getString(scheme, "bearerFormat"),
205
+ flows: isObject(flowsProp) ? flowsProp : void 0,
206
+ openIdConnectUrl: getString(scheme, "openIdConnectUrl")
207
+ });
208
+ }
209
+ return result;
210
+ }
211
+ function getResponseHeaders(response) {
212
+ const result = /* @__PURE__ */ new Map();
213
+ const headers = getProperty(response, "headers");
214
+ if (!isObject(headers)) return result;
215
+ for (const [name, headerObj] of Object.entries(headers)) {
216
+ if (!isObject(headerObj)) continue;
217
+ const ref = getString(headerObj, "$ref");
218
+ const header = (ref !== void 0 ? resolveRefInDoc(headerObj, ref) : void 0) ?? headerObj;
219
+ const schemaProp = getProperty(header, "schema");
220
+ result.set(name, {
221
+ name,
222
+ description: getString(header, "description"),
223
+ required: getProperty(header, "required") === true,
224
+ deprecated: getProperty(header, "deprecated") === true,
225
+ schema: isObject(schemaProp) ? schemaProp : void 0
226
+ });
227
+ }
228
+ return result;
229
+ }
230
+ function listWebhooks(parsed) {
231
+ const result = [];
232
+ const webhooks = getProperty(parsed.doc, "webhooks");
233
+ if (!isObject(webhooks)) return result;
234
+ for (const [name, hookItem] of Object.entries(webhooks)) {
235
+ if (!isObject(hookItem)) continue;
236
+ const operations = [];
237
+ for (const method of METHODS) {
238
+ const operation = getProperty(hookItem, method);
239
+ if (!isObject(operation)) continue;
240
+ operations.push({
241
+ path: name,
242
+ method,
243
+ operationId: getString(operation, "operationId"),
244
+ summary: getString(operation, "summary"),
245
+ description: getString(operation, "description"),
246
+ deprecated: getProperty(operation, "deprecated") === true,
247
+ operation
248
+ });
249
+ }
250
+ result.push({
251
+ name,
252
+ operations
253
+ });
254
+ }
255
+ return result;
256
+ }
257
+ function getExternalDocs(obj) {
258
+ const docs = getProperty(obj, "externalDocs");
259
+ if (!isObject(docs)) return void 0;
260
+ const url = getString(docs, "url");
261
+ if (typeof url !== "string") return void 0;
262
+ return {
263
+ url,
264
+ description: getString(docs, "description")
265
+ };
266
+ }
267
+ function getXmlInfo(schema) {
268
+ const xml = getProperty(schema, "xml");
269
+ if (!isObject(xml)) return void 0;
270
+ return {
271
+ name: getString(xml, "name"),
272
+ namespace: getString(xml, "namespace"),
273
+ prefix: getString(xml, "prefix"),
274
+ attribute: getProperty(xml, "attribute") === true,
275
+ wrapped: getProperty(xml, "wrapped") === true
276
+ };
277
+ }
278
+ function listCallbacks(parsed, path, method) {
279
+ const operation = getProperty(lookupPathItem(parsed, path), method);
280
+ if (!isObject(operation)) return [];
281
+ const callbacks = getProperty(operation, "callbacks");
282
+ if (!isObject(callbacks)) return [];
283
+ const result = [];
284
+ for (const [name, callbackItem] of Object.entries(callbacks)) {
285
+ if (!isObject(callbackItem)) continue;
286
+ const operations = [];
287
+ for (const [cbPath, cbPathItem] of Object.entries(callbackItem)) {
288
+ if (!isObject(cbPathItem)) continue;
289
+ for (const cbMethod of METHODS) {
290
+ const cbOp = getProperty(cbPathItem, cbMethod);
291
+ if (!isObject(cbOp)) continue;
292
+ const ref = getString(cbOp, "$ref");
293
+ const resolved = ref !== void 0 ? resolveRefInDoc(parsed.doc, ref) ?? cbOp : cbOp;
294
+ operations.push({
295
+ path: `${name}/${cbPath}`,
296
+ method: cbMethod,
297
+ operationId: getString(resolved, "operationId"),
298
+ summary: getString(resolved, "summary"),
299
+ description: getString(resolved, "description"),
300
+ deprecated: getProperty(resolved, "deprecated") === true,
301
+ operation: isObject(resolved) ? resolved : cbOp
302
+ });
303
+ }
304
+ }
305
+ result.push({
306
+ name,
307
+ operations
308
+ });
309
+ }
310
+ return result;
311
+ }
312
+ function getLinks(parsed, path, method, statusCode) {
313
+ const response = getProperty(getProperty(getProperty(lookupPathItem(parsed, path), method), "responses"), statusCode);
314
+ if (!isObject(response)) return [];
315
+ const links = getProperty(response, "links");
316
+ if (!isObject(links)) return [];
317
+ const result = [];
318
+ for (const [name, linkObj] of Object.entries(links)) {
319
+ if (!isObject(linkObj)) continue;
320
+ const ref = getString(linkObj, "$ref");
321
+ const resolved = ref !== void 0 ? resolveRefInDoc(parsed.doc, ref) ?? linkObj : linkObj;
322
+ const link = isObject(resolved) ? resolved : linkObj;
323
+ const params = getProperty(link, "parameters");
324
+ const paramMap = /* @__PURE__ */ new Map();
325
+ if (isObject(params)) {
326
+ for (const [paramName, paramValue] of Object.entries(params)) if (typeof paramValue === "string") paramMap.set(paramName, paramValue);
327
+ }
328
+ result.push({
329
+ name,
330
+ operationId: getString(link, "operationId"),
331
+ operationRef: getString(link, "operationRef"),
332
+ description: getString(link, "description"),
333
+ parameters: paramMap,
334
+ requestBody: getString(link, "requestBody")
335
+ });
336
+ }
337
+ return result;
338
+ }
158
339
  //#endregion
159
- export { getParameters, getRequestBody, getResponses, getSchema, listOperations, parseOpenApiDocument };
340
+ export { getExternalDocs, getLinks, getParameters, getRequestBody, getResponseHeaders, getResponses, getSchema, getSecurityRequirements, getSecuritySchemes, getXmlInfo, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
@@ -1,5 +1,7 @@
1
- import { E as RenderProps, _ as WalkedField, a as FromJSONSchema, b as ComponentResolver, f as PathOfType, i as FieldOverrides, m as SchemaMeta, p as ResolveOpenAPIRef, r as FieldOverride } from "../types-BJzEgJdX.mjs";
1
+ import { d as FieldOverrides, j as WalkedField, u as FieldOverride, w as SchemaMeta } from "../types-ag2jYLqQ.mjs";
2
2
  import { t as SchemaError } from "../errors-DIKI2C78.mjs";
3
+ import { l as RenderProps, r as ComponentResolver } from "../renderer-DseHeliw.mjs";
4
+ import { c as ResolveOpenAPIRef, s as PathOfType, t as FromJSONSchema } from "../typeInference-CRPqVwKu.mjs";
3
5
  import { z } from "zod";
4
6
  import { ReactNode } from "react";
5
7
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
@@ -79,7 +81,7 @@ declare function SchemaComponent<T = unknown, Ref extends string | undefined = u
79
81
  description,
80
82
  widgets: instanceWidgets
81
83
  }: SchemaComponentProps<T, Ref>): ReactNode;
82
- declare function renderField(tree: WalkedField, value: unknown, onChange: (v: unknown) => void, userResolver: ComponentResolver | undefined, renderChild: (tree: WalkedField, value: unknown, onChange: (v: unknown) => void) => ReactNode, instanceWidgets?: WidgetMap, contextWidgets?: WidgetMap): ReactNode;
84
+ declare function renderField(tree: WalkedField, value: unknown, onChange: (v: unknown) => void, userResolver: ComponentResolver | undefined, renderChild: (tree: WalkedField, value: unknown, onChange: (v: unknown) => void) => ReactNode, instanceWidgets?: WidgetMap, contextWidgets?: WidgetMap, depth?: number): ReactNode;
83
85
  /**
84
86
  * Infer the schema's output type for SchemaField path inference.
85
87
  */
@@ -1,13 +1,14 @@
1
1
  "use client";
2
- import { isObject, toRecord, toRecordOrUndefined } from "../core/guards.mjs";
2
+ import { isObject, toRecordOrUndefined } from "../core/guards.mjs";
3
3
  import { normaliseSchema } from "../core/adapter.mjs";
4
4
  import { SchemaFieldError, SchemaNormalisationError, SchemaRenderError } from "../core/errors.mjs";
5
5
  import { getRenderFunction, mergeResolvers } from "../core/renderer.mjs";
6
6
  import { walk } from "../core/walker.mjs";
7
7
  import { headlessResolver } from "./headless.mjs";
8
+ import { resolvePath, resolveValue, setNestedValue } from "./fieldPath.mjs";
8
9
  import { z } from "zod";
9
10
  import { createContext, isValidElement, useCallback, useContext, useMemo } from "react";
10
- import { jsx } from "react/jsx-runtime";
11
+ import { jsx, jsxs } from "react/jsx-runtime";
11
12
  //#region src/react/SchemaComponent.tsx
12
13
  /**
13
14
  * <SchemaComponent> — renders UI from Zod, JSON Schema, or OpenAPI schemas.
@@ -101,10 +102,11 @@ function SchemaComponent({ schema: schemaInput, ref: refInput, value, onChange,
101
102
  fieldOverrides: fields,
102
103
  rootDocument
103
104
  });
104
- const renderChild = (childTree, childValue, childOnChange) => {
105
- return renderField(childTree, childValue, childOnChange, userResolver, renderChild, instanceWidgets, contextWidgets);
105
+ const makeRenderChild = (currentDepth) => (childTree, childValue, childOnChange) => {
106
+ return renderField(childTree, childValue, childOnChange, userResolver, makeRenderChild(currentDepth + 1), instanceWidgets, contextWidgets, currentDepth + 1);
106
107
  };
107
- return renderField(tree, value ?? tree.defaultValue, handleChange, userResolver, renderChild, instanceWidgets, contextWidgets);
108
+ const renderChild = makeRenderChild(0);
109
+ return renderField(tree, value ?? tree.defaultValue, handleChange, userResolver, renderChild, instanceWidgets, contextWidgets, 0);
108
110
  }
109
111
  function runValidation(zodSchema, jsonSchema, value) {
110
112
  if (zodSchema !== void 0 && isObject(zodSchema)) {
@@ -124,8 +126,17 @@ function runValidation(zodSchema, jsonSchema, value) {
124
126
  }
125
127
  }
126
128
  }
127
- function renderField(tree, value, onChange, userResolver, renderChild, instanceWidgets, contextWidgets) {
128
- if (tree.meta.visible === false) return null;
129
+ /** Maximum rendering depth before treating a field as recursive. */
130
+ const MAX_RENDER_DEPTH = 10;
131
+ function renderField(tree, value, onChange, userResolver, renderChild, instanceWidgets, contextWidgets, depth = 0) {
132
+ if (depth >= MAX_RENDER_DEPTH) {
133
+ const refTarget = tree.type === "recursive" ? tree.refTarget : "";
134
+ return /* @__PURE__ */ jsx("fieldset", { children: /* @__PURE__ */ jsxs("em", { children: [
135
+ "↻ ",
136
+ (typeof tree.meta.description === "string" ? tree.meta.description : refTarget) || "schema",
137
+ " (recursive)"
138
+ ] }) });
139
+ }
129
140
  const componentHint = tree.meta.component;
130
141
  if (typeof componentHint === "string") {
131
142
  const widget = instanceWidgets?.get(componentHint) ?? contextWidgets?.get(componentHint) ?? globalWidgets.get(componentHint);
@@ -166,13 +177,21 @@ function buildRenderProps(tree, value, onChange, renderChild) {
166
177
  tree,
167
178
  renderChild
168
179
  };
169
- if (tree.enumValues !== void 0) props.enumValues = tree.enumValues;
170
- if (tree.element !== void 0) props.element = tree.element;
171
- if (tree.fields !== void 0) props.fields = tree.fields;
172
- if (tree.options !== void 0) props.options = tree.options;
173
- if (tree.discriminator !== void 0) props.discriminator = tree.discriminator;
174
- if (tree.keyType !== void 0) props.keyType = tree.keyType;
175
- if (tree.valueType !== void 0) props.valueType = tree.valueType;
180
+ if (tree.type === "enum") props.enumValues = tree.enumValues;
181
+ if (tree.type === "array" && tree.element !== void 0) props.element = tree.element;
182
+ if (tree.type === "object") props.fields = tree.fields;
183
+ if (tree.type === "union" || tree.type === "discriminatedUnion") props.options = tree.options;
184
+ if (tree.type === "discriminatedUnion") props.discriminator = tree.discriminator;
185
+ if (tree.type === "record") props.keyType = tree.keyType;
186
+ if (tree.type === "record") props.valueType = tree.valueType;
187
+ if (tree.type === "tuple") props.prefixItems = tree.prefixItems;
188
+ if (tree.type === "conditional") props.ifClause = tree.ifClause;
189
+ if (tree.type === "conditional" && tree.thenClause !== void 0) props.thenClause = tree.thenClause;
190
+ if (tree.type === "conditional" && tree.elseClause !== void 0) props.elseClause = tree.elseClause;
191
+ if (tree.type === "negation") props.negated = tree.negated;
192
+ if (tree.type === "recursive") props.refTarget = tree.refTarget;
193
+ if (tree.type === "literal") props.literalValues = tree.literalValues;
194
+ if (tree.examples !== void 0) props.examples = tree.examples;
176
195
  return props;
177
196
  }
178
197
  function SchemaField({ path, schema: schemaInput, ref: refInput, value, onChange, meta: fieldMeta, validate, onValidationError }) {
@@ -215,78 +234,10 @@ function SchemaField({ path, schema: schemaInput, ref: refInput, value, onChange
215
234
  onChange,
216
235
  onValidationError
217
236
  ]);
218
- const renderChild = (childTree, childValue, childOnChange) => {
219
- return renderField(childTree, childValue, childOnChange, userResolver, renderChild, void 0, contextWidgets);
237
+ const makeRenderChild = (currentDepth) => (childTree, childValue, childOnChange) => {
238
+ return renderField(childTree, childValue, childOnChange, userResolver, makeRenderChild(currentDepth + 1), void 0, contextWidgets, currentDepth + 1);
220
239
  };
221
- return renderField(fieldTree, fieldValue, handleChange, userResolver, renderChild, void 0, contextWidgets);
222
- }
223
- function resolvePath(tree, path) {
224
- if (path.length === 0) return tree;
225
- const parts = path.split(".");
226
- let current = tree;
227
- for (const part of parts) {
228
- if (current === void 0) return void 0;
229
- const bracketMatch = /^(.+)\[(\d+)\]$/.exec(part);
230
- if (bracketMatch?.[1] !== void 0 && bracketMatch[2] !== void 0) {
231
- const arrayField = bracketMatch[1];
232
- if (current.fields !== void 0) current = current.fields[arrayField];
233
- if (current?.element !== void 0) current = current.element;
234
- continue;
235
- }
236
- if (current.fields !== void 0) current = current.fields[part];
237
- else if (current.element !== void 0) current = current.element;
238
- else return;
239
- }
240
- return current;
241
- }
242
- function resolveValue(root, path) {
243
- if (path.length === 0) return root;
244
- const parts = path.split(".");
245
- let current = root;
246
- for (const part of parts) {
247
- if (typeof current !== "object" || current === null) return void 0;
248
- const bracketMatch = /^(.+)\[(\d+)\]$/.exec(part);
249
- if (bracketMatch?.[1] !== void 0 && bracketMatch[2] !== void 0) {
250
- const key = bracketMatch[1];
251
- const index = Number(bracketMatch[2]);
252
- const arr = toRecord(current)[key];
253
- if (Array.isArray(arr)) current = arr[index];
254
- else return;
255
- } else current = toRecord(current)[part];
256
- }
257
- return current;
258
- }
259
- function setNestedValue(root, path, leafValue) {
260
- if (path.length === 0) return leafValue;
261
- const parts = path.split(".");
262
- const result = isObject(root) ? { ...toRecord(root) } : {};
263
- let current = result;
264
- for (let i = 0; i < parts.length; i++) {
265
- const part = parts[i];
266
- if (part === void 0) break;
267
- const isLast = i === parts.length - 1;
268
- const bracketMatch = /^(.+)\[(\d+)\]$/.exec(part);
269
- if (bracketMatch?.[1] !== void 0 && bracketMatch[2] !== void 0) {
270
- const key = bracketMatch[1];
271
- const index = Number(bracketMatch[2]);
272
- const existing = current[key];
273
- const arr = Array.isArray(existing) ? existing.slice() : [];
274
- if (isLast) arr[index] = leafValue;
275
- current[key] = arr;
276
- const nextCurrent = arr[index];
277
- if (nextCurrent !== void 0 && isObject(nextCurrent)) current = toRecord(nextCurrent);
278
- } else if (isLast) current[part] = leafValue;
279
- else {
280
- const existing = current[part];
281
- const next = isObject(existing) ? { ...toRecord(existing) } : {};
282
- current[part] = next;
283
- current = next;
284
- }
285
- }
286
- return result;
287
- }
288
- function isFieldErrorCallback(value) {
289
- return typeof value === "function";
240
+ return renderField(fieldTree, fieldValue, handleChange, userResolver, makeRenderChild(0), void 0, contextWidgets, 0);
290
241
  }
291
242
  /**
292
243
  * Dispatch Zod errors to per-field onValidationError callbacks.
@@ -315,6 +266,9 @@ function dispatchFieldErrors(fields, error) {
315
266
  if (fieldErrors.length > 0 && isFieldErrorCallback(fieldCallback)) fieldCallback({ issues: fieldErrors });
316
267
  }
317
268
  }
269
+ function isFieldErrorCallback(value) {
270
+ return typeof value === "function";
271
+ }
318
272
  function isCallable(value) {
319
273
  return typeof value === "function";
320
274
  }
@@ -1,4 +1,5 @@
1
- import { b as ComponentResolver, m as SchemaMeta } from "../types-BJzEgJdX.mjs";
1
+ import { w as SchemaMeta } from "../types-ag2jYLqQ.mjs";
2
+ import { r as ComponentResolver } from "../renderer-DseHeliw.mjs";
2
3
  import { WidgetMap } from "./SchemaComponent.mjs";
3
4
  import { ReactNode } from "react";
4
5
 
@@ -3,7 +3,7 @@ import { SchemaNormalisationError, SchemaRenderError } from "../core/errors.mjs"
3
3
  import { getRenderFunction, mergeResolvers } from "../core/renderer.mjs";
4
4
  import { walk } from "../core/walker.mjs";
5
5
  import { headlessResolver } from "./headless.mjs";
6
- import { isValidElement } from "react";
6
+ import { createElement, isValidElement } from "react";
7
7
  import { jsx } from "react/jsx-runtime";
8
8
  //#region src/react/SchemaView.tsx
9
9
  /**
@@ -61,7 +61,12 @@ function SchemaView({ schema: schemaInput, ref: refInput, value, fields, meta: c
61
61
  rootDocument
62
62
  });
63
63
  const userResolver = resolver !== void 0 ? mergeResolvers(resolver, headlessResolver) : headlessResolver;
64
- const renderChild = (childTree, childValue) => renderFieldServer(childTree, childValue, userResolver, renderChild, widgets);
64
+ const MAX_SERVER_DEPTH = 10;
65
+ const makeRenderChild = (currentDepth) => (childTree, childValue) => {
66
+ if (currentDepth >= MAX_SERVER_DEPTH) return createElement("fieldset", null, createElement("em", null, `\u21bb ${typeof childTree.meta.description === "string" ? childTree.meta.description : childTree.type === "recursive" ? childTree.refTarget : "schema"} (recursive)`));
67
+ return renderFieldServer(childTree, childValue, userResolver, makeRenderChild(currentDepth + 1), widgets);
68
+ };
69
+ const renderChild = makeRenderChild(0);
65
70
  return renderFieldServer(tree, value ?? tree.defaultValue, userResolver, renderChild, widgets);
66
71
  }
67
72
  function renderFieldServer(tree, value, resolver, renderChild, widgets) {
@@ -99,13 +104,20 @@ function renderFieldServer(tree, value, resolver, renderChild, widgets) {
99
104
  tree,
100
105
  renderChild: (childTree, childValue) => renderChild(childTree, childValue)
101
106
  };
102
- if (tree.enumValues !== void 0) props.enumValues = tree.enumValues;
103
- if (tree.element !== void 0) props.element = tree.element;
104
- if (tree.fields !== void 0) props.fields = tree.fields;
105
- if (tree.options !== void 0) props.options = tree.options;
106
- if (tree.discriminator !== void 0) props.discriminator = tree.discriminator;
107
- if (tree.keyType !== void 0) props.keyType = tree.keyType;
108
- if (tree.valueType !== void 0) props.valueType = tree.valueType;
107
+ if (tree.type === "enum") props.enumValues = tree.enumValues;
108
+ if (tree.type === "array" && tree.element !== void 0) props.element = tree.element;
109
+ if (tree.type === "object") props.fields = tree.fields;
110
+ if (tree.type === "union" || tree.type === "discriminatedUnion") props.options = tree.options;
111
+ if (tree.type === "discriminatedUnion") props.discriminator = tree.discriminator;
112
+ if (tree.type === "record") props.keyType = tree.keyType;
113
+ if (tree.type === "record") props.valueType = tree.valueType;
114
+ if (tree.type === "tuple") props.prefixItems = tree.prefixItems;
115
+ if (tree.type === "conditional") props.ifClause = tree.ifClause;
116
+ if (tree.type === "conditional" && tree.thenClause !== void 0) props.thenClause = tree.thenClause;
117
+ if (tree.type === "conditional" && tree.elseClause !== void 0) props.elseClause = tree.elseClause;
118
+ if (tree.type === "negation") props.negated = tree.negated;
119
+ if (tree.type === "recursive") props.refTarget = tree.refTarget;
120
+ if (tree.type === "literal") props.literalValues = tree.literalValues;
109
121
  try {
110
122
  const result = renderFn(props);
111
123
  if (result !== void 0 && result !== null) {
@@ -0,0 +1,20 @@
1
+ import { j as WalkedField } from "../types-ag2jYLqQ.mjs";
2
+
3
+ //#region src/react/fieldPath.d.ts
4
+ /**
5
+ * Resolve a dot-separated path through a WalkedField tree.
6
+ * Supports array index notation: `field[0]`.
7
+ */
8
+ declare function resolvePath(tree: WalkedField, path: string): WalkedField | undefined;
9
+ /**
10
+ * Resolve a dot-separated path through a data value.
11
+ * Supports array index notation: `field[0]`.
12
+ */
13
+ declare function resolveValue(root: unknown, path: string): unknown;
14
+ /**
15
+ * Set a value at a dot-separated path, producing a new root object.
16
+ * Does not mutate the input — returns a shallow-updated copy at each level.
17
+ */
18
+ declare function setNestedValue(root: unknown, path: string, leafValue: unknown): unknown;
19
+ //#endregion
20
+ export { resolvePath, resolveValue, setNestedValue };