Skip to content

Commit 99f6c94

Browse files
authored
Merge branch 'main' into feature/i18n
2 parents cd6144b + 646c5e1 commit 99f6c94

File tree

12 files changed

+136
-69
lines changed

12 files changed

+136
-69
lines changed

.changeset/small-pugs-laugh.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'docusaurus-plugin-redoc': minor
3+
'redocusaurus': minor
4+
---
5+
6+
Add support for auto-loading folder

packages/docusaurus-plugin-redoc/src/index.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
PluginOptionSchema,
2222
PluginOptions,
2323
PluginOptionsWithDefault,
24+
PluginDirectUsageOptions,
2425
DEFAULT_OPTIONS,
2526
} from './options';
2627
import type { SpecProps, ApiDocProps } from './types/common';
@@ -30,7 +31,7 @@ import { loadRedoclyConfig } from './loadRedoclyConfig';
3031
// eslint-disable-next-line @typescript-eslint/no-var-requires
3132
const version = require('../package.json').version;
3233

33-
export { PluginOptions, loadRedoclyConfig };
34+
export { PluginOptions, PluginDirectUsageOptions, loadRedoclyConfig };
3435

3536
export default function redocPlugin(
3637
context: LoadContext,
@@ -41,7 +42,7 @@ export default function redocPlugin(
4142
}> {
4243
const { baseUrl } = context.siteConfig;
4344
const options: PluginOptionsWithDefault = { ...DEFAULT_OPTIONS, ...opts };
44-
const { debug, spec, url: downloadUrl, config } = options;
45+
const { debug, spec, url: downloadUrl, config, themeId } = options;
4546

4647
let url = downloadUrl;
4748
const isSpecFile = fs.existsSync(spec);
@@ -56,7 +57,6 @@ export default function redocPlugin(
5657
console.error('[REDOCUSAURUS_PLUGIN] Options:', options);
5758
}
5859

59-
const { themeId } = options;
6060
return {
6161
name: 'docusaurus-plugin-redoc',
6262
async loadContent() {
@@ -185,9 +185,6 @@ export default function redocPlugin(
185185
fs.writeFileSync(staticFile, bundledYaml);
186186
},
187187
getPathsToWatch() {
188-
if (!isSpecFile) {
189-
return [];
190-
}
191188
return filesToWatch;
192189
},
193190
};

packages/docusaurus-plugin-redoc/src/options.ts

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,37 +15,47 @@ type LayoutProps = {
1515
};
1616
};
1717

18-
export interface PluginOptions {
19-
id?: string;
20-
spec: string;
21-
url?: string;
22-
route?: string;
23-
layout?: LayoutProps;
18+
/**
19+
* Can pass only if directly using plugin.
20+
* `redocusaurus` auto populates them
21+
*/
22+
export interface PluginDirectUsageOptions {
2423
debug?: boolean;
2524
themeId?: string;
2625
/**
2726
* Redocly config to bundle file
2827
* @see https://redocly.com/docs/cli/configuration/configuration-file/
2928
*/
3029
config?: string | RawConfig;
30+
layout?: LayoutProps;
31+
}
32+
33+
export interface PluginOptions extends PluginDirectUsageOptions {
34+
id?: string;
35+
spec: string;
36+
url?: string;
37+
route?: string;
3138
}
3239

3340
export interface PluginOptionsWithDefault extends PluginOptions {
3441
debug: boolean;
3542
}
3643

37-
export const DEFAULT_OPTIONS: Omit<PluginOptionsWithDefault, 'spec'> = {
44+
export const DEFAULT_OPTIONS = {
3845
layout: {},
3946
debug: false,
40-
};
47+
} satisfies Omit<PluginOptions, 'spec'>;
4148

4249
export const PluginOptionSchema = Joi.object<PluginOptions>({
50+
// Direct Usage without redocusaurus preset
4351
id: Joi.string(),
44-
spec: Joi.string(),
45-
url: Joi.string().uri({ allowRelative: true }).optional(),
46-
layout: Joi.any().default(DEFAULT_OPTIONS.layout),
4752
debug: Joi.boolean().default(DEFAULT_OPTIONS.debug),
48-
route: Joi.string().uri({ relativeOnly: true }).optional(),
4953
config: Joi.any().optional(),
5054
themeId: Joi.string().optional(),
55+
56+
// Basic
57+
spec: Joi.string(),
58+
url: Joi.string().uri({ allowRelative: true }).optional(),
59+
route: Joi.string().uri({ relativeOnly: true }).optional(),
60+
layout: Joi.any().default(DEFAULT_OPTIONS.layout),
5161
});

packages/redocusaurus/src/index.ts

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,76 @@
1+
import path from 'path';
12
import type { LoadContext } from '@docusaurus/types';
3+
import { Globby, createSlugger } from '@docusaurus/utils';
24
import type { PluginOptions } from 'docusaurus-plugin-redoc';
35
import type { ThemeOptions } from 'docusaurus-theme-redoc';
6+
import type { PresetEntry, PresetOptions, SpecOptions } from './types';
47

5-
export interface PresetOptions {
6-
id?: string;
7-
debug?: boolean;
8-
/**
9-
* Path to the Redocly config file `redocly.yaml`
10-
*/
11-
config?: string;
12-
specs: PluginOptions[];
13-
theme?: ThemeOptions;
14-
}
15-
16-
export type PresetEntry = ['redocusaurus', PresetOptions];
8+
export type { PresetEntry, PresetOptions };
179

18-
export default function preset(
10+
export default async function preset(
1911
context: LoadContext,
2012
opts: PresetOptions = {
21-
specs: [],
2213
theme: {},
2314
},
2415
) {
25-
let specsArray: PluginOptions[] = [];
26-
const { debug = false, specs, theme = {}, config } = opts;
16+
const { debug = false, openapi, specs, theme = {}, config } = opts;
2717
if (debug) {
2818
console.error('[REDOCUSAURUS] Options:', opts);
2919
}
3020

31-
if (Array.isArray(specs)) {
32-
specsArray = specs;
33-
} else if (specs) {
34-
specsArray = [specs];
21+
const id = opts.id ? `-${opts.id}` : '';
22+
const themeId = `theme-redoc${id}`;
23+
if (debug) {
24+
console.error('[REDOCUSAURUS] ID Suffix:', id);
3525
}
3626

37-
if (debug) {
38-
console.error('[REDOCUSAURUS] Specs:', specsArray);
27+
const specsArray: SpecOptions[] = [];
28+
29+
if (specs) {
30+
if (debug) {
31+
console.error('[REDOCUSAURUS] Specs Files:', specs);
32+
}
33+
specsArray.push(...(Array.isArray(specs) ? specs : [specs]));
3934
}
40-
const id = opts.id ? `-${opts.id}` : '';
41-
const themeId = `theme-redoc${id}`;
35+
if (!specs || openapi) {
36+
// Load folder if no specs provided or folder specifically provided
37+
const folder = openapi?.folder || 'openapi';
38+
const resolvedFolder = path.resolve(folder);
39+
if (debug) {
40+
console.error('[REDOCUSAURUS] Loading Folder:', {
41+
folder,
42+
resolvedFolder,
43+
});
44+
}
45+
const specFiles = await Globby([
46+
`${folder}/**/*.openapi.{yaml,json}`,
47+
`${folder}/**/openapi.{yaml,json}`,
48+
]);
49+
if (debug) {
50+
console.error('[REDOCUSAURUS] Found openapi files:', specFiles);
51+
}
52+
const slugger = createSlugger();
53+
specsArray.push(
54+
...specFiles.map((specFile): SpecOptions => {
55+
const spec = path.resolve(specFile);
56+
const fileRoute = path
57+
.relative(resolvedFolder, spec)
58+
.replace(/(\/index)?\.openapi\.(yaml|json)$/, '')
59+
.replace(/\/*$/, '');
4260

61+
const docRoute = `${openapi?.routeBasePath ?? ''}/${fileRoute}`;
62+
return {
63+
id: slugger.slug(fileRoute),
64+
spec: spec,
65+
route: docRoute,
66+
};
67+
}),
68+
);
69+
}
70+
71+
if (debug) {
72+
console.error('[REDOCUSAURUS] All specs:', specsArray);
73+
}
4374
const resolvedPreset: {
4475
themes: readonly (readonly [string, ThemeOptions])[];
4576
plugins: readonly (readonly [string, PluginOptions])[];

packages/redocusaurus/src/types.ts

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type {
2+
PluginOptions,
3+
PluginDirectUsageOptions,
4+
} from 'docusaurus-plugin-redoc';
5+
import type { ThemeOptions } from 'docusaurus-theme-redoc';
6+
7+
interface FolderOptions {
8+
/**
9+
* Default is `openapi`. This is similar to how
10+
* Will load all YAML or JSON files in the folder
11+
* that are named `openapi` or end with `.openapi`, like:
12+
* - `index.openapi.yaml`
13+
* - `swagger.openapi.yaml`
14+
* - `swagger.openapi.json`
15+
*/
16+
folder?: string;
17+
/**
18+
* The path at which the files will be rendered,
19+
* if the file is called `index.openapi.yaml` it will be rendered at base path itself
20+
* Otherwise the name of the file path from the base folder will be used as the url path
21+
*/
22+
routeBasePath?: string;
23+
}
24+
25+
export type SpecOptions = Omit<PluginOptions, keyof PluginDirectUsageOptions>;
26+
27+
export type PresetOptions = {
28+
id?: string;
29+
debug?: boolean;
30+
/**
31+
* Path to the Redocly config file `redocly.yaml`
32+
* @see https://redocly.com/docs/cli/configuration/configuration-file/
33+
*/
34+
config?: string;
35+
specs?: SpecOptions[];
36+
/**
37+
* The folder is not going to be hot-reloaded
38+
* but any changes to specs loaded at start will trigger live-reload
39+
*/
40+
openapi?: FolderOptions;
41+
theme?: Omit<ThemeOptions, 'id'>;
42+
};
43+
44+
export type PresetEntry = ['redocusaurus', PresetOptions];

website/docusaurus.config.ts

Lines changed: 4 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -45,38 +45,17 @@ const config: Config = {
4545
{
4646
debug: Boolean(process.env.DEBUG || process.env.CI),
4747
config: path.join(__dirname, 'redocly.yaml'),
48+
openapi: {
49+
folder: 'openapi',
50+
routeBasePath: '/examples',
51+
},
4852
specs: [
49-
{
50-
id: 'using-single-yaml',
51-
spec: 'openapi/single-file/openapi.yaml',
52-
route: '/examples/using-single-yaml/',
53-
},
54-
{
55-
id: 'using-multi-file-yaml',
56-
spec: 'openapi/multi-file/openapi.yaml',
57-
route: '/examples/using-multi-file-yaml/',
58-
},
59-
{
60-
id: 'using-swagger-json',
61-
spec: 'openapi/swagger/swagger.json',
62-
route: '/examples/using-swagger-json/',
63-
},
6453
{
6554
id: 'using-remote-url',
6655
// Remote File
6756
spec: 'https://redocly.github.io/redoc/openapi.yaml',
6857
route: '/examples/using-remote-url/',
6958
},
70-
{
71-
id: 'using-custom-page',
72-
spec: 'openapi/single-file/openapi.yaml',
73-
// NOTE: no `route` passed, instead data used in custom React Component ('custom-page/index.jsx')
74-
},
75-
{
76-
id: 'using-custom-layout',
77-
spec: 'openapi/single-file/openapi.yaml',
78-
// NOTE: no `route` passed, instead data used in custom React Component ('custom-layout/index.jsx')
79-
},
8059
],
8160
theme: {
8261
/**

0 commit comments

Comments
 (0)