rapidoc 12.0.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.md +127 -25
  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 +541 -1309
  5. package/dist/rapidoc-min.js.LICENSE.txt +381 -0
  6. package/package.json +21 -18
  7. package/src/README.md +150 -0
  8. package/src/components/README.md +91 -0
  9. package/src/components/api-request.ts +43 -0
  10. package/src/components/api-response.ts +9 -4
  11. package/src/components/schema-base-element.ts +18 -4
  12. package/src/components/schema-table.ts +58 -13
  13. package/src/components/schema-tree.ts +7 -0
  14. package/src/components/tag-input.ts +5 -9
  15. package/src/flow.js +3 -0
  16. package/src/rapi-flow.ts +1178 -0
  17. package/src/rapidoc-mini.ts +27 -6
  18. package/src/rapidoc.ts +108 -62
  19. package/src/styles/README.md +96 -0
  20. package/src/styles/css-bundle.js +2 -2
  21. package/src/styles/endpoint-styles.js +6 -1
  22. package/src/styles/flow-styles.js +248 -0
  23. package/src/styles/nav-styles.js +39 -15
  24. package/src/styles/schema-styles.js +13 -5
  25. package/src/styles/theme-tokens.js +2 -2
  26. package/src/templates/README.md +89 -0
  27. package/src/templates/api-response-template.js +14 -10
  28. package/src/templates/callback-template.js +1 -1
  29. package/src/templates/downloads-template.js +12 -27
  30. package/src/templates/endpoint-template.js +15 -24
  31. package/src/templates/expanded-endpoint-template.js +8 -4
  32. package/src/templates/focused-endpoint-template.js +4 -3
  33. package/src/templates/navbar-template.js +20 -11
  34. package/src/templates/request-body-template.js +29 -7
  35. package/src/templates/request-params-template.js +15 -4
  36. package/src/templates/security-scheme-template.js +11 -2
  37. package/src/templates/server-template.js +3 -2
  38. package/src/utils/README.md +146 -0
  39. package/src/utils/arazzo/README.md +119 -0
  40. package/src/utils/arazzo/components.js +15 -0
  41. package/src/utils/arazzo/graph.js +269 -0
  42. package/src/utils/arazzo/index.js +52 -0
  43. package/src/utils/arazzo/operations.js +106 -0
  44. package/src/utils/arazzo/parse.js +196 -0
  45. package/src/utils/arazzo/refs.js +40 -0
  46. package/src/utils/arazzo/svg.js +707 -0
  47. package/src/utils/curl-utils.js +5 -2
  48. package/src/utils/highlighter.js +3 -0
  49. package/src/utils/mcp/README.md +155 -0
  50. package/src/utils/mcp/common.js +45 -346
  51. package/src/utils/mcp/manifest.js +382 -0
  52. package/src/utils/mcp/project/server.ts +53 -0
  53. package/src/utils/mcp/project.js +88 -0
  54. package/src/utils/mcp/runtime.js +289 -0
  55. package/src/utils/mcp/schema.js +98 -0
  56. package/src/utils/mcp/workflow-runtime.js +374 -0
  57. package/src/utils/mcp/workflows.js +240 -0
  58. package/src/utils/mcp/zip.js +102 -0
  59. package/src/utils/mcp-generator.js +29 -125
  60. package/src/utils/mock-interceptor.js +134 -85
  61. package/src/utils/request-utils.js +61 -0
  62. package/src/utils/schema-utils.js +33 -6
  63. package/src/utils/slugger.js +5 -7
  64. package/src/utils/spec-parser.js +190 -164
  65. package/src/utils/url-utils.js +36 -1
  66. package/dist/rapidoc-static-min.js +0 -13542
  67. package/src/static/index.d.ts +0 -149
  68. package/src/static/index.js +0 -62
  69. package/src/static/navigation.js +0 -497
  70. package/src/static/render.js +0 -490
  71. package/src/static/serializer.js +0 -216
  72. package/src/utils/mcp/generators/csharp.js +0 -242
  73. package/src/utils/mcp/generators/go.js +0 -298
  74. package/src/utils/mcp/generators/java.js +0 -330
  75. package/src/utils/mcp/generators/python.js +0 -248
  76. package/src/utils/mcp/generators/rust.js +0 -281
  77. package/src/utils/mcp/generators/typescript.js +0 -290
