rapidoc 9.3.3 → 9.3.5

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.
Files changed (48) hide show
  1. package/.github/workflow/words.yaml +22 -0
  2. package/README.md +2 -7
  3. package/dist/index.html +1 -1
  4. package/dist/index.html.gz +0 -0
  5. package/dist/rapidoc-min.js +858 -748
  6. package/dist/rapidoc-min.js.LICENSE.txt +14 -9
  7. package/dist/rapidoc-min.js.LICENSE.txt.gz +0 -0
  8. package/dist/rapidoc-min.js.gz +0 -0
  9. package/dist/rapidoc-min.js.map +1 -1
  10. package/dist/rapidoc-min.js.map.gz +0 -0
  11. package/dist/rapidoc.js +11948 -32008
  12. package/dist/report.html +6 -5
  13. package/index.html +2 -1
  14. package/package.json +25 -24
  15. package/src/components/api-request.js +266 -122
  16. package/src/components/api-response.js +11 -10
  17. package/src/components/json-tree.js +17 -12
  18. package/src/components/schema-table.js +58 -49
  19. package/src/components/schema-tree.js +60 -56
  20. package/src/components/tag-input.js +7 -4
  21. package/src/json-schema-viewer.js +2 -1
  22. package/src/rapidoc-mini.js +1 -1
  23. package/src/rapidoc.js +108 -35
  24. package/src/styles/endpoint-styles.js +1 -1
  25. package/src/styles/info-styles.js +2 -1
  26. package/src/styles/input-styles.js +2 -16
  27. package/src/styles/nav-styles.js +57 -10
  28. package/src/styles/schema-styles.js +27 -15
  29. package/src/styles/tab-styles.js +1 -0
  30. package/src/templates/advance-search-template.js +3 -3
  31. package/src/templates/callback-template.js +3 -3
  32. package/src/templates/code-samples-template.js +1 -0
  33. package/src/templates/components-template.js +3 -5
  34. package/src/templates/endpoint-template.js +39 -26
  35. package/src/templates/expanded-endpoint-template.js +58 -9
  36. package/src/templates/focused-endpoint-template.js +5 -2
  37. package/src/templates/header-template.js +2 -2
  38. package/src/templates/json-schema-viewer-template.js +2 -1
  39. package/src/templates/main-body-template.js +19 -18
  40. package/src/templates/navbar-template.js +99 -82
  41. package/src/templates/overview-template.js +1 -1
  42. package/src/templates/security-scheme-template.js +51 -27
  43. package/src/templates/server-template.js +1 -1
  44. package/src/utils/common-utils.js +2 -2
  45. package/src/utils/schema-utils.js +192 -67
  46. package/src/utils/spec-parser.js +9 -3
  47. package/src/utils/theme.js +9 -3
  48. package/webpack.config.js +2 -1
@@ -1,3 +1,32 @@
1
+ import RandExp from 'randexp';
2
+
3
+ // Make RandExp determinist
4
+ RandExp.prototype.randInt = (from) => from;
5
+
6
+ // Takes a value as input and provides a printable string to replresent null values, spaces, blankstring etc
7
+ export function getPrintableVal(val) {
8
+ if (val === undefined) {
9
+ return '';
10
+ }
11
+ if (val === null) {
12
+ return 'null';
13
+ }
14
+ if (val === '') {
15
+ return '∅';
16
+ }
17
+ if (typeof val === 'boolean' || typeof val === 'number') {
18
+ return `${val}`;
19
+ }
20
+ if (Array.isArray(val)) {
21
+ return val.map((v) => (v === null ? 'null' : v === '' ? '∅' : v.toString().replace(/^ +| +$/g, (m) => '●'.repeat(m.length)) || '')).join(', ');
22
+ }
23
+ if (typeof val === 'object') {
24
+ const keys = Object.keys(val);
25
+ return `{ ${keys[0]}:${val[keys[0]]}${keys.length > 1 ? ',' : ''} ... }`;
26
+ }
27
+ return val.toString().replace(/^ +| +$/g, (m) => '●'.repeat(m.length)) || '';
28
+ }
29
+
1
30
  /* Generates an schema object containing type and constraint info */
