rapidoc 9.3.6 → 9.3.7
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/.eslintrc +9 -1
- package/dist/index.html +1 -1
- package/dist/index.html.gz +0 -0
- package/dist/rapidoc-min.js +390 -376
- package/dist/rapidoc-min.js.LICENSE.txt +1 -8
- package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
- package/dist/rapidoc-min.js.gz +0 -0
- package/dist/rapidoc-min.js.map +1 -1
- package/dist/rapidoc-min.js.map.gz +0 -0
- package/dist/rapidoc.js +436 -242
- package/dist/report.html +2 -2
- package/index.html +5 -4
- package/package.json +2 -2
- package/src/components/api-request.js +115 -77
- package/src/components/api-response.js +6 -7
- package/src/components/schema-table.js +6 -5
- package/src/components/schema-tree.js +9 -7
- package/src/json-schema-viewer.js +6 -2
- package/src/rapidoc-mini.js +20 -4
- package/src/rapidoc.js +33 -18
- package/src/styles/border-styles.js +2 -2
- package/src/styles/endpoint-styles.js +13 -10
- package/src/styles/flex-styles.js +1 -1
- package/src/styles/font-styles.js +13 -13
- package/src/styles/input-styles.js +2 -2
- package/src/styles/nav-styles.js +1 -1
- package/src/styles/schema-styles.js +12 -9
- package/src/templates/advance-search-template.js +2 -1
- package/src/templates/endpoint-template.js +29 -26
- package/src/templates/expanded-endpoint-template.js +4 -2
- package/src/templates/json-schema-viewer-template.js +3 -3
- package/src/templates/main-body-template.js +2 -2
- package/src/templates/navbar-template.js +6 -6
- package/src/templates/security-scheme-template.js +9 -7
- package/src/utils/common-utils.js +5 -9
- package/src/utils/schema-utils.js +65 -16
- package/src/utils/spec-parser.js +77 -7
- package/src/utils/theme.js +4 -6
|
@@ -6,7 +6,7 @@ import '~/components/api-response';
|
|
|
6
6
|
import codeSamplesTemplate from '~/templates/code-samples-template';
|
|
7
7
|
import callbackTemplate from '~/templates/callback-template';
|
|
8
8
|
import { pathSecurityTemplate } from '~/templates/security-scheme-template';
|
|
9
|
-
import {
|
|
9
|
+
import { getMatchedPaths, rapidocApiKey } from '~/utils/common-utils';
|
|
10
10
|
|
|
11
11
|
function toggleExpand(path) {
|
|
12
12
|
if (path.expanded) {
|
|
@@ -91,7 +91,7 @@ function endpointBodyTemplate(path) {
|
|
|
91
91
|
<div part="section-endpoint-body-${path.expanded ? 'expanded' : 'collapsed'}" class='endpoint-body ${path.method} ${path.deprecated ? 'deprecated' : ''}'>
|
|
92
92
|
<div class="summary">
|
|
93
93
|
${path.summary
|
|
94
|
-
? html`<div class="title" part="section-endpoint-body-title">${path.summary}
|
|
94
|
+
? html`<div class="title" part="section-endpoint-body-title">${path.summary}</div>`
|
|
95
95
|
: path.shortSummary !== path.description
|
|
96
96
|
? html`<div class="title" part="section-endpoint-body-title">${path.shortSummary}</div>`
|
|
97
97
|
: ''
|
|
@@ -100,7 +100,9 @@ function endpointBodyTemplate(path) {
|
|
|
100
100
|
? html`
|
|
101
101
|
<div style="display:flex; flex-wrap:wrap;font-size: var(--font-size-small);">
|
|
102
102
|
${path.xBadges.map((v) => (
|
|
103
|
-
|
|
103
|
+
v.color === 'none'
|
|
104
|
+
? ''
|
|
105
|
+
: html`<span part="endpoint-badge" style="margin:1px; margin-right:5px; padding:1px 8px; font-weight:bold; border-radius:12px; background-color: var(--light-${v.color}, var(--input-bg)); color:var(--${v.color}); border:1px solid var(--${v.color})">${v.label}</span>`
|
|
104
106
|
))
|
|
105
107
|
}
|
|
106
108
|
</div>
|
|
@@ -138,7 +140,7 @@ function endpointBodyTemplate(path) {
|
|
|
138
140
|
.request_body = "${path.requestBody}"
|
|
139
141
|
.api_keys = "${nonEmptyApiKeys}"
|
|
140
142
|
.servers = "${path.servers}"
|
|
141
|
-
server-url = "${path.servers && path.servers.length > 0 ? path.servers[0].url : this.selectedServer
|
|
143
|
+
server-url = "${path.servers && path.servers.length > 0 ? path.servers[0].url : this.selectedServer?.computedUrl}"
|
|
142
144
|
active-schema-tab = "${this.defaultSchemaTab}"
|
|
143
145
|
fill-request-fields-with-example = "${this.fillRequestFieldsWithExample}"
|
|
144
146
|
allow-try = "${this.allowTry}"
|
|
@@ -182,11 +184,12 @@ function endpointBodyTemplate(path) {
|
|
|
182
184
|
</div>`;
|
|
183
185
|
}
|
|
184
186
|
|
|
185
|
-
export default function endpointTemplate(
|
|
187
|
+
export default function endpointTemplate(isMini = false, pathsExpanded = false) {
|
|
186
188
|
if (!this.resolvedSpec) { return ''; }
|
|
187
189
|
return html`
|
|
188
|
-
${
|
|
189
|
-
?
|
|
190
|
+
${isMini
|
|
191
|
+
? ''
|
|
192
|
+
: html`
|
|
190
193
|
<div style="display:flex; justify-content:flex-end;">
|
|
191
194
|
<span @click="${(e) => onExpandCollapseAll(e, 'expand-all')}" style="color:var(--primary-color); cursor:pointer;">
|
|
192
195
|
Expand all
|
|
@@ -197,11 +200,25 @@ export default function endpointTemplate(showExpandCollapse = true, showTags = t
|
|
|
197
200
|
</span>
|
|
198
201
|
sections
|
|
199
202
|
</div>`
|
|
200
|
-
: ''
|
|
201
203
|
}
|
|
202
204
|
${this.resolvedSpec.tags.map((tag) => html`
|
|
203
|
-
${
|
|
204
|
-
? html`
|
|
205
|
+
${isMini
|
|
206
|
+
? html`
|
|
207
|
+
<div class='section-tag-body'>
|
|
208
|
+
${tag.paths.filter((path) => {
|
|
209
|
+
if (this.searchVal) {
|
|
210
|
+
return getMatchedPaths(this.searchVal, path, tag.name);
|
|
211
|
+
}
|
|
212
|
+
return true;
|
|
213
|
+
}).map((path) => html`
|
|
214
|
+
<section id='${path.elementId}' class='m-endpoint regular-font ${path.method} ${pathsExpanded || path.expanded ? 'expanded' : 'collapsed'}'>
|
|
215
|
+
${endpointHeadTemplate.call(this, path, pathsExpanded)}
|
|
216
|
+
${pathsExpanded || path.expanded ? endpointBodyTemplate.call(this, path) : ''}
|
|
217
|
+
</section>`)
|
|
218
|
+
}
|
|
219
|
+
</div>
|
|
220
|
+
`
|
|
221
|
+
: html`
|
|
205
222
|
<div class='regular-font section-gap section-tag ${tag.expanded ? 'expanded' : 'collapsed'}'>
|
|
206
223
|
<div class='section-tag-header' @click="${() => { tag.expanded = !tag.expanded; this.requestUpdate(); }}">
|
|
207
224
|
<div id='${tag.elementId}' class="sub-title tag" style="color:var(--primary-color)">${tag.displayName || tag.name}</div>
|
|
@@ -212,8 +229,8 @@ export default function endpointTemplate(showExpandCollapse = true, showTags = t
|
|
|
212
229
|
${unsafeHTML(marked(tag.description || ''))}
|
|
213
230
|
</div>
|
|
214
231
|
${tag.paths.filter((v) => {
|
|
215
|
-
if (this.
|
|
216
|
-
return
|
|
232
|
+
if (this.searchVal) {
|
|
233
|
+
return getMatchedPaths(this.searchVal, v, tag.name);
|
|
217
234
|
}
|
|
218
235
|
return true;
|
|
219
236
|
}).map((path) => html`
|
|
@@ -223,20 +240,6 @@ export default function endpointTemplate(showExpandCollapse = true, showTags = t
|
|
|
223
240
|
</section>`)
|
|
224
241
|
}
|
|
225
242
|
</div>
|
|
226
|
-
</div>`
|
|
227
|
-
: html`
|
|
228
|
-
<div class='section-tag-body'>
|
|
229
|
-
${tag.paths.filter((v) => {
|
|
230
|
-
if (this.matchPaths) {
|
|
231
|
-
return pathIsInSearch(this.matchPaths, v, this.matchType);
|
|
232
|
-
}
|
|
233
|
-
return true;
|
|
234
|
-
}).map((path) => html`
|
|
235
|
-
<section id='${path.elementId}' class='m-endpoint regular-font ${path.method} ${pathsExpanded || path.expanded ? 'expanded' : 'collapsed'}'>
|
|
236
|
-
${endpointHeadTemplate.call(this, path, pathsExpanded)}
|
|
237
|
-
${pathsExpanded || path.expanded ? endpointBodyTemplate.call(this, path) : ''}
|
|
238
|
-
</section>`)
|
|
239
|
-
}
|
|
240
243
|
</div>
|
|
241
244
|
`
|
|
242
245
|
}
|
|
@@ -80,7 +80,9 @@ export function expandedEndpointBodyTemplate(path, tagName = '', tagDescription
|
|
|
80
80
|
? html`
|
|
81
81
|
<div style="display:flex; flex-wrap:wrap; margin-bottom: -24px; font-size: var(--font-size-small);">
|
|
82
82
|
${path.xBadges.map((v) => (
|
|
83
|
-
|
|
83
|
+
v.color === 'none'
|
|
84
|
+
? ''
|
|
85
|
+
: html`<span style="margin:1px; margin-right:5px; padding:1px 8px; font-weight:bold; border-radius:12px; background-color: var(--light-${v.color}, var(--input-bg)); color:var(--${v.color}); border:1px solid var(--${v.color})">${v.label}</span>`
|
|
84
86
|
))
|
|
85
87
|
}
|
|
86
88
|
</div>
|
|
@@ -126,7 +128,7 @@ export function expandedEndpointBodyTemplate(path, tagName = '', tagDescription
|
|
|
126
128
|
.request_body = "${path.requestBody}"
|
|
127
129
|
.api_keys = "${nonEmptyApiKeys}"
|
|
128
130
|
.servers = "${path.servers}"
|
|
129
|
-
server-url = "${path.servers?.[0]?.url || this.selectedServer
|
|
131
|
+
server-url = "${path.servers?.[0]?.url || this.selectedServer?.computedUrl}"
|
|
130
132
|
fill-request-fields-with-example = "${this.fillRequestFieldsWithExample}"
|
|
131
133
|
allow-try = "${this.allowTry}"
|
|
132
134
|
show-curl-before-try = "${this.showCurlBeforeTry}"
|
|
@@ -5,7 +5,7 @@ import { marked } from 'marked';
|
|
|
5
5
|
// Templates
|
|
6
6
|
import overviewTemplate from '~/templates/overview-template';
|
|
7
7
|
import headerTemplate from '~/templates/header-template';
|
|
8
|
-
import { schemaInObjectNotation, generateExample } from '~/utils/schema-utils';
|
|
8
|
+
import { schemaInObjectNotation, generateExample, standardizeExample } from '~/utils/schema-utils';
|
|
9
9
|
import '~/components/json-tree';
|
|
10
10
|
import '~/components/schema-tree';
|
|
11
11
|
import SetTheme from '~/utils/theme';
|
|
@@ -49,7 +49,7 @@ function jsonSchemaBodyTemplate() {
|
|
|
49
49
|
${this.showInfo === 'true' ? overviewTemplate.call(this) : ''}
|
|
50
50
|
<div style="font-size:var(--font-size-regular);">
|
|
51
51
|
${this.resolvedSpec.schemaAndExamples.map((jSchemaBody) => {
|
|
52
|
-
const examplesObj = generateExample(jSchemaBody.schema, 'json', jSchemaBody.examples, jSchemaBody.example, true, false, 'json', true);
|
|
52
|
+
const examplesObj = generateExample(jSchemaBody.schema, 'json', standardizeExample(jSchemaBody.examples), standardizeExample(jSchemaBody.example), true, false, 'json', true);
|
|
53
53
|
jSchemaBody.selectedExample = examplesObj[0]?.exampleId;
|
|
54
54
|
return html`
|
|
55
55
|
<section id='${jSchemaBody.elementId}' class='json-schema-and-example regular-font' style="display:flex; flex-direction: column; border:1px solid var(--border-color); margin-bottom:32px; border-top: 5px solid var(--border-color)">
|
|
@@ -99,7 +99,7 @@ function jsonSchemaBodyTemplate() {
|
|
|
99
99
|
|
|
100
100
|
// Json Schema Root Template
|
|
101
101
|
export default function jsonSchemaViewerTemplate(isMini = false) {
|
|
102
|
-
// export default function jsonSchemaViewerTemplate(isMini = false,
|
|
102
|
+
// export default function jsonSchemaViewerTemplate(isMini = false, pathsExpanded = false) {
|
|
103
103
|
if (!this.resolvedSpec) {
|
|
104
104
|
return '';
|
|
105
105
|
}
|
|
@@ -13,7 +13,7 @@ import advancedSearchTemplate from '~/templates/advance-search-template';
|
|
|
13
13
|
import SetTheme from '~/utils/theme';
|
|
14
14
|
import { isValidHexColor } from '~/utils/color-utils';
|
|
15
15
|
|
|
16
|
-
export default function mainBodyTemplate(isMini = false,
|
|
16
|
+
export default function mainBodyTemplate(isMini = false, pathsExpanded = false) {
|
|
17
17
|
if (!this.resolvedSpec) {
|
|
18
18
|
return '';
|
|
19
19
|
}
|
|
@@ -104,7 +104,7 @@ export default function mainBodyTemplate(isMini = false, showExpandCollapse = tr
|
|
|
104
104
|
</div>
|
|
105
105
|
${this.renderStyle === 'read'
|
|
106
106
|
? expandedEndpointTemplate.call(this)
|
|
107
|
-
: endpointTemplate.call(this,
|
|
107
|
+
: endpointTemplate.call(this, isMini, pathsExpanded)
|
|
108
108
|
}
|
|
109
109
|
`
|
|
110
110
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { html } from 'lit';
|
|
2
2
|
import { marked } from 'marked';
|
|
3
|
-
import {
|
|
3
|
+
import { getMatchedPaths } from '~/utils/common-utils';
|
|
4
4
|
|
|
5
5
|
export function expandCollapseNavBarTag(navLinkEl, action = 'toggle') {
|
|
6
6
|
const tagAndPathEl = navLinkEl?.closest('.nav-bar-tag-and-paths');
|
|
@@ -82,7 +82,7 @@ export default function navbarTemplate() {
|
|
|
82
82
|
>
|
|
83
83
|
<div style='margin: 6px 5px 0 -24px; font-size:var(--font-size-regular); cursor:pointer;'>↩</div>
|
|
84
84
|
</div>
|
|
85
|
-
${this.
|
|
85
|
+
${this.searchVal
|
|
86
86
|
? html`
|
|
87
87
|
<button @click = '${this.onClearSearch}' class='m-btn thin-border' style='margin-left:5px; color:var(--nav-text-color); width:75px; padding:6px 8px;' part='btn btn-outline btn-clear-filter'>
|
|
88
88
|
CLEAR
|
|
@@ -91,7 +91,7 @@ export default function navbarTemplate() {
|
|
|
91
91
|
}
|
|
92
92
|
`
|
|
93
93
|
}
|
|
94
|
-
${this.allowAdvancedSearch === 'false' || this.
|
|
94
|
+
${this.allowAdvancedSearch === 'false' || this.searchVal
|
|
95
95
|
? ''
|
|
96
96
|
: html`
|
|
97
97
|
<button class='m-btn primary' part='btn btn-fill btn-search' style='margin-left:5px; padding:6px 8px; width:75px' @click='${this.onShowSearchModalClicked}'>
|
|
@@ -166,7 +166,7 @@ export default function navbarTemplate() {
|
|
|
166
166
|
|
|
167
167
|
<!-- TAGS AND PATHS-->
|
|
168
168
|
${this.resolvedSpec.tags
|
|
169
|
-
.filter((tag) => tag.paths.filter((path) =>
|
|
169
|
+
.filter((tag) => tag.paths.filter((path) => getMatchedPaths(this.searchVal, path, tag.name)).length)
|
|
170
170
|
.map((tag) => html`
|
|
171
171
|
<div class='nav-bar-tag-and-paths ${(this.renderStyle === 'read' ? 'expanded' : (tag.expanded ? 'expanded' : 'collapsed'))}' >
|
|
172
172
|
${tag.name === 'General ⦂'
|
|
@@ -208,8 +208,8 @@ export default function navbarTemplate() {
|
|
|
208
208
|
<div class='nav-bar-paths-under-tag' style='max-height:${(tag.expanded || this.renderStyle === 'read') ? ((tag.paths?.length || 1) * 50) : 0}px;'>
|
|
209
209
|
<!-- Paths in each tag (endpoints) -->
|
|
210
210
|
${tag.paths.filter((v) => {
|
|
211
|
-
if (this.
|
|
212
|
-
return
|
|
211
|
+
if (this.searchVal) {
|
|
212
|
+
return getMatchedPaths(this.searchVal, v, tag.name);
|
|
213
213
|
}
|
|
214
214
|
return true;
|
|
215
215
|
}).map((p) => html`
|
|
@@ -134,7 +134,7 @@ async function fetchAccessToken(tokenUrl, clientId, clientSecret, redirectUrl, g
|
|
|
134
134
|
}
|
|
135
135
|
return false;
|
|
136
136
|
}
|
|
137
|
-
} catch
|
|
137
|
+
} catch {
|
|
138
138
|
if (respDisplayEl) {
|
|
139
139
|
respDisplayEl.innerHTML = '<span style="color:var(--red)">Failed to get access token</span>';
|
|
140
140
|
}
|
|
@@ -261,7 +261,7 @@ function oAuthFlowTemplate(flowName, clientId, clientSecret, securitySchemeId, a
|
|
|
261
261
|
const pkceOnly = authFlow['x-pkce-only'] || false;
|
|
262
262
|
const isUrlAbsolute = (url) => (url.indexOf('://') > 0 || url.indexOf('//') === 0);
|
|
263
263
|
// Calculcate base URL
|
|
264
|
-
const url = new URL(this.selectedServer
|
|
264
|
+
const url = new URL(this.selectedServer?.computedUrl);
|
|
265
265
|
const baseUrl = url.origin;
|
|
266
266
|
|
|
267
267
|
if (refreshUrl && !isUrlAbsolute(refreshUrl)) {
|
|
@@ -322,8 +322,8 @@ function oAuthFlowTemplate(flowName, clientId, clientSecret, securitySchemeId, a
|
|
|
322
322
|
${flowName === 'password'
|
|
323
323
|
? html`
|
|
324
324
|
<div style="margin:5px 0">
|
|
325
|
-
<input type="text" value = "" placeholder="username" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} api-key-user" part="textbox textbox-username">
|
|
326
|
-
<input type="password" value = "" placeholder="password" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} api-key-password" style = "margin:0 5px;" part="textbox textbox-password">
|
|
325
|
+
<input type="text" value = "" placeholder="username" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} api-key-user" part="textbox textbox-username" id="input-${securitySchemeId}-${flowName}-api-key-user">
|
|
326
|
+
<input type="password" value = "" placeholder="password" spellcheck="false" class="oauth2 ${flowName} ${securitySchemeId} api-key-password" style = "margin:0 5px;" part="textbox textbox-password" id="input-${securitySchemeId}-${flowName}-api-key-password">
|
|
327
327
|
</div>`
|
|
328
328
|
: ''
|
|
329
329
|
}
|
|
@@ -343,6 +343,7 @@ function oAuthFlowTemplate(flowName, clientId, clientSecret, securitySchemeId, a
|
|
|
343
343
|
${flowName === 'authorizationCode' || flowName === 'clientCredentials' || flowName === 'password'
|
|
344
344
|
? html`
|
|
345
345
|
<input
|
|
346
|
+
id="${securitySchemeId}-${flowName}-oauth-client-secret"
|
|
346
347
|
type="password" part="textbox textbox-auth-client-secret"
|
|
347
348
|
value = "${clientSecret || ''}" placeholder="client-secret" spellcheck="false"
|
|
348
349
|
class="oauth2 ${flowName} ${securitySchemeId}
|
|
@@ -439,7 +440,7 @@ export default function securitySchemeTemplate() {
|
|
|
439
440
|
<div style="max-height:28px;">
|
|
440
441
|
${v.in !== 'cookie'
|
|
441
442
|
? html`
|
|
442
|
-
<input type = "text" value = "${v.value}" class="${v.type} ${v.securitySchemeId} api-key-input" placeholder = "api-token" spellcheck = "false">
|
|
443
|
+
<input type = "text" value = "${v.value}" class="${v.type} ${v.securitySchemeId} api-key-input" placeholder = "api-token" spellcheck = "false" id = "${v.type}-${v.securitySchemeId}-api-key-input">
|
|
443
444
|
<button class="m-btn thin-border" style = "margin-left:5px;"
|
|
444
445
|
part = "btn btn-outline"
|
|
445
446
|
@click="${(e) => { onApiKeyChange.call(this, v.securitySchemeId, e); }}">
|
|
@@ -456,8 +457,8 @@ export default function securitySchemeTemplate() {
|
|
|
456
457
|
Send <code>Authorization</code> in <code>header</code> containing the word <code>Basic</code> followed by a space and a base64 encoded string of <code>username:password</code>.
|
|
457
458
|
</div>
|
|
458
459
|
<div>
|
|
459
|
-
<input type="text" value = "${v.user}" placeholder="username" spellcheck="false" class="${v.type} ${v.securitySchemeId} api-key-user" style="width:100px">
|
|
460
|
-
<input type="password" value = "${v.password}" placeholder="password" spellcheck="false" class="${v.type} ${v.securitySchemeId} api-key-password" style = "width:100px; margin:0 5px;">
|
|
460
|
+
<input type="text" value = "${v.user}" placeholder="username" spellcheck="false" class="${v.type} ${v.securitySchemeId} api-key-user" style="width:100px" id = "input-${v.type}-${v.securitySchemeId}-api-key-user">
|
|
461
|
+
<input type="password" value = "${v.password}" placeholder="password" spellcheck="false" class="${v.type} ${v.securitySchemeId} api-key-password" style = "width:100px; margin:0 5px;" id = "input-${v.type}-${v.securitySchemeId}-api-key-password">
|
|
461
462
|
<button class="m-btn thin-border"
|
|
462
463
|
@click="${(e) => { onApiKeyChange.call(this, v.securitySchemeId, e); }}"
|
|
463
464
|
part = "btn btn-outline"
|
|
@@ -600,6 +601,7 @@ export function pathSecurityTemplate(pathSecurity) {
|
|
|
600
601
|
`)
|
|
601
602
|
}
|
|
602
603
|
</div>
|
|
604
|
+
</div>
|
|
603
605
|
`;
|
|
604
606
|
}
|
|
605
607
|
return '';
|
|
@@ -49,17 +49,13 @@ export async function wait(ms) {
|
|
|
49
49
|
});
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export function
|
|
52
|
+
export function getMatchedComponents(searchVal, component) {
|
|
53
53
|
return component.name.toLowerCase().includes(searchVal.toLowerCase());
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
export function
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return stringToSearch.includes(searchVal.toLowerCase());
|
|
60
|
-
}
|
|
61
|
-
const regex = new RegExp(searchVal, 'i');
|
|
62
|
-
return regex.test(`${path.method} ${path.path}`);
|
|
56
|
+
export function getMatchedPaths(searchVal, path, tagName = '') {
|
|
57
|
+
const stringToSearch = `${path.method} ${path.path} ${path.summary || ''} ${path.description || ''} ${path.operationId || ''} ${tagName}`.toLowerCase();
|
|
58
|
+
return stringToSearch.includes(searchVal.toLowerCase());
|
|
63
59
|
}
|
|
64
60
|
|
|
65
61
|
export function schemaKeys(schemaProps, result = new Set()) {
|
|
@@ -90,7 +86,7 @@ export function advancedSearch(searchVal, allSpecTags, searchOptions = []) {
|
|
|
90
86
|
stringToSearch = path.path;
|
|
91
87
|
}
|
|
92
88
|
if (searchOptions.includes('search-api-descr')) {
|
|
93
|
-
stringToSearch = `${stringToSearch} ${path.summary || path.description || ''}`;
|
|
89
|
+
stringToSearch = `${stringToSearch} ${(path.summary || '') + (path.description || '')}`;
|
|
94
90
|
}
|
|
95
91
|
if (searchOptions.includes('search-api-params')) {
|
|
96
92
|
stringToSearch = `${stringToSearch} ${path.parameters?.map((v) => v.name).join(' ') || ''}`;
|
|
@@ -120,18 +120,67 @@ export function getTypeInfo(schema) {
|
|
|
120
120
|
return info;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
123
|
+
/**
|
|
124
|
+
*
|
|
125
|
+
* @param {*} ex if the value
|
|
126
|
+
* - Is an Object with 'value' property like
|
|
127
|
+
* { 'value': 'example_val1', 'description': 'some description' }
|
|
128
|
+
* Returns >>>
|
|
129
|
+
* {
|
|
130
|
+
* 'Example': { 'value' : 'example_val1', 'description': 'some description' },
|
|
131
|
+
* }
|
|
132
|
+
* - Is an object where each key represents a valid example object (i,e has a value property)
|
|
133
|
+
* {
|
|
134
|
+
* 'example1': { 'value' : 'example_val1', 'description': 'some description' },
|
|
135
|
+
* 'example2': { 'value' : 'example_val2', 'description': 'some other description' },
|
|
136
|
+
* 'invalid': { 'description': 'invalid example object without any value property' }
|
|
137
|
+
* }
|
|
138
|
+
* Returns >>>
|
|
139
|
+
* {
|
|
140
|
+
* 'example1': { 'value' : 'example_val1', 'description': 'some description' },
|
|
141
|
+
* 'example2': { 'value' : 'example_val2', 'description': 'some other description' }
|
|
142
|
+
* }
|
|
143
|
+
* if none of the keys represents an object with 'value' property then return undefined
|
|
144
|
+
* - Is an array of premitive values
|
|
145
|
+
* ['example_val1', 'example_val2']
|
|
146
|
+
* Returns >>>
|
|
147
|
+
* {
|
|
148
|
+
* 'Example1': {value:'value1'}
|
|
149
|
+
* 'Example2': {value:'value2'}
|
|
150
|
+
* }
|
|
151
|
+
* - Is a premitive value
|
|
152
|
+
* 'example_val1'
|
|
153
|
+
* Returns >>>
|
|
154
|
+
* {
|
|
155
|
+
* 'Example': { 'value': 'example_val1' }
|
|
156
|
+
* }
|
|
157
|
+
* - Is undefined
|
|
158
|
+
* returns undefined
|
|
159
|
+
* @returns
|
|
160
|
+
*/
|
|
161
|
+
|
|
162
|
+
export function standardizeExample(ex) {
|
|
163
|
+
if (typeof ex === 'object' && !Array.isArray(ex)) {
|
|
164
|
+
if (ex.value !== undefined) {
|
|
165
|
+
// Case 1: Single object with 'value' property
|
|
166
|
+
return { Example: { ...ex } };
|
|
167
|
+
}
|
|
168
|
+
// Case 2: Object where each key is an object with a 'value' property
|
|
169
|
+
const filteredEntries = Object.entries(ex).filter(([_, obj]) => obj.value !== undefined); // eslint-disable-line
|
|
170
|
+
// If no valid entries found, return JSON.stringify of the input
|
|
171
|
+
if (filteredEntries.length === 0) {
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
return Object.fromEntries(filteredEntries);
|
|
175
|
+
} if (Array.isArray(ex)) {
|
|
176
|
+
// Case 3: Array of primitive values
|
|
177
|
+
return ex.reduce((acc, value, index) => {
|
|
178
|
+
acc[`Example${index + 1}`] = { value };
|
|
179
|
+
return acc;
|
|
180
|
+
}, {});
|
|
133
181
|
}
|
|
134
|
-
|
|
182
|
+
// Case 4: Single primitive value
|
|
183
|
+
return ex ? { Example: { value: ex } } : undefined;
|
|
135
184
|
}
|
|
136
185
|
|
|
137
186
|
/**
|
|
@@ -268,7 +317,7 @@ export function getSampleValueByType(schemaObj) {
|
|
|
268
317
|
if (schemaObj.pattern) {
|
|
269
318
|
try {
|
|
270
319
|
return new RandExp(schemaObj.pattern).gen();
|
|
271
|
-
} catch
|
|
320
|
+
} catch {
|
|
272
321
|
return schemaObj.pattern;
|
|
273
322
|
}
|
|
274
323
|
}
|
|
@@ -297,7 +346,7 @@ export function getSampleValueByType(schemaObj) {
|
|
|
297
346
|
case 'ipv6':
|
|
298
347
|
return '2001:0db8:5b96:0000:0000:426f:8e17:642a';
|
|
299
348
|
case 'uuid':
|
|
300
|
-
return [u.
|
|
349
|
+
return [u.substring(0, 8), u.substring(8, 12), `4000-8${u.substring(13, 16)}`, u.substring(16, 28)].join('-');
|
|
301
350
|
case 'byte':
|
|
302
351
|
return 'ZXhhbXBsZQ=='; // 'example' base64 encoded. See https://spec.openapis.org/oas/v3.0.0#data-types
|
|
303
352
|
default:
|
|
@@ -857,7 +906,7 @@ export function schemaInObjectNotation(schema, obj, level = 0, suffix = '') {
|
|
|
857
906
|
}
|
|
858
907
|
|
|
859
908
|
/* Create Example object */
|
|
860
|
-
export function generateExample(schema, mimeType, examples =
|
|
909
|
+
export function generateExample(schema, mimeType, examples = {}, example = {}, includeReadOnly = true, includeWriteOnly = true, outputType = 'json', includeGeneratedExample = false) {
|
|
861
910
|
const finalExamples = [];
|
|
862
911
|
// First check if examples is provided
|
|
863
912
|
if (examples) {
|
|
@@ -876,7 +925,7 @@ export function generateExample(schema, mimeType, examples = '', example = '', i
|
|
|
876
925
|
const fixedJsonString = examples[eg].value;
|
|
877
926
|
egContent = JSON.parse(fixedJsonString);
|
|
878
927
|
egFormat = 'json';
|
|
879
|
-
} catch
|
|
928
|
+
} catch {
|
|
880
929
|
egFormat = 'text';
|
|
881
930
|
egContent = examples[eg].value;
|
|
882
931
|
}
|
|
@@ -910,7 +959,7 @@ export function generateExample(schema, mimeType, examples = '', example = '', i
|
|
|
910
959
|
try {
|
|
911
960
|
egContent = JSON.parse(example);
|
|
912
961
|
egFormat = 'json';
|
|
913
|
-
} catch
|
|
962
|
+
} catch {
|
|
914
963
|
egFormat = 'text';
|
|
915
964
|
egContent = example;
|
|
916
965
|
}
|
package/src/utils/spec-parser.js
CHANGED
|
@@ -3,8 +3,22 @@ import OpenApiParser from '@apitools/openapi-parser';
|
|
|
3
3
|
import { marked } from 'marked';
|
|
4
4
|
import { invalidCharsRegEx, rapidocApiKey, sleep } from '~/utils/common-utils';
|
|
5
5
|
|
|
6
|
-
export default async function ProcessSpec(
|
|
6
|
+
export default async function ProcessSpec(
|
|
7
|
+
specUrl,
|
|
8
|
+
generateMissingTags = false,
|
|
9
|
+
sortTags = false,
|
|
10
|
+
sortSchemas = false,
|
|
11
|
+
sortEndpointsBy = '',
|
|
12
|
+
attrApiKey = '',
|
|
13
|
+
attrApiKeyLocation = '',
|
|
14
|
+
attrApiKeyValue = '',
|
|
15
|
+
serverUrl = '',
|
|
16
|
+
matchPaths = '',
|
|
17
|
+
matchType = '',
|
|
18
|
+
removeEndpointsWithBadgeLabelAs = '',
|
|
19
|
+
) {
|
|
7
20
|
let jsonParsedSpec;
|
|
21
|
+
|
|
8
22
|
try {
|
|
9
23
|
this.requestUpdate(); // important to show the initial loader
|
|
10
24
|
let specMeta;
|
|
@@ -15,7 +29,7 @@ export default async function ProcessSpec(specUrl, generateMissingTags = false,
|
|
|
15
29
|
}
|
|
16
30
|
await sleep(0); // important to show the initial loader (allows for rendering updates)
|
|
17
31
|
|
|
18
|
-
// If
|
|
32
|
+
// If JSON Schema Viewer
|
|
19
33
|
if (specMeta.resolvedSpec?.jsonSchemaViewer && specMeta.resolvedSpec?.schemaAndExamples) {
|
|
20
34
|
this.dispatchEvent(new CustomEvent('before-render', { detail: { spec: specMeta.resolvedSpec } }));
|
|
21
35
|
const schemaAndExamples = Object.entries(specMeta.resolvedSpec.schemaAndExamples).map((v) => ({ show: true, expanded: true, selectedExample: null, name: v[0], elementId: v[0].replace(invalidCharsRegEx, '-'), ...v[1] }));
|
|
@@ -27,8 +41,10 @@ export default async function ProcessSpec(specUrl, generateMissingTags = false,
|
|
|
27
41
|
};
|
|
28
42
|
return parsedSpec;
|
|
29
43
|
}
|
|
44
|
+
|
|
45
|
+
// If RapiDoc or RapiDocMini
|
|
30
46
|
if (specMeta.spec && (specMeta.spec.components || specMeta.spec.info || specMeta.spec.servers || specMeta.spec.tags || specMeta.spec.paths)) {
|
|
31
|
-
jsonParsedSpec = specMeta.spec;
|
|
47
|
+
jsonParsedSpec = filterPaths(specMeta.spec, matchPaths, matchType, removeEndpointsWithBadgeLabelAs);
|
|
32
48
|
this.dispatchEvent(new CustomEvent('before-render', { detail: { spec: jsonParsedSpec } }));
|
|
33
49
|
} else {
|
|
34
50
|
console.info('RapiDoc: %c There was an issue while parsing the spec %o ', 'color:orangered', specMeta); // eslint-disable-line no-console
|
|
@@ -112,7 +128,7 @@ export default async function ProcessSpec(specUrl, generateMissingTags = false,
|
|
|
112
128
|
|
|
113
129
|
// Servers
|
|
114
130
|
let servers = [];
|
|
115
|
-
if (jsonParsedSpec.servers && Array.isArray(jsonParsedSpec.servers)) {
|
|
131
|
+
if (jsonParsedSpec.servers && Array.isArray(jsonParsedSpec.servers) && jsonParsedSpec.servers.length > 0) {
|
|
116
132
|
jsonParsedSpec.servers.forEach((v) => {
|
|
117
133
|
let computedUrl = v.url.trim();
|
|
118
134
|
if (!(computedUrl.startsWith('http') || computedUrl.startsWith('//') || computedUrl.startsWith('{'))) {
|
|
@@ -141,7 +157,7 @@ export default async function ProcessSpec(specUrl, generateMissingTags = false,
|
|
|
141
157
|
} else {
|
|
142
158
|
jsonParsedSpec.servers = [{ url: 'http://localhost', computedUrl: 'http://localhost' }];
|
|
143
159
|
}
|
|
144
|
-
servers = jsonParsedSpec.servers;
|
|
160
|
+
servers = jsonParsedSpec.servers; // eslint-disable-line prefer-destructuring
|
|
145
161
|
const parsedSpec = {
|
|
146
162
|
specLoadError: false,
|
|
147
163
|
isSpecLoading: false,
|
|
@@ -156,6 +172,60 @@ export default async function ProcessSpec(specUrl, generateMissingTags = false,
|
|
|
156
172
|
return parsedSpec;
|
|
157
173
|
}
|
|
158
174
|
|
|
175
|
+
function filterPaths(openApiObject, matchPaths = '', matchType = '', removeEndpointsWithBadgeLabelAs = '') {
|
|
176
|
+
const filteredPaths = {};
|
|
177
|
+
|
|
178
|
+
// Convert the removePathsWithBadgeLabeledAs to an array if provided
|
|
179
|
+
const labelsToRemove = removeEndpointsWithBadgeLabelAs.split(',').map((label) => label.trim().toLowerCase()).filter(Boolean);
|
|
180
|
+
|
|
181
|
+
// Helper function to check if a path should be included based on matchPaths
|
|
182
|
+
function pathMatches(pathsKey, httpMethod) {
|
|
183
|
+
if (!matchPaths) {
|
|
184
|
+
return true; // If no matchPaths provided, include everything
|
|
185
|
+
}
|
|
186
|
+
const fullPath = `${httpMethod} ${pathsKey}`.toLowerCase(); // Construct "method path" string
|
|
187
|
+
if (matchType === 'regex') {
|
|
188
|
+
const regex = new RegExp(matchPaths, 'i');
|
|
189
|
+
return regex.test(matchPaths.toLowerCase());
|
|
190
|
+
}
|
|
191
|
+
return fullPath.includes(matchPaths.toLowerCase());
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Helper function to check if the badges contain any label that needs to be removed
|
|
195
|
+
function containsLabelToRemove(badges) {
|
|
196
|
+
return badges.some((badge) => labelsToRemove.includes(badge?.label.toLowerCase()));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Loop through the paths in the openApiObject
|
|
200
|
+
Object.entries(openApiObject.paths).forEach(([pathsKey, methods]) => {
|
|
201
|
+
const filteredMethods = {};
|
|
202
|
+
|
|
203
|
+
Object.entries(methods).forEach(([httpMethod, methodDetails]) => {
|
|
204
|
+
const badges = methodDetails['x-badges'];
|
|
205
|
+
|
|
206
|
+
// Filter by matchPaths
|
|
207
|
+
if (pathMatches(pathsKey, httpMethod)) {
|
|
208
|
+
if (badges && Array.isArray(badges)) {
|
|
209
|
+
// Filter out based on removePathsWithBadgeLabeledAs
|
|
210
|
+
if (!containsLabelToRemove(badges)) {
|
|
211
|
+
filteredMethods[httpMethod] = methodDetails;
|
|
212
|
+
}
|
|
213
|
+
} else {
|
|
214
|
+
// No badges present, include the method
|
|
215
|
+
filteredMethods[httpMethod] = methodDetails;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
if (Object.keys(filteredMethods).length > 0) {
|
|
221
|
+
filteredPaths[pathsKey] = filteredMethods;
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
openApiObject.paths = filteredPaths;
|
|
226
|
+
return openApiObject;
|
|
227
|
+
}
|
|
228
|
+
|
|
159
229
|
function getHeadersFromMarkdown(markdownContent) {
|
|
160
230
|
const tokens = marked.lexer(markdownContent);
|
|
161
231
|
const headers = tokens.filter((v) => v.type === 'heading' && v.depth <= 2);
|
|
@@ -245,7 +315,7 @@ function getComponents(openApiSpec, sortSchemas = false) {
|
|
|
245
315
|
|
|
246
316
|
function groupByTags(openApiSpec, sortEndpointsBy, generateMissingTags = false, sortTags = false) {
|
|
247
317
|
const supportedMethods = ['get', 'put', 'post', 'delete', 'patch', 'head', 'options']; // this is also used for ordering endpoints by methods
|
|
248
|
-
const tags = openApiSpec.tags && Array.isArray(openApiSpec.tags)
|
|
318
|
+
const tags = openApiSpec.tags && Array.isArray(openApiSpec.tags) && openApiSpec.tags.length > 0
|
|
249
319
|
? openApiSpec.tags.map((v) => ({
|
|
250
320
|
show: true,
|
|
251
321
|
elementId: `tag--${v.name.replace(invalidCharsRegEx, '-')}`,
|
|
@@ -286,7 +356,7 @@ function groupByTags(openApiSpec, sortEndpointsBy, generateMissingTags = false,
|
|
|
286
356
|
pathTags.push(pathOrHookNameKey);
|
|
287
357
|
} else {
|
|
288
358
|
// firstWordEndIndex -= 1;
|
|
289
|
-
pathTags.push(pathOrHookNameKey.
|
|
359
|
+
pathTags.push(pathOrHookNameKey.substring(0, firstWordEndIndex));
|
|
290
360
|
}
|
|
291
361
|
} else {
|
|
292
362
|
pathTags.push('General ⦂');
|
package/src/utils/theme.js
CHANGED
|
@@ -21,8 +21,8 @@ export default function setTheme(baseTheme, theme = {}) {
|
|
|
21
21
|
const fg3 = theme.fg3 ? theme.fg3 : ColorUtils.color.brightness(fg1, -20); // or #aaa
|
|
22
22
|
const lightFg = theme.fg3 ? theme.fg3 : ColorUtils.color.brightness(fg1, -65); // or #777
|
|
23
23
|
const inlineCodeFg = theme.inlineCodeFg ? theme.inlineCodeFg : '#aaa';
|
|
24
|
-
const selectionBg =
|
|
25
|
-
const selectionFg =
|
|
24
|
+
const selectionBg = fg2;
|
|
25
|
+
const selectionFg = bg2;
|
|
26
26
|
|
|
27
27
|
const headerColor = theme.headerColor ? theme.headerColor : ColorUtils.color.brightness(bg1, 10);
|
|
28
28
|
|
|
@@ -107,10 +107,8 @@ export default function setTheme(baseTheme, theme = {}) {
|
|
|
107
107
|
const fg3 = theme.fg3 ? theme.fg3 : ColorUtils.color.brightness(fg1, 30); // or #666
|
|
108
108
|
const lightFg = theme.fg3 ? theme.fg3 : ColorUtils.color.brightness(fg1, 70); // or #999
|
|
109
109
|
const inlineCodeFg = theme.inlineCodeFg ? theme.inlineCodeFg : 'brown';
|
|
110
|
-
|
|
111
|
-
const
|
|
112
|
-
const selectionFg = '#eee';
|
|
113
|
-
|
|
110
|
+
const selectionBg = fg2;
|
|
111
|
+
const selectionFg = bg2;
|
|
114
112
|
const headerColor = theme.headerColor ? theme.headerColor : ColorUtils.color.brightness(bg1, -180);
|
|
115
113
|
|
|
116
114
|
/*
|