Skip to content

Commit 8be84a9

Browse files
committed
Merge branch 'support-schema-property-examples' into change-anyOf-oneOf-tab-label
2 parents eef06ad + a6288c4 commit 8be84a9

File tree

15 files changed

+1184
-851
lines changed

15 files changed

+1184
-851
lines changed

demo/examples/tests/examples.yaml

Lines changed: 491 additions & 0 deletions
Large diffs are not rendered by default.

packages/docusaurus-plugin-openapi-docs/src/openapi/createRequestExample.ts

Lines changed: 2 additions & 251 deletions
Original file line numberDiff line numberDiff line change
@@ -5,258 +5,9 @@
55
* LICENSE file in the root directory of this source tree.
66
* ========================================================================== */
77

8-
import chalk from "chalk";
9-
import merge from "lodash/merge";
10-
8+
import { sampleFromSchema } from "./createSchemaExample";
119
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: () => "[email protected]",
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-
function sampleRequestFromProp(name: string, prop: any, obj: any): any {
60-
// Handle resolved circular props
61-
if (typeof prop === "object" && Object.keys(prop).length === 0) {
62-
obj[name] = prop;
63-
return obj;
64-
}
65-
66-
// TODO: handle discriminators
67-
68-
if (prop.oneOf) {
69-
obj[name] = sampleRequestFromSchema(prop.oneOf[0]);
70-
} else if (prop.anyOf) {
71-
obj[name] = sampleRequestFromSchema(prop.anyOf[0]);
72-
} else if (prop.allOf) {
73-
const mergedSchemas = mergeAllOf(prop) as SchemaObject;
74-
sampleRequestFromProp(name, mergedSchemas, obj);
75-
} else {
76-
obj[name] = sampleRequestFromSchema(prop);
77-
}
78-
return obj;
79-
}
8010

8111
export const sampleRequestFromSchema = (schema: SchemaObject = {}): any => {
82-
try {
83-
// deep copy schema before processing
84-
let schemaCopy = JSON.parse(JSON.stringify(schema));
85-
let { type, example, allOf, properties, items, oneOf, anyOf } = schemaCopy;
86-
87-
if (example !== undefined) {
88-
return example;
89-
}
90-
91-
if (oneOf) {
92-
if (properties) {
93-
const combinedSchemas = merge(schemaCopy, oneOf[0]);
94-
delete combinedSchemas.oneOf;
95-
return sampleRequestFromSchema(combinedSchemas);
96-
}
97-
// Just go with first schema
98-
return sampleRequestFromSchema(oneOf[0]);
99-
}
100-
101-
if (anyOf) {
102-
if (properties) {
103-
const combinedSchemas = merge(schemaCopy, anyOf[0]);
104-
delete combinedSchemas.anyOf;
105-
return sampleRequestFromSchema(combinedSchemas);
106-
}
107-
// Just go with first schema
108-
return sampleRequestFromSchema(anyOf[0]);
109-
}
110-
111-
if (allOf) {
112-
const mergedSchemas = mergeAllOf(schemaCopy) as SchemaObject;
113-
if (mergedSchemas.properties) {
114-
for (const [key, value] of Object.entries(mergedSchemas.properties)) {
115-
if ((value.readOnly && value.readOnly === true) || value.deprecated) {
116-
delete mergedSchemas.properties[key];
117-
}
118-
}
119-
}
120-
if (properties) {
121-
const combinedSchemas = merge(schemaCopy, mergedSchemas);
122-
delete combinedSchemas.allOf;
123-
return sampleRequestFromSchema(combinedSchemas);
124-
}
125-
return sampleRequestFromSchema(mergedSchemas);
126-
}
127-
128-
if (!type) {
129-
if (properties) {
130-
type = "object";
131-
} else if (items) {
132-
type = "array";
133-
} else {
134-
return;
135-
}
136-
}
137-
138-
if (type === "object") {
139-
let obj: any = {};
140-
for (let [name, prop] of Object.entries(properties ?? {}) as any) {
141-
if (prop.properties) {
142-
for (const [key, value] of Object.entries(prop.properties) as any) {
143-
if (
144-
(value.readOnly && value.readOnly === true) ||
145-
value.deprecated
146-
) {
147-
delete prop.properties[key];
148-
}
149-
}
150-
}
151-
152-
if (prop.items && prop.items.properties) {
153-
for (const [key, value] of Object.entries(
154-
prop.items.properties
155-
) as any) {
156-
if (
157-
(value.readOnly && value.readOnly === true) ||
158-
value.deprecated
159-
) {
160-
delete prop.items.properties[key];
161-
}
162-
}
163-
}
164-
165-
if (prop.readOnly && prop.readOnly === true) {
166-
continue;
167-
}
168-
169-
if (prop.deprecated) {
170-
continue;
171-
}
172-
173-
// Resolve schema from prop recursively
174-
obj = sampleRequestFromProp(name, prop, obj);
175-
}
176-
return obj;
177-
}
178-
179-
if (type === "array") {
180-
if (Array.isArray(items?.anyOf)) {
181-
return processArrayItems(items, "anyOf");
182-
}
183-
184-
if (Array.isArray(items?.oneOf)) {
185-
return processArrayItems(items, "oneOf");
186-
}
187-
188-
return normalizeArray(sampleRequestFromSchema(items));
189-
}
190-
191-
if (schemaCopy.enum) {
192-
if (schemaCopy.default) {
193-
return schemaCopy.default;
194-
}
195-
return normalizeArray(schemaCopy.enum)[0];
196-
}
197-
198-
if (
199-
(schema.readOnly && schema.readOnly === true) ||
200-
schemaCopy.deprecated
201-
) {
202-
return undefined;
203-
}
204-
205-
return primitive(schemaCopy);
206-
} catch (err) {
207-
console.error(
208-
chalk.yellow("WARNING: failed to create example from schema object:", err)
209-
);
210-
return;
211-
}
12+
return sampleFromSchema(schema, { type: "request" });
21213
};
213-
214-
function primitive(schema: SchemaObject = {}) {
215-
let { type, format } = schema;
216-
217-
if (type === undefined) {
218-
return;
219-
}
220-
221-
let fn = schema.default ? () => schema.default : primitives[type].default;
222-
223-
if (format !== undefined) {
224-
fn = primitives[type][format] || fn;
225-
}
226-
227-
if (fn) {
228-
return fn(schema);
229-
}
230-
231-
return "Unknown Type: " + schema.type;
232-
}
233-
234-
function normalizeArray(arr: any) {
235-
if (Array.isArray(arr)) {
236-
return arr;
237-
}
238-
return [arr];
239-
}
240-
241-
function processArrayItems(
242-
items: SchemaObject,
243-
schemaType: "anyOf" | "oneOf"
244-
): any[] {
245-
const itemsArray = items[schemaType] as SchemaObject[];
246-
return itemsArray.map((item: SchemaObject) => {
247-
// If items has properties, merge them with each item
248-
if (items.properties) {
249-
const combinedSchema = {
250-
...item,
251-
properties: {
252-
...items.properties, // Common properties from parent
253-
...item.properties, // Specific properties from this anyOf/oneOf item
254-
},
255-
};
256-
// Remove anyOf/oneOf to prevent infinite recursion when calling sampleRequestFromSchema
257-
delete combinedSchema[schemaType];
258-
return sampleRequestFromSchema(combinedSchema);
259-
}
260-
return sampleRequestFromSchema(item);
261-
});
262-
}

0 commit comments

Comments
 (0)