docusaurus-plugin-openapi-docs 0.0.0-429 → 0.0.0-433

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.
@@ -10,6 +10,7 @@ import { createDescription } from "./createDescription";
10
10
  import { createDetails } from "./createDetails";
11
11
  import { createDetailsSummary } from "./createDetailsSummary";
12
12
  import {
13
+ createExampleFromSchema,
13
14
  createResponseExample,
14
15
  createResponseExamples,
15
16
  } from "./createStatusCodes";
@@ -290,106 +291,106 @@ function createItems(schema: SchemaObject) {
290
291
  /**
291
292
  * For handling discriminators that do not map to a same-level property
292
293
  */
293
- function createDiscriminator(schema: SchemaObject) {
294
- const discriminator = schema.discriminator;
295
- const propertyName = discriminator?.propertyName;
296
- const propertyType = "string"; // should always be string
297
- const mapping: any = discriminator?.mapping;
298
-
299
- // Explicit mapping is required since we can't support implicit
300
- if (mapping === undefined) {
301
- return undefined;
302
- }
303
-
304
- // Attempt to get the property description we want to display
305
- // TODO: how to make it predictable when handling allOf
306
- let propertyDescription;
307
- const firstMappingSchema = mapping[Object.keys(mapping)[0]];
308
- if (firstMappingSchema.properties !== undefined) {
309
- propertyDescription =
310
- firstMappingSchema.properties![propertyName!].description;
311
- }
312
- if (firstMappingSchema.allOf !== undefined) {
313
- const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
314
- firstMappingSchema.allOf
315
- );
316
- if (mergedSchemas.properties !== undefined) {
317
- propertyDescription =
318
- mergedSchemas.properties[propertyName!]?.description;
319
- }
320
- }
321
-
322
- if (propertyDescription === undefined) {
323
- if (
324
- schema.properties !== undefined &&
325
- schema.properties![propertyName!] !== undefined
326
- ) {
327
- propertyDescription = schema.properties![propertyName!].description;
328
- }
329
- }
330
-
331
- return create("div", {
332
- className: "discriminatorItem",
333
- children: create("div", {
334
- children: [
335
- create("strong", {
336
- style: { paddingLeft: "1rem" },
337
- children: propertyName,
338
- }),
339
- guard(propertyType, (name) =>
340
- create("span", {
341
- style: { opacity: "0.6" },
342
- children: ` ${propertyType}`,
343
- })
344
- ),
345
- guard(getQualifierMessage(schema.discriminator as any), (message) =>
346
- create("div", {
347
- style: {
348
- paddingLeft: "1rem",
349
- },
350
- children: createDescription(message),
351
- })
352
- ),
353
- guard(propertyDescription, (description) =>
354
- create("div", {
355
- style: {
356
- paddingLeft: "1rem",
357
- },
358
- children: createDescription(description),
359
- })
360
- ),
361
- create("DiscriminatorTabs", {
362
- children: Object.keys(mapping!).map((key, index) => {
363
- if (mapping[key].allOf !== undefined) {
364
- const { mergedSchemas }: { mergedSchemas: SchemaObject } =
365
- mergeAllOf(mapping[key].allOf);
366
- // Cleanup duplicate property from mapping schema
367
- delete mergedSchemas.properties![propertyName!];
368
- mapping[key] = mergedSchemas;
369
- }
370
-
371
- if (mapping[key].properties !== undefined) {
372
- // Cleanup duplicate property from mapping schema
373
- delete mapping[key].properties![propertyName!];
374
- }
375
-
376
- const label = key;
377
- return create("TabItem", {
378
- label: label,
379
- value: `${index}-item-discriminator`,
380
- children: [
381
- create("div", {
382
- style: { marginLeft: "-4px" },
383
- children: createNodes(mapping[key]),
384
- }),
385
- ],
386
- });
387
- }),
388
- }),
389
- ],
390
- }),
391
- });
392
- }
294
+ // function createDiscriminator(schema: SchemaObject) {
295
+ // const discriminator = schema.discriminator;
296
+ // const propertyName = discriminator?.propertyName;
297
+ // const propertyType = "string"; // should always be string
298
+ // const mapping: any = discriminator?.mapping;
299
+
300
+ // // Explicit mapping is required since we can't support implicit
301
+ // if (mapping === undefined) {
302
+ // return undefined;
303
+ // }
304
+
305
+ // // Attempt to get the property description we want to display
306
+ // // TODO: how to make it predictable when handling allOf
307
+ // let propertyDescription;
308
+ // const firstMappingSchema = mapping[Object.keys(mapping)[0]];
309
+ // if (firstMappingSchema.properties !== undefined) {
310
+ // propertyDescription =
311
+ // firstMappingSchema.properties![propertyName!].description;
312
+ // }
313
+ // if (firstMappingSchema.allOf !== undefined) {
314
+ // const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
315
+ // firstMappingSchema.allOf
316
+ // );
317
+ // if (mergedSchemas.properties !== undefined) {
318
+ // propertyDescription =
319
+ // mergedSchemas.properties[propertyName!]?.description;
320
+ // }
321
+ // }
322
+
323
+ // if (propertyDescription === undefined) {
324
+ // if (
325
+ // schema.properties !== undefined &&
326
+ // schema.properties![propertyName!] !== undefined
327
+ // ) {
328
+ // propertyDescription = schema.properties![propertyName!].description;
329
+ // }
330
+ // }
331
+
332
+ // return create("div", {
333
+ // className: "discriminatorItem",
334
+ // children: create("div", {
335
+ // children: [
336
+ // create("strong", {
337
+ // style: { paddingLeft: "1rem" },
338
+ // children: propertyName,
339
+ // }),
340
+ // guard(propertyType, (name) =>
341
+ // create("span", {
342
+ // style: { opacity: "0.6" },
343
+ // children: ` ${propertyType}`,
344
+ // })
345
+ // ),
346
+ // guard(getQualifierMessage(schema.discriminator as any), (message) =>
347
+ // create("div", {
348
+ // style: {
349
+ // paddingLeft: "1rem",
350
+ // },
351
+ // children: createDescription(message),
352
+ // })
353
+ // ),
354
+ // guard(propertyDescription, (description) =>
355
+ // create("div", {
356
+ // style: {
357
+ // paddingLeft: "1rem",
358
+ // },
359
+ // children: createDescription(description),
360
+ // })
361
+ // ),
362
+ // create("DiscriminatorTabs", {
363
+ // children: Object.keys(mapping!).map((key, index) => {
364
+ // if (mapping[key].allOf !== undefined) {
365
+ // const { mergedSchemas }: { mergedSchemas: SchemaObject } =
366
+ // mergeAllOf(mapping[key].allOf);
367
+ // // Cleanup duplicate property from mapping schema
368
+ // delete mergedSchemas.properties![propertyName!];
369
+ // mapping[key] = mergedSchemas;
370
+ // }
371
+
372
+ // if (mapping[key].properties !== undefined) {
373
+ // // Cleanup duplicate property from mapping schema
374
+ // delete mapping[key].properties![propertyName!];
375
+ // }
376
+
377
+ // const label = key;
378
+ // return create("TabItem", {
379
+ // label: label,
380
+ // value: `${index}-item-discriminator`,
381
+ // children: [
382
+ // create("div", {
383
+ // style: { marginLeft: "-4px" },
384
+ // children: createNodes(mapping[key]),
385
+ // }),
386
+ // ],
387
+ // });
388
+ // }),
389
+ // }),
390
+ // ],
391
+ // }),
392
+ // });
393
+ // }
393
394
 
