rapidoc 11.0.1 → 12.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.
- package/README.md +46 -31
- package/dist/rapidoc-min.js +1424 -213
- package/dist/rapidoc-static-min.js +13542 -0
- package/package.json +47 -35
- package/src/components/api-request.ts +869 -0
- package/src/components/api-response.ts +509 -0
- package/src/components/json-tree.ts +171 -0
- package/src/components/schema-base-element.ts +315 -0
- package/src/components/schema-table.ts +430 -0
- package/src/components/schema-tree.ts +386 -0
- package/src/components/tag-input.ts +184 -0
- package/src/index.js +6 -0
- package/src/oauth-receiver.ts +29 -0
- package/src/rapidoc-mini.ts +582 -0
- package/src/rapidoc.ts +1808 -0
- package/src/static/index.d.ts +149 -0
- package/src/static/index.js +62 -0
- package/src/static/navigation.js +497 -0
- package/src/static/render.js +490 -0
- package/src/static/serializer.js +216 -0
- package/src/styles/auth-styles.js +318 -0
- package/src/styles/border-styles.js +24 -0
- package/src/styles/css-bundle.js +129 -0
- package/src/styles/custom-styles.js +8 -0
- package/src/styles/dialog-box-styles.js +102 -0
- package/src/styles/endpoint-styles.js +559 -0
- package/src/styles/flex-styles.js +16 -0
- package/src/styles/font-styles.js +432 -0
- package/src/styles/info-styles.js +36 -0
- package/src/styles/input-styles.js +555 -0
- package/src/styles/layout-styles.js +396 -0
- package/src/styles/microlighter-styles.js +99 -0
- package/src/styles/nav-styles.js +609 -0
- package/src/styles/param-list-styles.js +261 -0
- package/src/styles/schema-styles.js +288 -0
- package/src/styles/tab-styles.js +106 -0
- package/src/styles/theme-tokens.js +582 -0
- package/src/templates/advanced-search-dialog-template.js +94 -0
- package/src/templates/api-response-template.js +219 -0
- package/src/templates/callback-template.js +86 -0
- package/src/templates/code-samples-template.js +52 -0
- package/src/templates/components-template.js +86 -0
- package/src/templates/downloads-template.js +85 -0
- package/src/templates/endpoint-template.js +386 -0
- package/src/templates/expanded-endpoint-template.js +266 -0
- package/src/templates/focused-endpoint-template.js +145 -0
- package/src/templates/header-template.js +92 -0
- package/src/templates/logo-template.js +21 -0
- package/src/templates/main-body-template.js +102 -0
- package/src/templates/navbar-template.js +489 -0
- package/src/templates/overview-template.js +104 -0
- package/src/templates/request-body-template.js +651 -0
- package/src/templates/request-params-template.js +474 -0
- package/src/templates/security-scheme-template.js +1263 -0
- package/src/templates/server-template.js +152 -0
- package/src/utils/auto-color-scheme.js +99 -0
- package/src/utils/bind-navbar.js +175 -0
- package/src/utils/color-utils.js +59 -0
- package/src/utils/common-utils.js +191 -0
- package/src/utils/curl-utils.js +123 -0
- package/src/utils/highlighter.js +416 -0
- package/src/utils/markdown-utils.js +110 -0
- package/src/utils/mcp/common.js +467 -0
- package/src/utils/mcp/generators/csharp.js +242 -0
- package/src/utils/mcp/generators/go.js +298 -0
- package/src/utils/mcp/generators/java.js +330 -0
- package/src/utils/mcp/generators/python.js +248 -0
- package/src/utils/mcp/generators/rust.js +281 -0
- package/src/utils/mcp/generators/typescript.js +290 -0
- package/src/utils/mcp-generator.js +143 -0
- package/src/utils/mock-interceptor.js +508 -0
- package/src/utils/oauth-utils.js +87 -0
- package/src/utils/request-utils.js +203 -0
- package/src/utils/response-utils.js +203 -0
- package/src/utils/sanitize.js +57 -0
- package/src/utils/schema-utils.js +1927 -0
- package/src/utils/slugger.js +189 -0
- package/src/utils/spec-parser.js +915 -0
- package/src/utils/url-utils.js +211 -0
- package/src/utils/xml-utils.js +61 -0
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders individual API operation rows and expanded panels (summary, description, parameters, request, response, try-it console).
|
|
3
|
+
*/
|
|
4
|
+
import { html, nothing } from "lit";
|
|
5
|
+
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
6
|
+
import { sanitizeHTML } from "../utils/sanitize.js";
|
|
7
|
+
import { marked } from "marked";
|
|
8
|
+
import "~/components/api-request";
|
|
9
|
+
import "~/components/api-response";
|
|
10
|
+
import codeSamplesTemplate from "~/templates/code-samples-template";
|
|
11
|
+
import callbackTemplate from "~/templates/callback-template";
|
|
12
|
+
import { pathSecurityTemplate } from "~/templates/security-scheme-template";
|
|
13
|
+
import { getMatchedPaths, rapidocApiKey } from "~/utils/common-utils";
|
|
14
|
+
|
|
15
|
+
function toggleExpand(path) {
|
|
16
|
+
if (path.expanded) {
|
|
17
|
+
path.expanded = false; // collapse
|
|
18
|
+
if (this.updateRoute === "true") {
|
|
19
|
+
this.replaceHistoryState("");
|
|
20
|
+
}
|
|
21
|
+
} else {
|
|
22
|
+
path.expanded = true; // Expand
|
|
23
|
+
if (this.updateRoute === "true") {
|
|
24
|
+
const newHash = `#${path.elementId}`;
|
|
25
|
+
if (window.location.hash !== newHash) {
|
|
26
|
+
this.replaceHistoryState(path.elementId);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
this.requestUpdate();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function expandCollapseAll(operationsRootEl, action = "expand-all") {
|
|
34
|
+
const groupList = [...operationsRootEl.querySelectorAll(".section-tag-group")];
|
|
35
|
+
const elList = [...operationsRootEl.querySelectorAll(".section-tag")];
|
|
36
|
+
if (action === "expand-all") {
|
|
37
|
+
groupList.forEach((el) => {
|
|
38
|
+
el.classList.replace("collapsed", "expanded");
|
|
39
|
+
});
|
|
40
|
+
elList.forEach((el) => {
|
|
41
|
+
el.classList.replace("collapsed", "expanded");
|
|
42
|
+
});
|
|
43
|
+
} else {
|
|
44
|
+
groupList.forEach((el) => {
|
|
45
|
+
el.classList.replace("expanded", "collapsed");
|
|
46
|
+
});
|
|
47
|
+
elList.forEach((el) => {
|
|
48
|
+
el.classList.replace("expanded", "collapsed");
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function onExpandCollapseAll(e, action = "expand-all") {
|
|
54
|
+
expandCollapseAll.call(this, e.target.closest(".operations-root"), action);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function endpointHeadTemplate(path, pathsExpanded = false) {
|
|
58
|
+
return html`
|
|
59
|
+
<summary
|
|
60
|
+
@click="${(e) => {
|
|
61
|
+
toggleExpand.call(this, path, e);
|
|
62
|
+
}}"
|
|
63
|
+
part="section-endpoint-head-${path.expanded ? "expanded" : "collapsed"}"
|
|
64
|
+
class="endpoint-head ${path.method} ${path.deprecated ? "deprecated" : ""} ${
|
|
65
|
+
pathsExpanded || path.expanded ? "expanded" : "collapsed"
|
|
66
|
+
}"
|
|
67
|
+
>
|
|
68
|
+
<div part="section-endpoint-head-method" class="method ${path.method} ${path.deprecated ? "deprecated" : ""}">${path.method}</div>
|
|
69
|
+
<div part="section-endpoint-head-path" class="path ${path.deprecated ? "deprecated" : ""}">
|
|
70
|
+
${path.path}
|
|
71
|
+
${
|
|
72
|
+
path.isWebhook
|
|
73
|
+
? html`<span style="font-family: var(--font-sans); font-size: var(--font-size-small); color:var(--primary); margin-left: 16px">
|
|
74
|
+
Webhook</span
|
|
75
|
+
>`
|
|
76
|
+
: ""
|
|
77
|
+
}
|
|
78
|
+
</div>
|
|
79
|
+
${
|
|
80
|
+
path.deprecated
|
|
81
|
+
? html` <span
|
|
82
|
+
style="font-size:var(--font-size-small); text-transform:uppercase; font-weight:bold; color:var(--destructive); margin:2px 0 0 5px;"
|
|
83
|
+
>
|
|
84
|
+
deprecated
|
|
85
|
+
</span>`
|
|
86
|
+
: ""
|
|
87
|
+
}
|
|
88
|
+
${
|
|
89
|
+
this.showSummaryWhenCollapsed
|
|
90
|
+
? html`<div part="section-endpoint-head-description" class="descr">${path.summary || path.shortSummary}</div>`
|
|
91
|
+
: ""
|
|
92
|
+
}
|
|
93
|
+
</summary>
|
|
94
|
+
`;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function endpointBodyTemplate(path) {
|
|
98
|
+
const acceptContentTypes = new Set();
|
|
99
|
+
for (const respStatus in path.responses) {
|
|
100
|
+
for (const acceptContentType in path.responses[respStatus]?.content) {
|
|
101
|
+
acceptContentTypes.add(acceptContentType.trim());
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const accept = [...acceptContentTypes].join(", ");
|
|
105
|
+
// Filter API Keys that are non-empty and are applicable to the the path
|
|
106
|
+
const nonEmptyApiKeys =
|
|
107
|
+
this.resolvedSpec.securitySchemes.filter(
|
|
108
|
+
(v) => v.finalKeyValue && path.security?.some((ps) => v.securitySchemeId in ps),
|
|
109
|
+
) || [];
|
|
110
|
+
|
|
111
|
+
// If a RapiDoc API Key is specified on the element and its value is not hyphen(-) then include it for all paths
|
|
112
|
+
const rapiDocApiKey = this.resolvedSpec.securitySchemes.find(
|
|
113
|
+
(v) => v.securitySchemeId === rapidocApiKey && v.value !== "-",
|
|
114
|
+
);
|
|
115
|
+
if (rapiDocApiKey) {
|
|
116
|
+
nonEmptyApiKeys.push(rapiDocApiKey);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const codeSampleTabPanel = path.xCodeSamples ? codeSamplesTemplate(path.xCodeSamples) : "";
|
|
120
|
+
return html` <div
|
|
121
|
+
part="section-endpoint-body-${path.expanded ? "expanded" : "collapsed"}"
|
|
122
|
+
class="endpoint-body ${path.method} ${path.deprecated ? "deprecated" : ""}"
|
|
123
|
+
>
|
|
124
|
+
<div class="summary">
|
|
125
|
+
${
|
|
126
|
+
path.summary
|
|
127
|
+
? html`<h3 class="rapidoc-heading title" part="section-endpoint-body-title heading heading-3">${path.summary}</h3>`
|
|
128
|
+
: path.shortSummary !== path.description
|
|
129
|
+
? html`<h3 class="rapidoc-heading title" part="section-endpoint-body-title heading heading-3">${path.shortSummary}</h3>`
|
|
130
|
+
: html`<h3 class="visually-hidden">${path.method.toUpperCase()} ${path.path}</h3>`
|
|
131
|
+
}
|
|
132
|
+
${
|
|
133
|
+
path.xBadges && path.xBadges?.length > 0
|
|
134
|
+
? html`
|
|
135
|
+
<div style="display:flex; flex-wrap:wrap;font-size: var(--font-size-small);">
|
|
136
|
+
${path.xBadges.map((v) =>
|
|
137
|
+
v.color === "none"
|
|
138
|
+
? ""
|
|
139
|
+
: html`<span
|
|
140
|
+
part="endpoint-badge"
|
|
141
|
+
style="margin:1px; margin-right:5px; padding:1px 8px; font-weight:bold; border-radius:var(--radius); background: color-mix(in srgb, var(--${v.color}) 20%, transparent); color:var(--${v.color}); border:1px solid var(--${v.color})"
|
|
142
|
+
>${v.label}</span
|
|
143
|
+
>`,
|
|
144
|
+
)}
|
|
145
|
+
</div>
|
|
146
|
+
`
|
|
147
|
+
: ""
|
|
148
|
+
}
|
|
149
|
+
${pathSecurityTemplate.call(this, path.security, path.elementId)}
|
|
150
|
+
${
|
|
151
|
+
path.description
|
|
152
|
+
? html`<div part="section-endpoint-body-description" class="m-markdown">
|
|
153
|
+
${unsafeHTML(sanitizeHTML(marked(path.description)))}
|
|
154
|
+
</div>`
|
|
155
|
+
: ""
|
|
156
|
+
}
|
|
157
|
+
${
|
|
158
|
+
path.externalDocs?.url || path.externalDocs?.description
|
|
159
|
+
? html`<div class="external-docs-box">
|
|
160
|
+
<div class="m-markdown">${unsafeHTML(sanitizeHTML(marked(path.externalDocs?.description || "")))}</div>
|
|
161
|
+
${
|
|
162
|
+
path.externalDocs?.url
|
|
163
|
+
? html`<a class="external-docs-link" href="${path.externalDocs?.url}" target="_blank">
|
|
164
|
+
${path.externalDocs?.url}
|
|
165
|
+
<span class="external-docs-arrow">⇲</span>
|
|
166
|
+
</a>`
|
|
167
|
+
: ""
|
|
168
|
+
}
|
|
169
|
+
</div>`
|
|
170
|
+
: ""
|
|
171
|
+
}
|
|
172
|
+
<slot name="${path.elementId}"></slot>
|
|
173
|
+
${codeSampleTabPanel}
|
|
174
|
+
</div>
|
|
175
|
+
<div class="req-resp-container ${this.layout}-layout" part="section-req-resp-container">
|
|
176
|
+
<div class="request-panel view-mode-request ${this.layout}-layout" part="section-request-panel">
|
|
177
|
+
<api-request
|
|
178
|
+
.config="${this.config}"
|
|
179
|
+
class="${this.renderStyle}-mode ${this.layout}-layout"
|
|
180
|
+
style="width:100%;"
|
|
181
|
+
webhook="${path.isWebhook}"
|
|
182
|
+
method="${path.method}"
|
|
183
|
+
path="${path.path}"
|
|
184
|
+
.security="${path.security}"
|
|
185
|
+
.parameters="${path.parameters}"
|
|
186
|
+
.request_body="${path.requestBody}"
|
|
187
|
+
.api_keys="${nonEmptyApiKeys}"
|
|
188
|
+
.servers="${path.servers}"
|
|
189
|
+
server-url="${path.servers?.length > 0 ? path.servers[0].url : this.selectedServer?.computedUrl}"
|
|
190
|
+
active-schema-tab="${this.defaultSchemaTab}"
|
|
191
|
+
fill-request-fields-with-example="${this.fillRequestFieldsWithExample}"
|
|
192
|
+
allow-try="${this.allowTry}"
|
|
193
|
+
show-curl-before-try="${this.showCurlBeforeTry}"
|
|
194
|
+
accept="${accept}"
|
|
195
|
+
render-style="${this.renderStyle}"
|
|
196
|
+
schema-style="${this.schemaStyle}"
|
|
197
|
+
schema-expand-level="${this.schemaExpandLevel}"
|
|
198
|
+
schema-description-expanded="${this.schemaDescriptionExpanded}"
|
|
199
|
+
allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
|
|
200
|
+
schema-hide-read-only="${this.schemaHideReadOnly === "never" ? "false" : path.isWebhook ? "false" : "true"}"
|
|
201
|
+
schema-hide-write-only="${this.schemaHideWriteOnly === "never" ? "false" : path.isWebhook ? "true" : "false"}"
|
|
202
|
+
fetch-credentials="${this.fetchCredentials}"
|
|
203
|
+
exportparts="section-request-title:section-request-title, heading:heading, heading-4:heading-4, heading-5:heading-5, heading-6:heading-6,
|
|
204
|
+
wrap-request-btn:wrap-request-btn, btn:btn, btn-fill:btn-fill, btn-outline:btn-outline, btn-try:btn-try, btn-clear:btn-clear, btn-clear-resp:btn-clear-resp,
|
|
205
|
+
tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
|
|
206
|
+
file-input:file-input, textbox:textbox, textbox-param:textbox-param, textarea:textarea, textarea-param:textarea-param,
|
|
207
|
+
anchor:anchor, anchor-param-example:anchor-param-example, anchor-param-constraint:anchor-param-constraint, param-list:param-list, param:param, param-label:param-label, param-name:param-name, param-type:param-type, param-input:param-input, param-constraint:param-constraint, param-constraint-label:param-constraint-label, param-details:param-details, param-example-list:param-example-list, value-list:value-list, value-list-label:value-list-label, value-list-items:value-list-items, schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
|
|
208
|
+
>
|
|
209
|
+
</api-request>
|
|
210
|
+
|
|
211
|
+
${path.callbacks ? callbackTemplate.call(this, path.callbacks) : ""}
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<api-response
|
|
215
|
+
.config="${this.config}"
|
|
216
|
+
class="response-panel ${this.renderStyle}-mode ${this.layout}-layout"
|
|
217
|
+
part="section-response-panel"
|
|
218
|
+
style="width:100%;"
|
|
219
|
+
webhook="${path.isWebhook}"
|
|
220
|
+
.responses="${path.responses}"
|
|
221
|
+
active-schema-tab="${this.defaultSchemaTab}"
|
|
222
|
+
render-style="${this.renderStyle}"
|
|
223
|
+
schema-style="${this.schemaStyle}"
|
|
224
|
+
schema-expand-level="${this.schemaExpandLevel}"
|
|
225
|
+
schema-description-expanded="${this.schemaDescriptionExpanded}"
|
|
226
|
+
allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
|
|
227
|
+
schema-hide-read-only="${this.schemaHideReadOnly === "never" ? "false" : path.isWebhook ? "true" : "false"}"
|
|
228
|
+
schema-hide-write-only="${this.schemaHideWriteOnly === "never" ? "false" : path.isWebhook ? "false" : "true"}"
|
|
229
|
+
selected-status="${Object.keys(path.responses || {})[0] || ""}"
|
|
230
|
+
exportparts="section-response-title:section-response-title, heading:heading, heading-4:heading-4, heading-5:heading-5, heading-6:heading-6,
|
|
231
|
+
btn:btn, btn-fill:btn-fill, btn-outline:btn-outline, btn-try:btn-try, file-input:file-input,
|
|
232
|
+
textbox:textbox, textbox-param:textbox-param, textarea:textarea, textarea-param:textarea-param, anchor:anchor, anchor-param-example:anchor-param-example, anchor-param-constraint:anchor-param-constraint, param-list:param-list, param:param, param-label:param-label, param-name:param-name, param-type:param-type, param-input:param-input, param-constraint:param-constraint, param-constraint-label:param-constraint-label, param-details:param-details, param-example-list:param-example-list, value-list:value-list, value-list-label:value-list-label, value-list-items:value-list-items, btn-clear-resp:btn-clear-resp,
|
|
233
|
+
tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
|
|
234
|
+
schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
|
|
235
|
+
>
|
|
236
|
+
</api-response>
|
|
237
|
+
</div>
|
|
238
|
+
</div>`;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export default function endpointTemplate(isMini = false, pathsExpanded = false) {
|
|
242
|
+
if (!this.resolvedSpec) {
|
|
243
|
+
return "";
|
|
244
|
+
}
|
|
245
|
+
const renderTagSection = (tag) => html`
|
|
246
|
+
${
|
|
247
|
+
isMini
|
|
248
|
+
? html`
|
|
249
|
+
<div class="section-tag-body">
|
|
250
|
+
${
|
|
251
|
+
tag.description
|
|
252
|
+
? html`<div class="regular-font regular-font-size m-markdown" style="padding-bottom:12px">
|
|
253
|
+
${unsafeHTML(sanitizeHTML(marked(tag.description || "")))}
|
|
254
|
+
</div>`
|
|
255
|
+
: ""
|
|
256
|
+
}
|
|
257
|
+
${tag.paths
|
|
258
|
+
.filter((path) => {
|
|
259
|
+
if (this.searchVal) {
|
|
260
|
+
return getMatchedPaths(this.searchVal, path, tag.name);
|
|
261
|
+
}
|
|
262
|
+
return true;
|
|
263
|
+
})
|
|
264
|
+
.map(
|
|
265
|
+
(path, idx) =>
|
|
266
|
+
html` <section
|
|
267
|
+
id="${path.elementId}"
|
|
268
|
+
class="m-endpoint regular-font ${path.method} ${pathsExpanded || path.expanded ? "expanded" : "collapsed"}"
|
|
269
|
+
data-first-operation-in-tag="${idx === 0 ? "true" : nothing}"
|
|
270
|
+
>
|
|
271
|
+
${endpointHeadTemplate.call(this, path, pathsExpanded)}
|
|
272
|
+
${pathsExpanded || path.expanded ? endpointBodyTemplate.call(this, path) : ""}
|
|
273
|
+
</section>`,
|
|
274
|
+
)}
|
|
275
|
+
</div>
|
|
276
|
+
`
|
|
277
|
+
: html`
|
|
278
|
+
<div class="regular-font section-gap section-tag ${tag.expanded ? "expanded" : "collapsed"}">
|
|
279
|
+
<div
|
|
280
|
+
class="section-tag-header"
|
|
281
|
+
@click="${() => {
|
|
282
|
+
tag.expanded = !tag.expanded;
|
|
283
|
+
this.requestUpdate();
|
|
284
|
+
}}"
|
|
285
|
+
>
|
|
286
|
+
<h2 id="${tag.elementId}" class="rapidoc-heading sub-title tag" part="heading heading-2" style="color:var(--primary)">
|
|
287
|
+
${tag.displayName || tag.name}
|
|
288
|
+
</h2>
|
|
289
|
+
</div>
|
|
290
|
+
<div class="section-tag-body">
|
|
291
|
+
<slot name="${tag.elementId}"></slot>
|
|
292
|
+
${
|
|
293
|
+
tag.description
|
|
294
|
+
? html`<div class="regular-font regular-font-size m-markdown" style="padding-bottom:12px">
|
|
295
|
+
${unsafeHTML(sanitizeHTML(marked(tag.description || "")))}
|
|
296
|
+
</div>`
|
|
297
|
+
: ""
|
|
298
|
+
}
|
|
299
|
+
${tag.paths
|
|
300
|
+
.filter((v) => {
|
|
301
|
+
if (this.searchVal) {
|
|
302
|
+
return getMatchedPaths(this.searchVal, v, tag.name);
|
|
303
|
+
}
|
|
304
|
+
return true;
|
|
305
|
+
})
|
|
306
|
+
.map(
|
|
307
|
+
(path, idx) =>
|
|
308
|
+
html` <section
|
|
309
|
+
part="section-endpoint"
|
|
310
|
+
id="${path.elementId}"
|
|
311
|
+
class="m-endpoint regular-font ${path.method} ${pathsExpanded || path.expanded ? "expanded" : "collapsed"}"
|
|
312
|
+
data-first-operation-in-tag="${idx === 0 ? "true" : nothing}"
|
|
313
|
+
>
|
|
314
|
+
${endpointHeadTemplate.call(this, path, pathsExpanded)}
|
|
315
|
+
${pathsExpanded || path.expanded ? endpointBodyTemplate.call(this, path) : ""}
|
|
316
|
+
</section>`,
|
|
317
|
+
)}
|
|
318
|
+
</div>
|
|
319
|
+
</div>
|
|
320
|
+
`
|
|
321
|
+
}
|
|
322
|
+
`;
|
|
323
|
+
|
|
324
|
+
const hasTagGroups = this.resolvedSpec.tagGroups && this.resolvedSpec.tagGroups.length > 0;
|
|
325
|
+
const assignedTagNames = new Set();
|
|
326
|
+
if (hasTagGroups) {
|
|
327
|
+
this.resolvedSpec.tagGroups.forEach((group) => {
|
|
328
|
+
(group.tags || []).forEach((tag) => assignedTagNames.add(tag.name.toLowerCase()));
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
const remainingTags = hasTagGroups
|
|
332
|
+
? (this.resolvedSpec.tags || []).filter((tag) => !assignedTagNames.has(tag.name.toLowerCase()))
|
|
333
|
+
: [];
|
|
334
|
+
|
|
335
|
+
return html`${
|
|
336
|
+
isMini
|
|
337
|
+
? ""
|
|
338
|
+
: html`<div class="section-expand-collapse-container">
|
|
339
|
+
<span @click="${(e) => onExpandCollapseAll(e, "expand-all")}" style="color:var(--primary); cursor:pointer;"> Expand all </span>
|
|
340
|
+
|
|
|
341
|
+
<span @click="${(e) => onExpandCollapseAll(e, "collapse-all")}" style="color:var(--primary); cursor:pointer;">
|
|
342
|
+
Collapse all
|
|
343
|
+
</span>
|
|
344
|
+
sections
|
|
345
|
+
</div>`
|
|
346
|
+
}
|
|
347
|
+
${
|
|
348
|
+
hasTagGroups
|
|
349
|
+
? html`
|
|
350
|
+
${this.resolvedSpec.tagGroups.map(
|
|
351
|
+
(group) => html`
|
|
352
|
+
<div class="regular-font section-gap section-tag-group ${group.expanded ? "expanded" : "collapsed"}" id="${group.elementId}">
|
|
353
|
+
<div
|
|
354
|
+
class="section-tag-group-header"
|
|
355
|
+
@click="${() => {
|
|
356
|
+
group.expanded = !group.expanded;
|
|
357
|
+
this.requestUpdate();
|
|
358
|
+
}}"
|
|
359
|
+
>
|
|
360
|
+
<h2
|
|
361
|
+
class="rapidoc-heading sub-title tag-group"
|
|
362
|
+
part="heading heading-2"
|
|
363
|
+
style="color:var(--foreground); font-size:var(--h4-font-size); font-weight:700; text-transform:uppercase; letter-spacing:0.05em;"
|
|
364
|
+
>
|
|
365
|
+
${group.displayName || group.name}
|
|
366
|
+
</h2>
|
|
367
|
+
<div class="section-tag-group-icon"></div>
|
|
368
|
+
</div>
|
|
369
|
+
<div class="section-tag-group-body">
|
|
370
|
+
${
|
|
371
|
+
group.description
|
|
372
|
+
? html`<div class="regular-font regular-font-size m-markdown" style="padding-bottom:12px">
|
|
373
|
+
${unsafeHTML(sanitizeHTML(marked(group.description || "")))}
|
|
374
|
+
</div>`
|
|
375
|
+
: ""
|
|
376
|
+
}
|
|
377
|
+
${group.tags.map((tag) => renderTagSection(tag))}
|
|
378
|
+
</div>
|
|
379
|
+
</div>
|
|
380
|
+
`,
|
|
381
|
+
)}
|
|
382
|
+
${remainingTags.map((tag) => renderTagSection(tag))}
|
|
383
|
+
`
|
|
384
|
+
: this.resolvedSpec.tags.map((tag) => renderTagSection(tag))
|
|
385
|
+
}`;
|
|
386
|
+
}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Renders all API operations in an expanded continuous documentation layout grouped by tags.
|
|
3
|
+
*/
|
|
4
|
+
import { fixRenderedAnchorLinks } from "~/utils/markdown-utils";
|
|
5
|
+
import { html, nothing } from "lit";
|
|
6
|
+
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
7
|
+
import { sanitizeHTML } from "../utils/sanitize.js";
|
|
8
|
+
import { marked } from "marked";
|
|
9
|
+
import Slugger from "github-slugger";
|
|
10
|
+
import { rapidocApiKey } from "~/utils/common-utils";
|
|
11
|
+
import { pathSecurityTemplate } from "~/templates/security-scheme-template";
|
|
12
|
+
import codeSamplesTemplate from "~/templates/code-samples-template";
|
|
13
|
+
import callbackTemplate from "~/templates/callback-template";
|
|
14
|
+
import "~/components/api-request";
|
|
15
|
+
import "~/components/api-response";
|
|
16
|
+
|
|
17
|
+
function headingRenderer(tagElementId) {
|
|
18
|
+
const slugger = new Slugger();
|
|
19
|
+
const renderer = new marked.Renderer();
|
|
20
|
+
renderer.heading = ({ text, depth }) =>
|
|
21
|
+
`<h${depth} class="observe-me" id="${tagElementId}--${slugger.slug(text)}">${text}</h${depth}>`;
|
|
22
|
+
fixRenderedAnchorLinks(renderer);
|
|
23
|
+
return renderer;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function expandedEndpointBodyTemplate(
|
|
27
|
+
path,
|
|
28
|
+
tagName = "",
|
|
29
|
+
tagDescription = "",
|
|
30
|
+
isFirst = false,
|
|
31
|
+
) {
|
|
32
|
+
const acceptContentTypes = new Set();
|
|
33
|
+
for (const respStatus in path.responses) {
|
|
34
|
+
for (const acceptContentType in path.responses[respStatus]?.content) {
|
|
35
|
+
acceptContentTypes.add(acceptContentType.trim());
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const accept = [...acceptContentTypes].join(", ");
|
|
39
|
+
|
|
40
|
+
// Filter API Keys that are non-empty and are applicable to the the path
|
|
41
|
+
const nonEmptyApiKeys =
|
|
42
|
+
this.resolvedSpec.securitySchemes.filter(
|
|
43
|
+
(v) => v.finalKeyValue && path.security?.some((ps) => v.securitySchemeId in ps),
|
|
44
|
+
) || [];
|
|
45
|
+
|
|
46
|
+
// If a RapiDoc API Key is specified on the element and its value is not hyphen(-) then include it for all paths
|
|
47
|
+
const rapiDocApiKey = this.resolvedSpec.securitySchemes.find(
|
|
48
|
+
(v) => v.securitySchemeId === rapidocApiKey && v.value !== "-",
|
|
49
|
+
);
|
|
50
|
+
if (rapiDocApiKey) {
|
|
51
|
+
nonEmptyApiKeys.push(rapiDocApiKey);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const codeSampleTabPanel = path.xCodeSamples
|
|
55
|
+
? codeSamplesTemplate.call(this, path.xCodeSamples)
|
|
56
|
+
: "";
|
|
57
|
+
return html`
|
|
58
|
+
${this.renderStyle === "read" && !isFirst ? html`<div class="divider" part="operation-divider"></div>` : ""}
|
|
59
|
+
<div
|
|
60
|
+
class="expanded-endpoint-body observe-me ${path.method} ${path.deprecated ? "deprecated" : ""} "
|
|
61
|
+
part="section-operation ${path.elementId}"
|
|
62
|
+
id="${path.elementId}"
|
|
63
|
+
data-first-operation-in-tag="${isFirst ? "true" : nothing}"
|
|
64
|
+
>
|
|
65
|
+
${
|
|
66
|
+
this.renderStyle === "focused" && tagName
|
|
67
|
+
? html`
|
|
68
|
+
<div class="tag-container" part="section-operation-tag" style="margin-bottom: 16px;">
|
|
69
|
+
<h2 class="rapidoc-heading upper" part="heading heading-2" style="font-size:var(--h3-font-size); margin:0;">${tagName}</h2>
|
|
70
|
+
${
|
|
71
|
+
isFirst && tagDescription
|
|
72
|
+
? html`
|
|
73
|
+
<div
|
|
74
|
+
class="tag-description regular-font"
|
|
75
|
+
part="section-tag-description"
|
|
76
|
+
style="margin-top:12px; padding:12px 14px; background:var(--code-bg); border-radius:min(var(--radius), 0.5rem); border:1px solid var(--border);"
|
|
77
|
+
>
|
|
78
|
+
<div class="m-markdown">${unsafeHTML(sanitizeHTML(marked(tagDescription)))}</div>
|
|
79
|
+
</div>
|
|
80
|
+
`
|
|
81
|
+
: ""
|
|
82
|
+
}
|
|
83
|
+
</div>
|
|
84
|
+
`
|
|
85
|
+
: ""
|
|
86
|
+
}
|
|
87
|
+
${path.deprecated ? html`<div class="bold-text red-text">DEPRECATED</div>` : ""}
|
|
88
|
+
${html` ${
|
|
89
|
+
path.xBadges && path.xBadges?.length > 0
|
|
90
|
+
? html`
|
|
91
|
+
<div style="display:flex; flex-wrap:wrap; margin-bottom: -24px; font-size: var(--font-size-small);">
|
|
92
|
+
${path.xBadges.map((v) =>
|
|
93
|
+
v.color === "none"
|
|
94
|
+
? ""
|
|
95
|
+
: html`<span
|
|
96
|
+
style="margin:1px; margin-right:5px; padding:1px 8px; font-weight:bold; border-radius:var(--radius); background: color-mix(in srgb, var(--${v.color}) 10%, transparent); color:var(--${v.color}); border:1px solid var(--${v.color})"
|
|
97
|
+
>${v.label}</span
|
|
98
|
+
>`,
|
|
99
|
+
)}
|
|
100
|
+
</div>
|
|
101
|
+
`
|
|
102
|
+
: ""
|
|
103
|
+
}
|
|
104
|
+
<h3 class="rapidoc-heading operation-summary" part="section-operation-summary heading heading-3">
|
|
105
|
+
${path.shortSummary || `${path.method.toUpperCase()} ${path.path}`}
|
|
106
|
+
</h3>
|
|
107
|
+
${
|
|
108
|
+
path.isWebhook
|
|
109
|
+
? html`<span
|
|
110
|
+
part="section-operation-webhook"
|
|
111
|
+
style="color:var(--primary); font-weight:bold; font-size: var(--font-size-regular);"
|
|
112
|
+
>
|
|
113
|
+
WEBHOOK
|
|
114
|
+
</span>`
|
|
115
|
+
: html`
|
|
116
|
+
<div
|
|
117
|
+
part="section-operation-webhook-method"
|
|
118
|
+
class="mono-font regular-font-size"
|
|
119
|
+
style="text-align:left; direction:ltr; padding: 8px 0; color:var(--muted-foreground)"
|
|
120
|
+
>
|
|
121
|
+
<span part="label-operation-method" class="regular-font upper method-fg bold-text ${path.method}">${path.method}</span>
|
|
122
|
+
<span style="overflow-wrap: break-word;" part="label-operation-path">${path.path}</span>
|
|
123
|
+
</div>
|
|
124
|
+
`
|
|
125
|
+
}
|
|
126
|
+
${pathSecurityTemplate.call(this, path.security, path.elementId)}
|
|
127
|
+
<slot name="${path.elementId}"></slot>`}
|
|
128
|
+
${path.description ? html`<div class="m-markdown">${unsafeHTML(sanitizeHTML(marked(path.description)))}</div>` : ""}
|
|
129
|
+
${
|
|
130
|
+
path.externalDocs?.url || path.externalDocs?.description
|
|
131
|
+
? html`<div class="external-docs-box">
|
|
132
|
+
<div class="m-markdown">${unsafeHTML(sanitizeHTML(marked(path.externalDocs?.description || "")))}</div>
|
|
133
|
+
${
|
|
134
|
+
path.externalDocs?.url
|
|
135
|
+
? html`<a class="external-docs-link" href="${path.externalDocs?.url}" target="_blank">
|
|
136
|
+
${path.externalDocs?.url}
|
|
137
|
+
<span class="external-docs-arrow">⇲</span>
|
|
138
|
+
</a>`
|
|
139
|
+
: ""
|
|
140
|
+
}
|
|
141
|
+
</div>`
|
|
142
|
+
: ""
|
|
143
|
+
}
|
|
144
|
+
${codeSampleTabPanel}
|
|
145
|
+
<div class="req-resp-container expanded-req-resp-container ${this.layout}-layout" part="section-req-resp-container">
|
|
146
|
+
<div class="request-panel view-mode-request ${this.renderStyle}-mode ${this.layout}-layout" part="section-request-panel">
|
|
147
|
+
<api-request
|
|
148
|
+
.config="${this.config}"
|
|
149
|
+
class="${this.renderStyle}-mode ${this.layout}-layout"
|
|
150
|
+
style="width:100%;"
|
|
151
|
+
webhook="${path.isWebhook}"
|
|
152
|
+
method="${path.method}"
|
|
153
|
+
path="${path.path}"
|
|
154
|
+
.security="${path.security}"
|
|
155
|
+
.parameters="${path.parameters}"
|
|
156
|
+
.request_body="${path.requestBody}"
|
|
157
|
+
.api_keys="${nonEmptyApiKeys}"
|
|
158
|
+
.servers="${path.servers}"
|
|
159
|
+
server-url="${path.servers?.[0]?.url || this.selectedServer?.computedUrl}"
|
|
160
|
+
fill-request-fields-with-example="${this.fillRequestFieldsWithExample}"
|
|
161
|
+
allow-try="${this.allowTry}"
|
|
162
|
+
show-curl-before-try="${this.showCurlBeforeTry}"
|
|
163
|
+
accept="${accept}"
|
|
164
|
+
render-style="${this.renderStyle}"
|
|
165
|
+
schema-style="${this.schemaStyle}"
|
|
166
|
+
active-schema-tab="${this.defaultSchemaTab}"
|
|
167
|
+
schema-expand-level="${this.schemaExpandLevel}"
|
|
168
|
+
schema-description-expanded="${this.schemaDescriptionExpanded}"
|
|
169
|
+
allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
|
|
170
|
+
schema-hide-read-only="${this.schemaHideReadOnly === "never" ? "false" : path.isWebhook ? "false" : "true"}"
|
|
171
|
+
schema-hide-write-only="${this.schemaHideWriteOnly === "never" ? "false" : path.isWebhook ? "true" : "false"}"
|
|
172
|
+
fetch-credentials="${this.fetchCredentials}"
|
|
173
|
+
exportparts="section-request-title:section-request-title, heading:heading, heading-4:heading-4, heading-5:heading-5, heading-6:heading-6,
|
|
174
|
+
wrap-request-btn:wrap-request-btn, btn:btn, btn-fill:btn-fill, btn-outline:btn-outline, btn-try:btn-try, btn-clear:btn-clear, btn-clear-resp:btn-clear-resp,
|
|
175
|
+
tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
|
|
176
|
+
file-input:file-input, textbox:textbox, textbox-param:textbox-param, textarea:textarea, textarea-param:textarea-param,
|
|
177
|
+
anchor:anchor, anchor-param-example:anchor-param-example, anchor-param-constraint:anchor-param-constraint, param-list:param-list, param:param, param-label:param-label, param-name:param-name, param-type:param-type, param-input:param-input, param-constraint:param-constraint, param-constraint-label:param-constraint-label, param-details:param-details, param-example-list:param-example-list, value-list:value-list, value-list-label:value-list-label, value-list-items:value-list-items, schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
|
|
178
|
+
>
|
|
179
|
+
</api-request>
|
|
180
|
+
|
|
181
|
+
${path.callbacks ? callbackTemplate.call(this, path.callbacks) : ""}
|
|
182
|
+
</div>
|
|
183
|
+
|
|
184
|
+
<api-response
|
|
185
|
+
.config="${this.config}"
|
|
186
|
+
class="response-panel ${this.renderStyle}-mode ${this.layout}-layout"
|
|
187
|
+
style="width:100%;"
|
|
188
|
+
webhook="${path.isWebhook}"
|
|
189
|
+
.responses="${path.responses}"
|
|
190
|
+
render-style="${this.renderStyle}"
|
|
191
|
+
schema-style="${this.schemaStyle}"
|
|
192
|
+
active-schema-tab="${this.defaultSchemaTab}"
|
|
193
|
+
schema-expand-level="${this.schemaExpandLevel}"
|
|
194
|
+
schema-description-expanded="${this.schemaDescriptionExpanded}"
|
|
195
|
+
allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
|
|
196
|
+
schema-hide-read-only="${this.schemaHideReadOnly === "never" ? "false" : path.isWebhook ? "true" : "false"}"
|
|
197
|
+
schema-hide-write-only="${this.schemaHideWriteOnly === "never" ? "false" : path.isWebhook ? "false" : "true"}"
|
|
198
|
+
selected-status="${Object.keys(path.responses || {})[0] || ""}"
|
|
199
|
+
exportparts="section-response-title:section-response-title, heading:heading, heading-4:heading-4, heading-5:heading-5, heading-6:heading-6,
|
|
200
|
+
btn:btn, btn-response-status:btn-response-status, btn-selected-response-status:btn-selected-response-status, btn-fill:btn-fill, btn-outline:btn-outline, btn-copy:btn-copy,
|
|
201
|
+
tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
|
|
202
|
+
schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle, param-list:param-list, param:param, param-label:param-label, param-name:param-name, param-type:param-type, param-constraint:param-constraint, param-constraint-label:param-constraint-label, param-details:param-details, param-example-list:param-example-list, value-list:value-list, value-list-label:value-list-label, value-list-items:value-list-items"
|
|
203
|
+
>
|
|
204
|
+
</api-response>
|
|
205
|
+
</div>
|
|
206
|
+
</div>
|
|
207
|
+
`;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export default function expandedEndpointTemplate() {
|
|
211
|
+
if (!this.resolvedSpec) {
|
|
212
|
+
return "";
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const renderTagSections = (tag) => html`
|
|
216
|
+
<section id="${tag.elementId}" part="section-tag" class="regular-font section-gap--read-mode observe-me read-mode-tag">
|
|
217
|
+
<h2 class="rapidoc-heading title tag" part="section-tag-title label-tag-title heading heading-2">${tag.displayName || tag.name}</h2>
|
|
218
|
+
<slot name="${tag.elementId}"></slot>
|
|
219
|
+
${unsafeHTML(`
|
|
220
|
+
<div class="m-markdown regular-font">
|
|
221
|
+
${sanitizeHTML(
|
|
222
|
+
marked(
|
|
223
|
+
tag.description || "",
|
|
224
|
+
this.infoDescriptionHeadingsInNavBar === "true"
|
|
225
|
+
? { renderer: headingRenderer(tag.elementId) }
|
|
226
|
+
: undefined,
|
|
227
|
+
),
|
|
228
|
+
)}
|
|
229
|
+
</div>`)}
|
|
230
|
+
</section>
|
|
231
|
+
<section class="regular-font section-gap--read-mode" part="section-operations-in-tag">
|
|
232
|
+
${tag.paths.map((path, idx) => expandedEndpointBodyTemplate.call(this, path, tag.name, tag.description, idx === 0))}
|
|
233
|
+
</section>
|
|
234
|
+
`;
|
|
235
|
+
|
|
236
|
+
if (this.resolvedSpec.tagGroups && this.resolvedSpec.tagGroups.length > 0) {
|
|
237
|
+
const assignedTagNames = new Set();
|
|
238
|
+
this.resolvedSpec.tagGroups.forEach((group) => {
|
|
239
|
+
(group.tags || []).forEach((tag) => assignedTagNames.add(tag.name.toLowerCase()));
|
|
240
|
+
});
|
|
241
|
+
const remainingTags = (this.resolvedSpec.tags || []).filter(
|
|
242
|
+
(tag) => !assignedTagNames.has(tag.name.toLowerCase()),
|
|
243
|
+
);
|
|
244
|
+
|
|
245
|
+
return html`
|
|
246
|
+
${this.resolvedSpec.tagGroups.map(
|
|
247
|
+
(group) => html`
|
|
248
|
+
<section id="${group.elementId}" part="section-tag-group" class="regular-font section-gap--read-mode observe-me read-mode-group">
|
|
249
|
+
<h2 class="rapidoc-heading title tag-group" part="section-tag-group-title heading heading-2">
|
|
250
|
+
${group.displayName || group.name}
|
|
251
|
+
</h2>
|
|
252
|
+
${
|
|
253
|
+
group.description
|
|
254
|
+
? html`<div class="m-markdown tag-group-description">${unsafeHTML(sanitizeHTML(marked(group.description)))}</div>`
|
|
255
|
+
: ""
|
|
256
|
+
}
|
|
257
|
+
</section>
|
|
258
|
+
${group.tags.map((tag) => renderTagSections(tag))}
|
|
259
|
+
`,
|
|
260
|
+
)}
|
|
261
|
+
${remainingTags.map((tag) => renderTagSections(tag))}
|
|
262
|
+
`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return html`${this.resolvedSpec.tags.map((tag) => renderTagSections(tag))}`;
|
|
266
|
+
}
|