docusaurus-plugin-openapi-docs 1.0.1 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +110 -21
  2. package/lib/index.d.ts +7 -1
  3. package/lib/index.js +257 -22
  4. package/lib/markdown/createAuthentication.d.ts +2 -0
  5. package/lib/markdown/createAuthentication.js +139 -0
  6. package/lib/markdown/createContactInfo.d.ts +2 -0
  7. package/lib/markdown/createContactInfo.js +49 -0
  8. package/lib/markdown/createLicense.d.ts +2 -0
  9. package/lib/markdown/createLicense.js +33 -0
  10. package/lib/markdown/createParamsDetails.js +2 -0
  11. package/lib/markdown/createSchemaDetails.js +6 -1
  12. package/lib/markdown/createStatusCodes.js +1 -1
  13. package/lib/markdown/createTermsOfService.d.ts +1 -0
  14. package/lib/markdown/createTermsOfService.js +32 -0
  15. package/lib/markdown/index.d.ts +3 -2
  16. package/lib/markdown/index.js +17 -3
  17. package/lib/openapi/createExample.js +59 -49
  18. package/lib/openapi/openapi.d.ts +5 -4
  19. package/lib/openapi/openapi.js +94 -50
  20. package/lib/openapi/openapi.test.js +0 -6
  21. package/lib/openapi/types.d.ts +5 -1
  22. package/lib/openapi/utils/loadAndBundleSpec.d.ts +3 -0
  23. package/lib/openapi/utils/loadAndBundleSpec.js +44 -0
  24. package/lib/openapi/utils/types.d.ts +306 -0
  25. package/lib/{markdown/createRequestBodyTable.js → openapi/utils/types.js} +0 -6
  26. package/lib/options.d.ts +0 -2
  27. package/lib/options.js +36 -7
  28. package/lib/sidebars/index.d.ts +2 -1
  29. package/lib/sidebars/index.js +91 -35
  30. package/lib/sidebars/utils.d.ts +2 -0
  31. package/lib/sidebars/utils.js +31 -0
  32. package/lib/types.d.ts +35 -11
  33. package/package.json +10 -9
  34. package/src/index.ts +332 -25
  35. package/src/markdown/createAuthentication.ts +160 -0
  36. package/src/markdown/createContactInfo.ts +52 -0
  37. package/src/markdown/createLicense.ts +34 -0
  38. package/src/markdown/createParamsDetails.ts +2 -0
  39. package/src/markdown/createSchemaDetails.ts +8 -2
  40. package/src/markdown/createStatusCodes.ts +1 -1
  41. package/src/markdown/createTermsOfService.ts +30 -0
  42. package/src/markdown/index.ts +23 -3
  43. package/src/openapi/createExample.ts +59 -50
  44. package/src/openapi/openapi.test.ts +0 -6
  45. package/src/openapi/openapi.ts +115 -53
  46. package/src/openapi/types.ts +5 -1
  47. package/src/openapi/utils/loadAndBundleSpec.ts +62 -0
  48. package/src/openapi/utils/types.ts +303 -0
  49. package/src/options.ts +41 -8
  50. package/src/{markdown/createRequestBodyTable.ts → postman-collection.d.ts} +2 -9
  51. package/src/sidebars/index.ts +116 -36
  52. package/src/sidebars/utils.ts +29 -0
  53. package/src/types.ts +36 -10
  54. package/lib/markdown/createFullWidthTable.d.ts +0 -2
  55. package/lib/markdown/createFullWidthTable.js +0 -18
  56. package/lib/markdown/createParamsTable.d.ts +0 -7
  57. package/lib/markdown/createParamsTable.js +0 -80
  58. package/lib/markdown/createRequestBodyTable.d.ts +0 -6
  59. package/lib/markdown/createSchemaTable.d.ts +0 -14
  60. package/lib/markdown/createSchemaTable.js +0 -217
  61. package/src/markdown/createFullWidthTable.ts +0 -16
  62. package/src/markdown/createParamsTable.ts +0 -102
  63. package/src/markdown/createSchemaTable.ts +0 -275
  64. package/src/openapi/__fixtures__/examples/yogurtstore/_category_.json +0 -4
  65. package/src/openapi/__fixtures__/examples/yogurtstore/froyo.yaml +0 -13
  66. package/src/openapi/__fixtures__/examples/yogurtstore/nested/nested.yaml +0 -13
