From 2fd910ba0a8fea3e5c648658d091d0d7895f7345 Mon Sep 17 00:00:00 2001 From: Rohit Gohri Date: Fri, 8 Mar 2024 18:20:18 +0100 Subject: [PATCH 1/4] separate normal options and preset options --- packages/docusaurus-plugin-redoc/src/index.ts | 9 ++--- .../docusaurus-plugin-redoc/src/options.ts | 34 ++++++++++++------- 2 files changed, 25 insertions(+), 18 deletions(-) diff --git a/packages/docusaurus-plugin-redoc/src/index.ts b/packages/docusaurus-plugin-redoc/src/index.ts index ecec9dca..b7d6991e 100644 --- a/packages/docusaurus-plugin-redoc/src/index.ts +++ b/packages/docusaurus-plugin-redoc/src/index.ts @@ -21,6 +21,7 @@ import { PluginOptionSchema, PluginOptions, PluginOptionsWithDefault, + PluginDirectUsageOptions, DEFAULT_OPTIONS, } from './options'; import type { SpecProps, ApiDocProps } from './types/common'; @@ -30,7 +31,7 @@ import { loadRedoclyConfig } from './loadRedoclyConfig'; // eslint-disable-next-line @typescript-eslint/no-var-requires const version = require('../package.json').version; -export { PluginOptions, loadRedoclyConfig }; +export { PluginOptions, PluginDirectUsageOptions, loadRedoclyConfig }; export default function redocPlugin( context: LoadContext, @@ -41,7 +42,7 @@ export default function redocPlugin( }> { const { baseUrl } = context.siteConfig; const options: PluginOptionsWithDefault = { ...DEFAULT_OPTIONS, ...opts }; - const { debug, spec, url: downloadUrl, config } = options; + const { debug, spec, url: downloadUrl, config, themeId } = options; let url = downloadUrl; const isSpecFile = fs.existsSync(spec); @@ -56,7 +57,6 @@ export default function redocPlugin( console.error('[REDOCUSAURUS_PLUGIN] Options:', options); } - const { themeId } = options; return { name: 'docusaurus-plugin-redoc', async loadContent() { @@ -185,9 +185,6 @@ export default function redocPlugin( fs.writeFileSync(staticFile, bundledYaml); }, getPathsToWatch() { - if (!isSpecFile) { - return []; - } return filesToWatch; }, }; diff --git a/packages/docusaurus-plugin-redoc/src/options.ts b/packages/docusaurus-plugin-redoc/src/options.ts index d8985ab8..1977b49c 100644 --- a/packages/docusaurus-plugin-redoc/src/options.ts +++ b/packages/docusaurus-plugin-redoc/src/options.ts @@ -15,12 +15,11 @@ type LayoutProps = { }; }; -export interface PluginOptions { - id?: string; - spec: string; - url?: string; - route?: string; - layout?: LayoutProps; +/** + * Can pass only if directly using plugin. + * `redocusaurus` auto populates them + */ +export interface PluginDirectUsageOptions { debug?: boolean; themeId?: string; /** @@ -28,24 +27,35 @@ export interface PluginOptions { * @see https://redocly.com/docs/cli/configuration/configuration-file/ */ config?: string | RawConfig; + layout?: LayoutProps; +} + +export interface PluginOptions extends PluginDirectUsageOptions { + id?: string; + spec: string; + url?: string; + route?: string; } export interface PluginOptionsWithDefault extends PluginOptions { debug: boolean; } -export const DEFAULT_OPTIONS: Omit = { +export const DEFAULT_OPTIONS = { layout: {}, debug: false, -}; +} satisfies Omit; export const PluginOptionSchema = Joi.object({ + // Direct Usage without redocusaurus preset id: Joi.string(), - spec: Joi.string(), - url: Joi.string().uri({ allowRelative: true }).optional(), - layout: Joi.any().default(DEFAULT_OPTIONS.layout), debug: Joi.boolean().default(DEFAULT_OPTIONS.debug), - route: Joi.string().uri({ relativeOnly: true }).optional(), config: Joi.any().optional(), themeId: Joi.string().optional(), + + // Basic + spec: Joi.string(), + url: Joi.string().uri({ allowRelative: true }).optional(), + route: Joi.string().uri({ relativeOnly: true }).optional(), + layout: Joi.any().default(DEFAULT_OPTIONS.layout), }); From fb4a3a8cf7580c74a00a370beb74fe59b59e415e Mon Sep 17 00:00:00 2001 From: Rohit Gohri Date: Fri, 8 Mar 2024 20:02:32 +0100 Subject: [PATCH 2/4] add support for auto-loading folder --- packages/redocusaurus/src/index.ts | 79 +++++++++++++++++++++--------- packages/redocusaurus/src/types.ts | 44 +++++++++++++++++ 2 files changed, 99 insertions(+), 24 deletions(-) create mode 100644 packages/redocusaurus/src/types.ts diff --git a/packages/redocusaurus/src/index.ts b/packages/redocusaurus/src/index.ts index 3ce0d250..928fac23 100644 --- a/packages/redocusaurus/src/index.ts +++ b/packages/redocusaurus/src/index.ts @@ -1,45 +1,76 @@ +import path from 'path'; import type { LoadContext } from '@docusaurus/types'; +import { Globby, createSlugger } from '@docusaurus/utils'; import type { PluginOptions } from 'docusaurus-plugin-redoc'; import type { ThemeOptions } from 'docusaurus-theme-redoc'; +import type { PresetEntry, PresetOptions, SpecOptions } from './types'; -export interface PresetOptions { - id?: string; - debug?: boolean; - /** - * Path to the Redocly config file `redocly.yaml` - */ - config?: string; - specs: PluginOptions[]; - theme?: ThemeOptions; -} - -export type PresetEntry = ['redocusaurus', PresetOptions]; +export type { PresetEntry, PresetOptions }; -export default function preset( +export default async function preset( context: LoadContext, opts: PresetOptions = { - specs: [], theme: {}, }, ) { - let specsArray: PluginOptions[] = []; - const { debug = false, specs, theme = {}, config } = opts; + const { debug = false, openapi, specs, theme = {}, config } = opts; if (debug) { console.error('[REDOCUSAURUS] Options:', opts); } - if (Array.isArray(specs)) { - specsArray = specs; - } else if (specs) { - specsArray = [specs]; + const id = opts.id ? `-${opts.id}` : ''; + const themeId = `theme-redoc${id}`; + if (debug) { + console.error('[REDOCUSAURUS] ID Suffix:', id); } - if (debug) { - console.error('[REDOCUSAURUS] Specs:', specsArray); + const specsArray: SpecOptions[] = []; + + if (specs) { + if (debug) { + console.error('[REDOCUSAURUS] Specs Files:', specs); + } + specsArray.push(...(Array.isArray(specs) ? specs : [specs])); } - const id = opts.id ? `-${opts.id}` : ''; - const themeId = `theme-redoc${id}`; + if (!specs || openapi) { + // Load folder if no specs provided or folder specifically provided + const folder = openapi?.folder || 'openapi'; + const resolvedFolder = path.resolve(folder); + if (debug) { + console.error('[REDOCUSAURUS] Loading Folder:', { + folder, + resolvedFolder, + }); + } + const specFiles = await Globby([ + `${folder}/**/*.openapi.{yaml,json}`, + `${folder}/**/openapi.{yaml,json}`, + ]); + if (debug) { + console.error('[REDOCUSAURUS] Found openapi files:', specFiles); + } + const slugger = createSlugger(); + specsArray.push( + ...specFiles.map((specFile): SpecOptions => { + const spec = path.resolve(specFile); + const fileRoute = path + .relative(resolvedFolder, spec) + .replace(/(\/index)?\.openapi\.(yaml|json)$/, '') + .replace(/\/*$/, ''); + const docRoute = `${openapi?.routeBasePath ?? ''}/${fileRoute}`; + return { + id: slugger.slug(fileRoute), + spec: spec, + route: docRoute, + }; + }), + ); + } + + if (debug) { + console.error('[REDOCUSAURUS] All specs:', specsArray); + } const resolvedPreset: { themes: readonly (readonly [string, ThemeOptions])[]; plugins: readonly (readonly [string, PluginOptions])[]; diff --git a/packages/redocusaurus/src/types.ts b/packages/redocusaurus/src/types.ts new file mode 100644 index 00000000..9dbe9c99 --- /dev/null +++ b/packages/redocusaurus/src/types.ts @@ -0,0 +1,44 @@ +import type { + PluginOptions, + PluginDirectUsageOptions, +} from 'docusaurus-plugin-redoc'; +import type { ThemeOptions } from 'docusaurus-theme-redoc'; + +interface FolderOptions { + /** + * Default is `openapi`. This is similar to how + * Will load all YAML or JSON files in the folder + * that are named `openapi` or end with `.openapi`, like: + * - `index.openapi.yaml` + * - `swagger.openapi.yaml` + * - `swagger.openapi.json` + */ + folder?: string; + /** + * The path at which the files will be rendered, + * if the file is called `index.openapi.yaml` it will be rendered at base path itself + * Otherwise the name of the file path from the base folder will be used as the url path + */ + routeBasePath?: string; +} + +export type SpecOptions = Omit; + +export type PresetOptions = { + id?: string; + debug?: boolean; + /** + * Path to the Redocly config file `redocly.yaml` + * @see https://redocly.com/docs/cli/configuration/configuration-file/ + */ + config?: string; + specs?: SpecOptions[]; + /** + * The folder is not going to be hot-reloaded + * but any changes to specs loaded at start will trigger live-reload + */ + openapi?: FolderOptions; + theme?: Omit; +}; + +export type PresetEntry = ['redocusaurus', PresetOptions]; From 638d69d3320f4ce159d79fe47f9381b6c90ba7c2 Mon Sep 17 00:00:00 2001 From: Rohit Gohri Date: Fri, 8 Mar 2024 20:02:55 +0100 Subject: [PATCH 3/4] update website config to use folder --- website/docusaurus.config.ts | 29 +++---------------- .../components/pets.yaml | 0 .../index.openapi.yaml} | 0 ...pi.yaml => using-single-yaml.openapi.yaml} | 0 ...r.json => using-swagger-json.openapi.json} | 0 .../pages/examples/custom-layout/index.jsx | 2 +- .../src/pages/examples/custom-page/index.jsx | 2 +- 7 files changed, 6 insertions(+), 27 deletions(-) rename website/openapi/{multi-file => using-multi-file-yaml}/components/pets.yaml (100%) rename website/openapi/{multi-file/openapi.yaml => using-multi-file-yaml/index.openapi.yaml} (100%) rename website/openapi/{single-file/openapi.yaml => using-single-yaml.openapi.yaml} (100%) rename website/openapi/{swagger/swagger.json => using-swagger-json.openapi.json} (100%) diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index dc8d7d24..b31830c8 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -38,38 +38,17 @@ const config: Config = { { debug: Boolean(process.env.DEBUG || process.env.CI), config: path.join(__dirname, 'redocly.yaml'), + openapi: { + folder: 'openapi', + routeBasePath: '/examples', + }, specs: [ - { - id: 'using-single-yaml', - spec: 'openapi/single-file/openapi.yaml', - route: '/examples/using-single-yaml/', - }, - { - id: 'using-multi-file-yaml', - spec: 'openapi/multi-file/openapi.yaml', - route: '/examples/using-multi-file-yaml/', - }, - { - id: 'using-swagger-json', - spec: 'openapi/swagger/swagger.json', - route: '/examples/using-swagger-json/', - }, { id: 'using-remote-url', // Remote File spec: 'https://redocly.github.io/redoc/openapi.yaml', route: '/examples/using-remote-url/', }, - { - id: 'using-custom-page', - spec: 'openapi/single-file/openapi.yaml', - // NOTE: no `route` passed, instead data used in custom React Component ('custom-page/index.jsx') - }, - { - id: 'using-custom-layout', - spec: 'openapi/single-file/openapi.yaml', - // NOTE: no `route` passed, instead data used in custom React Component ('custom-layout/index.jsx') - }, ], theme: { /** diff --git a/website/openapi/multi-file/components/pets.yaml b/website/openapi/using-multi-file-yaml/components/pets.yaml similarity index 100% rename from website/openapi/multi-file/components/pets.yaml rename to website/openapi/using-multi-file-yaml/components/pets.yaml diff --git a/website/openapi/multi-file/openapi.yaml b/website/openapi/using-multi-file-yaml/index.openapi.yaml similarity index 100% rename from website/openapi/multi-file/openapi.yaml rename to website/openapi/using-multi-file-yaml/index.openapi.yaml diff --git a/website/openapi/single-file/openapi.yaml b/website/openapi/using-single-yaml.openapi.yaml similarity index 100% rename from website/openapi/single-file/openapi.yaml rename to website/openapi/using-single-yaml.openapi.yaml diff --git a/website/openapi/swagger/swagger.json b/website/openapi/using-swagger-json.openapi.json similarity index 100% rename from website/openapi/swagger/swagger.json rename to website/openapi/using-swagger-json.openapi.json diff --git a/website/src/pages/examples/custom-layout/index.jsx b/website/src/pages/examples/custom-layout/index.jsx index 8e019132..281f3dd8 100644 --- a/website/src/pages/examples/custom-layout/index.jsx +++ b/website/src/pages/examples/custom-layout/index.jsx @@ -4,7 +4,7 @@ import Redoc from '@theme/Redoc'; import useSpecData from '@theme/useSpecData'; function CustomPage() { - const specData = useSpecData('using-custom-layout'); + const specData = useSpecData('using-single-yaml'); return ( Date: Fri, 8 Mar 2024 20:03:24 +0100 Subject: [PATCH 4/4] docs(changeset): Add support for auto-loading folder --- .changeset/small-pugs-laugh.md | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 .changeset/small-pugs-laugh.md diff --git a/.changeset/small-pugs-laugh.md b/.changeset/small-pugs-laugh.md new file mode 100644 index 00000000..2c7e5e0f --- /dev/null +++ b/.changeset/small-pugs-laugh.md @@ -0,0 +1,6 @@ +--- +'docusaurus-plugin-redoc': minor +'redocusaurus': minor +--- + +Add support for auto-loading folder