schema-components 1.19.0 → 1.20.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 (62) hide show
  1. package/dist/core/adapter.d.mts +2 -2
  2. package/dist/core/adapter.mjs +59 -9
  3. package/dist/core/constraints.d.mts +2 -2
  4. package/dist/core/diagnostics.d.mts +1 -1
  5. package/dist/core/errors.d.mts +1 -1
  6. package/dist/core/errors.mjs +9 -1
  7. package/dist/core/fieldOrder.d.mts +1 -1
  8. package/dist/core/formats.d.mts +21 -14
  9. package/dist/core/formats.mjs +88 -4
  10. package/dist/core/merge.d.mts +1 -1
  11. package/dist/core/normalise.d.mts +2 -2
  12. package/dist/core/normalise.mjs +1 -1
  13. package/dist/core/openapi30.mjs +1 -1
  14. package/dist/core/ref.d.mts +1 -1
  15. package/dist/core/renderer.d.mts +1 -1
  16. package/dist/core/swagger2.d.mts +1 -1
  17. package/dist/core/swagger2.mjs +1 -1
  18. package/dist/core/typeInference.d.mts +2 -2
  19. package/dist/core/types.d.mts +1 -1
  20. package/dist/core/uri.d.mts +41 -0
  21. package/dist/core/uri.mjs +76 -0
  22. package/dist/core/version.d.mts +2 -2
  23. package/dist/core/version.mjs +25 -1
  24. package/dist/core/walkBuilders.d.mts +3 -3
  25. package/dist/core/walker.d.mts +1 -1
  26. package/dist/core/walker.mjs +50 -3
  27. package/dist/{diagnostics-VgEKI_Ct.d.mts → diagnostics-CbBPsxSt.d.mts} +1 -1
  28. package/dist/{errors-CnGjT1cg.d.mts → errors-C2iABcn9.d.mts} +8 -1
  29. package/dist/html/a11y.d.mts +2 -2
  30. package/dist/html/renderToHtml.d.mts +2 -2
  31. package/dist/html/renderToHtmlStream.d.mts +2 -2
  32. package/dist/html/renderers.d.mts +2 -2
  33. package/dist/html/renderers.mjs +9 -2
  34. package/dist/html/streamRenderers.d.mts +2 -2
  35. package/dist/{normalise-C0ofw3W6.mjs → normalise-CMMEl4cd.mjs} +255 -18
  36. package/dist/openapi/ApiCallbacks.d.mts +1 -1
  37. package/dist/openapi/ApiLinks.d.mts +1 -1
  38. package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
  39. package/dist/openapi/ApiSecurity.d.mts +1 -1
  40. package/dist/openapi/bundle.mjs +2 -0
  41. package/dist/openapi/components.d.mts +2 -2
  42. package/dist/openapi/components.mjs +16 -5
  43. package/dist/openapi/parser.d.mts +1 -1
  44. package/dist/openapi/parser.mjs +2 -0
  45. package/dist/openapi/resolve.d.mts +11 -1
  46. package/dist/openapi/resolve.mjs +39 -2
  47. package/dist/react/SchemaComponent.d.mts +21 -9
  48. package/dist/react/SchemaView.d.mts +3 -3
  49. package/dist/react/fieldPath.d.mts +1 -1
  50. package/dist/react/headless.d.mts +1 -1
  51. package/dist/react/headlessRenderers.d.mts +2 -2
  52. package/dist/react/headlessRenderers.mjs +18 -6
  53. package/dist/{ref-Bb43ZURY.d.mts → ref-C8JbwfiS.d.mts} +1 -1
  54. package/dist/{renderer-BQqiXUYP.d.mts → renderer-SOIbJBtk.d.mts} +1 -1
  55. package/dist/themes/mantine.d.mts +1 -1
  56. package/dist/themes/mui.d.mts +1 -1
  57. package/dist/themes/radix.d.mts +1 -1
  58. package/dist/themes/shadcn.d.mts +1 -1
  59. package/dist/{typeInference-5JiqIZ8t.d.mts → typeInference-CDoD_LZ_.d.mts} +187 -42
  60. package/dist/{types-D_5ST7SS.d.mts → types-C9zw9wbX.d.mts} +6 -0
  61. package/dist/{version-XNH7PRGP.d.mts → version-D-u7aMfy.d.mts} +36 -1
  62. package/package.json +1 -1