@@ -0,0 +1,303 @@
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
+ type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
9
+
10
+ export interface OpenAPISpec {
11
+ openapi: string;
12
+ info: OpenAPIInfo;
13
+ servers?: OpenAPIServer[];
14
+ paths: OpenAPIPaths;
15
+ components?: OpenAPIComponents;
16
+ security?: OpenAPISecurityRequirement[];
17
+ tags?: OpenAPITag[];
18
+ externalDocs?: OpenAPIExternalDocumentation;
19
+ "x-webhooks"?: OpenAPIPaths;
20
+ webhooks?: OpenAPIPaths;
21
+ }
22
+
23
+ export interface OpenAPIInfo {
24
+ title: string;
25
+ version: string;
26
+
27
+ description?: string;
28
+ summary?: string;
29
+ termsOfService?: string;
30
+ contact?: OpenAPIContact;
31
+ license?: OpenAPILicense;
32
+ }
33
+
34
+ export interface OpenAPIServer {
35
+ url: string;
36
+ description?: string;
37
+ variables?: { [name: string]: OpenAPIServerVariable };
38
+ }
39
+
40
+ export interface OpenAPIServerVariable {
41
+ enum?: string[];
42
+ default: string;
43
+ description?: string;
44
+ }
45
+
46
+ export interface OpenAPIPaths {
47
+ [path: string]: OpenAPIPath;
48
+ }
49
+ export interface OpenAPIRef {
50
+ $ref: string;
51
+ }
52
+
53
+ export type Referenced<T> = OpenAPIRef | T;
54
+
55
+ export interface OpenAPIPath {
56
+ summary?: string;
57
+ description?: string;
58
+ get?: OpenAPIOperation;
59
+ put?: OpenAPIOperation;
60
+ post?: OpenAPIOperation;
61
+ delete?: OpenAPIOperation;
62
+ options?: OpenAPIOperation;
63
+ head?: OpenAPIOperation;
64
+ patch?: OpenAPIOperation;
65
+ trace?: OpenAPIOperation;
66
+ servers?: OpenAPIServer[];
67
+ parameters?: Array<Referenced<OpenAPIParameter>>;
68
+ $ref?: string;
69
+ }
70
+
71
+ export interface OpenAPIXCodeSample {
72
+ lang: string;
73
+ label?: string;
74
+ source: string;
75
+ }
76
+
77
+ export interface OpenAPIOperation {
78
+ tags?: string[];
79
+ summary?: string;
80
+ description?: string;
81
+ externalDocs?: OpenAPIExternalDocumentation;
82
+ operationId?: string;
83
+ parameters?: Array<Referenced<OpenAPIParameter>>;
84
+ requestBody?: Referenced<OpenAPIRequestBody>;
85
+ responses: OpenAPIResponses;
86
+ callbacks?: { [name: string]: Referenced<OpenAPICallback> };
87
+ deprecated?: boolean;
88
+ security?: OpenAPISecurityRequirement[];
89
+ servers?: OpenAPIServer[];
90
+ "x-codeSamples"?: OpenAPIXCodeSample[];
91
+ "x-code-samples"?: OpenAPIXCodeSample[]; // deprecated
92
+ }
93
+
94
+ export interface OpenAPIParameter {
95
+ name: string;
96
+ in?: OpenAPIParameterLocation;
97
+ description?: string;
98
+ required?: boolean;
99
+ deprecated?: boolean;
100
+ allowEmptyValue?: boolean;
101
+ style?: OpenAPIParameterStyle;
102
+ explode?: boolean;
103
+ allowReserved?: boolean;
104
+ schema?: Referenced<OpenAPISchema>;
105
+ example?: any;
106
+ examples?: { [media: string]: Referenced<OpenAPIExample> };
107
+ content?: { [media: string]: OpenAPIMediaType };
108
+ encoding?: Record<string, OpenAPIEncoding>;
109
+ const?: any;
110
+ }
111
+
112
+ export interface OpenAPIExample {
113
+ value: any;
114
+ summary?: string;
115
+ description?: string;
116
+ externalValue?: string;
117
+ }
118
+
119
+ export interface OpenAPISchema {
120
+ $ref?: string;
121
+ type?: string | string[];
122
+ properties?: { [name: string]: OpenAPISchema };
123
+ patternProperties?: { [name: string]: OpenAPISchema };
124
+ additionalProperties?: boolean | OpenAPISchema;
125
+ unevaluatedProperties?: boolean | OpenAPISchema;
126
+ description?: string;
127
+ default?: any;
128
+ items?: OpenAPISchema | OpenAPISchema[] | boolean;
129
+ required?: string[];
130
+ readOnly?: boolean;
131
+ writeOnly?: boolean;
132
+ deprecated?: boolean;
133
+ format?: string;
134
+ externalDocs?: OpenAPIExternalDocumentation;
135
+ discriminator?: OpenAPIDiscriminator;
136
+ nullable?: boolean;
137
+ oneOf?: OpenAPISchema[];
138
+ anyOf?: OpenAPISchema[];
139
+ allOf?: OpenAPISchema[];
140
+ not?: OpenAPISchema;
141
+
142
+ title?: string;
143
+ multipleOf?: number;
144
+ maximum?: number;
145
+ exclusiveMaximum?: boolean | number;
146
+ minimum?: number;
147
+ exclusiveMinimum?: boolean | number;
148
+ maxLength?: number;
149
+ minLength?: number;
150
+ pattern?: string;
151
+ maxItems?: number;
152
+ minItems?: number;
153
+ uniqueItems?: boolean;
154
+ maxProperties?: number;
155
+ minProperties?: number;
156
+ enum?: any[];
157
+ example?: any;
158
+
159
+ if?: OpenAPISchema;
160
+ else?: OpenAPISchema;
161
+ then?: OpenAPISchema;
162
+ examples?: any[];
163
+ const?: string;
164
+ contentEncoding?: string;
165
+ contentMediaType?: string;
166
+ prefixItems?: OpenAPISchema[];
167
+ additionalItems?: OpenAPISchema | boolean;
168
+ }
169
+
170
+ export interface OpenAPIDiscriminator {
171
+ propertyName: string;
172
+ mapping?: { [name: string]: string };
173
+ "x-explicitMappingOnly"?: boolean;
174
+ }
175
+
176
+ export interface OpenAPIMediaType {
177
+ schema?: Referenced<OpenAPISchema>;
178
+ example?: any;
179
+ examples?: { [name: string]: Referenced<OpenAPIExample> };
180
+ encoding?: { [field: string]: OpenAPIEncoding };
181
+ }
182
+
183
+ export interface OpenAPIEncoding {
184
+ contentType: string;
185
+ headers?: { [name: string]: Referenced<OpenAPIHeader> };
186
+ style: OpenAPIParameterStyle;
187
+ explode: boolean;
188
+ allowReserved: boolean;
189
+ }
190
+
191
+ export type OpenAPIParameterLocation = "query" | "header" | "path" | "cookie";
192
+ export type OpenAPIParameterStyle =
193
+ | "matrix"
194
+ | "label"
195
+ | "form"
196
+ | "simple"
197
+ | "spaceDelimited"
198
+ | "pipeDelimited"
199
+ | "deepObject";
200
+
201
+ export interface OpenAPIRequestBody {
202
+ description?: string;
203
+ required?: boolean;
204
+ content: { [mime: string]: OpenAPIMediaType };
205
+
206
+ "x-examples"?: {
207
+ [mime: string]: { [name: string]: Referenced<OpenAPIExample> };
208
+ };
209
+ "x-example"?: { [mime: string]: any };
210
+ }
211
+
212
+ export interface OpenAPIResponses {
213
+ [code: string]: Referenced<OpenAPIResponse>;
214
+ }
215
+
216
+ export interface OpenAPIResponse
217
+ extends Pick<OpenAPIRequestBody, "description" | "x-examples" | "x-example"> {
218
+ headers?: { [name: string]: Referenced<OpenAPIHeader> };
219
+ links?: { [name: string]: Referenced<OpenAPILink> };
220
+ content?: { [mime: string]: OpenAPIMediaType };
221
+ }
222
+
223
+ export interface OpenAPILink {
224
+ $ref?: string;
225
+ }
226
+
227
+ export type OpenAPIHeader = Omit<OpenAPIParameter, "in" | "name">;
228
+
229
+ export interface OpenAPICallback {
230
+ [name: string]: OpenAPIPath;
231
+ }
232
+
233
+ export interface OpenAPIComponents {
234
+ schemas?: { [name: string]: Referenced<OpenAPISchema> };
235
+ responses?: { [name: string]: Referenced<OpenAPIResponse> };
236
+ parameters?: { [name: string]: Referenced<OpenAPIParameter> };
237
+ examples?: { [name: string]: Referenced<OpenAPIExample> };
238
+ requestBodies?: { [name: string]: Referenced<OpenAPIRequestBody> };
239
+ headers?: { [name: string]: Referenced<OpenAPIHeader> };
240
+ securitySchemes?: { [name: string]: Referenced<OpenAPISecurityScheme> };
241
+ links?: { [name: string]: Referenced<OpenAPILink> };
242
+ callbacks?: { [name: string]: Referenced<OpenAPICallback> };
243
+ }
244
+
245
+ export interface OpenAPISecurityRequirement {
246
+ [name: string]: string[];
247
+ }
248
+
249
+ export interface OpenAPISecurityScheme {
250
+ type: "apiKey" | "http" | "oauth2" | "openIdConnect";
251
+ description?: string;
252
+ name?: string;
253
+ in?: "query" | "header" | "cookie";
254
+ scheme?: string;
255
+ bearerFormat: string;
256
+ flows: {
257
+ implicit?: {
258
+ refreshUrl?: string;
259
+ scopes: Record<string, string>;
260
+ authorizationUrl: string;
261
+ };
262
+ password?: {
263
+ refreshUrl?: string;
264
+ scopes: Record<string, string>;
265
+ tokenUrl: string;
266
+ };
267
+ clientCredentials?: {
268
+ refreshUrl?: string;
269
+ scopes: Record<string, string>;
270
+ tokenUrl: string;
271
+ };
272
+ authorizationCode?: {
273
+ refreshUrl?: string;
274
+ scopes: Record<string, string>;
275
+ tokenUrl: string;
276
+ };
277
+ };
278
+ openIdConnectUrl?: string;
279
+ }
280
+
281
+ export interface OpenAPITag {
282
+ name: string;
283
+ description?: string;
284
+ externalDocs?: OpenAPIExternalDocumentation;
285
+ "x-displayName"?: string;
286
+ }
287
+
288
+ export interface OpenAPIExternalDocumentation {
289
+ description?: string;
290
+ url: string;
291
+ }
292
+
293
+ export interface OpenAPIContact {
294
+ name?: string;
295
+ url?: string;
296
+ email?: string;
297
+ }
298
+
299
+ export interface OpenAPILicense {
300
+ name: string;
301
+ url?: string;
302
+ identifier?: string;
303
+ }
package/src/options.ts CHANGED
@@ -7,14 +7,47 @@
7
7
 
