docusaurus-plugin-openapi-docs 0.0.0-430 → 0.0.0-434

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.
@@ -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) {
@@ -0,0 +1,205 @@
1
+ /* ============================================================================
2
+ * Copyright (c) Palo Alto Networks
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ * ========================================================================== */
7
+
8
+ import chalk from "chalk";
9
+
10
+ import { mergeAllOf } from "../markdown/createResponseSchema";
11
+ import { SchemaObject } from "./types";
12
+
13
+ interface OASTypeToTypeMap {
14
+ string: string;
15
+ number: number;
16
+ integer: number;
17
+ boolean: boolean;
18
+ object: any;
19
+ array: any[];
20
+ }
21
+
22
+ type Primitives = {
23
+ [OASType in keyof OASTypeToTypeMap]: {
24
+ [format: string]: (schema: SchemaObject) => OASTypeToTypeMap[OASType];
25
+ };
26
+ };
27
+
28
+ const primitives: Primitives = {
29
+ string: {
30
+ default: () => "string",
31
+ email: () => "user@example.com",
32
+ date: () => new Date().toISOString().substring(0, 10),
33
+ "date-time": () => new Date().toISOString().substring(0, 10),
34
+ uuid: () => "3fa85f64-5717-4562-b3fc-2c963f66afa6",
35
+ hostname: () => "example.com",
36
+ ipv4: () => "198.51.100.42",
37
+ ipv6: () => "2001:0db8:5b96:0000:0000:426f:8e17:642a",
38
+ },
39
+ number: {
40
+ default: () => 0,
41
+ float: () => 0.0,
42
+ },
43
+ integer: {
44
+ default: () => 0,
45
+ },
46
+ boolean: {
47
+ default: (schema) =>
48
+ typeof schema.default === "boolean" ? schema.default : true,
49
+ },
50
+ object: {},
51
+ array: {},
52
+ };
53
+
54
+ function sampleResponseFromProp(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] = sampleResponseFromSchema(prop.oneOf[0]);
65
+ } else if (prop.anyOf) {
66
+ obj[name] = sampleResponseFromSchema(prop.anyOf[0]);
67
+ } else if (prop.allOf) {
68
+ const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
69
+ prop.allOf
70
+ );
71
+ sampleResponseFromProp(name, mergedSchemas, obj);
72
+ } else {
73
+ obj[name] = sampleResponseFromSchema(prop);
74
+ }
75
+ return obj;
76
+ }
77
+
78
+ export const sampleResponseFromSchema = (schema: SchemaObject = {}): any => {
79
+ try {
80
+ let { type, example, allOf, oneOf, anyOf, properties, items } = schema;
81
+
82
+ if (example !== undefined) {
83
+ return example;
84
+ }
85
+
86
+ if (allOf) {
87
+ const { mergedSchemas }: { mergedSchemas: SchemaObject } =
88
+ mergeAllOf(allOf);
89
+ if (mergedSchemas.properties) {
90
+ for (const [key, value] of Object.entries(mergedSchemas.properties)) {
91
+ if (value.readOnly && value.readOnly === true) {
92
+ delete mergedSchemas.properties[key];
93
+ }
94
+ }
95
+ }
96
+ return sampleResponseFromSchema(mergedSchemas);
97
+ }
98
+
99
+ if (oneOf) {
100
+ // Just go with first schema
101
+ return sampleResponseFromSchema(oneOf[0]);
102
+ }
103
+
104
+ if (anyOf) {
105
+ // Just go with first schema
106
+ return sampleResponseFromSchema(anyOf[0]);
107
+ }
108
+
109
+ if (!type) {
110
+ if (properties) {
111
+ type = "object";
112
+ } else if (items) {
113
+ type = "array";
114
+ } else {
115
+ return;
116
+ }
117
+ }
118
+
119
+ if (type === "object") {
120
+ let obj: any = {};
121
+ for (let [name, prop] of Object.entries(properties ?? {})) {
122
+ if (prop.properties) {
123
+ for (const [key, value] of Object.entries(prop.properties)) {
124
+ if (value.readOnly && value.readOnly === true) {
125
+ delete prop.properties[key];
126
+ }
127
+ }
128
+ }
129
+
130
+ if (prop.items && prop.items.properties) {
131
+ for (const [key, value] of Object.entries(prop.items.properties)) {
132
+ if (value.readOnly && value.readOnly === true) {
133
+ delete prop.items.properties[key];
134
+ }
135
+ }
136
+ }
137
+
138
+ if (prop.deprecated) {
139
+ continue;
140
+ }
141
+
142
+ // Resolve schema from prop recursively
143
+ obj = sampleResponseFromProp(name, prop, obj);
144
+ }
145
+ return obj;
146
+ }
147
+
148
+ if (type === "array") {
149
+ if (Array.isArray(items?.anyOf)) {
150
+ return items?.anyOf.map((item) => sampleResponseFromSchema(item));
151
+ }
152
+
153
+ if (Array.isArray(items?.oneOf)) {
154
+ return items?.oneOf.map((item) => sampleResponseFromSchema(item));
155
+ }
156
+
157
+ return [sampleResponseFromSchema(items)];
158
+ }
159
+
160
+ if (schema.enum) {
161
+ if (schema.default) {
162
+ return schema.default;
163
+ }
164
+ return normalizeArray(schema.enum)[0];
165
+ }
166
+
167
+ if (schema.writeOnly && schema.writeOnly === true) {
168
+ return undefined;
169
+ }
170
+
171
+ return primitive(schema);
172
+ } catch (err) {
173
+ console.error(
174
+ chalk.yellow("WARNING: failed to create example from schema object:", err)
175
+ );
176
+ return;
177
+ }
178
+ };
179
+
180
+ function primitive(schema: SchemaObject = {}) {
181
+ let { type, format } = schema;
182
+
183
+ if (type === undefined) {
184
+ return;
185
+ }
186
+
187
+ let fn = schema.default ? () => schema.default : primitives[type].default;
188
+
189
+ if (format !== undefined) {
190
+ fn = primitives[type][format] || fn;
191
+ }
192
+
193
+ if (fn) {
194
+ return fn(schema);
195
+ }
196
+
197
+ return "Unknown Type: " + schema.type;
198
+ }
199
+
200
+ function normalizeArray(arr: any) {
201
+ if (Array.isArray(arr)) {
202
+ return arr;
203
+ }
204
+ return [arr];
205
+ }
@@ -25,7 +25,7 @@ import {
25
25
  SidebarOptions,
26
26
  TagPageMetadata,
27
27
  } from "../types";
