docusaurus-plugin-openapi-docs 2.0.0-beta.4 → 2.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.
package/README.md CHANGED
@@ -25,9 +25,39 @@ Key Features:
25
25
  - **Compatible:** Works with Swagger 2.0 and OpenAPI 3.0.
26
26
  - **Fast:** Convert large OpenAPI specs into MDX docs in seconds. 🔥
27
27
  - **Stylish:** Based on the same [Infima styling framework](https://infima.dev/) that powers the Docusaurus UI.
28
- - **Capable:** Supports single, multi and _even micro_ OpenAPI specs.
28
+ - **Flexible:** Supports single, multi and _even micro_ OpenAPI specs.
29
29
 
30
- ## Installation
30
+ ## Compatibility Matrix
31
+
32
+ | Docusaurus OpenAPI Docs | Docusaurus |
33
+ | ----------------------- | --------------- |
34
+ | 2.0.x (current) | `2.4.1 - 2.4.3` |
35
+ | 1.7.3 (legacy) | `2.0.1 - 2.2.0` |
36
+
37
+ ## Bootstrapping from Template (new Docusaurus site)
38
+
39
+ Run the following to bootstrap a Docsaurus v2 site (classic theme) with `docusaurus-openapi-docs`:
40
+
41
+ ```bash
42
+ npx create-docusaurus@2.4.3 my-website --package-manager yarn
43
+ ```
44
+
45
+ > When prompted to select a template choose `Git repository`.
46
+
47
+ Template Repository URL:
48
+
49
+ ```bash
50
+ https://github.com/PaloAltoNetworks/docusaurus-template-openapi-docs.git
51
+ ```
52
+
53
+ > When asked how the template repo should be cloned choose "copy" (unless you know better).
54
+
55
+ ```bash
56
+ cd my-website
57
+ yarn start
58
+ ```
59
+
60
+ ## Installation (existing Docusaurus site)
31
61
 
32
62
  Plugin:
33
63
 
@@ -43,51 +73,48 @@ yarn add docusaurus-theme-openapi-docs
43
73
 
44
74
  ## Configuring `docusaurus.config.js` (Plugin and theme usage)
45
75
 
46
- Here is an example of properly configuring your `docusaurus.config.js` file for `docusaurus-plugin-openapi-docs` and `docusaurus-theme-openapi-docs` usage.
76
+ Here is an example of properly configuring `docusaurus.config.js` file for `docusaurus-plugin-openapi-docs` and `docusaurus-theme-openapi-docs` usage.
47
77
 
48
78
  ```js
49
79
  // docusaurus.config.js
50
80
 
51
81
  {
52
82
  presets: [
53
- [
54
- "classic",
55
- /** @type {import('@docusaurus/preset-classic').Options} */
56
- ({
57
- docs: {
58
- sidebarPath: require.resolve("./sidebars.js"),
59
- // Please change this to your repo.
60
- // Remove this to remove the "edit this page" links.
61
- editUrl:
62
- "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/",
63
- docLayoutComponent: "@theme/DocPage",
64
- docItemComponent: "@theme/ApiItem" // Derived from docusaurus-theme-openapi-docs
65
- },
66
- blog: {
67
- showReadingTime: true,
68
- // Please change this to your repo.
69
- // Remove this to remove the "edit this page" links.
70
- editUrl:
71
- "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/"
72
- },
73
- theme: {
74
- customCss: require.resolve("./src/css/custom.css")
75
- }
76
- })
77
- ]
78
- ],
83
+ [
84
+ "classic",
85
+ /** @type {import('@docusaurus/preset-classic').Options} */
86
+ ({
87
+ docs: {
88
+ sidebarPath: require.resolve("./sidebars.js"),
89
+ editUrl:
90
+ "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/",
91
+ docLayoutComponent: "@theme/DocPage",
92
+ docItemComponent: "@theme/ApiItem" // derived from docusaurus-theme-openapi-docs
93
+ },
94
+ blog: {
95
+ showReadingTime: true,
96
+ editUrl:
97
+ "https://github.com/facebook/docusaurus/tree/main/packages/create-docusaurus/templates/shared/"
98
+ },
99
+ theme: {
100
+ customCss: require.resolve("./src/css/custom.css")
101
+ }
102
+ })
103
+ ]
104
+ ],
79
105
 
80
106
  plugins: [
107
+ [
81
108
  'docusaurus-plugin-openapi-docs',
82
109
  {
83
- id: "apiDocs",
84
- docsPluginId: "classic",
110
+ id: "api", // plugin id
111
+ docsPluginId: "classic", // id of plugin-content-docs or preset for rendering docs
85
112
  config: {
86
- petstore: { // Note: petstore key is treated as the <id> and can be used to specify an API doc instance when using CLI commands
87
- specPath: "examples/petstore.yaml", // Path to designated spec file
88
- outputDir: "api/petstore", // Output directory for generated .mdx docs
89
- sidebarOptions: {
90
- groupPathsBy: "tag",
113
+ petstore: { // the <id> referenced when running CLI commands
114
+ specPath: "examples/petstore.yaml", // path to OpenAPI spec, URLs supported
115
+ outputDir: "api/petstore", // output directory for generated files
116
+ sidebarOptions: { // optional, instructs plugin to generate sidebar.js
117
+ groupPathsBy: "tag", // group sidebar items by operation "tag"
91
118
  },
92
119
  },
93
120
  burgers: {
@@ -98,7 +125,7 @@ Here is an example of properly configuring your `docusaurus.config.js` file for
98
125
  },
99
126
  ]
100
127
  ],
101
- themes: ["docusaurus-theme-openapi-docs"] // Allows use of @theme/ApiItem and other components
128
+ themes: ["docusaurus-theme-openapi-docs"], // export theme components
102
129
  }
103
130
  ```
104
131
 
@@ -110,37 +137,38 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
110
137
 
111
138
  | Name | Type | Default | Description |
112
139
  | -------------- | -------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
113
- | `id` | `string` | `null` | A unique document id. |
140
+ | `id` | `string` | `null` | A unique plugin id. |
114
141
  | `docsPluginId` | `string` | `null` | The ID associated with the `plugin-content-docs` or `preset` instance used to render the OpenAPI docs (e.g. "your-plugin-id", "classic", "default"). |
115
142
 
116
143
  ### config
117
144
 
118
145
  `config` can be configured with the following options:
119
146
 
120
- | Name | Type | Default | Description |
121
- | ---------------- | --------- | ------- | --------------------------------------------------------------------------------------------------------------------------- |
122
- | `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
123
- | `ouputDir` | `string` | `null` | Desired output path for generated MDX files. |
124
- | `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. |
125
- | `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
126
- | `downloadUrl` | `string` | `null` | _Optional:_ Designated URL for downloading OpenAPI specification. (requires `info` section/doc) |
127
- | `hideSendButton` | `boolean` | `null` | _Optional:_ If set to `true`, hides the "Send API Request" button in API demo panel |
128
- | `showExtensions` | `boolean` | `null` | _Optional:_ If set to `true`, renders operation-level vendor-extensions in description. |
129
- | `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
130
- | `version` | `string` | `null` | _Optional:_ Version assigned to single or micro-spec API specified in `specPath`. |
131
- | `label` | `string` | `null` | _Optional:_ Version label used when generating version selector dropdown menu. |
132
- | `baseUrl` | `string` | `null` | _Optional:_ Version base URL used when generating version selector dropdown menu. |
133
- | `versions` | `object` | `null` | _Optional:_ Set of options for versioning configuration. See below for a list of supported options. |
147
+ | Name | Type | Default | Description |
148
+ | -------------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
149
+ | `specPath` | `string` | `null` | Designated URL or path to the source of an OpenAPI specification file or directory of multiple OpenAPI specification files. |
150
+ | `ouputDir` | `string` | `null` | Desired output path for generated MDX files. |
151
+ | `proxy` | `string` | `null` | _Optional:_ Proxy URL to prepend to base URL when performing API requests from browser. |
152
+ | `template` | `string` | `null` | _Optional:_ Customize MDX content with a desired template. |
153
+ | `downloadUrl` | `string` | `null` | _Optional:_ Designated URL for downloading OpenAPI specification. (requires `info` section/doc) |
154
+ | `hideSendButton` | `boolean` | `null` | _Optional:_ If set to `true`, hides the "Send API Request" button in API demo panel |
155
+ | `showExtensions` | `boolean` | `null` | _Optional:_ If set to `true`, renders operation-level vendor-extensions in description. |
156
+ | `sidebarOptions` | `object` | `null` | _Optional:_ Set of options for sidebar configuration. See below for a list of supported options. |
157
+ | `version` | `string` | `null` | _Optional:_ Version assigned to single or micro-spec API specified in `specPath`. |
158
+ | `label` | `string` | `null` | _Optional:_ Version label used when generating version selector dropdown menu. |
159
+ | `baseUrl` | `string` | `null` | _Optional:_ Version base URL used when generating version selector dropdown menu. |
160
+ | `versions` | `object` | `null` | _Optional:_ Set of options for versioning configuration. See below for a list of supported options. |
161
+ | `markdownGenerators` | `object` | `null` | _Optional:_ Customize MDX content with a set of options for specifying markdown generator functions. See below for a list of supported options. |
134
162
 
135
163
  `sidebarOptions` can be configured with the following options:
136
164
 
137
- | Name | Type | Default | Description |
138
- | -------------------- | --------- | ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
139
- | `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag`. |
140
- | `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category pages when grouping paths by tag. By default, pages are not created for categories, only groups that can be expanded/collapsed. <br/><br/>The supported options are as follows: <br/><br/> `auto`: Sets the category link config type to `generated-index`, building an index page with links to each page in the group.<br/><br/> `tag`: Sets the category link config type to `generated-index` and uses the tag description at the top of the page. <br/><br/>`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios). |
141
- | `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
142
- | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
143
- | `customProps` | `object` | `null` | Additional props for customizing a sidebar item. |
165
+ | Name | Type | Default | Description |
166
+ | -------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
167
+ | `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag`. |
168
+ | `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag. <br/><br/>The supported options are as follows: <br/><br/> `tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description. <br/><br/>`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios). <br/><br/>`none`: Does not create pages for categories, only groups that can be expanded/collapsed. |
169
+ | `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
170
+ | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
171
+ | `customProps` | `object` | `null` | Additional props for customizing a sidebar item. |
144
172
 
145
173
  > You may optionally configure a `sidebarOptions`. In doing so, an individual `sidebar.js` slice with the configured options will be generated within the respective `outputDir`.
146
174
 
@@ -155,6 +183,16 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
155
183
 
156
184
  > All versions will automatically inherit `sidebarOptions` from the parent/base config.
157
185
 
186
+ ### markdownGenerators
187
+
188
+ `markdownGenerators` can be configured with the following options:
189
+
190
+ | Name | Type | Default | Description |
191
+ | ------------------ | ---------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
192
+ | `createApiPageMD` | `function` | `null` | _Optional:_ Returns a string of the raw markdown body for API pages.<br/><br/>**Function type:** `(pageData: ApiPageMetadata) => string` |
193
+ | `createInfoPageMD` | `function` | `null` | _Optional:_ Returns a string of the raw markdown body for info pages.<br/><br/>**Function type:** `(pageData: InfoPageMetadata) => string` |
194
+ | `createTagPageMD` | `function` | `null` | _Optional:_ Returns a string of the raw markdown body for tag pages.<br/><br/>**Function type:** `(pageData: TagPageMetadata) => string` |
195
+
158
196
  ## CLI Usage
159
197
 
160
198
  ```bash
