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.
- package/README.md +127 -25
- package/dist/rapidoc-flow-min.js +580 -0
- package/dist/rapidoc-flow-min.js.LICENSE.txt +171 -0
- package/dist/rapidoc-min.js +541 -1309
- package/dist/rapidoc-min.js.LICENSE.txt +381 -0
- package/package.json +21 -18
- package/src/README.md +150 -0
- package/src/components/README.md +91 -0
- package/src/components/api-request.ts +43 -0
- package/src/components/api-response.ts +9 -4
- package/src/components/schema-base-element.ts +18 -4
- package/src/components/schema-table.ts +58 -13
- package/src/components/schema-tree.ts +7 -0
- package/src/components/tag-input.ts +5 -9
- package/src/flow.js +3 -0
- package/src/rapi-flow.ts +1178 -0
- package/src/rapidoc-mini.ts +27 -6
- package/src/rapidoc.ts +108 -62
- package/src/styles/README.md +96 -0
- package/src/styles/css-bundle.js +2 -2
- package/src/styles/endpoint-styles.js +6 -1
- package/src/styles/flow-styles.js +248 -0
- package/src/styles/nav-styles.js +39 -15
- package/src/styles/schema-styles.js +13 -5
- package/src/styles/theme-tokens.js +2 -2
- package/src/templates/README.md +89 -0
- package/src/templates/api-response-template.js +14 -10
- package/src/templates/callback-template.js +1 -1
- package/src/templates/downloads-template.js +12 -27
- package/src/templates/endpoint-template.js +15 -24
- package/src/templates/expanded-endpoint-template.js +8 -4
- package/src/templates/focused-endpoint-template.js +4 -3
- package/src/templates/navbar-template.js +20 -11
- package/src/templates/request-body-template.js +29 -7
- package/src/templates/request-params-template.js +15 -4
- package/src/templates/security-scheme-template.js +11 -2
- package/src/templates/server-template.js +3 -2
- package/src/utils/README.md +146 -0
- package/src/utils/arazzo/README.md +119 -0
- package/src/utils/arazzo/components.js +15 -0
- package/src/utils/arazzo/graph.js +269 -0
- package/src/utils/arazzo/index.js +52 -0
- package/src/utils/arazzo/operations.js +106 -0
- package/src/utils/arazzo/parse.js +196 -0
- package/src/utils/arazzo/refs.js +40 -0
- package/src/utils/arazzo/svg.js +707 -0
- package/src/utils/curl-utils.js +5 -2
- package/src/utils/highlighter.js +3 -0
- package/src/utils/mcp/README.md +155 -0
- package/src/utils/mcp/common.js +45 -346
- package/src/utils/mcp/manifest.js +382 -0
- package/src/utils/mcp/project/server.ts +53 -0
- package/src/utils/mcp/project.js +88 -0
- package/src/utils/mcp/runtime.js +289 -0
- package/src/utils/mcp/schema.js +98 -0
- package/src/utils/mcp/workflow-runtime.js +374 -0
- package/src/utils/mcp/workflows.js +240 -0
- package/src/utils/mcp/zip.js +102 -0
- package/src/utils/mcp-generator.js +29 -125
- package/src/utils/mock-interceptor.js +134 -85
- package/src/utils/request-utils.js +61 -0
- package/src/utils/schema-utils.js +33 -6
- package/src/utils/slugger.js +5 -7
- package/src/utils/spec-parser.js +190 -164
- package/src/utils/url-utils.js +36 -1
- package/dist/rapidoc-static-min.js +0 -13542
- package/src/static/index.d.ts +0 -149
- package/src/static/index.js +0 -62
- package/src/static/navigation.js +0 -497
- package/src/static/render.js +0 -490
- package/src/static/serializer.js +0 -216
- package/src/utils/mcp/generators/csharp.js +0 -242
- package/src/utils/mcp/generators/go.js +0 -298
- package/src/utils/mcp/generators/java.js +0 -330
- package/src/utils/mcp/generators/python.js +0 -248
- package/src/utils/mcp/generators/rust.js +0 -281
- 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
|
+
`;
|
package/src/styles/nav-styles.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
188
|
+
transition:
|
|
189
|
+
height 0.25s ease,
|
|
190
|
+
visibility 0s;
|
|
181
191
|
}
|
|
182
|
-
.collapsed .nav-bar-paths-under-tag,
|
|
183
|
-
.nav-bar-tag-
|
|
184
|
-
|
|
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
|
-
|
|
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-
|
|
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:
|
|
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
|
|
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
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
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)
|
|
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
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
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 {
|
|
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 =
|
|
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
|
-
?
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
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="${(
|
|
330
|
+
<span @click="${() => expandCollapseAll.call(this, "expand-all")}" style="color:var(--primary); cursor:pointer;"> Expand all </span>
|
|
340
331
|
|
|
|
341
|
-
<span @click="${(
|
|
332
|
+
<span @click="${() => expandCollapseAll.call(this, "collapse-all")}" style="color:var(--primary); cursor:pointer;">
|
|
342
333
|
Collapse all
|
|
343
334
|
</span>
|
|
344
335
|
sections
|