docusaurus-plugin-openapi-docs 1.1.2 → 1.1.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 (37) hide show
  1. package/README.md +1 -1
  2. package/lib/markdown/createLogo.d.ts +2 -0
  3. package/lib/markdown/createLogo.js +19 -0
  4. package/lib/markdown/createRequestBodyDetails.d.ts +9 -2
  5. package/lib/markdown/createRequestBodyDetails.js +2 -2
  6. package/lib/markdown/createRequestSchema.d.ts +21 -0
  7. package/lib/markdown/createRequestSchema.js +680 -0
  8. package/lib/markdown/{createSchemaDetails.d.ts → createResponseSchema.d.ts} +2 -2
  9. package/lib/markdown/{createSchemaDetails.js → createResponseSchema.js} +289 -48
  10. package/lib/markdown/createStatusCodes.js +117 -4
  11. package/lib/markdown/index.d.ts +1 -1
  12. package/lib/markdown/index.js +12 -3
  13. package/lib/markdown/schema.js +50 -14
  14. package/lib/markdown/schema.test.js +18 -18
  15. package/lib/openapi/createExample.js +27 -14
  16. package/lib/openapi/openapi.d.ts +1 -1
  17. package/lib/openapi/openapi.js +30 -19
  18. package/lib/openapi/types.d.ts +8 -1
  19. package/lib/openapi/utils/loadAndResolveSpec.js +13 -0
  20. package/lib/sidebars/index.d.ts +1 -1
  21. package/lib/sidebars/index.js +14 -5
  22. package/lib/types.d.ts +1 -1
  23. package/package.json +8 -8
  24. package/src/markdown/createLogo.ts +21 -0
  25. package/src/markdown/createRequestBodyDetails.ts +11 -4
  26. package/src/markdown/createRequestSchema.ts +848 -0
  27. package/src/markdown/{createSchemaDetails.ts → createResponseSchema.ts} +350 -54
  28. package/src/markdown/createStatusCodes.ts +149 -9
  29. package/src/markdown/index.ts +34 -3
  30. package/src/markdown/schema.test.ts +18 -18
  31. package/src/markdown/schema.ts +60 -14
  32. package/src/openapi/createExample.ts +31 -14
  33. package/src/openapi/openapi.ts +21 -13
  34. package/src/openapi/types.ts +9 -1
  35. package/src/openapi/utils/loadAndResolveSpec.ts +13 -0
  36. package/src/sidebars/index.ts +17 -7
  37. package/src/types.ts +1 -1
@@ -99,6 +99,7 @@ function createAnyOneOf(schema: SchemaObject): any {
99
99
  }
100
100
 
