docusaurus-plugin-openapi-docs 3.0.0-beta.8 → 3.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.
Files changed (36) hide show
  1. package/README.md +86 -61
  2. package/lib/index.d.ts +1 -1
  3. package/lib/index.js +24 -24
  4. package/lib/markdown/createRequestSchema.js +0 -6
  5. package/lib/markdown/createResponseSchema.js +0 -5
  6. package/lib/markdown/createSchema.d.ts +1 -1
  7. package/lib/markdown/createSchema.js +69 -63
  8. package/lib/markdown/createSchema.test.js +77 -0
  9. package/lib/markdown/createStatusCodes.js +1 -1
  10. package/lib/markdown/createVersionBadge.js +1 -1
  11. package/lib/markdown/utils.js +1 -1
  12. package/lib/openapi/openapi.js +38 -33
  13. package/lib/openapi/openapi.test.js +2 -0
  14. package/lib/openapi/types.d.ts +2 -1
  15. package/lib/options.js +3 -0
  16. package/lib/sidebars/index.js +30 -11
  17. package/lib/types.d.ts +4 -1
  18. package/package.json +4 -4
  19. package/src/index.ts +35 -31
  20. package/src/markdown/__snapshots__/createSchema.test.ts.snap +221 -0
  21. package/src/markdown/createRequestSchema.ts +0 -6
  22. package/src/markdown/createResponseSchema.ts +0 -6
  23. package/src/markdown/createSchema.test.ts +88 -0
  24. package/src/markdown/createSchema.ts +83 -81
  25. package/src/markdown/createStatusCodes.ts +1 -1
  26. package/src/markdown/createVersionBadge.ts +8 -4
  27. package/src/markdown/utils.ts +1 -1
  28. package/src/openapi/__fixtures__/examples/openapi.yaml +7 -0
  29. package/src/openapi/openapi.test.ts +4 -0
  30. package/src/openapi/openapi.ts +43 -33
  31. package/src/openapi/types.ts +2 -1
  32. package/src/openapi-to-postmanv2.d.ts +1 -1
  33. package/src/options.ts +3 -0
  34. package/src/postman-collection.d.ts +1 -1
  35. package/src/sidebars/index.ts +55 -27
  36. package/src/types.ts +4 -1
@@ -6,6 +6,7 @@
6
6
  * ========================================================================== */
7
7
 
8
8
  import clsx from "clsx";
9
+ import isEmpty from "lodash/isEmpty";
9
10
 
10
11
  import {
11
12
  createClosingArrayBracket,
@@ -44,7 +45,7 @@ export function mergeAllOf(allOf: SchemaObject[]) {
44
45
  ignoreAdditionalProperties: true,
45
46
  });
46
47
 