@@ -245,29 +283,6 @@ yarn docusaurus gen-api-docs:version petstore:all
245
283
 
246
284
  > Substitue `all` with a specific version ID to generate/clean a specific version. Generating for `all` or a specific version ID will automatically update the `versions.json` file.
247
285
 
248
- ## Installing from Template
249
-
250
- Run the following to bootstrap a Docsaurus v2 site (classic theme) with `docusaurus-openapi-docs`:
251
-
252
- ```bash
253
- npx create-docusaurus@2.0.1 my-website --package-manager yarn
254
- ```
255
-
256
- > When prompted to select a template choose `Git repository`.
257
-
258
- Template Repository URL:
259
-
260
- ```bash
261
- https://github.com/PaloAltoNetworks/docusaurus-template-openapi-docs.git
262
- ```
263
-
264
- > When asked how the template repo should be cloned choose "copy" (unless you know better).
265
-
266
- ```bash
267
- cd my-website
268
- yarn
269
- ```
270
-
271
286
  ## Developer Quick Start
272
287
 
273
288
  > Looking to make a contribution? Make sure to checkout out our contributing guide.
package/lib/index.js CHANGED
@@ -77,7 +77,8 @@ function pluginOpenAPIDocs(context, options) {
77
77
  let docRouteBasePath = docData ? docData.routeBasePath : undefined;
78
78
  let docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
79
79
  async function generateApiDocs(options, pluginId) {
80
- let { specPath, outputDir, template, downloadUrl, sidebarOptions } = options;
80
+ var _a, _b, _c;
81
+ let { specPath, outputDir, template, markdownGenerators, downloadUrl, sidebarOptions, } = options;
81
82
  // Remove trailing slash before proceeding
82
83
  outputDir = outputDir.replace(/\/$/, "");
83
84
  // Override docPath if pluginId provided
@@ -194,12 +195,21 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
194
195
  <DocCardList items={useCurrentSidebarCategory().items}/>
195
196
  \`\`\`
196
197
  `;
198
+ const apiPageGenerator = (_a = markdownGenerators === null || markdownGenerators === void 0 ? void 0 : markdownGenerators.createApiPageMD) !== null && _a !== void 0 ? _a : markdown_1.createApiPageMD;
199
+ const infoPageGenerator = (_b = markdownGenerators === null || markdownGenerators === void 0 ? void 0 : markdownGenerators.createInfoPageMD) !== null && _b !== void 0 ? _b : markdown_1.createInfoPageMD;
200
+ const tagPageGenerator = (_c = markdownGenerators === null || markdownGenerators === void 0 ? void 0 : markdownGenerators.createTagPageMD) !== null && _c !== void 0 ? _c : markdown_1.createTagPageMD;
197
201
  loadedApi.map(async (item) => {
198
202
  if (item.type === "info") {
199
203
  if (downloadUrl && isURL(downloadUrl)) {
200
204
  item.downloadUrl = downloadUrl;
201
205
  }
202
206
  }
207
+ const markdown = item.type === "api"
208
+ ? apiPageGenerator(item)
209
+ : item.type === "info"
210
+ ? infoPageGenerator(item)
211
+ : tagPageGenerator(item);
212
+ item.markdown = markdown;
203
213
  if (item.type === "api") {
204
214
  // opportunity to compress JSON
205
215
  // const serialize = (o: any) => {
@@ -220,12 +230,6 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
220
230
  if (item.infoId)
221
231
  item.infoPath = infoBasePath;
222
232
  }
223
- const markdown = item.type === "api"
224
- ? (0, markdown_1.createApiPageMD)(item)
225
- : item.type === "info"
226
- ? (0, markdown_1.createInfoPageMD)(item)
227
- : (0, markdown_1.createTagPageMD)(item);
228
- item.markdown = markdown;
229
233
  const view = (0, mustache_1.render)(mdTemplate, item);
230
234
  const utils = (0, mustache_1.render)(infoMdTemplate, item);
231
235
  // eslint-disable-next-line testing-library/render-result-naming-convention
@@ -13,7 +13,7 @@ function createAdmonition({ children }) {
13
13
  }
14
14
  function createDeprecationNotice({ deprecated, description, }) {
15
15
  return (0, utils_1.guard)(deprecated, () => createAdmonition({
16
- children: description !== null && description !== void 0 ? description : "This endpoint has been deprecated and may be removed in future versions of the API.",
16
+ children: description !== null && description !== void 0 ? description : "This endpoint has been deprecated and may be replaced or removed in future versions of the API.",
17
17
  }));
18
18
  }
19
19
  exports.createDeprecationNotice = createDeprecationNotice;
@@ -356,8 +356,6 @@ function createDetailsNode(name, schemaName, schema, required, nullable) {
356
356
  * For handling anyOf/oneOf properties.
357
357
  */
358
358
  function createAnyOneOfProperty(name, schemaName, schema, required, nullable) {
359
- const type = schema.oneOf ? "oneOf" : "anyOf";
360
- const children = schema[type] || [];
361
359
  return (0, utils_1.create)("SchemaItem", {
362
360
  collapsible: true,
363
361
  className: "schemaItem",
@@ -408,38 +406,7 @@ function createAnyOneOfProperty(name, schemaName, schema, required, nullable) {
408
406
  })),
409
407
  ],
410
408
  }),
411
- (0, utils_1.create)("div", {
412
- children: [
413
- (0, utils_1.create)("span", {
414
- className: "badge badge--info",
415
- children: type,
416
- }),
417
- (0, utils_1.create)("SchemaTabs", {
418
- children: children.map((property, index) => {
419
- var _a;
420
- const label = (_a = property.title) !== null && _a !== void 0 ? _a : `MOD${index + 1}`;
421
- if (property.properties) {
422
- return (0, utils_1.create)("TabItem", {
423
- label: label,
424
- value: `${index}-property`,
425
- children: [createNodes(property)],
426
- });
427
- }
428
- return (0, utils_1.create)("TabItem", {
429
- label: label,
430
- value: `${index}-property`,
431
- children: [
432
- (0, utils_1.create)("p", { children: label }),
433
- (0, utils_1.guard)(schema.description, (description) => (0, utils_1.create)("div", {
434
- style: { marginTop: ".5rem", marginBottom: ".5rem" },
435
- children: (0, createDescription_1.createDescription)(description),
436
- })),
437
- ],
438
- });
439
- }),
440
- }),
441
- ],
442
- }),
409
+ createAnyOneOf(schema),
443
410
  ],
444
411
  }),
