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.
- package/README.md +171 -54
- package/dist/rapidoc-flow-min.js +580 -0
- package/dist/rapidoc-flow-min.js.LICENSE.txt +171 -0
- package/dist/rapidoc-min.js +645 -202
- package/dist/rapidoc-min.js.LICENSE.txt +381 -0
- package/package.json +57 -42
- package/src/README.md +150 -0
- package/src/components/README.md +91 -0
- package/src/components/api-request.ts +912 -0
- package/src/components/api-response.ts +514 -0
- package/src/components/json-tree.ts +171 -0
- package/src/components/schema-base-element.ts +329 -0
- package/src/components/schema-table.ts +475 -0
- package/src/components/schema-tree.ts +393 -0
- package/src/components/tag-input.ts +180 -0
- package/src/flow.js +3 -0
- package/src/index.js +6 -0
- package/src/oauth-receiver.ts +29 -0
- package/src/rapi-flow.ts +1178 -0
- package/src/rapidoc-mini.ts +603 -0
- package/src/rapidoc.ts +1854 -0
- package/src/styles/README.md +96 -0
- package/src/styles/auth-styles.js +318 -0
- package/src/styles/border-styles.js +24 -0
- package/src/styles/css-bundle.js +129 -0
- package/src/styles/custom-styles.js +8 -0
- package/src/styles/dialog-box-styles.js +102 -0
- package/src/styles/endpoint-styles.js +564 -0
- package/src/styles/flex-styles.js +16 -0
- package/src/styles/flow-styles.js +248 -0
- package/src/styles/font-styles.js +432 -0
- package/src/styles/info-styles.js +36 -0
- package/src/styles/input-styles.js +555 -0
- package/src/styles/layout-styles.js +396 -0
- package/src/styles/microlighter-styles.js +99 -0
- package/src/styles/nav-styles.js +633 -0
- package/src/styles/param-list-styles.js +261 -0
- package/src/styles/schema-styles.js +296 -0
- package/src/styles/tab-styles.js +106 -0
- package/src/styles/theme-tokens.js +582 -0
- package/src/templates/README.md +89 -0
- package/src/templates/advanced-search-dialog-template.js +94 -0
- package/src/templates/api-response-template.js +223 -0
- package/src/templates/callback-template.js +86 -0
- package/src/templates/code-samples-template.js +52 -0
- package/src/templates/components-template.js +86 -0
- package/src/templates/downloads-template.js +70 -0
- package/src/templates/endpoint-template.js +377 -0
- package/src/templates/expanded-endpoint-template.js +270 -0
- package/src/templates/focused-endpoint-template.js +146 -0
- package/src/templates/header-template.js +92 -0
- package/src/templates/logo-template.js +21 -0
- package/src/templates/main-body-template.js +102 -0
- package/src/templates/navbar-template.js +498 -0
- package/src/templates/overview-template.js +104 -0
- package/src/templates/request-body-template.js +673 -0
- package/src/templates/request-params-template.js +485 -0
- package/src/templates/security-scheme-template.js +1272 -0
- package/src/templates/server-template.js +153 -0
- 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/auto-color-scheme.js +99 -0
- package/src/utils/bind-navbar.js +175 -0
- package/src/utils/color-utils.js +59 -0
- package/src/utils/common-utils.js +191 -0
- package/src/utils/curl-utils.js +126 -0
- package/src/utils/highlighter.js +419 -0
- package/src/utils/markdown-utils.js +110 -0
- package/src/utils/mcp/README.md +155 -0
- package/src/utils/mcp/common.js +166 -0
- 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 +47 -0
- package/src/utils/mock-interceptor.js +557 -0
- package/src/utils/oauth-utils.js +87 -0
- package/src/utils/request-utils.js +264 -0
- package/src/utils/response-utils.js +203 -0
- package/src/utils/sanitize.js +57 -0
- package/src/utils/schema-utils.js +1954 -0
- package/src/utils/slugger.js +187 -0
- package/src/utils/spec-parser.js +941 -0
- package/src/utils/url-utils.js +246 -0
- package/src/utils/xml-utils.js +61 -0
|
@@ -0,0 +1,514 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { customElement, property } from "lit/decorators.js";
|
|
3
|
+
import { unsafeHTML } from "lit/directives/unsafe-html.js";
|
|
4
|
+
import { sanitizeHTML } from "../utils/sanitize.js";
|
|
5
|
+
import { marked } from "marked";
|
|
6
|
+
import { prepareResponseDefinitions } from "../utils/response-utils.js";
|
|
7
|
+
import { exampleLabel } from "~/utils/schema-utils";
|
|
8
|
+
import FontStyles from "~/styles/font-styles";
|
|
9
|
+
import FlexStyles from "~/styles/flex-styles";
|
|
10
|
+
import ParamListStyles from "~/styles/param-list-styles";
|
|
11
|
+
import InputStyles from "~/styles/input-styles";
|
|
12
|
+
import TabStyles from "~/styles/tab-styles";
|
|
13
|
+
import BorderStyles from "~/styles/border-styles";
|
|
14
|
+
import CustomStyles from "~/styles/custom-styles";
|
|
15
|
+
import "~/components/json-tree";
|
|
16
|
+
import "~/components/schema-tree";
|
|
17
|
+
import "~/components/schema-table";
|
|
18
|
+
|
|
19
|
+
@customElement("api-response")
|
|
20
|
+
export default class ApiResponse extends LitElement {
|
|
21
|
+
@property({ type: Object }) config: any;
|
|
22
|
+
@property({ type: String }) callback = "";
|
|
23
|
+
@property({ type: String }) webhook = "";
|
|
24
|
+
@property({ type: Object }) responses: any;
|
|
25
|
+
@property({ type: Object }) parser: any;
|
|
26
|
+
@property({ type: String, attribute: "schema-style" }) schemaStyle = "";
|
|
27
|
+
@property({ type: String, attribute: "render-style" }) renderStyle = "";
|
|
28
|
+
@property({ type: String, attribute: "selected-status" }) selectedStatus = "";
|
|
29
|
+
@property({ type: String, attribute: "selected-mime-type" }) selectedMimeType = "";
|
|
30
|
+
@property({ type: String, attribute: "active-schema-tab" }) activeSchemaTab = "schema";
|
|
31
|
+
@property({ type: Number, attribute: "schema-expand-level" }) schemaExpandLevel = 99999;
|
|
32
|
+
@property({ type: String, attribute: "schema-description-expanded" }) schemaDescriptionExpanded =
|
|
33
|
+
"false";
|
|
34
|
+
@property({ type: String, attribute: "allow-schema-description-expand-toggle" })
|
|
35
|
+
allowSchemaDescriptionExpandToggle = "false";
|
|
36
|
+
@property({ type: String, attribute: "schema-hide-read-only" }) schemaHideReadOnly = "false";
|
|
37
|
+
@property({ type: String, attribute: "schema-hide-write-only" }) schemaHideWriteOnly = "true";
|
|
38
|
+
|
|
39
|
+
defaultStatus = "";
|
|
40
|
+
defaultMimeType = "";
|
|
41
|
+
headersForEachRespStatus: any = {};
|
|
42
|
+
mimeResponsesForEachStatus: any = {};
|
|
43
|
+
|
|
44
|
+
constructor() {
|
|
45
|
+
super();
|
|
46
|
+
this.selectedStatus = "";
|
|
47
|
+
this.defaultStatus = "";
|
|
48
|
+
this.defaultMimeType = "";
|
|
49
|
+
this.headersForEachRespStatus = {};
|
|
50
|
+
this.mimeResponsesForEachStatus = {};
|
|
51
|
+
this.activeSchemaTab = "schema";
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
static get styles() {
|
|
55
|
+
return [
|
|
56
|
+
FontStyles,
|
|
57
|
+
FlexStyles,
|
|
58
|
+
TabStyles,
|
|
59
|
+
ParamListStyles,
|
|
60
|
+
InputStyles,
|
|
61
|
+
BorderStyles,
|
|
62
|
+
css`
|
|
63
|
+
.resp-headers-list {
|
|
64
|
+
margin-bottom: 16px;
|
|
65
|
+
}
|
|
66
|
+
:where(button, input[type='checkbox'], [tabindex='0']):focus-visible {
|
|
67
|
+
box-shadow: var(--focus-shadow);
|
|
68
|
+
}
|
|
69
|
+
:where(input[type='text'], input[type='password'], select, textarea):focus-visible {
|
|
70
|
+
border-color: var(--primary);
|
|
71
|
+
}
|
|
72
|
+
.resp-head {
|
|
73
|
+
vertical-align: middle;
|
|
74
|
+
padding: 16px 0 8px;
|
|
75
|
+
|
|
76
|
+
&.divider {
|
|
77
|
+
border-top: 1px solid var(--border);
|
|
78
|
+
margin-top: 10px;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
.resp-status {
|
|
82
|
+
font-weight: bold;
|
|
83
|
+
font-size: calc(var(--font-size-small) + 1px);
|
|
84
|
+
}
|
|
85
|
+
.resp-descr {
|
|
86
|
+
font-size: var(--font-size-description);
|
|
87
|
+
color: var(--muted-foreground);
|
|
88
|
+
text-align: left;
|
|
89
|
+
}
|
|
90
|
+
.top-gap {
|
|
91
|
+
margin-top: 16px;
|
|
92
|
+
}
|
|
93
|
+
.example-panel {
|
|
94
|
+
font-size: var(--font-size-small);
|
|
95
|
+
margin: 0;
|
|
96
|
+
}
|
|
97
|
+
/* Response codes: a segmented control (one choice), the selected code tinted with the primary color */
|
|
98
|
+
.status-group {
|
|
99
|
+
display: inline-flex;
|
|
100
|
+
flex-wrap: wrap;
|
|
101
|
+
margin-top: 8px;
|
|
102
|
+
}
|
|
103
|
+
.status-btn {
|
|
104
|
+
margin: 0 0 0 -1px;
|
|
105
|
+
border-color: var(--input);
|
|
106
|
+
border-radius: 0;
|
|
107
|
+
background: color-mix(in srgb, var(--foreground) 5%, transparent);
|
|
108
|
+
color: var(--muted-foreground);
|
|
109
|
+
|
|
110
|
+
&:first-child {
|
|
111
|
+
margin-left: 0;
|
|
112
|
+
border-start-start-radius: var(--radius);
|
|
113
|
+
border-end-start-radius: var(--radius);
|
|
114
|
+
}
|
|
115
|
+
&:last-child {
|
|
116
|
+
border-start-end-radius: var(--radius);
|
|
117
|
+
border-end-end-radius: var(--radius);
|
|
118
|
+
}
|
|
119
|
+
&:hover {
|
|
120
|
+
background: var(--muted);
|
|
121
|
+
color: var(--foreground);
|
|
122
|
+
}
|
|
123
|
+
&[aria-pressed='true'] {
|
|
124
|
+
position: relative;
|
|
125
|
+
z-index: 1;
|
|
126
|
+
border-color: var(--primary);
|
|
127
|
+
background: color-mix(in srgb, var(--primary) 14%, transparent);
|
|
128
|
+
color: var(--primary);
|
|
129
|
+
}
|
|
130
|
+
&:focus-visible {
|
|
131
|
+
z-index: 2;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
`,
|
|
135
|
+
CustomStyles,
|
|
136
|
+
];
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
willUpdate(changedProperties) {
|
|
140
|
+
super.willUpdate?.(changedProperties);
|
|
141
|
+
// Sync configuration options passed down from parent <rapi-doc>
|
|
142
|
+
if (this.config && changedProperties.has("config")) {
|
|
143
|
+
if (this.config.renderStyle) this.renderStyle = this.config.renderStyle;
|
|
144
|
+
if (this.config.schemaStyle) this.schemaStyle = this.config.schemaStyle;
|
|
145
|
+
if (this.config.schemaExpandLevel !== undefined)
|
|
146
|
+
this.schemaExpandLevel = this.config.schemaExpandLevel;
|
|
147
|
+
if (this.config.schemaDescriptionExpanded !== undefined)
|
|
148
|
+
this.schemaDescriptionExpanded = this.config.schemaDescriptionExpanded;
|
|
149
|
+
if (this.config.allowSchemaDescriptionExpandToggle !== undefined)
|
|
150
|
+
this.allowSchemaDescriptionExpandToggle = this.config.allowSchemaDescriptionExpandToggle;
|
|
151
|
+
// In responses, readOnly fields are shown by default ('false') while writeOnly fields are hidden ('true').
|
|
152
|
+
// For webhooks, this behavior is inverted unless configured to 'never'.
|
|
153
|
+
if (this.config.schemaHideReadOnly !== undefined)
|
|
154
|
+
this.schemaHideReadOnly =
|
|
155
|
+
this.config.schemaHideReadOnly === "never"
|
|
156
|
+
? "false"
|
|
157
|
+
: this.webhook === "true"
|
|
158
|
+
? "true"
|
|
159
|
+
: "false";
|
|
160
|
+
if (this.config.schemaHideWriteOnly !== undefined)
|
|
161
|
+
this.schemaHideWriteOnly =
|
|
162
|
+
this.config.schemaHideWriteOnly === "never"
|
|
163
|
+
? "false"
|
|
164
|
+
: this.webhook === "true"
|
|
165
|
+
? "false"
|
|
166
|
+
: "true";
|
|
167
|
+
if (this.config.defaultSchemaTab) this.activeSchemaTab = this.config.defaultSchemaTab;
|
|
168
|
+
}
|
|
169
|
+
// Parse response definitions, headers, examples, and AST schemas when responses change
|
|
170
|
+
if (
|
|
171
|
+
changedProperties.has("responses") ||
|
|
172
|
+
changedProperties.has("callback") ||
|
|
173
|
+
changedProperties.has("webhook")
|
|
174
|
+
) {
|
|
175
|
+
if (!this.responses || typeof this.responses !== "object") {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
const defs = prepareResponseDefinitions(this.responses, {
|
|
179
|
+
callback: this.callback,
|
|
180
|
+
webhook: this.webhook,
|
|
181
|
+
});
|
|
182
|
+
this.headersForEachRespStatus = defs.headersForEachRespStatus;
|
|
183
|
+
this.mimeResponsesForEachStatus = defs.mimeResponsesForEachStatus;
|
|
184
|
+
this.defaultStatus = defs.defaultStatus;
|
|
185
|
+
this.defaultMimeType = defs.defaultMimeType;
|
|
186
|
+
// Default to primary status code (e.g. '200') if none is currently selected or if the old status doesn't exist on this response
|
|
187
|
+
if (!this.selectedStatus || !this.responses?.[this.selectedStatus]) {
|
|
188
|
+
this.selectedStatus = defs.defaultStatus;
|
|
189
|
+
}
|
|
190
|
+
if (!this.selectedMimeType) {
|
|
191
|
+
this.selectedMimeType = defs.defaultMimeType;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
render() {
|
|
197
|
+
return html`<div class="col regular-font response-panel ${this.renderStyle}-mode">
|
|
198
|
+
${
|
|
199
|
+
this.callback === "true"
|
|
200
|
+
? html`<h6 class="rapidoc-heading label-heading tiny-title" part="section-response-title heading heading-6">
|
|
201
|
+
Callback response
|
|
202
|
+
</h6>`
|
|
203
|
+
: html`<h4 class="rapidoc-heading label-heading req-res-title" part="section-response-title heading heading-4">Response</h4>`
|
|
204
|
+
}
|
|
205
|
+
<div>${this.responseTemplate()}</div>
|
|
206
|
+
</div> `;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Called by rapi-doc after navigating in focused mode.
|
|
210
|
+
// In focused mode, the single <api-response> element instance is reused across operations.
|
|
211
|
+
// We reset selections back to the default status code and MIME type of the active endpoint,
|
|
212
|
+
// preventing user selections from a prior endpoint (e.g., status 400) from carrying over or hiding panels.
|
|
213
|
+
resetSelection() {
|
|
214
|
+
this.selectedStatus =
|
|
215
|
+
this.defaultStatus ||
|
|
216
|
+
(this.responses ? Object.keys(this.responses).find((k) => k !== "$$ref") || "" : "");
|
|
217
|
+
if (this.selectedStatus && this.mimeResponsesForEachStatus?.[this.selectedStatus]) {
|
|
218
|
+
this.selectedMimeType =
|
|
219
|
+
Object.keys(this.mimeResponsesForEachStatus[this.selectedStatus])[0] || "";
|
|
220
|
+
} else {
|
|
221
|
+
this.selectedMimeType = this.defaultMimeType || "";
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
responseTemplate() {
|
|
226
|
+
if (!this.responses) {
|
|
227
|
+
return "";
|
|
228
|
+
}
|
|
229
|
+
// Fallback guard: Ensure selectedStatus and selectedMimeType always point to valid options
|
|
230
|
+
// for this endpoint, even if resetSelection was called or responses have not re-rendered yet.
|
|
231
|
+
if (!this.selectedStatus || !this.responses[this.selectedStatus]) {
|
|
232
|
+
this.selectedStatus =
|
|
233
|
+
this.defaultStatus ||
|
|
234
|
+
Object.keys(this.responses).find((k) => k !== "$$ref") ||
|
|
235
|
+
Object.keys(this.responses)[0] ||
|
|
236
|
+
"";
|
|
237
|
+
}
|
|
238
|
+
if (
|
|
239
|
+
!this.selectedMimeType &&
|
|
240
|
+
this.selectedStatus &&
|
|
241
|
+
this.mimeResponsesForEachStatus?.[this.selectedStatus]
|
|
242
|
+
) {
|
|
243
|
+
this.selectedMimeType =
|
|
244
|
+
Object.keys(this.mimeResponsesForEachStatus[this.selectedStatus])[0] ||
|
|
245
|
+
this.defaultMimeType ||
|
|
246
|
+
"";
|
|
247
|
+
}
|
|
248
|
+
return html`
|
|
249
|
+
${
|
|
250
|
+
Object.keys(this.responses).length > 1
|
|
251
|
+
? html`<div class="status-group" role="group" aria-label="Response status">
|
|
252
|
+
${Object.keys(this.responses).map(
|
|
253
|
+
(respStatus) =>
|
|
254
|
+
html` ${
|
|
255
|
+
respStatus === "$$ref" // Ignore '$$ref' if present from legacy reference parsing
|
|
256
|
+
? ""
|
|
257
|
+
: html`<button
|
|
258
|
+
@click="${() => {
|
|
259
|
+
this.selectedStatus = respStatus;
|
|
260
|
+
if (
|
|
261
|
+
this.responses[respStatus].content &&
|
|
262
|
+
Object.keys(this.responses[respStatus].content)[0]
|
|
263
|
+
) {
|
|
264
|
+
this.selectedMimeType = Object.keys(
|
|
265
|
+
this.responses[respStatus].content,
|
|
266
|
+
)[0];
|
|
267
|
+
} else {
|
|
268
|
+
this.selectedMimeType = undefined;
|
|
269
|
+
}
|
|
270
|
+
}}"
|
|
271
|
+
class="btn btn-sm status-btn"
|
|
272
|
+
aria-pressed="${this.selectedStatus === respStatus ? "true" : "false"}"
|
|
273
|
+
part="btn ${
|
|
274
|
+
this.selectedStatus === respStatus
|
|
275
|
+
? "btn-response-status btn-selected-response-status"
|
|
276
|
+
: " btn-response-status"
|
|
277
|
+
}"
|
|
278
|
+
>
|
|
279
|
+
${respStatus}
|
|
280
|
+
</button>`
|
|
281
|
+
}`,
|
|
282
|
+
)}
|
|
283
|
+
</div>`
|
|
284
|
+
: html`<span>${Object.keys(this.responses)[0]}</span>`
|
|
285
|
+
}
|
|
286
|
+
${Object.keys(this.responses).map(
|
|
287
|
+
(status) =>
|
|
288
|
+
html`<div style="display: ${status === this.selectedStatus ? "block" : "none"}">
|
|
289
|
+
<div class="top-gap">
|
|
290
|
+
<span class="resp-descr m-markdown">${unsafeHTML(sanitizeHTML(marked(this.responses[status]?.description || "")))}</span>
|
|
291
|
+
${
|
|
292
|
+
this.headersForEachRespStatus[status] &&
|
|
293
|
+
this.headersForEachRespStatus[status]?.length > 0
|
|
294
|
+
? html`${this.responseHeaderListTemplate(this.headersForEachRespStatus[status])}`
|
|
295
|
+
: ""
|
|
296
|
+
}
|
|
297
|
+
</div>
|
|
298
|
+
${
|
|
299
|
+
!this.mimeResponsesForEachStatus[status] ||
|
|
300
|
+
Object.keys(this.mimeResponsesForEachStatus[status]).length === 0
|
|
301
|
+
? ""
|
|
302
|
+
: html`<div part="tab-panel" class="tab-panel col">
|
|
303
|
+
<div
|
|
304
|
+
part="tab-btn-row"
|
|
305
|
+
class="tab-buttons row"
|
|
306
|
+
@click="${(e) => {
|
|
307
|
+
if (e.target.tagName.toLowerCase() === "button") {
|
|
308
|
+
this.activeSchemaTab = e.target.dataset.tab;
|
|
309
|
+
}
|
|
310
|
+
}}"
|
|
311
|
+
>
|
|
312
|
+
<button part="tab-btn" class="tab-btn ${this.activeSchemaTab === "example" ? "active" : ""}" data-tab="example">
|
|
313
|
+
EXAMPLE
|
|
314
|
+
</button>
|
|
315
|
+
<button part="tab-btn" class="tab-btn ${this.activeSchemaTab !== "example" ? "active" : ""}" data-tab="schema">
|
|
316
|
+
SCHEMA
|
|
317
|
+
</button>
|
|
318
|
+
${
|
|
319
|
+
Object.keys(this.mimeResponsesForEachStatus[status]).length === 1
|
|
320
|
+
? html`<span class="tab-bar-end">${Object.keys(this.mimeResponsesForEachStatus[status])[0]}</span>`
|
|
321
|
+
: html`${this.mimeTypeDropdownTemplate(Object.keys(this.mimeResponsesForEachStatus[status]))}`
|
|
322
|
+
}
|
|
323
|
+
</div>
|
|
324
|
+
${
|
|
325
|
+
this.activeSchemaTab === "example"
|
|
326
|
+
? html`<div part="tab-content" class="tab-content col">
|
|
327
|
+
${this.mimeExampleTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}
|
|
328
|
+
</div>`
|
|
329
|
+
: html`<div part="tab-content" class="tab-content col">
|
|
330
|
+
${this.mimeSchemaTemplate(this.mimeResponsesForEachStatus[status][this.selectedMimeType])}
|
|
331
|
+
</div>`
|
|
332
|
+
}
|
|
333
|
+
</div> `
|
|
334
|
+
}
|
|
335
|
+
</div>`,
|
|
336
|
+
)}
|
|
337
|
+
`;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
responseHeaderListTemplate(respHeaders) {
|
|
341
|
+
return html`<h5 class="rapidoc-heading label-heading resp-headers" part="heading heading-5">Response headers</h5>
|
|
342
|
+
<div class="param-list-container resp-headers-list">
|
|
343
|
+
<ul class="param-list" part="param-list" role="list">
|
|
344
|
+
${respHeaders.map(
|
|
345
|
+
(v) =>
|
|
346
|
+
html`<li class="param" part="param">
|
|
347
|
+
<div class="param-label" part="param-label">
|
|
348
|
+
<div class="param-name" part="param-name">${v.name || ""}</div>
|
|
349
|
+
${v.schema?.type ? html`<div class="param-type" part="param-type">${v.schema.type}</div>` : ""}
|
|
350
|
+
</div>
|
|
351
|
+
${
|
|
352
|
+
v.schema?.example
|
|
353
|
+
? html`<dl class="param-constraint" part="param-constraint">
|
|
354
|
+
<dt class="param-constraint-label" part="param-constraint-label">Example:</dt>
|
|
355
|
+
<dd>${v.schema.example}</dd>
|
|
356
|
+
</dl>`
|
|
357
|
+
: ""
|
|
358
|
+
}
|
|
359
|
+
<div class="param-details" part="param-details">
|
|
360
|
+
${v.description ? html`<div class="m-markdown-small">${unsafeHTML(sanitizeHTML(marked(v.description)))}</div>` : ""}
|
|
361
|
+
</div>
|
|
362
|
+
</li>`,
|
|
363
|
+
)}
|
|
364
|
+
</ul>
|
|
365
|
+
</div>`;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
mimeTypeDropdownTemplate(mimeTypes) {
|
|
369
|
+
return html`<select
|
|
370
|
+
aria-label="mime types"
|
|
371
|
+
class="select-sm tab-bar-end"
|
|
372
|
+
@change="${(e) => {
|
|
373
|
+
this.selectedMimeType = e.target.value;
|
|
374
|
+
}}"
|
|
375
|
+
>
|
|
376
|
+
${mimeTypes.map(
|
|
377
|
+
(mimeType) =>
|
|
378
|
+
html`<option value="${mimeType}" ?selected="${mimeType === this.selectedMimeType}">${mimeType}</option>`,
|
|
379
|
+
)}
|
|
380
|
+
</select>`;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
onSelectExample(e) {
|
|
384
|
+
const exampleContainerEl = e.target.closest(".example-panel");
|
|
385
|
+
const exampleEls = [...exampleContainerEl.querySelectorAll(".example")];
|
|
386
|
+
|
|
387
|
+
exampleEls.forEach((v) => {
|
|
388
|
+
v.style.display = v.dataset.example === e.target.value ? "block" : "none";
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
mimeExampleTemplate(mimeRespDetails) {
|
|
393
|
+
if (!mimeRespDetails || !mimeRespDetails.examples || mimeRespDetails.examples.length === 0) {
|
|
394
|
+
return html` <pre style="color:var(--destructive)" class="example-panel"> No example provided </pre> `;
|
|
395
|
+
}
|
|
396
|
+
return html`
|
|
397
|
+
${
|
|
398
|
+
mimeRespDetails.examples.length === 1
|
|
399
|
+
? html` ${
|
|
400
|
+
mimeRespDetails.examples[0].exampleFormat === "json"
|
|
401
|
+
? html` ${
|
|
402
|
+
mimeRespDetails.examples[0].exampleSummary &&
|
|
403
|
+
mimeRespDetails.examples[0].exampleSummary.length > 80
|
|
404
|
+
? html`<div style="padding: 4px 0">${mimeRespDetails.examples[0].exampleSummary}</div>`
|
|
405
|
+
: ""
|
|
406
|
+
}
|
|
407
|
+
${
|
|
408
|
+
mimeRespDetails.examples[0].exampleDescription
|
|
409
|
+
? html`<div class="m-markdown-small" style="padding: 4px 0">
|
|
410
|
+
${unsafeHTML(sanitizeHTML(marked(mimeRespDetails.examples[0].exampleDescription || "")))}
|
|
411
|
+
</div>`
|
|
412
|
+
: ""
|
|
413
|
+
}
|
|
414
|
+
<json-tree
|
|
415
|
+
render-style="${this.renderStyle}"
|
|
416
|
+
.data="${mimeRespDetails.examples[0].exampleValue}"
|
|
417
|
+
class="example-panel"
|
|
418
|
+
exportparts="btn:btn, btn-outline:btn-outline, btn-copy:btn-copy"
|
|
419
|
+
></json-tree>`
|
|
420
|
+
: html`
|
|
421
|
+
${
|
|
422
|
+
mimeRespDetails.examples[0].exampleSummary &&
|
|
423
|
+
mimeRespDetails.examples[0].exampleSummary.length > 80
|
|
424
|
+
? html`<div style="padding: 4px 0">${mimeRespDetails.examples[0].exampleSummary}</div>`
|
|
425
|
+
: ""
|
|
426
|
+
}
|
|
427
|
+
${
|
|
428
|
+
mimeRespDetails.examples[0].exampleDescription
|
|
429
|
+
? html`<div class="m-markdown-small" style="padding: 4px 0">
|
|
430
|
+
${unsafeHTML(sanitizeHTML(marked(mimeRespDetails.examples[0].exampleDescription || "")))}
|
|
431
|
+
</div>`
|
|
432
|
+
: ""
|
|
433
|
+
}
|
|
434
|
+
<pre class="example-panel">${mimeRespDetails.examples[0].exampleValue}</pre>
|
|
435
|
+
`
|
|
436
|
+
}`
|
|
437
|
+
: html`
|
|
438
|
+
<div class="example-panel">
|
|
439
|
+
<select
|
|
440
|
+
aria-label="response examples"
|
|
441
|
+
class="select-sm example-select"
|
|
442
|
+
title="${exampleLabel(mimeRespDetails.examples.find((v) => v.exampleId === mimeRespDetails.selectedExample))}"
|
|
443
|
+
@change="${(e) => this.onSelectExample(e)}"
|
|
444
|
+
>
|
|
445
|
+
${mimeRespDetails.examples.map(
|
|
446
|
+
(v) =>
|
|
447
|
+
html`<option value="${v.exampleId}" title="${exampleLabel(v)}" ?selected=${v.exampleId === mimeRespDetails.selectedExample}>
|
|
448
|
+
${exampleLabel(v)}
|
|
449
|
+
</option>`,
|
|
450
|
+
)}
|
|
451
|
+
</select>
|
|
452
|
+
${mimeRespDetails.examples.map(
|
|
453
|
+
(v) => html`
|
|
454
|
+
<div
|
|
455
|
+
class="example"
|
|
456
|
+
data-example="${v.exampleId}"
|
|
457
|
+
style="display: ${v.exampleId === mimeRespDetails.selectedExample ? "block" : "none"}"
|
|
458
|
+
>
|
|
459
|
+
${
|
|
460
|
+
v.exampleDescription
|
|
461
|
+
? html`<div class="m-markdown-small" style="padding: 4px 0">
|
|
462
|
+
${unsafeHTML(sanitizeHTML(marked(v.exampleDescription || "")))}
|
|
463
|
+
</div>`
|
|
464
|
+
: ""
|
|
465
|
+
}
|
|
466
|
+
${
|
|
467
|
+
v.exampleFormat === "json"
|
|
468
|
+
? html`<json-tree
|
|
469
|
+
render-style="${this.renderStyle}"
|
|
470
|
+
.data="${v.exampleValue}"
|
|
471
|
+
exportparts="btn:btn, btn-outline:btn-outline, btn-copy:btn-copy"
|
|
472
|
+
></json-tree>`
|
|
473
|
+
: html`<pre>${v.exampleValue}</pre>`
|
|
474
|
+
}
|
|
475
|
+
</div>
|
|
476
|
+
`,
|
|
477
|
+
)}
|
|
478
|
+
</div>
|
|
479
|
+
`
|
|
480
|
+
}
|
|
481
|
+
`;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
mimeSchemaTemplate(mimeRespDetails) {
|
|
485
|
+
if (!mimeRespDetails) {
|
|
486
|
+
return html` <pre style="color:var(--destructive)" class="example-panel"> Schema not found</pre> `;
|
|
487
|
+
}
|
|
488
|
+
return html` ${
|
|
489
|
+
this.schemaStyle === "table"
|
|
490
|
+
? html`
|
|
491
|
+
<schema-table
|
|
492
|
+
.data="${mimeRespDetails.schemaTree}"
|
|
493
|
+
schema-expand-level="${this.schemaExpandLevel}"
|
|
494
|
+
schema-description-expanded="${this.schemaDescriptionExpanded}"
|
|
495
|
+
allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
|
|
496
|
+
schema-hide-read-only="${this.schemaHideReadOnly}"
|
|
497
|
+
schema-hide-write-only="${this.schemaHideWriteOnly}"
|
|
498
|
+
exportparts="schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
|
|
499
|
+
>
|
|
500
|
+
</schema-table>
|
|
501
|
+
`
|
|
502
|
+
: html`<schema-tree
|
|
503
|
+
.data="${mimeRespDetails.schemaTree}"
|
|
504
|
+
schema-expand-level="${this.schemaExpandLevel}"
|
|
505
|
+
schema-description-expanded="${this.schemaDescriptionExpanded}"
|
|
506
|
+
allow-schema-description-expand-toggle="${this.allowSchemaDescriptionExpandToggle}"
|
|
507
|
+
schema-hide-read-only="${this.schemaHideReadOnly}"
|
|
508
|
+
schema-hide-write-only="${this.schemaHideWriteOnly}"
|
|
509
|
+
exportparts="schema-description:schema-description, schema-multiline-toggle:schema-multiline-toggle"
|
|
510
|
+
>
|
|
511
|
+
</schema-tree>`
|
|
512
|
+
}`;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { LitElement, html, css } from "lit";
|
|
2
|
+
import { customElement, property } from "lit/decorators.js";
|
|
3
|
+
import { copyToClipboard } from "~/utils/common-utils";
|
|
4
|
+
import FontStyles from "~/styles/font-styles";
|
|
5
|
+
import BorderStyles from "~/styles/border-styles";
|
|
6
|
+
import InputStyles from "~/styles/input-styles";
|
|
7
|
+
import CustomStyles from "~/styles/custom-styles";
|
|
8
|
+
|
|
9
|
+
@customElement("json-tree")
|
|
10
|
+
export default class JsonTree extends LitElement {
|
|
11
|
+
@property({ type: Object }) data = null;
|
|
12
|
+
@property({ type: String, attribute: "render-style" }) renderStyle = "";
|
|
13
|
+
|
|
14
|
+
static get styles() {
|
|
15
|
+
return [
|
|
16
|
+
FontStyles,
|
|
17
|
+
BorderStyles,
|
|
18
|
+
InputStyles,
|
|
19
|
+
css`
|
|
20
|
+
:host {
|
|
21
|
+
display: flex;
|
|
22
|
+
}
|
|
23
|
+
:where(button, input[type='checkbox'], [tabindex='0']):focus-visible {
|
|
24
|
+
box-shadow: var(--focus-shadow);
|
|
25
|
+
}
|
|
26
|
+
:where(input[type='text'], input[type='password'], select, textarea):focus-visible {
|
|
27
|
+
border-color: var(--primary);
|
|
28
|
+
}
|
|
29
|
+
.json-tree {
|
|
30
|
+
position: relative;
|
|
31
|
+
font-family: var(--font-mono);
|
|
32
|
+
font-size: var(--font-size-small);
|
|
33
|
+
display: inline-block;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
word-break: break-all;
|
|
36
|
+
flex: 1;
|
|
37
|
+
line-height: calc(var(--font-size-small) + 6px);
|
|
38
|
+
min-height: 40px;
|
|
39
|
+
direction: ltr;
|
|
40
|
+
text-align: left;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.open-bracket {
|
|
44
|
+
display: inline-block;
|
|
45
|
+
padding: 0 20px 0 0;
|
|
46
|
+
cursor: pointer;
|
|
47
|
+
border: 1px solid transparent;
|
|
48
|
+
border-radius: min(var(--radius), 0.5rem);
|
|
49
|
+
|
|
50
|
+
&:hover {
|
|
51
|
+
color: var(--primary);
|
|
52
|
+
border: 1px solid var(--border);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
&.expanded:hover ~ .inside-bracket {
|
|
56
|
+
border-left: 1px solid var(--muted-foreground);
|
|
57
|
+
}
|
|
58
|
+
&.expanded:hover ~ .close-bracket {
|
|
59
|
+
color: var(--primary);
|
|
60
|
+
}
|
|
61
|
+
&.collapsed + .inside-bracket,
|
|
62
|
+
&.collapsed + .inside-bracket + .close-bracket {
|
|
63
|
+
display: none;
|
|
64
|
+
}
|
|
65
|
+
&.expanded .open-bracket-collapsed {
|
|
66
|
+
display: none;
|
|
67
|
+
}
|
|
68
|
+
&.collapsed .open-bracket-expanded {
|
|
69
|
+
display: none;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
.close-bracket {
|
|
73
|
+
border: 1px solid transparent;
|
|
74
|
+
border-radius: min(var(--radius), 0.5rem);
|
|
75
|
+
display: inline-block;
|
|
76
|
+
}
|
|
77
|
+
.inside-bracket {
|
|
78
|
+
padding-left: 12px;
|
|
79
|
+
overflow: hidden;
|
|
80
|
+
border-left: 1px dotted var(--border);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
.string {
|
|
84
|
+
color: var(--green);
|
|
85
|
+
}
|
|
86
|
+
.number {
|
|
87
|
+
color: var(--blue);
|
|
88
|
+
}
|
|
89
|
+
.null {
|
|
90
|
+
color: var(--destructive);
|
|
91
|
+
}
|
|
92
|
+
.boolean {
|
|
93
|
+
color: var(--purple);
|
|
94
|
+
}
|
|
95
|
+
.object {
|
|
96
|
+
color: var(--foreground);
|
|
97
|
+
}
|
|
98
|
+
.toolbar {
|
|
99
|
+
position: absolute;
|
|
100
|
+
top: 5px;
|
|
101
|
+
right: 6px;
|
|
102
|
+
display: flex;
|
|
103
|
+
padding: 2px;
|
|
104
|
+
align-items: center;
|
|
105
|
+
}
|
|
106
|
+
`,
|
|
107
|
+
CustomStyles,
|
|
108
|
+
];
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
render() {
|
|
112
|
+
return html`
|
|
113
|
+
<div
|
|
114
|
+
class="json-tree"
|
|
115
|
+
@click="${(e) => {
|
|
116
|
+
if (e.target.classList.contains("btn-copy")) {
|
|
117
|
+
copyToClipboard(JSON.stringify(this.data, null, 2), e);
|
|
118
|
+
} else {
|
|
119
|
+
this.toggleExpand(e);
|
|
120
|
+
}
|
|
121
|
+
}}"
|
|
122
|
+
>
|
|
123
|
+
<div class="toolbar">
|
|
124
|
+
<button class="btn btn-sm btn-outline toolbar-btn btn-copy" part="btn btn-outline btn-copy">Copy</button>
|
|
125
|
+
</div>
|
|
126
|
+
${this.generateTree(this.data, true)}
|
|
127
|
+
</div>
|
|
128
|
+
`;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
generateTree(data, isLast = false) {
|
|
132
|
+
if (data === null) {
|
|
133
|
+
return html`<span class="null">null</span>${isLast ? "" : ","}`;
|
|
134
|
+
}
|
|
135
|
+
if (typeof data === "object" && data instanceof Date === false) {
|
|
136
|
+
const detailType = Array.isArray(data) ? "array" : "pure_object";
|
|
137
|
+
if (Object.keys(data).length === 0) {
|
|
138
|
+
return html`${Array.isArray(data) ? "[ ]," : "{ },"}`;
|
|
139
|
+
}
|
|
140
|
+
return html`
|
|
141
|
+
<div class="open-bracket expanded ${detailType === "array" ? "array" : "object"}">
|
|
142
|
+
<span class="open-bracket-expanded">${detailType === "array" ? "[" : "{"}</span>
|
|
143
|
+
<span class="open-bracket-collapsed">${detailType === "array" ? "[...]" : "{...}"}</span>
|
|
144
|
+
</div>
|
|
145
|
+
<div class="inside-bracket">
|
|
146
|
+
${Object.keys(data).map(
|
|
147
|
+
(key, i, a) =>
|
|
148
|
+
html`<div class="item">
|
|
149
|
+
${detailType === "pure_object" ? html`"${key}":` : ""} ${this.generateTree(data[key], i === a.length - 1)}
|
|
150
|
+
</div>`,
|
|
151
|
+
)}
|
|
152
|
+
</div>
|
|
153
|
+
<div class="close-bracket">${detailType === "array" ? "]" : "}"}${isLast ? "" : ","}</div>
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
return typeof data === "string" || data instanceof Date
|
|
157
|
+
? html`<span class="${typeof data}">"${data}"</span>${isLast ? "" : ","}`
|
|
158
|
+
: html`<span class="${typeof data}">${data}</span>${isLast ? "" : ","}`;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
toggleExpand(e) {
|
|
162
|
+
const openBracketEl = e.target.closest(".open-bracket");
|
|
163
|
+
if (openBracketEl) {
|
|
164
|
+
if (openBracketEl.classList.contains("expanded")) {
|
|
165
|
+
openBracketEl.classList.replace("expanded", "collapsed");
|
|
166
|
+
} else {
|
|
167
|
+
openBracketEl.classList.replace("collapsed", "expanded");
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|