28
- import { sampleFromSchema } from "./createExample";
28
+ import { sampleRequestFromSchema } from "./createRequestExample";
29
29
  import { OpenApiObject, TagObject } from "./types";
30
30
  import { loadAndResolveSpec } from "./utils/loadAndResolveSpec";
31
31
 
@@ -170,7 +170,7 @@ function createItems(
170
170
  let jsonRequestBodyExample;
171
171
  const body = operationObject.requestBody?.content?.["application/json"];
172
172
  if (body?.schema) {
173
- jsonRequestBodyExample = sampleFromSchema(body.schema);
173
+ jsonRequestBodyExample = sampleRequestFromSchema(body.schema);
174
174
  }
175
175
 
176
176
  // Handle vendor JSON media types
@@ -180,7 +180,7 @@ function createItems(
180
180
  if (firstBodyContentKey.endsWith("+json")) {
181
181
  const firstBody = bodyContent[firstBodyContentKey];
182
182
  if (firstBody?.schema) {
183
- jsonRequestBodyExample = sampleFromSchema(firstBody.schema);
183
+ jsonRequestBodyExample = sampleRequestFromSchema(firstBody.schema);
184
184
  }
185
185
  }
186
186
  }
@@ -1,2 +0,0 @@
1
- import { SchemaObject } from "./types";
2
- export declare const sampleFromSchema: (schema?: SchemaObject) => any;