docusaurus-plugin-openapi-docs 3.0.0-beta.8 → 3.0.0

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.
Files changed (36) hide show
  1. package/README.md +86 -61
  2. package/lib/index.d.ts +1 -1
  3. package/lib/index.js +24 -24
  4. package/lib/markdown/createRequestSchema.js +0 -6
  5. package/lib/markdown/createResponseSchema.js +0 -5
  6. package/lib/markdown/createSchema.d.ts +1 -1
  7. package/lib/markdown/createSchema.js +69 -63
  8. package/lib/markdown/createSchema.test.js +77 -0
  9. package/lib/markdown/createStatusCodes.js +1 -1
  10. package/lib/markdown/createVersionBadge.js +1 -1
  11. package/lib/markdown/utils.js +1 -1
  12. package/lib/openapi/openapi.js +38 -33
  13. package/lib/openapi/openapi.test.js +2 -0
  14. package/lib/openapi/types.d.ts +2 -1
  15. package/lib/options.js +3 -0
  16. package/lib/sidebars/index.js +30 -11
  17. package/lib/types.d.ts +4 -1
  18. package/package.json +4 -4
  19. package/src/index.ts +35 -31
  20. package/src/markdown/__snapshots__/createSchema.test.ts.snap +221 -0
  21. package/src/markdown/createRequestSchema.ts +0 -6
  22. package/src/markdown/createResponseSchema.ts +0 -6
  23. package/src/markdown/createSchema.test.ts +88 -0
  24. package/src/markdown/createSchema.ts +83 -81
  25. package/src/markdown/createStatusCodes.ts +1 -1
  26. package/src/markdown/createVersionBadge.ts +8 -4
  27. package/src/markdown/utils.ts +1 -1
  28. package/src/openapi/__fixtures__/examples/openapi.yaml +7 -0
  29. package/src/openapi/openapi.test.ts +4 -0
  30. package/src/openapi/openapi.ts +43 -33
  31. package/src/openapi/types.ts +2 -1
  32. package/src/openapi-to-postmanv2.d.ts +1 -1
  33. package/src/options.ts +3 -0
  34. package/src/postman-collection.d.ts +1 -1
  35. package/src/sidebars/index.ts +55 -27
  36. package/src/types.ts +4 -1
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": "3.0.0-beta.8",
4
+ "version": "3.0.0",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -41,8 +41,6 @@
41
41
  "@docusaurus/plugin-content-docs": "^3.0.1",
42
42
  "@docusaurus/utils": "^3.0.1",
43
43
  "@docusaurus/utils-validation": "^3.0.1",
44
- "@paloaltonetworks/openapi-to-postmanv2": "3.1.0-hotfix.1",
45
- "@paloaltonetworks/postman-collection": "^4.1.0",
46
44
  "@redocly/openapi-core": "^1.10.5",
47
45
  "chalk": "^4.1.2",
48
46
  "clsx": "^1.1.1",
@@ -52,6 +50,8 @@
52
50
  "json5": "^2.2.3",
53
51
  "lodash": "^4.17.20",
54
52
  "mustache": "^4.2.0",
53
+ "openapi-to-postmanv2": "^4.21.0",
54
+ "postman-collection": "^4.4.0",
55
55
  "slugify": "^1.6.5",
56
56
  "swagger2openapi": "^7.0.8",
57
57
  "xml-formatter": "^2.6.1"
@@ -62,5 +62,5 @@
62
62
  "engines": {
63
63
  "node": ">=14"
64
64
  },
65
- "gitHead": "5877a91dbf3a6f75d4b13258fe5d1f578dd35637"
65
+ "gitHead": "d03859d67953de59558a3fa84e7cc690941dbd69"
66
66
  }