@@ -53,7 +53,10 @@ function ApiOperation({ schema: doc, path, method, requestBodyValue, onRequestBo
53
53
  return /* @__PURE__ */ jsxs("section", {
54
54
  "data-operation": `${method.toUpperCase()} ${path}`,
55
55
  children: [
56
- /* @__PURE__ */ jsx(OperationHeader, { operation: resolved.operation }),
56
+ /* @__PURE__ */ jsx(OperationHeader, {
57
+ operation: resolved.operation,
58
+ pathItem: resolved.pathItem
59
+ }),
57
60
  /* @__PURE__ */ jsx(ApiSecurity, {
58
61
  requirements: securityReqs,
59
62
  schemes: securitySchemes
@@ -176,8 +179,18 @@ function ApiResponse({ schema: doc, path, method, status, value, meta, fields, w
176
179
  idPrefix: instancePrefix
177
180
  });
178
181
  }
179
- function OperationHeader({ operation }) {
182
+ function OperationHeader({ operation, pathItem }) {
180
183
  return /* @__PURE__ */ jsxs("header", { children: [
184
+ (pathItem.summary !== void 0 || pathItem.description !== void 0) && /* @__PURE__ */ jsxs("div", {
185
+ "data-path-info": true,
186
+ children: [pathItem.summary !== void 0 && /* @__PURE__ */ jsx("p", {
187
+ "data-path-summary": true,
188
+ children: pathItem.summary
189
+ }), pathItem.description !== void 0 && /* @__PURE__ */ jsx("p", {
190
+ "data-path-description": true,
191
+ children: pathItem.description
192
+ })]
193
+ }),
181
194
  /* @__PURE__ */ jsxs("h3", { children: [
182
195
  operation.method.toUpperCase(),
183
196
  " ",
@@ -224,9 +237,7 @@ function ResponseCard({ response, rootDoc, value, fields, meta, widgets, path, m
224
237
  ]
225
238
  });
226
239
  let links = [];
227
- if (path !== void 0 && method !== void 0) try {
228
- links = getLinks(getParsed(rootDoc), path, method, response.statusCode);
229
- } catch {}
240
+ if (path !== void 0 && method !== void 0) links = getLinks(getParsed(rootDoc), path, method, response.statusCode);
230
241
  return /* @__PURE__ */ jsxs("div", {
231
242
  "data-status": response.statusCode,
232
243
  children: [
@@ -1,4 +1,4 @@
1
- import { m as JsonObject } from "../types-D_5ST7SS.mjs";
1
+ import { m as JsonObject } from "../types-C9zw9wbX.mjs";
2
2
 
3
3
  //#region src/openapi/parser.d.ts
4
4
  interface OpenApiDocument {
@@ -1,4 +1,5 @@
1
1
  import { getProperty, isObject } from "../core/guards.mjs";
2
+ import { isPrototypePollutingKey } from "../core/uri.mjs";
2
3
  //#region src/openapi/parser.ts
3
4
  function getString(value, key) {
4
5
  const result = isObject(value) ? value[key] : void 0;
@@ -173,6 +174,7 @@ function resolveRefInDoc(doc, ref) {
173
174
  for (const part of parts) {
174
175
  if (!isObject(current)) return void 0;
175
176
  const decoded = part.replace(/~1/g, "/").replace(/~0/g, "~");
177
+ if (isPrototypePollutingKey(decoded)) return void 0;
176
178
  current = current[decoded];
177
179
  }
178
180
  return isObject(current) ? current : void 0;
@@ -23,8 +23,18 @@ declare function getParsed(doc: Record<string, unknown>): OpenApiDocument;
23
23
  * for non-objects.
24
24
  */
25
25
  declare function toDoc(value: unknown): Record<string, unknown>;
26
+ /**
27
+ * Path-Item-level metadata. OpenAPI 3.1 added `summary` and `description`
28
+ * to Path Item Objects alongside the existing operation-level fields.
29
+ * Both are plain strings (no Markdown rendering at this layer).
30
+ */
31
+ interface PathItemInfo {
32
+ summary: string | undefined;
33
+ description: string | undefined;
34
+ }
26
35
  interface ResolvedOperation {
27
36
  operation: OperationInfo;
37
+ pathItem: PathItemInfo;
28
38
  parameters: ParameterInfo[];
29
39
  requestBody: ReturnType<typeof getRequestBody>;
30
40
  responses: ResponseInfo[];
@@ -51,4 +61,4 @@ declare function resolveResponse(doc: Record<string, unknown>, path: string, met
51
61
  */
52
62
  declare function resolveResponses(doc: Record<string, unknown>, path: string, method: string): ResponseInfo[];
53
63
  //#endregion
54
- export { ResolvedOperation, getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, resolveResponses, toDoc };
64
+ export { PathItemInfo, ResolvedOperation, getParsed, resolveOperation, resolveParameters, resolveRequestBody, resolveResponse, resolveResponses, toDoc };
@@ -1,6 +1,6 @@
1
- import { isObject } from "../core/guards.mjs";
1
+ import { getProperty, isObject } from "../core/guards.mjs";
2
2
  import { detectOpenApiVersion } from "../core/version.mjs";
3
- import { a as normaliseOpenApiSchemas } from "../normalise-C0ofw3W6.mjs";
3
+ import { a as normaliseOpenApiSchemas } from "../normalise-CMMEl4cd.mjs";
4
4
  import { getParameters, getRequestBody, getResponses, listOperations, parseOpenApiDocument } from "./parser.mjs";
5
5
  //#region src/openapi/resolve.ts
6
6
  /**
@@ -45,6 +45,40 @@ function toDoc(value) {
45
45
  return isObject(value) ? value : {};
46
46
  }
47
47
  /**
48
+ * Look up a Path Item Object on the (already-normalised) parsed document,
49
+ * following a single `$ref` hop into `components/pathItems` (OpenAPI 3.1)
50
+ * if present. Returns `undefined` when the path is not present or the
51
+ * value is not an object.
52
+ *
53
+ * Implemented inside `resolve.ts` to avoid touching `parser.ts` while
54
+ * still surfacing path-item-level metadata to the React layer.
55
+ */
56
+ function lookupPathItemNode(parsed, path) {
57
+ return resolvePathItemNode(parsed, getProperty(getProperty(parsed.doc, "paths"), path));
58
+ }
59
+ function resolvePathItemNode(parsed, pathItem) {
60
+ if (!isObject(pathItem)) return void 0;
61
+ const ref = getProperty(pathItem, "$ref");
62
+ if (typeof ref !== "string") return pathItem;
63
+ if (!ref.startsWith("#/")) return pathItem;
64
+ const parts = ref.slice(2).split("/");
65
+ let current = parsed.doc;
66
+ for (const part of parts) {
67
+ if (!isObject(current)) return void 0;
68
+ const decoded = part.replace(/~1/g, "/").replace(/~0/g, "~");
69
+ current = current[decoded];
70
+ }
71
+ return isObject(current) ? current : pathItem;
72
+ }
73
+ function extractPathItemInfo(pathItem) {
74
+ const summary = pathItem.summary;
75
+ const description = pathItem.description;
76
+ return {
77
+ summary: typeof summary === "string" ? summary : void 0,
78
+ description: typeof description === "string" ? description : void 0
79
+ };
80
+ }
81
+ /**
48
82
  * Resolve an operation from an OpenAPI document by path and method.
49
83
  * Throws if the operation is not found.
50
84
  */
@@ -52,8 +86,11 @@ function resolveOperation(doc, path, method) {
52
86
  const parsed = getParsed(doc);
53
87
  const operation = listOperations(parsed).find((op) => op.path === path && op.method === method);
54
88
  if (operation === void 0) throw new Error(`Operation not found: ${method.toUpperCase()} ${path}`);
89
+ const pathItemNode = lookupPathItemNode(parsed, path);
90
+ if (pathItemNode === void 0) throw new Error(`Path item missing for ${method.toUpperCase()} ${path}`);
55
91
  return {
56
92
  operation,
93
+ pathItem: extractPathItemInfo(pathItemNode),
57
94
  parameters: getParameters(parsed, path, method),
58
95
  requestBody: getRequestBody(parsed, path, method),
59
96
  responses: getResponses(parsed, path, method)
@@ -1,8 +1,8 @@
1
- import { M as WalkedField, T as SchemaMeta, d as FieldOverrides, u as FieldOverride } from "../types-D_5ST7SS.mjs";
2
- import { t as Diagnostic } from "../diagnostics-VgEKI_Ct.mjs";
3
- import { t as SchemaError } from "../errors-CnGjT1cg.mjs";
4
- import { l as RenderProps, r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
5
- import { c as PathOfType, l as ResolveOpenAPIRef, n as FromJSONSchema } from "../typeInference-5JiqIZ8t.mjs";
1
+ import { M as WalkedField, T as SchemaMeta, d as FieldOverrides, u as FieldOverride } from "../types-C9zw9wbX.mjs";
2
+ import { t as Diagnostic } from "../diagnostics-CbBPsxSt.mjs";
3
+ import { t as SchemaError } from "../errors-C2iABcn9.mjs";
4
+ import { l as RenderProps, r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
5
+ import { c as PathOfType, l as RejectUnrepresentableZod, n as FromJSONSchema, u as ResolveOpenAPIRef } from "../typeInference-CDoD_LZ_.mjs";
6
6
  import { z } from "zod";
7
7
  import * as _$react_jsx_runtime0 from "react/jsx-runtime";
8
8
  import { ReactNode } from "react";
@@ -40,8 +40,17 @@ type InferFields<T, Ref extends string | undefined> = T extends z.ZodType ? Fiel
40
40
  openapi: unknown;
41
41
  } ? Ref extends string ? FieldOverrides<ResolveOpenAPIRef<T & Record<string, unknown>, Ref>> : Record<string, FieldOverride> : T extends object ? unknown extends FromJSONSchema<T> ? Record<string, FieldOverride> : FieldOverrides<FromJSONSchema<T>> : Record<string, FieldOverride>;
42
42
  interface SchemaComponentProps<T = unknown, Ref extends string | undefined = undefined> {
43
- /** Zod schema, JSON Schema object, or OpenAPI document. */
44
- schema: T;
43
+ /**
44
+ * Zod schema, JSON Schema object, or OpenAPI document.
45
+ *
46
+ * Zod 4 types that cannot round-trip through `z.toJSONSchema()`
47
+ * (bigint, date, map, set, symbol, function, undefined, void, nan,
48
+ * codec) are rejected at the type level via
49
+ * {@link RejectUnrepresentableZod}. Runtime conversion would throw
50
+ * `SchemaNormalisationError` with kind `zod-type-unrepresentable`
51
+ * — the static rejection surfaces the same failure at compile time.
52
+ */
53
+ schema: RejectUnrepresentableZod<T>;
45
54
  /** For OpenAPI: a ref string like "#/components/schemas/User" or "/users/post". */
46
55
  ref?: Ref;
47
56
  /** Current value to render. */
@@ -128,8 +137,11 @@ interface SchemaFieldProps<T = unknown, Ref extends string | undefined = undefin
128
137
  * paths are accepted. Falls back to `string` for runtime schemas.
129
138
  */
130
139
  path: P;
131
- /** The schema to extract the field from. */
132
- schema: T;
140
+ /**
141
+ * The schema to extract the field from. Subject to the same
142
+ * unrepresentable-Zod rejection as {@link SchemaComponentProps.schema}.
143
+ */
144
+ schema: RejectUnrepresentableZod<T>;
133
145
  /** For OpenAPI: a ref string. */
134
146
  ref?: Ref;
135
147
  /** Current value of the field at the given path. */
@@ -1,6 +1,6 @@
1
- import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
- import { t as Diagnostic } from "../diagnostics-VgEKI_Ct.mjs";
3
- import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
1
+ import { T as SchemaMeta } from "../types-C9zw9wbX.mjs";
2
+ import { t as Diagnostic } from "../diagnostics-CbBPsxSt.mjs";
3
+ import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
4
4
  import { WidgetMap } from "./SchemaComponent.mjs";
5
5
  import { ReactNode } from "react";
6
6
 
@@ -1,4 +1,4 @@
1
- import { M as WalkedField } from "../types-D_5ST7SS.mjs";
1
+ import { M as WalkedField } from "../types-C9zw9wbX.mjs";
2
2
 
3
3
  //#region src/react/fieldPath.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
1
+ import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
2
2
 
3
3
  //#region src/react/headless.d.ts
4
4
  /**
@@ -1,5 +1,5 @@
1
- import { M as WalkedField } from "../types-D_5ST7SS.mjs";
2
- import { l as RenderProps } from "../renderer-BQqiXUYP.mjs";
1
+ import { M as WalkedField } from "../types-C9zw9wbX.mjs";
2
+ import { l as RenderProps } from "../renderer-SOIbJBtk.mjs";
3
3
  import { ReactNode } from "react";
4
4
 
5
5
  //#region src/react/headlessRenderers.d.ts
@@ -1,5 +1,6 @@
1
1
  import { isObject } from "../core/guards.mjs";
2
2
  import { sortFieldsByOrder } from "../core/fieldOrder.mjs";
3
+ import { isSafeHyperlink, isSafeMailtoAddress } from "../core/uri.mjs";
3
4
  import { jsx, jsxs } from "react/jsx-runtime";
4
5
  import { isValidElement, useCallback, useEffect, useRef } from "react";
5
6
  //#region src/react/headlessRenderers.tsx
@@ -83,13 +84,13 @@ function renderString(props) {
83
84
  children: "—"
84
85
  });
85
86
  const format = props.constraints.format;
86
- if (format === "email") return /* @__PURE__ */ jsx("a", {
87
+ if (format === "email" && isSafeMailtoAddress(strValue)) return /* @__PURE__ */ jsx("a", {
87
88
  href: `mailto:${strValue}`,
88
89
  id,
89
90
  "aria-readonly": "true",
90
91
  children: strValue
91
92
  });
92
- if (format === "uri" || format === "url") return /* @__PURE__ */ jsx("a", {
93
+ if ((format === "uri" || format === "url") && isSafeHyperlink(strValue)) return /* @__PURE__ */ jsx("a", {
93
94
  href: strValue,
94
95
  id,
95
96
  "aria-readonly": "true",
@@ -658,12 +659,14 @@ function renderNever(props) {
658
659
  function renderTuple(props) {
659
660
  if (props.tree.type !== "tuple") return null;
660
661
  const prefixItems = props.tree.prefixItems;
661
- if (prefixItems.length === 0) return null;
662
+ const restItems = props.tree.restItems;
662
663
  const arr = Array.isArray(props.value) ? props.value : [];
663
- return /* @__PURE__ */ jsx("div", {
664
+ if (prefixItems.length === 0 && restItems === void 0 && arr.length === 0) return null;
665
+ const restCount = restItems !== void 0 ? Math.max(arr.length - prefixItems.length, 0) : 0;
666
+ return /* @__PURE__ */ jsxs("div", {
664
667
  role: "group",
665
668
  "aria-label": props.meta.description ?? void 0,
666
- children: prefixItems.map((element, i) => {
669
+ children: [prefixItems.map((element, i) => {
667
670
  const itemValue = arr[i];
668
671
  const childOnChange = (v) => {
669
672
  const next = arr.slice();
@@ -671,7 +674,16 @@ function renderTuple(props) {
671
674
  props.onChange(next);
672
675
  };
673
676
  return /* @__PURE__ */ jsx("div", { children: toReactNode(props.renderChild(element, itemValue, childOnChange, `[${String(i)}]`)) }, String(i));
674
- })
677
+ }), restItems !== void 0 && Array.from({ length: restCount }, (_, j) => {
678
+ const i = prefixItems.length + j;
679
+ const itemValue = arr[i];
680
+ const childOnChange = (v) => {
681
+ const next = arr.slice();
682
+ next[i] = v;
683
+ props.onChange(next);
684
+ };
685
+ return /* @__PURE__ */ jsx("div", { children: toReactNode(props.renderChild(restItems, itemValue, childOnChange, `[${String(i)}]`)) }, `rest-${String(i)}`);
686
+ })]
675
687
  });
676
688
  }
677
689
  /**
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "./diagnostics-VgEKI_Ct.mjs";
1
+ import { i as DiagnosticsOptions } from "./diagnostics-CbBPsxSt.mjs";
2
2
 
3
3
  //#region src/core/ref.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { D as StringConstraints, M as WalkedField, T as SchemaMeta, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "./types-D_5ST7SS.mjs";
1
+ import { D as StringConstraints, M as WalkedField, T as SchemaMeta, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "./types-C9zw9wbX.mjs";
2
2
 
3
3
  //#region src/core/renderer.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
1
+ import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
2
2
 
3
3
  //#region src/themes/mantine.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
1
+ import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
2
2
 
3
3
  //#region src/themes/mui.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
1
+ import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
2
2
 
3
3
  //#region src/themes/radix.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { r as ComponentResolver } from "../renderer-BQqiXUYP.mjs";
1
+ import { r as ComponentResolver } from "../renderer-SOIbJBtk.mjs";
2
2
 
3
3
  //#region src/themes/shadcn.d.ts
4
4
  declare const shadcnResolver: ComponentResolver;