docusaurus-plugin-openapi-docs 1.0.2 → 1.0.3

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
@@ -80,7 +80,7 @@ Here is an example of properly configuring your `docusaurus.config.js` file for
80
80
  specPath: "examples/petstore.yaml", // Path to designated spec file
81
81
  outputDir: "api/petstore", // Output directory for generated .mdx docs
82
82
  sidebarOptions: {
83
- groupPathsBy: "tags",
83
+ groupPathsBy: "tag",
84
84
  },
85
85
  },
86
86
  burgers: {
@@ -112,7 +112,7 @@ Here is an example of properly configuring your `docusaurus.config.js` file for
112
112
 
113
113
  | Name | Type | Default | Description |
114
114
  | -------------------- | --------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
115
- | `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by "tags". |
115
+ | `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag`. |
116
116
  | `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). |
117
117
  | `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
118
118
  | `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import type { LoadContext, Plugin } from "@docusaurus/types";
2
2
  import type { PluginOptions, LoadedContent } from "./types";
3
+ export declare function isURL(str: string): boolean;
3
4
  export default function pluginOpenAPI(context: LoadContext, options: PluginOptions): Plugin<LoadedContent>;
package/lib/index.js CHANGED
@@ -9,6 +9,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
9
9
  return (mod && mod.__esModule) ? mod : { "default": mod };
10
10
  };
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.isURL = void 0;
12
13
  const fs_1 = __importDefault(require("fs"));
13
14
  const path_1 = __importDefault(require("path"));
14
15
  const utils_1 = require("@docusaurus/utils");
@@ -17,15 +18,21 @@ const mustache_1 = require("mustache");
17
18
  const markdown_1 = require("./markdown");
18
19
  const openapi_1 = require("./openapi");
19
20
  const sidebars_1 = __importDefault(require("./sidebars"));