445
412
  ],
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ /* ============================================================================
3
+ * Copyright (c) Palo Alto Networks
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ * ========================================================================== */
8
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
9
+ if (k2 === undefined) k2 = k;
10
+ var desc = Object.getOwnPropertyDescriptor(m, k);
11
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
12
+ desc = { enumerable: true, get: function() { return m[k]; } };
13
+ }
14
+ Object.defineProperty(o, k2, desc);
15
+ }) : (function(o, m, k, k2) {
16
+ if (k2 === undefined) k2 = k;
17
+ o[k2] = m[k];
18
+ }));
19
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
20
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
21
+ }) : function(o, v) {
22
+ o["default"] = v;
23
+ });
24
+ var __importStar = (this && this.__importStar) || function (mod) {
25
+ if (mod && mod.__esModule) return mod;
26
+ var result = {};
27
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
28
+ __setModuleDefault(result, mod);
29
+ return result;
30
+ };
31
+ Object.defineProperty(exports, "__esModule", { value: true });
32
+ const prettier = __importStar(require("prettier"));
33
+ const createSchema_1 = require("./createSchema");
34
+ describe("createNodes", () => {
35
+ it("should create readable MODs for oneOf primitive properties", () => {
36
+ const schema = {
37
+ type: "object",
38
+ properties: {
39
+ oneOfProperty: {
40
+ oneOf: [
41
+ {
42
+ type: "object",
43
+ properties: {
44
+ noseLength: {
45
+ type: "number",
46
+ },
47
+ },
48
+ required: ["noseLength"],
49
+ description: "Clown's nose length",
50
+ },
51
+ {
52
+ type: "array",
53
+ items: {
54
+ type: "string",
55
+ },
56
+ description: "Array of strings",
57
+ },
58
+ {
59
+ type: "boolean",
60
+ },
61
+ {
62
+ type: "number",
63
+ },
64
+ {
65
+ type: "string",
66
+ },
67
+ ],
68
+ },
69
+ },
70
+ };
71
+ expect((0, createSchema_1.createNodes)(schema).map((md) => prettier.format(md, { parser: "babel" }))).toMatchSnapshot();
72
+ });
73
+ });
@@ -61,7 +61,7 @@ async function createPostmanCollection(openapiData) {
61
61
  return await jsonToCollection(data);
62
62
  }
