schema-components 1.21.0 → 1.23.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.
- package/README.md +3 -1
- package/dist/core/adapter.d.mts +115 -4
- package/dist/core/adapter.mjs +405 -75
- package/dist/core/constraints.d.mts +2 -2
- package/dist/core/constraints.mjs +0 -7
- package/dist/core/cssClasses.d.mts +52 -0
- package/dist/core/cssClasses.mjs +51 -0
- package/dist/core/diagnostics.d.mts +1 -1
- package/dist/core/errors.d.mts +1 -1
- package/dist/core/errors.mjs +5 -13
- package/dist/core/fieldOrder.d.mts +1 -1
- package/dist/core/formats.d.mts +30 -2
- package/dist/core/formats.mjs +33 -1
- package/dist/core/idPath.d.mts +54 -0
- package/dist/core/idPath.mjs +66 -0
- package/dist/core/limits.d.mts +2 -0
- package/dist/core/limits.mjs +23 -0
- package/dist/core/merge.d.mts +10 -1
- package/dist/core/merge.mjs +49 -10
- package/dist/core/normalise.d.mts +40 -3
- package/dist/core/normalise.mjs +2 -2
- package/dist/core/openapi30.d.mts +15 -1
- package/dist/core/openapi30.mjs +2 -2
- package/dist/core/openapiConstants.d.mts +67 -0
- package/dist/core/openapiConstants.mjs +90 -0
- package/dist/core/ref.d.mts +2 -2
- package/dist/core/ref.mjs +85 -6
- package/dist/core/refChain.d.mts +70 -0
- package/dist/core/refChain.mjs +44 -0
- package/dist/core/renderer.d.mts +1 -1
- package/dist/core/renderer.mjs +0 -2
- package/dist/core/swagger2.d.mts +1 -1
- package/dist/core/swagger2.mjs +1 -1
- package/dist/core/typeInference.d.mts +982 -2
- package/dist/core/types.d.mts +2 -2
- package/dist/core/types.mjs +1 -4
- package/dist/core/unionMatch.d.mts +36 -0
- package/dist/core/unionMatch.mjs +53 -0
- package/dist/core/version.d.mts +1 -1
- package/dist/core/version.mjs +29 -17
- package/dist/core/walkBuilders.d.mts +23 -4
- package/dist/core/walkBuilders.mjs +27 -7
- package/dist/core/walker.d.mts +1 -1
- package/dist/core/walker.mjs +123 -47
- package/dist/{diagnostics-CbBPsxSt.d.mts → diagnostics-BS2kaUyE.d.mts} +1 -1
- package/dist/{errors-QEwOtQAA.d.mts → errors-g_MCTQel.d.mts} +10 -16
- package/dist/html/a11y.d.mts +9 -4
- package/dist/html/a11y.mjs +10 -12
- package/dist/html/renderToHtml.d.mts +10 -3
- package/dist/html/renderToHtml.mjs +13 -3
- package/dist/html/renderToHtmlStream.d.mts +2 -2
- package/dist/html/renderToHtmlStream.mjs +12 -1
- package/dist/html/renderers.d.mts +43 -8
- package/dist/html/renderers.mjs +136 -116
- package/dist/html/streamRenderers.d.mts +6 -6
- package/dist/html/streamRenderers.mjs +129 -89
- package/dist/limits-Cw5QZND8.d.mts +29 -0
- package/dist/{normalise-DaSrnr8g.mjs → normalise-DCYp06Sr.mjs} +770 -227
- package/dist/openapi/ApiCallbacks.d.mts +1 -1
- package/dist/openapi/ApiLinks.d.mts +1 -1
- package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
- package/dist/openapi/ApiSecurity.d.mts +1 -1
- package/dist/openapi/ApiSecurity.mjs +16 -2
- package/dist/openapi/components.d.mts +234 -23
- package/dist/openapi/components.mjs +183 -52
- package/dist/openapi/parser.d.mts +9 -8
- package/dist/openapi/parser.mjs +252 -70
- package/dist/openapi/resolve.d.mts +31 -15
- package/dist/openapi/resolve.mjs +260 -40
- package/dist/react/SchemaComponent.d.mts +126 -36
- package/dist/react/SchemaComponent.mjs +95 -57
- package/dist/react/SchemaView.d.mts +30 -10
- package/dist/react/SchemaView.mjs +2 -2
- package/dist/react/a11y.d.mts +21 -0
- package/dist/react/a11y.mjs +24 -0
- package/dist/react/fieldPath.d.mts +1 -1
- package/dist/react/headless.d.mts +1 -1
- package/dist/react/headless.mjs +1 -2
- package/dist/react/headlessRenderers.d.mts +9 -11
- package/dist/react/headlessRenderers.mjs +51 -102
- package/dist/{ref-si8ViYun.d.mts → ref-DjLEKa_E.d.mts} +38 -3
- package/dist/{renderer-DI6ZYf7a.d.mts → renderer-CXJ8y0qw.d.mts} +2 -2
- package/dist/themes/mantine.d.mts +1 -1
- package/dist/themes/mui.d.mts +1 -1
- package/dist/themes/radix.d.mts +1 -1
- package/dist/themes/shadcn.d.mts +1 -1
- package/dist/themes/shadcn.mjs +2 -1
- package/dist/{types-BnxPEElk.d.mts → types-BTB73MB8.d.mts} +35 -14
- package/dist/{version-D-u7aMfy.d.mts → version-BFTVLsdb.d.mts} +7 -1
- package/package.json +1 -3
- package/dist/typeInference-Bxw3NOG1.d.mts +0 -647
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { isObject } from "../core/guards.mjs";
|
|
2
|
+
import "../core/limits.mjs";
|
|
3
|
+
import { emitDiagnostic } from "../core/diagnostics.mjs";
|
|
4
|
+
import { SC_CLASSES } from "../core/cssClasses.mjs";
|
|
2
5
|
import { getHtmlRenderFn } from "../core/renderer.mjs";
|
|
6
|
+
import { matchUnionOption, resolveDiscriminatedActive } from "../core/unionMatch.mjs";
|
|
3
7
|
import { VOID_ELEMENTS, h, raw, serialize, serializeAttributes } from "./html.mjs";
|
|
4
|
-
import { ariaLabelAttrs, buildHintElement, buildInputId, requiredIndicator } from "./a11y.mjs";
|
|
8
|
+
import { ariaLabelAttrs, buildHintElement, buildInputId, joinPath, requiredIndicator } from "./a11y.mjs";
|
|
9
|
+
import { panelId, tabId } from "./renderers.mjs";
|
|
10
|
+
import { recursionSentinelHtml } from "./renderToHtml.mjs";
|
|
5
11
|
//#region src/html/streamRenderers.ts
|
|
6
12
|
function yieldOpen(el) {
|
|
7
13
|
const attrStr = serializeAttributes(el.attributes);
|
|
8
|
-
if (
|
|
14
|
+
if (VOID_ELEMENTS.has(el.tag)) return `<${el.tag}${attrStr} />`;
|
|
9
15
|
return `<${el.tag}${attrStr}>`;
|
|
10
16
|
}
|
|
11
17
|
function yieldClose(el) {
|
|
@@ -24,20 +30,32 @@ function renderLeaf(tree, value, mergedResolver, path) {
|
|
|
24
30
|
tree,
|
|
25
31
|
renderChild: () => ""
|
|
26
32
|
});
|
|
27
|
-
if (value === void 0 || value === null) return serialize(h("span", { class:
|
|
28
|
-
return serialize(h("span", { class:
|
|
33
|
+
if (value === void 0 || value === null) return serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
|
|
34
|
+
return serialize(h("span", { class: SC_CLASSES.value }, typeof value === "string" ? value : JSON.stringify(value)));
|
|
29
35
|
}
|
|
30
|
-
function renderFieldSync(tree, value, mergedResolver, path, rawResolver) {
|
|
31
|
-
return [...streamField(tree, value, mergedResolver, path, rawResolver)].join("");
|
|
36
|
+
function renderFieldSync(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
|
|
37
|
+
return [...streamField(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics)].join("");
|
|
32
38
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
+
/**
|
|
40
|
+
* Build a visible placeholder element used when a value does not match
|
|
41
|
+
* the shape implied by its field type. The expected-shape label is
|
|
42
|
+
* passed verbatim into `h()` so the serialiser escapes it.
|
|
43
|
+
*
|
|
44
|
+
* Streaming must keep producing output, so we never throw here — the
|
|
45
|
+
* diagnostic surfaces the problem to the caller (when a sink is wired)
|
|
46
|
+
* while the rendered output remains structurally valid.
|
|
47
|
+
*/
|
|
48
|
+
function typeMismatchPlaceholder(expectedShape) {
|
|
49
|
+
return serialize(h("span", {
|
|
50
|
+
class: "sc-value sc-value--invalid",
|
|
51
|
+
role: "alert"
|
|
52
|
+
}, `invalid value (expected ${expectedShape})`));
|
|
39
53
|
}
|
|
40
|
-
function* streamField(tree, value, mergedResolver, path, rawResolver) {
|
|
54
|
+
function* streamField(tree, value, mergedResolver, path, rawResolver, currentDepth = 0, diagnostics) {
|
|
55
|
+
if (currentDepth >= 10) {
|
|
56
|
+
yield recursionSentinelHtml(typeof tree.meta.description === "string" ? tree.meta.description : "schema");
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
41
59
|
const effectiveValue = value ?? tree.defaultValue;
|
|
42
60
|
const type = tree.type;
|
|
43
61
|
if (type === "string" || type === "number" || type === "boolean" || type === "enum" || type === "literal" || type === "file" || type === "unknown") {
|
|
@@ -45,36 +63,50 @@ function* streamField(tree, value, mergedResolver, path, rawResolver) {
|
|
|
45
63
|
return;
|
|
46
64
|
}
|
|
47
65
|
if (type === "union") {
|
|
48
|
-
yield* streamUnion(tree, effectiveValue, mergedResolver, path, rawResolver);
|
|
66
|
+
yield* streamUnion(tree, effectiveValue, mergedResolver, path, rawResolver, currentDepth, diagnostics);
|
|
49
67
|
return;
|
|
50
68
|
}
|
|
51
69
|
if (type === "discriminatedUnion") {
|
|
52
|
-
yield* streamDiscriminatedUnion(tree, value, mergedResolver, path, rawResolver);
|
|
70
|
+
yield* streamDiscriminatedUnion(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics);
|
|
53
71
|
return;
|
|
54
72
|
}
|
|
55
73
|
if (type === "object") {
|
|
56
|
-
yield* streamObject(tree, value, mergedResolver, path, rawResolver);
|
|
74
|
+
yield* streamObject(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics);
|
|
57
75
|
return;
|
|
58
76
|
}
|
|
59
77
|
if (type === "array") {
|
|
60
|
-
yield* streamArray(tree, value, mergedResolver, path, rawResolver);
|
|
78
|
+
yield* streamArray(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics);
|
|
61
79
|
return;
|
|
62
80
|
}
|
|
63
81
|
if (type === "record") {
|
|
64
|
-
yield* streamRecord(tree, value, mergedResolver, path, rawResolver);
|
|
82
|
+
yield* streamRecord(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics);
|
|
65
83
|
return;
|
|
66
84
|
}
|
|
67
85
|
yield renderLeaf(tree, value, mergedResolver, path);
|
|
68
86
|
}
|
|
69
|
-
function* streamObject(tree, value, mergedResolver, path, rawResolver) {
|
|
87
|
+
function* streamObject(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
|
|
70
88
|
if (tree.type !== "object") return;
|
|
71
89
|
const fields = tree.fields;
|
|
90
|
+
if (value !== void 0 && value !== null && !isObject(value)) {
|
|
91
|
+
emitDiagnostic(diagnostics, {
|
|
92
|
+
code: "type-mismatch",
|
|
93
|
+
message: "Object schema received non-object value during streaming render",
|
|
94
|
+
pointer: path === "" ? "/" : `/${path}`,
|
|
95
|
+
detail: {
|
|
96
|
+
expected: "object",
|
|
97
|
+
actualType: typeof value,
|
|
98
|
+
path
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
yield typeMismatchPlaceholder("object");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
72
104
|
const obj = isObject(value) ? value : {};
|
|
73
105
|
const readOnly = tree.editability === "presentation";
|
|
74
106
|
const descriptionText = typeof tree.meta.description === "string" ? tree.meta.description : void 0;
|
|
75
107
|
const labelAttrs = ariaLabelAttrs(descriptionText);
|
|
76
108
|
if (readOnly) {
|
|
77
|
-
const dlAttrs = { class:
|
|
109
|
+
const dlAttrs = { class: SC_CLASSES.object };
|
|
78
110
|
Object.assign(dlAttrs, labelAttrs);
|
|
79
111
|
const dl = h("dl", dlAttrs);
|
|
80
112
|
const legend = descriptionText !== void 0 ? serialize(h("legend", {}, descriptionText)) : "";
|
|
@@ -82,12 +114,12 @@ function* streamObject(tree, value, mergedResolver, path, rawResolver) {
|
|
|
82
114
|
for (const [key, field] of Object.entries(fields)) {
|
|
83
115
|
const label = typeof field.meta.description === "string" ? field.meta.description : key;
|
|
84
116
|
const childValue = obj[key];
|
|
85
|
-
const childHtml = renderFieldSync(field, childValue, mergedResolver, key, rawResolver);
|
|
86
|
-
yield `${serialize(h("dt", { class:
|
|
117
|
+
const childHtml = renderFieldSync(field, childValue, mergedResolver, joinPath(path, key), rawResolver, currentDepth + 1, diagnostics);
|
|
118
|
+
yield `${serialize(h("dt", { class: SC_CLASSES.label }, label))}${serialize(h("dd", { class: SC_CLASSES.value }, raw(childHtml)))}`;
|
|
87
119
|
}
|
|
88
120
|
yield yieldClose(dl);
|
|
89
121
|
} else {
|
|
90
|
-
const fieldsetAttrs = { class:
|
|
122
|
+
const fieldsetAttrs = { class: SC_CLASSES.object };
|
|
91
123
|
Object.assign(fieldsetAttrs, labelAttrs);
|
|
92
124
|
const fieldset = h("fieldset", fieldsetAttrs);
|
|
93
125
|
const legend = descriptionText !== void 0 ? serialize(h("legend", {}, descriptionText)) : "";
|
|
@@ -96,137 +128,145 @@ function* streamObject(tree, value, mergedResolver, path, rawResolver) {
|
|
|
96
128
|
const label = typeof field.meta.description === "string" ? field.meta.description : key;
|
|
97
129
|
const fieldId = buildInputId(path, key);
|
|
98
130
|
const childValue = obj[key];
|
|
99
|
-
const childChunks = [...streamField(field, childValue, mergedResolver, key, rawResolver)].join("");
|
|
131
|
+
const childChunks = [...streamField(field, childValue, mergedResolver, joinPath(path, key), rawResolver, currentDepth + 1, diagnostics)].join("");
|
|
100
132
|
const required = requiredIndicator(field);
|
|
101
133
|
const labelContent = [label];
|
|
102
134
|
if (required !== void 0) labelContent.push(required);
|
|
103
135
|
const fieldChildren = [h("label", {
|
|
104
|
-
class:
|
|
136
|
+
class: SC_CLASSES.label,
|
|
105
137
|
for: fieldId
|
|
106
138
|
}, ...labelContent), raw(childChunks)];
|
|
107
139
|
const hint = buildHintElement(key, field.constraints);
|
|
108
140
|
if (hint !== void 0) fieldChildren.push(hint);
|
|
109
|
-
yield serialize(h("div", { class:
|
|
141
|
+
yield serialize(h("div", { class: SC_CLASSES.field }, ...fieldChildren));
|
|
110
142
|
}
|
|
111
143
|
yield yieldClose(fieldset);
|
|
112
144
|
}
|
|
113
145
|
}
|
|
114
|
-
function* streamArray(tree, value, mergedResolver, path, rawResolver) {
|
|
115
|
-
const arr = Array.isArray(value) ? value : [];
|
|
146
|
+
function* streamArray(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
|
|
116
147
|
if (tree.type !== "array") return;
|
|
117
148
|
const element = tree.element;
|
|
118
149
|
if (element === void 0) return;
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
150
|
+
if (value !== void 0 && value !== null && !Array.isArray(value)) {
|
|
151
|
+
emitDiagnostic(diagnostics, {
|
|
152
|
+
code: "type-mismatch",
|
|
153
|
+
message: "Array schema received non-array value during streaming render",
|
|
154
|
+
pointer: path === "" ? "/" : `/${path}`,
|
|
155
|
+
detail: {
|
|
156
|
+
expected: "array",
|
|
157
|
+
actualType: typeof value,
|
|
158
|
+
path
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
yield typeMismatchPlaceholder("array");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const arr = Array.isArray(value) ? value : [];
|
|
165
|
+
if (tree.editability === "presentation") {
|
|
166
|
+
const ul = h("ul", { class: SC_CLASSES.array });
|
|
123
167
|
yield yieldOpen(ul);
|
|
124
|
-
for (const item of arr) yield serialize(h("li", { class: "sc-item" }, raw(renderFieldSync(element, item, mergedResolver,
|
|
168
|
+
for (const [i, item] of arr.entries()) yield serialize(h("li", { class: "sc-item" }, raw(renderFieldSync(element, item, mergedResolver, joinPath(path, `[${String(i)}]`), rawResolver, currentDepth + 1, diagnostics))));
|
|
125
169
|
yield yieldClose(ul);
|
|
126
170
|
} else {
|
|
127
|
-
const div = h("div", { class:
|
|
171
|
+
const div = h("div", { class: SC_CLASSES.array });
|
|
128
172
|
yield yieldOpen(div);
|
|
129
|
-
for (const item of arr) yield serialize(h("div", {}, raw(renderFieldSync(element, item, mergedResolver,
|
|
173
|
+
for (const [i, item] of arr.entries()) yield serialize(h("div", {}, raw(renderFieldSync(element, item, mergedResolver, joinPath(path, `[${String(i)}]`), rawResolver, currentDepth + 1, diagnostics))));
|
|
130
174
|
yield yieldClose(div);
|
|
131
175
|
}
|
|
132
176
|
}
|
|
133
|
-
function* streamRecord(tree, value, mergedResolver, path, rawResolver) {
|
|
134
|
-
const obj = isObject(value) ? value : {};
|
|
177
|
+
function* streamRecord(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
|
|
135
178
|
if (tree.type !== "record") return;
|
|
136
179
|
const valueType = tree.valueType;
|
|
180
|
+
if (value !== void 0 && value !== null && !isObject(value)) {
|
|
181
|
+
emitDiagnostic(diagnostics, {
|
|
182
|
+
code: "type-mismatch",
|
|
183
|
+
message: "Record schema received non-object value during streaming render",
|
|
184
|
+
pointer: path === "" ? "/" : `/${path}`,
|
|
185
|
+
detail: {
|
|
186
|
+
expected: "object",
|
|
187
|
+
actualType: typeof value,
|
|
188
|
+
path
|
|
189
|
+
}
|
|
190
|
+
});
|
|
191
|
+
yield typeMismatchPlaceholder("object");
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
const obj = isObject(value) ? value : {};
|
|
137
195
|
const readOnly = tree.editability === "presentation";
|
|
138
196
|
const attrs = {
|
|
139
|
-
class:
|
|
197
|
+
class: SC_CLASSES.record,
|
|
140
198
|
role: "group"
|
|
141
199
|
};
|
|
142
200
|
if (readOnly) {
|
|
143
201
|
const dl = h("dl", attrs);
|
|
144
202
|
yield yieldOpen(dl);
|
|
145
203
|
for (const [key, val] of Object.entries(obj)) {
|
|
146
|
-
const childHtml = renderFieldSync(valueType, val, mergedResolver, key, rawResolver);
|
|
147
|
-
yield `${serialize(h("dt", { class:
|
|
204
|
+
const childHtml = renderFieldSync(valueType, val, mergedResolver, joinPath(path, key), rawResolver, currentDepth + 1, diagnostics);
|
|
205
|
+
yield `${serialize(h("dt", { class: SC_CLASSES.label }, key))}${serialize(h("dd", { class: SC_CLASSES.value }, raw(childHtml)))}`;
|
|
148
206
|
}
|
|
149
207
|
yield yieldClose(dl);
|
|
150
208
|
} else {
|
|
151
209
|
const container = h("div", attrs);
|
|
152
210
|
yield yieldOpen(container);
|
|
153
211
|
for (const [key, val] of Object.entries(obj)) {
|
|
154
|
-
const childHtml = renderFieldSync(valueType, val, mergedResolver, key, rawResolver);
|
|
155
|
-
yield serialize(h("div", { class:
|
|
212
|
+
const childHtml = renderFieldSync(valueType, val, mergedResolver, joinPath(path, key), rawResolver, currentDepth + 1, diagnostics);
|
|
213
|
+
yield serialize(h("div", { class: SC_CLASSES.field }, h("label", { class: SC_CLASSES.label }, key), raw(childHtml)));
|
|
156
214
|
}
|
|
157
215
|
yield yieldClose(container);
|
|
158
216
|
}
|
|
159
217
|
}
|
|
160
|
-
function* streamUnion(tree, value, mergedResolver, path, rawResolver) {
|
|
218
|
+
function* streamUnion(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
|
|
161
219
|
const options = tree.type === "union" ? tree.options : void 0;
|
|
162
220
|
if (options === void 0 || options.length === 0) {
|
|
163
|
-
if (value === void 0 || value === null) yield serialize(h("span", { class:
|
|
164
|
-
else yield serialize(h("span", { class:
|
|
221
|
+
if (value === void 0 || value === null) yield serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
|
|
222
|
+
else yield serialize(h("span", { class: SC_CLASSES.value }, JSON.stringify(value)));
|
|
165
223
|
return;
|
|
166
224
|
}
|
|
167
225
|
const target = matchUnionOption(options, value) ?? options[0];
|
|
168
|
-
if (target !== void 0) yield* streamField(target, value, mergedResolver,
|
|
169
|
-
else yield serialize(h("span", { class:
|
|
226
|
+
if (target !== void 0) yield* streamField(target, value, mergedResolver, path, rawResolver, currentDepth + 1, diagnostics);
|
|
227
|
+
else yield serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
|
|
170
228
|
}
|
|
171
|
-
function* streamDiscriminatedUnion(tree, value, mergedResolver, path, rawResolver) {
|
|
172
|
-
|
|
173
|
-
const
|
|
174
|
-
if (options
|
|
175
|
-
if (value === void 0 || value === null) yield serialize(h("span", { class:
|
|
176
|
-
else yield serialize(h("span", { class:
|
|
229
|
+
function* streamDiscriminatedUnion(tree, value, mergedResolver, path, rawResolver, currentDepth, diagnostics) {
|
|
230
|
+
if (tree.type !== "discriminatedUnion") return;
|
|
231
|
+
const { options, discriminator } = tree;
|
|
232
|
+
if (options.length === 0) {
|
|
233
|
+
if (value === void 0 || value === null) yield serialize(h("span", { class: SC_CLASSES.valueEmpty }, "—"));
|
|
234
|
+
else yield serialize(h("span", { class: SC_CLASSES.value }, JSON.stringify(value)));
|
|
177
235
|
return;
|
|
178
236
|
}
|
|
179
|
-
const
|
|
180
|
-
const obj = isRecord(value) ? value : {};
|
|
181
|
-
const discKey = discriminator ?? "";
|
|
182
|
-
const currentDiscriminatorValue = typeof obj[discKey] === "string" ? obj[discKey] : void 0;
|
|
183
|
-
const optionLabels = options.map((opt) => {
|
|
184
|
-
if (opt.type === "object") {
|
|
185
|
-
const discriminatorField = opt.fields[discKey];
|
|
186
|
-
if (discriminatorField?.type === "literal") {
|
|
187
|
-
const constVal = discriminatorField.literalValues[0];
|
|
188
|
-
if (typeof constVal === "string") return constVal;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
return typeof opt.meta.title === "string" ? opt.meta.title : opt.type;
|
|
192
|
-
});
|
|
193
|
-
let activeIndex = 0;
|
|
194
|
-
if (currentDiscriminatorValue !== void 0) {
|
|
195
|
-
const found = optionLabels.indexOf(currentDiscriminatorValue);
|
|
196
|
-
if (found !== -1) activeIndex = found;
|
|
197
|
-
}
|
|
198
|
-
const activeOption = options[activeIndex];
|
|
237
|
+
const { optionLabels, activeIndex, activeOption } = resolveDiscriminatedActive(options, discriminator, isObject(value) ? value : void 0);
|
|
199
238
|
if (tree.editability === "presentation") {
|
|
200
|
-
if (activeOption !== void 0) yield* streamField(activeOption, value, mergedResolver,
|
|
239
|
+
if (activeOption !== void 0) yield* streamField(activeOption, value, mergedResolver, path, rawResolver, currentDepth + 1, diagnostics);
|
|
201
240
|
return;
|
|
202
241
|
}
|
|
203
|
-
const
|
|
204
|
-
const wrapper = h("div", { class:
|
|
242
|
+
const tabPanelId = panelId(path);
|
|
243
|
+
const wrapper = h("div", { class: SC_CLASSES.discriminatedUnion });
|
|
205
244
|
yield yieldOpen(wrapper);
|
|
206
|
-
|
|
207
|
-
role: "tablist",
|
|
208
|
-
class: "sc-tabs",
|
|
209
|
-
"aria-label": "Select variant"
|
|
210
|
-
}, ...options.map((_opt, i) => {
|
|
245
|
+
const tabButtons = options.map((_opt, i) => {
|
|
211
246
|
return h("button", {
|
|
212
247
|
type: "button",
|
|
213
248
|
role: "tab",
|
|
214
|
-
class: i === activeIndex ?
|
|
215
|
-
id:
|
|
249
|
+
class: i === activeIndex ? SC_CLASSES.tabActive : SC_CLASSES.tab,
|
|
250
|
+
id: tabId(path, i),
|
|
216
251
|
"aria-selected": i === activeIndex ? "true" : void 0,
|
|
217
|
-
"aria-controls":
|
|
252
|
+
"aria-controls": tabPanelId,
|
|
218
253
|
tabindex: i === activeIndex ? "0" : "-1"
|
|
219
254
|
}, optionLabels[i]);
|
|
220
|
-
})
|
|
255
|
+
});
|
|
256
|
+
yield serialize(h("div", {
|
|
257
|
+
role: "tablist",
|
|
258
|
+
class: SC_CLASSES.tabs,
|
|
259
|
+
"aria-label": "Select variant"
|
|
260
|
+
}, ...tabButtons));
|
|
221
261
|
const panelOpen = h("div", {
|
|
222
262
|
role: "tabpanel",
|
|
223
|
-
id:
|
|
224
|
-
"aria-labelledby":
|
|
263
|
+
id: tabPanelId,
|
|
264
|
+
"aria-labelledby": tabId(path, activeIndex)
|
|
225
265
|
});
|
|
226
266
|
yield yieldOpen(panelOpen);
|
|
227
|
-
if (activeOption !== void 0) yield* streamField(activeOption, value, mergedResolver,
|
|
267
|
+
if (activeOption !== void 0) yield* streamField(activeOption, value, mergedResolver, path, rawResolver, currentDepth + 1, diagnostics);
|
|
228
268
|
yield yieldClose(panelOpen);
|
|
229
269
|
yield yieldClose(wrapper);
|
|
230
270
|
}
|
|
231
271
|
//#endregion
|
|
232
|
-
export {
|
|
272
|
+
export { renderFieldSync, renderLeaf, streamField, yieldClose, yieldOpen };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/core/limits.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Shared depth caps and hop counts used to bound recursion across
|
|
4
|
+
* schema-components. All numeric limits live here so the renderer, the
|
|
5
|
+
* ref resolver, the OpenAPI parser, and the type-level inference engine
|
|
6
|
+
* agree on the same constants.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Maximum recursion depth for the schema walker, the React renderers,
|
|
10
|
+
* the streaming HTML renderer, and the server-side renderer. Beyond
|
|
11
|
+
* this depth a recursion sentinel is emitted instead of further descent
|
|
12
|
+
* — the only safe response to a cyclic walked-field graph.
|
|
13
|
+
*/
|
|
14
|
+
declare const MAX_RENDER_DEPTH = 10;
|
|
15
|
+
/**
|
|
16
|
+
* Maximum depth for `$ref` resolution and Zod-tree walks. Mirrors the
|
|
17
|
+
* type-level `DEFAULT_MAX_DEPTH` ({@link MaxRefDepth}) so the runtime
|
|
18
|
+
* and compile-time bounds agree.
|
|
19
|
+
*/
|
|
20
|
+
type MaxRefDepth = 64;
|
|
21
|
+
declare const MAX_REF_DEPTH: MaxRefDepth;
|
|
22
|
+
/**
|
|
23
|
+
* Maximum number of `$ref` hops permitted when walking a chain of
|
|
24
|
+
* OpenAPI Path Item Object references. Beyond this a
|
|
25
|
+
* `path-item-ref-too-deep` diagnostic is emitted and resolution stops.
|
|
26
|
+
*/
|
|
27
|
+
declare const MAX_PATH_ITEM_REF_HOPS = 8;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { MaxRefDepth as i, MAX_REF_DEPTH as n, MAX_RENDER_DEPTH as r, MAX_PATH_ITEM_REF_HOPS as t };
|