docusaurus-plugin-openapi-docs 0.0.0-359 → 0.0.0-360

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/lib/index.js CHANGED
@@ -25,7 +25,7 @@ function pluginOpenAPI(context, options) {
25
25
  const contentPath = path_1.default.resolve(siteDir, specPath);
26
26
  try {
27
27
  const openapiFiles = await (0, openapi_1.readOpenapiFiles)(contentPath, {});
28
- const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles);
28
+ const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles, sidebarOptions);
29
29
  if (!fs_1.default.existsSync(outputDir)) {
30
30
  try {
31
31
  fs_1.default.mkdirSync(outputDir, { recursive: true });
@@ -96,17 +96,40 @@ hide_title: true
96
96
  import DocCardList from '@theme/DocCardList';
97
97
  import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
98
98
 
99
+ <DocCardList items={useCurrentSidebarCategory().items}/>
100
+ \`\`\`
101
+ `;
102
+ const tagMdTemplate = template
103
+ ? fs_1.default.readFileSync(template).toString()
104
+ : `---
105
+ id: {{{id}}}
106
+ title: {{{description}}}
107
+ description: {{{description}}}
108
+ ---
109
+
110
+ {{{markdown}}}
111
+
112
+ \`\`\`mdx-code-block
113
+ import DocCardList from '@theme/DocCardList';
114
+ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
115
+
99
116
  <DocCardList items={useCurrentSidebarCategory().items}/>
100
117
  \`\`\`
101
118
  `;
102
119
  loadedApi.map(async (item) => {
103
- const markdown = item.type === "api" ? (0, markdown_1.createApiPageMD)(item) : (0, markdown_1.createInfoPageMD)(item);
120
+ const markdown = item.type === "api"
121
+ ? (0, markdown_1.createApiPageMD)(item)
122
+ : item.type === "info"
123
+ ? (0, markdown_1.createInfoPageMD)(item)
124
+ : (0, markdown_1.createTagPageMD)(item);
104
125
  item.markdown = markdown;
105
126
  if (item.type === "api") {
106
127
  item.json = JSON.stringify(item.api);
107
128
  }
108
129
  const view = (0, mustache_1.render)(mdTemplate, item);
109
130
  const utils = (0, mustache_1.render)(infoMdTemplate, item);
131
+ // eslint-disable-next-line testing-library/render-result-naming-convention
132
+ const tagUtils = (0, mustache_1.render)(tagMdTemplate, item);
110
133
  if (item.type === "api") {
111
134
  if (!fs_1.default.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
112
135
  try {
@@ -132,6 +155,17 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
132
155
  }
133
156
  }
134
157
  }
158
+ if (item.type === "tag") {
159
+ if (!fs_1.default.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
160
+ try {
161
+ fs_1.default.writeFileSync(`${outputDir}/${item.id}.tag.mdx`, tagUtils, "utf8");
162
+ console.log(chalk_1.default.green(`Successfully created "${outputDir}/${item.id}.tag.mdx"`));
163
+ }
164
+ catch (err) {
165
+ console.error(chalk_1.default.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`), chalk_1.default.yellow(err));
166
+ }
167
+ }
168
+ }
135
169
  return;
136
170
  });
137
171
  return;
@@ -144,7 +178,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
144
178
  async function cleanApiDocs(options) {
145
179
  const { outputDir } = options;
146
180
  const apiDir = path_1.default.join(siteDir, outputDir);
147
- const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx"], {
181
+ const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
148
182
  cwd: path_1.default.resolve(apiDir),
149
183
  });
150
184
  const sidebarFile = await (0, utils_1.Globby)(["sidebar.js"], {
@@ -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
3
  export declare function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, }: InfoPageMetadata): string;
4
+ export declare function createTagPageMD({ tag: { description } }: TagPageMetadata): string;
@@ -6,7 +6,7 @@
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
11
  const createContactInfo_1 = require("./createContactInfo");
12
12
  const createDeprecationNotice_1 = require("./createDeprecationNotice");
@@ -47,3 +47,7 @@ function createInfoPageMD({ info: { title, version, description, contact, licens
47
47
  ]);
48
48
  }
49
49
  exports.createInfoPageMD = createInfoPageMD;
50
+ function createTagPageMD({ tag: { description } }) {
51
+ return (0, utils_1.render)([(0, createDescription_1.createDescription)(description)]);
52
+ }
53
+ exports.createTagPageMD = createTagPageMD;
@@ -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 {};
@@ -63,12 +63,38 @@ async function createPostmanCollection(openapiData) {
63
63
  }
64
64
  return await jsonToCollection(data);
65
65
  }
66
- function createItems(openapiData) {
67
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
66
+ function createItems(openapiData, sidebarOptions) {
67
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
68
68
  // TODO: Find a better way to handle this
69
69
  let items = [];
70
- // Only create an info page if we have a description.
70
+ if ((sidebarOptions === null || sidebarOptions === void 0 ? void 0 : sidebarOptions.categoryLinkSource) === "tag") {
71
+ // Only create an tag pages if categoryLinkSource set to tag.
72
+ const tags = (_a = openapiData.tags) !== null && _a !== void 0 ? _a : [];
73
+ // eslint-disable-next-line array-callback-return
74
+ tags
75
+ .filter((tag) => { var _a; return !((_a = tag.description) === null || _a === void 0 ? void 0 : _a.includes("SchemaDefinition")); })
76
+ // eslint-disable-next-line array-callback-return
77
+ .map((tag) => {
78
+ var _a;
79
+ const description = getTagDisplayName(tag.name, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []);
80
+ const tagId = (0, lodash_1.kebabCase)(tag.name);
81
+ const tagPage = {
82
+ type: "tag",
83
+ id: tagId,
84
+ unversionedId: tagId,
85
+ title: description !== null && description !== void 0 ? description : "",
86
+ description: description !== null && description !== void 0 ? description : "",
87
+ slug: "/" + tagId,
88
+ frontMatter: {},
89
+ tag: {
90
+ ...tag,
91
+ },
92
+ };
93
+ items.push(tagPage);
94
+ });
95
+ }
71
96
  if (openapiData.info.description) {
97
+ // Only create an info page if we have a description.
72
98
  const infoId = (0, lodash_1.kebabCase)(openapiData.info.title);
73
99
  const infoPage = {
74
100
  type: "info",
@@ -80,8 +106,8 @@ function createItems(openapiData) {
80
106
  frontMatter: {},
81
107
  info: {
82
108
  ...openapiData.info,
83
- tags: (_a = openapiData.tags) === null || _a === void 0 ? void 0 : _a.map((tagName) => { var _a; return getTagDisplayName(tagName.name, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []); }),
84
- title: (_b = openapiData.info.title) !== null && _b !== void 0 ? _b : "Introduction",
109
+ tags: (_b = openapiData.tags) === null || _b === void 0 ? void 0 : _b.map((tagName) => { var _a; return getTagDisplayName(tagName.name, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []); }),
110
+ title: (_c = openapiData.info.title) !== null && _c !== void 0 ? _c : "Introduction",
85
111
  },
86
112
  };
87
113
  items.push(infoPage);
@@ -89,16 +115,16 @@ function createItems(openapiData) {
89
115
  for (let [path, pathObject] of Object.entries(openapiData.paths)) {
90
116
  const { $ref, description, parameters, servers, summary, ...rest } = pathObject;
91
117
  for (let [method, operationObject] of Object.entries({ ...rest })) {
92
- const title = (_d = (_c = operationObject.summary) !== null && _c !== void 0 ? _c : operationObject.operationId) !== null && _d !== void 0 ? _d : "Missing summary";
118
+ const title = (_e = (_d = operationObject.summary) !== null && _d !== void 0 ? _d : operationObject.operationId) !== null && _e !== void 0 ? _e : "Missing summary";
93
119
  if (operationObject.description === undefined) {
94
120
  operationObject.description =
95
- (_f = (_e = operationObject.summary) !== null && _e !== void 0 ? _e : operationObject.operationId) !== null && _f !== void 0 ? _f : "";
121
+ (_g = (_f = operationObject.summary) !== null && _f !== void 0 ? _f : operationObject.operationId) !== null && _g !== void 0 ? _g : "";
96
122
  }
97
123
  const baseId = (0, lodash_1.kebabCase)(title);
98
- const servers = (_h = (_g = operationObject.servers) !== null && _g !== void 0 ? _g : pathObject.servers) !== null && _h !== void 0 ? _h : openapiData.servers;
99
- const security = (_j = operationObject.security) !== null && _j !== void 0 ? _j : openapiData.security;
124
+ const servers = (_j = (_h = operationObject.servers) !== null && _h !== void 0 ? _h : pathObject.servers) !== null && _j !== void 0 ? _j : openapiData.servers;
125
+ const security = (_k = operationObject.security) !== null && _k !== void 0 ? _k : openapiData.security;
100
126
  // Add security schemes so we know how to handle security.
101
- const securitySchemes = (_k = openapiData.components) === null || _k === void 0 ? void 0 : _k.securitySchemes;
127
+ const securitySchemes = (_l = openapiData.components) === null || _l === void 0 ? void 0 : _l.securitySchemes;
102
128
  // Make sure schemes are lowercase. See: https://github.com/cloud-annotations/docusaurus-plugin-openapi/issues/79
103
129
  if (securitySchemes) {
104
130
  for (let securityScheme of Object.values(securitySchemes)) {
@@ -108,7 +134,7 @@ function createItems(openapiData) {
108
134
  }
109
135
  }
110
136
  let jsonRequestBodyExample;
111
- const body = (_m = (_l = operationObject.requestBody) === null || _l === void 0 ? void 0 : _l.content) === null || _m === void 0 ? void 0 : _m["application/json"];
137
+ const body = (_o = (_m = operationObject.requestBody) === null || _m === void 0 ? void 0 : _m.content) === null || _o === void 0 ? void 0 : _o["application/json"];
112
138
  if (body === null || body === void 0 ? void 0 : body.schema) {
113
139
  jsonRequestBodyExample = (0, createExample_1.sampleFromSchema)(body.schema);
114
140
  }
@@ -124,7 +150,7 @@ function createItems(openapiData) {
124
150
  frontMatter: {},
125
151
  api: {
126
152
  ...defaults,
127
- tags: (_o = operationObject.tags) === null || _o === void 0 ? void 0 : _o.map((tagName) => { var _a; return getTagDisplayName(tagName, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []); }),
153
+ tags: (_p = operationObject.tags) === null || _p === void 0 ? void 0 : _p.map((tagName) => { var _a; return getTagDisplayName(tagName, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []); }),
128
154
  method,
129
155
  path,
130
156
  servers,
@@ -149,7 +175,7 @@ function bindCollectionToApiItems(items, postmanCollection) {
149
175
  .getPath({ unresolved: true }) // unresolved returns "/:variableName" instead of "/<type>"
150
176
  .replace(/:([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
151
177
  const apiItem = items.find((item) => {
152
- if (item.type === "info") {
178
+ if (item.type === "info" || item.type === "tag") {
153
179
  return false;
154
180
  }
155
181
  return item.api.path === path && item.api.method === method;
@@ -192,9 +218,9 @@ async function readOpenapiFiles(openapiPath, _options) {
192
218
  ];
193
219
  }
194
220
  exports.readOpenapiFiles = readOpenapiFiles;
195
- async function processOpenapiFiles(files) {
221
+ async function processOpenapiFiles(files, sidebarOptions) {
196
222
  const promises = files.map(async (file) => {
197
- const processedFile = await processOpenapiFile(file.data);
223
+ const processedFile = await processOpenapiFile(file.data, sidebarOptions);
198
224
  const itemsObjectsArray = processedFile[0].map((item) => ({
199
225
  ...item,
200
226
  }));
@@ -213,10 +239,10 @@ async function processOpenapiFiles(files) {
213
239
  return [items, tags];
214
240
  }
215
241
  exports.processOpenapiFiles = processOpenapiFiles;
216
- async function processOpenapiFile(openapiDataWithRefs) {
242
+ async function processOpenapiFile(openapiDataWithRefs, sidebarOptions) {
217
243
  const openapiData = await resolveRefs(openapiDataWithRefs);
218
244
  const postmanCollection = await createPostmanCollection(openapiData);
219
- const items = createItems(openapiData);
245
+ const items = createItems(openapiData, sidebarOptions);
220
246
  bindCollectionToApiItems(items, postmanCollection);
221
247
  let tags = [];
222
248
  if (openapiData.tags !== undefined) {
@@ -85,12 +85,10 @@ function groupByTags(items, sidebarOptions, options, tags) {
85
85
  }
86
86
  // TODO: perhaps move this into a getLinkConfig() function
87
87
  if (tagObject !== undefined && categoryLinkSource === "tag") {
88
- const linkDescription = tagObject === null || tagObject === void 0 ? void 0 : tagObject.description;
88
+ const tagId = (0, lodash_1.kebabCase)(tagObject.name);
89
89
  linkConfig = {
90
- type: "generated-index",
91
- title: tag,
92
- description: linkDescription,
93
- slug: "/category/" + (0, lodash_1.kebabCase)(tag),
90
+ type: "doc",
91
+ id: `${basePath}/${tagId}`,
94
92
  };
95
93
  }
96
94
  // Default behavior
package/lib/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type Request from "@paloaltonetworks/postman-collection";
2
- import { InfoObject, OperationObject, SecuritySchemeObject } from "./openapi/types";
2
+ import { InfoObject, OperationObject, SecuritySchemeObject, TagObject } from "./openapi/types";
3
3
  export type { PropSidebarItemCategory, SidebarItemLink, PropSidebar, PropSidebarItem, } from "@docusaurus/plugin-content-docs-types";
4
4
  export interface PluginOptions {
5
5
  id?: string;
@@ -16,7 +16,7 @@ export interface APIOptions {
16
16
  export interface LoadedContent {
17
17
  loadedApi: ApiMetadata[];
18
18
  }
19
- export declare type ApiMetadata = ApiPageMetadata | InfoPageMetadata;
19
+ export declare type ApiMetadata = ApiPageMetadata | InfoPageMetadata | TagPageMetadata;
20
20
  export interface ApiMetadataBase {
21
21
  sidebar?: string;
22
22
  previous?: ApiNavLink;
@@ -53,6 +53,11 @@ export interface InfoPageMetadata extends ApiMetadataBase {
53
53
  info: ApiInfo;
54
54
  markdown?: string;
55
55
  }
56
+ export interface TagPageMetadata extends ApiMetadataBase {
57
+ type: "tag";
58
+ tag: TagObject;
59
+ markdown?: string;
60
+ }
56
61
  export declare type ApiInfo = InfoObject;
57
62
  export interface ApiNavLink {
58
63
  title: 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": "0.0.0-359",
4
+ "version": "0.0.0-360",
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": "ec537d885e9432e381404f0b741b70b3156766d2"
63
+ "gitHead": "68ef835e7fa974cbf00ea0ccab6945b3c7ef2ba7"
64
64
  }
package/src/index.ts CHANGED
@@ -13,7 +13,7 @@ import { Globby } from "@docusaurus/utils";
13
13
  import chalk from "chalk";
14
14
  import { render } from "mustache";
15
15
 
16
- import { createApiPageMD, createInfoPageMD } from "./markdown";
16
+ import { createApiPageMD, createInfoPageMD, createTagPageMD } from "./markdown";
17
17
  import { readOpenapiFiles, processOpenapiFiles } from "./openapi";
18
18
  import generateSidebarSlice from "./sidebars";
19
19
  import type { PluginOptions, LoadedContent, APIOptions } from "./types";
@@ -32,7 +32,10 @@ export default function pluginOpenAPI(
32
32
 
33
33
  try {
34
34
  const openapiFiles = await readOpenapiFiles(contentPath, {});
35
- const [loadedApi, tags] = await processOpenapiFiles(openapiFiles);
35
+ const [loadedApi, tags] = await processOpenapiFiles(
36
+ openapiFiles,
37
+ sidebarOptions!
38
+ );
36
39
  if (!fs.existsSync(outputDir)) {
37
40
  try {
38
41
  fs.mkdirSync(outputDir, { recursive: true });
@@ -119,19 +122,43 @@ hide_title: true
119
122
  import DocCardList from '@theme/DocCardList';
120
123
  import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
121
124
 
125
+ <DocCardList items={useCurrentSidebarCategory().items}/>
126
+ \`\`\`
127
+ `;
128
+
129
+ const tagMdTemplate = template
130
+ ? fs.readFileSync(template).toString()
131
+ : `---
132
+ id: {{{id}}}
133
+ title: {{{description}}}
134
+ description: {{{description}}}
135
+ ---
136
+
137
+ {{{markdown}}}
138
+
139
+ \`\`\`mdx-code-block
140
+ import DocCardList from '@theme/DocCardList';
141
+ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
142
+
122
143
  <DocCardList items={useCurrentSidebarCategory().items}/>
123
144
  \`\`\`
124
145
  `;
125
146
 
126
147
  loadedApi.map(async (item) => {
127
148
  const markdown =
128
- item.type === "api" ? createApiPageMD(item) : createInfoPageMD(item);
149
+ item.type === "api"
150
+ ? createApiPageMD(item)
151
+ : item.type === "info"
152
+ ? createInfoPageMD(item)
153
+ : createTagPageMD(item);
129
154
  item.markdown = markdown;
130
155
  if (item.type === "api") {
131
156
  item.json = JSON.stringify(item.api);
132
157
  }
133
158
  const view = render(mdTemplate, item);
134
159
  const utils = render(infoMdTemplate, item);
160
+ // eslint-disable-next-line testing-library/render-result-naming-convention
161
+ const tagUtils = render(tagMdTemplate, item);
135
162
 
136
163
  if (item.type === "api") {
137
164
  if (!fs.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
@@ -179,8 +206,31 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
179
206
  }
180
207
  }
181
208
  }
209
+
210
+ if (item.type === "tag") {
211
+ if (!fs.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
212
+ try {
213
+ fs.writeFileSync(
214
+ `${outputDir}/${item.id}.tag.mdx`,
215
+ tagUtils,
216
+ "utf8"
217
+ );
218
+ console.log(
219
+ chalk.green(
220
+ `Successfully created "${outputDir}/${item.id}.tag.mdx"`
221
+ )
222
+ );
223
+ } catch (err) {
224
+ console.error(
225
+ chalk.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`),
226
+ chalk.yellow(err)
227
+ );
228
+ }
229
+ }
230
+ }
182
231
  return;
183
232
  });
233
+
184
234
  return;
185
235
  } catch (e) {
186
236
  console.error(chalk.red(`Loading of api failed for "${contentPath}"`));
@@ -191,7 +241,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
191
241
  async function cleanApiDocs(options: APIOptions) {
192
242
  const { outputDir } = options;
193
243
  const apiDir = path.join(siteDir, outputDir);
194
- const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx"], {
244
+ const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
195
245
  cwd: path.resolve(apiDir),
196
246
  });
197
247
  const sidebarFile = await Globby(["sidebar.js"], {
@@ -8,7 +8,7 @@
8
8
  import { escape } from "lodash";
9
9
 
10
10
  import { ContactObject, LicenseObject } from "../openapi/types";
11
- import { ApiPageMetadata, InfoPageMetadata } from "../types";
11
+ import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
12
12
  import { createContactInfo } from "./createContactInfo";
13
13
  import { createDeprecationNotice } from "./createDeprecationNotice";
14
14
  import { createDescription } from "./createDescription";
@@ -60,3 +60,7 @@ export function createInfoPageMD({
60
60
  createLicense(license as LicenseObject),
61
61
  ]);
62
62
  }
63
+
64
+ export function createTagPageMD({ tag: { description } }: TagPageMetadata) {
65
+ return render([createDescription(description)]);
66
+ }
@@ -17,7 +17,13 @@ import yaml from "js-yaml";
17
17
  import JsonRefs from "json-refs";
18
18
  import { kebabCase } from "lodash";
19
19
 
20
- import { ApiMetadata, ApiPageMetadata, InfoPageMetadata } from "../types";
20
+ import {
21
+ ApiMetadata,
22
+ ApiPageMetadata,
23
+ InfoPageMetadata,
24
+ SidebarOptions,
25
+ TagPageMetadata,
26
+ } from "../types";
21
27
  import { sampleFromSchema } from "./createExample";
22
28
  import { OpenApiObject, OpenApiObjectWithRef, TagObject } from "./types";
23
29
 
@@ -75,12 +81,44 @@ async function createPostmanCollection(
75
81
 
76
82
  type PartialPage<T> = Omit<T, "permalink" | "source" | "sourceDirName">;
77
83
 
78
- function createItems(openapiData: OpenApiObject): ApiMetadata[] {
84
+ function createItems(
85
+ openapiData: OpenApiObject,
86
+ sidebarOptions: SidebarOptions
87
+ ): ApiMetadata[] {
79
88
  // TODO: Find a better way to handle this
80
89
  let items: PartialPage<ApiMetadata>[] = [];
81
90
 
82
- // Only create an info page if we have a description.
91
+ if (sidebarOptions?.categoryLinkSource === "tag") {
92
+ // Only create an tag pages if categoryLinkSource set to tag.
93
+ const tags: TagObject[] = openapiData.tags ?? [];
94
+ // eslint-disable-next-line array-callback-return
95
+ tags
96
+ .filter((tag) => !tag.description?.includes("SchemaDefinition"))
97
+ // eslint-disable-next-line array-callback-return
98
+ .map((tag) => {
99
+ const description = getTagDisplayName(
100
+ tag.name!,
101
+ openapiData.tags ?? []
102
+ );
103
+ const tagId = kebabCase(tag.name);
104
+ const tagPage: PartialPage<TagPageMetadata> = {
105
+ type: "tag",
106
+ id: tagId,
107
+ unversionedId: tagId,
108
+ title: description ?? "",
109
+ description: description ?? "",
110
+ slug: "/" + tagId,
111
+ frontMatter: {},
112
+ tag: {
113
+ ...tag,
114
+ },
115
+ };
116
+ items.push(tagPage);
117
+ });
118
+ }
119
+
83
120
  if (openapiData.info.description) {
121
+ // Only create an info page if we have a description.
84
122
  const infoId = kebabCase(openapiData.info.title);
85
123
  const infoPage: PartialPage<InfoPageMetadata> = {
86
124
  type: "info",
@@ -186,7 +224,7 @@ function bindCollectionToApiItems(
186
224
  .replace(/:([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
187
225
 
188
226
  const apiItem = items.find((item) => {
189
- if (item.type === "info") {
227
+ if (item.type === "info" || item.type === "tag") {
190
228
  return false;
191
229
  }
192
230
  return item.api.path === path && item.api.method === method;
@@ -248,10 +286,11 @@ export async function readOpenapiFiles(
248
286
  }
249
287
 
250
288
  export async function processOpenapiFiles(
251
- files: OpenApiFiles[]
289
+ files: OpenApiFiles[],
290
+ sidebarOptions: SidebarOptions
252
291
  ): Promise<[ApiMetadata[], TagObject[]]> {
253
292
  const promises = files.map(async (file) => {
254
- const processedFile = await processOpenapiFile(file.data);
293
+ const processedFile = await processOpenapiFile(file.data, sidebarOptions);
255
294
  const itemsObjectsArray = processedFile[0].map((item) => ({
256
295
  ...item,
257
296
  }));
@@ -271,11 +310,12 @@ export async function processOpenapiFiles(
271
310
  }
272
311
 
273
312
  export async function processOpenapiFile(
274
- openapiDataWithRefs: OpenApiObjectWithRef
313
+ openapiDataWithRefs: OpenApiObjectWithRef,
314
+ sidebarOptions: SidebarOptions
275
315
  ): Promise<[ApiMetadata[], TagObject[]]> {
276
316
  const openapiData = await resolveRefs(openapiDataWithRefs);
277
317
  const postmanCollection = await createPostmanCollection(openapiData);
278
- const items = createItems(openapiData);
318
+ const items = createItems(openapiData, sidebarOptions);
279
319
 
280
320
  bindCollectionToApiItems(items, postmanCollection);
281
321
 
@@ -122,12 +122,10 @@ function groupByTags(
122
122
 
123
123
  // TODO: perhaps move this into a getLinkConfig() function
124
124
  if (tagObject !== undefined && categoryLinkSource === "tag") {
125
- const linkDescription = tagObject?.description;
125
+ const tagId = kebabCase(tagObject.name);
126
126
  linkConfig = {
127
- type: "generated-index" as "generated-index",
128
- title: tag,
129
- description: linkDescription,
130
- slug: "/category/" + kebabCase(tag),
127
+ type: "doc",
128
+ id: `${basePath}/${tagId}`,
131
129
  } as SidebarItemCategoryLinkConfig;
132
130
  }
133
131
 
package/src/types.ts CHANGED
@@ -11,6 +11,7 @@ import {
11
11
  InfoObject,
12
12
  OperationObject,
13
13
  SecuritySchemeObject,
14
+ TagObject,
14
15
  } from "./openapi/types";
15
16
 
16
17
  export type {
@@ -38,7 +39,7 @@ export interface LoadedContent {
38
39
  // loadedDocs: DocPageMetadata[]; TODO: cleanup
39
40
  }
40
41
 
41
- export type ApiMetadata = ApiPageMetadata | InfoPageMetadata;
42
+ export type ApiMetadata = ApiPageMetadata | InfoPageMetadata | TagPageMetadata;
42
43
 
43
44
  export interface ApiMetadataBase {
44
45
  sidebar?: string;
@@ -81,6 +82,12 @@ export interface InfoPageMetadata extends ApiMetadataBase {
81
82
  markdown?: string;
82
83
  }
83
84
 
85
+ export interface TagPageMetadata extends ApiMetadataBase {
86
+ type: "tag";
87
+ tag: TagObject;
88
+ markdown?: string;
89
+ }
90
+
84
91
  export type ApiInfo = InfoObject;
85
92
 
86
93
  export interface ApiNavLink {