101
101
  function createProperties(schema: SchemaObject) {
102
+ const discriminator = schema.discriminator;
102
103
  return Object.entries(schema.properties!).map(([key, val]) =>
103
104
  createEdges({
104
105
  name: key,
@@ -106,6 +107,7 @@ function createProperties(schema: SchemaObject) {
106
107
  required: Array.isArray(schema.required)
107
108
  ? schema.required.includes(key)
108
109
  : false,
110
+ discriminator,
109
111
  })
110
112
  );
111
113
  }
@@ -225,8 +227,12 @@ function createItems(schema: SchemaObject) {
225
227
  }
226
228
 
227
229
  if (schema.items?.allOf !== undefined) {
228
- const { mergedSchemas }: { mergedSchemas: SchemaObject; required: any } =
229
- mergeAllOf(schema.items?.allOf);
230
+ // TODO: figure out if and how we should pass merged required array
231
+ const {
232
+ mergedSchemas,
233
+ }: { mergedSchemas: SchemaObject; required: string[] } = mergeAllOf(
234
+ schema.items?.allOf
235
+ );
230
236
 
231
237
  // Handles combo anyOf/oneOf + properties
232
238
  if (
@@ -277,11 +283,115 @@ function createItems(schema: SchemaObject) {
277
283
  );
278
284
  }
279
285
 
286
+ /**
287
+ * For handling discriminators that do not map to a same-level property
288
+ */
289
+ function createDiscriminator(schema: SchemaObject) {
290
+ const discriminator = schema.discriminator;
291
+ const propertyName = discriminator?.propertyName;
292
+ const propertyType = "string"; // should always be string
293
+ const mapping: any = discriminator?.mapping;
294
+
295
+ // Explicit mapping is required since we can't support implicit
296
+ if (mapping === undefined) {
297
+ return undefined;
298
+ }
299
+
300
+ // Attempt to get the property description we want to display
301
+ // TODO: how to make it predictable when handling allOf
302
+ let propertyDescription;
303
+ const firstMappingSchema = mapping[Object.keys(mapping)[0]];
304
+ if (firstMappingSchema.properties !== undefined) {
305
+ propertyDescription =
306
+ firstMappingSchema.properties![propertyName!].description;
307
+ }
308
+ if (firstMappingSchema.allOf !== undefined) {
309
+ const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
310
+ firstMappingSchema.allOf
311
+ );
312
+ if (mergedSchemas.properties !== undefined) {
313
+ propertyDescription =
314
+ mergedSchemas.properties[propertyName!]?.description;
315
+ }
316
+ }
317
+
318
+ if (propertyDescription === undefined) {
319
+ if (
320
+ schema.properties !== undefined &&
321
+ schema.properties![propertyName!] !== undefined
322
+ ) {
323
+ propertyDescription = schema.properties![propertyName!].description;
324
+ }
325
+ }
326
+
327
+ return create("div", {
328
+ className: "discriminatorItem",
329
+ children: create("div", {
330
+ children: [
331
+ create("strong", {
332
+ style: { paddingLeft: "1rem" },
333
+ children: propertyName,
334
+ }),
335
+ guard(propertyType, (name) =>
336
+ create("span", {
337
+ style: { opacity: "0.6" },
338
+ children: ` ${propertyType}`,
339
+ })
340
+ ),
341
+ guard(getQualifierMessage(schema.discriminator as any), (message) =>
342
+ create("div", {
343
+ style: {
344
+ paddingLeft: "1rem",
345
+ },
346
+ children: createDescription(message),
347
+ })
348
+ ),
349
+ guard(propertyDescription, (description) =>
350
+ create("div", {
351
+ style: {
352
+ paddingLeft: "1rem",
353
+ },
354
+ children: createDescription(description),
355
+ })
356
+ ),
357
+ create("DiscriminatorTabs", {
358
+ children: Object.keys(mapping!).map((key, index) => {
359
+ if (mapping[key].allOf !== undefined) {
360
+ const { mergedSchemas }: { mergedSchemas: SchemaObject } =
361
+ mergeAllOf(mapping[key].allOf);
362
+ // Cleanup duplicate property from mapping schema
363
+ delete mergedSchemas.properties![propertyName!];
364
+ mapping[key] = mergedSchemas;
365
+ }
366
+
367
+ if (mapping[key].properties !== undefined) {
368
+ // Cleanup duplicate property from mapping schema
369
+ delete mapping[key].properties![propertyName!];
370
+ }
371
+
372
+ const label = key;
373
+ return create("TabItem", {
374
+ label: label,
375
+ value: `${index}-item-discriminator`,
376
+ children: [
377
+ create("div", {
378
+ style: { marginLeft: "-4px" },
379
+ children: createNodes(mapping[key]),
380
+ }),
381
+ ],
382
+ });
383
+ }),
384
+ }),
385
+ ],
386
+ }),
387
+ });
388
+ }
389
+
280
390
  function createDetailsNode(
281
391
  name: string,
282
392
  schemaName: string,
283
393
  schema: SchemaObject,
284
- required: any
394
+ required: string[] | boolean
285
395
  ): any {
286
396
  return create("SchemaItem", {
287
397
  collapsible: true,
@@ -296,7 +406,7 @@ function createDetailsNode(
296
406
  style: { opacity: "0.6" },
297
407
  children: ` ${schemaName}`,
298
408
  }),
299
- guard(required, () => [
409
+ guard(schema.required && schema.required === true, () => [
300
410
  create("strong", {
301
411
  style: {
302
412
  fontSize: "var(--ifm-code-font-size)",
@@ -331,18 +441,111 @@ function createDetailsNode(
331
441
  });
332
442
  }
333
443
 
444
+ /**
445
+ * For handling discriminators that map to a same-level property (like 'petType').
446
+ * Note: These should only be encountered while iterating through properties.
447
+ */
448
+ function createPropertyDiscriminator(
449
+ name: string,
450
+ schemaName: string,
451
+ schema: SchemaObject,
452
+ discriminator: any,
453
+ required: string[] | boolean
454
+ ): any {
455
+ if (schema === undefined) {
456
+ return undefined;
457
+ }
458
+
459
+ if (discriminator.mapping === undefined) {
460
+ return undefined;
461
+ }
462
+
463
+ return create("div", {
464
+ className: "discriminatorItem",
465
+ children: create("div", {
466
+ children: [
467
+ create("strong", { style: { paddingLeft: "1rem" }, children: name }),
468
+ guard(schemaName, (name) =>
469
+ create("span", {
470
+ style: { opacity: "0.6" },
471
+ children: ` ${schemaName}`,
472
+ })
473
+ ),
474
+ guard(required, () => [
475
+ create("strong", {
476
+ style: {
477
+ fontSize: "var(--ifm-code-font-size)",
478
+ color: "var(--openapi-required)",
479
+ },
480
+ children: " required",
481
+ }),
482
+ ]),
483
+ guard(getQualifierMessage(discriminator), (message) =>
484
+ create("div", {
485
+ style: {
486
+ paddingLeft: "1rem",
487
+ },
488
+ children: createDescription(message),
489
+ })
490
+ ),
491
+ guard(schema.description, (description) =>
492
+ create("div", {
493
+ style: {
494
+ paddingLeft: "1rem",
495
+ },
496
+ children: createDescription(description),
497
+ })
498
+ ),
499
+ create("DiscriminatorTabs", {
500
+ children: Object.keys(discriminator?.mapping!).map((key, index) => {
501
+ const label = key;
502
+ return create("TabItem", {
503
+ label: label,
504
+ value: `${index}-item-discriminator`,
505
+ children: [
506
+ create("div", {
507
+ style: { marginLeft: "-4px" },
508
+ children: createNodes(discriminator?.mapping[key]),
509
+ }),
510
+ ],
511
+ });
512
+ }),
513
+ }),
514
+ ],
515
+ }),
516
+ });
517
+ }
518
+
334
519
  interface EdgeProps {
335
520
  name: string;
336
521
  schema: SchemaObject;
337
- required: boolean;
522
+ required: string[] | boolean;
523
+ discriminator?: any | unknown;
338
524
  }
339
525
 
340
526
  /**
341
527
  * Creates the edges or "leaves" of a schema tree. Edges can branch into sub-nodes with createDetails().
342
528
  */
343
- function createEdges({ name, schema, required }: EdgeProps): any {
529
+ function createEdges({
530
+ name,
531
+ schema,
532
+ required,
533
+ discriminator,
534
+ }: EdgeProps): any {
344
535
  const schemaName = getSchemaName(schema);
345
536
 
537
+ // if (name === "id") console.log(name, schema, required);
538
+
539
+ if (discriminator !== undefined && discriminator.propertyName === name) {
540
+ return createPropertyDiscriminator(
541
+ name,
542
+ "string",
543
+ schema,
544
+ discriminator,
545
+ required
546
+ );
547
+ }
548
+
346
549
  if (schema.oneOf !== undefined || schema.anyOf !== undefined) {
347
550
  return createDetailsNode(name, schemaName, schema, required);
348
551
  }
@@ -351,9 +554,8 @@ function createEdges({ name, schema, required }: EdgeProps): any {
351
554
  const {
352
555
  mergedSchemas,
353
556
  required,
354
- }: { mergedSchemas: SchemaObject; required: any } = mergeAllOf(
355
- schema.allOf
356
- );
557
+ }: { mergedSchemas: SchemaObject; required: string[] | boolean } =
558
+ mergeAllOf(schema.allOf);
357
559
  const mergedSchemaName = getSchemaName(mergedSchemas);
358
560
 
359
561
  if (
@@ -371,13 +573,23 @@ function createEdges({ name, schema, required }: EdgeProps): any {
371
573
  return createDetailsNode(name, mergedSchemaName, mergedSchemas, required);
372
574
  }
373
575
 
576
+ // array of objects
577
+ if (mergedSchemas.items?.properties !== undefined) {
578
+ return createDetailsNode(name, mergedSchemaName, mergedSchemas, required);
579
+ }
580
+
581
+ if (mergedSchemas.writeOnly && mergedSchemas.writeOnly === true) {
582
+ return undefined;
583
+ }
584
+
374
585
  return create("SchemaItem", {
375
586
  collapsible: false,
376
587
  name,
377
- required,
588
+ required: false,
378
589
  schemaDescription: mergedSchemas.description,
379
590
  schemaName: schemaName,
380
591
  qualifierMessage: getQualifierMessage(schema),
592
+ defaultValue: mergedSchemas.default,
381
593
  });
382
594
  }
383
595
 
@@ -394,14 +606,19 @@ function createEdges({ name, schema, required }: EdgeProps): any {
394
606
  return createDetailsNode(name, schemaName, schema, required);
395
607
  }
396
608
 
609
+ if (schema.writeOnly && schema.writeOnly === true) {
610
+ return undefined;
611
+ }
612
+
397
613
  // primitives and array of non-objects
398
614
  return create("SchemaItem", {
399
615
  collapsible: false,
400
616
  name,
401
- required,
617
+ required: false,
402
618
  schemaDescription: schema.description,
403
619
  schemaName: schemaName,
404
620
  qualifierMessage: getQualifierMessage(schema),
621
+ defaultValue: schema.default,
405
622
  });
406
623
  }
407
624
 
@@ -409,6 +626,10 @@ function createEdges({ name, schema, required }: EdgeProps): any {
409
626
  * Creates a hierarchical level of a schema tree. Nodes produce edges that can branch into sub-nodes with edges, recursively.
410
627
  */
411
628
  function createNodes(schema: SchemaObject): any {
629
+ if (schema.discriminator !== undefined) {
630
+ return createDiscriminator(schema);
631
+ }
632
+
412
633
  if (schema.oneOf !== undefined || schema.anyOf !== undefined) {
413
634
  return createAnyOneOf(schema);
414
635
  }
@@ -477,11 +698,11 @@ interface Props {
477
698
  [key: string]: MediaTypeObject;
478
699
  };
479
700
  description?: string;
480
- required?: boolean;
701
+ required?: string[] | boolean;
481
702
  };
482
703
  }
483
704
 
484
- export function createSchemaDetails({ title, body, ...rest }: Props) {
705
+ export function createResponseSchema({ title, body, ...rest }: Props) {
485
706
  if (
486
707
  body === undefined ||
487
708
  body.content === undefined ||
@@ -491,8 +712,75 @@ export function createSchemaDetails({ title, body, ...rest }: Props) {
491
712
  return undefined;
492
713
  }
493
714
 
494
- // NOTE: We just pick a random content-type.
495
- // How common is it to have multiple?
715
+ // Get all MIME types, including vendor-specific
716
+ const mimeTypes = Object.keys(body.content);
717
+
718
+ if (mimeTypes && mimeTypes.length > 1) {
719
+ return create("MimeTabs", {
720
+ groupId: "mime-type",
721
+ children: mimeTypes.map((mimeType) => {
722
+ const firstBody = body.content![mimeType].schema;
723
+ if (firstBody === undefined) {
724
+ return undefined;
725
+ }
726
+ if (firstBody.properties !== undefined) {
727
+ if (Object.keys(firstBody.properties).length === 0) {
728
+ return undefined;
729
+ }
730
+ }
731
+ return create("TabItem", {
732
+ label: mimeType,
733
+ value: `${mimeType}`,
734
+ children: [
735
+ createDetails({
736
+ "data-collapsed": false,
737
+ open: true,
738
+ ...rest,
739
+ children: [
740
+ createDetailsSummary({
741
+ style: { textAlign: "left" },
742
+ children: [
743
+ create("strong", { children: `${title}` }),
744
+ guard(firstBody.type === "array", (format) =>
745
+ create("span", {
746
+ style: { opacity: "0.6" },
747
+ children: ` array`,
748
+ })
749
+ ),
750
+ guard(body.required && body.required === true, () => [
751
+ create("strong", {
752
+ style: {
753
+ fontSize: "var(--ifm-code-font-size)",
754
+ color: "var(--openapi-required)",
755
+ },
756
+ children: " required",
757
+ }),
758
+ ]),
759
+ ],
760
+ }),
761
+ create("div", {
762
+ style: { textAlign: "left", marginLeft: "1rem" },
763
+ children: [
764
+ guard(body.description, () => [
765
+ create("div", {
766
+ style: { marginTop: "1rem", marginBottom: "1rem" },
767
+ children: createDescription(body.description),
768
+ }),
769
+ ]),
770
+ ],
771
+ }),
772
+ create("ul", {
773
+ style: { marginLeft: "1rem" },
774
+ children: createNodes(firstBody),
775
+ }),
776
+ ],
777
+ }),
778
+ ],
779
+ });
780
+ }),
781
+ });
782
+ }
783
+
496
784
  const randomFirstKey = Object.keys(body.content)[0];
497
785
  const firstBody = body.content[randomFirstKey].schema;
498
786
 
@@ -506,49 +794,57 @@ export function createSchemaDetails({ title, body, ...rest }: Props) {
506
794
  return undefined;
507
795
  }
508
796
  }
509
-
510
- // Root-level schema dropdown
511
- return createDetails({
512
- "data-collapsed": false,
513
- open: true,
514
- ...rest,
797
+ return create("MimeTabs", {
515
798
  children: [
516
- createDetailsSummary({
517
- style: { textAlign: "left" },
799
+ create("TabItem", {
800
+ label: randomFirstKey,
801
+ value: `${randomFirstKey}-schema`,
518
802
  children: [
519
- create("strong", { children: `${title}` }),
520
- guard(firstBody.type === "array", (format) =>
521
- create("span", {
522
- style: { opacity: "0.6" },
523
- children: ` array`,
524
- })
525
- ),
526
- guard(body.required, () => [
527
- create("strong", {
528
- style: {
529
- fontSize: "var(--ifm-code-font-size)",
530
- color: "var(--openapi-required)",
531
- },
532
- children: " required",
533
- }),
534
- ]),
535
- ],
536
- }),
537
- create("div", {
538
- style: { textAlign: "left", marginLeft: "1rem" },
539
- children: [
540
- guard(body.description, () => [
541
- create("div", {
542
- style: { marginTop: "1rem", marginBottom: "1rem" },
543
- children: createDescription(body.description),
544
- }),
545
- ]),
803
+ createDetails({
804
+ "data-collapsed": false,
805
+ open: true,
806
+ ...rest,
807
+ children: [
808
+ createDetailsSummary({
809
+ style: { textAlign: "left" },
810
+ children: [
811
+ create("strong", { children: `${title}` }),
812
+ guard(firstBody.type === "array", (format) =>
813
+ create("span", {
814
+ style: { opacity: "0.6" },
815
+ children: ` array`,
816
+ })
817
+ ),
818
+ guard(body.required, () => [
819
+ create("strong", {
820
+ style: {
821
+ fontSize: "var(--ifm-code-font-size)",
822
+ color: "var(--openapi-required)",
823
+ },
824
+ children: " required",
825
+ }),
826
+ ]),
827
+ ],
828
+ }),
829
+ create("div", {
830
+ style: { textAlign: "left", marginLeft: "1rem" },
831
+ children: [
832
+ guard(body.description, () => [
833
+ create("div", {
834
+ style: { marginTop: "1rem", marginBottom: "1rem" },
835
+ children: createDescription(body.description),
836
+ }),
837
+ ]),
838
+ ],
839
+ }),
840
+ create("ul", {
841
+ style: { marginLeft: "1rem" },
842
+ children: createNodes(firstBody),
843
+ }),
844
+ ],
845
+ }),
546
846
  ],
547
847
  }),
548
- create("ul", {
549
- style: { marginLeft: "1rem" },
550
- children: createNodes(firstBody),
551
- }),
552
848
  ],
553
849
  });
554
850
  }