394
395
  function createDetailsNode(
395
396
  name: string,
@@ -628,9 +629,9 @@ function createEdges({
628
629
  * Creates a hierarchical level of a schema tree. Nodes produce edges that can branch into sub-nodes with edges, recursively.
629
630
  */
630
631
  function createNodes(schema: SchemaObject): any {
631
- if (schema.discriminator !== undefined) {
632
- return createDiscriminator(schema);
633
- }
632
+ // if (schema.discriminator !== undefined) {
633
+ // return createDiscriminator(schema);
634
+ // }
634
635
 
635
636
  if (schema.oneOf !== undefined || schema.anyOf !== undefined) {
636
637
  return createAnyOneOf(schema);
@@ -748,7 +749,7 @@ export function createResponseSchema({ title, body, ...rest }: Props) {
748
749
  groupId: "schema-tabs",
749
750
  children: [
750
751
  firstBody &&
751
- create("TabTtem", {
752
+ create("TabItem", {
752
753
  label: `${title}`,
753
754
  value: `${title}`,
754
755
  children: [
@@ -803,8 +804,11 @@ export function createResponseSchema({ title, body, ...rest }: Props) {
803
804
  }),
804
805
  ],
805
806
  }),
806
- responseExamples && createResponseExamples(responseExamples),
807
- responseExample && createResponseExample(responseExample),
807
+ firstBody && createExampleFromSchema(firstBody, mimeType),
808
+ responseExamples &&
809
+ createResponseExamples(responseExamples, mimeType),
810
+ responseExample &&
811
+ createResponseExample(responseExample, mimeType),
808
812
  ],
809
813
  }),
810
814
  ],
@@ -5,6 +5,9 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
+ import format from "xml-formatter";
9
+
10
+ import { sampleResponseFromSchema } from "../openapi/createResponseExample";
8
11
  import { ApiItem } from "../types";
9
12
  import { createDescription } from "./createDescription";
10
13
  import { createDetails } from "./createDetails";
@@ -13,6 +16,43 @@ import { createResponseSchema } from "./createResponseSchema";
13
16
  import { create } from "./utils";
14
17
  import { guard } from "./utils";
15
18
 
19
+ export default function json2xml(o: any, tab: any) {
20
+ var toXml = function (v: any, name: string, ind: any) {
21
+ var xml = "";
22
+ if (v instanceof Array) {
23
+ for (var i = 0, n = v.length; i < n; i++)
24
+ xml += ind + toXml(v[i], name, ind + "\t") + "\n";
25
+ } else if (typeof v == "object") {
26
+ var hasChild = false;
27
+ xml += ind + "<" + name;
28
+ for (var m in v) {
29
+ if (m.charAt(0) === "@")
30
+ xml += " " + m.substr(1) + '="' + v[m].toString() + '"';
31
+ else hasChild = true;
32
+ }
33
+ xml += hasChild ? ">" : "/>";
34
+ if (hasChild) {
35
+ for (var m2 in v) {
36
+ if (m2 === "#text") xml += v[m2];
37
+ else if (m2 === "#cdata") xml += "<![CDATA[" + v[m2] + "]]>";
38
+ else if (m2.charAt(0) !== "@") xml += toXml(v[m2], m2, ind + "\t");
39
+ }
40
+ xml +=
41
+ (xml.charAt(xml.length - 1) === "\n" ? ind : "") +
42
+ "</" +
43
+ name +
44
+ ">";
45
+ }
46
+ } else {
47
+ xml += ind + "<" + name + ">" + v.toString() + "</" + name + ">";
48
+ }
49
+ return xml;
50
+ },
51
+ xml = "";
52
+ for (var m3 in o) xml += toXml(o[m3], m3, "");
53
+ return tab ? xml.replace(/\t/g, tab) : xml.replace(/\t|\n/g, "");
54
+ }
55
+
16
56
  interface Props {
17
57
  responses: ApiItem["responses"];
18
58
  }
@@ -67,7 +107,17 @@ function createResponseHeaders(responseHeaders: any) {
67
107
  );
68
108
  }
69
109
 
70
- export function createResponseExamples(responseExamples: any) {
110
+ export function createResponseExamples(
111
+ responseExamples: any,
112
+ mimeType: string
113
+ ) {
114
+ let language = "shell";
115
+ if (mimeType.endsWith("json")) {
116
+ language = "json";
117
+ }
118
+ if (mimeType.endsWith("xml")) {
119
+ language = "xml";
120
+ }
71
121
  return Object.entries(responseExamples).map(
72
122
  ([exampleName, exampleValue]: any) => {
73
123
  const camelToSpaceName = exampleName.replace(/([A-Z])/g, " $1");
@@ -81,6 +131,7 @@ export function createResponseExamples(responseExamples: any) {
81
131
  children: [
82
132
  create("ResponseSamples", {
83
133
  responseExample: JSON.stringify(exampleValue.value, null, 2),
134
+ language: language,
84
135
  }),
85
136
  ],
86
137
  });
@@ -91,6 +142,7 @@ export function createResponseExamples(responseExamples: any) {
91
142
  children: [
92
143
  create("ResponseSamples", {
93
144
  responseExample: exampleValue.value,
145
+ language: language,
94
146
  }),
95
147
  ],
96
148
  });
@@ -98,7 +150,14 @@ export function createResponseExamples(responseExamples: any) {
98
150
  );
99
151
  }
100
152
 
101
- export function createResponseExample(responseExample: any) {
153
+ export function createResponseExample(responseExample: any, mimeType: string) {
154
+ let language = "shell";
155
+ if (mimeType.endsWith("json")) {
156
+ language = "json";
157
+ }
158
+ if (mimeType.endsWith("xml")) {
159
+ language = "xml";
160
+ }
102
161
  if (typeof responseExample === "object") {
103
162
  return create("TabItem", {
104
163
  label: `Example`,
@@ -106,6 +165,7 @@ export function createResponseExample(responseExample: any) {
106
165
  children: [
107
166
  create("ResponseSamples", {
108
167
  responseExample: JSON.stringify(responseExample, null, 2),
168
+ language: language,
109
169
  }),
110
170
  ],
111
171
  });
@@ -116,11 +176,69 @@ export function createResponseExample(responseExample: any) {
116
176
  children: [
117
177
  create("ResponseSamples", {
118
178
  responseExample: responseExample,
179
+ language: language,
119
180
  }),
120
181
  ],
121
182
  });
122
183
  }
123
184
 
185
+ export function createExampleFromSchema(schema: any, mimeType: string) {
186
+ const responseExample = sampleResponseFromSchema(schema);
187
+ if (mimeType.endsWith("xml")) {
188
+ let responseExampleObject;
189
+ try {
190
+ responseExampleObject = JSON.parse(JSON.stringify(responseExample));
191
+ } catch {
192
+ return undefined;
193
+ }
194
+
195
+ if (typeof responseExampleObject === "object") {
196
+ let xmlExample;
197
+ try {
198
+ xmlExample = format(json2xml(responseExampleObject, ""), {
199
+ indentation: " ",
200
+ lineSeparator: "\n",
201
+ collapseContent: true,
202
+ });
203
+ } catch {
204
+ const xmlExampleWithRoot = { root: responseExampleObject };
205
+ try {
206
+ xmlExample = format(json2xml(xmlExampleWithRoot, ""), {
207
+ indentation: " ",
208
+ lineSeparator: "\n",
209
+ collapseContent: true,
210
+ });
211
+ } catch {
212
+ xmlExample = json2xml(responseExampleObject, "");
213
+ }
214
+ }
215
+ return create("TabItem", {
216
+ label: `Example (from schema)`,
217
+ value: `Example (from schema)`,
218
+ children: [
219
+ create("ResponseSamples", {
220
+ responseExample: xmlExample,
221
+ language: "xml",
222
+ }),
223
+ ],
224
+ });
225
+ }
226
+ }
227
+ if (typeof responseExample === "object") {
228
+ return create("TabItem", {
229
+ label: `Example (from schema)`,
230
+ value: `Example (from schema)`,
231
+ children: [
232
+ create("ResponseSamples", {
233
+ responseExample: JSON.stringify(responseExample, null, 2),
234
+ language: "json",
235
+ }),
236
+ ],
237
+ });
238
+ }
239
+ return undefined;
240
+ }
241
+
124
242
  export function createStatusCodes({ responses }: Props) {
125
243
  if (responses === undefined) {
126
244
  return undefined;
@@ -147,8 +265,8 @@ export function createStatusCodes({ responses }: Props) {
147
265
  }),
148
266
  responseHeaders &&
149
267
  createDetails({
150
- "data-collaposed": false,
151
- open: true,
268
+ "data-collaposed": true,
269
+ open: false,
152
270
  style: { textAlign: "left", marginBottom: "1rem" },
153
271
  children: [
154
272
  createDetailsSummary({
@@ -51,14 +51,48 @@ const primitives: Primitives = {
51
51
  array: {},
52
52
  };
53
53
 
54
- export const sampleFromSchema = (schema: SchemaObject = {}): any => {
54
+ function sampleRequestFromProp(name: string, prop: any, obj: any): any {
55
+ // Handle resolved circular props
56
+ if (typeof prop === "object" && Object.keys(prop).length === 0) {
57
+ obj[name] = prop;
58
+ return obj;
59
+ }
60
+
61
+ // TODO: handle discriminators
62
+
63
+ if (prop.oneOf) {
64
+ obj[name] = sampleRequestFromSchema(prop.oneOf[0]);
65
+ } else if (prop.anyOf) {
66
+ obj[name] = sampleRequestFromSchema(prop.anyOf[0]);
67
+ } else if (prop.allOf) {
68
+ const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
69
+ prop.allOf
70
+ );
71
+ sampleRequestFromProp(name, mergedSchemas, obj);
72
+ } else {
73
+ obj[name] = sampleRequestFromSchema(prop);
74
+ }
75
+ return obj;
76
+ }
77
+
78
+ export const sampleRequestFromSchema = (schema: SchemaObject = {}): any => {
55
79
  try {
56
- let { type, example, allOf, properties, items } = schema;
80
+ let { type, example, allOf, properties, items, oneOf, anyOf } = schema;
57
81
 
58
82
  if (example !== undefined) {
59
83
  return example;
60
84
  }
61
85
 
86
+ if (oneOf) {
87
+ // Just go with first schema
88
+ return sampleRequestFromSchema(oneOf[0]);
89
+ }
90
+
91
+ if (anyOf) {
92
+ // Just go with first schema
93
+ return sampleRequestFromSchema(anyOf[0]);
94
+ }
95
+
62
96
  if (allOf) {
63
97
  const { mergedSchemas }: { mergedSchemas: SchemaObject } =
64
98
  mergeAllOf(allOf);
@@ -69,7 +103,7 @@ export const sampleFromSchema = (schema: SchemaObject = {}): any => {
69
103
  }
70
104
  }
71
105
  }
72
- return sampleFromSchema(mergedSchemas);
106
+ return sampleRequestFromSchema(mergedSchemas);
73
107
  }
74
108
 
75
109
  if (!type) {
@@ -104,21 +138,23 @@ export const sampleFromSchema = (schema: SchemaObject = {}): any => {
104
138
  if (prop.deprecated) {
105
139
  continue;
106
140
  }
107
- obj[name] = sampleFromSchema(prop);
141
+
142
+ // Resolve schema from prop recursively
143
+ obj = sampleRequestFromProp(name, prop, obj);
108
144
  }
109
145
  return obj;
110
146
  }
111
147
 
112
148
  if (type === "array") {
113
149
  if (Array.isArray(items?.anyOf)) {
114
- return items?.anyOf.map((item) => sampleFromSchema(item));
150
+ return items?.anyOf.map((item) => sampleRequestFromSchema(item));
115
151
  }
116
152
 
117
153
  if (Array.isArray(items?.oneOf)) {
118
- return items?.oneOf.map((item) => sampleFromSchema(item));
154
+ return items?.oneOf.map((item) => sampleRequestFromSchema(item));
119
155
  }
120
156
 
121
- return [sampleFromSchema(items)];
157
+ return [sampleRequestFromSchema(items)];
122
158
  }
123
159
 
124
160
  if (schema.enum) {