schema-components 0.0.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/LICENSE +21 -0
  3. package/README.md +526 -0
  4. package/dist/core/adapter.d.mts +19 -0
  5. package/dist/core/adapter.mjs +140 -0
  6. package/dist/core/errors.d.mts +2 -0
  7. package/dist/core/errors.mjs +74 -0
  8. package/dist/core/guards.d.mts +44 -0
  9. package/dist/core/guards.mjs +58 -0
  10. package/dist/core/renderer.d.mts +2 -0
  11. package/dist/core/renderer.mjs +71 -0
  12. package/dist/core/types.d.mts +3 -0
  13. package/dist/core/types.mjs +40 -0
  14. package/dist/core/walker.d.mts +14 -0
  15. package/dist/core/walker.mjs +366 -0
  16. package/dist/errors-DIKI2C78.d.mts +57 -0
  17. package/dist/html/a11y.d.mts +47 -0
  18. package/dist/html/a11y.mjs +81 -0
  19. package/dist/html/html.d.mts +135 -0
  20. package/dist/html/html.mjs +168 -0
  21. package/dist/html/renderToHtml.d.mts +32 -0
  22. package/dist/html/renderToHtml.mjs +352 -0
  23. package/dist/html/renderToHtmlStream.d.mts +58 -0
  24. package/dist/html/renderToHtmlStream.mjs +285 -0
  25. package/dist/html/styles.css +151 -0
  26. package/dist/openapi/components.d.mts +76 -0
  27. package/dist/openapi/components.mjs +223 -0
  28. package/dist/openapi/parser.d.mts +45 -0
  29. package/dist/openapi/parser.mjs +159 -0
  30. package/dist/react/SchemaComponent.d.mts +96 -0
  31. package/dist/react/SchemaComponent.mjs +283 -0
  32. package/dist/react/SchemaErrorBoundary.d.mts +26 -0
  33. package/dist/react/SchemaErrorBoundary.mjs +47 -0
  34. package/dist/react/headless.d.mts +13 -0
  35. package/dist/react/headless.mjs +163 -0
  36. package/dist/themes/shadcn.d.mts +6 -0
  37. package/dist/themes/shadcn.mjs +166 -0
  38. package/dist/types-BU0ETFHk.d.mts +326 -0
  39. package/package.json +113 -3
