rapidoc 9.1.0 → 9.1.4
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 +17 -1
- package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
- package/dist/rapidoc-min.js.gz +0 -0
- package/dist/report.html +6 -5
- package/docker/Dockerfile +5 -5
- package/docs/api.html +48 -40
- package/docs/examples/auth-test1.html +113 -0
- package/docs/examples/auth.html +37 -34
- package/docs/examples/badges.html +1 -1
- package/docs/examples/dynamic-query-params.html +1 -0
- package/docs/examples/mongo.html +33 -0
- package/docs/examples/readwrite.html +40 -0
- package/docs/examples/slots.html +7 -0
- package/docs/examples.html +3 -2
- package/docs/index.html +2 -2
- package/docs/list.html +15 -3
- package/docs/quickstart.html +1 -1
- package/docs/rapidoc-min.js +2 -5
- package/docs/rapidoc-mini.html +20 -20
- package/docs/specs/auth-test1.yaml +35 -0
- package/docs/specs/auth.yaml +2 -2
- package/docs/specs/code-highlight.yaml +1 -1
- package/docs/specs/data-types.yaml +0 -1
- package/docs/specs/dynamic-query-params.yaml +41 -0
- package/docs/specs/examples.yaml +11 -0
- package/docs/specs/mongo.yaml +78 -0
- package/docs/specs/multipart-formdata.yaml +3 -0
- package/docs/specs/petstore_extended.yaml +1 -1
- package/docs/specs/readwrite.yaml +90 -0
- package/docs/specs/server.yaml +4 -4
- package/docs/specs/temp.json +24 -105
- package/docs/specs/temp.yaml +20 -282
- package/docs/welcome.html +3 -3
- package/index.html +11 -6
- package/package.json +22 -21
- package/src/components/api-request.js +105 -63
- package/src/components/api-response.js +10 -10
- package/src/components/json-tree.js +2 -1
- package/src/components/schema-table.js +51 -14
- package/src/components/schema-tree.js +59 -18
- package/src/components/tag-input.js +8 -1
- package/src/index.js +2 -1
- package/src/json-schema-viewer.js +341 -0
- package/src/rapidoc-mini.js +5 -1
- package/src/rapidoc.js +11 -7
- package/src/styles/font-styles.js +3 -2
- package/src/styles/nav-styles.js +2 -2
- package/src/templates/components-template.js +9 -10
- package/src/templates/endpoint-template.js +1 -1
- package/src/templates/expanded-endpoint-template.js +1 -1
- package/src/templates/focused-endpoint-template.js +1 -1
- package/src/templates/header-template.js +1 -1
- package/src/templates/json-schema-viewer-template.js +184 -0
- package/src/templates/main-body-template.js +4 -1
- package/src/templates/navbar-template.js +3 -3
- package/src/templates/overview-template.js +6 -3
- package/src/templates/security-scheme-template.js +78 -38
- package/src/templates/server-template.js +1 -1
- package/src/utils/common-utils.js +2 -1
- package/src/utils/schema-utils.js +24 -19
- package/src/utils/spec-parser.js +24 -3
- package/webpack.config.js +1 -12
- package/dist/rapidoc-min.js.map +0 -1
- package/dist/rapidoc-min.js.map.gz +0 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LitElement, html, css } from 'lit-element';
|
|
2
|
-
import marked from 'marked';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
3
|
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
|
|
4
4
|
import FontStyles from '~/styles/font-styles';
|
|
5
5
|
import SchemaStyles from '~/styles/schema-styles';
|
|
@@ -123,11 +123,31 @@ export default class SchemaTable extends LitElement {
|
|
|
123
123
|
`;
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
generateTree(data, dataType = 'object', arrayType = '', key = '', description = '', schemaLevel = 0, indentLevel = 0) {
|
|
126
|
+
generateTree(data, dataType = 'object', arrayType = '', key = '', description = '', schemaLevel = 0, indentLevel = 0, readOrWrite = '') {
|
|
127
|
+
if (this.schemaHideReadOnly === 'true') {
|
|
128
|
+
if (dataType === 'array') {
|
|
129
|
+
if (readOrWrite === 'readonly') {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (data['::readwrite'] === 'readonly') {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
if (this.schemaHideWriteOnly === 'true') {
|
|
138
|
+
if (dataType === 'array') {
|
|
139
|
+
if (readOrWrite === 'writeonly') {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (data['::readwrite'] === 'writeonly') {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
127
148
|
const newSchemaLevel = data['::type']?.startsWith('xxx-of') ? schemaLevel : (schemaLevel + 1);
|
|
128
149
|
const newIndentLevel = dataType === 'xxx-of-option' || data['::type'] === 'xxx-of-option' || key.startsWith('::OPTION') ? indentLevel : (indentLevel + 1);
|
|
129
150
|
const leftPadding = 16 * newIndentLevel; // 2 space indentation at each level
|
|
130
|
-
|
|
131
151
|
if (!data) {
|
|
132
152
|
return html`<div class="null" style="display:inline;">null</div>`;
|
|
133
153
|
}
|
|
@@ -189,7 +209,10 @@ export default class SchemaTable extends LitElement {
|
|
|
189
209
|
}
|
|
190
210
|
${data['::type'] === 'xxx-of' && dataType === 'array' ? html`<span style="color:var(--primary-color)">ARRAY</span>` : ''}
|
|
191
211
|
</div>
|
|
192
|
-
<div class='td key-type'
|
|
212
|
+
<div class='td key-type' title="${data['::readwrite'] === 'readonly' ? 'Read-Only' : data['::readwrite'] === 'writeonly' ? 'Write-Only' : ''}">
|
|
213
|
+
${(data['::type'] || '').includes('xxx-of') ? '' : detailObjType}
|
|
214
|
+
${data['::readwrite'] === 'readonly' ? ' 🆁' : data['::readwrite'] === 'writeonly' ? ' 🆆' : ''}
|
|
215
|
+
</div>
|
|
193
216
|
<div class='td key-descr m-markdown-small' style='line-height:1.7'>${unsafeHTML(marked(description || ''))}</div>
|
|
194
217
|
</div>`
|
|
195
218
|
: html`
|
|
@@ -197,7 +220,9 @@ export default class SchemaTable extends LitElement {
|
|
|
197
220
|
? html`
|
|
198
221
|
<div class='tr'>
|
|
199
222
|
<div class='td key'></div>
|
|
200
|
-
<div class='td key-type'>
|
|
223
|
+
<div class='td key-type'>
|
|
224
|
+
${arrayType && arrayType !== 'object' ? `${dataType} of ${arrayType}` : dataType}
|
|
225
|
+
</div>
|
|
201
226
|
<div class='td key-descr'></div>
|
|
202
227
|
</div>`
|
|
203
228
|
: ''
|
|
@@ -206,10 +231,10 @@ export default class SchemaTable extends LitElement {
|
|
|
206
231
|
}
|
|
207
232
|
<div class='object-body'>
|
|
208
233
|
${Array.isArray(data) && data[0]
|
|
209
|
-
? html`${this.generateTree(data[0], 'xxx-of-option', '', '::ARRAY~OF', '', newSchemaLevel, newIndentLevel)}`
|
|
234
|
+
? html`${this.generateTree(data[0], 'xxx-of-option', '', '::ARRAY~OF', '', newSchemaLevel, newIndentLevel, '')}`
|
|
210
235
|
: html`
|
|
211
236
|
${Object.keys(data).map((dataKey) => html`
|
|
212
|
-
${['::description', '::type', '::props', '::deprecated', '::array-type'].includes(dataKey)
|
|
237
|
+
${['::description', '::type', '::props', '::deprecated', '::array-type', '::readwrite'].includes(dataKey)
|
|
213
238
|
? data[dataKey]['::type'] === 'array' || data[dataKey]['::type'] === 'object'
|
|
214
239
|
? html`${this.generateTree(
|
|
215
240
|
data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey],
|
|
@@ -219,6 +244,7 @@ export default class SchemaTable extends LitElement {
|
|
|
219
244
|
data[dataKey]['::description'],
|
|
220
245
|
newSchemaLevel,
|
|
221
246
|
newIndentLevel,
|
|
247
|
+
data[dataKey]['::readwrite'] ? data[dataKey]['::readwrite'] : '',
|
|
222
248
|
)}`
|
|
223
249
|
: ''
|
|
224
250
|
: html`${this.generateTree(
|
|
@@ -229,6 +255,7 @@ export default class SchemaTable extends LitElement {
|
|
|
229
255
|
data[dataKey]['::description'],
|
|
230
256
|
newSchemaLevel,
|
|
231
257
|
newIndentLevel,
|
|
258
|
+
data[dataKey]['::readwrite'] ? data[dataKey]['::readwrite'] : '',
|
|
232
259
|
)}`
|
|
233
260
|
}
|
|
234
261
|
`)}
|
|
@@ -239,17 +266,29 @@ export default class SchemaTable extends LitElement {
|
|
|
239
266
|
}
|
|
240
267
|
|
|
241
268
|
// For Primitive Data types
|
|
242
|
-
const [type,
|
|
243
|
-
if (
|
|
269
|
+
const [type, readOrWriteOnly, constraint, defaultValue, allowedValues, pattern, schemaDescription, schemaTitle, deprecated] = data.split('~|~');
|
|
270
|
+
if (readOrWriteOnly === '🆁' && this.schemaHideReadOnly === 'true') {
|
|
244
271
|
return;
|
|
245
272
|
}
|
|
246
|
-
if (
|
|
273
|
+
if (readOrWriteOnly === '🆆' && this.schemaHideWriteOnly === 'true') {
|
|
247
274
|
return;
|
|
248
275
|
}
|
|
249
276
|
const dataTypeCss = type.replace(/┃.*/g, '').replace(/[^a-zA-Z0-9+]/g, '').substring(0, 4).toLowerCase();
|
|
277
|
+
let dataTypeHtml = '';
|
|
278
|
+
if (dataType === 'array') {
|
|
279
|
+
dataTypeHtml = html`
|
|
280
|
+
<div class='td key-type ${dataTypeCss}' title="${readOrWrite === 'readonly' ? 'Read-Only' : readOrWriteOnly === 'writeonly' ? 'Write-Only' : ''}">
|
|
281
|
+
[${type}] ${readOrWrite === 'readonly' ? '🆁' : readOrWrite === 'writeonly' ? '🆆' : ''}
|
|
282
|
+
</div>`;
|
|
283
|
+
} else {
|
|
284
|
+
dataTypeHtml = html`
|
|
285
|
+
<div class='td key-type ${dataTypeCss}' title="${readOrWriteOnly === '🆁' ? 'Read-Only' : readOrWriteOnly === '🆆' ? 'Write-Only' : ''}">
|
|
286
|
+
${type} ${readOrWriteOnly}
|
|
287
|
+
</div>`;
|
|
288
|
+
}
|
|
250
289
|
return html`
|
|
251
290
|
<div class = "tr primitive">
|
|
252
|
-
<div class="td key ${deprecated}" style='padding-left:${leftPadding}px'
|
|
291
|
+
<div class="td key ${deprecated}" style='padding-left:${leftPadding}px'>
|
|
253
292
|
${keyLabel?.endsWith('*')
|
|
254
293
|
? html`<span class="key-label">${keyLabel.substring(0, keyLabel.length - 1)}</span><span style='color:var(--red);'>*</span>`
|
|
255
294
|
: key.startsWith('::OPTION')
|
|
@@ -257,9 +296,7 @@ export default class SchemaTable extends LitElement {
|
|
|
257
296
|
: html`${keyLabel ? html`<span class="key-label"> ${keyLabel}</span>` : html`<span class="xxx-of-descr">${schemaTitle}</span>`}`
|
|
258
297
|
}
|
|
259
298
|
</div>
|
|
260
|
-
|
|
261
|
-
${dataType === 'array' ? `[${type}]` : type}
|
|
262
|
-
<span style="font-family: var(--font-mono);">${readorWriteOnly} </span> </div>
|
|
299
|
+
${dataTypeHtml}
|
|
263
300
|
<div class='td key-descr'>
|
|
264
301
|
${dataType === 'array' ? html`<span class="m-markdown-small">${unsafeHTML(marked(description))}</span>` : ''}
|
|
265
302
|
${constraint ? html`<div style='display:inline-block; line-break:anywhere; margin-right:8px;'> <span class='bold-text'>Constraints: </span> ${constraint}</div>` : ''}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { LitElement, html, css } from 'lit-element';
|
|
2
|
-
import marked from 'marked';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
3
|
import { unsafeHTML } from 'lit-html/directives/unsafe-html';
|
|
4
4
|
import FontStyles from '~/styles/font-styles';
|
|
5
5
|
import SchemaStyles from '~/styles/schema-styles';
|
|
@@ -115,7 +115,6 @@ export default class SchemaTree extends LitElement {
|
|
|
115
115
|
this.data['::type'] === 'array' ? this.data['::props'] : this.data,
|
|
116
116
|
this.data['::type'],
|
|
117
117
|
this.data['::array-type'] || '',
|
|
118
|
-
|
|
119
118
|
)}`
|
|
120
119
|
: html`<span class='mono-font' style='color:var(--red)'> Schema not found </span>`
|
|
121
120
|
}
|
|
@@ -123,7 +122,28 @@ export default class SchemaTree extends LitElement {
|
|
|
123
122
|
`;
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
generateTree(data, dataType = 'object', arrayType = '', key = '', description = '', schemaLevel = 0, indentLevel = 0) {
|
|
125
|
+
generateTree(data, dataType = 'object', arrayType = '', key = '', description = '', schemaLevel = 0, indentLevel = 0, readOrWrite = '') {
|
|
126
|
+
if (this.schemaHideReadOnly === 'true') {
|
|
127
|
+
if (dataType === 'array') {
|
|
128
|
+
if (readOrWrite === 'readonly') {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (data['::readwrite'] === 'readonly') {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (this.schemaHideWriteOnly === 'true') {
|
|
137
|
+
if (dataType === 'array') {
|
|
138
|
+
if (readOrWrite === 'writeonly') {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
if (data['::readwrite'] === 'writeonly') {
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
127
147
|
if (!data) {
|
|
128
148
|
return html`<div class="null" style="display:inline;">null</div>`;
|
|
129
149
|
}
|
|
@@ -189,13 +209,13 @@ export default class SchemaTree extends LitElement {
|
|
|
189
209
|
<div class="td key ${data['::deprecated'] ? 'deprecated' : ''}" style='min-width:${minFieldColWidth}px'>
|
|
190
210
|
${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' || key.startsWith('::OPTION')
|
|
191
211
|
? html`<span class='key-label xxx-of-key'>${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>`
|
|
192
|
-
: keyLabel
|
|
193
|
-
?
|
|
194
|
-
:
|
|
195
|
-
? ''
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
: keyLabel === '::props' || keyLabel === '::ARRAY~OF'
|
|
213
|
+
? ''
|
|
214
|
+
: schemaLevel > 0
|
|
215
|
+
? html`<span class="key-label" title="${readOrWrite === 'readonly' ? 'Read-Only' : readOrWrite === 'writeonly' ? 'Write-Only' : ''}">
|
|
216
|
+
${keyLabel.replace(/\*$/, '')}${keyLabel.endsWith('*') ? html`<span style="color:var(--red)">*</span>` : ''}${readOrWrite === 'readonly' ? html` 🆁` : readOrWrite === 'writeonly' ? html` 🆆` : readOrWrite}:
|
|
217
|
+
</span>`
|
|
218
|
+
: ''
|
|
199
219
|
}
|
|
200
220
|
${data['::type'] === 'xxx-of' && dataType === 'array' ? html`<span style="color:var(--primary-color)">ARRAY</span>` : ''}
|
|
201
221
|
${openBracket}
|
|
@@ -204,10 +224,10 @@ export default class SchemaTree extends LitElement {
|
|
|
204
224
|
</div>
|
|
205
225
|
<div class='inside-bracket ${data['::type'] || 'no-type-info'}' style='padding-left:${data['::type'] === 'xxx-of-option' || data['::type'] === 'xxx-of-array' ? 0 : leftPadding}px;'>
|
|
206
226
|
${Array.isArray(data) && data[0]
|
|
207
|
-
? html`${this.generateTree(data[0], 'xxx-of-option', '', '::ARRAY~OF', '', newSchemaLevel, newIndentLevel)}`
|
|
227
|
+
? html`${this.generateTree(data[0], 'xxx-of-option', '', '::ARRAY~OF', '', newSchemaLevel, newIndentLevel, data[0]['::readwrite'])}`
|
|
208
228
|
: html`
|
|
209
229
|
${Object.keys(data).map((dataKey) => html`
|
|
210
|
-
${['::description', '::type', '::props', '::deprecated', '::array-type'].includes(dataKey)
|
|
230
|
+
${['::description', '::type', '::props', '::deprecated', '::array-type', '::readwrite'].includes(dataKey)
|
|
211
231
|
? data[dataKey]['::type'] === 'array' || data[dataKey]['::type'] === 'object'
|
|
212
232
|
? html`${this.generateTree(
|
|
213
233
|
data[dataKey]['::type'] === 'array' ? data[dataKey]['::props'] : data[dataKey],
|
|
@@ -217,6 +237,7 @@ export default class SchemaTree extends LitElement {
|
|
|
217
237
|
data[dataKey]['::description'],
|
|
218
238
|
newSchemaLevel,
|
|
219
239
|
newIndentLevel,
|
|
240
|
+
data[dataKey]['::readwrite'] ? data[dataKey]['::readwrite'] : '',
|
|
220
241
|
)}`
|
|
221
242
|
: ''
|
|
222
243
|
: html`${this.generateTree(
|
|
@@ -227,6 +248,7 @@ export default class SchemaTree extends LitElement {
|
|
|
227
248
|
data[dataKey]['::description'],
|
|
228
249
|
newSchemaLevel,
|
|
229
250
|
newIndentLevel,
|
|
251
|
+
data[dataKey]['::readwrite'] ? data[dataKey]['::readwrite'] : '',
|
|
230
252
|
)}`
|
|
231
253
|
}
|
|
232
254
|
`)}
|
|
@@ -240,15 +262,34 @@ export default class SchemaTree extends LitElement {
|
|
|
240
262
|
`;
|
|
241
263
|
}
|
|
242
264
|
|
|
243
|
-
// For Primitive
|
|
244
|
-
const [type,
|
|
245
|
-
if (
|
|
265
|
+
// For Primitive types and array of Primitives
|
|
266
|
+
const [type, primitiveReadOrWrite, constraint, defaultValue, allowedValues, pattern, schemaDescription, , deprecated] = data.split('~|~');
|
|
267
|
+
if (primitiveReadOrWrite === '🆁' && this.schemaHideReadOnly === 'true') {
|
|
246
268
|
return;
|
|
247
269
|
}
|
|
248
|
-
if (
|
|
270
|
+
if (primitiveReadOrWrite === '🆆' && this.schemaHideWriteOnly === 'true') {
|
|
249
271
|
return;
|
|
250
272
|
}
|
|
251
273
|
const dataTypeCss = type.replace(/┃.*/g, '').replace(/[^a-zA-Z0-9+]/g, '').substring(0, 4).toLowerCase();
|
|
274
|
+
|
|
275
|
+
let finalReadWriteText = '';
|
|
276
|
+
let finalReadWriteTip = '';
|
|
277
|
+
if (dataType === 'array') {
|
|
278
|
+
if (readOrWrite === 'readonly') {
|
|
279
|
+
finalReadWriteText = '🆁';
|
|
280
|
+
finalReadWriteTip = 'Read-Only';
|
|
281
|
+
} else if (readOrWrite === 'writeonly') {
|
|
282
|
+
finalReadWriteText = '🆆';
|
|
283
|
+
finalReadWriteTip = 'Write-Only';
|
|
284
|
+
}
|
|
285
|
+
} else if (primitiveReadOrWrite === '🆁') {
|
|
286
|
+
finalReadWriteText = '🆁';
|
|
287
|
+
finalReadWriteTip = 'Read-Only';
|
|
288
|
+
} else if (primitiveReadOrWrite === '🆆') {
|
|
289
|
+
finalReadWriteText = '🆆';
|
|
290
|
+
finalReadWriteTip = 'Write-Only';
|
|
291
|
+
}
|
|
292
|
+
|
|
252
293
|
return html`
|
|
253
294
|
<div class = "tr primitive">
|
|
254
295
|
<div class="td key ${deprecated}" style='min-width:${minFieldColWidth}px' >
|
|
@@ -258,9 +299,9 @@ export default class SchemaTree extends LitElement {
|
|
|
258
299
|
? html`<span class='key-label xxx-of-key'>${keyLabel}</span><span class="xxx-of-descr">${keyDescr}</span>`
|
|
259
300
|
: html`<span class="key-label">${keyLabel}:</span>`
|
|
260
301
|
}
|
|
261
|
-
<span class="${dataTypeCss}" >
|
|
302
|
+
<span class="${dataTypeCss}" title="${finalReadWriteTip}">
|
|
262
303
|
${dataType === 'array' ? `[${type}]` : `${type}`}
|
|
263
|
-
${
|
|
304
|
+
${finalReadWriteText}
|
|
264
305
|
</span>
|
|
265
306
|
</div>
|
|
266
307
|
<div class='td key-descr'>
|
|
@@ -38,7 +38,14 @@ export default class TagInput extends LitElement {
|
|
|
38
38
|
afterPaste(e) {
|
|
39
39
|
const clipboardData = e.clipboardData || window.clipboardData;
|
|
40
40
|
const pastedData = clipboardData.getData('Text');
|
|
41
|
-
|
|
41
|
+
const pastedArray = pastedData ? pastedData.split(',').filter((v) => v.trim() !== '') : '';
|
|
42
|
+
if (pastedArray) {
|
|
43
|
+
if (Array.isArray(this.value)) {
|
|
44
|
+
this.value = [...this.value, ...pastedArray];
|
|
45
|
+
} else {
|
|
46
|
+
this.value = pastedArray;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
42
49
|
e.preventDefault();
|
|
43
50
|
}
|
|
44
51
|
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import RapiDoc from '~/rapidoc';
|
|
2
2
|
import RapiDocMini from '~/rapidoc-mini';
|
|
3
3
|
import OAuthReceiver from '~/oauth-receiver';
|
|
4
|
+
import JsonSchemaViewer from '~/json-schema-viewer';
|
|
4
5
|
|
|
5
6
|
export default { RapiDoc };
|
|
6
|
-
export { RapiDocMini, OAuthReceiver };
|
|
7
|
+
export { RapiDocMini, OAuthReceiver, JsonSchemaViewer };
|
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
import { css, LitElement } from 'lit-element';
|
|
2
|
+
import { marked } from 'marked';
|
|
3
|
+
import Prism from 'prismjs';
|
|
4
|
+
import 'prismjs/components/prism-css';
|
|
5
|
+
import 'prismjs/components/prism-yaml';
|
|
6
|
+
import 'prismjs/components/prism-go';
|
|
7
|
+
import 'prismjs/components/prism-java';
|
|
8
|
+
import 'prismjs/components/prism-json';
|
|
9
|
+
import 'prismjs/components/prism-bash';
|
|
10
|
+
import 'prismjs/components/prism-python';
|
|
11
|
+
import 'prismjs/components/prism-http';
|
|
12
|
+
import 'prismjs/components/prism-csharp';
|
|
13
|
+
|
|
14
|
+
// Styles
|
|
15
|
+
import FontStyles from '~/styles/font-styles';
|
|
16
|
+
import InputStyles from '~/styles/input-styles';
|
|
17
|
+
import FlexStyles from '~/styles/flex-styles';
|
|
18
|
+
import TableStyles from '~/styles/table-styles';
|
|
19
|
+
import PrismStyles from '~/styles/prism-styles';
|
|
20
|
+
import TabStyles from '~/styles/tab-styles';
|
|
21
|
+
import NavStyles from '~/styles/nav-styles';
|
|
22
|
+
import InfoStyles from '~/styles/info-styles';
|
|
23
|
+
|
|
24
|
+
import EndpointStyles from '~/styles/endpoint-styles';
|
|
25
|
+
import ProcessSpec from '~/utils/spec-parser';
|
|
26
|
+
import jsonSchemaViewerTemplate from '~/templates/json-schema-viewer-template';
|
|
27
|
+
|
|
28
|
+
export default class JsonSchemaViewer extends LitElement {
|
|
29
|
+
constructor() {
|
|
30
|
+
super();
|
|
31
|
+
this.isMini = false;
|
|
32
|
+
this.updateRoute = 'false';
|
|
33
|
+
this.renderStyle = 'focused';
|
|
34
|
+
this.showHeader = 'true';
|
|
35
|
+
this.allowAdvancedSearch = 'false';
|
|
36
|
+
this.selectedExampleForEachSchema = {};
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
static get properties() {
|
|
40
|
+
return {
|
|
41
|
+
// Spec
|
|
42
|
+
specUrl: { type: String, attribute: 'spec-url' },
|
|
43
|
+
|
|
44
|
+
// Schema Styles
|
|
45
|
+
schemaStyle: { type: String, attribute: 'schema-style' },
|
|
46
|
+
schemaExpandLevel: { type: Number, attribute: 'schema-expand-level' },
|
|
47
|
+
schemaDescriptionExpanded: { type: String, attribute: 'schema-description-expanded' },
|
|
48
|
+
allowSchemaDescriptionExpandToggle: { type: String, attribute: 'allow-schema-description-expand-toggle' },
|
|
49
|
+
|
|
50
|
+
// Hide/show Sections
|
|
51
|
+
showHeader: { type: String, attribute: 'show-header' },
|
|
52
|
+
showSideNav: { type: String, attribute: 'show-side-nav' },
|
|
53
|
+
showInfo: { type: String, attribute: 'show-info' },
|
|
54
|
+
|
|
55
|
+
// Allow or restrict features
|
|
56
|
+
allowSpecUrlLoad: { type: String, attribute: 'allow-spec-url-load' },
|
|
57
|
+
allowSpecFileLoad: { type: String, attribute: 'allow-spec-file-load' },
|
|
58
|
+
allowSpecFileDownload: { type: String, attribute: 'allow-spec-file-download' },
|
|
59
|
+
allowSearch: { type: String, attribute: 'allow-search' },
|
|
60
|
+
|
|
61
|
+
// Main Colors and Font
|
|
62
|
+
theme: { type: String },
|
|
63
|
+
bgColor: { type: String, attribute: 'bg-color' },
|
|
64
|
+
textColor: { type: String, attribute: 'text-color' },
|
|
65
|
+
primaryColor: { type: String, attribute: 'primary-color' },
|
|
66
|
+
fontSize: { type: String, attribute: 'font-size' },
|
|
67
|
+
regularFont: { type: String, attribute: 'regular-font' },
|
|
68
|
+
monoFont: { type: String, attribute: 'mono-font' },
|
|
69
|
+
loadFonts: { type: String, attribute: 'load-fonts' },
|
|
70
|
+
|
|
71
|
+
// Internal Properties
|
|
72
|
+
loading: { type: Boolean }, // indicates spec is being loaded
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
static get styles() {
|
|
77
|
+
return [
|
|
78
|
+
FontStyles,
|
|
79
|
+
InputStyles,
|
|
80
|
+
FlexStyles,
|
|
81
|
+
TableStyles,
|
|
82
|
+
EndpointStyles,
|
|
83
|
+
PrismStyles,
|
|
84
|
+
TabStyles,
|
|
85
|
+
NavStyles,
|
|
86
|
+
InfoStyles,
|
|
87
|
+
css`
|
|
88
|
+
:host {
|
|
89
|
+
display:flex;
|
|
90
|
+
flex-direction: column;
|
|
91
|
+
min-width:360px;
|
|
92
|
+
width:100%;
|
|
93
|
+
height:100%;
|
|
94
|
+
margin:0;
|
|
95
|
+
padding:0;
|
|
96
|
+
overflow: hidden;
|
|
97
|
+
letter-spacing:normal;
|
|
98
|
+
color:var(--fg);
|
|
99
|
+
background-color:var(--bg);
|
|
100
|
+
font-family:var(--font-regular);
|
|
101
|
+
}
|
|
102
|
+
.body {
|
|
103
|
+
display:flex;
|
|
104
|
+
height:100%;
|
|
105
|
+
width:100%;
|
|
106
|
+
overflow:hidden;
|
|
107
|
+
}
|
|
108
|
+
.nav-bar {
|
|
109
|
+
width: 230px;
|
|
110
|
+
display:flex;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.main-content {
|
|
114
|
+
margin:0;
|
|
115
|
+
padding: 16px;
|
|
116
|
+
display:block;
|
|
117
|
+
flex:1;
|
|
118
|
+
height:100%;
|
|
119
|
+
overflow-y: auto;
|
|
120
|
+
overflow-x: hidden;
|
|
121
|
+
scrollbar-width: thin;
|
|
122
|
+
scrollbar-color: var(--border-color) transparent;
|
|
123
|
+
}
|
|
124
|
+
.main-content-inner--view-mode {
|
|
125
|
+
padding: 0 8px;
|
|
126
|
+
}
|
|
127
|
+
.main-content::-webkit-scrollbar {
|
|
128
|
+
width: 8px;
|
|
129
|
+
height: 8px;
|
|
130
|
+
}
|
|
131
|
+
.main-content::-webkit-scrollbar-track {
|
|
132
|
+
background:transparent;
|
|
133
|
+
}
|
|
134
|
+
.main-content::-webkit-scrollbar-thumb {
|
|
135
|
+
background-color: var(--border-color);
|
|
136
|
+
}
|
|
137
|
+
.header {
|
|
138
|
+
background-color:var(--header-bg);
|
|
139
|
+
color:var(--header-fg);
|
|
140
|
+
width:100%;
|
|
141
|
+
}
|
|
142
|
+
.header-title {
|
|
143
|
+
font-size:calc(var(--font-size-regular) + 8px);
|
|
144
|
+
padding:0 8px;
|
|
145
|
+
}
|
|
146
|
+
input.header-input{
|
|
147
|
+
background:var(--header-color-darker);
|
|
148
|
+
color:var(--header-fg);
|
|
149
|
+
border:1px solid var(--header-color-border);
|
|
150
|
+
flex:1;
|
|
151
|
+
padding-right:24px;
|
|
152
|
+
border-radius:3px;
|
|
153
|
+
}
|
|
154
|
+
input.header-input::placeholder {
|
|
155
|
+
opacity:0.4;
|
|
156
|
+
}
|
|
157
|
+
.loader {
|
|
158
|
+
margin: 16px auto 16px auto;
|
|
159
|
+
border: 4px solid var(--bg3);
|
|
160
|
+
border-radius: 50%;
|
|
161
|
+
border-top: 4px solid var(--primary-color);
|
|
162
|
+
width: 36px;
|
|
163
|
+
height: 36px;
|
|
164
|
+
animation: spin 2s linear infinite;
|
|
165
|
+
}
|
|
166
|
+
@media only screen and (min-width: 768px) {
|
|
167
|
+
.only-large-screen{
|
|
168
|
+
display:block;
|
|
169
|
+
}
|
|
170
|
+
.only-large-screen-flex{
|
|
171
|
+
display:flex;
|
|
172
|
+
}
|
|
173
|
+
}`,
|
|
174
|
+
];
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Startup
|
|
178
|
+
connectedCallback() {
|
|
179
|
+
super.connectedCallback();
|
|
180
|
+
const parent = this.parentElement;
|
|
181
|
+
if (parent) {
|
|
182
|
+
if (parent.offsetWidth === 0 && parent.style.width === '') {
|
|
183
|
+
parent.style.width = '100vw';
|
|
184
|
+
}
|
|
185
|
+
if (parent.offsetHeight === 0 && parent.style.height === '') {
|
|
186
|
+
parent.style.height = '100vh';
|
|
187
|
+
}
|
|
188
|
+
if (parent.tagName === 'BODY') {
|
|
189
|
+
if (!parent.style.marginTop) { parent.style.marginTop = '0'; }
|
|
190
|
+
if (!parent.style.marginRight) { parent.style.marginRight = '0'; }
|
|
191
|
+
if (!parent.style.marginBottom) { parent.style.marginBottom = '0'; }
|
|
192
|
+
if (!parent.style.marginLeft) { parent.style.marginLeft = '0'; }
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (this.loadFonts !== 'false') {
|
|
197
|
+
const fontDescriptor = {
|
|
198
|
+
family: 'Open Sans',
|
|
199
|
+
style: 'normal',
|
|
200
|
+
weight: '300',
|
|
201
|
+
unicodeRange: 'U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD',
|
|
202
|
+
};
|
|
203
|
+
const fontWeight300 = new FontFace(
|
|
204
|
+
'Open Sans',
|
|
205
|
+
"url(https://fonts.gstatic.com/s/opensans/v18/mem5YaGs126MiZpBA-UN_r8OUuhpKKSTjw.woff2) format('woff2')",
|
|
206
|
+
fontDescriptor,
|
|
207
|
+
);
|
|
208
|
+
fontDescriptor.weight = '600';
|
|
209
|
+
const fontWeight600 = new FontFace(
|
|
210
|
+
'Open Sans',
|
|
211
|
+
"url(https://fonts.gstatic.com/s/opensans/v18/mem5YaGs126MiZpBA-UNirkOUuhpKKSTjw.woff2) format('woff2')",
|
|
212
|
+
fontDescriptor,
|
|
213
|
+
);
|
|
214
|
+
fontWeight300.load().then((font) => { document.fonts.add(font); });
|
|
215
|
+
fontWeight600.load().then((font) => { document.fonts.add(font); });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
this.renderStyle = 'focused';
|
|
219
|
+
this.pathsExpanded = this.pathsExpanded === 'true';
|
|
220
|
+
|
|
221
|
+
if (!this.showInfo || !'true, false,'.includes(`${this.showInfo},`)) { this.showInfo = 'true'; }
|
|
222
|
+
if (!this.showSideNav || !'true false'.includes(this.showSideNav)) { this.showSideNav = 'true'; }
|
|
223
|
+
if (!this.showHeader || !'true, false,'.includes(`${this.showHeader},`)) { this.showHeader = 'true'; }
|
|
224
|
+
|
|
225
|
+
if (!this.schemaStyle || !'tree, table,'.includes(`${this.schemaStyle},`)) { this.schemaStyle = 'tree'; }
|
|
226
|
+
if (!this.theme || !'light, dark,'.includes(`${this.theme},`)) {
|
|
227
|
+
this.theme = (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches) ? 'light' : 'dark';
|
|
228
|
+
}
|
|
229
|
+
if (!this.allowSearch || !'true, false,'.includes(`${this.allowSearch},`)) { this.allowSearch = 'true'; }
|
|
230
|
+
if (!this.schemaExpandLevel || this.schemaExpandLevel < 1) { this.schemaExpandLevel = 99999; }
|
|
231
|
+
if (!this.schemaDescriptionExpanded || !'true, false,'.includes(`${this.schemaDescriptionExpanded},`)) { this.schemaDescriptionExpanded = 'false'; }
|
|
232
|
+
if (!this.responseAreaHeight) { this.responseAreaHeight = '300px'; }
|
|
233
|
+
if (!this.fontSize || !'default, large, largest,'.includes(`${this.fontSize},`)) { this.fontSize = 'default'; }
|
|
234
|
+
if (!this.matchType || !'includes regex'.includes(this.matchType)) { this.matchType = 'includes'; }
|
|
235
|
+
if (!this.allowSchemaDescriptionExpandToggle || !'true, false,'.includes(`${this.allowSchemaDescriptionExpandToggle},`)) { this.allowSchemaDescriptionExpandToggle = 'true'; }
|
|
236
|
+
|
|
237
|
+
marked.setOptions({
|
|
238
|
+
highlight: (code, lang) => {
|
|
239
|
+
if (Prism.languages[lang]) {
|
|
240
|
+
return Prism.highlight(code, Prism.languages[lang], lang);
|
|
241
|
+
}
|
|
242
|
+
return code;
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
render() {
|
|
248
|
+
return jsonSchemaViewerTemplate.call(this, true, false, false, this.pathsExpanded);
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
attributeChangedCallback(name, oldVal, newVal) {
|
|
252
|
+
if (name === 'spec-url') {
|
|
253
|
+
if (oldVal !== newVal) {
|
|
254
|
+
// put it at the end of event-loop to load all the attributes
|
|
255
|
+
window.setTimeout(async () => {
|
|
256
|
+
await this.loadSpec(newVal);
|
|
257
|
+
}, 0);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
super.attributeChangedCallback(name, oldVal, newVal);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
onSepcUrlChange() {
|
|
264
|
+
this.setAttribute('spec-url', this.shadowRoot.getElementById('spec-url').value);
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
onSearchChange(e) {
|
|
268
|
+
// Todo: Filter Search
|
|
269
|
+
this.matchPaths = e.target.value;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
// Public Method
|
|
273
|
+
async loadSpec(specUrl) {
|
|
274
|
+
if (!specUrl) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
try {
|
|
278
|
+
this.resolvedSpec = {
|
|
279
|
+
specLoadError: false,
|
|
280
|
+
isSpecLoading: true,
|
|
281
|
+
tags: [],
|
|
282
|
+
};
|
|
283
|
+
this.loading = true;
|
|
284
|
+
this.loadFailed = false;
|
|
285
|
+
this.requestUpdate();
|
|
286
|
+
const spec = await ProcessSpec.call(
|
|
287
|
+
this,
|
|
288
|
+
specUrl,
|
|
289
|
+
this.generateMissingTags === 'true',
|
|
290
|
+
this.sortTags === 'true',
|
|
291
|
+
this.getAttribute('sort-endpoints-by'),
|
|
292
|
+
);
|
|
293
|
+
this.loading = false;
|
|
294
|
+
this.afterSpecParsedAndValidated(spec);
|
|
295
|
+
} catch (err) {
|
|
296
|
+
this.loading = false;
|
|
297
|
+
this.loadFailed = true;
|
|
298
|
+
this.resolvedSpec = null;
|
|
299
|
+
console.error(`RapiDoc: Unable to resolve the API spec.. ${err.message}`); // eslint-disable-line no-console
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
async afterSpecParsedAndValidated(spec) {
|
|
304
|
+
this.resolvedSpec = spec;
|
|
305
|
+
const specLoadedEvent = new CustomEvent('spec-loaded', { detail: spec });
|
|
306
|
+
this.dispatchEvent(specLoadedEvent);
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Called by anchor tags created using markdown
|
|
310
|
+
handleHref(e) {
|
|
311
|
+
if (e.target.tagName.toLowerCase() === 'a') {
|
|
312
|
+
if (e.target.getAttribute('href').startsWith('#')) {
|
|
313
|
+
const gotoEl = this.shadowRoot.getElementById(e.target.getAttribute('href').replace('#', ''));
|
|
314
|
+
if (gotoEl) {
|
|
315
|
+
gotoEl.scrollIntoView({ behavior: 'auto', block: 'start' });
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Example Dropdown @change Handler
|
|
322
|
+
onSelectExample(e) {
|
|
323
|
+
const exampleContainerEl = e.target.closest('.json-schema-example-panel');
|
|
324
|
+
const exampleEls = [...exampleContainerEl.querySelectorAll('.example')];
|
|
325
|
+
exampleEls.forEach((v) => {
|
|
326
|
+
v.style.display = v.dataset.example === e.target.value ? 'flex' : 'none';
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
async scrollToEventTarget(event) {
|
|
331
|
+
const navEl = event.currentTarget;
|
|
332
|
+
if (!navEl.dataset.contentId) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
const contentEl = this.shadowRoot.getElementById(navEl.dataset.contentId);
|
|
336
|
+
if (contentEl) {
|
|
337
|
+
contentEl.scrollIntoView({ behavior: 'auto', block: 'start' });
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
customElements.define('json-schema-viewer', JsonSchemaViewer);
|