@@ -0,0 +1,248 @@
1
+ import { css } from "lit";
2
+
3
+ /**
4
+ * Styles for the workflow diagram drawn by utils/arazzo/svg.js. Shared by <rapi-flow> and by
5
+ * build-time pages (@rapidoc/prerender `getFlowCss()`), so selectors are plain classes, not :host.
6
+ */
7
+ export default css`
8
+ .rf-svg {
9
+ display: block;
10
+ max-width: 100%;
11
+ height: auto;
12
+ font-family: var(--font-sans);
13
+ font-size: var(--font-size-description);
14
+ overflow: visible;
15
+ }
16
+ .rf-node rect {
17
+ fill: var(--card);
18
+ stroke: var(--border);
19
+ stroke-width: 1.25;
20
+ }
21
+ .rf-io rect {
22
+ fill: var(--muted);
23
+ }
24
+ .rf-title {
25
+ fill: color-mix(in srgb, var(--primary) 65%, var(--foreground));
26
+ font-weight: 600;
27
+ font-size: var(--font-size-regular);
28
+ }
29
+ .rf-sub {
30
+ fill: var(--muted-foreground);
31
+ }
32
+ .rf-io-title,
33
+ .rf-criteria {
34
+ fill: var(--muted-foreground);
35
+ font-size: var(--font-size-xs);
36
+ text-transform: uppercase;
37
+ letter-spacing: 0.04em;
38
+ }
39
+ .rf-criteria {
40
+ text-transform: none;
41
+ letter-spacing: normal;
42
+ }
43
+ .rf-path,
44
+ .rf-method,
45
+ .rf-unresolved {
46
+ font-family: var(--font-mono);
47
+ font-size: var(--font-size-small);
48
+ }
49
+ .rf-path {
50
+ fill: var(--foreground);
51
+ }
52
+ .rf-method {
53
+ font-weight: 700;
54
+ fill: var(--method-default);
55
+ }
56
+ .rf-method-get { fill: var(--method-get); }
57
+ .rf-method-post { fill: var(--method-post); }
58
+ .rf-method-put { fill: var(--method-put); }
59
+ .rf-method-delete { fill: var(--method-delete); }
60
+ .rf-method-patch { fill: var(--method-patch); }
61
+ .rf-method-head { fill: var(--method-head); }
62
+ .rf-method-options { fill: var(--method-options); }
63
+ .rf-method-trace { fill: var(--method-trace); }
64
+ .rf-method-query { fill: var(--method-query); }
65
+ .rf-unresolved {
66
+ fill: var(--muted-foreground);
67
+ font-style: italic;
68
+ }
69
+ .rf-jump {
70
+ cursor: pointer;
71
+ outline: none;
72
+ }
73
+ .rf-jump:hover .rf-step-name,
74
+ .rf-tag.rf-jump:hover,
75
+ .rf-tag.rf-jump:focus-visible {
76
+ text-decoration: underline;
77
+ }
78
+ .rf-clickable {
79
+ cursor: pointer;
80
+ outline: none;
81
+ }
82
+ .rf-clickable:hover rect,
83
+ .rf-clickable:focus-visible rect {
84
+ stroke: var(--primary);
85
+ stroke-width: 2;
86
+ }
87
+ .rf-selected rect {
88
+ stroke: var(--primary);
89
+ stroke-width: 2;
90
+ }
91
+ .rf-seq {
92
+ fill: none;
93
+ stroke: var(--muted-foreground);
94
+ stroke-width: 1.25;
95
+ }
96
+ .rf-head-seq {
97
+ fill: var(--muted-foreground);
98
+ }
99
+ .rf-data {
100
+ fill: none;
101
+ stroke: var(--primary);
102
+ stroke-width: 1.5;
103
+ stroke-dasharray: 5 4;
104
+ }
105
+ .rf-head-data {
106
+ fill: var(--primary);
107
+ }
108
+ .rf-data.rf-to-output {
109
+ stroke: var(--muted-foreground);
110
+ }
111
+ .rf-head-output {
112
+ fill: var(--muted-foreground);
113
+ }
114
+ .rf-sep {
115
+ fill: none;
116
+ stroke: var(--border);
117
+ stroke-width: 1;
118
+ }
119
+ .rf-row {
120
+ font-size: var(--font-size-small);
121
+ }
122
+ .rf-in-name,
123
+ .rf-out-name,
124
+ .rf-bind-name,
125
+ .rf-bind-val,
126
+ .rf-act-when,
127
+ .rf-act-then {
128
+ fill: var(--foreground);
129
+ }
130
+ .rf-bind-name,
131
+ .rf-bind-val,
132
+ .rf-kw,
133
+ .rf-in-type,
134
+ .rf-in-default,
135
+ .rf-in-enum {
136
+ font-family: var(--font-mono);
137
+ }
138
+ .rf-in-type,
139
+ .rf-in-default,
140
+ .rf-in-enum,
141
+ .rf-out-from,
142
+ .rf-out-kind,
143
+ .rf-act-name,
144
+ .rf-more,
145
+ .rf-tag,
146
+ .rf-sec-title {
147
+ fill: var(--muted-foreground);
148
+ }
149
+ .rf-kw,
150
+ .rf-out-kind {
151
+ font-weight: 600;
152
+ }
153
+ /* Step names are the step color wherever they appear: box titles, value lines, outputs */
154
+ /* --primary mixed toward the text color keeps the hue and reads at 4.5:1 on light cards */
155
+ .rf-step-name,
156
+ .rf-kw-step,
157
+ .rf-tag.rf-out-step,
158
+ .rf-row.rf-linked .rf-out-name {
159
+ fill: color-mix(in srgb, var(--primary) 65%, var(--foreground));
160
+ }
161
+ .rf-tag.rf-out-step {
162
+ font-size: var(--font-size-small);
163
+ font-weight: 600;
164
+ }
165
+ /* Hover linking (<rapi-flow>): a step, its lines and its rows in the outputs box */
166
+ .rf-step.rf-linked rect {
167
+ stroke: var(--primary);
168
+ stroke-width: 2;
169
+ }
170
+ .rf-data.rf-linked {
171
+ stroke-width: 2.5;
172
+ }
173
+ /* A run in <rapi-flow>: the step whose request is in flight */
174
+ .rf-step.rf-running rect {
175
+ stroke: var(--primary);
176
+ stroke-width: 2;
177
+ stroke-dasharray: 6 4;
178
+ animation: rf-march 1s linear infinite;
179
+ }
180
+ @keyframes rf-march {
181
+ to {
182
+ stroke-dashoffset: -20;
183
+ }
184
+ }
185
+ .rf-io .rf-sep {
186
+ stroke: var(--muted-foreground);
187
+ stroke-opacity: 0.35;
188
+ }
189
+ .rf-out-from {
190
+ font-family: var(--font-mono);
191
+ }
192
+ .rf-kw-input {
193
+ fill: var(--blue);
194
+ }
195
+ .rf-kw-value,
196
+ .rf-kw-expression {
197
+ fill: var(--muted-foreground);
198
+ }
199
+ .rf-req {
200
+ fill: var(--destructive);
201
+ font-size: var(--font-size-xs);
202
+ font-weight: 600;
203
+ }
204
+ .rf-more,
205
+ .rf-tag,
206
+ .rf-sec-title {
207
+ font-size: var(--font-size-xs);
208
+ }
209
+ .rf-sec-title {
210
+ text-transform: uppercase;
211
+ letter-spacing: 0.04em;
212
+ }
213
+ .rf-check-type {
214
+ fill: var(--muted-foreground);
215
+ }
216
+ .rf-check-type,
217
+ .rf-check {
218
+ font-family: var(--font-mono);
219
+ }
220
+ .rf-check {
221
+ fill: var(--foreground);
222
+ }
223
+ .rf-data-label rect {
224
+ fill: var(--background);
225
+ stroke: var(--primary);
226
+ stroke-width: 1;
227
+ }
228
+ .rf-data-label text {
229
+ fill: var(--foreground);
230
+ font-size: var(--font-size-xs);
231
+ }
232
+ .rf-goto {
233
+ fill: none;
234
+ stroke-width: 1.5;
235
+ }
236
+ .rf-goto.rf-success {
237
+ stroke: var(--green);
238
+ }
239
+ .rf-goto.rf-failure {
240
+ stroke: var(--destructive);
241
+ }
242
+ .rf-head-success {
243
+ fill: var(--green);
244
+ }
245
+ .rf-head-failure {
246
+ fill: var(--destructive);
247
+ }
248
+ `;
@@ -59,6 +59,8 @@ export default css`
59
59
  border: 1px solid var(--input);
60
60
  border-radius: var(--radius);
61
61
  background: var(--input-background);
62
+ /* Inputs do not inherit the page font; getNavCss() puts this on a page, outside the element's input styles. */
63
+ font-family: inherit;
62
64
  font-size: calc(var(--font-size-small) + 1px);
63
65
  box-sizing: border-box;
64
66
  transition:
@@ -175,15 +177,34 @@ export default css`
175
177
  justify-content: space-between;