@@ -0,0 +1,285 @@
1
+ import { isObject } from "../core/guards.mjs";
2
+ import { normaliseSchema } from "../core/adapter.mjs";
3
+ import { getHtmlRenderFn, mergeHtmlResolvers } from "../core/renderer.mjs";
4
+ import { walk } from "../core/walker.mjs";
5
+ import { VOID_ELEMENTS, h, raw, serialize, serializeAttributes } from "./html.mjs";
6
+ import { ariaLabelAttrs, buildHintElement, buildInputId, requiredIndicator } from "./a11y.mjs";
7
+ import { defaultHtmlResolver } from "./renderToHtml.mjs";
8
+ //#region src/html/renderToHtmlStream.ts
9
+ /**
10
+ * Streaming HTML renderer — yields HTML chunks incrementally.
11
+ *
12
+ * Same rendering pipeline as `renderToHtml` but yields string fragments
13
+ * as each field/element is produced instead of building the entire string
14
+ * in memory. Use for server-side rendering where you want to start
15
+ * flushing the response before the full schema is rendered.
16
+ *
17
+ * Three output formats:
18
+ *
19
+ * - `renderToHtmlChunks(schema, options)` → sync `Iterable<string>`
20
+ * - `renderToHtmlStream(schema, options)` → async `AsyncIterable<string>`
21
+ * - `renderToHtmlReadable(schema, options)` → web `ReadableStream<string>`
22
+ *
23
+ * Chunk boundaries:
24
+ * - Object: opening tag, one chunk per field, closing tag
25
+ * - Array: opening tag, one chunk per item, closing tag
26
+ * - Record: opening tag, one chunk per entry, closing tag
27
+ * - Leaf types (string, number, boolean, enum, literal, unknown):
28
+ * rendered entirely as one chunk
29
+ *
30
+ * All HTML construction uses `h()` from `html.ts` — the streaming module
31
+ * manually yields the opening tag, then children, then the closing tag.
32
+ */
33
+ /**
34
+ * Yield the opening tag of an element (e.g. `<fieldset class="sc-object">`).
35
+ * For void elements, yields the complete self-closing tag.
36
+ */
37
+ function yieldOpen(el) {
38
+ const attrs = serializeAttributes(el.attributes);
39
+ return `<${el.tag}${attrs}>`;
40
+ }
41
+ /**
42
+ * Yield the closing tag of an element (e.g. `</fieldset>`).
43
+ * Returns empty string for void elements.
44
+ */
45
+ function yieldClose(el) {
46
+ if (VOID_ELEMENTS.has(el.tag)) return "";
47
+ return `</${el.tag}>`;
48
+ }
49
+ /**
50
+ * Render a schema to HTML string chunks, yielded incrementally.
51
+ *
52
+ * Each yielded chunk is a self-contained HTML fragment. Concatenating
53
+ * all chunks produces the same output as `renderToHtml`.
54
+ *
55
+ * @returns Sync iterable of HTML string chunks
56
+ */
57
+ function* renderToHtmlChunks(schema, options = {}) {
58
+ const tree = prepareTree(schema, options);
59
+ const resolver = options.resolver ?? defaultHtmlResolver;
60
+ const mergedResolver = mergeHtmlResolvers(resolver, defaultHtmlResolver);
61
+ yield* streamField(tree, options.value, mergedResolver, "", resolver);
62
+ }
63
+ /**
64
+ * Render a schema to HTML string chunks asynchronously.
65
+ *
66
+ * Identical chunk boundaries to `renderToHtmlChunks` but yields via
67
+ * an async generator. Use with `for await...of` or pipe to a response.
68
+ *
69
+ * @returns Async iterable of HTML string chunks
70
+ */
71
+ async function* renderToHtmlStream(schema, options = {}) {
72
+ const tree = prepareTree(schema, options);
73
+ const resolver = options.resolver ?? defaultHtmlResolver;
74
+ const mergedResolver = mergeHtmlResolvers(resolver, defaultHtmlResolver);
75
+ for (const chunk of streamField(tree, options.value, mergedResolver, "", resolver)) {
76
+ yield chunk;
77
+ await schedulerYield();
78
+ }
79
+ }
80
+ /**
81
+ * No-op await that yields control to the event loop.
82
+ */
83
+ function schedulerYield() {
84
+ return Promise.resolve(void 0);
85
+ }
86
+ /**
87
+ * Render a schema to a web `ReadableStream<string>`.
88
+ *
89
+ * ```ts
90
+ * return new Response(renderToHtmlReadable(schema, { value }), {
91
+ * headers: { "Content-Type": "text/html" },
92
+ * });
93
+ * ```
94
+ */
95
+ function renderToHtmlReadable(schema, options = {}) {
96
+ const iterator = renderToHtmlChunks(schema, options)[Symbol.iterator]();
97
+ return new ReadableStream({
98
+ pull(controller) {
99
+ const result = iterator.next();
100
+ if (result.done) controller.close();
101
+ else controller.enqueue(result.value);
102
+ },
103
+ cancel() {
104
+ if (iterator.return !== void 0) iterator.return();
105
+ }
106
+ });
107
+ }
108
+ function prepareTree(schema, options) {
109
+ const mergedMeta = { ...options.meta };
110
+ if (options.readOnly === true) mergedMeta.readOnly = true;
111
+ if (options.writeOnly === true) mergedMeta.writeOnly = true;
112
+ if (options.description !== void 0) mergedMeta.description = options.description;
113
+ const { jsonSchema, rootMeta, rootDocument } = normaliseSchema(schema, options.ref);
114
+ return walk(jsonSchema, {
115
+ componentMeta: mergedMeta,
116
+ rootMeta,
117
+ fieldOverrides: options.fields,
118
+ rootDocument
119
+ });
120
+ }
121
+ function* streamField(tree, value, mergedResolver, path, rawResolver) {
122
+ const type = tree.type;
123
+ if (type === "string" || type === "number" || type === "boolean" || type === "enum" || type === "literal" || type === "file" || type === "unknown") {
124
+ yield renderLeaf(tree, value, mergedResolver, path);
125
+ return;
126
+ }
127
+ if (type === "union" || type === "discriminatedUnion") {
128
+ yield* streamUnion(tree, value, mergedResolver, path, rawResolver);
129
+ return;
130
+ }
131
+ if (type === "object") {
132
+ yield* streamObject(tree, value, mergedResolver, path, rawResolver);
133
+ return;
134
+ }
135
+ if (type === "array") {
136
+ yield* streamArray(tree, value, mergedResolver, path, rawResolver);
137
+ return;
138
+ }
139
+ if (type === "record") {
140
+ yield* streamRecord(tree, value, mergedResolver, path, rawResolver);
141
+ return;
142
+ }
143
+ yield renderLeaf(tree, value, mergedResolver, path);
144
+ }
145
+ function* streamObject(tree, value, mergedResolver, path, rawResolver) {
146
+ const fields = tree.fields;
147
+ if (fields === void 0) return;
148
+ const obj = isObject(value) ? value : {};
149
+ const readOnly = tree.editability === "presentation";
150
+ const descriptionText = typeof tree.meta.description === "string" ? tree.meta.description : void 0;
151
+ const labelAttrs = ariaLabelAttrs(descriptionText);
152
+ if (readOnly) {
153
+ const dlAttrs = { class: "sc-object" };
154
+ Object.assign(dlAttrs, labelAttrs);
155
+ const dl = h("dl", dlAttrs);
156
+ const legend = descriptionText !== void 0 ? serialize(h("legend", {}, descriptionText)) : "";
157
+ yield `${yieldOpen(dl)}${legend}`;
158
+ for (const [key, field] of Object.entries(fields)) {
159
+ const label = typeof field.meta.description === "string" ? field.meta.description : key;
160
+ const childValue = obj[key];
161
+ const childHtml = renderFieldSync(field, childValue, mergedResolver, key, rawResolver);
162
+ yield `${serialize(h("dt", { class: "sc-label" }, label))}${serialize(h("dd", { class: "sc-value" }, raw(childHtml)))}`;
163
+ }
164
+ yield yieldClose(dl);
165
+ } else {
166
+ const fieldsetAttrs = { class: "sc-object" };
167
+ Object.assign(fieldsetAttrs, labelAttrs);
168
+ const fieldset = h("fieldset", fieldsetAttrs);
169
+ const legend = descriptionText !== void 0 ? serialize(h("legend", {}, descriptionText)) : "";
170
+ yield `${yieldOpen(fieldset)}${legend}`;
171
+ for (const [key, field] of Object.entries(fields)) {
172
+ const label = typeof field.meta.description === "string" ? field.meta.description : key;
173
+ const fieldId = buildInputId(path, key);
174
+ const childValue = obj[key];
175
+ const childChunks = [...streamField(field, childValue, mergedResolver, key, rawResolver)].join("");
176
+ const required = requiredIndicator(field);
177
+ const labelContent = [label];
178
+ if (required !== void 0) labelContent.push(required);
179
+ const fieldChildren = [h("label", {
180
+ class: "sc-label",
181
+ for: fieldId
182
+ }, ...labelContent), raw(childChunks)];
183
+ const hint = buildHintElement(key, field.constraints);
184
+ if (hint !== void 0) fieldChildren.push(hint);
185
+ yield serialize(h("div", { class: "sc-field" }, ...fieldChildren));
186
+ }
187
+ yield yieldClose(fieldset);
188
+ }
189
+ }
190
+ function* streamArray(tree, value, mergedResolver, path, rawResolver) {
191
+ const arr = Array.isArray(value) ? value : [];
192
+ const element = tree.element;
193
+ if (element === void 0) return;
194
+ const readOnly = tree.editability === "presentation";
195
+ const elementPath = typeof element.meta.description === "string" ? element.meta.description : "";
196
+ if (readOnly) {
197
+ const ul = h("ul", { class: "sc-array" });
198
+ yield yieldOpen(ul);
199
+ for (const item of arr) yield serialize(h("li", { class: "sc-item" }, raw(renderFieldSync(element, item, mergedResolver, elementPath, rawResolver))));
200
+ yield yieldClose(ul);
201
+ } else {
202
+ const div = h("div", { class: "sc-array" });
203
+ yield yieldOpen(div);
204
+ for (const item of arr) yield serialize(h("div", {}, raw(renderFieldSync(element, item, mergedResolver, elementPath, rawResolver))));
205
+ yield yieldClose(div);
206
+ }
207
+ }
208
+ function* streamRecord(tree, value, mergedResolver, path, rawResolver) {
209
+ const obj = isObject(value) ? value : {};
210
+ const valueType = tree.valueType;
211
+ if (valueType === void 0) return;
212
+ const readOnly = tree.editability === "presentation";
213
+ const attrs = {
214
+ class: "sc-record",
215
+ role: "group"
216
+ };
217
+ if (readOnly) {
218
+ const dl = h("dl", attrs);
219
+ yield yieldOpen(dl);
220
+ for (const [key, val] of Object.entries(obj)) {
221
+ const childHtml = renderFieldSync(valueType, val, mergedResolver, key, rawResolver);
222
+ yield `${serialize(h("dt", { class: "sc-label" }, key))}${serialize(h("dd", { class: "sc-value" }, raw(childHtml)))}`;
223
+ }
224
+ yield yieldClose(dl);
225
+ } else {
226
+ const container = h("div", attrs);
227
+ yield yieldOpen(container);
228
+ for (const [key, val] of Object.entries(obj)) {
229
+ const childHtml = renderFieldSync(valueType, val, mergedResolver, key, rawResolver);
230
+ yield serialize(h("div", { class: "sc-field" }, h("label", { class: "sc-label" }, key), raw(childHtml)));
231
+ }
232
+ yield yieldClose(container);
233
+ }
234
+ }
235
+ function* streamUnion(tree, value, mergedResolver, path, rawResolver) {
236
+ const options = tree.options;
237
+ if (options === void 0 || options.length === 0) {
238
+ if (value === void 0 || value === null) yield serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
239
+ else yield serialize(h("span", { class: "sc-value" }, JSON.stringify(value)));
240
+ return;
241
+ }
242
+ const target = matchUnionOption(options, value) ?? options[0];
243
+ if (target !== void 0) yield* streamField(target, value, mergedResolver, typeof target.meta.description === "string" ? target.meta.description : "", rawResolver);
244
+ else yield serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
245
+ }
246
+ function renderLeaf(tree, value, mergedResolver, path) {
247
+ const renderFn = getHtmlRenderFn(tree.type, mergedResolver);
248
+ if (renderFn !== void 0) {
249
+ const props = {
250
+ value,
251
+ readOnly: tree.editability === "presentation",
252
+ writeOnly: tree.editability === "input",
253
+ meta: tree.meta,
254
+ constraints: tree.constraints,
255
+ path,
256
+ tree,
257
+ renderChild: () => ""
258
+ };
259
+ if (tree.enumValues !== void 0) props.enumValues = tree.enumValues;
260
+ if (tree.element !== void 0) props.element = tree.element;
261
+ if (tree.fields !== void 0) props.fields = tree.fields;
262
+ if (tree.options !== void 0) props.options = tree.options;
263
+ if (tree.discriminator !== void 0) props.discriminator = tree.discriminator;
264
+ if (tree.keyType !== void 0) props.keyType = tree.keyType;
265
+ if (tree.valueType !== void 0) props.valueType = tree.valueType;
266
+ return renderFn(props);
267
+ }
268
+ if (value === void 0 || value === null) return serialize(h("span", { class: "sc-value sc-value--empty" }, "—"));
269
+ return serialize(h("span", { class: "sc-value" }, typeof value === "string" ? value : JSON.stringify(value)));
270
+ }
271
+ /**
272
+ * Render a field synchronously to a string, recursively streaming children.
273
+ */
274
+ function renderFieldSync(tree, value, mergedResolver, path, rawResolver) {
275
+ return [...streamField(tree, value, mergedResolver, path, rawResolver)].join("");
276
+ }
277
+ function matchUnionOption(options, value) {
278
+ if (typeof value === "string") return options.find((o) => o.type === "string" || o.type === "enum");
279
+ if (typeof value === "number") return options.find((o) => o.type === "number");
280
+ if (typeof value === "boolean") return options.find((o) => o.type === "boolean");
281
+ if (Array.isArray(value)) return options.find((o) => o.type === "array");
282
+ if (typeof value === "object" && value !== null) return options.find((o) => o.type === "object");
283
+ }
284
+ //#endregion
285
+ export { renderToHtmlChunks, renderToHtmlReadable, renderToHtmlStream };
@@ -0,0 +1,151 @@
1
+ /**
2
+ * Default styles for Schema Components HTML output.
3
+ *
4
+ * All classes use the `sc-` prefix to avoid collisions.
5
+ * Import this stylesheet when using the HTML renderer without
6
+ * a custom theme adapter.
7
+ *
8
+ * ```html
9
+ * <link rel="stylesheet" href="node_modules/@scalar/schema-components/dist/styles.css">
10
+ * ```
11
+ */
12
+
13
+ /* ---------------------------------------------------------------------- */
14
+ /* Object containers */
15
+ /* ---------------------------------------------------------------------- */
16
+
17
+ .sc-object {
18
+ border: 1px solid #e2e8f0;
19
+ border-radius: 0.375rem;
20
+ padding: 1rem;
21
+ }
22
+
23
+ .sc-object legend {
24
+ font-weight: 600;
25
+ font-size: 0.875rem;
26
+ color: #334155;
27
+ padding: 0 0.25rem;
28
+ }
29
+
30
+ /* ---------------------------------------------------------------------- */
31
+ /* Fields */
32
+ /* ---------------------------------------------------------------------- */
33
+
34
+ .sc-field {
35
+ margin-bottom: 0.75rem;
36
+ }
37
+
38
+ .sc-field:last-child {
39
+ margin-bottom: 0;
40
+ }
41
+
42
+ .sc-label {
43
+ display: block;
44
+ font-size: 0.875rem;
45
+ font-weight: 500;
46
+ color: #374151;
47
+ margin-bottom: 0.25rem;
48
+ }
49
+
50
+ .sc-required {
51
+ color: #dc2626;
52
+ font-weight: 600;
53
+ }
54
+
55
+ /* ---------------------------------------------------------------------- */
56
+ /* Inputs */
57
+ /* ---------------------------------------------------------------------- */
58
+
59
+ .sc-input {
60
+ width: 100%;
61
+ padding: 0.375rem 0.5rem;
62
+ border: 1px solid #d1d5db;
63
+ border-radius: 0.25rem;
64
+ font-size: 0.875rem;
65
+ line-height: 1.25rem;
66
+ color: #111827;
67
+ background-color: #fff;
68
+ box-sizing: border-box;
69
+ }
70
+
71
+ .sc-input:focus {
72
+ outline: 2px solid #3b82f6;
73
+ outline-offset: -1px;
74
+ border-color: transparent;
75
+ }
76
+
77
+ .sc-input[type="checkbox"] {
78
+ width: auto;
79
+ margin: 0;
80
+ }
81
+
82
+ /* ---------------------------------------------------------------------- */
83
+ /* Read-only values */
84
+ /* ---------------------------------------------------------------------- */
85
+
86
+ .sc-value {
87
+ font-size: 0.875rem;
88
+ color: #111827;
89
+ }
90
+
91
+ .sc-value--empty {
92
+ color: #9ca3af;
93
+ }
94
+
95
+ .sc-value--boolean {
96
+ font-weight: 500;
97
+ }
98
+
99
+ .sc-value[href] {
100
+ color: #2563eb;
101
+ text-decoration: none;
102
+ }
103
+
104
+ .sc-value[href]:hover {
105
+ text-decoration: underline;
106
+ }
107
+
108
+ /* ---------------------------------------------------------------------- */
109
+ /* Arrays */
110
+ /* ---------------------------------------------------------------------- */
111
+
112
+ .sc-array {
113
+ list-style: none;
114
+ padding: 0;
115
+ margin: 0;
116
+ }
117
+
118
+ .sc-array > div {
119
+ margin-bottom: 0.375rem;
120
+ }
121
+
122
+ .sc-array > div:last-child {
123
+ margin-bottom: 0;
124
+ }
125
+
126
+ .sc-item {
127
+ margin-bottom: 0.375rem;
128
+ }
129
+
130
+ .sc-item:last-child {
131
+ margin-bottom: 0;
132
+ }
133
+
134
+ /* ---------------------------------------------------------------------- */
135
+ /* Records */
136
+ /* ---------------------------------------------------------------------- */
137
+
138
+ .sc-record {
139
+ margin: 0;
140
+ }
141
+
142
+ /* ---------------------------------------------------------------------- */
143
+ /* Constraint hints */
144
+ /* ---------------------------------------------------------------------- */
145
+
146
+ .sc-hint {
147
+ display: block;
148
+ font-size: 0.75rem;
149
+ color: #6b7280;
150
+ margin-top: 0.25rem;
151
+ }
@@ -0,0 +1,76 @@
1
+ import { c as InferResponseFields, m as SchemaMeta, o as InferParameterOverrides, r as FieldOverride, s as InferRequestBodyFields } from "../types-BU0ETFHk.mjs";
2
+ import { ReactNode } from "react";
3
+
4
+ //#region src/openapi/components.d.ts
5
+ interface ApiOperationProps<Doc = unknown, Path extends string = string, Method extends string = string> {
6
+ schema: Doc;
7
+ path: Path;
8
+ method: Method;
9
+ requestBodyValue?: unknown;
10
+ onRequestBodyChange?: (value: unknown) => void;
11
+ responseValue?: unknown;
12
+ meta?: SchemaMeta;
13
+ requestBodyFields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path, Method> : Record<string, FieldOverride>;
14
+ }
15
+ declare function ApiOperation<Doc = unknown, Path extends string = string, Method extends string = string>({
16
+ schema: doc,
17
+ path,
18
+ method,
19
+ requestBodyValue,
20
+ onRequestBodyChange,
21
+ responseValue,
22
+ meta,
23
+ requestBodyFields
24
+ }: ApiOperationProps<Doc, Path, Method>): ReactNode;
25
+ interface ApiParametersProps<Doc = unknown, Path extends string = string, Method extends string = string> {
26
+ schema: Doc;
27
+ path: Path;
28
+ method: Method;
29
+ meta?: SchemaMeta;
30
+ overrides?: Doc extends Record<string, unknown> ? InferParameterOverrides<Doc, Path, Method> : Record<string, FieldOverride>;
31
+ }
32
+ declare function ApiParameters<Doc = unknown, Path extends string = string, Method extends string = string>({
33
+ schema: doc,
34
+ path,
35
+ method,
36
+ meta,
37
+ overrides
38
+ }: ApiParametersProps<Doc, Path, Method>): ReactNode;
39
+ interface ApiRequestBodyProps<Doc = unknown, Path extends string = string, Method extends string = string> {
40
+ schema: Doc;
41
+ path: Path;
42
+ method: Method;
43
+ value?: unknown;
44
+ onChange?: (value: unknown) => void;
45
+ meta?: SchemaMeta;
46
+ fields?: Doc extends Record<string, unknown> ? InferRequestBodyFields<Doc, Path, Method> : Record<string, FieldOverride>;
47
+ }
48
+ declare function ApiRequestBody<Doc = unknown, Path extends string = string, Method extends string = string>({
49
+ schema: doc,
50
+ path,
51
+ method,
52
+ value,
53
+ onChange,
54
+ meta,
55
+ fields
56
+ }: ApiRequestBodyProps<Doc, Path, Method>): ReactNode;
57
+ interface ApiResponseProps<Doc = unknown, Path extends string = string, Method extends string = string, Status extends string = string> {
58
+ schema: Doc;
59
+ path: Path;
60
+ method: Method;
61
+ status: Status;
62
+ value?: unknown;
63
+ meta?: SchemaMeta;
64
+ fields?: Doc extends Record<string, unknown> ? InferResponseFields<Doc, Path, Method, Status> : Record<string, FieldOverride>;
65
+ }
66
+ declare function ApiResponse<Doc = unknown, Path extends string = string, Method extends string = string, Status extends string = string>({
67
+ schema: doc,
68
+ path,
69
+ method,
70
+ status,
71
+ value,
72
+ meta,
73
+ fields
74
+ }: ApiResponseProps<Doc, Path, Method, Status>): ReactNode;
75
+ //#endregion
76
+ export { ApiOperation, ApiOperationProps, ApiParameters, ApiParametersProps, ApiRequestBody, ApiRequestBodyProps, ApiResponse, ApiResponseProps };