47
- const required = allOf.reduce((acc, cur) => {
48
+ const mergedRequired = allOf.reduce((acc, cur) => {
48
49
  if (Array.isArray(cur.required)) {
49
50
  const next = [...acc, ...cur.required];
50
51
  return next;
@@ -52,7 +53,7 @@ export function mergeAllOf(allOf: SchemaObject[]) {
52
53
  return acc;
53
54
  }, [] as any);
54
55
 
55
- return { mergedSchemas, required };
56
+ return { mergedSchemas, mergedRequired };
56
57
  }
57
58
 
58
59
  /**
@@ -129,6 +130,16 @@ function createAnyOneOf(schema: SchemaObject): any {
129
130
  */
130
131
  function createProperties(schema: SchemaObject) {
131
132
  const discriminator = schema.discriminator;
133
+ if (Object.keys(schema.properties!).length === 0) {
134
+ return create("SchemaItem", {
135
+ collapsible: false,
136
+ name: "",
137
+ required: false,
138
+ schemaName: "object",
139
+ qualifierMessage: undefined,
140
+ schema: {},
141
+ });
142
+ }
132
143
  return Object.entries(schema.properties!).map(([key, val]) => {
133
144
  return createEdges({
134
145
  name: key,
@@ -146,27 +157,29 @@ function createProperties(schema: SchemaObject) {
146
157
  */
147
158
  function createAdditionalProperties(schema: SchemaObject) {
148
159
  const additionalProperties = schema.additionalProperties;
149
- const type: string | unknown = additionalProperties?.type;
160
+ if (!additionalProperties) return [];
161
+
150
162
  // Handle free-form objects
151
- if (String(additionalProperties) === "true" && schema.type === "object") {
163
+ if (additionalProperties === true || isEmpty(additionalProperties)) {
152
164
  return create("SchemaItem", {
153
165
  name: "property name*",
154
166
  required: false,
155
167
  schemaName: "any",
156
- qualifierMessage: getQualifierMessage(schema.additionalProperties),
168
+ qualifierMessage: getQualifierMessage(schema),
157
169
  schema: schema,
158
170
  collapsible: false,
159
171
  discriminator: false,
160
172
  });
161
173
  }
174
+
175
+ // objects, arrays, complex schemas
162
176
  if (
163
- (type === "object" || type === "array") &&
164
- (additionalProperties?.properties ||
165
- additionalProperties?.items ||
166
- additionalProperties?.allOf ||
167
- additionalProperties?.additionalProperties ||
168
- additionalProperties?.oneOf ||
169
- additionalProperties?.anyOf)
177
+ additionalProperties.properties ||
178
+ additionalProperties.items ||
179
+ additionalProperties.allOf ||
180
+ additionalProperties.additionalProperties ||
181
+ additionalProperties.oneOf ||
182
+ additionalProperties.anyOf
170
183
  ) {
171
184
  const title = additionalProperties.title as string;
172
185
  const schemaName = getSchemaName(additionalProperties);
@@ -180,52 +193,27 @@ function createAdditionalProperties(schema: SchemaObject) {
180
193
  );
181
194
  }
182
195
 
196
+ // primitive types
183
197
  if (
184
- (schema.additionalProperties?.type as string) === "string" ||
185
- (schema.additionalProperties?.type as string) === "object" ||
186
- (schema.additionalProperties?.type as string) === "boolean" ||
187
- (schema.additionalProperties?.type as string) === "integer" ||
188
- (schema.additionalProperties?.type as string) === "number"
198
+ additionalProperties.type === "string" ||
199
+ additionalProperties.type === "boolean" ||
200
+ additionalProperties.type === "integer" ||
201
+ additionalProperties.type === "number"
189
202
  ) {
190
- const additionalProperties =
191
- schema.additionalProperties?.additionalProperties;
192
- if (additionalProperties !== undefined) {
193
- const type = schema.additionalProperties?.additionalProperties?.type;
194
- const schemaName = getSchemaName(
195
- schema.additionalProperties?.additionalProperties!
196
- );
197
- return create("SchemaItem", {
198
- name: "property name*",
199
- required: false,
200
- schemaName: schemaName ?? type,
201
- qualifierMessage:
202
- schema.additionalProperties ??
203
- getQualifierMessage(schema.additionalProperties),
204
- schema: schema,
205
- collapsible: false,
206
- discriminator: false,
207
- });
208
- }
209
- const schemaName = getSchemaName(schema.additionalProperties!);
203
+ const schemaName = getSchemaName(additionalProperties);
210
204
  return create("SchemaItem", {
211
205
  name: "property name*",
212
206
  required: false,
213
207
  schemaName: schemaName,
214
208
  qualifierMessage: getQualifierMessage(schema),
215
- schema: schema.additionalProperties,
209
+ schema: additionalProperties,
216
210
  collapsible: false,
217
211
  discriminator: false,
218
212
  });
219
213
  }
220
- return Object.entries(schema.additionalProperties!).map(([key, val]) =>
221
- createEdges({
222
- name: key,
223
- schema: val,
224
- required: Array.isArray(schema.required)
225
- ? schema.required.includes(key)
226
- : false,
227
- })
228
- );
214
+
215
+ // unknown
216
+ return [];
229
217
  }
230
218
 
231
219
  /**
@@ -260,9 +248,8 @@ function createItems(schema: SchemaObject) {
260
248
  // TODO: figure out if and how we should pass merged required array
261
249
  const {
262
250
  mergedSchemas,
263
- }: { mergedSchemas: SchemaObject; required: string[] } = mergeAllOf(
264
- schema.items?.allOf
265
- );
251
+ }: { mergedSchemas: SchemaObject; mergedRequired: string[] | boolean } =
252
+ mergeAllOf(schema.items?.allOf);
266
253
 
267
254
  // Handles combo anyOf/oneOf + properties
268
255
  if (
@@ -595,8 +582,19 @@ function createEdges({
595
582
  required,
596
583
  discriminator,
597
584
  }: EdgeProps): any {
598
- const schemaName = getSchemaName(schema);
585
+ if (SCHEMA_TYPE === "request") {
586
+ if (schema.readOnly && schema.readOnly === true) {
587
+ return undefined;
588
+ }
589
+ }
599
590
 
591
+ if (SCHEMA_TYPE === "response") {
592
+ if (schema.writeOnly && schema.writeOnly === true) {
593
+ return undefined;
594
+ }
595
+ }
596
+
597
+ const schemaName = getSchemaName(schema);
600
598
  if (discriminator !== undefined && discriminator.propertyName === name) {
601
599
  return createPropertyDiscriminator(
602
600
  name,
@@ -618,11 +616,22 @@ function createEdges({
618
616
  }
619
617
 
620
618
  if (schema.allOf !== undefined) {
621
- const {
622
- mergedSchemas,
623
- required,
624
- }: { mergedSchemas: SchemaObject; required: string[] | boolean } =
625
- mergeAllOf(schema.allOf);
619
+ const { mergedSchemas }: { mergedSchemas: SchemaObject } = mergeAllOf(
620
+ schema.allOf
621
+ );
622
+
623
+ if (SCHEMA_TYPE === "request") {
624
+ if (mergedSchemas.readOnly && mergedSchemas.readOnly === true) {
625
+ return undefined;
626
+ }
627
+ }
628
+
629
+ if (SCHEMA_TYPE === "response") {
630
+ if (mergedSchemas.writeOnly && mergedSchemas.writeOnly === true) {
631
+ return undefined;
632
+ }
633
+ }
634
+
626
635
  const mergedSchemaName = getSchemaName(mergedSchemas);
627
636
  if (
628
637
  mergedSchemas.oneOf !== undefined ||
@@ -668,18 +677,6 @@ function createEdges({
668
677
  );
669
678
  }
670
679
 
671
- if (SCHEMA_TYPE === "request") {
672
- if (mergedSchemas.readOnly && mergedSchemas.readOnly === true) {
673
- return undefined;
674
- }
675
- }
676
-
677
- if (SCHEMA_TYPE === "response") {
678
- if (mergedSchemas.writeOnly && mergedSchemas.writeOnly === true) {
679
- return undefined;
680
- }
681
- }
682
-
683
680
  return create("SchemaItem", {
684
681
  collapsible: false,
685
682
  name,
@@ -731,18 +728,6 @@ function createEdges({
731
728
  );
732
729
  }
733
730
 
734
- if (SCHEMA_TYPE === "request") {
735
- if (schema.readOnly && schema.readOnly === true) {
736
- return undefined;
737
- }
738
- }
739
-
740
- if (SCHEMA_TYPE === "response") {
741
- if (schema.writeOnly && schema.writeOnly === true) {
742
- return undefined;
743
- }
744
- }
745
-
746
731
  // primitives and array of non-objects
747
732
  return create("SchemaItem", {
748
733
  collapsible: false,
@@ -762,6 +747,17 @@ export function createNodes(
762
747
  schemaType: "request" | "response"
763
748
  ): any {
764
749
  SCHEMA_TYPE = schemaType;
750
+ if (SCHEMA_TYPE === "request") {
751
+ if (schema.readOnly && schema.readOnly === true) {
752
+ return undefined;
753
+ }
754
+ }
755
+
756
+ if (SCHEMA_TYPE === "response") {
757
+ if (schema.writeOnly && schema.writeOnly === true) {
758
+ return undefined;
759
+ }
760
+ }
765
761
  const nodes = [];
766
762
  // if (schema.discriminator !== undefined) {
767
763
  // return createDiscriminator(schema);
@@ -774,7 +770,13 @@ export function createNodes(
774
770
  if (schema.allOf !== undefined) {
775
771
  const { mergedSchemas } = mergeAllOf(schema.allOf);
776
772
 
777
- // allOf seems to always result in properties
773
+ if (
774
+ mergedSchemas.oneOf !== undefined ||
775
+ mergedSchemas.anyOf !== undefined
776
+ ) {
777
+ nodes.push(createAnyOneOf(mergedSchemas));
778
+ }
779
+
778
780
  if (mergedSchemas.properties !== undefined) {
779
781
  nodes.push(createProperties(mergedSchemas));
780
782
  }
@@ -285,7 +285,7 @@ export function createStatusCodes({ label, id, responses }: Props) {
285
285
  responseHeaders &&
286
286
  createDetails({
287
287
  className: "openapi-markdown__details",
288
- "data-collaposed": true,
288
+ "data-collapsed": true,
289
289
  open: false,
290
290
  style: { textAlign: "left", marginBottom: "1rem" },
291
291
  children: [
@@ -9,10 +9,14 @@ import { create, guard } from "./utils";
9
9
 
10
10
  export function createVersionBadge(version: string | undefined) {
11
11
  return guard(version, (version) => [
12
- create("span", {
13
- className: "theme-doc-version-badge badge badge--secondary",
14
- children: `Version: ${escape(version)}`,
15
- }),
12
+ create(
13
+ "span",
14
+ {
15
+ className: "theme-doc-version-badge badge badge--secondary",
16
+ children: `Version: ${escape(version)}`,
17
+ },
18
+ { inline: true }
19
+ ),
16
20
  `\n\n`,
17
21
  ]);
18
22
  }
@@ -61,7 +61,7 @@ export const lessThan =
61
61
  export const greaterThan =
62
62
  /(?<!(button|code|details|summary|hr|br|span|strong|small|table|thead|tbody|td|tr|th|h1|h2|h3|h4|h5|h6|title|p|em|b|i|u|strike|bold|a|li|ol|ul|img|svg|div|center|\/|\s|"|'))>/gu;
63
63
  export const codeFence = /`{1,3}[\s\S]*?`{1,3}/g;
64
- export const curlyBrackets = /([{|}])/g;
64
+ export const curlyBrackets = /([{}])/g;
65
65
  export const codeBlock = /(^```.*[\s\S]*?```$|`[^`].+?`)/gm;
66
66
 
67
67
  export function clean(value: string | undefined): string {
@@ -40,3 +40,10 @@ x-tagGroups:
40
40
  tags:
41
41
  - tag3
42
42
  - tag4
43
+
44
+ components:
45
+ schemas:
46
+ HelloString:
47
+ x-tags:
48
+ - tag1
49
+ type: string
@@ -31,6 +31,10 @@ describe("openapi", () => {
31
31
 
32
32
  expect(yaml?.data.tags).toBeDefined();
33
33
  expect(yaml?.data["x-tagGroups"]).toBeDefined();
34
+
35
+ expect(
36
+ yaml?.data.components?.schemas?.HelloString["x-tags"]
37
+ ).toBeDefined();
34
38
  });
35
39
  });
36
40
  });
@@ -8,15 +8,15 @@
8
8
  import path from "path";
9
9
 
10
10
  import { Globby, GlobExcludeDefault, posixPath } from "@docusaurus/utils";
11
- import Converter from "@paloaltonetworks/openapi-to-postmanv2";
12
- import sdk from "@paloaltonetworks/postman-collection";
13
- import Collection from "@paloaltonetworks/postman-collection";
14
11
  import chalk from "chalk";
15
12
  import fs from "fs-extra";
16
13
  import cloneDeep from "lodash/cloneDeep";
17
14
  import kebabCase from "lodash/kebabCase";
18
15
  import unionBy from "lodash/unionBy";
19
16
  import uniq from "lodash/uniq";
17
+ import Converter from "openapi-to-postmanv2";
18
+ import Collection from "postman-collection";
19
+ import sdk from "postman-collection";
20
20
 
21
21
  import { sampleRequestFromSchema } from "./createRequestExample";
22
22
  import { OpenApiObject, TagGroupObject, TagObject } from "./types";
@@ -410,43 +410,53 @@ function createItems(
410
410
  }
411
411
  }
412
412
 
413
- if (options?.showSchemas === true) {
413
+ if (
414
+ options?.showSchemas === true ||
415
+ Object.entries(openapiData?.components?.schemas ?? {})
416
+ .flatMap(([_, s]) => s["x-tags"])
417
+ .filter((item) => !!item).length > 0
418
+ ) {
414
419
  // Gather schemas
415
420
  for (let [schema, schemaObject] of Object.entries(
416
421
  openapiData?.components?.schemas ?? {}
417
422
  )) {
418
- const baseIdSpaces =
419
- schemaObject?.title?.replace(" ", "-").toLowerCase() ?? "";
420
- const baseId = kebabCase(baseIdSpaces);
421
-
422
- const schemaDescription = schemaObject.description;
423
- let splitDescription: any;
424
- if (schemaDescription) {
425
- splitDescription = schemaDescription.match(/[^\r\n]+/g);
426
- }
423
+ if (options?.showSchemas === true || schemaObject["x-tags"]) {
424
+ const baseIdSpaces =
425
+ schemaObject?.title?.replace(" ", "-").toLowerCase() ?? "";
426
+ const baseId = kebabCase(baseIdSpaces);
427
+
428
+ const schemaDescription = schemaObject.description;
429
+ let splitDescription: any;
430
+ if (schemaDescription) {
431
+ splitDescription = schemaDescription.match(/[^\r\n]+/g);
432
+ }
427
433
 
428
- const schemaPage: PartialPage<SchemaPageMetadata> = {
429
- type: "schema",
430
- id: baseId,
431
- infoId: infoId ?? "",
432
- unversionedId: baseId,
433
- title: schemaObject.title
434
- ? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
435
- : schema,
436
- description: schemaObject.description
437
- ? schemaObject.description.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
438
- : "",
439
- frontMatter: {
440
- description: splitDescription
441
- ? splitDescription[0]
442
- .replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
443
- .replace(/\s+$/, "")
434
+ const schemaPage: PartialPage<SchemaPageMetadata> = {
435
+ type: "schema",
436
+ id: baseId,
437
+ infoId: infoId ?? "",
438
+ unversionedId: baseId,
439
+ title: schemaObject.title
440
+ ? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
441
+ : schema,
442
+ description: schemaObject.description
443
+ ? schemaObject.description.replace(
444
+ /((?:^|[^\\])(?:\\{2})*)"/g,
445
+ "$1'"
446
+ )
444
447
  : "",
445
- },
446
- schema: schemaObject,
447
- };
448
+ frontMatter: {
449
+ description: splitDescription
450
+ ? splitDescription[0]
451
+ .replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
452
+ .replace(/\s+$/, "")
453
+ : "",
454
+ },
455
+ schema: schemaObject,
456
+ };
448
457
 
449
- items.push(schemaPage);
458
+ items.push(schemaPage);
459
+ }
450
460
  }
451
461
  }
452
462
 
@@ -341,7 +341,7 @@ export type SchemaObject = Omit<
341
341
  not?: SchemaObject;
342
342
  items?: SchemaObject;
343
343
  properties?: Map<SchemaObject>;
344
- additionalProperties?: Map<SchemaObject>;
344
+ additionalProperties?: boolean | SchemaObject;
345
345
 
346
346
  // OpenAPI additions
347
347
  nullable?: boolean;
@@ -352,6 +352,7 @@ export type SchemaObject = Omit<
352
352
  externalDocs?: ExternalDocumentationObject;
353
353
  example?: any;
354
354
  deprecated?: boolean;
355
+ "x-tags"?: string[];
355
356
  };
356
357
 
357
358
  export type SchemaObjectWithRef = Omit<
@@ -5,6 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- declare module "@paloaltonetworks/openapi-to-postmanv2" {
8
+ declare module "openapi-to-postmanv2" {
9
9
  export default any;
10
10
  }
package/src/options.ts CHANGED
@@ -23,6 +23,7 @@ const markdownGenerators = Joi.object({
23
23
 
24
24
  export const OptionsSchema = Joi.object({
25
25
  id: Joi.string().required(),
26
+ docsPlugin: Joi.string(),
26
27
  docsPluginId: Joi.string().required(),
27
28
  config: Joi.object()
28
29
  .pattern(
@@ -38,6 +39,7 @@ export const OptionsSchema = Joi.object({
38
39
  sidebarOptions: sidebarOptions,
39
40
  markdownGenerators: markdownGenerators,
40
41
  showSchemas: Joi.boolean(),
42
+ disableCompression: Joi.boolean(),
41
43
  version: Joi.string().when("versions", {
42
44
  is: Joi.exist(),
43
45
  then: Joi.required(),
@@ -57,6 +59,7 @@ export const OptionsSchema = Joi.object({
57
59
  outputDir: Joi.string().required(),
58
60
  label: Joi.string().required(),
59
61
  baseUrl: Joi.string().required(),
62
+ downloadUrl: Joi.string(),
60
63
  })
61
64
  ),
62
65
  })
@@ -5,6 +5,6 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  * ========================================================================== */
7
7
 
8
- declare module "@paloaltonetworks/postman-collection" {
8
+ declare module "postman-collection" {
9
9
  export default any;
10
10
  }
@@ -25,6 +25,7 @@ import type {
25
25
  APIOptions,
26
26
  ApiPageMetadata,
27
27
  ApiMetadata,
28
+ InfoPageMetadata,
28
29
  SchemaPageMetadata,
29
30
  } from "../types";
30
31
 
@@ -41,13 +42,13 @@ function isSchemaItem(item: ApiMetadata): item is ApiMetadata {
41
42
  }
42
43
 
43
44
  function groupByTags(
44
- items: ApiPageMetadata[],
45
+ items: ApiMetadata[],
45
46
  sidebarOptions: SidebarOptions,
46
47
  options: APIOptions,
47
48
  tags: TagObject[][],
48
49
  docPath: string
49
50
  ): ProcessedSidebar {
50
- let { outputDir, label } = options;
51
+ let { outputDir, label, showSchemas } = options;
51
52
 
52
53
  // Remove trailing slash before proceeding
53
54
  outputDir = outputDir.replace(/\/$/, "");
@@ -59,9 +60,9 @@ function groupByTags(
59
60
  categoryLinkSource,
60
61
  } = sidebarOptions;
61
62
 
62
- const apiItems = items.filter(isApiItem);
63
- const infoItems = items.filter(isInfoItem);
64
- const schemaItems = items.filter(isSchemaItem);
63
+ const apiItems = items.filter(isApiItem) as ApiPageMetadata[];
64
+ const infoItems = items.filter(isInfoItem) as InfoPageMetadata[];
65
+ const schemaItems = items.filter(isSchemaItem) as SchemaPageMetadata[];
65
66
  const intros = infoItems.map((item: any) => {
66
67
  return {
67
68
  id: item.id,
@@ -77,17 +78,25 @@ function groupByTags(
77
78
  .flatMap((item) => item.api.tags)
78
79
  .filter((item): item is string => !!item)
79
80
  );
81
+ const schemaTags = uniq(
82
+ schemaItems
83
+ .flatMap((item) => item.schema["x-tags"])
84
+ .filter((item): item is string => !!item)
85
+ );
80
86
 
81
- // Combine globally defined tags with operation tags
82
- // Only include global tag if referenced in operation tags
87
+ // Combine globally defined tags with operation and schema tags
88
+ // Only include global tag if referenced in operation/schema tags
83
89
  let apiTags: string[] = [];
84
90
  tags.flat().forEach((tag) => {
85
91
  // Should we also check x-displayName?
86
- if (operationTags.includes(tag.name!)) {
92
+ if (operationTags.includes(tag.name!) || schemaTags.includes(tag.name!)) {
87
93
  apiTags.push(tag.name!);
88
94
  }
89
95
  });
90
- apiTags = uniq(apiTags.concat(operationTags));
96
+
97
+ if (sidebarOptions.groupPathsBy !== "tagGroup") {
98
+ apiTags = uniq(apiTags.concat(operationTags, schemaTags));
99
+ }
91
100
 
92
101
  const basePath = docPath
93
102
  ? outputDir.split(docPath!)[1].replace(/^\/+/g, "")
@@ -107,9 +116,12 @@ function groupByTags(
107
116
  },
108
117
  item.api.method
109
118
  )
110
- : clsx({
111
- "menu__list-item--deprecated": item.schema.deprecated,
112
- });
119
+ : clsx(
120
+ {
121
+ "menu__list-item--deprecated": item.schema.deprecated,
122
+ },
123
+ "schema"
124
+ );
113
125
  return {
114
126
  type: "doc" as const,
115
127
  id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
@@ -183,15 +195,20 @@ function groupByTags(
183
195
  } as SidebarItemCategoryLinkConfig;
184
196
  }
185
197
 
198
+ const taggedApiItems = apiItems.filter(
199
+ (item) => !!item.api.tags?.includes(tag)
200
+ );
201
+ const taggedSchemaItems = schemaItems.filter(
202
+ (item) => !!item.schema["x-tags"]?.includes(tag)
203
+ );
204
+
186
205
  return {
187
206
  type: "category" as const,
188
207
  label: tagObject?.["x-displayName"] ?? tag,
189
208
  link: linkConfig,
190
209
  collapsible: sidebarCollapsible,
191
210
  collapsed: sidebarCollapsed,
192
- items: apiItems
193
- .filter((item) => !!item.api.tags?.includes(tag))
194
- .map(createDocItem),
211
+ items: [...taggedSchemaItems, ...taggedApiItems].map(createDocItem),
195
212
  };
196
213
  })
197
214
  .filter((item) => item.items.length > 0); // Filter out any categories with no items.
@@ -216,14 +233,16 @@ function groupByTags(
216
233
  }
217
234
 
218
235
  let schemas: SidebarItemCategory[] = [];
219
- if (schemaItems.length > 0) {
236
+ if (showSchemas && schemaItems.length > 0) {
220
237
  schemas = [
221
238
  {
222
239
  type: "category" as const,
223
240
  label: "Schemas",
224
241
  collapsible: sidebarCollapsible!,
225
242
  collapsed: sidebarCollapsed!,
226
- items: schemaItems.map(createDocItem),
243
+ items: schemaItems
244
+ .filter(({ schema }) => !schema["x-tags"])
245
+ .map(createDocItem),
227
246
  },
228
247
  ];
229
248
  }
@@ -248,6 +267,7 @@ export default function generateSidebarSlice(
248
267
  let sidebarSlice: ProcessedSidebar = [];
249
268
 
250
269
  if (sidebarOptions.groupPathsBy === "tagGroup") {
270
+ let schemasGroup: ProcessedSidebar = [];
251
271
  tagGroups?.forEach((tagGroup) => {
252
272
  //filter tags only included in group
253
273
  const filteredTags: TagObject[] = [];
@@ -263,24 +283,32 @@ export default function generateSidebarSlice(
263
283
  collapsible: true,
264
284
  collapsed: true,
265
285
  items: groupByTags(
266
- api as ApiPageMetadata[],
286
+ api,
267
287
  sidebarOptions,
268
288
  options,
269
289
  [filteredTags],
270
290
  docPath
271
291
  ),
272
- } as ProcessedSidebarItem;
292
+ };
273
293
 
274
- sidebarSlice.push(groupCategory);
294
+ if (options.showSchemas) {
295
+ // For the first tagGroup, save the generated "Schemas" category for later.
296
+ if (schemasGroup.length === 0) {
297
+ schemasGroup = groupCategory.items?.filter(
298
+ (item) => item.type === "category" && item.label === "Schemas"
299
+ );
300
+ }
301
+ // Remove the "Schemas" category from every `groupCategory`.
302
+ groupCategory.items = groupCategory.items.filter((item) =>
303
+ "label" in item ? item.label !== "Schemas" : true
304
+ );
305
+ }
306
+ sidebarSlice.push(groupCategory as ProcessedSidebarItem);
275
307
  });
308
+ // Add `schemasGroup` to the end of the sidebar.
309
+ sidebarSlice.push(...schemasGroup);
276
310
  } else if (sidebarOptions.groupPathsBy === "tag") {
277
- sidebarSlice = groupByTags(
278
- api as ApiPageMetadata[],
279
- sidebarOptions,
280
- options,
281
- tags,
282
- docPath
283
- );
311
+ sidebarSlice = groupByTags(api, sidebarOptions, options, tags, docPath);
284
312
  }
285
313
 
286
314
  return sidebarSlice;