docusaurus-plugin-openapi-docs 0.0.0-1011 → 0.0.0-1012
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/lib/openapi/createRequestExample.js +2 -201
- package/lib/openapi/createResponseExample.js +2 -202
- package/lib/openapi/createSchemaExample.d.ts +7 -0
- package/lib/openapi/createSchemaExample.js +231 -0
- package/package.json +2 -2
- package/src/openapi/createRequestExample.ts +2 -251
- package/src/openapi/createResponseExample.ts +2 -254
- package/src/openapi/createSchemaExample.ts +292 -0
|
@@ -0,0 +1,292 @@
|
|
|
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
|
+
import merge from "lodash/merge";
|
|
10
|
+
|
|
11
|
+
import { SchemaObject } from "./types";
|
|
12
|
+
import { mergeAllOf } from "../markdown/createSchema";
|
|
13
|
+
|
|
14
|
+
interface OASTypeToTypeMap {
|
|
15
|
+
string: string;
|
|
16
|
+
number: number;
|
|
17
|
+
integer: number;
|
|
18
|
+
boolean: boolean;
|
|
19
|
+
object: any;
|
|
20
|
+
array: any[];
|
|
21
|
+
null: string | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type Primitives = {
|
|
25
|
+
[OASType in keyof OASTypeToTypeMap]: {
|
|
26
|
+
[format: string]: (schema: SchemaObject) => OASTypeToTypeMap[OASType];
|
|
27
|
+
};
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
const primitives: Primitives = {
|
|
31
|
+
string: {
|
|
32
|
+
default: () => "string",
|
|
33
|
+
email: () => "user@example.com",
|
|
34
|
+
date: () => "2024-07-29",
|
|
35
|
+
"date-time": () => "2024-07-29T15:51:28.071Z",
|
|
36
|
+
uuid: () => "3fa85f64-5717-4562-b3fc-2c963f66afa6",
|
|
37
|
+
hostname: () => "example.com",
|
|
38
|
+
ipv4: () => "198.51.100.42",
|
|
39
|
+
ipv6: () => "2001:0db8:5b96:0000:0000:426f:8e17:642a",
|
|
40
|
+
},
|
|
41
|
+
number: {
|
|
42
|
+
default: () => 0,
|
|
43
|
+
float: () => 0.0,
|
|
44
|
+
},
|
|
45
|
+
integer: {
|
|
46
|
+
default: () => 0,
|
|
47
|
+
},
|
|
48
|
+
boolean: {
|
|
49
|
+
default: (schema) =>
|
|
50
|
+
typeof schema.default === "boolean" ? schema.default : true,
|
|
51
|
+
},
|
|
52
|
+
object: {},
|
|
53
|
+
array: {},
|
|
54
|
+
null: {
|
|
55
|
+
default: () => "null",
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
type ExampleType = "request" | "response";
|
|
60
|
+
|
|
61
|
+
interface ExampleContext {
|
|
62
|
+
type: ExampleType;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function shouldExcludeProperty(
|
|
66
|
+
prop: SchemaObject,
|
|
67
|
+
context: ExampleContext
|
|
68
|
+
): boolean {
|
|
69
|
+
if (prop.deprecated) {
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
if (context.type === "request") {
|
|
74
|
+
return prop.readOnly === true;
|
|
75
|
+
} else {
|
|
76
|
+
return prop.writeOnly === true;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function sampleFromProp(
|
|
81
|
+
name: string,
|
|
82
|
+
prop: any,
|
|
83
|
+
obj: any,
|
|
84
|
+
context: ExampleContext
|
|
85
|
+
): any {
|
|
86
|
+
// Handle resolved circular props
|
|
87
|
+
if (typeof prop === "object" && Object.keys(prop).length === 0) {
|
|
88
|
+
obj[name] = prop;
|
|
89
|
+
return obj;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
// TODO: handle discriminators
|
|
93
|
+
|
|
94
|
+
if (prop.oneOf) {
|
|
95
|
+
obj[name] = sampleFromSchema(prop.oneOf[0], context);
|
|
96
|
+
} else if (prop.anyOf) {
|
|
97
|
+
obj[name] = sampleFromSchema(prop.anyOf[0], context);
|
|
98
|
+
} else if (prop.allOf) {
|
|
99
|
+
const mergedSchemas = mergeAllOf(prop) as SchemaObject;
|
|
100
|
+
sampleFromProp(name, mergedSchemas, obj, context);
|
|
101
|
+
} else {
|
|
102
|
+
obj[name] = sampleFromSchema(prop, context);
|
|
103
|
+
}
|
|
104
|
+
return obj;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export const sampleFromSchema = (
|
|
108
|
+
schema: SchemaObject = {},
|
|
109
|
+
context: ExampleContext
|
|
110
|
+
): any => {
|
|
111
|
+
try {
|
|
112
|
+
// deep copy schema before processing
|
|
113
|
+
let schemaCopy = JSON.parse(JSON.stringify(schema));
|
|
114
|
+
let { type, example, allOf, properties, items, oneOf, anyOf } = schemaCopy;
|
|
115
|
+
|
|
116
|
+
if (example !== undefined) {
|
|
117
|
+
return example;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (oneOf) {
|
|
121
|
+
if (properties) {
|
|
122
|
+
const combinedSchemas = merge(schemaCopy, oneOf[0]);
|
|
123
|
+
delete combinedSchemas.oneOf;
|
|
124
|
+
return sampleFromSchema(combinedSchemas, context);
|
|
125
|
+
}
|
|
126
|
+
// Just go with first schema
|
|
127
|
+
return sampleFromSchema(oneOf[0], context);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
if (anyOf) {
|
|
131
|
+
if (properties) {
|
|
132
|
+
const combinedSchemas = merge(schemaCopy, anyOf[0]);
|
|
133
|
+
delete combinedSchemas.anyOf;
|
|
134
|
+
return sampleFromSchema(combinedSchemas, context);
|
|
135
|
+
}
|
|
136
|
+
// Just go with first schema
|
|
137
|
+
return sampleFromSchema(anyOf[0], context);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (allOf) {
|
|
141
|
+
const mergedSchemas = mergeAllOf(schemaCopy) as SchemaObject;
|
|
142
|
+
if (mergedSchemas.properties) {
|
|
143
|
+
for (const [key, value] of Object.entries(mergedSchemas.properties)) {
|
|
144
|
+
if (shouldExcludeProperty(value, context)) {
|
|
145
|
+
delete mergedSchemas.properties[key];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (properties) {
|
|
150
|
+
const combinedSchemas = merge(schemaCopy, mergedSchemas);
|
|
151
|
+
delete combinedSchemas.allOf;
|
|
152
|
+
return sampleFromSchema(combinedSchemas, context);
|
|
153
|
+
}
|
|
154
|
+
return sampleFromSchema(mergedSchemas, context);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (!type) {
|
|
158
|
+
if (properties) {
|
|
159
|
+
type = "object";
|
|
160
|
+
} else if (items) {
|
|
161
|
+
type = "array";
|
|
162
|
+
} else {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (type === "object") {
|
|
168
|
+
let obj: any = {};
|
|
169
|
+
for (let [name, prop] of Object.entries(properties ?? {}) as any) {
|
|
170
|
+
if (prop.properties) {
|
|
171
|
+
for (const [key, value] of Object.entries(prop.properties) as any) {
|
|
172
|
+
if (shouldExcludeProperty(value, context)) {
|
|
173
|
+
delete prop.properties[key];
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (prop.items && prop.items.properties) {
|
|
179
|
+
for (const [key, value] of Object.entries(
|
|
180
|
+
prop.items.properties
|
|
181
|
+
) as any) {
|
|
182
|
+
if (shouldExcludeProperty(value, context)) {
|
|
183
|
+
delete prop.items.properties[key];
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (shouldExcludeProperty(prop, context)) {
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// Resolve schema from prop recursively
|
|
193
|
+
obj = sampleFromProp(name, prop, obj, context);
|
|
194
|
+
}
|
|
195
|
+
return obj;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (type === "array") {
|
|
199
|
+
if (Array.isArray(items?.anyOf)) {
|
|
200
|
+
return processArrayItems(items, "anyOf", context);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (Array.isArray(items?.oneOf)) {
|
|
204
|
+
return processArrayItems(items, "oneOf", context);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return normalizeArray(sampleFromSchema(items, context));
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
if (schemaCopy.enum) {
|
|
211
|
+
if (schemaCopy.default) {
|
|
212
|
+
return schemaCopy.default;
|
|
213
|
+
}
|
|
214
|
+
return normalizeArray(schemaCopy.enum)[0];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (shouldExcludeProperty(schemaCopy, context)) {
|
|
218
|
+
return undefined;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
return primitive(schemaCopy);
|
|
222
|
+
} catch (err) {
|
|
223
|
+
console.error(
|
|
224
|
+
chalk.yellow("WARNING: failed to create example from schema object:", err)
|
|
225
|
+
);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
function primitive(schema: SchemaObject = {}) {
|
|
231
|
+
let { type, format } = schema;
|
|
232
|
+
|
|
233
|
+
if (type === undefined) {
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// If type is an array, use the first type
|
|
238
|
+
if (Array.isArray(type)) {
|
|
239
|
+
type = type[0];
|
|
240
|
+
if (type === undefined) {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Use schema default if available, otherwise use type default
|
|
246
|
+
if (schema.default !== undefined) {
|
|
247
|
+
return schema.default;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const typeConfig = primitives[type];
|
|
251
|
+
if (typeConfig) {
|
|
252
|
+
if (format !== undefined && typeConfig[format] !== undefined) {
|
|
253
|
+
return typeConfig[format](schema);
|
|
254
|
+
}
|
|
255
|
+
if (typeConfig.default !== undefined) {
|
|
256
|
+
return typeConfig.default(schema);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return "Unknown Type: " + schema.type;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
function normalizeArray(arr: any) {
|
|
264
|
+
if (Array.isArray(arr)) {
|
|
265
|
+
return arr;
|
|
266
|
+
}
|
|
267
|
+
return [arr];
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function processArrayItems(
|
|
271
|
+
items: SchemaObject,
|
|
272
|
+
schemaType: "anyOf" | "oneOf",
|
|
273
|
+
context: ExampleContext
|
|
274
|
+
): any[] {
|
|
275
|
+
const itemsArray = items[schemaType] as SchemaObject[];
|
|
276
|
+
return itemsArray.map((item: SchemaObject) => {
|
|
277
|
+
// If items has properties, merge them with each item
|
|
278
|
+
if (items.properties) {
|
|
279
|
+
const combinedSchema = {
|
|
280
|
+
...item,
|
|
281
|
+
properties: {
|
|
282
|
+
...items.properties, // Common properties from parent
|
|
283
|
+
...item.properties, // Specific properties from this anyOf/oneOf item
|
|
284
|
+
},
|
|
285
|
+
};
|
|
286
|
+
// Remove anyOf/oneOf to prevent infinite recursion when calling sampleFromSchema
|
|
287
|
+
delete combinedSchema[schemaType];
|
|
288
|
+
return sampleFromSchema(combinedSchema, context);
|
|
289
|
+
}
|
|
290
|
+
return sampleFromSchema(item, context);
|
|
291
|
+
});
|
|
292
|
+
}
|