8
8
  import { Joi } from "@docusaurus/utils-validation";
9
9
 
10
- import type { PluginOptions } from "./types";
11
-
12
- export const DEFAULT_OPTIONS: PluginOptions = {
13
- id: "default",
14
- config: {},
15
- };
10
+ const sidebarOptions = Joi.object({
11
+ groupPathsBy: Joi.string().valid("tag"),
12
+ categoryLinkSource: Joi.string().valid("tag", "info"),
13
+ customProps: Joi.object(),
14
+ sidebarCollapsible: Joi.boolean(),
15
+ sidebarCollapsed: Joi.boolean(),
16
+ });
16
17
 
17
18
  export const OptionsSchema = Joi.object({
18
- id: Joi.string().default(DEFAULT_OPTIONS.id),
19
- config: Joi.object().default(DEFAULT_OPTIONS.config),
19
+ id: Joi.string().required(),
20
+ docPluginId: Joi.string().required(),
21
+ config: Joi.object()
22
+ .pattern(
23
+ /^/,
24
+ Joi.object({
25
+ specPath: Joi.string().required(),
26
+ outputDir: Joi.string().required(),
27
+ template: Joi.string(),
28
+ sidebarOptions: sidebarOptions,
29
+ version: Joi.string().when("versions", {
30
+ is: Joi.exist(),
31
+ then: Joi.required(),
32
+ }),
33
+ label: Joi.string().when("versions", {
34
+ is: Joi.exist(),
35
+ then: Joi.required(),
36
+ }),
37
+ baseUrl: Joi.string().when("versions", {
38
+ is: Joi.exist(),
39
+ then: Joi.required(),
40
+ }),
41
+ versions: Joi.object().pattern(
42
+ /^/,
43
+ Joi.object({
44
+ specPath: Joi.string().required(),
45
+ outputDir: Joi.string().required(),
46
+ label: Joi.string().required(),
47
+ baseUrl: Joi.string().required(),
48
+ })
49
+ ),
50
+ })
51
+ )
52
+ .required(),
20
53
  });
