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,315 @@
1
+ import { LitElement, html } from "lit";
2
+ import { property } from "lit/decorators.js";
3
+ import { unsafeHTML } from "lit/directives/unsafe-html.js";
4
+ import { marked } from "marked";
5
+ import { sanitizeHTML } from "../utils/sanitize.js";
6
+ import { blockSummary, firstLineHtml } from "../utils/markdown-utils.js";
7
+
8
+ // Markdown or HTML syntax, a bare URL or e-mail (GFM autolinks), or a list, quote, heading or rule marker at the start
9
+ const MARKDOWN_SYNTAX = /[*_`~[\]<>#|\\&\n]|https?:|ftp:|www\.|@|^([-+]|\d+[.)])\s|^-{3,}$/;
10
+
11
+ function isPlainText(text) {
12
+ return !MARKDOWN_SYNTAX.test(text);
13
+ }
14
+
15
+ // Rendered markdown descriptions by source text: large specs repeat the same description thousands of times
16
+ const markdownCache = new Map();
17
+ const MARKDOWN_CACHE_SIZE = 5000;
18
+
19
+ /**
20
+ * Markdown description as sanitized HTML, with the one-line summary and whether the row hides content (see renderDescrCell).
21
+ * @param {string} text - Markdown description, trimmed
22
+ * @param {string} title - Schema title, shown in bold before the description
23
+ * @returns {{ summary: string, html: string, hasMore: boolean }}
24
+ */
25
+ function renderMarkdownDescription(text, title) {
26
+ const key = `${title}\n\n${text}`;
27
+ let rendered = markdownCache.get(key);
28
+ if (rendered) {
29
+ return rendered;
30
+ }
31
+ const firstBlock: any = text ? marked.lexer(text).find((t: any) => t.type !== "space") : null;
32
+ const blockLine = blockSummary(firstBlock);
33
+ // A title can only be prefixed inline to a paragraph; before a list, heading, table, ... it gets its own paragraph
34
+ const titleHtml = title ? `<b>${title}${text ? ":" : ""}</b>` : "";
35
+ const titleOwnBlock = !!titleHtml && !!firstBlock && firstBlock.type !== "paragraph";
36
+ const summary = titleOwnBlock
37
+ ? `${titleHtml} ${blockLine || firstLineHtml(firstBlock)}`
38
+ : blockLine;
39
+ const markdown =
40
+ titleHtml && text ? `${titleHtml}${titleOwnBlock ? "\n\n" : " "}${text}` : titleHtml || text;
41
+ const tokens = markdown ? marked.lexer(markdown) : [];
42
+ const blocks = tokens.filter((t: any) => t.type !== "space");
43
+ rendered = {
44
+ summary: summary ? sanitizeHTML(summary) : "",
45
+ html: blocks.length ? sanitizeHTML(marked.parser(tokens)).trim() : "",
46
+ hasMore:
47
+ !!summary ||
48
+ blocks.length > 1 ||
49
+ (blocks[0]?.type === "list" && blocks[0].items.length > 1) ||
50
+ /<br\s*\/?>(?!\s*$)/i.test(markdown),
51
+ };
52
+ if (markdownCache.size >= MARKDOWN_CACHE_SIZE) {
53
+ markdownCache.clear();
54
+ }
55
+ markdownCache.set(key, rendered);
56
+ return rendered;
57
+ }
58
+
59
+ export default class SchemaBaseElement extends LitElement {
60
+ @property({ type: Object }) config: any;
61
+ @property({ type: Object }) data: any;
62
+ @property({ type: Number, attribute: "schema-expand-level" }) schemaExpandLevel = 99999;
63
+ @property({ type: String, attribute: "schema-description-expanded" }) schemaDescriptionExpanded =
64
+ "false";
65
+ @property({ type: String, attribute: "allow-schema-description-expand-toggle" })
66
+ allowSchemaDescriptionExpandToggle = "false";
67
+ @property({ type: String, attribute: "schema-hide-read-only" }) schemaHideReadOnly = "true";
68
+ @property({ type: String, attribute: "schema-hide-write-only" }) schemaHideWriteOnly = "true";
69
+
70
+ willUpdate(changedProperties) {
71
+ super.willUpdate?.(changedProperties);
72
+ if (this.config && changedProperties.has("config")) {
73
+ if (this.config.schemaExpandLevel !== undefined)
74
+ this.schemaExpandLevel = this.config.schemaExpandLevel;
75
+ if (this.config.schemaDescriptionExpanded !== undefined)
76
+ this.schemaDescriptionExpanded = this.config.schemaDescriptionExpanded;
77
+ if (this.config.allowSchemaDescriptionExpandToggle !== undefined)
78
+ this.allowSchemaDescriptionExpandToggle = this.config.allowSchemaDescriptionExpandToggle;
79
+ if (this.config.schemaHideReadOnly !== undefined)
80
+ this.schemaHideReadOnly = this.config.schemaHideReadOnly;
81
+ if (this.config.schemaHideWriteOnly !== undefined)
82
+ this.schemaHideWriteOnly = this.config.schemaHideWriteOnly;
83
+ }
84
+ if (!this.schemaExpandLevel || this.schemaExpandLevel < 1) {
85
+ this.schemaExpandLevel = 99999;
86
+ }
87
+ if (!this.schemaDescriptionExpanded || !"true false".includes(this.schemaDescriptionExpanded)) {
88
+ this.schemaDescriptionExpanded = "false";
89
+ }
90
+ if (!this.schemaHideReadOnly || !"true false".includes(this.schemaHideReadOnly)) {
91
+ this.schemaHideReadOnly = "true";
92
+ }
93
+ if (!this.schemaHideWriteOnly || !"true false".includes(this.schemaHideWriteOnly)) {
94
+ this.schemaHideWriteOnly = "true";
95
+ }
96
+ }
97
+
98
+ handleAllEvents(e) {
99
+ const toggleTrigger = e.target.closest(".open-bracket, .obj-toggle");
100
+ if (toggleTrigger) {
101
+ this.toggleObjectExpand(toggleTrigger);
102
+ } else if (e.target.classList.contains("schema-multiline-toggle")) {
103
+ this.schemaDescriptionExpanded = this.schemaDescriptionExpanded === "true" ? "false" : "true";
104
+ } else if (e.target.closest(".descr-expand-toggle, .descr-body")) {
105
+ // Links inside a description still navigate, and selecting text to copy it doesn't toggle the row
106
+ if (
107
+ this.schemaDescriptionExpanded === "true" ||
108
+ e.target.closest("a") ||
109
+ window.getSelection()?.isCollapsed === false
110
+ ) {
111
+ return;
112
+ }
113
+ const trEl = e.target.closest(".tr");
114
+ if (
115
+ trEl &&
116
+ (trEl.classList.contains("expanded-descr") ||
117
+ this.descrHasMore(e.target.closest(".descr-body")))
118
+ ) {
119
+ const isExpanded = trEl.classList.toggle("expanded-descr");
120
+ trEl
121
+ .querySelector(".descr-expand-toggle")
122
+ ?.setAttribute("aria-expanded", isExpanded ? "true" : "false");
123
+ }
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Whether a collapsed description has more to show, so a click expands it: CSS shows the arrow for those rows,
129
+ * and a line cut off for length counts too (browsers without scroll-state queries can't show the arrow for it).
130
+ * Read at click time only; nothing measures rows as they render or resize.
131
+ */
132
+ descrHasMore(bodyEl) {
133
+ if (!bodyEl) {
134
+ return false;
135
+ }
136
+ const toggleEl = bodyEl.querySelector(":scope > .descr-expand-toggle");
137
+ return (
138
+ (toggleEl && getComputedStyle(toggleEl).visibility === "visible") ||
139
+ bodyEl.scrollWidth > bodyEl.clientWidth
140
+ );
141
+ }
142
+
143
+ handleKeyDown(e) {
144
+ if (e.key === "Enter" || e.key === " ") {
145
+ const toggleTrigger = e.target.closest(
146
+ ".open-bracket, .obj-toggle, .descr-expand-toggle, .schema-multiline-toggle",
147
+ );
148
+ if (toggleTrigger) {
149
+ e.preventDefault();
150
+ toggleTrigger.click();
151
+ }
152
+ }
153
+ }
154
+
155
+ toggleObjectExpand(targetEl) {
156
+ const rowEl = targetEl.closest(".tr");
157
+ if (!rowEl) {
158
+ return;
159
+ }
160
+ const isExpanding = rowEl.classList.contains("collapsed");
161
+ if (isExpanding) {
162
+ rowEl.classList.replace("collapsed", "expanded");
163
+ } else {
164
+ rowEl.classList.replace("expanded", "collapsed");
165
+ }
166
+ const toggleEl = rowEl.querySelector(".open-bracket, .obj-toggle");
167
+ if (toggleEl) {
168
+ toggleEl.setAttribute("aria-expanded", isExpanding ? "true" : "false");
169
+ }
170
+ }
171
+
172
+ isFieldHidden(node) {
173
+ if (!node) {
174
+ return true;
175
+ }
176
+ if (this.schemaHideReadOnly === "true" && node.readOnly) {
177
+ return true;
178
+ }
179
+ if (this.schemaHideWriteOnly === "true" && node.writeOnly) {
180
+ return true;
181
+ }
182
+ return false;
183
+ }
184
+
185
+ // Ends with the space before the name, so rows without the icon have no whitespace node there
186
+ renderDeprecatedIcon(node) {
187
+ return node?.deprecated
188
+ ? html`<svg viewBox="0 0 10 10" width="10" height="10" style="stroke:var(--destructive); margin-right:-6px">
189
+ <path d="M2 2L8 8M2 8L8 2" />
190
+ </svg> `
191
+ : "";
192
+ }
193
+
194
+ getReadWriteBadge(node) {
195
+ return node?.readOnly ? html` 🆁` : node?.writeOnly ? html` 🆆` : "";
196
+ }
197
+
198
+ getReadWriteTip(node) {
199
+ return node?.readOnly ? "Read-Only" : node?.writeOnly ? "Write-Only" : "";
200
+ }
201
+
202
+ getDataTypeCss(type) {
203
+ return (type || "")
204
+ .replace(/┃.*/g, "")
205
+ .replace(/[^a-zA-Z0-9+]/g, "")
206
+ .substring(0, 4)
207
+ .toLowerCase();
208
+ }
209
+
210
+ hasDetailChips(node) {
211
+ return Boolean(
212
+ node &&
213
+ (node.constraints ||
214
+ node.defaultValue ||
215
+ node.allowedValues ||
216
+ node.pattern ||
217
+ node.contentMediaType ||
218
+ node.contentEncoding),
219
+ );
220
+ }
221
+
222
+ renderDetailChips(node) {
223
+ if (!node) {
224
+ return "";
225
+ }
226
+ return html`
227
+ ${node.constraints ? html`<div class="descr-chip"><span class="descr-label">Constraints:</span> <span class="descr-value">${node.constraints}</span></div>` : ""}
228
+ ${node.defaultValue ? html`<div class="descr-chip"><span class="descr-label">Default:</span> <span class="descr-value">${node.defaultValue}</span></div>` : ""}
229
+ ${node.allowedValues ? html`<div class="descr-chip"><span class="descr-label">${node.type === "const" ? "Value" : "Allowed"}:</span> <span class="descr-value">${node.allowedValues}</span></div>` : ""}
230
+ ${node.pattern ? html`<div class="descr-chip"><span class="descr-label">Pattern:</span> <span class="descr-value">${node.pattern}</span></div>` : ""}
231
+ ${node.contentMediaType ? html`<div class="descr-chip"><span class="descr-label">Media-Type:</span> <span class="descr-value">${node.contentMediaType}</span></div>` : ""}
232
+ ${node.contentEncoding ? html`<div class="descr-chip"><span class="descr-label">Encoding:</span> <span class="descr-value">${node.contentEncoding}</span></div>` : ""}
233
+ `;
234
+ }
235
+
236
+ renderDescriptionHtml(desc, title = "") {
237
+ if (!desc && !title) {
238
+ return "";
239
+ }
240
+ const text = title ? (desc ? `<b>${title}:</b> ${desc}` : `<b>${title}</b>`) : desc;
241
+ return html`${unsafeHTML(sanitizeHTML(marked(text)))}`;
242
+ }
243
+
244
+ /**
245
+ * Description cell shared by every schema row.
246
+ * Collapsed rows show only the first markdown block (or the constraint chips, when there is no description) on one line,
247
+ * and CSS marks a cut-off line with an ellipsis.
248
+ * A first block that cannot fit on one line (table, code block, HTML block, blockquote) is replaced there by a summary
249
+ * line (`.descr-summary`), which CSS shows only in collapsed rows. A title before any block other than a paragraph
250
+ * (list, heading, table, ...) gets a paragraph of its own, and the summary line is the title plus the block's first line.
251
+ * CSS shows the arrow when the row has hidden content (the `has-more` class: more markdown blocks, a line break,
252
+ * a summarized block, or chips under the text) or, where scroll-state container queries work, when the line is cut off.
253
+ * The arrow sits inside the description box so those queries can reach it.
254
+ *
255
+ * @param {string} desc - Markdown description
256
+ * @param {object} [chipsNode] - Node whose constraints, default, allowed values, etc. are shown as chips
257
+ * @param {string} [title] - Schema title, shown in bold before the description
258
+ */
259
+ renderDescrCell(desc, chipsNode = null, title = "") {
260
+ const text = typeof desc === "string" ? desc.trim() : "";
261
+ const hasChips = this.hasDetailChips(chipsNode);
262
+ if (!text && !title && !hasChips) {
263
+ return html`<div class="td key-descr"></div>`;
264
+ }
265
+ let body;
266
+ let hasMore;
267
+ if (isPlainText(text) && isPlainText(title)) {
268
+ // Most descriptions are plain sentences: shown as they are, without the markdown parser, the sanitizer and the HTML parse
269
+ body = title
270
+ ? html`<p><b>${title}${text ? ":" : ""}</b> ${text}</p>`
271
+ : text
272
+ ? html`<p>${text}</p>`
273
+ : "";
274
+ hasMore = hasChips && !!body;
275
+ } else {
276
+ const rendered = renderMarkdownDescription(text, title);
277
+ body = html`${rendered.summary ? html`<span class="descr-summary">${unsafeHTML(rendered.summary)}</span>` : ""}${rendered.html ? unsafeHTML(rendered.html) : ""}`;
278
+ hasMore = rendered.hasMore || (!!rendered.html && hasChips);
279
+ }
280
+ const isExpanded = this.schemaDescriptionExpanded === "true";
281
+ // The arrow, the text and the chips sit next to each other: whitespace between them would be a text node per row
282
+ return html`
283
+ <div class="td key-descr">
284
+ <div class="descr-body m-markdown-small ${hasMore ? "has-more" : ""}">
285
+ <span
286
+ class="descr-expand-toggle"
287
+ role="button"
288
+ tabindex="0"
289
+ aria-label="Toggle description"
290
+ aria-expanded="${isExpanded ? "true" : "false"}"
291
+ >➔</span
292
+ >${body}${hasChips ? html`<div class="item-details">${this.renderDetailChips(chipsNode)}</div>` : ""}
293
+ </div>
294
+ </div>
295
+ `;
296
+ }
297
+
298
+ renderToolbar(rootType) {
299
+ return html`
300
+ <div class="toolbar">
301
+ <div class="toolbar-item schema-root-type ${rootType} ">${rootType}</div>
302
+ ${
303
+ this.allowSchemaDescriptionExpandToggle === "true"
304
+ ? html`
305
+ <div style="flex:1"></div>
306
+ <div part="schema-toolbar-item schema-multiline-toggle" class="toolbar-item schema-multiline-toggle">
307
+ ${this.schemaDescriptionExpanded === "true" ? "Single line description" : "Multiline description"}
308
+ </div>
309
+ `
310
+ : ""
311
+ }
312
+ </div>
313
+ `;
314
+ }
315
+ }