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.
Files changed (80) hide show
  1. package/README.md +46 -31
  2. package/dist/rapidoc-min.js +1424 -213
  3. package/dist/rapidoc-static-min.js +13542 -0
  4. package/package.json +47 -35
  5. package/src/components/api-request.ts +869 -0
  6. package/src/components/api-response.ts +509 -0
  7. package/src/components/json-tree.ts +171 -0
  8. package/src/components/schema-base-element.ts +315 -0
  9. package/src/components/schema-table.ts +430 -0
  10. package/src/components/schema-tree.ts +386 -0
  11. package/src/components/tag-input.ts +184 -0
  12. package/src/index.js +6 -0
  13. package/src/oauth-receiver.ts +29 -0
  14. package/src/rapidoc-mini.ts +582 -0
  15. package/src/rapidoc.ts +1808 -0
  16. package/src/static/index.d.ts +149 -0
  17. package/src/static/index.js +62 -0
  18. package/src/static/navigation.js +497 -0
  19. package/src/static/render.js +490 -0
  20. package/src/static/serializer.js +216 -0
  21. package/src/styles/auth-styles.js +318 -0
  22. package/src/styles/border-styles.js +24 -0
  23. package/src/styles/css-bundle.js +129 -0
  24. package/src/styles/custom-styles.js +8 -0
  25. package/src/styles/dialog-box-styles.js +102 -0
  26. package/src/styles/endpoint-styles.js +559 -0
  27. package/src/styles/flex-styles.js +16 -0
  28. package/src/styles/font-styles.js +432 -0
  29. package/src/styles/info-styles.js +36 -0
  30. package/src/styles/input-styles.js +555 -0
  31. package/src/styles/layout-styles.js +396 -0
  32. package/src/styles/microlighter-styles.js +99 -0
  33. package/src/styles/nav-styles.js +609 -0
  34. package/src/styles/param-list-styles.js +261 -0
  35. package/src/styles/schema-styles.js +288 -0
  36. package/src/styles/tab-styles.js +106 -0
  37. package/src/styles/theme-tokens.js +582 -0
  38. package/src/templates/advanced-search-dialog-template.js +94 -0
  39. package/src/templates/api-response-template.js +219 -0
  40. package/src/templates/callback-template.js +86 -0
  41. package/src/templates/code-samples-template.js +52 -0
  42. package/src/templates/components-template.js +86 -0
  43. package/src/templates/downloads-template.js +85 -0
  44. package/src/templates/endpoint-template.js +386 -0
  45. package/src/templates/expanded-endpoint-template.js +266 -0
  46. package/src/templates/focused-endpoint-template.js +145 -0
  47. package/src/templates/header-template.js +92 -0
  48. package/src/templates/logo-template.js +21 -0
  49. package/src/templates/main-body-template.js +102 -0
  50. package/src/templates/navbar-template.js +489 -0
  51. package/src/templates/overview-template.js +104 -0
  52. package/src/templates/request-body-template.js +651 -0
  53. package/src/templates/request-params-template.js +474 -0
  54. package/src/templates/security-scheme-template.js +1263 -0
  55. package/src/templates/server-template.js +152 -0
  56. package/src/utils/auto-color-scheme.js +99 -0
  57. package/src/utils/bind-navbar.js +175 -0
  58. package/src/utils/color-utils.js +59 -0
  59. package/src/utils/common-utils.js +191 -0
  60. package/src/utils/curl-utils.js +123 -0
  61. package/src/utils/highlighter.js +416 -0
  62. package/src/utils/markdown-utils.js +110 -0
  63. package/src/utils/mcp/common.js +467 -0
  64. package/src/utils/mcp/generators/csharp.js +242 -0
  65. package/src/utils/mcp/generators/go.js +298 -0
  66. package/src/utils/mcp/generators/java.js +330 -0
  67. package/src/utils/mcp/generators/python.js +248 -0
  68. package/src/utils/mcp/generators/rust.js +281 -0
  69. package/src/utils/mcp/generators/typescript.js +290 -0
  70. package/src/utils/mcp-generator.js +143 -0
  71. package/src/utils/mock-interceptor.js +508 -0
  72. package/src/utils/oauth-utils.js +87 -0
  73. package/src/utils/request-utils.js +203 -0
  74. package/src/utils/response-utils.js +203 -0
  75. package/src/utils/sanitize.js +57 -0
  76. package/src/utils/schema-utils.js +1927 -0
  77. package/src/utils/slugger.js +189 -0
  78. package/src/utils/spec-parser.js +915 -0
  79. package/src/utils/url-utils.js +211 -0
  80. 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
+ &nbsp;|&nbsp;
341
+ <span @click="${(e) => onExpandCollapseAll(e, "collapse-all")}" style="color:var(--primary); cursor:pointer;">
342
+ Collapse all
343
+ </span>
344
+ &nbsp; 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
+ }