2
31
  export function getTypeInfo(schema) {
3
32
  if (!schema) {
@@ -13,12 +42,14 @@ export function getTypeInfo(schema) {
13
42
  dataType = `{recursive: ${schemaNode}} `;
14
43
  } else if (schema.type) {
15
44
  dataType = Array.isArray(schema.type) ? schema.type.join(schema.length === 2 ? ' or ' : '┃') : schema.type;
16
- if (schema.format || schema.enum) {
17
- dataType = dataType.replace('string', schema.enum ? 'enum' : schema.format);
45
+ if (schema.format || schema.enum || schema.const) {
46
+ dataType = dataType.replace('string', schema.enum ? 'enum' : schema.const ? 'const' : schema.format);
18
47
  }
19
48
  if (schema.nullable) {
20
49
  dataType += '┃null';
21
50
  }
51
+ } else if (schema.const) {
52
+ dataType = 'const';
22
53
  } else if (Object.keys(schema).length === 0) {
23
54
  dataType = 'any';
24
55
  } else {
@@ -32,7 +63,7 @@ export function getTypeInfo(schema) {
32
63
  readOrWriteOnly: (schema.readOnly ? '🆁' : schema.writeOnly ? '🆆' : ''),
33
64
  deprecated: schema.deprecated ? '❌' : '',
34
65
  examples: schema.examples || schema.example,
35
- default: schema.default != null ? `${schema.default}` : '',
66
+ default: getPrintableVal(schema.default),
36
67
  description: schema.description || '',
37
68
  constrain: '',
38
69
  allowedValues: '',
@@ -45,16 +76,24 @@ export function getTypeInfo(schema) {
45
76
  } else if (info.type === '{missing-type-info}' || info.type === 'any') {
46
77
  info.description = info.description || '';
47
78
  }
48
-
49
79
  // Set Allowed Values
50
- info.allowedValues = Array.isArray(schema.enum) ? schema.enum.join('┃') : '';
80
+ info.allowedValues = schema.const
81
+ ? schema.const
82
+ : Array.isArray(schema.enum)
83
+ ? schema.enum.map((v) => (getPrintableVal(v))).join('┃')
84
+ : '';
85
+
51
86
  if (dataType === 'array' && schema.items) {
52
87
  const arrayItemType = schema.items?.type;
53
- const arrayItemDefault = schema.items?.default !== undefined ? schema.items.default : '';
88
+ const arrayItemDefault = getPrintableVal(schema.items.default);
54
89
 
55
90
  info.arrayType = `${schema.type} of ${Array.isArray(arrayItemType) ? arrayItemType.join('') : arrayItemType}`;
56
91
  info.default = arrayItemDefault;
57
- info.allowedValues = Array.isArray(schema.items?.enum) ? schema.items.enum.join('┃') : '';
92
+ info.allowedValues = schema.items.const
93
+ ? schema.const
94
+ : Array.isArray(schema.items?.enum)
95
+ ? schema.items.enum.map((v) => (getPrintableVal(v))).join('┃')
96
+ : '';
58
97
  }
59
98
  if (dataType.match(/integer|number/g)) {
60
99
  if (schema.minimum !== undefined || schema.exclusiveMinimum !== undefined) {
@@ -80,8 +119,9 @@ export function getTypeInfo(schema) {
80
119
  info.html = `${info.type}~|~${info.readOrWriteOnly}~|~${info.constrain}~|~${info.default}~|~${info.allowedValues}~|~${info.pattern}~|~${info.description}~|~${schema.title || ''}~|~${info.deprecated ? 'deprecated' : ''}`;
81
120
  return info;
82
121
  }
122
+
83
123
  export function nestExampleIfPresent(example) {
84
- if (typeof example === 'boolean') {
124
+ if (typeof example === 'boolean' || typeof example === 'number') {
85
125
  return {
86
126
  Example: { value: `${example}` },
87
127
  };
@@ -94,6 +134,18 @@ export function nestExampleIfPresent(example) {
94
134
  return example ? { Example: { value: example } } : example;
95
135
  }
96
136
 
137
+ /**
138
+ * Normalize example object in the following format (List of object which is used to render example links and fill the input boxes)
139
+ * [{
140
+ * exampleVal : 'value to be rendered on the input control (text-box)',
141
+ * exampleList : [
142
+ * value : '',
143
+ * printableValue: '',
144
+ * summary : '',
145
+ * description : ''
146
+ * ]
147
+ * }]
148
+ * */
97
149
  export function normalizeExamples(examples, dataType = 'string') {
98
150
  if (!examples) {
99
151
  return {
@@ -101,19 +153,18 @@ export function normalizeExamples(examples, dataType = 'string') {
101
153
  exampleList: [],
102
154
  };
103
155
  }
104
-
105
156
  if (examples.constructor === Object) {
106
- const exampleValAndDescr = Object.values(examples);
107
- const exampleVal = exampleValAndDescr.length > 0
108
- ? typeof exampleValAndDescr[0].value === 'boolean' || typeof exampleValAndDescr[0].value === 'number'
109
- ? exampleValAndDescr[0].value.toString()
110
- : exampleValAndDescr[0].value
157
+ const exampleList = Object.values(examples)
158
+ .filter((v) => (v['x-example-show-value'] !== false))
159
+ .map((v) => ({
160
+ value: (typeof v.value === 'boolean' || typeof v.value === 'number' ? `${v.value}` : (v.value || '')),
161
+ printableValue: getPrintableVal(v.value),
162
+ summary: v.summary || '',
163
+ description: v.description || '',
164
+ }));
165
+ const exampleVal = exampleList.length > 0
166
+ ? exampleList[0].value
111
167
  : '';
112
- const exampleList = Object.values(examples).map((v) => ({
113
- value: typeof v.value === 'boolean' || typeof v.value === 'number' ? v.value.toString() : v.value,
114
- summary: v.summary,
115
- description: v.description,
116
- }));
117
168
  return { exampleVal, exampleList };
118
169
  }
119
170
 
@@ -131,12 +182,18 @@ export function normalizeExamples(examples, dataType = 'string') {
131
182
 
132
183
  if (dataType === 'array') {
133
184
  const [exampleVal] = examples;
134
- const exampleList = examples.map((v) => ({ value: v }));
185
+ const exampleList = examples.map((v) => ({
186
+ value: v,
187
+ printableValue: getPrintableVal(v),
188
+ }));
135
189
  return { exampleVal, exampleList };
136
190
  }
137
191
 
138
192
  const exampleVal = examples[0].toString();
139
- const exampleList = examples.map((v) => ({ value: v.toString() }));
193
+ const exampleList = examples.map((v) => ({
194
+ value: v.toString(),
195
+ printableValue: getPrintableVal(v),
196
+ }));
140
197
  return { exampleVal, exampleList };
141
198
  }
142
199
 
@@ -153,6 +210,17 @@ export function getSampleValueByType(schemaObj) {
153
210
  if (example === '') { return ''; }
154
211
  if (example === null) { return null; }
155
212
  if (example === 0) { return 0; }
213
+ if (example === false) { return false; }
214
+ if (example instanceof Date) {
215
+ switch (schemaObj.format.toLowerCase()) {
216
+ case 'date':
217
+ return example.toISOString().split('T')[0];
218
+ case 'time':
219
+ return example.toISOString().split('T')[1];
220
+ default:
221
+ return example.toISOString();
222
+ }
223
+ }
156
224
  if (example) { return example; }
157
225
 
158
226
  if (Object.keys(schemaObj).length === 0) {
@@ -160,11 +228,20 @@ export function getSampleValueByType(schemaObj) {
160
228
  }
161
229
  if (schemaObj.$ref) {
162
230
  // Indicates a Circular ref
163
- return schemaObj.$ref;
231
+ return {};
232
+ }
233
+ if (schemaObj.const === false || schemaObj.const === 0 || schemaObj.const === null || schemaObj.const === '') {
234
+ return schemaObj.const;
235
+ }
236
+ if (schemaObj.const) {
237
+ return schemaObj.const;
238
+ }
239
+ if (schemaObj.default) {
240
+ return schemaObj.default;
164
241
  }
165
242
  const typeValue = Array.isArray(schemaObj.type) ? schemaObj.type[0] : schemaObj.type;
166
243
  if (!typeValue) {
167
- return '?';
244
+ return null;
168
245
  }
169
246
  if (typeValue.match(/^integer|^number/g)) {
170
247
  const multipleOf = Number.isNaN(Number(schemaObj.multipleOf)) ? undefined : Number(schemaObj.multipleOf);
@@ -187,7 +264,14 @@ export function getSampleValueByType(schemaObj) {
187
264
  if (typeValue.match(/^null/g)) { return null; }
188
265
  if (typeValue.match(/^string/g)) {
189
266
  if (schemaObj.enum) { return schemaObj.enum[0]; }
190
- if (schemaObj.pattern) { return schemaObj.pattern; }
267
+ if (schemaObj.const) { return schemaObj.const; }
268
+ if (schemaObj.pattern) {
269
+ try {
270
+ return new RandExp(schemaObj.pattern).gen();
271
+ } catch (error) {
272
+ return schemaObj.pattern;
273
+ }
274
+ }
191
275
  if (schemaObj.format) {
192
276
  const u = `${Date.now().toString(16)}${Math.random().toString(16)}0`.repeat(16);
193
277
  switch (schemaObj.format.toLowerCase()) {
@@ -214,6 +298,8 @@ export function getSampleValueByType(schemaObj) {
214
298
  return '2001:0db8:5b96:0000:0000:426f:8e17:642a';
215
299
  case 'uuid':
216
300
  return [u.substr(0, 8), u.substr(8, 4), `4000-8${u.substr(13, 3)}`, u.substr(16, 12)].join('-');
301
+ case 'byte':
302
+ return 'ZXhhbXBsZQ=='; // 'example' base64 encoded. See https://spec.openapis.org/oas/v3.0.0#data-types
217
303
  default:
218
304
  return '';
219
305
  }
@@ -225,7 +311,7 @@ export function getSampleValueByType(schemaObj) {
225
311
  }
226
312
  }
227
313
  // If type cannot be determined
228
- return '?';
314
+ return null;
229
315
  }
230
316
 
231
317
  /*
@@ -242,9 +328,9 @@ json2xml- TestCase
242
328
  <root>
243
329
  <prop1>simple</prop1>
244
330
  <prop2>
245
- <0> a </0>
246
- <1> b </1>
247
- <2> c </2>
331
+ <0>a</0>
332
+ <1>b</1>
333
+ <2>c</2>
248
334
  </prop2>
249
335
  <prop3>
250
336
  <ob1>val-1</ob1>
@@ -259,12 +345,22 @@ export function json2xml(obj, level = 1) {
259
345
  return `\n${indent}${obj.toString()}`;
260
346
  }
261
347
  for (const prop in obj) {
348
+ const tagNameOrProp = (obj[prop]['::XML_TAG'] || prop);
349
+ let tagName = '';
262
350
  if (Array.isArray(obj[prop])) {
263
- xmlText = `${xmlText}\n${indent}<${prop}> ${json2xml(obj[prop], level + 1)}\n${indent}</${prop}>`;
351
+ tagName = tagNameOrProp[0]['::XML_TAG'] || `${prop}`;
352
+ } else {
353
+ tagName = tagNameOrProp;
354
+ }
355
+ if (prop.startsWith('::')) {
356
+ continue;
357
+ }
358
+ if (Array.isArray(obj[prop])) {
359
+ xmlText = `${xmlText}\n${indent}<${tagName}>${json2xml(obj[prop], level + 1)}\n${indent}</${tagName}>`;
264
360
  } else if (typeof obj[prop] === 'object') {
265
- xmlText = `${xmlText}\n${indent}<${prop}> ${json2xml(obj[prop], level + 1)}\n${indent}</${prop}>`;
361
+ xmlText = `${xmlText}\n${indent}<${tagName}>${json2xml(obj[prop], level + 1)}\n${indent}</${tagName}>`;
266
362
  } else {
267
- xmlText = `${xmlText}\n${indent}<${prop}> ${obj[prop].toString()} </${prop}>`;
363
+ xmlText = `${xmlText}\n${indent}<${tagName}>${obj[prop].toString()}</${tagName}>`;
268
364
  }
269
365
  }
270
366
  return xmlText;
@@ -280,6 +376,12 @@ function addSchemaInfoToExample(schema, obj) {
280
376
  if (schema.description) {
281
377
  obj['::DESCRIPTION'] = schema.description;
282
378
  }
379
+ if (schema.xml?.name) {
380
+ obj['::XML_TAG'] = schema.xml?.name;
381
+ }
382
+ if (schema.xml?.wrapped) {
383
+ obj['::XML_WRAP'] = schema.xml?.wrapped.toString();
384
+ }
283
385
  }
284
386
 
285
387
  function removeTitlesAndDescriptions(obj) {
@@ -288,6 +390,8 @@ function removeTitlesAndDescriptions(obj) {
288
390
  }
289
391
  delete obj['::TITLE'];
290
392
  delete obj['::DESCRIPTION'];
393
+ delete obj['::XML_TAG'];
394
+ delete obj['::XML_WRAP'];
291
395
  for (const k in obj) {
292
396
  removeTitlesAndDescriptions(obj[k]);
293
397
  }
@@ -326,11 +430,10 @@ export function schemaToSampleObj(schema, config = { }) {
326
430
  if (!schema) {
327
431
  return;
328
432
  }
329
-
330
433
  if (schema.allOf) {
331
434
  const objWithAllProps = {};
332
435
 
333
- if (schema.allOf.length === 1 && !schema.allOf[0].properties && !schema.allOf[0].items) {
436
+ if (schema.allOf.length === 1 && !schema.allOf[0]?.properties && !schema.allOf[0]?.items) {
334
437
  // If allOf has single item and the type is not an object or array, then its a primitive
335
438
  if (schema.allOf[0].$ref) {
336
439
  return '{ }';
@@ -363,7 +466,11 @@ export function schemaToSampleObj(schema, config = { }) {
363
466
  const objWithSchemaProps = {};
364
467
  if (schema.properties) {
365
468
  for (const propertyName in schema.properties) {
366
- objWithSchemaProps[propertyName] = getSampleValueByType(schema.properties[propertyName]);
469
+ if (schema.properties[propertyName].properties || schema.properties[propertyName].properties?.items) {
470
+ objWithSchemaProps[propertyName] = schemaToSampleObj(schema.properties[propertyName], config);
471
+ } else {
472
+ objWithSchemaProps[propertyName] = getSampleValueByType(schema.properties[propertyName]);
473
+ }
367
474
  }
368
475
  }
369
476
 
@@ -477,16 +584,31 @@ export function schemaToSampleObj(schema, config = { }) {
477
584
  addPropertyExampleToObjectExamples([schema.properties[propertyName].items.example], obj, propertyName);
478
585
  } else {
479
586
  const itemSamples = schemaToSampleObj(schema.properties[propertyName].items, config);
480
- const arraySamples = [];
481
- for (const key in itemSamples) {
482
- arraySamples[key] = [itemSamples[key]];
587
+ if (config.useXmlTagForProp) {
588
+ const xmlTagName = schema.properties[propertyName].xml?.name || propertyName;
589
+ if (schema.properties[propertyName].xml?.wrapped) {
590
+ const wrappedItemSample = JSON.parse(`{ "${xmlTagName}" : { "${xmlTagName}" : ${JSON.stringify(itemSamples['example-0'])} } }`);
591
+ obj = mergePropertyExamples(obj, xmlTagName, wrappedItemSample);
592
+ } else {
593
+ obj = mergePropertyExamples(obj, xmlTagName, itemSamples);
594
+ }
595
+ } else {
596
+ const arraySamples = [];
597
+ for (const key in itemSamples) {
598
+ arraySamples[key] = [itemSamples[key]];
599
+ }
600
+ obj = mergePropertyExamples(obj, propertyName, arraySamples);
483
601
  }
484
- obj = mergePropertyExamples(obj, propertyName, arraySamples);
485
602
  }
486
603
  continue;
487
604
  }
488
605
  obj = mergePropertyExamples(obj, propertyName, schemaToSampleObj(schema.properties[propertyName], config));
489
606
  }
607
+ if (typeof schema.additionalProperties === 'object') {
608
+ const propertyName = schema.additionalProperties['x-additionalPropertiesName'] || 'property';
609
+ obj = mergePropertyExamples(obj, `${propertyName}1`, schemaToSampleObj(schema.additionalProperties, config));
610
+ obj = mergePropertyExamples(obj, `${propertyName}2`, schemaToSampleObj(schema.additionalProperties, config));
611
+ }
490
612
  }
491
613
  } else if (schema.type === 'array' || schema.items) {
492
614
  if (schema.items || schema.example) {
@@ -513,26 +635,29 @@ export function schemaToSampleObj(schema, config = { }) {
513
635
  }
514
636
 
515
637
  function generateMarkdownForArrayAndObjectDescription(schema, level = 0) {
516
- let markdown = '';
638
+ let markdown = ((schema.description || schema.title) && (schema.minItems || schema.maxItems)) ? '<span class="descr-expand-toggle">➔</span>' : '';
517
639
  if (schema.title) {
518
- markdown = `**${schema.title}:** `;
519
- }
520
- if (schema.description) {
521
- markdown = `${markdown} ${schema.description} ${schema.minItems || schema.maxItems ? '<span class="more-content">⤵</span><br/>' : ''}`;
640
+ if (schema.description) {
641
+ markdown = `${markdown} <b>${schema.title}:</b> ${schema.description}<br/>`;
642
+ } else {
643
+ markdown = `${markdown} ${schema.title}<br/>`;
644
+ }
645
+ } else if (schema.description) {
646
+ markdown = `${markdown} ${schema.description}<br/>`;
522
647
  }
523
648
  if (schema.minItems) {
524
- markdown = `${markdown} **Min Items:** ${schema.minItems}`;
649
+ markdown = `${markdown} <b>Min Items:</b> ${schema.minItems}`;
525
650
  }
526
651
  if (schema.maxItems) {
527
- markdown = `${markdown} **Max Items:** ${schema.maxItems}`;
652
+ markdown = `${markdown} <b>Max Items:</b> ${schema.maxItems}`;
528
653
  }
529
654
  if (level > 0 && schema.items?.description) {
530
655
  let itemsMarkdown = '';
531
656
  if (schema.items.minProperties) {
532
- itemsMarkdown = `**Min Properties:** ${schema.items.minProperties}`;
657
+ itemsMarkdown = `<b>Min Properties:</b> ${schema.items.minProperties}`;
533
658
  }
534
659
  if (schema.items.maxProperties) {
535
- itemsMarkdown = `${itemsMarkdown} **Max Properties:** ${schema.items.maxProperties}`;
660
+ itemsMarkdown = `${itemsMarkdown} <b>Max Properties:</b> ${schema.items.maxProperties}`;
536
661
  }
537
662
  markdown = `${markdown} ⮕ ${itemsMarkdown} [ ${schema.items.description} ] `;
538
663
  }
@@ -597,11 +722,13 @@ export function schemaInObjectNotation(schema, obj, level = 0, suffix = '') {
597
722
  if (v.type === 'object' || v.properties || v.allOf || v.anyOf || v.oneOf) {
598
723
  const partialObj = schemaInObjectNotation(v, {});
599
724
  objWithAnyOfProps[`::OPTION~${index + 1}${v.title ? `~${v.title}` : ''}`] = partialObj;
725
+ objWithAnyOfProps[`::OPTION~${index + 1}${v.title ? `~${v.title}` : ''}`]['::readwrite'] = ''; // xxx-options cannot be read or write only
600
726
  objWithAnyOfProps['::type'] = 'xxx-of-option';
601
727
  } else if (v.type === 'array' || v.items) {
602
728
  // This else-if block never seems to get executed
603
729
  const partialObj = schemaInObjectNotation(v, {});
604
730
  objWithAnyOfProps[`::OPTION~${index + 1}${v.title ? `~${v.title}` : ''}`] = partialObj;
731
+ objWithAnyOfProps[`::OPTION~${index + 1}${v.title ? `~${v.title}` : ''}`]['::readwrite'] = ''; // xxx-options cannot be read or write only
605
732
  objWithAnyOfProps['::type'] = 'xxx-of-array';
606
733
  } else {
607
734
  const prop = `::OPTION~${index + 1}${v.title ? `~${v.title}` : ''}`;
@@ -610,7 +737,8 @@ export function schemaInObjectNotation(schema, obj, level = 0, suffix = '') {
610
737
  }
611
738
  });
612
739
  obj[(schema.anyOf ? `::ANY~OF ${suffix}` : `::ONE~OF ${suffix}`)] = objWithAnyOfProps;
613
- obj['::type'] = 'xxx-of';
740
+ // obj['::type'] = 'object';
741
+ obj['::type'] = 'object';
614
742
  } else if (Array.isArray(schema.type)) {
615
743
  // When a property has multiple types, then check further if any of the types are array or object, if yes then modify the schema using one-of
616
744
  // Clone the schema - as it will be modified to replace multi-data-types with one-of;
@@ -640,7 +768,7 @@ export function schemaInObjectNotation(schema, obj, level = 0, suffix = '') {
640
768
  }
641
769
  }
642
770
  if (complexTypes.length > 0) {
643
- obj['::type'] = 'xxx-of';
771
+ obj['::type'] = 'object';
644
772
  const multiTypeOptions = {
645
773
  '::type': 'xxx-of-option',
646
774
  };
@@ -687,6 +815,7 @@ export function schemaInObjectNotation(schema, obj, level = 0, suffix = '') {
687
815
  obj['::type'] = 'object';
688
816
  if ((Array.isArray(schema.type) && schema.type.includes('null')) || schema.nullable) {
689
817
  obj['::dataTypeLabel'] = 'object or null';
818
+ obj['::nullable'] = true;
690
819
  }
691
820
  obj['::deprecated'] = schema.deprecated || false;
692
821
  obj['::readwrite'] = schema.readOnly ? 'readonly' : schema.writeOnly ? 'writeonly' : '';
@@ -697,8 +826,11 @@ export function schemaInObjectNotation(schema, obj, level = 0, suffix = '') {
697
826
  obj[key] = schemaInObjectNotation(schema.properties[key], {}, (level + 1));
698
827
  }
699
828
  }
829
+ for (const key in schema.patternProperties) {
830
+ obj[`[pattern: ${key}]`] = schemaInObjectNotation(schema.patternProperties[key], obj, (level + 1));
831
+ }
700
832
  if (schema.additionalProperties) {
701
- obj['<any-key>'] = schemaInObjectNotation(schema.additionalProperties, {});
833
+ obj['[any-key]'] = schemaInObjectNotation(schema.additionalProperties, {});
702
834
  }
703
835
  } else if (schema.type === 'array' || schema.items) { // If Array
704
836
  obj['::title'] = schema.title || '';
@@ -706,6 +838,7 @@ export function schemaInObjectNotation(schema, obj, level = 0, suffix = '') {
706
838
  obj['::type'] = 'array';
707
839
  if ((Array.isArray(schema.type) && schema.type.includes('null')) || schema.nullable) {
708
840
  obj['::dataTypeLabel'] = 'array or null';
841
+ obj['::nullable'] = true;
709
842
  }
710
843
  obj['::deprecated'] = schema.deprecated || false;
711
844
  obj['::readwrite'] = schema.readOnly ? 'readonly' : schema.writeOnly ? 'writeonly' : '';
@@ -739,7 +872,8 @@ export function generateExample(schema, mimeType, examples = '', example = '', i
739
872
  egContent = examples[eg].value;
740
873
  if (typeof examples[eg].value === 'string') {
741
874
  try {
742
- const fixedJsonString = examples[eg].value.replace((/([\w]+)(:)/g), '"$1"$2').replace((/'/g), '"');
875
+ // const fixedJsonString = examples[eg].value.replace((/([\w]+)(:)/g), '"$1"$2').replace((/'/g), '"');
876
+ const fixedJsonString = examples[eg].value;
743
877
  egContent = JSON.parse(fixedJsonString);
744
878
  egFormat = 'json';
745
879
  } catch (err) {
@@ -797,7 +931,8 @@ export function generateExample(schema, mimeType, examples = '', example = '', i
797
931
  // If schema-level examples are not provided or includeGeneratedExample === true then generate one based on the schema field types
798
932
  if (finalExamples.length === 0 || includeGeneratedExample === true) {
799
933
  if (schema) {
800
- if (schema.example) { // Note: schema.examples (plurals) is not allowed as per spec
934
+ if (schema.example) {
935
+ // Note: Deprecated: The 'example' property has been deprecated in 3.1.0 in favor of the JSON Schema 'examples' keyword
801
936
  finalExamples.push({
802
937
  exampleId: 'Example',
803
938
  exampleSummary: '',
@@ -812,22 +947,13 @@ export function generateExample(schema, mimeType, examples = '', example = '', i
812
947
  let exampleFormat = '';
813
948
  let exampleValue = '';
814
949
  if (mimeType?.toLowerCase().includes('xml')) {
815
- xmlRootStart = (schema.xml && schema.xml.name) ? `<${schema.xml.name}>` : '<root>';
816
- xmlRootEnd = (schema.xml && schema.xml.name) ? `</${schema.xml.name}>` : '</root>';
950
+ xmlRootStart = schema.xml?.name ? `<${schema.xml.name} ${schema.xml.namespace ? `xmlns="${schema.xml.namespace}"` : ''}>` : '<root>';
951
+ xmlRootEnd = schema.xml?.name ? `</${schema.xml.name}>` : '</root>';
817
952
  exampleFormat = 'text';
818
953
  } else {
819
954
  exampleFormat = outputType;
820
955
  }
821
-
822
- const samples = schemaToSampleObj(
823
- schema,
824
- {
825
- includeReadOnly,
826
- includeWriteOnly,
827
- deprecated: true,
828
- },
829
- );
830
-
956
+ const samples = schemaToSampleObj(schema, { includeReadOnly, includeWriteOnly, deprecated: true, useXmlTagForProp: mimeType?.toLowerCase().includes('xml') });
831
957
  let i = 0;
832
958
  for (const samplesKey in samples) {
833
959
  if (!samples[samplesKey]) {
@@ -835,11 +961,10 @@ export function generateExample(schema, mimeType, examples = '', example = '', i
835
961
  }
836
962
  const summary = samples[samplesKey]['::TITLE'] || `Example ${++i}`;
837
963
  const description = samples[samplesKey]['::DESCRIPTION'] || '';
838
- removeTitlesAndDescriptions(samples[samplesKey]);
839
-
840
964
  if (mimeType?.toLowerCase().includes('xml')) {
841
- exampleValue = `${xmlRootStart}${json2xml(samples[samplesKey])}\n${xmlRootEnd}`;
965
+ exampleValue = `<?xml version="1.0" encoding="UTF-8"?>\n${xmlRootStart}${json2xml(samples[samplesKey], 1)}\n${xmlRootEnd}`;
842
966
  } else {
967
+ removeTitlesAndDescriptions(samples[samplesKey]);
843
968
  exampleValue = outputType === 'text' ? JSON.stringify(samples[samplesKey], null, 2) : samples[samplesKey];
844
969
  }
845
970
 
@@ -3,7 +3,7 @@ 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(specUrl, generateMissingTags = false, sortTags = false, sortEndpointsBy = '', attrApiKey = '', attrApiKeyLocation = '', attrApiKeyValue = '', serverUrl = '') {
6
+ export default async function ProcessSpec(specUrl, generateMissingTags = false, sortTags = false, sortSchemas = false, sortEndpointsBy = '', attrApiKey = '', attrApiKeyLocation = '', attrApiKeyValue = '', serverUrl = '') {
7
7
  let jsonParsedSpec;
8
8
  try {
9
9
  this.requestUpdate(); // important to show the initial loader
@@ -53,7 +53,7 @@ export default async function ProcessSpec(specUrl, generateMissingTags = false,
53
53
  const tags = groupByTags(jsonParsedSpec, sortEndpointsBy, generateMissingTags, sortTags);
54
54
 
55
55
  // Components
56
- const components = getComponents(jsonParsedSpec);
56
+ const components = getComponents(jsonParsedSpec, sortSchemas);
57
57
 
58
58
  // Info Description Headers
59
59
  const infoDescriptionHeaders = jsonParsedSpec.info?.description ? getHeadersFromMarkdown(jsonParsedSpec.info.description) : [];
@@ -162,7 +162,7 @@ function getHeadersFromMarkdown(markdownContent) {
162
162
  return headers || [];
163
163
  }
164
164
 
165
- function getComponents(openApiSpec) {
165
+ function getComponents(openApiSpec, sortSchemas = false) {
166
166
  if (!openApiSpec.components) {
167
167
  return [];
168
168
  }
@@ -184,6 +184,10 @@ function getComponents(openApiSpec) {
184
184
 
185
185
  switch (component) {
186
186
  case 'schemas':
187
+ if (sortSchemas) {
188
+ subComponents.sort((c1, c2) => c1.name.localeCompare(c2.name));
189
+ }
190
+
187
191
  cmpName = 'Schemas';
188
192
  cmpDescription = 'Schemas allows the definition of input and output data types. These types can be objects, but also primitives and arrays.';
189
193
  break;
@@ -246,6 +250,7 @@ function groupByTags(openApiSpec, sortEndpointsBy, generateMissingTags = false,
246
250
  show: true,
247
251
  elementId: `tag--${v.name.replace(invalidCharsRegEx, '-')}`,
248
252
  name: v.name,
253
+ displayName: v['x-displayName'] || v.name,
249
254
  description: v.description || '',
250
255
  headers: v.description ? getHeadersFromMarkdown(v.description) : [],
251
256
  paths: [],
@@ -347,6 +352,7 @@ function groupByTags(openApiSpec, sortEndpointsBy, generateMissingTags = false,
347
352
  expandedAtLeastOnce: false,
348
353
  summary: (pathOrHookObj.summary || ''),
349
354
  description: (pathOrHookObj.description || ''),
355
+ externalDocs: pathOrHookObj.externalDocs,
350
356
  shortSummary,
351
357
  method: methodName,
352
358
  path: pathOrHookName,
@@ -7,7 +7,7 @@ export default function setTheme(baseTheme, theme = {}) {
7
7
  // Common Theme colors
8
8
  const primaryColor = theme.primaryColor ? theme.primaryColor : baseTheme === 'dark' ? '#f76b39' : '#ff591e';
9
9
  const primaryColorInvert = ColorUtils.color.invert(primaryColor);
10
- const primaryColorTrans = ColorUtils.color.opacity(primaryColor, '0.8');
10
+ const primaryColorTrans = ColorUtils.color.opacity(primaryColor, '0.4');
11
11
 
12
12
  // Dark and Light Theme colors
13
13
  if (baseTheme === 'dark') {
@@ -31,6 +31,8 @@ export default function setTheme(baseTheme, theme = {}) {
31
31
  const navHoverBgColor = theme.navHoverBgColor ? theme.navHoverBgColor : ColorUtils.color.brightness(navBgColor, -15);
32
32
  const navHoverTextColor = theme.navHoverTextColor ? theme.navHoverTextColor : ColorUtils.color.invert(navBgColor);
33
33
  const navAccentColor = theme.navAccentColor ? theme.navAccentColor : ColorUtils.color.brightness(primaryColor, 25);
34
+ const navAccentTextColor = theme.navAccentTextColor ? theme.navAccenttextColor : ColorUtils.color.invert(navAccentColor);
35
+
34
36
  const overlayBg = 'rgba(80, 80, 80, 0.4)';
35
37
 
36
38
  newTheme = {
@@ -54,7 +56,7 @@ export default function setTheme(baseTheme, theme = {}) {
54
56
  navHoverBgColor,
55
57
  navHoverTextColor,
56
58
  navAccentColor,
57
-
59
+ navAccentTextColor,
58
60
  headerColor,
59
61
  headerColorInvert: ColorUtils.color.invert(headerColor),
60
62
  headerColorDarker: ColorUtils.color.brightness(headerColor, -20),
@@ -123,6 +125,7 @@ export default function setTheme(baseTheme, theme = {}) {
123
125
  const navHoverBgColor = theme.navHoverBgColor ? theme.navHoverBgColor : ColorUtils.color.brightness(navBgColor, -15);
124
126
  const navHoverTextColor = theme.navHoverTextColor ? theme.navHoverTextColor : ColorUtils.color.invert(navBgColor);
125
127
  const navAccentColor = theme.navAccentColor ? theme.navAccentColor : ColorUtils.color.brightness(primaryColor, 25);
128
+ const navAccentTextColor = theme.navAccentTextColor ? theme.navAccenttextColor : ColorUtils.color.invert(navAccentColor);
126
129
  const overlayBg = 'rgba(0, 0, 0, 0.4)';
127
130
 
128
131
  newTheme = {
@@ -146,7 +149,7 @@ export default function setTheme(baseTheme, theme = {}) {
146
149
  navHoverBgColor,
147
150
  navHoverTextColor,
148
151
  navAccentColor,
149
-
152
+ navAccentTextColor,
150
153
  headerColor,
151
154
  headerColorInvert: ColorUtils.color.invert(headerColor),
152
155
  headerColorDarker: ColorUtils.color.brightness(headerColor, -20),
@@ -211,6 +214,8 @@ export default function setTheme(baseTheme, theme = {}) {
211
214
  --font-size-regular: ${this.fontSize === 'default' ? '14px' : (this.fontSize === 'large' ? '15px' : '16px')};
212
215
  --dialog-z-index: 1000;
213
216
 
217
+ --focus-shadow: 0 0 0 1px transparent, 0 0 0 3px ${newTheme.primaryColorTrans};
218
+
214
219
  /* Theme specific styles */
215
220
  --bg:${newTheme.bg1};
216
221
  --bg2:${newTheme.bg2};
@@ -259,6 +264,7 @@ export default function setTheme(baseTheme, theme = {}) {
259
264
  --nav-hover-bg-color:${newTheme.navHoverBgColor};
260
265
  --nav-hover-text-color:${newTheme.navHoverTextColor};
261
266
  --nav-accent-color:${newTheme.navAccentColor};
267
+ --nav-accent-text-color:${newTheme.navAccentTextColor};
262
268
 
263
269
  /* Nav API Method Colors*/
264
270
  --nav-get-color:${newTheme.blue};
package/webpack.config.js CHANGED
@@ -31,7 +31,8 @@ const rapidocBanner = `
31
31
  * License: MIT
32
32
  * Repo : https://github.com/rapi-doc/RapiDoc
33
33
  * Author : Mrinmoy Majumdar
34
- *`;
34
+ */
35
+ `;
35
36
 
36
37
  const commonPlugins = [
37
38
  new webpack.ProvidePlugin({ Buffer: ['buffer', 'Buffer'] }),