rapidoc 12.0.0 → 12.1.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 +127 -25
- package/dist/rapidoc-flow-min.js +580 -0
- package/dist/rapidoc-flow-min.js.LICENSE.txt +171 -0
- package/dist/rapidoc-min.js +541 -1309
- package/dist/rapidoc-min.js.LICENSE.txt +381 -0
- package/package.json +21 -18
- package/src/README.md +150 -0
- package/src/components/README.md +91 -0
- package/src/components/api-request.ts +43 -0
- package/src/components/api-response.ts +9 -4
- package/src/components/schema-base-element.ts +18 -4
- package/src/components/schema-table.ts +58 -13
- package/src/components/schema-tree.ts +7 -0
- package/src/components/tag-input.ts +5 -9
- package/src/flow.js +3 -0
- package/src/rapi-flow.ts +1178 -0
- package/src/rapidoc-mini.ts +27 -6
- package/src/rapidoc.ts +108 -62
- package/src/styles/README.md +96 -0
- package/src/styles/css-bundle.js +2 -2
- package/src/styles/endpoint-styles.js +6 -1
- package/src/styles/flow-styles.js +248 -0
- package/src/styles/nav-styles.js +39 -15
- package/src/styles/schema-styles.js +13 -5
- package/src/styles/theme-tokens.js +2 -2
- package/src/templates/README.md +89 -0
- package/src/templates/api-response-template.js +14 -10
- package/src/templates/callback-template.js +1 -1
- package/src/templates/downloads-template.js +12 -27
- package/src/templates/endpoint-template.js +15 -24
- package/src/templates/expanded-endpoint-template.js +8 -4
- package/src/templates/focused-endpoint-template.js +4 -3
- package/src/templates/navbar-template.js +20 -11
- package/src/templates/request-body-template.js +29 -7
- package/src/templates/request-params-template.js +15 -4
- package/src/templates/security-scheme-template.js +11 -2
- package/src/templates/server-template.js +3 -2
- package/src/utils/README.md +146 -0
- package/src/utils/arazzo/README.md +119 -0
- package/src/utils/arazzo/components.js +15 -0
- package/src/utils/arazzo/graph.js +269 -0
- package/src/utils/arazzo/index.js +52 -0
- package/src/utils/arazzo/operations.js +106 -0
- package/src/utils/arazzo/parse.js +196 -0
- package/src/utils/arazzo/refs.js +40 -0
- package/src/utils/arazzo/svg.js +707 -0
- package/src/utils/curl-utils.js +5 -2
- package/src/utils/highlighter.js +3 -0
- package/src/utils/mcp/README.md +155 -0
- package/src/utils/mcp/common.js +45 -346
- package/src/utils/mcp/manifest.js +382 -0
- package/src/utils/mcp/project/server.ts +53 -0
- package/src/utils/mcp/project.js +88 -0
- package/src/utils/mcp/runtime.js +289 -0
- package/src/utils/mcp/schema.js +98 -0
- package/src/utils/mcp/workflow-runtime.js +374 -0
- package/src/utils/mcp/workflows.js +240 -0
- package/src/utils/mcp/zip.js +102 -0
- package/src/utils/mcp-generator.js +29 -125
- package/src/utils/mock-interceptor.js +134 -85
- package/src/utils/request-utils.js +61 -0
- package/src/utils/schema-utils.js +33 -6
- package/src/utils/slugger.js +5 -7
- package/src/utils/spec-parser.js +190 -164
- package/src/utils/url-utils.js +36 -1
- package/dist/rapidoc-static-min.js +0 -13542
- package/src/static/index.d.ts +0 -149
- package/src/static/index.js +0 -62
- package/src/static/navigation.js +0 -497
- package/src/static/render.js +0 -490
- package/src/static/serializer.js +0 -216
- package/src/utils/mcp/generators/csharp.js +0 -242
- package/src/utils/mcp/generators/go.js +0 -298
- package/src/utils/mcp/generators/java.js +0 -330
- package/src/utils/mcp/generators/python.js +0 -248
- package/src/utils/mcp/generators/rust.js +0 -281
- package/src/utils/mcp/generators/typescript.js +0 -290
package/src/static/render.js
DELETED
|
@@ -1,490 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Framework-agnostic static pre-rendering engine for RapiDoc.
|
|
3
|
-
*
|
|
4
|
-
* Runs seamlessly in Node.js >= 22, Bun, Astro, Nuxt, Next.js, and custom SSG scripts.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
// Safe idempotent customElements registry in pure Node/Bun/SSR environments
|
|
8
|
-
if (typeof globalThis.customElements === "undefined") {
|
|
9
|
-
const registry = new Map();
|
|
10
|
-
globalThis.customElements = {
|
|
11
|
-
define: (name, constructor) => {
|
|
12
|
-
registry.set(name, constructor);
|
|
13
|
-
},
|
|
14
|
-
get: (name) => registry.get(name),
|
|
15
|
-
whenDefined: () => Promise.resolve(),
|
|
16
|
-
};
|
|
17
|
-
} else if (globalThis.customElements && !globalThis.customElements.__safeDefinePatched) {
|
|
18
|
-
const origDefine = globalThis.customElements.define;
|
|
19
|
-
globalThis.customElements.define = function (name, constructor, options) {
|
|
20
|
-
if (!this.get(name)) {
|
|
21
|
-
try {
|
|
22
|
-
origDefine.call(this, name, constructor, options);
|
|
23
|
-
} catch {
|
|
24
|
-
// Safe fallback if already registered in registry
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
globalThis.customElements.__safeDefinePatched = true;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
if (
|
|
32
|
-
typeof CustomElementRegistry !== "undefined" &&
|
|
33
|
-
!CustomElementRegistry.prototype.__safeDefinePatched
|
|
34
|
-
) {
|
|
35
|
-
const origProtoDefine = CustomElementRegistry.prototype.define;
|
|
36
|
-
CustomElementRegistry.prototype.define = function (name, constructor, options) {
|
|
37
|
-
if (!this.get(name)) {
|
|
38
|
-
try {
|
|
39
|
-
origProtoDefine.call(this, name, constructor, options);
|
|
40
|
-
} catch {
|
|
41
|
-
// Safe fallback if already registered in registry
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
CustomElementRegistry.prototype.__safeDefinePatched = true;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
import ProcessSpec from "../utils/spec-parser.js";
|
|
49
|
-
import mainBodyTemplate from "../templates/main-body-template.js";
|
|
50
|
-
import { expandedEndpointBodyTemplate } from "../templates/expanded-endpoint-template.js";
|
|
51
|
-
import { schemaToAST } from "../utils/schema-utils.js";
|
|
52
|
-
import SchemaTable from "../components/schema-table.ts";
|
|
53
|
-
import SchemaTree from "../components/schema-tree.ts";
|
|
54
|
-
import { getBundledCss } from "../styles/css-bundle.js";
|
|
55
|
-
import { DEFAULT_THEME } from "../styles/theme-tokens.js";
|
|
56
|
-
import { renderTemplateToString, escapeHtml } from "./serializer.js";
|
|
57
|
-
|
|
58
|
-
function toKebabCase(str) {
|
|
59
|
-
return str.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function toCamelCase(str) {
|
|
63
|
-
return str.replace(/-([a-z0-9])/g, (_, c) => c.toUpperCase());
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Resolves an OpenAPI specification from a file path, URL, JSON/YAML string, or JS object.
|
|
68
|
-
*
|
|
69
|
-
* @param {string|Object} specInput
|
|
70
|
-
* @param {Object} [options]
|
|
71
|
-
* @returns {Promise<Object>} Fully parsed and dereferenced OpenAPI specification
|
|
72
|
-
*/
|
|
73
|
-
export async function resolveSpecInput(specInput, options = {}) {
|
|
74
|
-
if (!specInput) {
|
|
75
|
-
throw new Error("OpenAPI specification input is required (file path, URL, string, or object).");
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// Already resolved/parsed spec object (from ProcessSpec)
|
|
79
|
-
if (
|
|
80
|
-
typeof specInput === "object" &&
|
|
81
|
-
specInput !== null &&
|
|
82
|
-
Array.isArray(specInput.securitySchemes)
|
|
83
|
-
) {
|
|
84
|
-
return specInput;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
let rawSpec = specInput;
|
|
88
|
-
|
|
89
|
-
if (typeof specInput === "string") {
|
|
90
|
-
const trimmed = specInput.trim();
|
|
91
|
-
|
|
92
|
-
// Check if it's inlined JSON or multiline YAML
|
|
93
|
-
if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.includes("\n")) {
|
|
94
|
-
try {
|
|
95
|
-
rawSpec = JSON.parse(trimmed);
|
|
96
|
-
} catch {
|
|
97
|
-
rawSpec = trimmed;
|
|
98
|
-
}
|
|
99
|
-
} else if (!trimmed.startsWith("http://") && !trimmed.startsWith("https://")) {
|
|
100
|
-
// Local file path in Node.js / Bun
|
|
101
|
-
if (typeof process !== "undefined" && process.versions?.node) {
|
|
102
|
-
try {
|
|
103
|
-
const fs = await import("node:fs");
|
|
104
|
-
if (fs.existsSync(trimmed)) {
|
|
105
|
-
const content = fs.readFileSync(trimmed, "utf-8");
|
|
106
|
-
try {
|
|
107
|
-
rawSpec = JSON.parse(content);
|
|
108
|
-
} catch {
|
|
109
|
-
rawSpec = content;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
} catch {
|
|
113
|
-
// If filesystem read fails, fall through to default loader
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return ProcessSpec(
|
|
120
|
-
rawSpec,
|
|
121
|
-
options.generateMissingTags ?? options["generate-missing-tags"] ?? false,
|
|
122
|
-
options.sortTags ?? options["sort-tags"] ?? false,
|
|
123
|
-
options.sortSchemas ?? options["sort-schemas"] ?? false,
|
|
124
|
-
options.sortEndpointsBy ?? options["sort-endpoints-by"] ?? "none",
|
|
125
|
-
options.apiKey ?? options.apiKeyName ?? options["api-key-name"] ?? "",
|
|
126
|
-
options.apiKeyLocation ?? options["api-key-location"] ?? "",
|
|
127
|
-
options.apiKeyValue ?? options["api-key-value"] ?? "",
|
|
128
|
-
options.serverUrl ?? options["server-url"] ?? "",
|
|
129
|
-
options.matchPaths ?? options["match-paths"] ?? "",
|
|
130
|
-
options.matchType ?? options["match-type"] ?? "",
|
|
131
|
-
options.removeEndpointsWithBadgeLabelAs ??
|
|
132
|
-
options["remove-endpoints-with-badge-label-as"] ??
|
|
133
|
-
"",
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Pre-renders an entire OpenAPI documentation page into static HTML.
|
|
139
|
-
*
|
|
140
|
-
* Supported output modes:
|
|
141
|
-
* - 'dsd' (default): Declarative Shadow DOM `<rapi-doc><template shadowrootmode="open">...</template></rapi-doc>`.
|
|
142
|
-
* Delivers zero FOUC, instant first paint, and automatic hydration when client bundle loads.
|
|
143
|
-
* - 'html' / 'light': Semantic Light DOM `<div class="rapidoc-static-container">...</div>`.
|
|
144
|
-
*
|
|
145
|
-
* @param {Object} options
|
|
146
|
-
* @param {string|Object} options.spec - Specification file path, URL, raw string, or parsed object
|
|
147
|
-
* @param {'read'|'view'|'focused'} [options.renderStyle='read'] - Layout style
|
|
148
|
-
* @param {string} [options.theme='ember'] - Theme preset ('ember', 'carbon', 'cobalt', 'jade', 'indigo') or hex
|
|
149
|
-
* @param {'dark'|'light'|'system'} [options.colorScheme='dark'] - Color scheme
|
|
150
|
-
* @param {'row'|'column'} [options.layout] - Layout orientation ('column' default for read/focused, 'row' for view)
|
|
151
|
-
* @param {boolean|string} [options.showHeader=true] - Whether to render top header
|
|
152
|
-
* @param {boolean|string} [options.showSideNav=true] - Whether to render sidebar navigation
|
|
153
|
-
* @param {boolean|string} [options.showInfo=true] - Whether to render spec overview & info
|
|
154
|
-
* @param {boolean|string} [options.allowSearch=true] - Whether search is available
|
|
155
|
-
* @param {boolean|string} [options.allowAdvancedSearch=false] - Whether advanced search dialog is pre-rendered
|
|
156
|
-
* @param {boolean|string} [options.allowServerSelection=true] - Whether to show server selection
|
|
157
|
-
* @param {boolean|string} [options.allowAuthentication=true] - Whether to render auth security schemes
|
|
158
|
-
* @param {boolean|string} [options.allowTry=true] - Whether try-it console is included
|
|
159
|
-
* @param {'table'|'tree'} [options.schemaStyle='table'] - Default schema display style
|
|
160
|
-
* @param {number} [options.schemaExpandLevel=99999] - Schema nesting expansion level
|
|
161
|
-
* @param {'example'|'schema'} [options.defaultSchemaTab='example'] - Active tab in schema views
|
|
162
|
-
* @param {'dsd'|'html'|'light'} [options.outputMode='dsd'] - Pre-rendered container mode
|
|
163
|
-
* @param {boolean} [options.includeStyles=true] - Whether to include bundled CSS in the output
|
|
164
|
-
* @returns {Promise<string>} Fully rendered static HTML string
|
|
165
|
-
*/
|
|
166
|
-
export async function renderRapiDoc(options = {}) {
|
|
167
|
-
// Normalize option names to support both camelCase and kebab-case
|
|
168
|
-
const normalized = {};
|
|
169
|
-
for (const [key, val] of Object.entries(options)) {
|
|
170
|
-
normalized[key] = val;
|
|
171
|
-
normalized[toCamelCase(key)] = val;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
const spec = options.spec ?? normalized.spec;
|
|
175
|
-
const renderStyle = normalized.renderStyle ?? "read";
|
|
176
|
-
const theme = normalized.theme ?? DEFAULT_THEME;
|
|
177
|
-
const colorScheme = normalized.colorScheme ?? "dark";
|
|
178
|
-
const showHeader = normalized.showHeader ?? true;
|
|
179
|
-
const showSideNav = normalized.showSideNav ?? true;
|
|
180
|
-
const showInfo = normalized.showInfo ?? true;
|
|
181
|
-
const allowSearch = normalized.allowSearch ?? true;
|
|
182
|
-
const allowAdvancedSearch = normalized.allowAdvancedSearch ?? false;
|
|
183
|
-
const allowServerSelection = normalized.allowServerSelection ?? true;
|
|
184
|
-
const allowAuthentication = normalized.allowAuthentication ?? true;
|
|
185
|
-
const allowTry = normalized.allowTry ?? true;
|
|
186
|
-
const schemaStyle = normalized.schemaStyle ?? "table";
|
|
187
|
-
const schemaExpandLevel = normalized.schemaExpandLevel ?? 99999;
|
|
188
|
-
const defaultSchemaTab = normalized.defaultSchemaTab ?? "example";
|
|
189
|
-
const outputMode = normalized.outputMode ?? "dsd";
|
|
190
|
-
const includeStyles = normalized.includeStyles ?? true;
|
|
191
|
-
const pageDirection = normalized.pageDirection ?? "ltr";
|
|
192
|
-
|
|
193
|
-
const defaultLayout = renderStyle === "read" || renderStyle === "focused" ? "column" : "row";
|
|
194
|
-
const layout = normalized.layout || defaultLayout;
|
|
195
|
-
|
|
196
|
-
const resolvedSpec = await resolveSpecInput(spec, normalized);
|
|
197
|
-
|
|
198
|
-
const INTERNAL_KEYS = new Set([
|
|
199
|
-
"spec",
|
|
200
|
-
"outputMode",
|
|
201
|
-
"includeStyles",
|
|
202
|
-
"inlineSpec",
|
|
203
|
-
"focusedElementId",
|
|
204
|
-
]);
|
|
205
|
-
|
|
206
|
-
// Pass any custom options into the template context
|
|
207
|
-
const customContextProps = {};
|
|
208
|
-
for (const [key, val] of Object.entries(normalized)) {
|
|
209
|
-
if (!INTERNAL_KEYS.has(key) && val !== undefined && val !== null) {
|
|
210
|
-
customContextProps[key] = typeof val === "boolean" ? String(val) : val;
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
const context = {
|
|
215
|
-
...customContextProps,
|
|
216
|
-
resolvedSpec,
|
|
217
|
-
renderStyle,
|
|
218
|
-
layout,
|
|
219
|
-
theme,
|
|
220
|
-
colorScheme,
|
|
221
|
-
showHeader: String(showHeader),
|
|
222
|
-
showSideNav: String(showSideNav),
|
|
223
|
-
showInfo: String(showInfo),
|
|
224
|
-
allowSearch: String(allowSearch),
|
|
225
|
-
allowAdvancedSearch: String(allowAdvancedSearch),
|
|
226
|
-
allowServerSelection: String(allowServerSelection),
|
|
227
|
-
allowAuthentication: String(allowAuthentication),
|
|
228
|
-
allowTry: String(allowTry),
|
|
229
|
-
schemaStyle,
|
|
230
|
-
schemaExpandLevel,
|
|
231
|
-
defaultSchemaTab,
|
|
232
|
-
pageDirection,
|
|
233
|
-
config: {
|
|
234
|
-
renderStyle,
|
|
235
|
-
schemaStyle,
|
|
236
|
-
schemaExpandLevel,
|
|
237
|
-
defaultSchemaTab,
|
|
238
|
-
allowTry: String(allowTry),
|
|
239
|
-
},
|
|
240
|
-
matchPaths: normalized.matchPaths || "",
|
|
241
|
-
selectedServer: resolvedSpec.servers?.[0],
|
|
242
|
-
focusedElementId:
|
|
243
|
-
options.focusedElementId ||
|
|
244
|
-
(showInfo === "false" || showInfo === false
|
|
245
|
-
? resolvedSpec.tags?.[0]?.paths?.[0]?.elementId || ""
|
|
246
|
-
: "overview"),
|
|
247
|
-
handleHref: () => {},
|
|
248
|
-
};
|
|
249
|
-
|
|
250
|
-
const templateResult = mainBodyTemplate.call(context);
|
|
251
|
-
const serializedBody = renderTemplateToString(templateResult);
|
|
252
|
-
|
|
253
|
-
if (outputMode === "html" || outputMode === "light") {
|
|
254
|
-
const scopeClass = "rapidoc-static-container";
|
|
255
|
-
const cssText = includeStyles
|
|
256
|
-
? `<style>${getBundledCss({ theme, colorScheme, scope: `.${scopeClass}` })}</style>`
|
|
257
|
-
: "";
|
|
258
|
-
return `<div class="${scopeClass}" data-theme="${escapeHtml(theme)}" data-color-scheme="${escapeHtml(colorScheme)}" data-render-style="${escapeHtml(renderStyle)}" data-layout="${escapeHtml(layout)}" data-schema-style="${escapeHtml(schemaStyle)}">
|
|
259
|
-
${cssText}
|
|
260
|
-
${serializedBody}
|
|
261
|
-
</div>`;
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Default: Declarative Shadow DOM (DSD)
|
|
265
|
-
const cssText = includeStyles ? `<style>${getBundledCss({ theme, colorScheme })}</style>` : "";
|
|
266
|
-
const specScript =
|
|
267
|
-
options.inlineSpec !== false && typeof spec === "object" && spec !== null
|
|
268
|
-
? ` <script type="application/json" slot="rapidoc-spec">${JSON.stringify(spec).replace(/</g, "\\u003c")}</script>\n`
|
|
269
|
-
: "";
|
|
270
|
-
|
|
271
|
-
// Construct complete attributes map to ensure exact client hydration parity
|
|
272
|
-
const attrsMap = new Map();
|
|
273
|
-
attrsMap.set("theme", theme);
|
|
274
|
-
attrsMap.set("color-scheme", colorScheme);
|
|
275
|
-
attrsMap.set("render-style", renderStyle);
|
|
276
|
-
attrsMap.set("layout", layout);
|
|
277
|
-
attrsMap.set("schema-style", schemaStyle);
|
|
278
|
-
attrsMap.set("schema-expand-level", String(schemaExpandLevel));
|
|
279
|
-
attrsMap.set("default-schema-tab", defaultSchemaTab);
|
|
280
|
-
attrsMap.set("show-header", String(showHeader));
|
|
281
|
-
attrsMap.set("show-side-nav", String(showSideNav));
|
|
282
|
-
attrsMap.set("show-info", String(showInfo));
|
|
283
|
-
attrsMap.set("allow-search", String(allowSearch));
|
|
284
|
-
attrsMap.set("allow-advanced-search", String(allowAdvancedSearch));
|
|
285
|
-
attrsMap.set("allow-server-selection", String(allowServerSelection));
|
|
286
|
-
attrsMap.set("allow-authentication", String(allowAuthentication));
|
|
287
|
-
attrsMap.set("allow-try", String(allowTry));
|
|
288
|
-
attrsMap.set("page-direction", pageDirection);
|
|
289
|
-
|
|
290
|
-
// Reflect any additional user-provided options to custom element attributes (converted to kebab-case)
|
|
291
|
-
for (const [key, val] of Object.entries(options)) {
|
|
292
|
-
const camel = toCamelCase(key);
|
|
293
|
-
if (!INTERNAL_KEYS.has(camel) && !INTERNAL_KEYS.has(key) && val !== undefined && val !== null) {
|
|
294
|
-
const kebab = toKebabCase(camel);
|
|
295
|
-
attrsMap.set(kebab, typeof val === "boolean" ? String(val) : String(val));
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (typeof spec === "string" && (spec.startsWith("http://") || spec.startsWith("https://"))) {
|
|
300
|
-
attrsMap.set("spec-url", spec);
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
const attrsString = Array.from(attrsMap.entries())
|
|
304
|
-
.map(([name, value]) => `${name}="${escapeHtml(value)}"`)
|
|
305
|
-
.join(" ");
|
|
306
|
-
|
|
307
|
-
return `<rapi-doc ${attrsString}>
|
|
308
|
-
${specScript} <template shadowrootmode="open">
|
|
309
|
-
${cssText}
|
|
310
|
-
${serializedBody}
|
|
311
|
-
</template>
|
|
312
|
-
</rapi-doc>`;
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Pre-renders a single isolated endpoint / operation into static HTML.
|
|
317
|
-
* Ideal for embedding individual API operations in Markdown/MDX guides (Cosmo Cargo / Zudoku style).
|
|
318
|
-
*
|
|
319
|
-
* @param {Object} options
|
|
320
|
-
* @param {string|Object} options.spec - Specification file path, URL, raw string, or parsed object
|
|
321
|
-
* @param {string} options.path - Operation path (e.g. '/v1/shipments' or '/pet/{petId}')
|
|
322
|
-
* @param {string} options.method - HTTP method ('get', 'post', 'put', 'delete', etc.)
|
|
323
|
-
* @param {'read'|'view'} [options.renderStyle='read'] - Layout style
|
|
324
|
-
* @param {'row'|'column'} [options.layout='column'] - Layout orientation
|
|
325
|
-
* @param {string} [options.theme='ember'] - Theme preset name or hex
|
|
326
|
-
* @param {'dark'|'light'|'system'} [options.colorScheme='dark'] - Color scheme
|
|
327
|
-
* @param {boolean} [options.includeStyles=true] - Whether to prepend scoped CSS
|
|
328
|
-
* @returns {Promise<string>} Rendered HTML string of the isolated endpoint
|
|
329
|
-
*/
|
|
330
|
-
export async function renderEndpoint(options = {}) {
|
|
331
|
-
const {
|
|
332
|
-
spec,
|
|
333
|
-
path: targetPathStr,
|
|
334
|
-
method: targetMethodStr,
|
|
335
|
-
renderStyle = "read",
|
|
336
|
-
layout = "column",
|
|
337
|
-
theme = DEFAULT_THEME,
|
|
338
|
-
colorScheme = "dark",
|
|
339
|
-
includeStyles = true,
|
|
340
|
-
allowTry = false,
|
|
341
|
-
} = options;
|
|
342
|
-
|
|
343
|
-
if (!targetPathStr || !targetMethodStr) {
|
|
344
|
-
throw new Error("Both `path` and `method` are required for renderEndpoint().");
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
const normalizedMethod = targetMethodStr.toLowerCase().trim();
|
|
348
|
-
const resolvedSpec = await resolveSpecInput(spec, options);
|
|
349
|
-
|
|
350
|
-
// Search across tags for matching operation
|
|
351
|
-
let matchedPath = null;
|
|
352
|
-
let matchedTagName = "";
|
|
353
|
-
let matchedTagDescription = "";
|
|
354
|
-
let isFirstOperation = false;
|
|
355
|
-
|
|
356
|
-
for (const tag of resolvedSpec.tags || []) {
|
|
357
|
-
const foundIdx = (tag.paths || []).findIndex(
|
|
358
|
-
(p) => p.path === targetPathStr && p.method.toLowerCase() === normalizedMethod,
|
|
359
|
-
);
|
|
360
|
-
if (foundIdx !== -1) {
|
|
361
|
-
matchedPath = tag.paths[foundIdx];
|
|
362
|
-
matchedTagName = tag.name;
|
|
363
|
-
matchedTagDescription = tag.description || "";
|
|
364
|
-
isFirstOperation = foundIdx === 0;
|
|
365
|
-
break;
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
|
|
369
|
-
if (!matchedPath) {
|
|
370
|
-
throw new Error(
|
|
371
|
-
`Endpoint not found in spec: ${targetMethodStr.toUpperCase()} ${targetPathStr}`,
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
const context = {
|
|
376
|
-
resolvedSpec,
|
|
377
|
-
renderStyle,
|
|
378
|
-
layout,
|
|
379
|
-
theme,
|
|
380
|
-
colorScheme,
|
|
381
|
-
fillRequestFieldsWithExample: "true",
|
|
382
|
-
allowTry: String(allowTry),
|
|
383
|
-
config: {
|
|
384
|
-
renderStyle,
|
|
385
|
-
schemaStyle: options.schemaStyle || "table",
|
|
386
|
-
allowTry: String(allowTry),
|
|
387
|
-
},
|
|
388
|
-
selectedServer: resolvedSpec.servers?.[0],
|
|
389
|
-
};
|
|
390
|
-
|
|
391
|
-
const renderedTemplate = expandedEndpointBodyTemplate.call(
|
|
392
|
-
context,
|
|
393
|
-
matchedPath,
|
|
394
|
-
matchedTagName,
|
|
395
|
-
matchedTagDescription,
|
|
396
|
-
isFirstOperation,
|
|
397
|
-
);
|
|
398
|
-
const serializedHtml = renderTemplateToString(renderedTemplate);
|
|
399
|
-
|
|
400
|
-
const containerClass = "rapidoc-endpoint-container";
|
|
401
|
-
const cssText = includeStyles
|
|
402
|
-
? `<style>${getBundledCss({ theme, colorScheme, scope: `.${containerClass}` })}</style>`
|
|
403
|
-
: "";
|
|
404
|
-
|
|
405
|
-
return `<div class="${containerClass} ${renderStyle}-mode" data-theme="${theme}" data-color-scheme="${colorScheme}">
|
|
406
|
-
${cssText}
|
|
407
|
-
${serializedHtml}
|
|
408
|
-
</div>`;
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Pre-renders an isolated JSON Schema or component schema into static HTML.
|
|
413
|
-
*
|
|
414
|
-
* @param {Object} options
|
|
415
|
-
* @param {Object|string} options.schema - JSON Schema object, or name of schema in `components.schemas`
|
|
416
|
-
* @param {Object|string} [options.spec] - Optional OpenAPI spec to resolve schema names against
|
|
417
|
-
* @param {'table'|'tree'} [options.style='table'] - Display style ('table' or 'tree')
|
|
418
|
-
* @param {number} [options.schemaExpandLevel=99999] - Level of initial property expansion
|
|
419
|
-
* @param {string} [options.theme='ember'] - Theme preset name or hex
|
|
420
|
-
* @param {'dark'|'light'|'system'} [options.colorScheme='dark'] - Color scheme
|
|
421
|
-
* @param {boolean} [options.includeStyles=true] - Whether to prepend scoped CSS
|
|
422
|
-
* @returns {Promise<string>} Rendered schema HTML string
|
|
423
|
-
*/
|
|
424
|
-
export async function renderSchema(options = {}) {
|
|
425
|
-
const {
|
|
426
|
-
schema,
|
|
427
|
-
spec,
|
|
428
|
-
style = "table",
|
|
429
|
-
schemaExpandLevel = 99999,
|
|
430
|
-
theme = DEFAULT_THEME,
|
|
431
|
-
colorScheme = "dark",
|
|
432
|
-
includeStyles = true,
|
|
433
|
-
} = options;
|
|
434
|
-
|
|
435
|
-
let resolvedSchema = schema;
|
|
436
|
-
|
|
437
|
-
if (typeof schema === "string") {
|
|
438
|
-
if (!spec) {
|
|
439
|
-
throw new Error(`When schema is a string name ('${schema}'), options.spec must be provided.`);
|
|
440
|
-
}
|
|
441
|
-
const resolvedSpec = await resolveSpecInput(spec);
|
|
442
|
-
let schemaObj = (typeof spec === "object" && spec.components?.schemas?.[schema]) || null;
|
|
443
|
-
if (!schemaObj) {
|
|
444
|
-
const schemasGroup = (resolvedSpec.components || []).find((c) => c.name === "Schemas");
|
|
445
|
-
const found = (schemasGroup?.subComponents || []).find((sc) => sc.name === schema);
|
|
446
|
-
schemaObj = found?.component;
|
|
447
|
-
}
|
|
448
|
-
if (!schemaObj) {
|
|
449
|
-
throw new Error(`Schema '${schema}' not found in spec components.schemas.`);
|
|
450
|
-
}
|
|
451
|
-
resolvedSchema = schemaObj;
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
if (!resolvedSchema || typeof resolvedSchema !== "object") {
|
|
455
|
-
throw new Error("Invalid schema provided to renderSchema().");
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
const ast = schemaToAST(resolvedSchema);
|
|
459
|
-
let renderedTemplate;
|
|
460
|
-
|
|
461
|
-
if (style === "tree") {
|
|
462
|
-
const tree = new SchemaTree();
|
|
463
|
-
tree.data = ast;
|
|
464
|
-
tree.schemaExpandLevel = schemaExpandLevel;
|
|
465
|
-
renderedTemplate = tree.render();
|
|
466
|
-
} else {
|
|
467
|
-
const table = new SchemaTable();
|
|
468
|
-
table.data = ast;
|
|
469
|
-
table.schemaExpandLevel = schemaExpandLevel;
|
|
470
|
-
renderedTemplate = table.render();
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const serializedHtml = renderTemplateToString(renderedTemplate);
|
|
474
|
-
const containerClass = "rapidoc-schema-container";
|
|
475
|
-
const cssText = includeStyles
|
|
476
|
-
? `<style>${getBundledCss({ theme, colorScheme, scope: `.${containerClass}` })}</style>`
|
|
477
|
-
: "";
|
|
478
|
-
|
|
479
|
-
return `<div class="${containerClass}" data-theme="${theme}" data-color-scheme="${colorScheme}">
|
|
480
|
-
${cssText}
|
|
481
|
-
${serializedHtml}
|
|
482
|
-
</div>`;
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
export default {
|
|
486
|
-
resolveSpecInput,
|
|
487
|
-
renderRapiDoc,
|
|
488
|
-
renderEndpoint,
|
|
489
|
-
renderSchema,
|
|
490
|
-
};
|