176
178
  flex-direction: row;
177
179
  }
178
- .nav-bar-paths-under-tag {
180
+ /* Collapsing a tag or tag group slides its body shut: height auto -> 0 (interpolate-size lets the
181
+ keyword animate; browsers without it switch at once). The body goes visibility: hidden once
182
+ closed, so its links leave the tab order; opening shows it at once. */
183
+ .nav-bar-paths-under-tag,
184
+ .nav-bar-tags-under-group {
185
+ interpolate-size: allow-keywords;
186
+ height: auto;
179
187
  overflow: hidden;
180
- padding-left: 10px;
188
+ transition:
189
+ height 0.25s ease,
190
+ visibility 0s;
181
191
  }
182
- .collapsed .nav-bar-paths-under-tag,
183
- .nav-bar-tag-and-paths.collapsed .nav-bar-paths-under-tag {
184
- display: none;
192
+ .nav-bar-tag-and-paths.collapsed .nav-bar-paths-under-tag,
193
+ .nav-bar-tag-group.collapsed .nav-bar-tags-under-group {
194
+ height: 0;
185
195
  visibility: hidden;
186
- max-height: 0;
196
+ transition:
197
+ height 0.25s ease,
198
+ visibility 0s linear 0.25s;
199
+ }
200
+ @media (prefers-reduced-motion: reduce) {
201
+ .nav-bar-paths-under-tag,
202
+ .nav-bar-tags-under-group {
203
+ transition: none;
204
+ }
205
+ }
206
+ .nav-bar-paths-under-tag {
207
+ padding-left: 10px;
187
208
  }
188
209
 
189
210
  .nav-bar-expand-all {
@@ -268,7 +289,7 @@ export default css`
268
289
  font-weight: 700;
269
290
  text-transform: uppercase;
270
291
  letter-spacing: 0.05em;
271
- color: var(--foreground);
292
+ color: var(--sidebar-foreground);
272
293
  cursor: pointer;
273
294
  user-select: none;
274
295
  border-inline-start: 4px solid transparent;
@@ -277,15 +298,12 @@ export default css`
277
298
  color 0.15s ease;
278
299
  }
279
300
  .nav-bar-tag-group-header:hover {
280
- color: var(--foreground);
301
+ color: var(--sidebar-accent-foreground);
281
302
  }
282
303
  .nav-bar-tag-group-title {
283
304
  flex: 1;
284
305
  min-width: 0;
285
306
  }
286
- .nav-bar-tag-group.collapsed .nav-bar-tags-under-group {
287
- display: none;
288
- }
289
307
  .nav-bar-tags-under-group {
290
308
  border-inline-start: 1px solid var(--border);
291
309
  margin-inline-start: 10px;
@@ -313,6 +331,10 @@ export default css`
313
331
  color: inherit;
314
332
  text-decoration: none;
315
333
  }
334
+ /* a description-only tag (show-unused-tags) is itself the link */
335
+ a.nav-bar-tag {
336
+ text-decoration: none;
337
+ }
316
338
 
317
339
  .nav-bar-components,
318
340
  .nav-bar-h1,
@@ -322,11 +344,15 @@ export default css`
322
344
  .nav-bar-path {
323
345
  display: flex;
324
346
  cursor: pointer;
347
+ /* Border-box and no underline here too: getNavCss() (@rapidoc/prerender) styles these on a page
348
+ without the component's global box-sizing reset and link styles */
349
+ box-sizing: border-box;
325
350
  width: 100%;
326
351
  border: none;
327
- color: var(--foreground);
352
+ color: var(--sidebar-foreground);
328
353
  background: transparent;
329
354
  border-inline-start: 4px solid transparent;
355
+ text-decoration: none;
330
356
  transition:
331
357
  background 0.15s ease,
332
358
  color 0.15s ease;
@@ -338,11 +364,9 @@ export default css`
338
364
  justify-content: space-between;
339
365
  gap: 8px;
340
366
  min-width: 0;
341
- box-sizing: border-box;
342
- text-decoration: none;
343
367
  }
344
368
 
345
- .nav-bar-path:hover,
369
+ a.nav-bar-info:hover,
346
370
  a.nav-bar-path:hover {
347
371
  text-decoration: none;
348
372
  }
@@ -47,7 +47,7 @@ export default css`
47
47
  gap: 4px;
48
48
  align-items: flex-start;
49
49
  overflow: hidden;
50
- display: none;
50
+ display: flex;
51
51
 
52
52
  /* in the description box's start padding, so descriptions line up whether or not a row shows its arrow */
53
53
  & .descr-expand-toggle {
@@ -239,7 +239,7 @@ export default css`
239
239
  .int3,
240
240
  .floa,
241
241
  .doub,
242
- .deci .blue {
242
+ .deci {
243
243
  color: var(--blue);
244
244
  }
245
245
  .null {
@@ -280,9 +280,17 @@ export default css`
280
280
  text-transform: uppercase;
281
281
  }
282
282
 
283
- @container (min-width: 500px) {
284
- .key-descr {
285
- display: flex;
283
+ /* Narrow schemas (phones): a description gets a line of its own under its field instead of a column (#1074) */
284
+ @container (width < 500px) {
285
+ .tr {
286
+ flex-wrap: wrap;
287
+ }
288
+ .tr > .key-descr {
289
+ flex-basis: 100%;
290
+
291
+ &:empty {
292
+ display: none;
293
+ }
286
294
  }
287
295
  }
288
296
  `;
@@ -214,7 +214,7 @@ export function isLightColor(color) {
214
214
  export function applyCustomTheme(element, themeVal) {
215
215
  if (!element || !element.style) return;
216
216
  if (
217
- !themeVal ||
217
+ typeof themeVal !== "string" ||
218
218
  THEME_PRESETS.includes(themeVal.trim().toLowerCase()) ||
219
219
  !isValidHexColor(themeVal)
220
220
  ) {
@@ -571,7 +571,7 @@ export default css`
571
571
  --syntax-inserted: #116329;
572
572
  --syntax-deleted: #cf222e;
573
573
 
574
- --code-bg: color-mix(in srgb, var(--background) 94%, var(--foreground));
574
+ --code-bg: color-mix(in srgb, var(--background) 96%, var(--foreground));
575
575
  }
576
576
  }
577
577
 
@@ -0,0 +1,89 @@
1
+ # `src/templates` — `<rapi-doc>` render templates
2
+
3
+ ## Overview
4
+
5
+ Lit `html` template functions, no classes. Each is called with `this` bound to its host, so
6
+ `this.*` is the host's reactive state and methods. `main-body-template.js` is the entry used by
7
+ `<rapi-doc>`, `<rapi-doc-mini>` and the static renderer (`@rapidoc/prerender`, `packages/rapidoc-prerender/src/`). Three files render inside
8
+ `<api-request>` (`src/components/`): `request-params-template.js`, `request-body-template.js`,
9
+ `api-response-template.js`.
10
+
11
+ Templates read `this.resolvedSpec` (built by `utils/spec-parser.js`) and compose the elements in
12
+ `src/components/`. They do not parse specs or define styles. The exception to "render only" is
13
+ `security-scheme-template.js`, which also owns API key and OAuth logic (token fetch, popup,
14
+ persistence).
15
+
16
+ ## Interface
17
+
18
+ Default exports are section templates; named exports are helpers used by other templates or hosts.
19
+
20
+ - `mainBodyTemplate(isMini, pathsExpanded)`: page shell; picks layout from `this.renderStyle`.
21
+ - Sections: `headerTemplate`, `navbarTemplate`, `overviewTemplate`, `downloadsTemplate`,
22
+ `serverTemplate`, `securitySchemeTemplate`, `endpointTemplate` (view mode),
23
+ `expandedEndpointTemplate` (read mode), `focusedEndpointTemplate`, `componentsTemplate`,
24
+ `callbackTemplate`, `codeSamplesTemplate`, `advancedSearchDialogTemplate`, `logoTemplate`.
25
+ - Used by hosts: `setApiServer` (`server-template.js`); `applyApiKey`, `onClearAllApiKeys`,
26
+ `recoverPersistedApiKeys` (`security-scheme-template.js`); `expandedEndpointBodyTemplate`
27
+ (static renderer); navbar helpers such as `expandCollapseNavBarTag` (`utils/bind-navbar.js`).
28
+ - Inside `<api-request>`: `inputParametersTemplate`, `requestBodyTemplate`, `apiCallTemplate`.
29
+ - Events (all `bubbles`, `composed`): `api-server-change` (`[server-template.js:setApiServer]`);
30
+ `before-authorize`, cancelable, for `authorizationCode` and `implicit` flows; and
31
+ `before-token-request`, cancelable, before each token fetch (listeners may edit
32
+ `detail.request`), both in `security-scheme-template.js`.
33
+
34
+ ## Invariants
35
+
36
+ - **Headings.** Titles are real `<h1>`–`<h6>` with `class="rapidoc-heading"` and
37
+ `part="heading heading-N"`, never styled divs; the outline is checked by
38
+ `tests/unit/semantic-markup.test.js`.
39
+ - **Exported parts.** A part added inside `<api-request>` / `<api-response>` must be added to the
40
+ `exportparts` lists in `endpoint-template.js`, `expanded-endpoint-template.js` and
41
+ `callback-template.js` (the lists differ today); the semantic-markup test catches omissions.
42
+ - **String flags.** Host flags are compared as exact strings (`=== "true"` or `=== "false"`),
43
+ never by truthiness; `[focused-endpoint-template.js:focusedEndpointTemplate]` also accepts
44
+ boolean `false` for `showInfo`.
45
+ - **Markdown.** Every `marked` result passes through `sanitizeHTML` before `unsafeHTML`.
46
+ - **Loading states.** `mainBodyTemplate` returns `""` without `resolvedSpec`, then renders
47
+ `#spec-not-found` on `specLoadError`, a loader while loading, and an error on `loadFailed`.
48
+ `navbarTemplate` returns a stub `<nav part="section-navbar">` in those cases.
49
+ - **Navigation ids.** An operation root has `id="${path.elementId}"`; its nav link is
50
+ `id="link-${elementId}"` with `data-content-id` on navigate items (expandable tags carry
51
+ `data-first-path-id` instead).
52
+ - **Schema hide flags.** In `endpoint-template.js` and `expanded-endpoint-template.js`, `"never"`
53
+ yields `"false"`; otherwise requests hide read-only and responses hide write-only fields,
54
+ inverted for webhooks. `callback-template.js` always uses the webhook direction.
55
+ - **Auth.** `[security-scheme-template.js:applyApiKey]` returns `false` for an unknown scheme or an
56
+ empty value, so an empty value never clears a key. OAuth uses a fresh `state` and `nonce` per
57
+ sign-in and PKCE (`S256`) when its checkbox is checked; a reply is accepted only when
58
+ `isExpectedOAuthReply` matches. Relative OAuth URLs resolve against the selected server's
59
+ `computedUrl` (or its origin).
60
+ - **Persistence.** With `persistAuth === "true"`, `localStorage["rapidoc"]` holds
61
+ `{ securitySchemeId, value }` per apiKey / bearer scheme; Basic credentials are never stored.
62
+ `removeApiKey` deletes one entry; `[security-scheme-template.js:onClearAllApiKeys]` empties it.
63
+ - **Server variables.** `[server-template.js:onApiServerVarChange]` reads every input in the
64
+ enclosing `<ul class="server-vars">` and recomputes `selectedServer.computedUrl`; the list
65
+ class is what it looks up, so keep it.
66
+
67
+ ## Side Effects
68
+
69
+ - Render writes host state: `mainBodyTemplate` calls `recoverPersistedApiKeys` on every render
70
+ (before the `specLoadError` check), which can call `requestUpdate()` during render;
71
+ `requestBodyTemplate` sets the selected body type and example when unset;
72
+ `focusedEndpointTemplate` sets `focusedElementId` and expands its nav item.
73
+ - Handlers mutate `resolvedSpec` (`expanded` flags in `endpoint-template.js`; scheme values in
74
+ `security-scheme-template.js`) and host tab state, then call `requestUpdate()`.
75
+ - `localStorage` key `rapidoc` (see Persistence); no `sessionStorage`.
76
+ - `security-scheme-template.js`: `fetch` to the token URL, `window.open` for sign-in
77
+ (`console.error` if blocked), a `BroadcastChannel` and `window` `message` listener while
78
+ waiting, `document` `keydown` listener for popovers.
79
+ - Clipboard, downloads and new tabs through `utils/common-utils.js`; navbar handlers toggle
80
+ classes and `aria-expanded` directly in the DOM.
81
+
82
+ ## Verification
83
+
84
+ - `npm run test:unit` (repo root; tests in `tests/unit/`): `semantic-markup.test.js` (outline,
85
+ `exportparts`), `auth-host-note.test.js`, `request-body-form.test.js`,
86
+ `multipart-part-types.test.js`, `example-dropdown.test.js`, `query-json-array.test.js`,
87
+ `param-content-example.test.js`, `server-description.test.js`, `unused-tags.test.js`,
88
+ `spec-parser-tag-groups.test.js`.
89
+ - After edits: `npm run build:rapidoc`, `npm run lint`, `npm run format-fix`.
@@ -179,19 +179,23 @@ export function apiCallTemplate() {
179
179
  <div class="try-actions">
180
180
  ${
181
181
  this.parameters.length > 0 || this.request_body
182
- ? html` <button
183
- class="btn btn-outline"
184
- part="btn btn-outline btn-fill"
185
- ?disabled="${this.loading}"
186
- @click="${this.onFillRequestData}"
187
- title="Fills with example data (if provided)"
188
- >
189
- FILL EXAMPLE
190
- </button>
182
+ ? html`${
183
+ this.hasExampleToFill
184
+ ? html`<button
185
+ class="btn btn-outline"
186
+ part="btn btn-outline btn-fill btn-fill-example"
187
+ ?disabled="${this.loading}"
188
+ @click="${this.onFillRequestData}"
189
+ title="Fills the request fields with their examples"
190
+ >
191
+ FILL EXAMPLE
192
+ </button>`
193
+ : ""
194
+ }
191
195
  <button
192
196
  class="btn btn-outline"
193
197
  part="btn btn-outline btn-clear"
194
- ?disabled="${this.loading}"
198
+ ?disabled="${this.loading || !this.hasValueToClear}"
195
199
  @click="${this.onClearRequestData}"
196
200
  >
197
201
  CLEAR
@@ -45,7 +45,7 @@ export default function callbackTemplate(callbacks) {
45
45
  schema-hide-write-only="${this.schemaHideWriteOnly === "never" ? "false" : "true"}"
46
46
  fetch-credentials="${this.fetchCredentials}"
47
47
  exportparts="section-request-title:section-request-title, heading:heading, heading-4:heading-4, heading-5:heading-5, heading-6:heading-6,
48
- 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,
48
+ 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,
49
49
  tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
50
50
  file-input:file-input, textbox:textbox, textbox-param:textbox-param, textarea:textarea, textarea-param:textarea-param,
51
51
  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"
@@ -4,12 +4,11 @@
4
4
  */
5
5
  import { html } from "lit";
6
6
  import { downloadResource, viewResource } from "~/utils/common-utils";
7
- import { parseMcpTargets, MCP_TARGET_LABELS } from "~/utils/mcp-generator";
7
+ import { parseMcpEnabled } from "~/utils/mcp-generator";
8
8
 
9
9
  export default function downloadsTemplate() {
10
- const mcpTargets = parseMcpTargets(this.mcp);
11
10
  const showSpecDownload = this.specUrl && this.allowSpecFileDownload === "true";
12
- const showMcpExport = mcpTargets.length > 0;
11
+ const showMcpExport = parseMcpEnabled(this.mcp);
13
12
 
14
13
  if (!showSpecDownload && !showMcpExport) {
15
14
  return "";
@@ -54,30 +53,16 @@ export default function downloadsTemplate() {
54
53
  }
55
54
  ${
56
55
  showMcpExport
57
- ? mcpTargets.length === 1
58
- ? html`<button
59
- class="btn btn-outline download-btn"
60
- part="btn btn-outline btn-mcp-export"
61
- @click="${() => {
62
- this.downloadMcpServer(mcpTargets[0]);
63
- }}"
64
- >
65
- Export MCP Server (${MCP_TARGET_LABELS[mcpTargets[0]] || mcpTargets[0]})
66
- </button>`
67
- : html`<select
68
- class="btn btn-outline download-select"
69
- part="btn btn-outline btn-mcp-export"
70
- @change="${(e) => {
71
- const target = e.target.value;
72
- if (target) {
73
- this.downloadMcpServer(target);
74
- e.target.value = "";
75
- }
76
- }}"
77
- >
78
- <option value="" disabled selected>Export MCP Server</option>
79
- ${mcpTargets.map((t) => html`<option value="${t}">Export ${MCP_TARGET_LABELS[t] || t}</option>`)}
80
- </select>`
56
+ ? html`<button
57
+ class="btn btn-outline download-btn"
58
+ part="btn btn-outline btn-mcp-export"
59
+ title="Download an MCP server project (manifest, runtime and stdio server) as a zip"
60
+ @click="${() => {
61
+ this.downloadMcpServer();
62
+ }}"
63
+ >
64
+ Export MCP Server
65
+ </button>`
81
66
  : ""
82
67
  }
83
68
  </section>
@@ -30,28 +30,19 @@ function toggleExpand(path) {
30
30
  this.requestUpdate();
31
31
  }
32
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");
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;
39
40
  });
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);
41
+ });
42
+ (this.resolvedSpec.tags || []).forEach((tag) => {
43
+ tag.expanded = expanded;
44
+ });
45
+ this.requestUpdate();
55
46
  }
56
47
 
57
48
  function endpointHeadTemplate(path, pathsExpanded = false) {
@@ -201,7 +192,7 @@ function endpointBodyTemplate(path) {
201
192
  schema-hide-write-only="${this.schemaHideWriteOnly === "never" ? "false" : path.isWebhook ? "true" : "false"}"
202
193
  fetch-credentials="${this.fetchCredentials}"
203
194
  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,
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,
205
196
  tab-panel:tab-panel, tab-btn:tab-btn, tab-btn-row:tab-btn-row, tab-content:tab-content,
206
197
  file-input:file-input, textbox:textbox, textbox-param:textbox-param, textarea:textarea, textarea-param:textarea-param,
207
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"
@@ -336,9 +327,9 @@ export default function endpointTemplate(isMini = false, pathsExpanded = false)
336
327
  isMini
337
328
  ? ""
338
329
  : html`<div class="section-expand-collapse-container">
339
- <span @click="${(e) => onExpandCollapseAll(e, "expand-all")}" style="color:var(--primary); cursor:pointer;"> Expand all </span>
330
+ <span @click="${() => expandCollapseAll.call(this, "expand-all")}" style="color:var(--primary); cursor:pointer;"> Expand all </span>
340
331
  &nbsp;|&nbsp;
341
- <span @click="${(e) => onExpandCollapseAll(e, "collapse-all")}" style="color:var(--primary); cursor:pointer;">
332
+ <span @click="${() => expandCollapseAll.call(this, "collapse-all")}" style="color:var(--primary); cursor:pointer;">
342
333
  Collapse all
343
334
  </span>
344
335
  &nbsp; sections