@@ -5,13 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- import { createSchemaTable } from "./createSchemaTable";
9
-
10
- interface Props {
11
- title: string;
12
- body: any;
13
- }
14
-
15
- export function createRequestBodyTable({ title, body }: Props) {
16
- return createSchemaTable({ title, body });
8
+ declare module "@paloaltonetworks/postman-collection" {
9
+ export default any;
17
10
  }
@@ -7,11 +7,15 @@
7
7
 
8
8
  import {
9
9
  ProcessedSidebar,
10
+ SidebarItemCategory,
11
+ SidebarItemCategoryLinkConfig,
10
12
  SidebarItemDoc,
11
13
  } from "@docusaurus/plugin-content-docs/src/sidebars/types";
12
14
  import clsx from "clsx";
15
+ import { kebabCase } from "lodash";
13
16
  import uniq from "lodash/uniq";
14
17
 
18
+ import { TagObject } from "../openapi/types";
15
19
  import type {
16
20
  SidebarOptions,
17
21
  APIOptions,
@@ -23,37 +27,46 @@ function isApiItem(item: ApiMetadata): item is ApiMetadata {
23
27
  return item.type === "api";
24
28
  }
25
29
 
30
+ function isInfoItem(item: ApiMetadata): item is ApiMetadata {
31
+ return item.type === "info";
32
+ }
33
+
26
34
  function groupByTags(
27
35
  items: ApiPageMetadata[],
28
36
  sidebarOptions: SidebarOptions,
29
- options: APIOptions
37
+ options: APIOptions,
38
+ tags: TagObject[],
39
+ docPath: string
30
40
  ): ProcessedSidebar {
31
- // TODO: Figure out how to handle these
32
- // const intros = items.filter(isInfoItem).map((item) => {
33
- // return {
34
- // type: "link" as const,
35
- // label: item.title,
36
- // href: item.permalink,
37
- // docId: item.id,
38
- // };
39
- // });
40
-
41
41
  const { outputDir } = options;
42
- const { sidebarCollapsed, sidebarCollapsible, customProps } = sidebarOptions;
42
+ const {
43
+ sidebarCollapsed,
44
+ sidebarCollapsible,
45
+ customProps,
46
+ categoryLinkSource,
47
+ } = sidebarOptions;
43
48
 
44
49
  const apiItems = items.filter(isApiItem);
50
+ const infoItems = items.filter(isInfoItem);
51
+ const intros = infoItems.map((item: any) => {
52
+ return {
53
+ id: item.id,
54
+ title: item.title,
55
+ description: item.description,
56
+ tags: item.info.tags,
57
+ };
58
+ });
45
59
 
46
60
  // TODO: make sure we only take the first tag
47
- const tags = uniq(
61
+ const apiTags = uniq(
48
62
  apiItems
49
63
  .flatMap((item) => item.api.tags)
50
64
  .filter((item): item is string => !!item)
51
65
  );
52
66
 
53
- // TODO: optimize this or make it a function
54
- const basePath = outputDir
55
- .slice(outputDir.indexOf("/", 1))
56
- .replace(/^\/+/g, "");
67
+ const basePath = docPath
68
+ ? outputDir.split(docPath!)[1].replace(/^\/+/g, "")
69
+ : outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
57
70
 
58
71
  function createDocItem(item: ApiPageMetadata): SidebarItemDoc {
59
72
  const sidebar_label = item.frontMatter.sidebar_label;
@@ -61,7 +74,8 @@ function groupByTags(
61
74
  const id = item.id;
62
75
  return {
63
76
  type: "doc" as const,
64
- id: `${basePath}/${item.id}`,
77
+ id:
78
+ basePath === "" || undefined ? `${item.id}` : `${basePath}/${item.id}`,
65
79
  label: (sidebar_label as string) ?? title ?? id,
66
80
  customProps: customProps,
67
81
  className: clsx(
@@ -74,11 +88,61 @@ function groupByTags(
74
88
  };
75
89
  }
76
90
 
77
- const tagged = tags
91
+ let rootIntroDoc = undefined;
92
+ if (infoItems.length === 1) {
93
+ const infoItem = infoItems[0];
94
+ const id = infoItem.id;
95
+ rootIntroDoc = {
96
+ type: "doc" as const,
97
+ id: `${basePath}/${id}`,
98
+ };
99
+ }
100
+
101
+ const tagged = apiTags
78
102
  .map((tag) => {
103
+ // Map info object to tag
104
+ const taggedInfoObject = intros.find((i) =>
105
+ i.tags ? i.tags.includes(tag) : undefined
106
+ );
107
+ const tagObject = tags.flat().find(
108
+ (t) =>
109
+ (tag === t.name || tag === t["x-displayName"]) ?? {
110
+ name: tag,
111
+ description: `${tag} Index`,
112
+ }
113
+ );
114
+
115
+ // TODO: perhaps move this into a getLinkConfig() function
116
+ let linkConfig = undefined;
117
+ if (taggedInfoObject !== undefined && categoryLinkSource === "info") {
118
+ linkConfig = {
119
+ type: "doc",
120
+ id: `${basePath}/${taggedInfoObject.id}`,
121
+ } as SidebarItemCategoryLinkConfig;
122
+ }
123
+
124
+ // TODO: perhaps move this into a getLinkConfig() function
125
+ if (tagObject !== undefined && categoryLinkSource === "tag") {
126
+ const tagId = kebabCase(tagObject.name);
127
+ linkConfig = {
128
+ type: "doc",
129
+ id: `${basePath}/${tagId}`,
130
+ } as SidebarItemCategoryLinkConfig;
131
+ }
132
+
133
+ // Default behavior
134
+ if (categoryLinkSource === undefined) {
135
+ linkConfig = {
136
+ type: "generated-index" as "generated-index",
137
+ title: tag,
138
+ slug: "/category/" + kebabCase(tag),
139
+ } as SidebarItemCategoryLinkConfig;
140
+ }
141
+
79
142
  return {
80
143
  type: "category" as const,
81
144
  label: tag,
145
+ link: linkConfig,
82
146
  collapsible: sidebarCollapsible,
83
147
  collapsed: sidebarCollapsed,
84
148
  items: apiItems
@@ -88,33 +152,49 @@ function groupByTags(
88
152
  })
89
153
  .filter((item) => item.items.length > 0); // Filter out any categories with no items.
90
154
 
91
- // const untagged = [
92
- // // TODO: determine if needed and how
93
- // {
94
- // type: "category" as const,
95
- // label: "UNTAGGED",
96
- // // collapsible: options.sidebarCollapsible, TODO: add option
97
- // // collapsed: options.sidebarCollapsed, TODO: add option
98
- // items: apiItems
99
- // //@ts-ignore
100
- // .filter(({ api }) => api.tags === undefined || api.tags.length === 0)
101
- // .map(createDocItem),
102
- // },
103
- // ];
104
- return [...tagged];
155
+ // Handle items with no tag
156
+ const untaggedItems = apiItems
157
+ .filter(({ api }) => api.tags === undefined || api.tags.length === 0)
158
+ .map(createDocItem);
159
+ let untagged: SidebarItemCategory[] = [];
160
+ if (untaggedItems.length > 0) {
161
+ untagged = [
162
+ {
163
+ type: "category" as const,
164
+ label: "UNTAGGED",
165
+ collapsible: sidebarCollapsible!,
166
+ collapsed: sidebarCollapsed!,
167
+ items: apiItems
168
+ .filter(({ api }) => api.tags === undefined || api.tags.length === 0)
169
+ .map(createDocItem),
170
+ },
171
+ ];
172
+ }
173
+
174
+ // Shift root intro doc to top of sidebar
175
+ // TODO: Add input validation for categoryLinkSource options
176
+ if (rootIntroDoc && categoryLinkSource !== "info") {
177
+ tagged.unshift(rootIntroDoc as any);
178
+ }
179
+
180
+ return [...tagged, ...untagged];
105
181
  }
106
182
 
107
183
  export default function generateSidebarSlice(
108
184
  sidebarOptions: SidebarOptions,
109
185
  options: APIOptions,
110
- api: ApiMetadata[]
186
+ api: ApiMetadata[],
187
+ tags: TagObject[],
188
+ docPath: string
111
189
  ) {
112
190
  let sidebarSlice: ProcessedSidebar = [];
113
- if (sidebarOptions.groupPathsBy === "tags") {
191
+ if (sidebarOptions.groupPathsBy === "tag") {
114
192
  sidebarSlice = groupByTags(
115
193
  api as ApiPageMetadata[],
116
194
  sidebarOptions,
117
- options
195
+ options,
196
+ tags,
197
+ docPath
118
198
  );
119
199
  }
120
200
  return sidebarSlice;
@@ -0,0 +1,29 @@
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 { render } from "mustache";
9
+
10
+ export function versionSelector(versions: object[]) {
11
+ const template = `<div class="dropdown dropdown--hoverable dropdown--right">
12
+ <button class="button button--block button--sm button--secondary"><span>Select API Version</span></button>
13
+ <ul class="dropdown__menu">
14
+ {{#.}}<li><a class="dropdown__link" href="{{{baseUrl}}}">{{{label}}}</a></li>{{/.}}
15
+ </ul>
16
+ </div>
17
+ `;
18
+ const view = render(template, versions);
19
+ return view;
20
+ }
21
+
22
+ export function versionCrumb(version: string) {
23
+ const template = `<ul style="display: flex;" class="breadcrumbs breadcrumbs--sm">
24
+ <li style="margin-left: auto; margin-right: 0;" class="breadcrumbs__item breadcrumbs__item--active">
25
+ <a class="breadcrumbs__link"><span>{{{.}}}</span></a></li></ul>
26
+ `;
27
+ const view = render(template, version);
28
+ return view;
29
+ }