21
+ function isURL(str) {
22
+ return /^(https?:)\/\//m.test(str);
23
+ }
24
+ exports.isURL = isURL;
20
25
  function pluginOpenAPI(context, options) {
21
26
  let { config } = options;
22
27
  let { siteDir } = context;
23
28
  async function generateApiDocs(options) {
24
29
  let { specPath, outputDir, template, sidebarOptions } = options;
25
- const contentPath = path_1.default.resolve(siteDir, specPath);
30
+ const contentPath = isURL(specPath)
31
+ ? specPath
32
+ : path_1.default.resolve(siteDir, specPath);
26
33
  try {
27
34
  const openapiFiles = await (0, openapi_1.readOpenapiFiles)(contentPath, {});
28
- const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles);
35
+ const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles, sidebarOptions);
29
36
  if (!fs_1.default.existsSync(outputDir)) {
30
37
  try {
31
38
  fs_1.default.mkdirSync(outputDir, { recursive: true });
@@ -78,6 +85,9 @@ api: {{{json}}}
78
85
  {{#api.method}}
79
86
  sidebar_class_name: "{{{api.method}}} api-method"
80
87
  {{/api.method}}
88
+ {{#infoPath}}
89
+ info_path: {{{infoPath}}}
90
+ {{/infoPath}}
81
91
  ---
82
92
 
83
93
  {{{markdown}}}
@@ -96,17 +106,42 @@ hide_title: true
96
106
  import DocCardList from '@theme/DocCardList';
97
107
  import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
98
108
 
109
+ <DocCardList items={useCurrentSidebarCategory().items}/>
110
+ \`\`\`
111
+ `;
112
+ const tagMdTemplate = template
113
+ ? fs_1.default.readFileSync(template).toString()
114
+ : `---
115
+ id: {{{id}}}
116
+ title: {{{description}}}
117
+ description: {{{description}}}
118
+ ---
119
+
120
+ {{{markdown}}}
121
+
122
+ \`\`\`mdx-code-block
123
+ import DocCardList from '@theme/DocCardList';
124
+ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
125
+
99
126
  <DocCardList items={useCurrentSidebarCategory().items}/>
100
127
  \`\`\`
101
128
  `;
102
129
  loadedApi.map(async (item) => {
103
- const markdown = item.type === "api" ? (0, markdown_1.createApiPageMD)(item) : (0, markdown_1.createInfoPageMD)(item);
130
+ const markdown = item.type === "api"
131
+ ? (0, markdown_1.createApiPageMD)(item)
132
+ : item.type === "info"
133
+ ? (0, markdown_1.createInfoPageMD)(item)
134
+ : (0, markdown_1.createTagPageMD)(item);
104
135
  item.markdown = markdown;
105
136
  if (item.type === "api") {
106
137
  item.json = JSON.stringify(item.api);
138
+ if (item.infoId)
139
+ item.infoPath = `${outputDir}/${item.infoId}`;
107
140
  }
108
141
  const view = (0, mustache_1.render)(mdTemplate, item);
109
142
  const utils = (0, mustache_1.render)(infoMdTemplate, item);
143
+ // eslint-disable-next-line testing-library/render-result-naming-convention
144
+ const tagUtils = (0, mustache_1.render)(tagMdTemplate, item);
110
145
  if (item.type === "api") {
111
146
  if (!fs_1.default.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
112
147
  try {
@@ -132,6 +167,17 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
132
167
  }
133
168
  }
134
169
  }
170
+ if (item.type === "tag") {
171
+ if (!fs_1.default.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
172
+ try {
173
+ fs_1.default.writeFileSync(`${outputDir}/${item.id}.tag.mdx`, tagUtils, "utf8");
174
+ console.log(chalk_1.default.green(`Successfully created "${outputDir}/${item.id}.tag.mdx"`));
175
+ }
176
+ catch (err) {
177
+ console.error(chalk_1.default.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`), chalk_1.default.yellow(err));
178
+ }
179
+ }
180
+ }
135
181
  return;
136
182
  });
137
183
  return;
@@ -144,7 +190,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
144
190
  async function cleanApiDocs(options) {
145
191
  const { outputDir } = options;
146
192
  const apiDir = path_1.default.join(siteDir, outputDir);
147
- const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx"], {
193
+ const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
148
194
  cwd: path_1.default.resolve(apiDir),
149
195
  });
150
196
  const sidebarFile = await (0, utils_1.Globby)(["sidebar.js"], {
@@ -0,0 +1,2 @@
1
+ import { SecuritySchemeObject } from "../openapi/types";
2
+ export declare function createAuthentication(securitySchemes: SecuritySchemeObject): string;
@@ -0,0 +1,139 @@
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
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.createAuthentication = void 0;
10
+ const createDescription_1 = require("./createDescription");
11
+ const utils_1 = require("./utils");
12
+ function createAuthentication(securitySchemes) {
13
+ if (!securitySchemes || !Object.keys(securitySchemes).length)
14
+ return "";
15
+ const createAuthenticationTable = (securityScheme) => {
16
+ const { bearerFormat, flows, name, scheme, type } = securityScheme;
17
+ const createSecuritySchemeTypeRow = () => (0, utils_1.create)("tr", {
18
+ children: [
19
+ (0, utils_1.create)("th", { children: "Security Scheme Type:" }),
20
+ (0, utils_1.create)("td", { children: type }),
21
+ ],
22
+ });
23
+ const createOAuthFlowRows = () => {
24
+ const flowRows = Object.entries(flows).map(([flowType, flowObj]) => {
25
+ const { authorizationUrl, tokenUrl, refreshUrl, scopes } = flowObj;
26
+ return (0, utils_1.create)("tr", {
27
+ children: [
28
+ (0, utils_1.create)("th", { children: `${flowType} OAuth Flow:` }),
29
+ (0, utils_1.create)("td", {
30
+ children: [
31
+ (0, utils_1.guard)(tokenUrl, () => (0, utils_1.create)("p", { children: `Token URL: ${tokenUrl}` })),
32
+ (0, utils_1.guard)(authorizationUrl, () => (0, utils_1.create)("p", {
33
+ children: `Authorization URL: ${authorizationUrl}`,
34
+ })),
35
+ (0, utils_1.guard)(refreshUrl, () => (0, utils_1.create)("p", { children: `Refresh URL: ${refreshUrl}` })),
36
+ (0, utils_1.create)("span", { children: "Scopes:" }),
37
+ (0, utils_1.create)("ul", {
38
+ children: Object.entries(scopes).map(([scope, description]) => (0, utils_1.create)("li", { children: `${scope}: ${description}` })),
39
+ }),
40
+ ],
41
+ }),
42
+ ],
43
+ });
44
+ });
45
+ return flowRows.join("");
46
+ };
47
+ switch (type) {
48
+ case "apiKey":
49
+ return (0, utils_1.create)("div", {
50
+ children: [
51
+ (0, utils_1.create)("table", {
52
+ children: (0, utils_1.create)("tbody", {
53
+ children: [
54
+ createSecuritySchemeTypeRow(),
55
+ (0, utils_1.create)("tr", {
56
+ children: [
57
+ (0, utils_1.create)("th", { children: "Header parameter name:" }),
58
+ (0, utils_1.create)("td", { children: name }),
59
+ ],
60
+ }),
61
+ ],
62
+ }),
63
+ }),
64
+ ],
65
+ });
66
+ case "http":
67
+ return (0, utils_1.create)("div", {
68
+ children: [
69
+ (0, utils_1.create)("table", {
70
+ children: (0, utils_1.create)("tbody", {
71
+ children: [
72
+ createSecuritySchemeTypeRow(),
73
+ (0, utils_1.create)("tr", {
74
+ children: [
75
+ (0, utils_1.create)("th", { children: "HTTP Authorization Scheme:" }),
76
+ (0, utils_1.create)("td", { children: scheme }),
77
+ ],
78
+ }),
79
+ (0, utils_1.create)("tr", {
80
+ children: [
81
+ (0, utils_1.create)("th", { children: "Bearer format:" }),
82
+ (0, utils_1.create)("td", { children: bearerFormat }),
83
+ ],
84
+ }),
85
+ ],
86
+ }),
87
+ }),
88
+ ],
89
+ });
90
+ case "oauth2":
91
+ return (0, utils_1.create)("div", {
92
+ children: [
93
+ (0, utils_1.create)("table", {
94
+ children: (0, utils_1.create)("tbody", {
95
+ children: [
96
+ createSecuritySchemeTypeRow(),
97
+ createOAuthFlowRows(),
98
+ ],
99
+ }),
100
+ }),
101
+ ],
102
+ });
103
+ default:
104
+ return "";
105
+ }
106
+ };
107
+ const formatTabLabel = (str) => {
108
+ const formattedLabel = str
109
+ .replace(/(_|-)/g, " ")
110
+ .trim()
111
+ .replace(/\w\S*/g, (str) => str.charAt(0).toUpperCase() + str.substr(1))
112
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
113
+ .replace(/([A-Z])([A-Z][a-z])/g, "$1 $2");
114
+ const isOAuth = formattedLabel.toLowerCase().includes("oauth2");
115
+ const isApiKey = formattedLabel.toLowerCase().includes("api");
116
+ return isOAuth ? "OAuth 2.0" : isApiKey ? "API Key" : formattedLabel;
117
+ };
118
+ return (0, utils_1.create)("div", {
119
+ children: [
120
+ (0, utils_1.create)("h2", {
121
+ children: "Authentication",
122
+ id: "authentication",
123
+ style: { marginBottom: "1rem" },
124
+ }),
125
+ (0, utils_1.create)("Tabs", {
126
+ children: Object.entries(securitySchemes).map(([schemeType, schemeObj]) => (0, utils_1.create)("TabItem", {
127
+ label: formatTabLabel(schemeType),
128
+ value: `${schemeType}`,
129
+ children: [
130
+ (0, createDescription_1.createDescription)(schemeObj.description),
131
+ createAuthenticationTable(schemeObj),
132
+ ],
133
+ })),
134
+ }),
135
+ ],
136
+ style: { marginBottom: "2rem" },
137
+ });
138
+ }
139
+ exports.createAuthentication = createAuthentication;
@@ -1,3 +1,4 @@
1
- import { ApiPageMetadata, InfoPageMetadata } from "../types";
1
+ import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
2
2
  export declare function createApiPageMD({ title, api: { deprecated, "x-deprecated-description": deprecatedDescription, description, parameters, requestBody, responses, }, }: ApiPageMetadata): string;
3
- export declare function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, }: InfoPageMetadata): string;
3
+ export declare function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, securitySchemes, }: InfoPageMetadata): string;
4
+ export declare function createTagPageMD({ tag: { description } }: TagPageMetadata): string;
@@ -6,8 +6,9 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  * ========================================================================== */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.createInfoPageMD = exports.createApiPageMD = void 0;
9
+ exports.createTagPageMD = exports.createInfoPageMD = exports.createApiPageMD = void 0;
10
10
  const lodash_1 = require("lodash");
11
+ const createAuthentication_1 = require("./createAuthentication");
11
12
  const createContactInfo_1 = require("./createContactInfo");
12
13
  const createDeprecationNotice_1 = require("./createDeprecationNotice");
13
14
  const createDescription_1 = require("./createDescription");
@@ -36,14 +37,21 @@ function createApiPageMD({ title, api: { deprecated, "x-deprecated-description":
36
37
  ]);
37
38
  }
38
39
  exports.createApiPageMD = createApiPageMD;
39
- function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, }) {
40
+ function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, securitySchemes, }) {
40
41
  return (0, utils_1.render)([
42
+ `import Tabs from "@theme/Tabs";\n`,
43
+ `import TabItem from "@theme/TabItem";\n`,
41
44
  (0, createVersionBadge_1.createVersionBadge)(version),
42
45
  `# ${(0, lodash_1.escape)(title)}\n\n`,
43
46
  (0, createDescription_1.createDescription)(description),
47
+ (0, createAuthentication_1.createAuthentication)(securitySchemes),
44
48
  (0, createContactInfo_1.createContactInfo)(contact),
45
49
  (0, createTermsOfService_1.createTermsOfService)(termsOfService),
46
50
  (0, createLicense_1.createLicense)(license),
47
51
  ]);
48
52
  }
49
53
  exports.createInfoPageMD = createInfoPageMD;
54
+ function createTagPageMD({ tag: { description } }) {
55
+ return (0, utils_1.render)([(0, createDescription_1.createDescription)(description)]);
56
+ }
57
+ exports.createTagPageMD = createTagPageMD;
@@ -5,8 +5,12 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  * ========================================================================== */
8
+ var __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
8
11
  Object.defineProperty(exports, "__esModule", { value: true });
9
12
  exports.sampleFromSchema = void 0;
13
+ const chalk_1 = __importDefault(require("chalk"));
10
14
  const primitives = {
11
15
  string: {
12
16
  default: () => "string",
@@ -31,64 +35,70 @@ const primitives = {
31
35
  array: {},
32
36
  };
33
37
  const sampleFromSchema = (schema = {}) => {
34
- let { type, example, allOf, properties, items } = schema;
35
- if (example !== undefined) {
36
- return example;
37
- }
38
- if (allOf) {
39
- // TODO: We are just assuming it will always be an object for now
40
- let obj = {
41
- type: "object",
42
- properties: {},
43
- required: [], // NOTE: We shouldn't need to worry about required
44
- };
45
- for (let item of allOf) {
46
- if (item.properties) {
47
- obj.properties = {
48
- ...obj.properties,
49
- ...item.properties,
50
- };
51
- }
52
- }
53
- return (0, exports.sampleFromSchema)(obj);
54
- }
55
- if (!type) {
56
- if (properties) {
57
- type = "object";
38
+ try {
39
+ let { type, example, allOf, properties, items } = schema;
40
+ if (example !== undefined) {
41
+ return example;
58
42
  }
59
- else if (items) {
60
- type = "array";
43
+ if (allOf) {
44
+ // TODO: We are just assuming it will always be an object for now
45
+ let obj = {
46
+ type: "object",
47
+ properties: {},
48
+ required: [], // NOTE: We shouldn't need to worry about required
49
+ };
50
+ for (let item of allOf) {
51
+ if (item.properties) {
52
+ obj.properties = {
53
+ ...obj.properties,
54
+ ...item.properties,
55
+ };
56
+ }
57
+ }
58
+ return (0, exports.sampleFromSchema)(obj);
61
59
  }
62
- else {
63
- return;
60
+ if (!type) {
61
+ if (properties) {
62
+ type = "object";
63
+ }
64
+ else if (items) {
65
+ type = "array";
66
+ }
67
+ else {
68
+ return;
69
+ }
64
70
  }
65
- }
66
- if (type === "object") {
67
- let obj = {};
68
- for (let [name, prop] of Object.entries(properties !== null && properties !== void 0 ? properties : {})) {
69
- if (prop.deprecated) {
70
- continue;
71
+ if (type === "object") {
72
+ let obj = {};
73
+ for (let [name, prop] of Object.entries(properties !== null && properties !== void 0 ? properties : {})) {
74
+ if (prop.deprecated) {
75
+ continue;
76
+ }
77
+ obj[name] = (0, exports.sampleFromSchema)(prop);
71
78
  }
72
- obj[name] = (0, exports.sampleFromSchema)(prop);
79
+ return obj;
73
80
  }
74
- return obj;
75
- }
76
- if (type === "array") {
77
- if (Array.isArray(items === null || items === void 0 ? void 0 : items.anyOf)) {
78
- return items === null || items === void 0 ? void 0 : items.anyOf.map((item) => (0, exports.sampleFromSchema)(item));
81
+ if (type === "array") {
82
+ if (Array.isArray(items === null || items === void 0 ? void 0 : items.anyOf)) {
83
+ return items === null || items === void 0 ? void 0 : items.anyOf.map((item) => (0, exports.sampleFromSchema)(item));
84
+ }
85
+ if (Array.isArray(items === null || items === void 0 ? void 0 : items.oneOf)) {
86
+ return items === null || items === void 0 ? void 0 : items.oneOf.map((item) => (0, exports.sampleFromSchema)(item));
87
+ }
88
+ return [(0, exports.sampleFromSchema)(items)];
79
89
  }
80
- if (Array.isArray(items === null || items === void 0 ? void 0 : items.oneOf)) {
81
- return items === null || items === void 0 ? void 0 : items.oneOf.map((item) => (0, exports.sampleFromSchema)(item));
90
+ if (schema.enum) {
91
+ if (schema.default) {
92
+ return schema.default;
93
+ }
94
+ return normalizeArray(schema.enum)[0];
82
95
  }
83
- return [(0, exports.sampleFromSchema)(items)];
96
+ return primitive(schema);
84
97
  }
85
- if (schema.enum) {
86
- if (schema.default) {
87
- return schema.default;
88
- }
89
- return normalizeArray(schema.enum)[0];
98
+ catch (err) {
99
+ console.error(chalk_1.default.yellow("WARNING: failed to create example from schema object:", err));
100
+ return;
90
101
  }
91
- return primitive(schema);
92
102
  };
93
103
  exports.sampleFromSchema = sampleFromSchema;
94
104
  function primitive(schema = {}) {
@@ -1,4 +1,4 @@
1
- import { ApiMetadata } from "../types";
1
+ import { ApiMetadata, SidebarOptions } from "../types";
2
2
  import { OpenApiObjectWithRef, TagObject } from "./types";
3
3
  interface OpenApiFiles {
4
4
  source: string;
@@ -6,7 +6,7 @@ interface OpenApiFiles {
6
6
  data: OpenApiObjectWithRef;
7
7
  }
8
8
  export declare function readOpenapiFiles(openapiPath: string, _options: {}): Promise<OpenApiFiles[]>;
9
- export declare function processOpenapiFiles(files: OpenApiFiles[]): Promise<[ApiMetadata[], TagObject[]]>;
10
- export declare function processOpenapiFile(openapiDataWithRefs: OpenApiObjectWithRef): Promise<[ApiMetadata[], TagObject[]]>;
9
+ export declare function processOpenapiFiles(files: OpenApiFiles[], sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[]]>;
10
+ export declare function processOpenapiFile(openapiDataWithRefs: OpenApiObjectWithRef, sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[]]>;
11
11
  export declare function getTagDisplayName(tagName: string, tags: TagObject[]): string;
12
12
  export {};