From 49396b7c61e5cabe548ff9f53fadc888dcb629b4 Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 13:00:44 -0500 Subject: [PATCH 01/10] introduce x-tags onto SchemaObject type, and revise sidebar types A few of the types in the `sidebars/index.ts` page have been changed to allow for more proper typing of both api items and schema items. --- .../src/openapi/types.ts | 1 + .../src/sidebars/index.ts | 19 +++++++------------ 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/docusaurus-plugin-openapi-docs/src/openapi/types.ts b/packages/docusaurus-plugin-openapi-docs/src/openapi/types.ts index 147cc943c..b9e45c48a 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/openapi/types.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/openapi/types.ts @@ -352,6 +352,7 @@ export type SchemaObject = Omit< externalDocs?: ExternalDocumentationObject; example?: any; deprecated?: boolean; + "x-tags"?: string[]; }; export type SchemaObjectWithRef = Omit< diff --git a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts index fd8ec3d7d..b58048b67 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts @@ -25,6 +25,7 @@ import type { APIOptions, ApiPageMetadata, ApiMetadata, + InfoPageMetadata, SchemaPageMetadata, } from "../types"; @@ -41,7 +42,7 @@ function isSchemaItem(item: ApiMetadata): item is ApiMetadata { } function groupByTags( - items: ApiPageMetadata[], + items: ApiMetadata[], sidebarOptions: SidebarOptions, options: APIOptions, tags: TagObject[][], @@ -59,9 +60,9 @@ function groupByTags( categoryLinkSource, } = sidebarOptions; - const apiItems = items.filter(isApiItem); - const infoItems = items.filter(isInfoItem); - const schemaItems = items.filter(isSchemaItem); + const apiItems = items.filter(isApiItem) as ApiPageMetadata[]; + const infoItems = items.filter(isInfoItem) as InfoPageMetadata[]; + const schemaItems = items.filter(isSchemaItem) as SchemaPageMetadata[]; const intros = infoItems.map((item: any) => { return { id: item.id, @@ -263,7 +264,7 @@ export default function generateSidebarSlice( collapsible: true, collapsed: true, items: groupByTags( - api as ApiPageMetadata[], + api, sidebarOptions, options, [filteredTags], @@ -274,13 +275,7 @@ export default function generateSidebarSlice( sidebarSlice.push(groupCategory); }); } else if (sidebarOptions.groupPathsBy === "tag") { - sidebarSlice = groupByTags( - api as ApiPageMetadata[], - sidebarOptions, - options, - tags, - docPath - ); + sidebarSlice = groupByTags(api, sidebarOptions, options, tags, docPath); } return sidebarSlice; From 2e235d02ddc5eebebb45f3a237ada4e1f787946c Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 13:04:21 -0500 Subject: [PATCH 02/10] add schemas with x-tags into the tag category sidebar slice --- .../src/sidebars/index.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts index b58048b67..0930f544f 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts @@ -48,7 +48,7 @@ function groupByTags( tags: TagObject[][], docPath: string ): ProcessedSidebar { - let { outputDir, label } = options; + let { outputDir, label, showSchemas } = options; // Remove trailing slash before proceeding outputDir = outputDir.replace(/\/$/, ""); @@ -184,15 +184,20 @@ function groupByTags( } as SidebarItemCategoryLinkConfig; } + const taggedApiItems = apiItems.filter( + (item) => !!item.api.tags?.includes(tag) + ); + const taggedSchemaItems = schemaItems.filter( + (item) => !!item.schema["x-tags"]?.includes(tag) + ); + return { type: "category" as const, label: tagObject?.["x-displayName"] ?? tag, link: linkConfig, collapsible: sidebarCollapsible, collapsed: sidebarCollapsed, - items: apiItems - .filter((item) => !!item.api.tags?.includes(tag)) - .map(createDocItem), + items: [...taggedSchemaItems, ...taggedApiItems].map(createDocItem), }; }) .filter((item) => item.items.length > 0); // Filter out any categories with no items. @@ -217,7 +222,7 @@ function groupByTags( } let schemas: SidebarItemCategory[] = []; - if (schemaItems.length > 0) { + if (showSchemas && schemaItems.length > 0) { schemas = [ { type: "category" as const, From 77a1fbb075131c38ae1e1fddf5c08291089ba7da Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 13:06:34 -0500 Subject: [PATCH 03/10] add schemas with x-tags even if showSchemas is not true --- .../src/openapi/openapi.ts | 70 +++++++++++-------- 1 file changed, 40 insertions(+), 30 deletions(-) diff --git a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts index 0f6a49bfc..b6521362e 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts @@ -410,43 +410,53 @@ function createItems( } } - if (options?.showSchemas === true) { + if ( + options?.showSchemas === true || + Object.entries(openapiData?.components?.schemas ?? {}) + .flatMap(([_, s]) => s["x-tags"]) + .filter((item) => !!item).length > 0 + ) { // Gather schemas for (let [schema, schemaObject] of Object.entries( openapiData?.components?.schemas ?? {} )) { - const baseIdSpaces = - schemaObject?.title?.replace(" ", "-").toLowerCase() ?? ""; - const baseId = kebabCase(baseIdSpaces); - - const schemaDescription = schemaObject.description; - let splitDescription: any; - if (schemaDescription) { - splitDescription = schemaDescription.match(/[^\r\n]+/g); - } + if (options?.showSchemas === true || schemaObject["x-tags"]) { + const baseIdSpaces = + schemaObject?.title?.replace(" ", "-").toLowerCase() ?? ""; + const baseId = kebabCase(baseIdSpaces); + + const schemaDescription = schemaObject.description; + let splitDescription: any; + if (schemaDescription) { + splitDescription = schemaDescription.match(/[^\r\n]+/g); + } - const schemaPage: PartialPage = { - type: "schema", - id: baseId, - infoId: infoId ?? "", - unversionedId: baseId, - title: schemaObject.title - ? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'") - : schema, - description: schemaObject.description - ? schemaObject.description.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'") - : "", - frontMatter: { - description: splitDescription - ? splitDescription[0] - .replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'") - .replace(/\s+$/, "") + const schemaPage: PartialPage = { + type: "schema", + id: baseId, + infoId: infoId ?? "", + unversionedId: baseId, + title: schemaObject.title + ? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'") + : schema, + description: schemaObject.description + ? schemaObject.description.replace( + /((?:^|[^\\])(?:\\{2})*)"/g, + "$1'" + ) : "", - }, - schema: schemaObject, - }; + frontMatter: { + description: splitDescription + ? splitDescription[0] + .replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'") + .replace(/\s+$/, "") + : "", + }, + schema: schemaObject, + }; - items.push(schemaPage); + items.push(schemaPage); + } } } From 747d35611f74666d355f7976aaa3db566f43bf6a Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 13:24:19 -0500 Subject: [PATCH 04/10] add a badge and some styling for schema sidebar labels --- demo/src/css/custom.css | 13 ++++++++++--- .../src/sidebars/index.ts | 9 ++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/demo/src/css/custom.css b/demo/src/css/custom.css index 6dc5ea86d..4ca833446 100644 --- a/demo/src/css/custom.css +++ b/demo/src/css/custom.css @@ -37,13 +37,15 @@ a:any-link:hover { } /* Sidebar Method labels */ -.api-method > .menu__link { +.api-method > .menu__link, +.schema > .menu__link { align-items: center; justify-content: start; } -.api-method > .menu__link::before { - width: 50px; +.api-method > .menu__link::before, +.schema > .menu__link::before { + width: 55px; height: 20px; font-size: 12px; line-height: 20px; @@ -93,6 +95,11 @@ a:any-link:hover { background-color: var(--ifm-color-secondary-darkest); } +.schema > .menu__link::before { + content: "schema"; + background-color: var(--ifm-color-secondary-darkest); +} + /* GitHub Header Link */ .header-github-link:hover { opacity: 0.6; diff --git a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts index 0930f544f..2949397ee 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts @@ -108,9 +108,12 @@ function groupByTags( }, item.api.method ) - : clsx({ - "menu__list-item--deprecated": item.schema.deprecated, - }); + : clsx( + { + "menu__list-item--deprecated": item.schema.deprecated, + }, + "schema" + ); return { type: "doc" as const, id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`, From 8ffd6710092256cb335d9bd82f8c72946f109fe3 Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 13:34:37 -0500 Subject: [PATCH 05/10] add some test coverage --- .../src/markdown/createSchema.test.ts | 1 + .../src/openapi/__fixtures__/examples/openapi.yaml | 7 +++++++ .../src/openapi/openapi.test.ts | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/packages/docusaurus-plugin-openapi-docs/src/markdown/createSchema.test.ts b/packages/docusaurus-plugin-openapi-docs/src/markdown/createSchema.test.ts index df70dcc04..5299210e9 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/markdown/createSchema.test.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/markdown/createSchema.test.ts @@ -13,6 +13,7 @@ import { SchemaObject } from "../openapi/types"; describe("createNodes", () => { it("should create readable MODs for oneOf primitive properties", () => { const schema: SchemaObject = { + "x-tags": ["clown"], type: "object", properties: { oneOfProperty: { diff --git a/packages/docusaurus-plugin-openapi-docs/src/openapi/__fixtures__/examples/openapi.yaml b/packages/docusaurus-plugin-openapi-docs/src/openapi/__fixtures__/examples/openapi.yaml index 461c9f0f8..6c9fa2f8d 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/openapi/__fixtures__/examples/openapi.yaml +++ b/packages/docusaurus-plugin-openapi-docs/src/openapi/__fixtures__/examples/openapi.yaml @@ -40,3 +40,10 @@ x-tagGroups: tags: - tag3 - tag4 + +components: + schemas: + HelloString: + x-tags: + - tag1 + type: string diff --git a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.test.ts b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.test.ts index fe7bf823d..678a003ff 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.test.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.test.ts @@ -31,6 +31,10 @@ describe("openapi", () => { expect(yaml?.data.tags).toBeDefined(); expect(yaml?.data["x-tagGroups"]).toBeDefined(); + + expect( + yaml?.data.components?.schemas?.HelloString["x-tags"] + ).toBeDefined(); }); }); }); From b0f53c2fd9f71a5b7adf6ee573df652b01c3eada Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 13:49:01 -0500 Subject: [PATCH 06/10] add some x-tags documentation to `sidebars.md` --- demo/docs/sidebars.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/demo/docs/sidebars.md b/demo/docs/sidebars.md index dcfb9d01b..468216cd0 100644 --- a/demo/docs/sidebars.md +++ b/demo/docs/sidebars.md @@ -66,3 +66,9 @@ The OpenAPI Docs plugin can leverage this feature in a number of ways, including - Using the `generated-index` feature to create an index of all paths/endpoints available under a tag. - Setting the `tag` description of an OpenAPI specification as the content that displays when a category is clicked. - Setting the `info` section of an OpenAPI specification as the page that displays when a category is clicked (reserved primarily for micro-specs). + +### Grouping Schemas by `x-tags` + +The OpenAPI plugin provides out-of-the-box support for grouping schema objects into tags alongside path objects grouped by that same tag. + +What this means is that when the `groupPathsBy` sidebar option is set to `tag`, any `x-tag`ged schema objects will be gathered together with the tagged paths in that sidebar category. In the event that `showSchemas` is not configured, and `x-tags` is found on a schema object, the schema **will be included** in the relevant tag's category sidebar. From 1d0c5af1f9a943e9ac30029d2b46bd0aa4358ec4 Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 13:58:50 -0500 Subject: [PATCH 07/10] update documentation on styling sidebar items --- demo/docs/customization/styling.md | 40 +++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/demo/docs/customization/styling.md b/demo/docs/customization/styling.md index 7a3c34c60..6a43a5e22 100644 --- a/demo/docs/customization/styling.md +++ b/demo/docs/customization/styling.md @@ -18,13 +18,15 @@ The demo site uses the following CSS to add coloured labels to each request incl ```css /* API Menu Items */ -.api-method > .menu__link { +.api-method > .menu__link, +.schema > .menu__link { align-items: center; justify-content: start; } -.api-method > .menu__link::before { - width: 50px; +.api-method > .menu__link::before, +.schema > .menu__link::before { + width: 55px; height: 20px; font-size: 12px; line-height: 20px; @@ -68,6 +70,16 @@ The demo site uses the following CSS to add coloured labels to each request incl content: "head"; background-color: var(--ifm-color-secondary-darkest); } + +.event > .menu__link::before { + content: "event"; + background-color: var(--ifm-color-secondary-darkest); +} + +.schema > .menu__link::before { + content: "schema"; + background-color: var(--ifm-color-secondary-darkest); +} ``` ## Alternative Styling @@ -76,13 +88,15 @@ In [this issue](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/issu ```css /* Sidebar Method labels */ -.api-method > .menu__link { +.api-method > .menu__link, +.schema > .menu__link { align-items: center; justify-content: start; } -.api-method > .menu__link::before { - width: 50px; +.api-method > .menu__link::before, +.schema > .menu__link::before { + width: 55px; height: 20px; font-size: 12px; line-height: 20px; @@ -137,4 +151,18 @@ In [this issue](https://github.com/PaloAltoNetworks/docusaurus-openapi-docs/issu color: var(--ifm-color-secondary-contrast-foreground); border-color: var(--ifm-color-secondary-dark); } + +.event > .menu__link::before { + content: "event"; + background-color: var(--ifm-color-secondary-contrast-background); + color: var(--ifm-color-secondary-contrast-foreground); + border-color: var(--ifm-color-secondary-dark); +} + +.schema > .menu__link::before { + content: "schema"; + background-color: var(--ifm-color-secondary-contrast-background); + color: var(--ifm-color-secondary-contrast-foreground); + border-color: var(--ifm-color-secondary-dark); +} ``` From 14347fc4a3447b5736f1f67e4ea3625ffc7c6ebe Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 14:15:31 -0500 Subject: [PATCH 08/10] include schema-only tags, just like operation-only ones --- .../src/sidebars/index.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts index 2949397ee..6e7839af6 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts @@ -78,17 +78,22 @@ function groupByTags( .flatMap((item) => item.api.tags) .filter((item): item is string => !!item) ); + const schemaTags = uniq( + schemaItems + .flatMap((item) => item.schema["x-tags"]) + .filter((item): item is string => !!item) + ); - // Combine globally defined tags with operation tags - // Only include global tag if referenced in operation tags + // Combine globally defined tags with operation and schema tags + // Only include global tag if referenced in operation/schema tags let apiTags: string[] = []; tags.flat().forEach((tag) => { // Should we also check x-displayName? - if (operationTags.includes(tag.name!)) { + if (operationTags.includes(tag.name!) || schemaTags.includes(tag.name!)) { apiTags.push(tag.name!); } }); - apiTags = uniq(apiTags.concat(operationTags)); + apiTags = uniq(apiTags.concat(operationTags, schemaTags)); const basePath = docPath ? outputDir.split(docPath!)[1].replace(/^\/+/g, "") From adf4109532b82b235a33845c19b267d1acba3e5f Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 14:18:59 -0500 Subject: [PATCH 09/10] add the pet x-tag to the Cat schema for demo purposes --- demo/examples/petstore.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/demo/examples/petstore.yaml b/demo/examples/petstore.yaml index c615a9232..c31ac04ae 100644 --- a/demo/examples/petstore.yaml +++ b/demo/examples/petstore.yaml @@ -37,7 +37,7 @@ info: Petstore offers two forms of authentication: - API Key - OAuth2 - + OAuth2 - an open protocol to allow secure authorization in a simple and standard method from web, mobile and desktop applications. @@ -934,6 +934,8 @@ components: message: type: string Cat: + x-tags: + - pet description: A representation of a cat allOf: - $ref: "#/components/schemas/Pet" From b66371bd3948c84524fd4b1cc29e0b0e682e82bf Mon Sep 17 00:00:00 2001 From: Elliot Voris Date: Wed, 12 Jun 2024 14:23:00 -0500 Subject: [PATCH 10/10] filter out x-tagged schemas from the "Schemas" category they'll already be displayed elsewhere --- packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts index 6e7839af6..7cfde2e12 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/sidebars/index.ts @@ -237,7 +237,9 @@ function groupByTags( label: "Schemas", collapsible: sidebarCollapsible!, collapsed: sidebarCollapsed!, - items: schemaItems.map(createDocItem), + items: schemaItems + .filter(({ schema }) => !schema["x-tags"]) + .map(createDocItem), }, ]; }