diff --git a/README.md b/README.md index 642fcd31a..3fa2abec3 100644 --- a/README.md +++ b/README.md @@ -282,6 +282,16 @@ yarn docusaurus gen-api-docs all --all-versions > This will generate API docs for all versions of all the OpenAPI specification (OAS) files referenced in your `docusaurus-plugin-openapi-docs` config. +To generate only schema MDX files—without updating the sidebar or requiring `showSchemas` in your plugin config—use the `--schemas-only` flag: + +```bash +yarn docusaurus gen-api-docs petstore --schemas-only +``` + +> This command writes the schema pages to the configured output directory while leaving other generated docs untouched. + +The `--schemas-only` flag is also available for `gen-api-docs:version`. + ### Cleaning API Docs To clean/remove all API Docs, run the following command from the root directory of your project: diff --git a/demo/docs/intro.mdx b/demo/docs/intro.mdx index d4779c3f7..fff1630d9 100644 --- a/demo/docs/intro.mdx +++ b/demo/docs/intro.mdx @@ -338,6 +338,14 @@ Example: yarn docusaurus gen-api-docs petstore ``` +To generate only schema MDX files—without updating the sidebar or requiring `showSchemas` in your plugin config—use the `--schemas-only` flag: + +```bash title="generating only schema docs for 'petstore'" +yarn docusaurus gen-api-docs petstore --schemas-only +``` + +> This command writes the schema pages to the configured output directory while leaving other generated docs untouched. + ### Cleaning API Docs To clean/remove all API Docs, run the following command from the root directory of your project: diff --git a/packages/docusaurus-plugin-openapi-docs/README.md b/packages/docusaurus-plugin-openapi-docs/README.md index c09d4eb19..eee387539 100644 --- a/packages/docusaurus-plugin-openapi-docs/README.md +++ b/packages/docusaurus-plugin-openapi-docs/README.md @@ -303,6 +303,16 @@ yarn docusaurus gen-api-docs all --all-versions > This will generate API docs for all versions of all the OpenAPI specification (OAS) files referenced in your `docusaurus-plugin-openapi-docs` config. +To generate only schema MDX files—without updating the sidebar or requiring `showSchemas` in your plugin config—use the `--schemas-only` flag: + +```bash +yarn docusaurus gen-api-docs petstore --schemas-only +``` + +> This command writes the schema pages to the configured output directory while leaving other generated docs untouched. + +The `--schemas-only` flag is also available for `gen-api-docs:version`. + ### Cleaning API Docs To clean/remove all API Docs, run the following command from the root directory of your project: diff --git a/packages/docusaurus-plugin-openapi-docs/src/index.ts b/packages/docusaurus-plugin-openapi-docs/src/index.ts index 570fcf2b5..d1148c69e 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/index.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/index.ts @@ -123,9 +123,12 @@ export default function pluginOpenAPIDocs( markdownGenerators, downloadUrl, sidebarOptions, + schemasOnly, disableCompression, } = options; + const isSchemasOnly = schemasOnly === true; + // Remove trailing slash before proceeding outputDir = outputDir.replace(/\/$/, ""); @@ -160,7 +163,7 @@ export default function pluginOpenAPIDocs( } // TODO: figure out better way to set default - if (Object.keys(sidebarOptions ?? {}).length > 0) { + if (!isSchemasOnly && Object.keys(sidebarOptions ?? {}).length > 0) { const sidebarSlice = generateSidebarSlice( sidebarOptions!, options, @@ -332,6 +335,9 @@ custom_edit_url: null } const markdown = pageGeneratorByType[item.type](item as any); item.markdown = markdown; + if (isSchemasOnly && item.type !== "schema") { + return; + } if (item.type === "api") { // opportunity to compress JSON // const serialize = (o: any) => { @@ -668,10 +674,12 @@ custom_edit_url: null .arguments("") .option("-p, --plugin-id ", "OpenAPI docs plugin ID.") .option("--all-versions", "Generate all versions.") + .option("--schemas-only", "Generate only schema docs.") .action(async (id, instance) => { const options = instance.opts(); const pluginId = options.pluginId; const allVersions = options.allVersions; + const schemasOnly = options.schemasOnly; const pluginInstances = getPluginInstances(plugins); let targetConfig: any; let targetDocsPluginId: any; @@ -698,6 +706,9 @@ custom_edit_url: null targetConfig = config; } + const withSchemaOverride = (apiOptions: APIOptions): APIOptions => + schemasOnly ? { ...apiOptions, schemasOnly: true } : apiOptions; + if (id === "all") { if (targetConfig[id]) { console.error( @@ -707,12 +718,10 @@ custom_edit_url: null ); } else { Object.keys(targetConfig).forEach(async function (key) { - await generateApiDocs(targetConfig[key], targetDocsPluginId); + const apiOptions = withSchemaOverride(targetConfig[key]); + await generateApiDocs(apiOptions, targetDocsPluginId); if (allVersions) { - await generateAllVersions( - targetConfig[key], - targetDocsPluginId - ); + await generateAllVersions(apiOptions, targetDocsPluginId); } }); } @@ -721,9 +730,10 @@ custom_edit_url: null chalk.red(`ID '${id}' does not exist in OpenAPI docs config.`) ); } else { - await generateApiDocs(targetConfig[id], targetDocsPluginId); + const apiOptions = withSchemaOverride(targetConfig[id]); + await generateApiDocs(apiOptions, targetDocsPluginId); if (allVersions) { - await generateAllVersions(targetConfig[id], targetDocsPluginId); + await generateAllVersions(apiOptions, targetDocsPluginId); } } }); @@ -736,9 +746,11 @@ custom_edit_url: null .usage("") .arguments("") .option("-p, --plugin-id ", "OpenAPI docs plugin ID.") + .option("--schemas-only", "Generate only schema docs.") .action(async (id, instance) => { const options = instance.opts(); const pluginId = options.pluginId; + const schemasOnly = options.schemasOnly; const pluginInstances = getPluginInstances(plugins); let targetConfig: any; let targetDocsPluginId: any; @@ -767,6 +779,9 @@ custom_edit_url: null const [parentId, versionId] = id.split(":"); const parentConfig = Object.assign({}, targetConfig[parentId]); + const withSchemaOverride = (apiOptions: APIOptions): APIOptions => + schemasOnly ? { ...apiOptions, schemasOnly: true } : apiOptions; + const version = parentConfig.version as string; const label = parentConfig.label as string; const baseUrl = parentConfig.baseUrl as string; @@ -796,10 +811,10 @@ custom_edit_url: null await generateVersions(mergedVersions, parentConfig.outputDir); Object.keys(versions).forEach(async (key) => { const versionConfig = versions[key]; - const mergedConfig = { + const mergedConfig = withSchemaOverride({ ...parentConfig, ...versionConfig, - }; + }); await generateApiDocs(mergedConfig, targetDocsPluginId); }); } @@ -811,10 +826,10 @@ custom_edit_url: null ); } else { const versionConfig = versions[versionId]; - const mergedConfig = { + const mergedConfig = withSchemaOverride({ ...parentConfig, ...versionConfig, - }; + }); await generateVersions(mergedVersions, parentConfig.outputDir); await generateApiDocs(mergedConfig, targetDocsPluginId); } 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 678a003ff..a25734a22 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.test.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.test.ts @@ -11,6 +11,8 @@ import path from "path"; import { posixPath } from "@docusaurus/utils"; import { readOpenapiFiles } from "."; +import { processOpenapiFile } from "./openapi"; +import type { APIOptions, SidebarOptions } from "../types"; // npx jest packages/docusaurus-plugin-openapi/src/openapi/openapi.test.ts --watch @@ -37,4 +39,60 @@ describe("openapi", () => { ).toBeDefined(); }); }); + + describe("schemasOnly", () => { + it("includes schema metadata when showSchemas is disabled", async () => { + const openapiData = { + openapi: "3.0.0", + info: { + title: "Schema Only", + version: "1.0.0", + }, + paths: { + "/ping": { + get: { + summary: "Ping", + responses: { + "200": { + description: "OK", + }, + }, + }, + }, + }, + components: { + schemas: { + WithoutTags: { + title: "Without Tags", + type: "object", + properties: { + value: { + type: "string", + }, + }, + }, + }, + }, + }; + + const options: APIOptions = { + specPath: "dummy", // required by the type but unused in this context + outputDir: "build", + showSchemas: false, + schemasOnly: true, + }; + + const sidebarOptions = {} as SidebarOptions; + + const [items] = await processOpenapiFile( + openapiData as any, + options, + sidebarOptions + ); + + const schemaItems = items.filter((item) => item.type === "schema"); + expect(schemaItems).toHaveLength(1); + expect(schemaItems[0].id).toBe("without-tags"); + }); + }); }); diff --git a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts index 486a13751..773c6e317 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/openapi/openapi.ts @@ -95,6 +95,7 @@ function createItems( let items: PartialPage[] = []; const infoIdSpaces = openapiData.info.title.replace(" ", "-").toLowerCase(); const infoId = kebabCase(infoIdSpaces); + const schemasOnly = options?.schemasOnly === true; if (openapiData.info.description || openapiData.info.title) { // Only create an info page if we have a description. @@ -434,6 +435,7 @@ function createItems( } if ( + schemasOnly || options?.showSchemas === true || Object.entries(openapiData?.components?.schemas ?? {}) .flatMap(([_, s]) => s["x-tags"]) @@ -443,7 +445,11 @@ function createItems( for (let [schema, schemaObject] of Object.entries( openapiData?.components?.schemas ?? {} )) { - if (options?.showSchemas === true || schemaObject["x-tags"]) { + if ( + schemasOnly || + options?.showSchemas === true || + schemaObject["x-tags"] + ) { const baseIdSpaces = schemaObject?.title?.replace(" ", "-").toLowerCase() ?? ""; const baseId = kebabCase(baseIdSpaces); diff --git a/packages/docusaurus-plugin-openapi-docs/src/types.ts b/packages/docusaurus-plugin-openapi-docs/src/types.ts index 0c65e4360..45a74cf9a 100644 --- a/packages/docusaurus-plugin-openapi-docs/src/types.ts +++ b/packages/docusaurus-plugin-openapi-docs/src/types.ts @@ -51,6 +51,7 @@ export interface APIOptions { proxy?: string; markdownGenerators?: MarkdownGenerator; showSchemas?: boolean; + schemasOnly?: boolean; disableCompression?: boolean; maskCredentials?: boolean; }