schema-components 1.13.0 → 1.15.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 (71) hide show
  1. package/README.md +4 -0
  2. package/dist/core/adapter.d.mts +8 -3
  3. package/dist/core/adapter.mjs +25 -10
  4. package/dist/core/constraints.d.mts +3 -2
  5. package/dist/core/constraints.mjs +14 -2
  6. package/dist/core/diagnostics.d.mts +2 -0
  7. package/dist/core/diagnostics.mjs +33 -0
  8. package/dist/core/errors.d.mts +1 -1
  9. package/dist/core/formats.d.mts +33 -0
  10. package/dist/core/formats.mjs +67 -0
  11. package/dist/core/merge.d.mts +17 -1
  12. package/dist/core/merge.mjs +30 -1
  13. package/dist/core/normalise.d.mts +3 -2
  14. package/dist/core/normalise.mjs +1 -170
  15. package/dist/core/openapi30.d.mts +4 -1
  16. package/dist/core/openapi30.mjs +1 -222
  17. package/dist/core/ref.d.mts +2 -25
  18. package/dist/core/ref.mjs +102 -23
  19. package/dist/core/renderer.d.mts +1 -1
  20. package/dist/core/swagger2.d.mts +2 -1
  21. package/dist/core/swagger2.mjs +1 -293
  22. package/dist/core/typeInference.d.mts +2 -2
  23. package/dist/core/types.d.mts +2 -2
  24. package/dist/core/types.mjs +4 -1
  25. package/dist/core/version.d.mts +2 -2
  26. package/dist/core/version.mjs +84 -12
  27. package/dist/core/walkBuilders.d.mts +15 -1
  28. package/dist/core/walkBuilders.mjs +1 -1
  29. package/dist/core/walker.d.mts +1 -1
  30. package/dist/core/walker.mjs +122 -22
  31. package/dist/diagnostics-DzbZmcLI.d.mts +64 -0
  32. package/dist/html/a11y.d.mts +2 -2
  33. package/dist/html/renderToHtml.d.mts +2 -2
  34. package/dist/html/renderToHtmlStream.d.mts +2 -2
  35. package/dist/html/renderers.d.mts +2 -2
  36. package/dist/html/streamRenderers.d.mts +2 -2
  37. package/dist/normalise-tL9FckAk.mjs +748 -0
  38. package/dist/openapi/ApiCallbacks.d.mts +16 -0
  39. package/dist/openapi/ApiCallbacks.mjs +34 -0
  40. package/dist/openapi/ApiLinks.d.mts +16 -0
  41. package/dist/openapi/ApiLinks.mjs +42 -0
  42. package/dist/openapi/ApiResponseHeaders.d.mts +16 -0
  43. package/dist/openapi/ApiResponseHeaders.mjs +35 -0
  44. package/dist/openapi/ApiSecurity.d.mts +19 -0
  45. package/dist/openapi/ApiSecurity.mjs +33 -0
  46. package/dist/openapi/bundle.d.mts +47 -0
  47. package/dist/openapi/bundle.mjs +95 -0
  48. package/dist/openapi/components.d.mts +7 -2
  49. package/dist/openapi/components.mjs +30 -6
  50. package/dist/openapi/parser.d.mts +1 -1
  51. package/dist/react/SchemaComponent.d.mts +12 -5
  52. package/dist/react/SchemaComponent.mjs +13 -7
  53. package/dist/react/SchemaView.d.mts +10 -3
  54. package/dist/react/SchemaView.mjs +13 -7
  55. package/dist/react/fieldPath.d.mts +1 -1
  56. package/dist/react/headless.d.mts +1 -1
  57. package/dist/react/headlessRenderers.d.mts +1 -1
  58. package/dist/react/headlessRenderers.mjs +1 -1
  59. package/dist/ref-DvWoULcy.d.mts +44 -0
  60. package/dist/{renderer-DseHeliw.d.mts → renderer-BdSqllx5.d.mts} +1 -1
  61. package/dist/themes/mantine.d.mts +1 -1
  62. package/dist/themes/mui.d.mts +1 -1
  63. package/dist/themes/mui.mjs +1 -1
  64. package/dist/themes/radix.d.mts +1 -1
  65. package/dist/themes/shadcn.d.mts +1 -1
  66. package/dist/{typeInference-CRPqVwKu.d.mts → typeInference-k7FXfTVO.d.mts} +44 -8
  67. package/dist/{types-ag2jYLqQ.d.mts → types-D_5ST7SS.d.mts} +11 -3
  68. package/dist/version-B5NV-35j.d.mts +69 -0
  69. package/package.json +1 -1
  70. package/dist/version-CLchheaH.d.mts +0 -40
  71. /package/dist/{errors-DIKI2C78.d.mts → errors-C5zRC2PU.d.mts} +0 -0
