rapidoc 9.1.2 → 9.1.3
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/dist/index.html +1 -1
- package/dist/index.html.gz +0 -0
- package/dist/rapidoc-min.js +2 -5
- package/dist/rapidoc-min.js.LICENSE.txt +1 -1
- package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
- package/dist/rapidoc-min.js.gz +0 -0
- package/dist/report.html +2 -2
- package/docs/api.html +26 -35
- package/docs/examples/auth-test1.html +113 -0
- package/docs/examples/slots.html +7 -0
- package/docs/list.html +9 -1
- package/docs/rapidoc-min.js +2 -5
- package/docs/rapidoc-mini.html +10 -10
- package/docs/specs/auth-test1.yaml +35 -0
- package/docs/specs/auth.yaml +2 -2
- package/docs/specs/dynamic-query-params.yaml +41 -0
- package/docs/specs/multipart-formdata.yaml +3 -0
- package/docs/specs/server.yaml +4 -4
- package/index.html +3 -1
- package/package.json +4 -4
- package/src/components/api-request.js +24 -23
- package/src/components/json-tree.js +1 -1
- package/src/json-schema-viewer.js +1 -0
- package/src/rapidoc.js +1 -0
- package/src/templates/overview-template.js +1 -1
- package/src/templates/security-scheme-template.js +23 -18
- package/src/utils/schema-utils.js +8 -8
- package/src/utils/spec-parser.js +8 -0
- package/webpack.config.js +0 -12
- package/dist/rapidoc-min.js.map +0 -1
- package/dist/rapidoc-min.js.map.gz +0 -0
package/docs/rapidoc-mini.html
CHANGED
|
@@ -27,11 +27,11 @@
|
|
|
27
27
|
<main>
|
|
28
28
|
<h2>Introducing <rapi-doc-mini> Web Component </h2>
|
|
29
29
|
<p>
|
|
30
|
-
<b><rapi-doc-mini></b> a new way to expose your API documentation. There are various styles and
|
|
30
|
+
<b><rapi-doc-mini></b> a new way to expose your API documentation. There are various styles and needs how one would like to document their APIs.
|
|
31
31
|
such as
|
|
32
32
|
<ul>
|
|
33
33
|
<li>
|
|
34
|
-
All the APIs are documented in one central place. This is where <b><rapi-doc></b> fits in.
|
|
34
|
+
All the APIs are documented in one central place. This is where <b><rapi-doc></b> fits in. However for the rest of bullets listed below <b><rapi-doc-mini></b> is your friend
|
|
35
35
|
</li>
|
|
36
36
|
<li>
|
|
37
37
|
Expose just a few important APIs such as authentication etc as a part of a blog, to provide an initial understanding to your audience
|
|
@@ -41,13 +41,12 @@
|
|
|
41
41
|
</li>
|
|
42
42
|
<li>
|
|
43
43
|
Or you are explaining a business case which uses microservices,
|
|
44
|
-
where each microservice has its own APIs and the ask is to pick few APIs from each of theses microservice show how they
|
|
44
|
+
where each microservice has its own APIs and the ask is to pick few APIs from each of theses microservice show how they work together in a single document
|
|
45
45
|
</li>
|
|
46
46
|
</ul>
|
|
47
47
|
</p>
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
<h2>Usage in a bolg style writing</h2>
|
|
49
|
+
<h2>Usage in a blog style writing</h2>
|
|
51
50
|
<p style="flex:1">
|
|
52
51
|
It is fairly common to write specifically about few APIs to provide an initial understanding to your users.
|
|
53
52
|
However in those cases you run the risk of your writeup getting outdated when the actual API changes its shape.
|
|
@@ -69,7 +68,8 @@
|
|
|
69
68
|
bg-color = "#f9f9fb"
|
|
70
69
|
> </rapi-doc-mini></code>
|
|
71
70
|
</pre>
|
|
72
|
-
Above HTML snippet will result in generating an API doc as shown below.
|
|
71
|
+
Above HTML snippet will result in generating an API doc as shown below. Notice how it blends seamlessly with this writeup as if its a part of this page.
|
|
72
|
+
Go ahead and play with the below APIs, make live request and watch the responses, all from this very blog.
|
|
73
73
|
</p>
|
|
74
74
|
<rapi-doc-mini
|
|
75
75
|
style= "min-width:600px;"
|
|
@@ -95,9 +95,8 @@
|
|
|
95
95
|
paths-expanded = "false"
|
|
96
96
|
> </rapi-doc-mini>
|
|
97
97
|
|
|
98
|
-
|
|
99
98
|
<br/><br/>
|
|
100
|
-
<h3>Pick
|
|
99
|
+
<h3>Pick only specific APIs from OpenAPI spec</h3>
|
|
101
100
|
Instead of showing entire open-api spec you can just extract and choose to show what you need to show. This is done using <b>match-paths</b> attribute.
|
|
102
101
|
<br/>Example below uses the same OpenAPI spec as we used above, but showing only the paths that we intend to
|
|
103
102
|
|
|
@@ -125,6 +124,7 @@
|
|
|
125
124
|
> </rapi-doc-mini>
|
|
126
125
|
<br/>
|
|
127
126
|
<h3>More complex RegEx based filtering of API is possible too (match-paths & match-type)</h3>
|
|
127
|
+
Here we are using regular RegEx to select the paths which is either <span class="mono blue"> get /users/{userId}</span> or <span class="mono blue"> post /users</span>
|
|
128
128
|
<pre class="shadow1 code-block" style="width:575px">
|
|
129
129
|
<code class="language-html">
|
|
130
130
|
<rapi-doc-mini
|
|
@@ -152,7 +152,7 @@
|
|
|
152
152
|
> </rapi-doc-mini>
|
|
153
153
|
|
|
154
154
|
<h3>Show it Minimzed or Expanded</h3>
|
|
155
|
-
If expand/collapse is not your style,
|
|
155
|
+
If expand/collapse is not your style, then have it always expanded and make it more natural and integrated part of your writeup.
|
|
156
156
|
<br> Use the attribute <b>paths-expanded = "true"</b> to achive this <br/><br/>
|
|
157
157
|
|
|
158
158
|
<rapi-doc-mini
|
|
@@ -216,4 +216,4 @@
|
|
|
216
216
|
</main>
|
|
217
217
|
|
|
218
218
|
</body>
|
|
219
|
-
</html>
|
|
219
|
+
</html>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
openapi: 3.0.1
|
|
2
|
+
info:
|
|
3
|
+
title: Authentication Test Case
|
|
4
|
+
description: Demonstrate various authentication methods supported by RapiDoc
|
|
5
|
+
servers:
|
|
6
|
+
- url: https://reqres.in/api/
|
|
7
|
+
paths:
|
|
8
|
+
/users/{userId}:
|
|
9
|
+
get:
|
|
10
|
+
description: Uses HTTP Basic Auth
|
|
11
|
+
parameters:
|
|
12
|
+
- in: path
|
|
13
|
+
name: userId
|
|
14
|
+
schema:
|
|
15
|
+
type: integer
|
|
16
|
+
example: 3
|
|
17
|
+
required: true
|
|
18
|
+
description: Numeric ID of the user to get
|
|
19
|
+
security:
|
|
20
|
+
- http-basic: []
|
|
21
|
+
|
|
22
|
+
/users:
|
|
23
|
+
get:
|
|
24
|
+
description: Uses API Key Auth
|
|
25
|
+
security:
|
|
26
|
+
- api_key1: []
|
|
27
|
+
components:
|
|
28
|
+
securitySchemes:
|
|
29
|
+
http-basic:
|
|
30
|
+
type: http
|
|
31
|
+
scheme: basic
|
|
32
|
+
api_key1:
|
|
33
|
+
type: apiKey
|
|
34
|
+
name: Authorization
|
|
35
|
+
in: header
|
package/docs/specs/auth.yaml
CHANGED
|
@@ -48,9 +48,9 @@ paths:
|
|
|
48
48
|
- ms-oauth:
|
|
49
49
|
- User.ReadBasic.All
|
|
50
50
|
- Directory.Read.All
|
|
51
|
-
- http-basic: []
|
|
51
|
+
- http-basic: ['h-scope1', 'h-scope2']
|
|
52
52
|
- api_key_cookie: []
|
|
53
|
-
- api_key1: []
|
|
53
|
+
- api_key1: ['a-scope1', 'a-scope2']
|
|
54
54
|
api_key2: []
|
|
55
55
|
components:
|
|
56
56
|
securitySchemes:
|
|
@@ -75,6 +75,25 @@ paths:
|
|
|
75
75
|
type: string
|
|
76
76
|
additionalProperties:
|
|
77
77
|
type: string
|
|
78
|
+
- in: query
|
|
79
|
+
name: dynamic-query-params5
|
|
80
|
+
explode: false
|
|
81
|
+
required: false
|
|
82
|
+
schema:
|
|
83
|
+
type: object
|
|
84
|
+
properties:
|
|
85
|
+
propertyOne:
|
|
86
|
+
type: string
|
|
87
|
+
enum:
|
|
88
|
+
- VALUE-1
|
|
89
|
+
- VALUE-2
|
|
90
|
+
default: VALUE-2
|
|
91
|
+
propertyTwo:
|
|
92
|
+
type: string
|
|
93
|
+
enum:
|
|
94
|
+
- FLAG-1
|
|
95
|
+
- FLAG-2
|
|
96
|
+
default: FLAG-1
|
|
78
97
|
responses:
|
|
79
98
|
'200':
|
|
80
99
|
description: successful operation
|
|
@@ -187,6 +206,28 @@ paths:
|
|
|
187
206
|
type: string
|
|
188
207
|
additionalProperties:
|
|
189
208
|
type: string
|
|
209
|
+
- in: query
|
|
210
|
+
name: dynamic-query-params5
|
|
211
|
+
description: >
|
|
212
|
+
Example generation works for non-exloded objects:<br />
|
|
213
|
+
`propertyOne=VALUE-1&property2=FLAG-1`
|
|
214
|
+
explode: false
|
|
215
|
+
required: false
|
|
216
|
+
schema:
|
|
217
|
+
type: object
|
|
218
|
+
properties:
|
|
219
|
+
propertyOne:
|
|
220
|
+
type: string
|
|
221
|
+
enum:
|
|
222
|
+
- VALUE-1
|
|
223
|
+
- VALUE-2
|
|
224
|
+
default: VALUE-2
|
|
225
|
+
propertyTwo:
|
|
226
|
+
type: string
|
|
227
|
+
enum:
|
|
228
|
+
- FLAG-1
|
|
229
|
+
- FLAG-2
|
|
230
|
+
default: FLAG-1
|
|
190
231
|
responses:
|
|
191
232
|
'200':
|
|
192
233
|
description: successful operation
|
|
@@ -11,6 +11,8 @@ paths:
|
|
|
11
11
|
multipart/form-data:
|
|
12
12
|
schema:
|
|
13
13
|
type: object
|
|
14
|
+
required:
|
|
15
|
+
- agePart
|
|
14
16
|
properties:
|
|
15
17
|
photoPart:
|
|
16
18
|
type: string
|
|
@@ -27,6 +29,7 @@ paths:
|
|
|
27
29
|
agePart:
|
|
28
30
|
type: integer
|
|
29
31
|
default: 21
|
|
32
|
+
deprecated: true
|
|
30
33
|
description: 'Age of the person'
|
|
31
34
|
contactPart:
|
|
32
35
|
type: object
|
package/docs/specs/server.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
openapi: 3.0.2
|
|
2
2
|
info:
|
|
3
3
|
version: '1.0'
|
|
4
|
-
title: Server
|
|
4
|
+
title: API Server templating using variables
|
|
5
5
|
description: >
|
|
6
6
|
Various ways to define API servers in the spec including variables
|
|
7
7
|
|
|
@@ -84,10 +84,10 @@ servers:
|
|
|
84
84
|
- v1
|
|
85
85
|
- v2
|
|
86
86
|
paths:
|
|
87
|
-
/server-
|
|
87
|
+
/api-server-template:
|
|
88
88
|
get:
|
|
89
|
-
summary: Server
|
|
90
|
-
|
|
89
|
+
summary: Dynamic API Server.
|
|
90
|
+
description: Uses API server template string and variables which can be used to generatea a desired API server url - The selected and computed API Server URL should be shown against `API SERVER`.
|
|
91
91
|
responses:
|
|
92
92
|
'200':
|
|
93
93
|
description: successful operation
|
package/index.html
CHANGED
|
@@ -37,7 +37,9 @@
|
|
|
37
37
|
schema-style="tree"
|
|
38
38
|
show-components = "true"
|
|
39
39
|
show-info = "true"
|
|
40
|
-
show-header = "
|
|
40
|
+
show-header = "true"
|
|
41
|
+
allow-spec-url-load="false"
|
|
42
|
+
allow-spec-file-load="false"
|
|
41
43
|
allow-search = "true"
|
|
42
44
|
allow-advanced-search = "false"
|
|
43
45
|
allow-server-selection = "false"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rapidoc",
|
|
3
|
-
"version": "9.1.
|
|
3
|
+
"version": "9.1.3",
|
|
4
4
|
"description": "RapiDoc - Open API spec viewer with built in console",
|
|
5
5
|
"author": "Mrinmoy Majumdar <mrin9@yahoo.com>",
|
|
6
6
|
"repository": {
|
|
@@ -64,12 +64,12 @@
|
|
|
64
64
|
"filemanager-webpack-plugin": "^6.1.7",
|
|
65
65
|
"html-webpack-plugin": "^5.3.2",
|
|
66
66
|
"inspectpack": "^4.7.1",
|
|
67
|
-
"style-loader": "^3.
|
|
67
|
+
"style-loader": "^3.3.0",
|
|
68
68
|
"terser-webpack-plugin": "^5.2.4",
|
|
69
|
-
"webpack": "^5.
|
|
69
|
+
"webpack": "^5.54.0",
|
|
70
70
|
"webpack-bundle-analyzer": "^4.4.2",
|
|
71
71
|
"webpack-cli": "^4.8.0",
|
|
72
|
-
"webpack-dev-server": "^4.
|
|
72
|
+
"webpack-dev-server": "^4.3.0"
|
|
73
73
|
},
|
|
74
74
|
"engines": {
|
|
75
75
|
"node": ">=10.21.0"
|
|
@@ -102,6 +102,9 @@ export default class ApiRequest extends LitElement {
|
|
|
102
102
|
color: var(--fg);
|
|
103
103
|
font-family: var(--font-mono);
|
|
104
104
|
}
|
|
105
|
+
.param-name.deprecated {
|
|
106
|
+
text-decoration: line-through;
|
|
107
|
+
}
|
|
105
108
|
.param-type{
|
|
106
109
|
color: var(--light-fg);
|
|
107
110
|
font-family: var(--font-regular);
|
|
@@ -308,7 +311,7 @@ export default class ApiRequest extends LitElement {
|
|
|
308
311
|
'',
|
|
309
312
|
'',
|
|
310
313
|
declaredParamSchema,
|
|
311
|
-
serializeStyle,
|
|
314
|
+
serializeStyle || 'json',
|
|
312
315
|
true,
|
|
313
316
|
true,
|
|
314
317
|
'text',
|
|
@@ -581,9 +584,7 @@ export default class ApiRequest extends LitElement {
|
|
|
581
584
|
data-example-format = "${v.exampleFormat}"
|
|
582
585
|
style="width:100%; resize:vertical;"
|
|
583
586
|
.textContent = "${this.fillRequestFieldsWithExample === 'true' ? (v.exampleFormat === 'text' ? v.exampleValue : JSON.stringify(v.exampleValue, null, 2)) : ''}"
|
|
584
|
-
>
|
|
585
|
-
</textarea>
|
|
586
|
-
|
|
587
|
+
></textarea>
|
|
587
588
|
</div>
|
|
588
589
|
`)}
|
|
589
590
|
|
|
@@ -766,11 +767,8 @@ export default class ApiRequest extends LitElement {
|
|
|
766
767
|
formDataTableRows.push(html`
|
|
767
768
|
<tr>
|
|
768
769
|
<td style="width:${labelColWidth}; min-width:100px;">
|
|
769
|
-
<div class="param-name">
|
|
770
|
-
${fieldSchema.required
|
|
771
|
-
? html`<span style='color:var(--red);'>*</span>${fieldName}`
|
|
772
|
-
: html`${fieldName}`
|
|
773
|
-
}
|
|
770
|
+
<div class="param-name ${fieldSchema.deprecated ? 'deprecated' : ''}">
|
|
771
|
+
${fieldName}${(schema.required?.includes(fieldName) || fieldSchema.required) ? html`<span style='color:var(--red);'>*</span>` : ''}
|
|
774
772
|
</div>
|
|
775
773
|
<div class="param-type">${paramSchema.type}</div>
|
|
776
774
|
</td>
|
|
@@ -935,8 +933,7 @@ export default class ApiRequest extends LitElement {
|
|
|
935
933
|
<pre style="white-space:pre; max-height:400px; overflow:auto">${responseFormat
|
|
936
934
|
? html`<code>${unsafeHTML(Prism.highlight(this.responseText, Prism.languages[responseFormat], responseFormat))}</code>`
|
|
937
935
|
: `${this.responseText}`
|
|
938
|
-
}
|
|
939
|
-
</pre>
|
|
936
|
+
}</pre>
|
|
940
937
|
</div>`
|
|
941
938
|
}
|
|
942
939
|
<div class="tab-content col m-markdown" style="flex:1;display:${this.activeResponseTab === 'headers' ? 'flex' : 'none'};" >
|
|
@@ -1057,7 +1054,6 @@ export default class ApiRequest extends LitElement {
|
|
|
1057
1054
|
fetchUrl = this.path;
|
|
1058
1055
|
const fetchOptions = {
|
|
1059
1056
|
method: this.method.toUpperCase(),
|
|
1060
|
-
headers: {},
|
|
1061
1057
|
};
|
|
1062
1058
|
// Generate URL using Path Params
|
|
1063
1059
|
pathParamEls.map((el) => {
|
|
@@ -1154,13 +1150,13 @@ export default class ApiRequest extends LitElement {
|
|
|
1154
1150
|
curlUrl = fetchUrl;
|
|
1155
1151
|
}
|
|
1156
1152
|
curl = `curl -X ${this.method.toUpperCase()} "${curlUrl}" \\\n`;
|
|
1157
|
-
|
|
1153
|
+
const reqHeaders = new Headers();
|
|
1158
1154
|
if (acceptHeader) {
|
|
1159
1155
|
// Uses the acceptHeader from Response panel
|
|
1160
|
-
|
|
1156
|
+
reqHeaders.append('Accept', acceptHeader);
|
|
1161
1157
|
curlHeaders += ` -H "Accept: ${acceptHeader}" \\\n`;
|
|
1162
1158
|
} else if (this.accept) {
|
|
1163
|
-
|
|
1159
|
+
reqHeaders.append('Accept', this.accept);
|
|
1164
1160
|
curlHeaders += ` -H "Accept: ${this.accept}" \\\n`;
|
|
1165
1161
|
}
|
|
1166
1162
|
|
|
@@ -1168,14 +1164,14 @@ export default class ApiRequest extends LitElement {
|
|
|
1168
1164
|
this.api_keys
|
|
1169
1165
|
.filter((v) => (v.in === 'header'))
|
|
1170
1166
|
.forEach((v) => {
|
|
1171
|
-
|
|
1167
|
+
reqHeaders.append(v.name, v.finalKeyValue);
|
|
1172
1168
|
curlHeaders += ` -H "${v.name}: ${v.finalKeyValue}" \\\n`;
|
|
1173
1169
|
});
|
|
1174
1170
|
|
|
1175
1171
|
// Add Header Params
|
|
1176
1172
|
headerParamEls.map((el) => {
|
|
1177
1173
|
if (el.value) {
|
|
1178
|
-
|
|
1174
|
+
reqHeaders.append(el.dataset.pname, el.value);
|
|
1179
1175
|
curlHeaders += ` -H "${el.dataset.pname}: ${el.value}" \\\n`;
|
|
1180
1176
|
}
|
|
1181
1177
|
});
|
|
@@ -1257,18 +1253,22 @@ export default class ApiRequest extends LitElement {
|
|
|
1257
1253
|
const exampleTextAreaEl = requestPanelEl.querySelector('.request-body-param-user-input');
|
|
1258
1254
|
if (exampleTextAreaEl?.value) {
|
|
1259
1255
|
fetchOptions.body = exampleTextAreaEl.value;
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1256
|
+
if (requestBodyType.includes('json')) {
|
|
1257
|
+
try {
|
|
1258
|
+
curlData = ` -d '${JSON.stringify(JSON.parse(exampleTextAreaEl.value))}' \\\n`;
|
|
1259
|
+
} catch (err) {
|
|
1260
|
+
// Ignore.
|
|
1261
|
+
}
|
|
1262
|
+
}
|
|
1263
|
+
if (!curlData) {
|
|
1264
|
+
curlData = ` -d '${exampleTextAreaEl.value.replace(/'/g, '\'"\'"\'')}' \\\n`;
|
|
1265
1265
|
}
|
|
1266
1266
|
}
|
|
1267
1267
|
}
|
|
1268
1268
|
// Common for all request-body
|
|
1269
1269
|
if (!requestBodyType.includes('form-data')) {
|
|
1270
1270
|
// For multipart/form-data dont set the content-type to allow creation of browser generated part boundaries
|
|
1271
|
-
|
|
1271
|
+
reqHeaders.append('Content-Type', requestBodyType);
|
|
1272
1272
|
}
|
|
1273
1273
|
curlHeaders += ` -H "Content-Type: ${requestBodyType}" \\\n`;
|
|
1274
1274
|
}
|
|
@@ -1287,6 +1287,7 @@ export default class ApiRequest extends LitElement {
|
|
|
1287
1287
|
if (this.fetchCredentials) {
|
|
1288
1288
|
fetchOptions.credentials = this.fetchCredentials;
|
|
1289
1289
|
}
|
|
1290
|
+
fetchOptions.headers = reqHeaders;
|
|
1290
1291
|
const fetchRequest = new Request(fetchUrl, fetchOptions);
|
|
1291
1292
|
this.dispatchEvent(new CustomEvent('before-try', {
|
|
1292
1293
|
bubbles: true,
|
|
@@ -99,7 +99,7 @@ export default class JsonTree extends LitElement {
|
|
|
99
99
|
<div class="inside-bracket">
|
|
100
100
|
${Object.keys(data).map((key, i, a) => html`
|
|
101
101
|
<div class="item">
|
|
102
|
-
${detailType === 'pure_object' ? html
|
|
102
|
+
${detailType === 'pure_object' ? html`"${key}":` : ''}
|
|
103
103
|
${this.generateTree(data[key], i === (a.length - 1))}
|
|
104
104
|
</div>`)
|
|
105
105
|
}
|
|
@@ -55,6 +55,7 @@ export default class JsonSchemaViewer extends LitElement {
|
|
|
55
55
|
// Allow or restrict features
|
|
56
56
|
allowSpecUrlLoad: { type: String, attribute: 'allow-spec-url-load' },
|
|
57
57
|
allowSpecFileLoad: { type: String, attribute: 'allow-spec-file-load' },
|
|
58
|
+
allowSpecFileDownload: { type: String, attribute: 'allow-spec-file-download' },
|
|
58
59
|
allowSearch: { type: String, attribute: 'allow-search' },
|
|
59
60
|
|
|
60
61
|
// Main Colors and Font
|
package/src/rapidoc.js
CHANGED
|
@@ -88,6 +88,7 @@ export default class RapiDoc extends LitElement {
|
|
|
88
88
|
allowTry: { type: String, attribute: 'allow-try' },
|
|
89
89
|
allowSpecUrlLoad: { type: String, attribute: 'allow-spec-url-load' },
|
|
90
90
|
allowSpecFileLoad: { type: String, attribute: 'allow-spec-file-load' },
|
|
91
|
+
allowSpecFileDownload: { type: String, attribute: 'allow-spec-file-download' },
|
|
91
92
|
allowSearch: { type: String, attribute: 'allow-search' },
|
|
92
93
|
allowAdvancedSearch: { type: String, attribute: 'allow-advanced-search' },
|
|
93
94
|
allowServerSelection: { type: String, attribute: 'allow-server-selection' },
|
|
@@ -47,7 +47,7 @@ export default function overviewTemplate() {
|
|
|
47
47
|
? html`<span><a href="${this.resolvedSpec.info.termsOfService}" part="anchor anchor-overview">Terms of Service</a></span>`
|
|
48
48
|
: ''
|
|
49
49
|
}
|
|
50
|
-
${this.specUrl
|
|
50
|
+
${this.specUrl && this.allowSpecFileDownload === 'true'
|
|
51
51
|
? html`
|
|
52
52
|
<div style="display:flex; margin:12px 0; gap:8px; justify-content: start;">
|
|
53
53
|
<button class="m-btn thin-border" style="width:170px" part="btn btn-outline" @click='${(e) => { downloadResource(this.specUrl, 'openapi-spec', e); }}'>Download OpenAPI spec</button>
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable arrow-body-style */
|
|
1
2
|
import { html } from 'lit-element';
|
|
2
3
|
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
|
|
3
4
|
import marked from 'marked';
|
|
@@ -449,19 +450,18 @@ export function pathSecurityTemplate(pathSecurity) {
|
|
|
449
450
|
pathSecurity.forEach((pSecurity) => {
|
|
450
451
|
const andSecurityKeys1 = [];
|
|
451
452
|
const andKeyTypes = [];
|
|
452
|
-
let pathScopes = '';
|
|
453
453
|
Object.keys(pSecurity).forEach((pathSecurityKey) => {
|
|
454
|
+
let pathScopes = '';
|
|
454
455
|
const s = this.resolvedSpec.securitySchemes.find((ss) => ss.securitySchemeId === pathSecurityKey);
|
|
455
|
-
if (
|
|
456
|
+
if (pSecurity[pathSecurityKey] && Array.isArray(pSecurity[pathSecurityKey])) {
|
|
456
457
|
pathScopes = pSecurity[pathSecurityKey].join(', ');
|
|
457
458
|
}
|
|
458
459
|
if (s) {
|
|
459
460
|
andKeyTypes.push(s.typeDisplay);
|
|
460
|
-
andSecurityKeys1.push(s);
|
|
461
|
+
andSecurityKeys1.push({ ...s, ...({ scopes: pathScopes }) });
|
|
461
462
|
}
|
|
462
463
|
});
|
|
463
464
|
orSecurityKeys1.push({
|
|
464
|
-
pathScopes,
|
|
465
465
|
securityTypes: andKeyTypes.length > 1 ? `${andKeyTypes[0]} + ${andKeyTypes.length - 1} more` : andKeyTypes[0],
|
|
466
466
|
securityDefs: andSecurityKeys1,
|
|
467
467
|
});
|
|
@@ -485,7 +485,20 @@ export function pathSecurityTemplate(pathSecurity) {
|
|
|
485
485
|
<div class="tooltip-text" style="position:absolute; color: var(--fg); top:26px; right:0; border:1px solid var(--border-color);padding:2px 4px; display:block;">
|
|
486
486
|
${orSecurityItem1.securityDefs.length > 1 ? html`<div>Requires <b>all</b> of the following </div>` : ''}
|
|
487
487
|
<div style="padding-left: 8px">
|
|
488
|
-
${orSecurityItem1.securityDefs.map((andSecurityItem, j) =>
|
|
488
|
+
${orSecurityItem1.securityDefs.map((andSecurityItem, j) => {
|
|
489
|
+
const scopeHtml = html`${andSecurityItem.scopes !== ''
|
|
490
|
+
? html`
|
|
491
|
+
<div>
|
|
492
|
+
<b>Required scopes:</b>
|
|
493
|
+
<br/>
|
|
494
|
+
<div style="margin-left:8px">
|
|
495
|
+
${andSecurityItem.scopes.split(',').map((scope, cnt) => html`${cnt === 0 ? '' : '┃'}<span>${scope}</span>`)}
|
|
496
|
+
</div>
|
|
497
|
+
</div>`
|
|
498
|
+
: ''
|
|
499
|
+
}`;
|
|
500
|
+
|
|
501
|
+
return html`
|
|
489
502
|
${andSecurityItem.type === 'oauth2'
|
|
490
503
|
? html`
|
|
491
504
|
<div>
|
|
@@ -494,31 +507,23 @@ export function pathSecurityTemplate(pathSecurity) {
|
|
|
494
507
|
: 'Needs'
|
|
495
508
|
}
|
|
496
509
|
OAuth Token <span style="font-family:var(--font-mono); color:var(--primary-color);">${andSecurityItem.securitySchemeId}</span> in <b>Authorization header</b>
|
|
497
|
-
${
|
|
498
|
-
? html`
|
|
499
|
-
<div>
|
|
500
|
-
<b>Required scopes:</b>
|
|
501
|
-
<br/>
|
|
502
|
-
<div style="margin-left:8px">
|
|
503
|
-
${orSecurityItem1.pathScopes.split(',').map((scope, cnt) => html`${cnt === 0 ? '' : '┃'}<span>${scope}</span>`)}
|
|
504
|
-
</div>
|
|
505
|
-
</div>`
|
|
506
|
-
: ''
|
|
507
|
-
}
|
|
510
|
+
${scopeHtml}
|
|
508
511
|
</div>`
|
|
509
512
|
: andSecurityItem.type === 'http'
|
|
510
513
|
? html`
|
|
511
514
|
<div>
|
|
512
515
|
${orSecurityItem1.securityDefs.length > 1 ? html`<b>${j + 1}.</b> ` : html`Requires`}
|
|
513
516
|
${andSecurityItem.scheme === 'basic' ? 'Base 64 encoded username:password' : 'Bearer Token'} in <b>Authorization header</b>
|
|
517
|
+
${scopeHtml}
|
|
514
518
|
</div>`
|
|
515
519
|
: html`
|
|
516
520
|
<div>
|
|
517
521
|
${orSecurityItem1.securityDefs.length > 1 ? html`<b>${j + 1}.</b> ` : html`Requires`}
|
|
518
522
|
Token in <b>${andSecurityItem.name} ${andSecurityItem.in}</b>
|
|
523
|
+
${scopeHtml}
|
|
519
524
|
</div>`
|
|
520
|
-
}
|
|
521
|
-
|
|
525
|
+
}`;
|
|
526
|
+
})}
|
|
522
527
|
</div>
|
|
523
528
|
</div>
|
|
524
529
|
</div>
|
|
@@ -661,7 +661,7 @@ export function generateExample(examples = '', example = '', schema, mimeType, i
|
|
|
661
661
|
for (const eg in examples) {
|
|
662
662
|
let egContent = '';
|
|
663
663
|
let egFormat = 'json';
|
|
664
|
-
if (mimeType
|
|
664
|
+
if (mimeType?.toLowerCase().includes('json')) {
|
|
665
665
|
if (outputType === 'text') {
|
|
666
666
|
egContent = typeof examples[eg].value === 'string' ? examples[eg].value : JSON.stringify(examples[eg].value, undefined, 2);
|
|
667
667
|
egFormat = 'text';
|
|
@@ -695,7 +695,7 @@ export function generateExample(examples = '', example = '', schema, mimeType, i
|
|
|
695
695
|
} else if (example) {
|
|
696
696
|
let egContent = '';
|
|
697
697
|
let egFormat = 'json';
|
|
698
|
-
if (mimeType
|
|
698
|
+
if (mimeType?.toLowerCase().includes('json')) {
|
|
699
699
|
if (outputType === 'text') {
|
|
700
700
|
egContent = typeof example === 'string' ? example : JSON.stringify(example, undefined, 2);
|
|
701
701
|
egFormat = 'text';
|
|
@@ -734,14 +734,14 @@ export function generateExample(examples = '', example = '', schema, mimeType, i
|
|
|
734
734
|
exampleDescription: '',
|
|
735
735
|
exampleType: mimeType,
|
|
736
736
|
exampleValue: schema.example,
|
|
737
|
-
exampleFormat: ((mimeType
|
|
737
|
+
exampleFormat: ((mimeType?.toLowerCase().includes('json') && typeof schema.example === 'object') ? 'json' : 'text'),
|
|
738
738
|
});
|
|
739
|
-
} else if (mimeType
|
|
739
|
+
} else if (mimeType?.toLowerCase().includes('json') || mimeType?.toLowerCase().includes('text') || mimeType?.toLowerCase().includes('*/*') || mimeType?.toLowerCase().includes('xml')) {
|
|
740
740
|
let xmlRootStart = '';
|
|
741
741
|
let xmlRootEnd = '';
|
|
742
742
|
let exampleFormat = '';
|
|
743
743
|
let exampleValue = '';
|
|
744
|
-
if (mimeType
|
|
744
|
+
if (mimeType?.toLowerCase().includes('xml')) {
|
|
745
745
|
xmlRootStart = (schema.xml && schema.xml.name) ? `<${schema.xml.name}>` : '<root>';
|
|
746
746
|
xmlRootEnd = (schema.xml && schema.xml.name) ? `</${schema.xml.name}>` : '</root>';
|
|
747
747
|
exampleFormat = 'text';
|
|
@@ -767,7 +767,7 @@ export function generateExample(examples = '', example = '', schema, mimeType, i
|
|
|
767
767
|
const description = samples[samplesKey]['::DESCRIPTION'] || '';
|
|
768
768
|
removeTitlesAndDescriptions(samples[samplesKey]);
|
|
769
769
|
|
|
770
|
-
if (mimeType
|
|
770
|
+
if (mimeType?.toLowerCase().includes('xml')) {
|
|
771
771
|
exampleValue = `${xmlRootStart}${json2xml(samples[samplesKey])}\n${xmlRootEnd}`;
|
|
772
772
|
} else {
|
|
773
773
|
exampleValue = outputType === 'text' ? JSON.stringify(samples[samplesKey], null, 2) : samples[samplesKey];
|
|
@@ -819,7 +819,7 @@ function getSerializeStyleForContentType(contentType) {
|
|
|
819
819
|
|
|
820
820
|
export function getSchemaFromParam(param) {
|
|
821
821
|
if (param.schema) {
|
|
822
|
-
return [param.schema, null];
|
|
822
|
+
return [param.schema, null, null];
|
|
823
823
|
}
|
|
824
824
|
if (param.content) {
|
|
825
825
|
// we gonna use the first content-encoding
|
|
@@ -829,5 +829,5 @@ export function getSchemaFromParam(param) {
|
|
|
829
829
|
}
|
|
830
830
|
}
|
|
831
831
|
}
|
|
832
|
-
return [null, null];
|
|
832
|
+
return [null, null, null];
|
|
833
833
|
}
|
package/src/utils/spec-parser.js
CHANGED
|
@@ -331,6 +331,14 @@ function groupByTags(openApiSpec, generateMissingTags = false, sortTags = false,
|
|
|
331
331
|
finalParameters = pathOrHookObj.parameters ? pathOrHookObj.parameters.slice(0) : [];
|
|
332
332
|
}
|
|
333
333
|
|
|
334
|
+
// Filter callbacks to contain only objects.
|
|
335
|
+
if (pathOrHookObj.callbacks) {
|
|
336
|
+
for (const [callbackName, callbackConfig] of Object.entries(pathOrHookObj.callbacks)) {
|
|
337
|
+
const filteredCallbacks = Object.entries(callbackConfig).filter((entry) => typeof entry[1] === 'object') || [];
|
|
338
|
+
pathOrHookObj.callbacks[callbackName] = Object.fromEntries(filteredCallbacks);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
334
342
|
// Update Responses
|
|
335
343
|
tagObj.paths.push({
|
|
336
344
|
show: true,
|
package/webpack.config.js
CHANGED
|
@@ -49,18 +49,6 @@ const commonPlugins = [
|
|
|
49
49
|
},
|
|
50
50
|
},
|
|
51
51
|
}),
|
|
52
|
-
/*
|
|
53
|
-
new ESLintPlugin({
|
|
54
|
-
emitError: true,
|
|
55
|
-
emitWarning: true,
|
|
56
|
-
formatter: 'stylish',
|
|
57
|
-
overrideConfigFile: path.resolve(__dirname, '.eslintrc'),
|
|
58
|
-
outputReport: {
|
|
59
|
-
filePath: './eslint_report.html',
|
|
60
|
-
formatter: 'html',
|
|
61
|
-
},
|
|
62
|
-
}),
|
|
63
|
-
*/
|
|
64
52
|
];
|
|
65
53
|
|
|
66
54
|
if (process.env.NODE_ENV === 'production') {
|