docusaurus-plugin-openapi-docs 0.0.0-1109 → 0.0.0-1130

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.
@@ -45,7 +45,7 @@ const createDocItem = (item, { sidebarOptions: { customProps }, basePath }) => {
45
45
  className: className ? className : undefined,
46
46
  };
47
47
  };
48
- function groupByTags(items, sidebarOptions, options, tags, docPath) {
48
+ function groupByTags(items, sidebarOptions, options, tags, docPath, tagGroupKey) {
49
49
  var _a, _b;
50
50
  let { outputDir, label, showSchemas } = options;
51
51
  // Remove trailing slash before proceeding
@@ -102,9 +102,11 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
102
102
  if (infoItems.length === 1) {
103
103
  const infoItem = infoItems[0];
104
104
  const id = infoItem.id;
105
+ const docId = basePath === "" || undefined ? `${id}` : `${basePath}/${id}`;
105
106
  rootIntroDoc = {
106
107
  type: "doc",
107
- id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
108
+ id: docId,
109
+ ...(tagGroupKey && { key: (0, lodash_1.kebabCase)(`${tagGroupKey}-${docId}`) }),
108
110
  };
109
111
  }
110
112
  const tagged = apiTags
@@ -146,13 +148,27 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
146
148
  }
147
149
  const taggedApiItems = apiItems.filter((item) => { var _a; return !!((_a = item.api.tags) === null || _a === void 0 ? void 0 : _a.includes(tag)); });
148
150
  const taggedSchemaItems = schemaItems.filter((item) => { var _a; return !!((_a = item.schema["x-tags"]) === null || _a === void 0 ? void 0 : _a.includes(tag)); });
151
+ const categoryLabel = (_a = tagObject === null || tagObject === void 0 ? void 0 : tagObject["x-displayName"]) !== null && _a !== void 0 ? _a : tag;
152
+ const categoryKey = tagGroupKey
153
+ ? (0, lodash_1.kebabCase)(`${tagGroupKey}-${categoryLabel}`)
154
+ : undefined;
149
155
  return {
150
156
  type: "category",
151
- label: (_a = tagObject === null || tagObject === void 0 ? void 0 : tagObject["x-displayName"]) !== null && _a !== void 0 ? _a : tag,
157
+ label: categoryLabel,
158
+ ...(categoryKey && { key: categoryKey }),
152
159
  link: linkConfig,
153
160
  collapsible: sidebarCollapsible,
154
161
  collapsed: sidebarCollapsed,
155
- items: [...taggedSchemaItems, ...taggedApiItems].map((item) => createDocItemFn(item, createDocItemFnContext)),
162
+ items: [...taggedSchemaItems, ...taggedApiItems].map((item) => {
163
+ const docItem = createDocItemFn(item, createDocItemFnContext);
164
+ if (tagGroupKey && docItem.type === "doc") {
165
+ return {
166
+ ...docItem,
167
+ key: (0, lodash_1.kebabCase)(`${tagGroupKey}-${tag}-${docItem.id}`),
168
+ };
169
+ }
170
+ return docItem;
171
+ }),
156
172
  };
157
173
  })
158
174
  .filter((item) => item.items.length > 0); // Filter out any categories with no items.
@@ -208,12 +224,13 @@ function generateSidebarSlice(sidebarOptions, options, api, tags, docPath, tagGr
208
224
  filteredTags.push(tag);
209
225
  }
210
226
  });
227
+ const tagGroupKey = (0, lodash_1.kebabCase)(tagGroup.name);
211
228
  const groupCategory = {
212
229
  type: "category",
213
230
  label: tagGroup.name,
214
231
  collapsible: true,
215
232
  collapsed: true,
216
- items: groupByTags(api, sidebarOptions, options, [filteredTags], docPath),
233
+ items: groupByTags(api, sidebarOptions, options, [filteredTags], docPath, tagGroupKey),
217
234
  };