@@ -1,19 +1,63 @@
1
1
  import { isObject } from "./guards.mjs";
2
- import { resolveRef } from "./ref.mjs";
2
+ import { appendPointer, emitDiagnostic } from "./diagnostics.mjs";
3
+ import { countDistinctRefs, resolveRef } from "./ref.mjs";
3
4
  import { extractArrayConstraints, extractObjectConstraints, stripInapplicableConstraints } from "./constraints.mjs";
4
- import { detectDiscriminated, mergeAllOf, normaliseAnyOf } from "./merge.mjs";
5
+ import { ANNOTATION_SIBLINGS, detectDiscriminated, mergeAllOf, mergeRefSiblings, normaliseAnyOf } from "./merge.mjs";
5
6
  import { buildBase, buildBooleanField, buildFileField, buildNullField, buildNumberField, buildStringField, buildUnknownField, extractChildOverride, extractSchemaMetaFields, getArray, getObject, getString, isPrimitive, walkDependentRequiredMap, walkSubSchemaMap, withoutKeys } from "./walkBuilders.mjs";
6
7
  //#region src/core/walker.ts
8
+ /**
9
+ * Handle JSON Schema boolean values (Draft 06+).
10
+ * - `true` → permissive (unknown, editable)
11
+ * - `false` → never (cannot hold any value)
12
+ */
13
+ function walkBooleanSchema(value) {
14
+ if (value) return {
15
+ type: "unknown",
16
+ editability: "editable",
17
+ meta: {},
18
+ constraints: {}
19
+ };
20
+ return {
21
+ type: "never",
22
+ editability: "presentation",
23
+ meta: { rejected: true },
24
+ constraints: {}
25
+ };
26
+ }
27
+ /**
28
+ * Walk a sub-schema that may be an object, a boolean, or neither.
29
+ * Dispatches to walkNode (object), walkBooleanSchema (boolean),
30
+ * or returns unknown with a diagnostic.
31
+ */
32
+ function walkSubSchema(value, ctx) {
33
+ if (isObject(value)) return walkNode(value, ctx);
34
+ if (typeof value === "boolean") return walkBooleanSchema(value);
35
+ return {
36
+ type: "unknown",
37
+ editability: "editable",
38
+ meta: {},
39
+ constraints: {}
40
+ };
41
+ }
7
42
  function walk(schema, options = {}) {
8
- const { componentMeta, rootMeta, fieldOverrides, rootDocument } = options;
43
+ const { componentMeta, rootMeta, fieldOverrides, rootDocument, diagnostics, externalResolver } = options;
44
+ if (typeof schema === "boolean") return walkBooleanSchema(schema);
9
45
  if (!isObject(schema)) return {
10
46
  type: "unknown",
11
47
  editability: "editable",
12
48
  meta: {},
13
49
  constraints: {}
14
50
  };
51
+ const topRef = typeof schema.$ref === "string" ? schema.$ref : void 0;
52
+ if (topRef !== void 0 && !topRef.startsWith("#")) emitDiagnostic(diagnostics, {
53
+ code: "external-ref",
54
+ message: `External $ref not supported: ${topRef}`,
55
+ pointer: "",
56
+ detail: { ref: topRef }
57
+ });
15
58
  const doc = rootDocument ?? schema;
16
- return walkNode(resolveRef(schema, doc, /* @__PURE__ */ new Set()), {
59
+ const maxRefDepth = countDistinctRefs(doc);
60
+ return walkNode(resolveRef(schema, doc, /* @__PURE__ */ new Set(), diagnostics, maxRefDepth, externalResolver), {
17
61
  componentMeta,
18
62
  rootMeta,
19
63
  fieldOverrides,
@@ -21,7 +65,11 @@ function walk(schema, options = {}) {
21
65
  isNullable: false,
22
66
  isOptional: false,
23
67
  defaultValue: void 0,
24
- refResults: /* @__PURE__ */ new Map()
68
+ refResults: /* @__PURE__ */ new Map(),
69
+ pointer: "",
70
+ diagnostics,
71
+ maxRefDepth,
72
+ externalResolver
25
73
  });
26
74
  }
27
75
  function walkNode(schema, ctx) {
@@ -46,7 +94,8 @@ function walkNode(schema, ctx) {
46
94
  if (ref !== void 0) {
47
95
  const cached = ctx.refResults.get(ref);
48
96
  if (cached !== void 0) return cached;
49
- const resolved = resolveRef(schema, ctx.rootDocument, /* @__PURE__ */ new Set());
97
+ const hasSiblings = [...ANNOTATION_SIBLINGS].some((k) => k in schema);
98
+ const resolved = resolveRef(schema, ctx.rootDocument, /* @__PURE__ */ new Set(), ctx.diagnostics, ctx.maxRefDepth, ctx.externalResolver);
50
99
  const placeholder = {
51
100
  type: "unknown",
52
101
  editability: "editable",
@@ -54,12 +103,21 @@ function walkNode(schema, ctx) {
54
103
  constraints: {}
55
104
  };
56
105
  ctx.refResults.set(ref, placeholder);
57
- const result = walkNode(resolved, ctx);
106
+ let result = walkNode(resolved, ctx);
107
+ if (hasSiblings) result = {
108
+ ...result,
109
+ meta: mergeRefSiblings(schema, result.meta)
110
+ };
58
111
  Object.assign(placeholder, result);
59
112
  return placeholder;
60
113
  }
61
114
  const ifSchema = getObject(schema, "if");
62
115
  if (ifSchema !== void 0) {
116
+ emitDiagnostic(ctx.diagnostics, {
117
+ code: "conditional-fallback",
118
+ message: "if/then/else rendered as base schema; conditionals require runtime evaluation",
119
+ pointer: ctx.pointer
120
+ });
63
121
  const base = buildBase(withoutKeys(schema, [
64
122
  "if",
65
123
  "then",
@@ -78,15 +136,30 @@ function walkNode(schema, ctx) {
78
136
  return conditional;
79
137
  }
80
138
  const notSchema = getObject(schema, "not");
81
- if (notSchema !== void 0) return {
82
- ...buildBase(withoutKeys(schema, ["not"]), ctx),
83
- type: "negation",
84
- constraints: {},
85
- negated: walkNode(notSchema, ctx)
86
- };
139
+ if (notSchema !== void 0) {
140
+ emitDiagnostic(ctx.diagnostics, {
141
+ code: "type-negation-fallback",
142
+ message: "not schema rendered as negation; TypeScript cannot negate types",
143
+ pointer: ctx.pointer
144
+ });
145
+ return {
146
+ ...buildBase(withoutKeys(schema, ["not"]), ctx),
147
+ type: "negation",
148
+ constraints: {},
149
+ negated: walkNode(notSchema, ctx)
150
+ };
151
+ }
87
152
  const enumValues = getArray(schema, "enum");
88
153
  if (enumValues !== void 0) return walkEnum(schema, enumValues, ctx);
89
- if ("const" in schema) return walkLiteral(schema, ctx);
154
+ if ("const" in schema) {
155
+ if (!isPrimitive(schema.const)) emitDiagnostic(ctx.diagnostics, {
156
+ code: "invalid-const",
157
+ message: `const value is not a primitive: ${typeof schema.const}`,
158
+ pointer: ctx.pointer,
159
+ detail: { constValue: schema.const }
160
+ });
161
+ return walkLiteral(schema, ctx);
162
+ }
90
163
  const type = getString(schema, "type");
91
164
  const typeArray = getArray(schema, "type");
92
165
  if (type === void 0 && typeArray !== void 0) {
@@ -115,7 +188,14 @@ function walkNode(schema, ctx) {
115
188
  });
116
189
  return walkUnion(options, ctx);
117
190
  }
118
- if (type === void 0) return buildUnknownField(schema, ctx);
191
+ if (type === void 0) {
192
+ emitDiagnostic(ctx.diagnostics, {
193
+ code: "unsupported-type",
194
+ message: "Schema has no type, composition, enum, or const; rendering as unknown",
195
+ pointer: ctx.pointer
196
+ });
197
+ return buildUnknownField(schema, ctx);
198
+ }
119
199
  if (type === "string") return walkString(schema, ctx);
120
200
  if (type === "number" || type === "integer") return walkNumber(schema, ctx);
121
201
  if (type === "boolean") return walkBoolean(schema, ctx);
@@ -134,11 +214,20 @@ function walkNode(schema, ctx) {
134
214
  };
135
215
  }
136
216
  if (type === "array") return walkArray(schema, ctx);
217
+ emitDiagnostic(ctx.diagnostics, {
218
+ code: "unsupported-type",
219
+ message: `Unknown schema type: ${type}`,
220
+ pointer: ctx.pointer,
221
+ detail: { type }
222
+ });
137
223
  return buildUnknownField(schema, ctx);
138
224
  }
139
225
  function walkString(schema, ctx) {
140
226
  if (getString(schema, "format") === "binary") return buildFileField(schema, ctx);
141
- return buildStringField(schema, ctx);
227
+ const field = buildStringField(schema, ctx);
228
+ const contentSchema = getObject(schema, "contentSchema");
229
+ if (contentSchema !== void 0) field.meta.decodedSchema = walkNode(contentSchema, ctx);
230
+ return field;
142
231
  }
143
232
  function walkNumber(schema, ctx) {
144
233
  return buildNumberField(schema, ctx);
@@ -173,11 +262,13 @@ function walkObject(schema, properties, ctx) {
173
262
  const childCtx = {
174
263
  ...ctx,
175
264
  fieldOverrides: childOverride,
176
- isOptional: !isRequired
265
+ isOptional: !isRequired,
266
+ pointer: appendPointer(ctx.pointer, key)
177
267
  };
178
268
  const overrideMeta = extractSchemaMetaFields(childOverride);
179
269
  if (overrideMeta !== void 0 && ("readOnly" in overrideMeta || "writeOnly" in overrideMeta)) childCtx.componentMeta = void 0;
180
270
  if (isObject(propSchema)) fields[key] = walkNode(propSchema, childCtx);
271
+ else if (typeof propSchema === "boolean") fields[key] = walkBooleanSchema(propSchema);
181
272
  else fields[key] = {
182
273
  type: "unknown",
183
274
  editability: "editable",
@@ -191,6 +282,12 @@ function walkObject(schema, properties, ctx) {
191
282
  let additionalPropertiesSchema;
192
283
  const additionalProps = schema.additionalProperties;
193
284
  if (additionalProps === false) additionalPropertiesClosed = true;
285
+ else if (additionalProps === true) additionalPropertiesSchema = {
286
+ type: "unknown",
287
+ editability: "editable",
288
+ meta: {},
289
+ constraints: {}
290
+ };
194
291
  else if (isObject(additionalProps)) additionalPropertiesSchema = walkNode(additionalProps, ctx);
195
292
  const depSchemas = getObject(schema, "dependentSchemas");
196
293
  const walkedDepSchemas = depSchemas !== void 0 ? walkSubSchemaMap(depSchemas, walkNode, ctx) : void 0;
@@ -200,6 +297,12 @@ function walkObject(schema, properties, ctx) {
200
297
  let unevaluatedPropertiesClosed;
201
298
  const unevalProps = schema.unevaluatedProperties;
202
299
  if (unevalProps === false) unevaluatedPropertiesClosed = true;
300
+ else if (unevalProps === true) unevaluatedProperties = {
301
+ type: "unknown",
302
+ editability: "editable",
303
+ meta: {},
304
+ constraints: {}
305
+ };
203
306
  else if (isObject(unevalProps)) unevaluatedProperties = walkNode(unevalProps, ctx);
204
307
  const propertyNamesSchema = getObject(schema, "propertyNames");
205
308
  const walkedPropertyNames = propertyNamesSchema !== void 0 ? walkNode(propertyNamesSchema, ctx) : void 0;
@@ -271,15 +374,12 @@ function walkArray(schema, ctx) {
271
374
  };
272
375
  }
273
376
  function walkUnion(options, ctx) {
274
- const optionsArray = options.filter(isObject);
377
+ const walkedOptions = options.map((opt) => walkSubSchema(opt, ctx));
275
378
  return {
276
379
  ...buildBase({}, ctx),
277
380
  type: "union",
278
381
  constraints: {},
279
- options: optionsArray.map((opt) => walkNode(opt, {
280
- ...ctx,
281
- fieldOverrides: void 0
282
- }))
382
+ options: walkedOptions
283
383
  };
284
384
  }
285
385
  function walkDiscriminatedUnion(discriminated, ctx) {
@@ -0,0 +1,64 @@
1
+ //#region src/core/diagnostics.d.ts
2
+ /**
3
+ * Diagnostics channel for schema-components.
4
+ *
5
+ * Provides a structured way to surface silent fallbacks — unresolved `$ref`,
6
+ * unknown keywords, unknown `format` values, invalid `const` values,
7
+ * unsupported `type` entries, dropped Swagger 2.0 features, external
8
+ * `$ref`, type-negation fallbacks, and conditional fallbacks.
9
+ *
10
+ * Consumers pass a `DiagnosticSink` callback to receive diagnostics
11
+ * as they occur. By default, diagnostics are silently discarded.
12
+ * Setting `strict: true` converts any diagnostic into a thrown
13
+ * `SchemaCompatibilityError`.
14
+ */
15
+ /**
16
+ * Machine-readable codes identifying each class of diagnostic.
17
+ * Stable across releases — consumers can pattern-match on these.
18
+ */
19
+ type DiagnosticCode = "unresolved-ref" | "unknown-keyword" | "unknown-format" | "invalid-const" | "unsupported-type" | "dropped-swagger-feature" | "external-ref" | "type-negation-fallback" | "conditional-fallback" | "assumed-draft" | "depth-exceeded";
20
+ /**
21
+ * A single diagnostic emitted during schema processing.
22
+ */
23
+ interface Diagnostic {
24
+ /** Machine-readable code for programmatic handling. */
25
+ code: DiagnosticCode;
26
+ /** Human-readable description of the issue. */
27
+ message: string;
28
+ /** JSON Pointer to the schema node that triggered the diagnostic. */
29
+ pointer: string;
30
+ /** Additional context specific to the diagnostic code. */
31
+ detail?: Record<string, unknown>;
32
+ }
33
+ /**
34
+ * Callback that receives each diagnostic as it is emitted.
35
+ */
36
+ type DiagnosticSink = (d: Diagnostic) => void;
37
+ /**
38
+ * Diagnostics configuration threaded through the processing pipeline.
39
+ */
40
+ interface DiagnosticsOptions {
41
+ /**
42
+ * Callback for receiving diagnostics. When omitted, diagnostics
43
+ * are silently discarded (preserving backward compatibility).
44
+ */
45
+ diagnostics?: DiagnosticSink;
46
+ /**
47
+ * When `true`, any diagnostic is converted to a thrown
48
+ * `SchemaCompatibilityError`. Useful in CI or strict mode
49
+ * to catch schema drift early.
50
+ */
51
+ strict?: boolean;
52
+ }
53
+ /**
54
+ * Emit a diagnostic through the configured sink.
55
+ * When `strict` is enabled, throws a `SchemaCompatibilityError` instead.
56
+ */
57
+ declare function emitDiagnostic(opts: DiagnosticsOptions | undefined, diagnostic: Diagnostic): void;
58
+ /**
59
+ * Append a segment to a JSON Pointer.
60
+ * Encodes `/` and `~` per RFC 6901.
61
+ */
62
+ declare function appendPointer(base: string, segment: string): string;
63
+ //#endregion
64
+ export { appendPointer as a, DiagnosticsOptions as i, DiagnosticCode as n, emitDiagnostic as o, DiagnosticSink as r, Diagnostic as t };
@@ -1,5 +1,5 @@
1
- import { j as WalkedField } from "../types-ag2jYLqQ.mjs";
2
- import { t as AllConstraints } from "../renderer-DseHeliw.mjs";
1
+ import { M as WalkedField } from "../types-D_5ST7SS.mjs";
2
+ import { t as AllConstraints } from "../renderer-BdSqllx5.mjs";
3
3
  import { HtmlAttributes, HtmlNode } from "./html.mjs";
4
4
 
5
5
  //#region src/html/a11y.d.ts
@@ -1,5 +1,5 @@
1
- import { w as SchemaMeta } from "../types-ag2jYLqQ.mjs";
2
- import { o as HtmlResolver } from "../renderer-DseHeliw.mjs";
1
+ import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
+ import { o as HtmlResolver } from "../renderer-BdSqllx5.mjs";
3
3
 
4
4
  //#region src/html/renderToHtml.d.ts
5
5
  interface RenderToHtmlOptions {
@@ -1,5 +1,5 @@
1
- import { w as SchemaMeta } from "../types-ag2jYLqQ.mjs";
2
- import { o as HtmlResolver } from "../renderer-DseHeliw.mjs";
1
+ import { T as SchemaMeta } from "../types-D_5ST7SS.mjs";
2
+ import { o as HtmlResolver } from "../renderer-BdSqllx5.mjs";
3
3
 
4
4
  //#region src/html/renderToHtmlStream.d.ts
5
5
  interface StreamRenderOptions {
@@ -1,5 +1,5 @@
1
- import { j as WalkedField } from "../types-ag2jYLqQ.mjs";
2
- import { o as HtmlResolver } from "../renderer-DseHeliw.mjs";
1
+ import { M as WalkedField } from "../types-D_5ST7SS.mjs";
2
+ import { o as HtmlResolver } from "../renderer-BdSqllx5.mjs";
3
3
 
4
4
  //#region src/html/renderers.d.ts
5
5
  declare function dateInputType(format: string | undefined): string | undefined;
@@ -1,5 +1,5 @@
1
- import { j as WalkedField } from "../types-ag2jYLqQ.mjs";
2
- import { o as HtmlResolver } from "../renderer-DseHeliw.mjs";
1
+ import { M as WalkedField } from "../types-D_5ST7SS.mjs";
2
+ import { o as HtmlResolver } from "../renderer-BdSqllx5.mjs";
3
3
  import { HtmlElement } from "./html.mjs";
4
4
 
5
5
  //#region src/html/streamRenderers.d.ts