package/src/index.ts CHANGED
@@ -41,6 +41,7 @@ export function isURL(str: string): boolean {
41
41
 
42
42
  export function getDocsPluginConfig(
43
43
  presetsPlugins: any[],
44
+ plugin: string,
44
45
  pluginId: string
45
46
  ): Object | undefined {
46
47
  // eslint-disable-next-line array-callback-return
@@ -52,10 +53,7 @@ export function getDocsPluginConfig(
52
53
  }
53
54
 
54
55
  // Search plugin-content-docs instances
55
- if (
56
- typeof data[0] === "string" &&
57
- data[0] === "@docusaurus/plugin-content-docs"
58
- ) {
56
+ if (typeof data[0] === "string" && data[0] === plugin) {
59
57
  const configPluginId = data[1].id ? data[1].id : "default";
60
58
  if (configPluginId === pluginId) {
61
59
  return data[1];
@@ -71,7 +69,7 @@ export function getDocsPluginConfig(
71
69
  }
72
70
 
73
71
  // Search plugin-content-docs instances
74
- if (filteredConfig[0] === "@docusaurus/plugin-content-docs") {
72
+ if (filteredConfig[0] === plugin) {
75
73
  const configPluginId = filteredConfig[1].id
76
74
  ? filteredConfig[1].id
77
75
  : "default";
@@ -95,14 +93,22 @@ export default function pluginOpenAPIDocs(
95
93
  context: LoadContext,
96
94
  options: PluginOptions
97
95
  ): Plugin<LoadedContent> {
98
- const { config, docsPluginId } = options;
96
+ const {
97
+ config,
98
+ docsPlugin = "@docusaurus/plugin-content-docs",
99
+ docsPluginId,
100
+ } = options;
99
101
  const { siteDir, siteConfig } = context;
100
102
 
101
103
  // Get routeBasePath and path from plugin-content-docs or preset
102
104
  const presets: any = siteConfig.presets;
103
105
  const plugins: any = siteConfig.plugins;
104
106
  const presetsPlugins = presets.concat(plugins);
105
- let docData: any = getDocsPluginConfig(presetsPlugins, docsPluginId);
107
+ let docData: any = getDocsPluginConfig(
108
+ presetsPlugins,
109
+ docsPlugin,
110
+ docsPluginId
111
+ );
106
112
  let docRouteBasePath = docData ? docData.routeBasePath : undefined;
107
113
  let docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
108
114
 
@@ -114,6 +120,7 @@ export default function pluginOpenAPIDocs(
114
120
  markdownGenerators,
115
121
  downloadUrl,
116
122
  sidebarOptions,
123
+ disableCompression,
117
124
  } = options;
118
125
 
119
126
  // Remove trailing slash before proceeding
@@ -121,7 +128,7 @@ export default function pluginOpenAPIDocs(
121
128
 
122
129
  // Override docPath if pluginId provided
123
130
  if (pluginId) {
124
- docData = getDocsPluginConfig(presetsPlugins, pluginId);
131
+ docData = getDocsPluginConfig(presetsPlugins, docsPlugin, pluginId);
125
132
  docRouteBasePath = docData ? docData.routeBasePath : undefined;
126
133
  docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
127
134
  }
@@ -305,7 +312,7 @@ custom_edit_url: null
305
312
 
306
313
  loadedApi.map(async (item) => {
307
314
  if (item.type === "info") {
308
- if (downloadUrl && isURL(downloadUrl)) {
315
+ if (downloadUrl) {
309
316
  item.downloadUrl = downloadUrl;
310
317
  }
311
318
  }
@@ -319,9 +326,11 @@ custom_edit_url: null
319
326
  // const deserialize = (s: any) => {
320
327
  // return zlib.inflateSync(Buffer.from(s, "base64")).toString();
321
328
  // };
322
- item.json = zlib
323
- .deflateSync(JSON.stringify(item.api))
324
- .toString("base64");
329
+ disableCompression === true
330
+ ? (item.json = JSON.stringify(item.api))
331
+ : (item.json = zlib
332
+ .deflateSync(JSON.stringify(item.api))
333
+ .toString("base64"));
325
334
  let infoBasePath = `${outputDir}/${item.infoId}`;
326
335
  if (docRouteBasePath) {
327
336
  infoBasePath = `${docRouteBasePath}/${outputDir
@@ -470,11 +479,7 @@ custom_edit_url: null
470
479
  cwd: path.resolve(apiDir),
471
480
  deep: 1,
472
481
  });
473
- const schemaMdxFiles = await Globby(["*.schema.mdx"], {
474
- cwd: path.resolve(apiDir, "schemas"),
475
- deep: 1,
476
- });
477
- const sidebarFile = await Globby(["sidebar.js"], {
482
+ const sidebarFile = await Globby(["sidebar.js", "sidebar.ts"], {
478
483
  cwd: path.resolve(apiDir),
479
484
  deep: 1,
480
485
  });
@@ -491,20 +496,17 @@ custom_edit_url: null
491
496
  })
492
497
  );
493
498
 
494
- schemaMdxFiles.map((mdx) =>
495
- fs.unlink(`${apiDir}/schemas/${mdx}`, (err) => {
496
- if (err) {
497
- console.error(
498
- chalk.red(`Cleanup failed for "${apiDir}/schemas/${mdx}"`),
499
- chalk.yellow(err)
500
- );
501
- } else {
502
- console.log(
503
- chalk.green(`Cleanup succeeded for "${apiDir}/schemas/${mdx}"`)
504
- );
505
- }
506
- })
507
- );
499
+ try {
500
+ fs.rmSync(`${apiDir}/schemas`, { recursive: true });
501
+ console.log(chalk.green(`Cleanup succeeded for "${apiDir}/schemas"`));
502
+ } catch (err: any) {
503
+ if (err.code !== "ENOENT") {
504
+ console.error(
505
+ chalk.red(`Cleanup failed for "${apiDir}/schemas"`),
506
+ chalk.yellow(err)
507
+ );
508
+ }
509
+ }
508
510
 
509
511
  sidebarFile.map((sidebar) =>
510
512
  fs.unlink(`${apiDir}/${sidebar}`, (err) => {
@@ -529,6 +531,7 @@ custom_edit_url: null
529
531
  version: version,
530
532
  label: metadata.label,
531
533
  baseUrl: metadata.baseUrl,
534
+ downloadUrl: metadata.downloadUrl,
532
535
  });
533
536
  }
534
537
 
@@ -683,6 +686,7 @@ custom_edit_url: null
683
686
  delete parentConfig.version;
684
687
  delete parentConfig.label;
685
688
  delete parentConfig.baseUrl;
689
+ delete parentConfig.downloadUrl;
686
690
 
687
691
  // TODO: handle when no versions are defined by version command is passed
688
692
  if (versionId === "all") {
@@ -1,5 +1,226 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
+ exports[`createNodes additionalProperties should handle additionalProperties: {"allOf": [Array]} 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\\"}>property name*</strong>
10
+ <span className={\\"openapi-schema__name\\"}>object</span>
11
+ </span>
12
+ </summary>
13
+ <div style={{ marginLeft: \\"1rem\\" }}>
14
+ <div>
15
+ <span className={\\"badge badge--info\\"}>oneOf</span>
16
+ <SchemaTabs>
17
+ <TabItem label={\\"MOD1\\"} value={\\"0-item-properties\\"}>
18
+ <SchemaItem
19
+ collapsible={false}
20
+ name={\\"type\\"}
21
+ required={true}
22
+ schemaName={\\"string\\"}
23
+ qualifierMessage={\\"**Possible values:** [\`nose\`]\\"}
24
+ schema={{ type: \\"string\\", enum: [\\"nose\\"] }}
25
+ ></SchemaItem>
26
+ </TabItem>
27
+ <TabItem label={\\"MOD2\\"} value={\\"1-item-properties\\"}>
28
+ <SchemaItem
29
+ collapsible={false}
30
+ name={\\"type\\"}
31
+ required={true}
32
+ schemaName={\\"string\\"}
33
+ qualifierMessage={\\"**Possible values:** [\`mouth\`]\\"}
34
+ schema={{ type: \\"string\\", enum: [\\"mouth\\"] }}
35
+ ></SchemaItem>
36
+ </TabItem>
37
+ <TabItem label={\\"MOD3\\"} value={\\"2-item-properties\\"}>
38
+ <SchemaItem
39
+ collapsible={false}
40
+ name={\\"type\\"}
41
+ required={true}
42
+ schemaName={\\"string\\"}
43
+ qualifierMessage={\\"**Possible values:** [\`eyes\`]\\"}
44
+ schema={{ type: \\"string\\", enum: [\\"eyes\\"] }}
45
+ ></SchemaItem>
46
+ <SchemaItem
47
+ collapsible={false}
48
+ name={\\"default\\"}
49
+ required={false}
50
+ schemaName={\\"string\\"}
51
+ qualifierMessage={undefined}
52
+ schema={{ type: \\"string\\" }}
53
+ ></SchemaItem>
54
+ </TabItem>
55
+ </SchemaTabs>
56
+ </div>
57
+ <SchemaItem
58
+ collapsible={false}
59
+ name={\\"description\\"}
60
+ required={true}
61
+ schemaName={\\"string\\"}
62
+ qualifierMessage={undefined}
63
+ schema={{
64
+ type: \\"string\\",
65
+ description: \\"Description of the body part.\\",
66
+ }}
67
+ ></SchemaItem>
68
+ </div>
69
+ </details>
70
+ </SchemaItem>;
71
+ ",
72
+ ]
73
+ `;
74
+
75
+ exports[`createNodes additionalProperties should handle additionalProperties: {"items": [Object], "type": "array"} 1`] = `
76
+ Array [
77
+ "<SchemaItem collapsible={true} className={\\"schemaItem\\"}>
78
+ <details style={{}} className={\\"openapi-markdown__details\\"}>
79
+ <summary style={{}}>
80
+ <span className={\\"openapi-schema__container\\"}>
81
+ <strong className={\\"openapi-schema__property\\"}>property name*</strong>
82
+ <span className={\\"openapi-schema__name\\"}>object[]</span>
83
+ </span>
84
+ </summary>
85
+ <div style={{ marginLeft: \\"1rem\\" }}>
86
+ <li>
87
+ <div
88
+ style={{
89
+ fontSize: \\"var(--ifm-code-font-size)\\",
90
+ opacity: \\"0.6\\",
91
+ marginLeft: \\"-.5rem\\",
92
+ paddingBottom: \\".5rem\\",
93
+ }}
94
+ >
95
+ Array [
96
+ </div>
97
+ </li>
98
+ <SchemaItem
99
+ collapsible={false}
100
+ name={\\"a\\"}
101
+ required={false}
102
+ schemaName={\\"\\"}
103
+ qualifierMessage={undefined}
104
+ schema={\\"string\\"}
105
+ ></SchemaItem>
106
+ <SchemaItem
107
+ collapsible={false}
108
+ name={\\"b\\"}
109
+ required={false}
110
+ schemaName={\\"\\"}
111
+ qualifierMessage={undefined}
112
+ schema={\\"number\\"}
113
+ ></SchemaItem>
114
+ <li>
115
+ <div
116
+ style={{
117
+ fontSize: \\"var(--ifm-code-font-size)\\",
118
+ opacity: \\"0.6\\",
119
+ marginLeft: \\"-.5rem\\",
120
+ }}
121
+ >
122
+ ]
123
+ </div>
124
+ </li>
125
+ </div>
126
+ </details>
127
+ </SchemaItem>;
128
+ ",
129
+ ]
130
+ `;
131
+
132
+ exports[`createNodes additionalProperties should handle additionalProperties: {"type": "boolean"} 1`] = `
133
+ Array [
134
+ "<SchemaItem
135
+ name={\\"property name*\\"}
136
+ required={false}
137
+ schemaName={\\"boolean\\"}
138
+ qualifierMessage={undefined}
139
+ schema={{ type: \\"boolean\\" }}
140
+ collapsible={false}
141
+ discriminator={false}
142
+ ></SchemaItem>;
143
+ ",
144
+ ]
145
+ `;
146
+
147
+ exports[`createNodes additionalProperties should handle additionalProperties: {"type": "integer"} 1`] = `
148
+ Array [
149
+ "<SchemaItem
150
+ name={\\"property name*\\"}
151
+ required={false}
152
+ schemaName={\\"integer\\"}
153
+ qualifierMessage={undefined}
154
+ schema={{ type: \\"integer\\" }}
155
+ collapsible={false}
156
+ discriminator={false}
157
+ ></SchemaItem>;
158
+ ",
159
+ ]
160
+ `;
161
+
162
+ exports[`createNodes additionalProperties should handle additionalProperties: {"type": "number"} 1`] = `
163
+ Array [
164
+ "<SchemaItem
165
+ name={\\"property name*\\"}
166
+ required={false}
167
+ schemaName={\\"number\\"}
168
+ qualifierMessage={undefined}
169
+ schema={{ type: \\"number\\" }}
170
+ collapsible={false}
171
+ discriminator={false}
172
+ ></SchemaItem>;
173
+ ",
174
+ ]
175
+ `;
176
+
177
+ exports[`createNodes additionalProperties should handle additionalProperties: {"type": "string"} 1`] = `
178
+ Array [
179
+ "<SchemaItem
180
+ name={\\"property name*\\"}
181
+ required={false}
182
+ schemaName={\\"string\\"}
183
+ qualifierMessage={undefined}
184
+ schema={{ type: \\"string\\" }}
185
+ collapsible={false}
186
+ discriminator={false}
187
+ ></SchemaItem>;
188
+ ",
189
+ ]
190
+ `;
191
+
192
+ exports[`createNodes additionalProperties should handle additionalProperties: {} 1`] = `
193
+ Array [
194
+ "<SchemaItem
195
+ name={\\"property name*\\"}
196
+ required={false}
197
+ schemaName={\\"any\\"}
198
+ qualifierMessage={undefined}
199
+ schema={{ type: \\"object\\", additionalProperties: {} }}
200
+ collapsible={false}
201
+ discriminator={false}
202
+ ></SchemaItem>;
203
+ ",
204
+ ]
205
+ `;
206
+
207
+ exports[`createNodes additionalProperties should handle additionalProperties: false 1`] = `Array []`;
208
+
209
+ exports[`createNodes additionalProperties should handle additionalProperties: true 1`] = `
210
+ Array [
211
+ "<SchemaItem
212
+ name={\\"property name*\\"}
213
+ required={false}
214
+ schemaName={\\"any\\"}
215
+ qualifierMessage={undefined}
216
+ schema={{ type: \\"object\\", additionalProperties: true }}
217
+ collapsible={false}
218
+ discriminator={false}
219
+ ></SchemaItem>;
220
+ ",
221
+ ]
222
+ `;
223
+
3
224
  exports[`createNodes should create readable MODs for oneOf primitive properties 1`] = `
4
225
  Array [
5
226
  "<SchemaItem collapsible={true} className={\\"schemaItem\\"}>
@@ -108,12 +108,6 @@ export function createRequestSchema({ title, body, ...rest }: Props) {
108
108
  return undefined;
109
109
  }
110
110
 
111
- // we don't show the table if there is no properties to show
112
- if (firstBody.properties !== undefined) {
113
- if (Object.keys(firstBody.properties).length === 0) {
114
- return undefined;
115
- }
116
- }
117
111
  return create("MimeTabs", {
118
112
  className: "openapi-tabs__mime",
119
113
  children: [
@@ -60,12 +60,6 @@ export function createResponseSchema({ title, body, ...rest }: Props) {
60
60
  return undefined;
61
61
  }
62
62
 
63
- if (firstBody?.properties !== undefined) {
64
- if (Object.keys(firstBody?.properties).length === 0) {
65
- return undefined;
66
- }
67
- }
68
-
69
63
  return create("TabItem", {
70
64
  label: `${mimeType}`,
71
65
  value: `${mimeType}`,
@@ -13,6 +13,7 @@ import { SchemaObject } from "../openapi/types";
13
13
  describe("createNodes", () => {
14
14
  it("should create readable MODs for oneOf primitive properties", async () => {
15
15
  const schema: SchemaObject = {
16
+ "x-tags": ["clown"],
16
17
  type: "object",
17
18
  properties: {
18
19
  oneOfProperty: {
@@ -55,4 +56,91 @@ describe("createNodes", () => {
55
56
  )
56
57
  ).toMatchSnapshot();
57
58
  });
59
+
60
+ describe("additionalProperties", () => {
61
+ it.each([
62
+ [
63
+ {
64
+ allOf: [
65
+ {
66
+ oneOf: [
67
+ {
68
+ type: "object",
69
+ properties: {
70
+ type: {
71
+ type: "string",
72
+ enum: ["nose"],
73
+ },
74
+ },
75
+ required: ["type"],
76
+ },
77
+ {
78
+ type: "object",
79
+ properties: {
80
+ type: {
81
+ type: "string",
82
+ enum: ["mouth"],
83
+ },
84
+ },
85
+ required: ["type"],
86
+ },
87
+ {
88
+ type: "object",
89
+ properties: {
90
+ type: {
91
+ type: "string",
92
+ enum: ["eyes"],
93
+ },
94
+ default: {
95
+ type: "string",
96
+ },
97
+ },
98
+ required: ["type"],
99
+ },
100
+ ],
101
+ },
102
+ {
103
+ type: "object",
104
+ properties: {
105
+ description: {
106
+ type: "string",
107
+ description: "Description of the body part.",
108
+ },
109
+ },
110
+ required: ["description"],
111
+ },
112
+ ],
113
+ },
114
+ ],
115
+ [
116
+ {
117
+ type: "array",
118
+ items: { type: "object", properties: { a: "string", b: "number" } },
119
+ },
120
+ ],
121
+ [{ type: "string" }],
122
+ [{ type: "number" }],
123
+ [{ type: "integer" }],
124
+ [{ type: "boolean" }],
125
+ [false],
126
+ [true],
127
+ [{}],
128
+ ] as [SchemaObject["additionalProperties"]][])(
129
+ "should handle additionalProperties: %p",
130
+ async (additionalProperties) => {
131
+ const schema: SchemaObject = {
132
+ type: "object",
133
+ additionalProperties,
134
+ };
135
+
136
+ expect(
137
+ await Promise.all(
138
+ createNodes(schema, "request").map(
139
+ async (md: any) => await prettier.format(md, { parser: "babel" })
140
+ )
141
+ )
142
+ ).toMatchSnapshot();
143
+ }
144
+ );
145
+ });
58
146
  });