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