docusaurus-plugin-openapi-docs 2.2.1 → 2.2.2

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/README.md CHANGED
@@ -50,7 +50,7 @@ Key Features:
50
50
  Run the following to bootstrap a Docsaurus v3 site (classic theme) with `docusaurus-openapi-docs`:
51
51
 
52
52
  ```bash
53
- npx create-docusaurus@3.4.0 my-website --package-manager yarn
53
+ npx create-docusaurus@2.4.3 my-website --package-manager yarn
54
54
  ```
55
55
 
56
56
  > When prompted to select a template choose `Git repository`.
package/lib/index.js CHANGED
@@ -375,6 +375,15 @@ custom_edit_url: null
375
375
  downloadUrl: metadata.downloadUrl,
376
376
  });
377
377
  }
378
+ if (!fs_1.default.existsSync(outputDir)) {
379
+ try {
380
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
381
+ console.log(chalk_1.default.green(`Successfully created "${outputDir}"`));
382
+ }
383
+ catch (err) {
384
+ console.error(chalk_1.default.red(`Failed to create "${outputDir}"`), chalk_1.default.yellow(err));
385
+ }
386
+ }
378
387
  const versionsJson = JSON.stringify(versionsArray, null, 2);
379
388
  try {
380
389
  fs_1.default.writeFileSync(`${outputDir}/versions.json`, versionsJson, "utf8");
@@ -67,6 +67,12 @@ function createAnyOneOf(schema) {
67
67
  ? anyOneSchema.title
68
68
  : `MOD${index + 1}`;
69
69
  const anyOneChildren = [];
70
+ if (anyOneSchema.type === "object" &&
71
+ !anyOneSchema.properties &&
72
+ !anyOneSchema.allOf &&
73
+ !anyOneSchema.items) {
74
+ anyOneChildren.push(createNodes(anyOneSchema, SCHEMA_TYPE));
75
+ }
70
76
  if (anyOneSchema.properties !== undefined) {
71
77
  anyOneChildren.push(createProperties(anyOneSchema));
72
78
  delete anyOneSchema.properties;
@@ -510,6 +516,19 @@ function createEdges({ name, schema, required, discriminator, }) {
510
516
  if (schema.oneOf !== undefined || schema.anyOf !== undefined) {
511
517
  return createAnyOneOfProperty(name, schemaName, schema, required, schema.nullable);
512
518
  }
519
+ if (schema.properties !== undefined) {
520
+ return createDetailsNode(name, schemaName, schema, required, schema.nullable);
521
+ }
522
+ if (schema.additionalProperties !== undefined) {
523
+ return createDetailsNode(name, schemaName, schema, required, schema.nullable);
524
+ }
525
+ // array of objects
526
+ if (((_a = schema.items) === null || _a === void 0 ? void 0 : _a.properties) !== undefined) {
527
+ return createDetailsNode(name, schemaName, schema, required, schema.nullable);
528
+ }
529
+ if (((_b = schema.items) === null || _b === void 0 ? void 0 : _b.anyOf) !== undefined || ((_c = schema.items) === null || _c === void 0 ? void 0 : _c.oneOf) !== undefined) {
530
+ return createDetailsNode(name, schemaName, schema, required, schema.nullable);
531
+ }
513
532
  if (schema.allOf !== undefined) {
514
533
  const { mergedSchemas } = mergeAllOf(schema.allOf);
515
534
  if (SCHEMA_TYPE === "request") {
@@ -534,7 +553,7 @@ function createEdges({ name, schema, required, discriminator, }) {
534
553
  return createDetailsNode(name, mergedSchemaName, mergedSchemas, required, schema.nullable);
535
554
  }
536
555
  // array of objects
537
- if (((_a = mergedSchemas.items) === null || _a === void 0 ? void 0 : _a.properties) !== undefined) {
556
+ if (((_d = mergedSchemas.items) === null || _d === void 0 ? void 0 : _d.properties) !== undefined) {
538
557
  return createDetailsNode(name, mergedSchemaName, mergedSchemas, required, schema.nullable);
539
558
  }
540
559
  return (0, utils_1.create)("SchemaItem", {
@@ -546,19 +565,6 @@ function createEdges({ name, schema, required, discriminator, }) {
546
565
  schema: mergedSchemas,
547
566
  });
548
567
  }
549
- if (schema.properties !== undefined) {
550
- return createDetailsNode(name, schemaName, schema, required, schema.nullable);
551
- }
552
- if (schema.additionalProperties !== undefined) {
553
- return createDetailsNode(name, schemaName, schema, required, schema.nullable);
554
- }
555
- // array of objects
556
- if (((_b = schema.items) === null || _b === void 0 ? void 0 : _b.properties) !== undefined) {
557
- return createDetailsNode(name, schemaName, schema, required, schema.nullable);
558
- }
559
- if (((_c = schema.items) === null || _c === void 0 ? void 0 : _c.anyOf) !== undefined || ((_d = schema.items) === null || _d === void 0 ? void 0 : _d.oneOf) !== undefined) {
560
- return createDetailsNode(name, schemaName, schema, required, schema.nullable);
561
- }
562
568
  // primitives and array of non-objects
563
569
  return (0, utils_1.create)("SchemaItem", {
564
570
  collapsible: false,
@@ -591,13 +597,6 @@ function createNodes(schema, schemaType) {
591
597
  if (schema.oneOf !== undefined || schema.anyOf !== undefined) {
592
598
  nodes.push(createAnyOneOf(schema));
593
599
  }
594
- if (schema.allOf !== undefined) {
595
- const { mergedSchemas } = mergeAllOf(schema.allOf);
596
- // allOf seems to always result in properties
597
- if (mergedSchemas.properties !== undefined) {
598
- nodes.push(createProperties(mergedSchemas));
599
- }
600
- }
601
600
  if (schema.properties !== undefined) {
602
601
  nodes.push(createProperties(schema));
603
602
  }
@@ -608,6 +607,13 @@ function createNodes(schema, schemaType) {
608
607
  if (schema.items !== undefined) {
609
608
  nodes.push(createItems(schema));
610
609
  }
610
+ if (schema.allOf !== undefined) {
611
+ const { mergedSchemas } = mergeAllOf(schema.allOf);
612
+ // allOf seems to always result in properties
613
+ if (mergedSchemas.properties !== undefined) {
614
+ nodes.push(createProperties(mergedSchemas));
615
+ }
616
+ }
611
617
  if (nodes.length && nodes.length > 0) {
612
618
  return nodes.filter(Boolean).flat();
613
619
  }
@@ -32,43 +32,261 @@ Object.defineProperty(exports, "__esModule", { value: true });
32
32
  const prettier = __importStar(require("prettier"));
33
33
  const createSchema_1 = require("./createSchema");
34
34
  describe("createNodes", () => {
35
- it("should create readable MODs for oneOf primitive properties", () => {
36
- const schema = {
37
- "x-tags": ["clown"],
38
- type: "object",
39
- properties: {
40
- oneOfProperty: {
41
- oneOf: [
42
- {
43
- type: "object",
44
- properties: {
45
- noseLength: {
46
- type: "number",
35
+ describe("oneOf", () => {
36
+ it("should create readable MODs for oneOf primitive properties", async () => {
37
+ const schema = {
38
+ "x-tags": ["clown"],
39
+ type: "object",
40
+ properties: {
41
+ oneOfProperty: {
42
+ oneOf: [
43
+ {
44
+ type: "object",
45
+ properties: {
46
+ noseLength: {
47
+ type: "number",
48
+ },
47
49
  },
50
+ required: ["noseLength"],
51
+ description: "Clown's nose length",
52
+ },
53
+ {
54
+ type: "array",
55
+ items: {
56
+ type: "string",
57
+ },
58
+ description: "Array of strings",
59
+ },
60
+ {
61
+ type: "boolean",
62
+ },
63
+ {
64
+ type: "number",
65
+ },
66
+ {
67
+ type: "string",
68
+ },
69
+ ],
70
+ },
71
+ },
72
+ };
73
+ expect(await Promise.all((0, createSchema_1.createNodes)(schema, "request").map(async (md) => await prettier.format(md, { parser: "babel" })))).toMatchSnapshot();
74
+ });
75
+ });
76
+ describe("allOf", () => {
77
+ it("should render same-level properties with allOf", async () => {
78
+ const schema = {
79
+ allOf: [
80
+ {
81
+ type: "object",
82
+ properties: {
83
+ allOfProp1: {
84
+ type: "string",
85
+ },
86
+ allOfProp2: {
87
+ type: "string",
48
88
  },
49
- required: ["noseLength"],
50
- description: "Clown's nose length",
51
89
  },
52
- {
53
- type: "array",
54
- items: {
90
+ },
91
+ ],
92
+ properties: {
93
+ parentProp1: {
94
+ type: "string",
95
+ },
96
+ parentProp2: {
97
+ type: "string",
98
+ },
99
+ },
100
+ };
101
+ expect(await Promise.all((0, createSchema_1.createNodes)(schema, "response").map(async (md) => await prettier.format(md, { parser: "babel" })))).toMatchSnapshot();
102
+ });
103
+ it("should correctly merge nested properties from multiple allOf schemas", async () => {
104
+ const schema = {
105
+ allOf: [
106
+ {
107
+ type: "object",
108
+ properties: {
109
+ outerProp1: {
110
+ type: "object",
111
+ properties: {
112
+ innerProp1: {
113
+ type: "string",
114
+ },
115
+ },
116
+ },
117
+ },
118
+ },
119
+ {
120
+ type: "object",
121
+ properties: {
122
+ outerProp2: {
123
+ type: "object",
124
+ properties: {
125
+ innerProp2: {
126
+ type: "number",
127
+ },
128
+ },
129
+ },
130
+ },
131
+ },
132
+ ],
133
+ };
134
+ expect(await Promise.all((0, createSchema_1.createNodes)(schema, "response").map(async (md) => await prettier.format(md, { parser: "babel" })))).toMatchSnapshot();
135
+ });
136
+ it("should correctly handle shared required properties across allOf schemas", async () => {
137
+ const schema = {
138
+ allOf: [
139
+ {
140
+ type: "object",
141
+ properties: {
142
+ sharedProp: {
55
143
  type: "string",
56
144
  },
57
- description: "Array of strings",
58
145
  },
59
- {
60
- type: "boolean",
146
+ required: ["sharedProp"],
147
+ },
148
+ {
149
+ type: "object",
150
+ properties: {
151
+ anotherProp: {
152
+ type: "number",
153
+ },
61
154
  },
62
- {
63
- type: "number",
155
+ required: ["anotherProp"],
156
+ },
157
+ ],
158
+ };
159
+ expect(await Promise.all((0, createSchema_1.createNodes)(schema, "response").map(async (md) => await prettier.format(md, { parser: "babel" })))).toMatchSnapshot();
160
+ });
161
+ // Could not resolve values for path:"properties.conflictingProp.type". They are probably incompatible. Values:
162
+ // "string"
163
+ // "number"
164
+ // eslint-disable-next-line jest/no-commented-out-tests
165
+ // it("should handle conflicting properties in allOf schemas", async () => {
166
+ // const schema: SchemaObject = {
167
+ // allOf: [
168
+ // {
169
+ // type: "object",
170
+ // properties: {
171
+ // conflictingProp: {
172
+ // type: "string",
173
+ // },
174
+ // },
175
+ // },
176
+ // {
177
+ // type: "object",
178
+ // properties: {
179
+ // conflictingProp: {
180
+ // type: "number",
181
+ // },
182
+ // },
183
+ // },
184
+ // ],
185
+ // };
186
+ // expect(
187
+ // await Promise.all(
188
+ // createNodes(schema, "response").map(
189
+ // async (md: any) => await prettier.format(md, { parser: "babel" })
190
+ // )
191
+ // )
192
+ // ).toMatchSnapshot();
193
+ // });
194
+ // Could not resolve values for path:"type". They are probably incompatible. Values:
195
+ // "object"
196
+ // "array"
197
+ // eslint-disable-next-line jest/no-commented-out-tests
198
+ // it("should handle mixed data types in allOf schemas", async () => {
199
+ // const schema: SchemaObject = {
200
+ // allOf: [
201
+ // {
202
+ // type: "object",
203
+ // properties: {
204
+ // mixedTypeProp1: {
205
+ // type: "string",
206
+ // },
207
+ // },
208
+ // },
209
+ // {
210
+ // type: "array",
211
+ // items: {
212
+ // type: "number",
213
+ // },
214
+ // },
215
+ // ],
216
+ // };
217
+ // expect(
218
+ // await Promise.all(
219
+ // createNodes(schema, "response").map(
220
+ // async (md: any) => await prettier.format(md, { parser: "babel" })
221
+ // )
222
+ // )
223
+ // ).toMatchSnapshot();
224
+ // });
225
+ it("should correctly deep merge properties in allOf schemas", async () => {
226
+ const schema = {
227
+ allOf: [
228
+ {
229
+ type: "object",
230
+ properties: {
231
+ deepProp: {
232
+ type: "object",
233
+ properties: {
234
+ innerProp1: {
235
+ type: "string",
236
+ },
237
+ },
238
+ },
64
239
  },
65
- {
66
- type: "string",
240
+ },
241
+ {
242
+ type: "object",
243
+ properties: {
244
+ deepProp: {
245
+ type: "object",
246
+ properties: {
247
+ innerProp2: {
248
+ type: "number",
249
+ },
250
+ },
251
+ },
67
252
  },
68
- ],
69
- },
70
- },
71
- };
72
- expect((0, createSchema_1.createNodes)(schema, "request").map((md) => prettier.format(md, { parser: "babel" }))).toMatchSnapshot();
253
+ },
254
+ ],
255
+ };
256
+ expect(await Promise.all((0, createSchema_1.createNodes)(schema, "response").map(async (md) => await prettier.format(md, { parser: "babel" })))).toMatchSnapshot();
257
+ });
258
+ // eslint-disable-next-line jest/no-commented-out-tests
259
+ // it("should handle discriminator with allOf schemas", async () => {
260
+ // const schema: SchemaObject = {
261
+ // allOf: [
262
+ // {
263
+ // type: "object",
264
+ // discriminator: {
265
+ // propertyName: "type",
266
+ // },
267
+ // properties: {
268
+ // type: {
269
+ // type: "string",
270
+ // },
271
+ // },
272
+ // },
273
+ // {
274
+ // type: "object",
275
+ // properties: {
276
+ // specificProp: {
277
+ // type: "string",
278
+ // },
279
+ // },
280
+ // },
281
+ // ],
282
+ // };
283
+ // expect(
284
+ // await Promise.all(
285
+ // createNodes(schema, "response").map(
286
+ // async (md: any) => await prettier.format(md, { parser: "babel" })
287
+ // )
288
+ // )
289
+ // ).toMatchSnapshot();
290
+ // });
73
291
  });
74
292
  });
@@ -118,8 +118,9 @@ function createResponseExamples(responseExamples, mimeType) {
118
118
  value: `${exampleName}`,
119
119
  children: [
120
120
  (0, utils_2.guard)(exampleValue.summary, (summary) => [
121
- (0, utils_1.create)("Markdown", {
122
- children: ` ${summary}`,
121
+ (0, utils_1.create)("div", {
122
+ children: `${summary}`,
123
+ className: "openapi-example__summary",
123
124
  }),
124
125
  ]),
125
126
  (0, utils_1.create)("ResponseSamples", {
@@ -134,8 +135,9 @@ function createResponseExamples(responseExamples, mimeType) {
134
135
  value: `${exampleName}`,
135
136
  children: [
136
137
  (0, utils_2.guard)(exampleValue.summary, (summary) => [
137
- (0, utils_1.create)("Markdown", {
138
- children: ` ${summary}`,
138
+ (0, utils_1.create)("div", {
139
+ children: `${summary}`,
140
+ className: "openapi-example__summary",
139
141
  }),
140
142
  ]),
141
143
  (0, utils_1.create)("ResponseSamples", {
@@ -161,8 +163,9 @@ function createResponseExample(responseExample, mimeType) {
161
163
  value: `Example`,
162
164
  children: [
163
165
  (0, utils_2.guard)(responseExample.summary, (summary) => [
164
- (0, utils_1.create)("Markdown", {
165
- children: ` ${summary}`,
166
+ (0, utils_1.create)("div", {
167
+ children: `${summary}`,
168
+ className: "openapi-example__summary",
166
169
  }),
167
170
  ]),
168
171
  (0, utils_1.create)("ResponseSamples", {
@@ -177,8 +180,9 @@ function createResponseExample(responseExample, mimeType) {
177
180
  value: `Example`,
178
181
  children: [
179
182
  (0, utils_2.guard)(responseExample.summary, (summary) => [
180
- (0, utils_1.create)("Markdown", {
181
- children: ` ${summary}`,
183
+ (0, utils_1.create)("div", {
184
+ children: `${summary}`,
185
+ className: "openapi-example__summary",
182
186
  }),
183
187
  ]),
184
188
  (0, utils_1.create)("ResponseSamples", {
@@ -38,7 +38,7 @@ function createApiPageMD({ title, api: { deprecated, "x-deprecated-description":
38
38
  `import ResponseSamples from "@theme/ResponseSamples";\n`,
39
39
  `import SchemaItem from "@theme/SchemaItem";\n`,
40
40
  `import SchemaTabs from "@theme/SchemaTabs";\n`,
41
- `import Markdown from "@theme/Markdown";\n`,
41
+ `import Heading from "@theme/Heading";\n`,
42
42
  `import OperationTabs from "@theme/OperationTabs";\n`,
43
43
  `import TabItem from "@theme/TabItem";\n\n`,
44
44
  (0, createHeading_1.createHeading)(title.replace(utils_1.lessThan, "<").replace(utils_1.greaterThan, ">")),
@@ -17,8 +17,8 @@ const primitives = {
17
17
  string: {
18
18
  default: () => "string",
19
19
  email: () => "user@example.com",
20
- date: () => new Date().toISOString().substring(0, 10),
21
- "date-time": () => new Date().toISOString(),
20
+ date: () => "2024-07-29",
21
+ "date-time": () => "2024-07-29T15:51:28.071Z",
22
22
  uuid: () => "3fa85f64-5717-4562-b3fc-2c963f66afa6",
23
23
  hostname: () => "example.com",
24
24
  ipv4: () => "198.51.100.42",
@@ -17,8 +17,8 @@ const primitives = {
17
17
  string: {
18
18
  default: () => "string",
19
19
  email: () => "user@example.com",
20
- date: () => new Date().toISOString().substring(0, 10),
21
- "date-time": () => new Date().toISOString(),
20
+ date: () => "2024-07-29",
21
+ "date-time": () => "2024-07-29T15:51:28.071Z",
22
22
  uuid: () => "3fa85f64-5717-4562-b3fc-2c963f66afa6",
23
23
  hostname: () => "example.com",
24
24
  ipv4: () => "198.51.100.42",
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "docusaurus-plugin-openapi-docs",
3
3
  "description": "OpenAPI plugin for Docusaurus.",
4
- "version": "2.2.1",
4
+ "version": "2.2.2",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -60,5 +60,5 @@
60
60
  "engines": {
61
61
  "node": ">=14"
62
62
  },
63
- "gitHead": "73b212d18343aa7a35ede5136f5353f06b89d25f"
63
+ "gitHead": "297f91457e7742c5b5c334b975adf17e149f7f5c"
64
64
  }
package/src/index.ts CHANGED
@@ -536,6 +536,18 @@ custom_edit_url: null
536
536
  });
537
537
  }
538
538
 
539
+ if (!fs.existsSync(outputDir)) {
540
+ try {
541
+ fs.mkdirSync(outputDir, { recursive: true });
542
+ console.log(chalk.green(`Successfully created "${outputDir}"`));
543
+ } catch (err) {
544
+ console.error(
545
+ chalk.red(`Failed to create "${outputDir}"`),
546
+ chalk.yellow(err)
547
+ );
548
+ }
549
+ }
550
+
539
551
  const versionsJson = JSON.stringify(versionsArray, null, 2);
540
552
  try {
541
553
  fs.writeFileSync(`${outputDir}/versions.json`, versionsJson, "utf8");
@@ -1,6 +1,151 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`createNodes should create readable MODs for oneOf primitive properties 1`] = `
3
+ exports[`createNodes allOf should correctly deep merge properties in allOf schemas 1`] = `
4
+ Array [
5
+ "<SchemaItem collapsible={true} className={\\"schemaItem\\"}>
6
+ <details style={{}} className={\\"openapi-markdown__details\\"}>
7
+ <summary style={{}}>
8
+ <span className={\\"openapi-schema__container\\"}>
9
+ <strong className={\\"openapi-schema__property\\"}>deepProp</strong>
10
+ <span className={\\"openapi-schema__name\\"}> object</span>
11
+ </span>
12
+ </summary>
13
+ <div style={{ marginLeft: \\"1rem\\" }}>
14
+ <SchemaItem
15
+ collapsible={false}
16
+ name={\\"innerProp1\\"}
17
+ required={false}
18
+ schemaName={\\"string\\"}
19
+ qualifierMessage={undefined}
20
+ schema={{ type: \\"string\\" }}
21
+ ></SchemaItem>
22
+ <SchemaItem
23
+ collapsible={false}
24
+ name={\\"innerProp2\\"}
25
+ required={false}
26
+ schemaName={\\"number\\"}
27
+ qualifierMessage={undefined}
28
+ schema={{ type: \\"number\\" }}
29
+ ></SchemaItem>
30
+ </div>
31
+ </details>
32
+ </SchemaItem>;
33
+ ",
34
+ ]
35
+ `;
36
+
37
+ exports[`createNodes allOf should correctly handle shared required properties across allOf schemas 1`] = `
38
+ Array [
39
+ "<SchemaItem
40
+ collapsible={false}
41
+ name={\\"sharedProp\\"}
42
+ required={true}
43
+ schemaName={\\"string\\"}
44
+ qualifierMessage={undefined}
45
+ schema={{ type: \\"string\\" }}
46
+ ></SchemaItem>;
47
+ ",
48
+ "<SchemaItem
49
+ collapsible={false}
50
+ name={\\"anotherProp\\"}
51
+ required={true}
52
+ schemaName={\\"number\\"}
53
+ qualifierMessage={undefined}
54
+ schema={{ type: \\"number\\" }}
55
+ ></SchemaItem>;
56
+ ",
57
+ ]
58
+ `;
59
+
60
+ exports[`createNodes allOf should correctly merge nested properties from multiple allOf schemas 1`] = `
61
+ Array [
62
+ "<SchemaItem collapsible={true} className={\\"schemaItem\\"}>
63
+ <details style={{}} className={\\"openapi-markdown__details\\"}>
64
+ <summary style={{}}>
65
+ <span className={\\"openapi-schema__container\\"}>
66
+ <strong className={\\"openapi-schema__property\\"}>outerProp1</strong>
67
+ <span className={\\"openapi-schema__name\\"}> object</span>
68
+ </span>
69
+ </summary>
70
+ <div style={{ marginLeft: \\"1rem\\" }}>
71
+ <SchemaItem
72
+ collapsible={false}
73
+ name={\\"innerProp1\\"}
74
+ required={false}
75
+ schemaName={\\"string\\"}
76
+ qualifierMessage={undefined}
77
+ schema={{ type: \\"string\\" }}
78
+ ></SchemaItem>
79
+ </div>
80
+ </details>
81
+ </SchemaItem>;
82
+ ",
83
+ "<SchemaItem collapsible={true} className={\\"schemaItem\\"}>
84
+ <details style={{}} className={\\"openapi-markdown__details\\"}>
85
+ <summary style={{}}>
86
+ <span className={\\"openapi-schema__container\\"}>
87
+ <strong className={\\"openapi-schema__property\\"}>outerProp2</strong>
88
+ <span className={\\"openapi-schema__name\\"}> object</span>
89
+ </span>
90
+ </summary>
91
+ <div style={{ marginLeft: \\"1rem\\" }}>
92
+ <SchemaItem
93
+ collapsible={false}
94
+ name={\\"innerProp2\\"}
95
+ required={false}
96
+ schemaName={\\"number\\"}
97
+ qualifierMessage={undefined}
98
+ schema={{ type: \\"number\\" }}
99
+ ></SchemaItem>
100
+ </div>
101
+ </details>
102
+ </SchemaItem>;
103
+ ",
104
+ ]
105
+ `;
106
+
107
+ exports[`createNodes allOf should render same-level properties with allOf 1`] = `
108
+ Array [
109
+ "<SchemaItem
110
+ collapsible={false}
111
+ name={\\"parentProp1\\"}
112
+ required={false}
113
+ schemaName={\\"string\\"}
114
+ qualifierMessage={undefined}
115
+ schema={{ type: \\"string\\" }}
116
+ ></SchemaItem>;
117
+ ",
118
+ "<SchemaItem
119
+ collapsible={false}
120
+ name={\\"parentProp2\\"}
121
+ required={false}
122
+ schemaName={\\"string\\"}
123
+ qualifierMessage={undefined}
124
+ schema={{ type: \\"string\\" }}
125
+ ></SchemaItem>;
126
+ ",
127
+ "<SchemaItem
128
+ collapsible={false}
129
+ name={\\"allOfProp1\\"}
130
+ required={false}
131
+ schemaName={\\"string\\"}
132
+ qualifierMessage={undefined}
133
+ schema={{ type: \\"string\\" }}
134
+ ></SchemaItem>;
135
+ ",
136
+ "<SchemaItem
137
+ collapsible={false}
138
+ name={\\"allOfProp2\\"}
139
+ required={false}
140
+ schemaName={\\"string\\"}
141
+ qualifierMessage={undefined}
142
+ schema={{ type: \\"string\\" }}
143
+ ></SchemaItem>;
144
+ ",
145
+ ]
146
+ `;
147
+
148
+ exports[`createNodes oneOf should create readable MODs for oneOf primitive properties 1`] = `
4
149
  Array [
5
150
  "<SchemaItem collapsible={true} className={\\"schemaItem\\"}>
6
151
  <details style={{}} className={\\"openapi-markdown__details\\"}>
@@ -11,47 +11,305 @@ import { createNodes } from "./createSchema";
11
11
  import { SchemaObject } from "../openapi/types";
12
12
 
13
13
  describe("createNodes", () => {
14
- it("should create readable MODs for oneOf primitive properties", () => {
15
- const schema: SchemaObject = {
16
- "x-tags": ["clown"],
17
- type: "object",
18
- properties: {
19
- oneOfProperty: {
20
- oneOf: [
21
- {
22
- type: "object",
23
- properties: {
24
- noseLength: {
25
- type: "number",
14
+ describe("oneOf", () => {
15
+ it("should create readable MODs for oneOf primitive properties", async () => {
16
+ const schema: SchemaObject = {
17
+ "x-tags": ["clown"],
18
+ type: "object",
19
+ properties: {
20
+ oneOfProperty: {
21
+ oneOf: [
22
+ {
23
+ type: "object",
24
+ properties: {
25
+ noseLength: {
26
+ type: "number",
27
+ },
28
+ },
29
+ required: ["noseLength"],
30
+ description: "Clown's nose length",
31
+ },
32
+ {
33
+ type: "array",
34
+ items: {
35
+ type: "string",
36
+ },
37
+ description: "Array of strings",
38
+ },
39
+ {
40
+ type: "boolean",
41
+ },
42
+ {
43
+ type: "number",
44
+ },
45
+ {
46
+ type: "string",
47
+ },
48
+ ],
49
+ },
50
+ },
51
+ };
52
+ expect(
53
+ await Promise.all(
54
+ createNodes(schema, "request").map(
55
+ async (md: any) => await prettier.format(md, { parser: "babel" })
56
+ )
57
+ )
58
+ ).toMatchSnapshot();
59
+ });
60
+ });
61
+
62
+ describe("allOf", () => {
63
+ it("should render same-level properties with allOf", async () => {
64
+ const schema: SchemaObject = {
65
+ allOf: [
66
+ {
67
+ type: "object",
68
+ properties: {
69
+ allOfProp1: {
70
+ type: "string",
71
+ },
72
+ allOfProp2: {
73
+ type: "string",
74
+ },
75
+ },
76
+ },
77
+ ],
78
+ properties: {
79
+ parentProp1: {
80
+ type: "string",
81
+ },
82
+ parentProp2: {
83
+ type: "string",
84
+ },
85
+ },
86
+ };
87
+
88
+ expect(
89
+ await Promise.all(
90
+ createNodes(schema, "response").map(
91
+ async (md: any) => await prettier.format(md, { parser: "babel" })
92
+ )
93
+ )
94
+ ).toMatchSnapshot();
95
+ });
96
+
97
+ it("should correctly merge nested properties from multiple allOf schemas", async () => {
98
+ const schema: SchemaObject = {
99
+ allOf: [
100
+ {
101
+ type: "object",
102
+ properties: {
103
+ outerProp1: {
104
+ type: "object",
105
+ properties: {
106
+ innerProp1: {
107
+ type: "string",
108
+ },
26
109
  },
27
110
  },
28
- required: ["noseLength"],
29
- description: "Clown's nose length",
30
111
  },
31
- {
32
- type: "array",
33
- items: {
112
+ },
113
+ {
114
+ type: "object",
115
+ properties: {
116
+ outerProp2: {
117
+ type: "object",
118
+ properties: {
119
+ innerProp2: {
120
+ type: "number",
121
+ },
122
+ },
123
+ },
124
+ },
125
+ },
126
+ ],
127
+ };
128
+
129
+ expect(
130
+ await Promise.all(
131
+ createNodes(schema, "response").map(
132
+ async (md: any) => await prettier.format(md, { parser: "babel" })
133
+ )
134
+ )
135
+ ).toMatchSnapshot();
136
+ });
137
+
138
+ it("should correctly handle shared required properties across allOf schemas", async () => {
139
+ const schema: SchemaObject = {
140
+ allOf: [
141
+ {
142
+ type: "object",
143
+ properties: {
144
+ sharedProp: {
34
145
  type: "string",
35
146
  },
36
- description: "Array of strings",
37
147
  },
38
- {
39
- type: "boolean",
148
+ required: ["sharedProp"],
149
+ },
150
+ {
151
+ type: "object",
152
+ properties: {
153
+ anotherProp: {
154
+ type: "number",
155
+ },
40
156
  },
41
- {
42
- type: "number",
157
+ required: ["anotherProp"],
158
+ },
159
+ ],
160
+ };
161
+
162
+ expect(
163
+ await Promise.all(
164
+ createNodes(schema, "response").map(
165
+ async (md: any) => await prettier.format(md, { parser: "babel" })
166
+ )
167
+ )
168
+ ).toMatchSnapshot();
169
+ });
170
+
171
+ // Could not resolve values for path:"properties.conflictingProp.type". They are probably incompatible. Values:
172
+ // "string"
173
+ // "number"
174
+ // eslint-disable-next-line jest/no-commented-out-tests
175
+ // it("should handle conflicting properties in allOf schemas", async () => {
176
+ // const schema: SchemaObject = {
177
+ // allOf: [
178
+ // {
179
+ // type: "object",
180
+ // properties: {
181
+ // conflictingProp: {
182
+ // type: "string",
183
+ // },
184
+ // },
185
+ // },
186
+ // {
187
+ // type: "object",
188
+ // properties: {
189
+ // conflictingProp: {
190
+ // type: "number",
191
+ // },
192
+ // },
193
+ // },
194
+ // ],
195
+ // };
196
+
197
+ // expect(
198
+ // await Promise.all(
199
+ // createNodes(schema, "response").map(
200
+ // async (md: any) => await prettier.format(md, { parser: "babel" })
201
+ // )
202
+ // )
203
+ // ).toMatchSnapshot();
204
+ // });
205
+
206
+ // Could not resolve values for path:"type". They are probably incompatible. Values:
207
+ // "object"
208
+ // "array"
209
+ // eslint-disable-next-line jest/no-commented-out-tests
210
+ // it("should handle mixed data types in allOf schemas", async () => {
211
+ // const schema: SchemaObject = {
212
+ // allOf: [
213
+ // {
214
+ // type: "object",
215
+ // properties: {
216
+ // mixedTypeProp1: {
217
+ // type: "string",
218
+ // },
219
+ // },
220
+ // },
221
+ // {
222
+ // type: "array",
223
+ // items: {
224
+ // type: "number",
225
+ // },
226
+ // },
227
+ // ],
228
+ // };
229
+
230
+ // expect(
231
+ // await Promise.all(
232
+ // createNodes(schema, "response").map(
233
+ // async (md: any) => await prettier.format(md, { parser: "babel" })
234
+ // )
235
+ // )
236
+ // ).toMatchSnapshot();
237
+ // });
238
+
239
+ it("should correctly deep merge properties in allOf schemas", async () => {
240
+ const schema: SchemaObject = {
241
+ allOf: [
242
+ {
243
+ type: "object",
244
+ properties: {
245
+ deepProp: {
246
+ type: "object",
247
+ properties: {
248
+ innerProp1: {
249
+ type: "string",
250
+ },
251
+ },
252
+ },
43
253
  },
44
- {
45
- type: "string",
254
+ },
255
+ {
256
+ type: "object",
257
+ properties: {
258
+ deepProp: {
259
+ type: "object",
260
+ properties: {
261
+ innerProp2: {
262
+ type: "number",
263
+ },
264
+ },
265
+ },
46
266
  },
47
- ],
48
- },
49
- },
50
- };
51
- expect(
52
- createNodes(schema, "request").map((md: any) =>
53
- prettier.format(md, { parser: "babel" })
54
- )
55
- ).toMatchSnapshot();
267
+ },
268
+ ],
269
+ };
270
+
271
+ expect(
272
+ await Promise.all(
273
+ createNodes(schema, "response").map(
274
+ async (md: any) => await prettier.format(md, { parser: "babel" })
275
+ )
276
+ )
277
+ ).toMatchSnapshot();
278
+ });
279
+
280
+ // eslint-disable-next-line jest/no-commented-out-tests
281
+ // it("should handle discriminator with allOf schemas", async () => {
282
+ // const schema: SchemaObject = {
283
+ // allOf: [
284
+ // {
285
+ // type: "object",
286
+ // discriminator: {
287
+ // propertyName: "type",
288
+ // },
289
+ // properties: {
290
+ // type: {
291
+ // type: "string",
292
+ // },
293
+ // },
294
+ // },
295
+ // {
296
+ // type: "object",
297
+ // properties: {
298
+ // specificProp: {
299
+ // type: "string",
300
+ // },
301
+ // },
302
+ // },
303
+ // ],
304
+ // };
305
+
306
+ // expect(
307
+ // await Promise.all(
308
+ // createNodes(schema, "response").map(
309
+ // async (md: any) => await prettier.format(md, { parser: "babel" })
310
+ // )
311
+ // )
312
+ // ).toMatchSnapshot();
313
+ // });
56
314
  });
57
315
  });
@@ -73,6 +73,15 @@ function createAnyOneOf(schema: SchemaObject): any {
73
73
  : `MOD${index + 1}`;
74
74
  const anyOneChildren = [];
75
75
 
76
+ if (
77
+ anyOneSchema.type === "object" &&
78
+ !anyOneSchema.properties &&
79
+ !anyOneSchema.allOf &&
80
+ !anyOneSchema.items
81
+ ) {
82
+ anyOneChildren.push(createNodes(anyOneSchema, SCHEMA_TYPE));
83
+ }
84
+
76
85
  if (anyOneSchema.properties !== undefined) {
77
86
  anyOneChildren.push(createProperties(anyOneSchema));
78
87
  delete anyOneSchema.properties;
@@ -617,6 +626,7 @@ function createEdges({
617
626
  }
618
627
 
619
628
  const schemaName = getSchemaName(schema);
629
+
620
630
  if (discriminator !== undefined && discriminator.propertyName === name) {
621
631
  return createPropertyDiscriminator(
622
632
  name,
@@ -637,6 +647,47 @@ function createEdges({
637
647
  );
638
648
  }
639
649
 
650
+ if (schema.properties !== undefined) {
651
+ return createDetailsNode(
652
+ name,
653
+ schemaName,
654
+ schema,
655
+ required,
656
+ schema.nullable
657
+ );
658
+ }
659
+
660
+ if (schema.additionalProperties !== undefined) {
661
+ return createDetailsNode(
662
+ name,
663
+ schemaName,
664
+ schema,
665
+ required,
666
+ schema.nullable
667
+ );
668
+ }
669
+
670
+ // array of objects
671
+ if (schema.items?.properties !== undefined) {
672
+ return createDetailsNode(
673
+ name,
674
+ schemaName,
675
+ schema,
676
+ required,
677
+ schema.nullable
678
+ );
679
+ }
680
+
681
+ if (schema.items?.anyOf !== undefined || schema.items?.oneOf !== undefined) {
682
+ return createDetailsNode(
683
+ name,
684
+ schemaName,
685
+ schema,
686
+ required,
687
+ schema.nullable
688
+ );
689
+ }
690
+
640
691
  if (schema.allOf !== undefined) {
641
692
  const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
642
693
  schema.allOf
@@ -709,47 +760,6 @@ function createEdges({
709
760
  });
710
761
  }
711
762
 
712
- if (schema.properties !== undefined) {
713
- return createDetailsNode(
714
- name,
715
- schemaName,
716
- schema,
717
- required,
718
- schema.nullable
719
- );
720
- }
721
-
722
- if (schema.additionalProperties !== undefined) {
723
- return createDetailsNode(
724
- name,
725
- schemaName,
726
- schema,
727
- required,
728
- schema.nullable
729
- );
730
- }
731
-
732
- // array of objects
733
- if (schema.items?.properties !== undefined) {
734
- return createDetailsNode(
735
- name,
736
- schemaName,
737
- schema,
738
- required,
739
- schema.nullable
740
- );
741
- }
742
-
743
- if (schema.items?.anyOf !== undefined || schema.items?.oneOf !== undefined) {
744
- return createDetailsNode(
745
- name,
746
- schemaName,
747
- schema,
748
- required,
749
- schema.nullable
750
- );
751
- }
752
-
753
763
  // primitives and array of non-objects
754
764
  return create("SchemaItem", {
755
765
  collapsible: false,
@@ -789,15 +799,6 @@ export function createNodes(
789
799
  nodes.push(createAnyOneOf(schema));
790
800
  }
791
801
 
792
- if (schema.allOf !== undefined) {
793
- const { mergedSchemas } = mergeAllOf(schema.allOf);
794
-
795
- // allOf seems to always result in properties
796
- if (mergedSchemas.properties !== undefined) {
797
- nodes.push(createProperties(mergedSchemas));
798
- }
799
- }
800
-
801
802
  if (schema.properties !== undefined) {
802
803
  nodes.push(createProperties(schema));
803
804
  }
@@ -811,6 +812,15 @@ export function createNodes(
811
812
  nodes.push(createItems(schema));
812
813
  }
813
814
 
815
+ if (schema.allOf !== undefined) {
816
+ const { mergedSchemas } = mergeAllOf(schema.allOf);
817
+
818
+ // allOf seems to always result in properties
819
+ if (mergedSchemas.properties !== undefined) {
820
+ nodes.push(createProperties(mergedSchemas));
821
+ }
822
+ }
823
+
814
824
  if (nodes.length && nodes.length > 0) {
815
825
  return nodes.filter(Boolean).flat();
816
826
  }
@@ -127,8 +127,9 @@ export function createResponseExamples(
127
127
  value: `${exampleName}`,
128
128
  children: [
129
129
  guard(exampleValue.summary, (summary) => [
130
- create("Markdown", {
131
- children: ` ${summary}`,
130
+ create("div", {
131
+ children: `${summary}`,
132
+ className: "openapi-example__summary",
132
133
  }),
133
134
  ]),
134
135
  create("ResponseSamples", {
@@ -143,8 +144,9 @@ export function createResponseExamples(
143
144
  value: `${exampleName}`,
144
145
  children: [
145
146
  guard(exampleValue.summary, (summary) => [
146
- create("Markdown", {
147
- children: ` ${summary}`,
147
+ create("div", {
148
+ children: `${summary}`,
149
+ className: "openapi-example__summary",
148
150
  }),
149
151
  ]),
150
152
  create("ResponseSamples", {
@@ -171,8 +173,9 @@ export function createResponseExample(responseExample: any, mimeType: string) {
171
173
  value: `Example`,
172
174
  children: [
173
175
  guard(responseExample.summary, (summary) => [
174
- create("Markdown", {
175
- children: ` ${summary}`,
176
+ create("div", {
177
+ children: `${summary}`,
178
+ className: "openapi-example__summary",
176
179
  }),
177
180
  ]),
178
181
  create("ResponseSamples", {
@@ -187,8 +190,9 @@ export function createResponseExample(responseExample: any, mimeType: string) {
187
190
  value: `Example`,
188
191
  children: [
189
192
  guard(responseExample.summary, (summary) => [
190
- create("Markdown", {
191
- children: ` ${summary}`,
193
+ create("div", {
194
+ children: `${summary}`,
195
+ className: "openapi-example__summary",
192
196
  }),
193
197
  ]),
194
198
  create("ResponseSamples", {
@@ -76,7 +76,7 @@ export function createApiPageMD({
76
76
  `import ResponseSamples from "@theme/ResponseSamples";\n`,
77
77
  `import SchemaItem from "@theme/SchemaItem";\n`,
78
78
  `import SchemaTabs from "@theme/SchemaTabs";\n`,
79
- `import Markdown from "@theme/Markdown";\n`,
79
+ `import Heading from "@theme/Heading";\n`,
80
80
  `import OperationTabs from "@theme/OperationTabs";\n`,
81
81
  `import TabItem from "@theme/TabItem";\n\n`,
82
82
  createHeading(title.replace(lessThan, "&lt;").replace(greaterThan, "&gt;")),
@@ -30,8 +30,8 @@ const primitives: Primitives = {
30
30
  string: {
31
31
  default: () => "string",
32
32
  email: () => "user@example.com",
33
- date: () => new Date().toISOString().substring(0, 10),
34
- "date-time": () => new Date().toISOString(),
33
+ date: () => "2024-07-29",
34
+ "date-time": () => "2024-07-29T15:51:28.071Z",
35
35
  uuid: () => "3fa85f64-5717-4562-b3fc-2c963f66afa6",
36
36
  hostname: () => "example.com",
37
37
  ipv4: () => "198.51.100.42",
@@ -30,8 +30,8 @@ const primitives: Primitives = {
30
30
  string: {
31
31
  default: () => "string",
32
32
  email: () => "user@example.com",
33
- date: () => new Date().toISOString().substring(0, 10),
34
- "date-time": () => new Date().toISOString(),
33
+ date: () => "2024-07-29",
34
+ "date-time": () => "2024-07-29T15:51:28.071Z",
35
35
  uuid: () => "3fa85f64-5717-4562-b3fc-2c963f66afa6",
36
36
  hostname: () => "example.com",
37
37
  ipv4: () => "198.51.100.42",