63
63
  function createItems(openapiData, options, sidebarOptions) {
64
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2;
64
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
65
65
  // TODO: Find a better way to handle this
66
66
  let items = [];
67
67
  const infoIdSpaces = openapiData.info.title.replace(" ", "-").toLowerCase();
@@ -132,12 +132,20 @@ function createItems(openapiData, options, sidebarOptions) {
132
132
  }
133
133
  }
134
134
  let jsonRequestBodyExample;
135
- const body = (_o = (_m = operationObject.requestBody) === null || _m === void 0 ? void 0 : _m.content) === null || _o === void 0 ? void 0 : _o["application/json"];
135
+ const content = (_m = operationObject.requestBody) === null || _m === void 0 ? void 0 : _m.content;
136
+ let body;
137
+ for (let key in content) {
138
+ if (key.toLowerCase() === "application/json" ||
139
+ key.toLowerCase() === "application/json; charset=utf-8") {
140
+ body = content[key];
141
+ break;
142
+ }
143
+ }
136
144
  if (body === null || body === void 0 ? void 0 : body.schema) {
137
145
  jsonRequestBodyExample = (0, createRequestExample_1.sampleRequestFromSchema)(body.schema);
138
146
  }
139
147
  // Handle vendor JSON media types
140
- const bodyContent = (_p = operationObject.requestBody) === null || _p === void 0 ? void 0 : _p.content;
148
+ const bodyContent = (_o = operationObject.requestBody) === null || _o === void 0 ? void 0 : _o.content;
141
149
  if (bodyContent) {
142
150
  const firstBodyContentKey = Object.keys(bodyContent)[0];
143
151
  if (firstBodyContentKey.endsWith("+json")) {
@@ -204,15 +212,15 @@ function createItems(openapiData, options, sidebarOptions) {
204
212
  }
205
213
  }
206
214
  // Gather x-webhooks endpoints
207
- for (let [path, pathObject] of Object.entries((_q = openapiData["x-webhooks"]) !== null && _q !== void 0 ? _q : {})) {
215
+ for (let [path, pathObject] of Object.entries((_p = openapiData["x-webhooks"]) !== null && _p !== void 0 ? _p : {})) {
208
216
  path = "webhook";
209
217
  const { $ref, description, parameters, servers, summary, ...rest } = pathObject;
210
218
  for (let [method, operationObject] of Object.entries({ ...rest })) {
211
219
  method = "event";
212
- const title = (_s = (_r = operationObject.summary) !== null && _r !== void 0 ? _r : operationObject.operationId) !== null && _s !== void 0 ? _s : "Missing summary";
220
+ const title = (_r = (_q = operationObject.summary) !== null && _q !== void 0 ? _q : operationObject.operationId) !== null && _r !== void 0 ? _r : "Missing summary";
213
221
  if (operationObject.description === undefined) {
214
222
  operationObject.description =
215
- (_u = (_t = operationObject.summary) !== null && _t !== void 0 ? _t : operationObject.operationId) !== null && _u !== void 0 ? _u : "";
223
+ (_t = (_s = operationObject.summary) !== null && _s !== void 0 ? _s : operationObject.operationId) !== null && _t !== void 0 ? _t : "";
216
224
  }
217
225
  const baseId = operationObject.operationId
218
226
  ? (0, kebabCase_1.default)(operationObject.operationId)
@@ -224,10 +232,10 @@ function createItems(openapiData, options, sidebarOptions) {
224
232
  extensions.push({ key, value });
225
233
  }
226
234
  }
227
- const servers = (_w = (_v = operationObject.servers) !== null && _v !== void 0 ? _v : pathObject.servers) !== null && _w !== void 0 ? _w : openapiData.servers;
228
- const security = (_x = operationObject.security) !== null && _x !== void 0 ? _x : openapiData.security;
235
+ const servers = (_v = (_u = operationObject.servers) !== null && _u !== void 0 ? _u : pathObject.servers) !== null && _v !== void 0 ? _v : openapiData.servers;
236
+ const security = (_w = operationObject.security) !== null && _w !== void 0 ? _w : openapiData.security;
229
237
  // Add security schemes so we know how to handle security.
230
- const securitySchemes = (_y = openapiData.components) === null || _y === void 0 ? void 0 : _y.securitySchemes;
238
+ const securitySchemes = (_x = openapiData.components) === null || _x === void 0 ? void 0 : _x.securitySchemes;
231
239
  // Make sure schemes are lowercase. See: https://github.com/cloud-annotations/docusaurus-plugin-openapi/issues/79
232
240
  if (securitySchemes) {
233
241
  for (let securityScheme of Object.values(securitySchemes)) {
@@ -237,12 +245,20 @@ function createItems(openapiData, options, sidebarOptions) {
237
245
  }
238
246
  }
239
247
  let jsonRequestBodyExample;
240
- const body = (_0 = (_z = operationObject.requestBody) === null || _z === void 0 ? void 0 : _z.content) === null || _0 === void 0 ? void 0 : _0["application/json"];
248
+ const content = (_y = operationObject.requestBody) === null || _y === void 0 ? void 0 : _y.content;
249
+ let body;
250
+ for (let key in content) {
251
+ if (key.toLowerCase() === "application/json" ||
252
+ key.toLowerCase() === "application/json; charset=utf-8") {
253
+ body = content[key];
254
+ break;
255
+ }
256
+ }
241
257
  if (body === null || body === void 0 ? void 0 : body.schema) {
242
258
  jsonRequestBodyExample = (0, createRequestExample_1.sampleRequestFromSchema)(body.schema);
243
259
  }
244
260
  // Handle vendor JSON media types
245
- const bodyContent = (_1 = operationObject.requestBody) === null || _1 === void 0 ? void 0 : _1.content;
261
+ const bodyContent = (_z = operationObject.requestBody) === null || _z === void 0 ? void 0 : _z.content;
246
262
  if (bodyContent) {
247
263
  const firstBodyContentKey = Object.keys(bodyContent)[0];
248
264
  if (firstBodyContentKey.endsWith("+json")) {
@@ -310,7 +326,7 @@ function createItems(openapiData, options, sidebarOptions) {
310
326
  }
311
327
  if ((sidebarOptions === null || sidebarOptions === void 0 ? void 0 : sidebarOptions.categoryLinkSource) === "tag") {
312
328
  // Get global tags
313
- const tags = (_2 = openapiData.tags) !== null && _2 !== void 0 ? _2 : [];
329
+ const tags = (_0 = openapiData.tags) !== null && _0 !== void 0 ? _0 : [];
314
330
  // Get operation tags
315
331
  const apiItems = items.filter((item) => {
316
332
  return item.type === "api";
@@ -10,6 +10,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  const path_1 = __importDefault(require("path"));
13
+ // eslint-disable-next-line import/no-extraneous-dependencies
13
14
  const utils_1 = require("@docusaurus/utils");
14
15
  const _1 = require(".");
15
16
  // npx jest packages/docusaurus-plugin-openapi/src/openapi/openapi.test.ts --watch
package/lib/options.js CHANGED
@@ -15,6 +15,11 @@ const sidebarOptions = utils_validation_1.Joi.object({
15
15
  sidebarCollapsible: utils_validation_1.Joi.boolean(),
16
16
  sidebarCollapsed: utils_validation_1.Joi.boolean(),
17
17
  });
18
+ const markdownGenerators = utils_validation_1.Joi.object({
19
+ createApiPageMD: utils_validation_1.Joi.function(),
20
+ createInfoPageMD: utils_validation_1.Joi.function(),
21
+ createTagPageMD: utils_validation_1.Joi.function(),
22
+ });
18
23
  exports.OptionsSchema = utils_validation_1.Joi.object({
19
24
  id: utils_validation_1.Joi.string().required(),
20
25
  docsPluginId: utils_validation_1.Joi.string().required(),
@@ -28,6 +33,7 @@ exports.OptionsSchema = utils_validation_1.Joi.object({
28
33
  hideSendButton: utils_validation_1.Joi.boolean(),
29
34
  showExtensions: utils_validation_1.Joi.boolean(),
30
35
  sidebarOptions: sidebarOptions,
36
+ markdownGenerators: markdownGenerators,
31
37
  version: utils_validation_1.Joi.string().when("versions", {
32
38
  is: utils_validation_1.Joi.exist(),
33
39
  then: utils_validation_1.Joi.required(),
package/lib/types.d.ts CHANGED
@@ -23,6 +23,12 @@ export interface APIOptions {
23
23
  [key: string]: APIVersionOptions;
24
24
  };
25
25
  proxy?: string;
26
+ markdownGenerators?: MarkdownGenerator;
27
+ }
28
+ export interface MarkdownGenerator {
29
+ createApiPageMD?: (pageData: ApiPageMetadata) => string;
30
+ createInfoPageMD?: (pageData: InfoPageMetadata) => string;
31
+ createTagPageMD?: (pageData: TagPageMetadata) => string;
26
32
  }
27
33
  export interface SidebarOptions {
28
34
  groupPathsBy?: string;
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.0.0-beta.4",
4
+ "version": "2.0.0",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -28,7 +28,7 @@
28
28
  "watch": "tsc --watch"
29
29
  },
30
30
  "devDependencies": {
31
- "@docusaurus/types": ">=2.3.0 <2.5.0",
31
+ "@docusaurus/types": ">=2.4.1 <=2.4.3",
32
32
  "@types/fs-extra": "^9.0.13",
33
33
  "@types/json-pointer": "^1.0.31",
34
34
  "@types/json-schema": "^7.0.9",
@@ -37,9 +37,9 @@
37
37
  },
38
38
  "dependencies": {
39
39
  "@apidevtools/json-schema-ref-parser": "^10.1.0",
40
- "@docusaurus/plugin-content-docs": ">=2.3.0 <2.5.0",
41
- "@docusaurus/utils": ">=2.3.0 <2.5.0",
42
- "@docusaurus/utils-validation": ">=2.3.0 <2.5.0",
40
+ "@docusaurus/plugin-content-docs": ">=2.4.1 <=2.4.3",
41
+ "@docusaurus/utils": ">=2.4.1 <=2.4.3",
42
+ "@docusaurus/utils-validation": ">=2.4.1 <=2.4.3",
43
43
  "@paloaltonetworks/openapi-to-postmanv2": "3.1.0-hotfix.1",
44
44
  "@paloaltonetworks/postman-collection": "^4.1.0",
45
45
  "@redocly/openapi-core": "^1.0.0-beta.125",
@@ -55,10 +55,10 @@
55
55
  "xml-formatter": "^2.6.1"
56
56
  },
57
57
  "peerDependencies": {
58
- "react": "^16.8.4 || ^17.0.0"
58
+ "react": "^16.8.4 || ^17.0.0 || ^18.0.0"
59
59
  },
60
60
  "engines": {
61
61
  "node": ">=14"
62
62
  },
63
- "gitHead": "d7c1319c7977c3e7c54827b3950e5c9b66106e30"
63
+ "gitHead": "ec57fe9cac964cff00f5433fb829ce2d6219da7e"
64
64
  }
package/src/index.ts CHANGED
@@ -92,8 +92,14 @@ export default function pluginOpenAPIDocs(
92
92
  let docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
93
93
 
94
94
  async function generateApiDocs(options: APIOptions, pluginId: any) {
95
- let { specPath, outputDir, template, downloadUrl, sidebarOptions } =
96
- options;
95
+ let {
96
+ specPath,
97
+ outputDir,
98
+ template,
99
+ markdownGenerators,
100
+ downloadUrl,
101
+ sidebarOptions,
102
+ } = options;
97
103
 
98
104
  // Remove trailing slash before proceeding
99
105
  outputDir = outputDir.replace(/\/$/, "");
@@ -238,12 +244,26 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
238
244
  \`\`\`
239
245
  `;
240
246
 
247
+ const apiPageGenerator =
248
+ markdownGenerators?.createApiPageMD ?? createApiPageMD;
249
+ const infoPageGenerator =
250
+ markdownGenerators?.createInfoPageMD ?? createInfoPageMD;
251
+ const tagPageGenerator =
252
+ markdownGenerators?.createTagPageMD ?? createTagPageMD;
253
+
241
254
  loadedApi.map(async (item) => {
242
255
  if (item.type === "info") {
243
256
  if (downloadUrl && isURL(downloadUrl)) {
244
257
  item.downloadUrl = downloadUrl;
245
258
  }
246
259
  }
260
+ const markdown =
261
+ item.type === "api"
262
+ ? apiPageGenerator(item)
263
+ : item.type === "info"
264
+ ? infoPageGenerator(item)
265
+ : tagPageGenerator(item);
266
+ item.markdown = markdown;
247
267
  if (item.type === "api") {
248
268
  // opportunity to compress JSON
249
269
  // const serialize = (o: any) => {
@@ -263,13 +283,6 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
263
283
  }
264
284
  if (item.infoId) item.infoPath = infoBasePath;
265
285
  }
266
- const markdown =
267
- item.type === "api"
268
- ? createApiPageMD(item)
269
- : item.type === "info"
270
- ? createInfoPageMD(item)
271
- : createTagPageMD(item);
272
- item.markdown = markdown;
273
286
 
274
287
  const view = render(mdTemplate, item);
275
288
  const utils = render(infoMdTemplate, item);
@@ -0,0 +1,98 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`createNodes should create readable MODs for oneOf primitive properties 1`] = `
4
+ Array [
5
+ "<SchemaItem collapsible={true} className={\\"schemaItem\\"}>
6
+ <details style={{}} className={\\"openapi-markdown__details\\"}>
7
+ <summary style={{}}>
8
+ <strong>oneOfProperty</strong>
9
+ <span style={{ opacity: \\"0.6\\" }}> object</span>
10
+ </summary>
11
+ <div style={{ marginLeft: \\"1rem\\" }}></div>
12
+ <div>
13
+ <span className={\\"badge badge--info\\"}>oneOf</span>
14
+ <SchemaTabs>
15
+ <TabItem label={\\"MOD1\\"} value={\\"0-item-properties\\"}>
16
+ <SchemaItem
17
+ collapsible={false}
18
+ name={\\"noseLength\\"}
19
+ required={true}
20
+ schemaName={\\"number\\"}
21
+ qualifierMessage={undefined}
22
+ schema={{ type: \\"number\\" }}
23
+ ></SchemaItem>
24
+ </TabItem>
25
+ <TabItem label={\\"MOD2\\"} value={\\"1-item-properties\\"}>
26
+ <li>
27
+ <div
28
+ style={{
29
+ fontSize: \\"var(--ifm-code-font-size)\\",
30
+ opacity: \\"0.6\\",
31
+ marginLeft: \\"-.5rem\\",
32
+ paddingBottom: \\".5rem\\",
33
+ }}
34
+ >
35
+ Array [
36
+ </div>
37
+ </li>
38
+ <div
39
+ style={{
40
+ marginTop: \\".5rem\\",
41
+ marginBottom: \\".5rem\\",
42
+ marginLeft: \\"1rem\\",
43
+ }}
44
+ >
45
+ string
46
+ </div>
47
+ <li>
48
+ <div
49
+ style={{
50
+ fontSize: \\"var(--ifm-code-font-size)\\",
51
+ opacity: \\"0.6\\",
52
+ marginLeft: \\"-.5rem\\",
53
+ }}
54
+ >
55
+ ]
56
+ </div>
57
+ </li>
58
+ </TabItem>
59
+ <TabItem label={\\"MOD3\\"} value={\\"2-item-properties\\"}>
60
+ <div
61
+ style={{
62
+ marginTop: \\".5rem\\",
63
+ marginBottom: \\".5rem\\",
64
+ marginLeft: \\"1rem\\",
65
+ }}
66
+ >
67
+ boolean
68
+ </div>
69
+ </TabItem>
70
+ <TabItem label={\\"MOD4\\"} value={\\"3-item-properties\\"}>
71
+ <div
72
+ style={{
73
+ marginTop: \\".5rem\\",
74
+ marginBottom: \\".5rem\\",
75
+ marginLeft: \\"1rem\\",
76
+ }}
77
+ >
78
+ number
79
+ </div>
80
+ </TabItem>
81
+ <TabItem label={\\"MOD5\\"} value={\\"4-item-properties\\"}>
82
+ <div
83
+ style={{
84
+ marginTop: \\".5rem\\",
85
+ marginBottom: \\".5rem\\",
86
+ marginLeft: \\"1rem\\",
87
+ }}
88
+ >
89
+ string
90
+ </div>
91
+ </TabItem>
92
+ </SchemaTabs>
93
+ </div>
94
+ </details>
95
+ </SchemaItem>;
96
+ ",
97
+ ]
98
+ `;
@@ -24,7 +24,7 @@ export function createDeprecationNotice({
24
24
  createAdmonition({
25
25
  children:
26
26
  description ??
27
- "This endpoint has been deprecated and may be removed in future versions of the API.",
27
+ "This endpoint has been deprecated and may be replaced or removed in future versions of the API.",
28
28
  })
29
29
  );
30
30
  }
@@ -0,0 +1,56 @@
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 * as prettier from "prettier";
9
+
10
+ import { SchemaObject } from "../openapi/types";
11
+ import { createNodes } from "./createSchema";
12
+
13
+ describe("createNodes", () => {
14
+ it("should create readable MODs for oneOf primitive properties", () => {
15
+ const schema: SchemaObject = {
16
+ type: "object",
17
+ properties: {
18
+ oneOfProperty: {
19
+ oneOf: [
20
+ {
21
+ type: "object",
22
+ properties: {
23
+ noseLength: {
24
+ type: "number",
25
+ },
26
+ },
27
+ required: ["noseLength"],
28
+ description: "Clown's nose length",
29
+ },
30
+ {
31
+ type: "array",
32
+ items: {
33
+ type: "string",
34
+ },
35
+ description: "Array of strings",
36
+ },
37
+ {
38
+ type: "boolean",
39
+ },
40
+ {
41
+ type: "number",
42
+ },
43
+ {
44
+ type: "string",
45
+ },
46
+ ],
47
+ },
48
+ },
49
+ };
50
+ expect(
51
+ createNodes(schema).map((md: any) =>
52
+ prettier.format(md, { parser: "babel" })
53
+ )
54
+ ).toMatchSnapshot();
55
+ });
56
+ });
@@ -430,8 +430,6 @@ function createAnyOneOfProperty(
430
430
  required: string[] | boolean,
431
431
  nullable: boolean | unknown
432
432
  ): any {
433
- const type = schema.oneOf ? "oneOf" : "anyOf";
434
- const children = schema[type] || [];
435
433
  return create("SchemaItem", {
436
434
  collapsible: true,
437
435
  className: "schemaItem",
@@ -492,39 +490,7 @@ function createAnyOneOfProperty(
492
490
  ),
493
491
  ],
494
492
  }),
495
- create("div", {
496
- children: [
497
- create("span", {
498
- className: "badge badge--info",
499
- children: type,
500
- }),
501
- create("SchemaTabs", {
502
- children: children.map((property, index) => {
503
- const label = property.title ?? `MOD${index + 1}`;
504
- if (property.properties) {
505
- return create("TabItem", {
506
- label: label,
507
- value: `${index}-property`,
508
- children: [createNodes(property)],
509
- });
510
- }
511
- return create("TabItem", {
512
- label: label,
513
- value: `${index}-property`,
514
- children: [
515
- create("p", { children: label }),
516
- guard(schema.description, (description) =>
517
- create("div", {
518
- style: { marginTop: ".5rem", marginBottom: ".5rem" },
519
- children: createDescription(description),
520
- })
521
- ),
522
- ],
523
- });
524
- }),
525
- }),
526
- ],
527
- }),
493
+ createAnyOneOf(schema),
528
494
  ],
529
495
  }),
530
496
  ],
@@ -7,6 +7,7 @@
7
7
 
8
8
  import path from "path";
9
9
 
10
+ // eslint-disable-next-line import/no-extraneous-dependencies
10
11
  import { posixPath } from "@docusaurus/utils";
11
12
 
12
13
  import { readOpenapiFiles } from ".";
@@ -171,7 +171,18 @@ function createItems(
171
171
  }
172
172
 
173
173
  let jsonRequestBodyExample;
174
- const body = operationObject.requestBody?.content?.["application/json"];
174
+ const content = operationObject.requestBody?.content;
175
+ let body;
176
+ for (let key in content) {
177
+ if (
178
+ key.toLowerCase() === "application/json" ||
179
+ key.toLowerCase() === "application/json; charset=utf-8"
180
+ ) {
181
+ body = content[key];
182
+ break;
183
+ }
184
+ }
185
+
175
186
  if (body?.schema) {
176
187
  jsonRequestBodyExample = sampleRequestFromSchema(body.schema);
177
188
  }
@@ -304,7 +315,18 @@ function createItems(
304
315
  }
305
316
 
306
317
  let jsonRequestBodyExample;
307
- const body = operationObject.requestBody?.content?.["application/json"];
318
+ const content = operationObject.requestBody?.content;
319
+ let body;
320
+ for (let key in content) {
321
+ if (
322
+ key.toLowerCase() === "application/json" ||
323
+ key.toLowerCase() === "application/json; charset=utf-8"
324
+ ) {
325
+ body = content[key];
326
+ break;
327
+ }
328
+ }
329
+
308
330
  if (body?.schema) {
309
331
  jsonRequestBodyExample = sampleRequestFromSchema(body.schema);
310
332
  }
package/src/options.ts CHANGED
@@ -15,6 +15,12 @@ const sidebarOptions = Joi.object({
15
15
  sidebarCollapsed: Joi.boolean(),
16
16
  });
17
17
 
18
+ const markdownGenerators = Joi.object({
19
+ createApiPageMD: Joi.function(),
20
+ createInfoPageMD: Joi.function(),
21
+ createTagPageMD: Joi.function(),
22
+ });
23
+
18
24
  export const OptionsSchema = Joi.object({
19
25
  id: Joi.string().required(),
20
26
  docsPluginId: Joi.string().required(),
@@ -30,6 +36,7 @@ export const OptionsSchema = Joi.object({
30
36
  hideSendButton: Joi.boolean(),
31
37
  showExtensions: Joi.boolean(),
32
38
  sidebarOptions: sidebarOptions,
39
+ markdownGenerators: markdownGenerators,
33
40
  version: Joi.string().when("versions", {
34
41
  is: Joi.exist(),
35
42
  then: Joi.required(),
package/src/types.ts CHANGED
@@ -43,6 +43,13 @@ export interface APIOptions {
43
43
  [key: string]: APIVersionOptions;
44
44
  };
45
45
  proxy?: string;
46
+ markdownGenerators?: MarkdownGenerator;
47
+ }
48
+
49
+ export interface MarkdownGenerator {
50
+ createApiPageMD?: (pageData: ApiPageMetadata) => string;
51
+ createInfoPageMD?: (pageData: InfoPageMetadata) => string;
52
+ createTagPageMD?: (pageData: TagPageMetadata) => string;
46
53
  }
47
54
 
48
55
  export interface SidebarOptions {