218
235
  if (options.showSchemas) {
219
236
  // For the first tagGroup, save the generated "Schemas" category for later.
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,68 @@
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 __importDefault = (this && this.__importDefault) || function (mod) {
9
+ return (mod && mod.__esModule) ? mod : { "default": mod };
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const index_1 = __importDefault(require("./index"));
13
+ describe("generateSidebarSlice", () => {
14
+ describe("tagGroup with overlapping tags", () => {
15
+ const mockApiItems = [
16
+ {
17
+ type: "api",
18
+ id: "get-books",
19
+ unversionedId: "get-books",
20
+ title: "Get Books",
21
+ description: "",
22
+ source: "",
23
+ sourceDirName: "",
24
+ permalink: "/get-books",
25
+ frontMatter: {},
26
+ api: {
27
+ method: "get",
28
+ path: "/books",
29
+ tags: ["Books", "Deprecated"],
30
+ jsonRequestBodyExample: "",
31
+ info: { title: "Test API", version: "1.0.0" },
32
+ },
33
+ },
34
+ ];
35
+ const mockTags = [
36
+ [
37
+ { name: "Books", description: "Book operations" },
38
+ { name: "Deprecated", description: "Deprecated endpoints" },
39
+ ],
40
+ ];
41
+ const mockTagGroups = [
42
+ { name: "Library", tags: ["Books"] },
43
+ { name: "Deprecation", tags: ["Deprecated"] },
44
+ ];
45
+ function collectKeys(obj) {
46
+ const keys = [];
47
+ JSON.stringify(obj, (k, v) => {
48
+ if (k === "key" && typeof v === "string") {
49
+ keys.push(v);
50
+ }
51
+ return v;
52
+ });
53
+ return keys;
54
+ }
55
+ it("should generate unique keys for items appearing in multiple tagGroups", () => {
56
+ const result = (0, index_1.default)({ groupPathsBy: "tagGroup" }, { outputDir: "docs/test", specPath: "" }, mockApiItems, mockTags, "", mockTagGroups);
57
+ const keys = collectKeys(result);
58
+ expect(keys.length).toBeGreaterThan(0);
59
+ expect(new Set(keys).size).toBe(keys.length);
60
+ });
61
+ it("should include tagGroup name in keys to differentiate same items", () => {
62
+ const result = (0, index_1.default)({ groupPathsBy: "tagGroup" }, { outputDir: "docs/test", specPath: "" }, mockApiItems, mockTags, "", mockTagGroups);
63
+ const keys = collectKeys(result);
64
+ expect(keys.filter((k) => k.includes("library")).length).toBeGreaterThan(0);
65
+ expect(keys.filter((k) => k.includes("deprecation")).length).toBeGreaterThan(0);
66
+ });
67
+ });
68
+ });
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-1109",
4
+ "version": "0.0.0-1130",
5
5
  "license": "MIT",
6
6
  "keywords": [
7
7
  "openapi",
@@ -65,5 +65,5 @@
65
65
  "engines": {
66
66
  "node": ">=14"
67
67
  },
68
- "gitHead": "96c769dd3f97f033600a157fb9b607b5a05b439e"
68
+ "gitHead": "5e9591e0e848677c7589a091580feffcc0a86b41"
69
69
  }
@@ -0,0 +1,94 @@
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 type { TagGroupObject, TagObject } from "../openapi/types";
9
+ import type { ApiMetadata } from "../types";
10
+ import generateSidebarSlice from "./index";
11
+
12
+ describe("generateSidebarSlice", () => {
13
+ describe("tagGroup with overlapping tags", () => {
14
+ const mockApiItems: ApiMetadata[] = [
15
+ {
16
+ type: "api",
17
+ id: "get-books",
18
+ unversionedId: "get-books",
19
+ title: "Get Books",
20
+ description: "",
21
+ source: "",
22
+ sourceDirName: "",
23
+ permalink: "/get-books",
24
+ frontMatter: {},
25
+ api: {
26
+ method: "get",
27
+ path: "/books",
28
+ tags: ["Books", "Deprecated"],
29
+ jsonRequestBodyExample: "",
30
+ info: { title: "Test API", version: "1.0.0" },
31
+ },
32
+ } as ApiMetadata,
33
+ ];
34
+
35
+ const mockTags: TagObject[][] = [
36
+ [
37
+ { name: "Books", description: "Book operations" },
38
+ { name: "Deprecated", description: "Deprecated endpoints" },
39
+ ],
40
+ ];
41
+
42
+ const mockTagGroups: TagGroupObject[] = [
43
+ { name: "Library", tags: ["Books"] },
44
+ { name: "Deprecation", tags: ["Deprecated"] },
45
+ ];
46
+
47
+ function collectKeys(obj: unknown): string[] {
48
+ const keys: string[] = [];
49
+ JSON.stringify(obj, (k, v) => {
50
+ if (k === "key" && typeof v === "string") {
51
+ keys.push(v);
52
+ }
53
+ return v;
54
+ });
55
+ return keys;
56
+ }
57
+
58
+ it("should generate unique keys for items appearing in multiple tagGroups", () => {
59
+ const result = generateSidebarSlice(
60
+ { groupPathsBy: "tagGroup" },
61
+ { outputDir: "docs/test", specPath: "" },
62
+ mockApiItems,
63
+ mockTags,
64
+ "",
65
+ mockTagGroups
66
+ );
67
+
68
+ const keys = collectKeys(result);
69
+
70
+ expect(keys.length).toBeGreaterThan(0);
71
+ expect(new Set(keys).size).toBe(keys.length);
72
+ });
73
+
74
+ it("should include tagGroup name in keys to differentiate same items", () => {
75
+ const result = generateSidebarSlice(
76
+ { groupPathsBy: "tagGroup" },
77
+ { outputDir: "docs/test", specPath: "" },
78
+ mockApiItems,
79
+ mockTags,
80
+ "",
81
+ mockTagGroups
82
+ );
83
+
84
+ const keys = collectKeys(result);
85
+
86
+ expect(keys.filter((k) => k.includes("library")).length).toBeGreaterThan(
87
+ 0
88
+ );
89
+ expect(
90
+ keys.filter((k) => k.includes("deprecation")).length
91
+ ).toBeGreaterThan(0);
92
+ });
93
+ });
94
+ });
@@ -77,7 +77,8 @@ function groupByTags(
77
77
  sidebarOptions: SidebarOptions,
78
78
  options: APIOptions,
79
79
  tags: TagObject[][],
80
- docPath: string
80
+ docPath: string,
81
+ tagGroupKey?: string
81
82
  ): ProcessedSidebar {
82
83
  let { outputDir, label, showSchemas } = options;
83
84
 
@@ -152,9 +153,11 @@ function groupByTags(
152
153
  if (infoItems.length === 1) {
153
154
  const infoItem = infoItems[0];
154
155
  const id = infoItem.id;
156
+ const docId = basePath === "" || undefined ? `${id}` : `${basePath}/${id}`;
155
157
  rootIntroDoc = {
156
158
  type: "doc" as const,
157
- id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
159
+ id: docId,
160
+ ...(tagGroupKey && { key: kebabCase(`${tagGroupKey}-${docId}`) }),
158
161
  };
159
162
  }
160
163
 
@@ -219,15 +222,28 @@ function groupByTags(
219
222
  (item) => !!item.schema["x-tags"]?.includes(tag)
220
223
  );
221
224
 
225
+ const categoryLabel = tagObject?.["x-displayName"] ?? tag;
226
+ const categoryKey = tagGroupKey
227
+ ? kebabCase(`${tagGroupKey}-${categoryLabel}`)
228
+ : undefined;
229
+
222
230
  return {
223
231
  type: "category" as const,
224
- label: tagObject?.["x-displayName"] ?? tag,
232
+ label: categoryLabel,
233
+ ...(categoryKey && { key: categoryKey }),
225
234
  link: linkConfig,
226
235
  collapsible: sidebarCollapsible,
227
236
  collapsed: sidebarCollapsed,
228
- items: [...taggedSchemaItems, ...taggedApiItems].map((item) =>
229
- createDocItemFn(item, createDocItemFnContext)
230
- ),
237
+ items: [...taggedSchemaItems, ...taggedApiItems].map((item) => {
238
+ const docItem = createDocItemFn(item, createDocItemFnContext);
239
+ if (tagGroupKey && docItem.type === "doc") {
240
+ return {
241
+ ...docItem,
242
+ key: kebabCase(`${tagGroupKey}-${tag}-${docItem.id}`),
243
+ };
244
+ }
245
+ return docItem;
246
+ }),
231
247
  };
232
248
  })
233
249
  .filter((item) => item.items.length > 0); // Filter out any categories with no items.
@@ -296,6 +312,8 @@ export default function generateSidebarSlice(
296
312
  }
297
313
  });
298
314
 
315
+ const tagGroupKey = kebabCase(tagGroup.name);
316
+
299
317
  const groupCategory = {
300
318
  type: "category" as const,
301
319
  label: tagGroup.name,
@@ -306,7 +324,8 @@ export default function generateSidebarSlice(
306
324
  sidebarOptions,
307
325
  options,
308
326
  [filteredTags],
309
- docPath
327
+ docPath,
328
+ tagGroupKey
310
329
  ),
311
330
  };
312
331