diff --git a/.gitignore b/.gitignore
index fd1c0d0b6..8043415e1 100644
--- a/.gitignore
+++ b/.gitignore
@@ -138,6 +138,7 @@ demo/**/*.api.mdx
demo/**/*.info.mdx
demo/**/*.tag.mdx
demo/**/*.schema.mdx
+demo/**/index.mdx
demo/**/sidebar.ts
demo/**/versions.json
diff --git a/README.md b/README.md
index 439097e43..227868722 100644
--- a/README.md
+++ b/README.md
@@ -179,6 +179,7 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
| Name | Type | Default | Description |
| -------------------- | --------- | ------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `groupPathsBy` | `string` | `null` | Organize and group sidebar slice by specified option. Note: Currently, `groupPathsBy` only contains support for grouping by `tag` and `tagGroup`. |
+| `nested` | `boolean` | `false` | Whether to create a nested filesystem structure. Needs to be `true` for Docusaurus-instances [which create a sidebar automatically from the filesystem structure](https://docusaurus.io/docs/next/sidebar/autogenerated). |
| `categoryLinkSource` | `string` | `null` | Defines what source to use for rendering category link pages when grouping paths by tag.
The supported options are as follows:
`tag`: Sets the category link config type to `generated-index` and uses the tag description as the link config description.
`info`: Sets the category link config type to `doc` and renders the `info` section as the category link (recommended only for multi/micro-spec scenarios).
`none`: Does not create pages for categories, only groups that can be expanded/collapsed. |
| `sidebarCollapsible` | `boolean` | `true` | Whether sidebar categories are collapsible by default. |
| `sidebarCollapsed` | `boolean` | `true` | Whether sidebar categories are collapsed by default. |
diff --git a/packages/docusaurus-plugin-openapi-docs/src/index.ts b/packages/docusaurus-plugin-openapi-docs/src/index.ts
index 61a84e0ac..17e34cb71 100644
--- a/packages/docusaurus-plugin-openapi-docs/src/index.ts
+++ b/packages/docusaurus-plugin-openapi-docs/src/index.ts
@@ -156,8 +156,34 @@ export default function pluginOpenAPIDocs(
}
}
+ if (sidebarOptions?.nested) {
+ let dirNames =
+ sidebarOptions.groupPathsBy === "tag"
+ ? tags[0].map((tag) => {
+ return tag.name;
+ })
+ : tagGroups.map((tagGroup) => {
+ return tagGroup.name;
+ });
+
+ dirNames.forEach((directory) => {
+ if (!fs.existsSync(`${outputDir}/${directory}`)) {
+ try {
+ fs.mkdirSync(`${outputDir}/${directory}`, { recursive: true });
+ console.log(
+ chalk.green(`Successfully created "${outputDir}/${directory}"`)
+ );
+ } catch (err) {
+ console.error(
+ chalk.red(`Failed to create "${outputDir}/${directory}"`),
+ chalk.yellow(err)
+ );
+ }
+ }
+ });
+ }
// TODO: figure out better way to set default
- if (Object.keys(sidebarOptions ?? {}).length > 0) {
+ else if (Object.keys(sidebarOptions ?? {}).length > 0) {
const sidebarSlice = generateSidebarSlice(
sidebarOptions!,
options,
@@ -350,7 +376,20 @@ custom_edit_url: null
const tagUtils = render(tagMdTemplate, item);
if (item.type === "api") {
- if (!fs.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
+ let path = `${outputDir}/${item.id}.tag.mdx`;
+ if (sidebarOptions?.nested) {
+ path = `${outputDir}/${item.api.tags![0]}/${item.id}.api.mdx`;
+
+ if (sidebarOptions.groupPathsBy === "tagGroup") {
+ //get the tagGroup of the tag
+ tagGroups.forEach((tagGroup) => {
+ if (tagGroup.tags.includes(item.api.tags![0])) {
+ path = `${outputDir}/${tagGroup.name}/${item.id}.api.mdx`;
+ }
+ });
+ }
+ }
+ if (!fs.existsSync(path)) {
try {
// kebabCase(arg) returns 0-length string when arg is undefined
if (item.id.length === 0) {
@@ -358,15 +397,11 @@ custom_edit_url: null
"Operation must have summary or operationId defined"
);
}
- fs.writeFileSync(`${outputDir}/${item.id}.api.mdx`, view, "utf8");
- console.log(
- chalk.green(
- `Successfully created "${outputDir}/${item.id}.api.mdx"`
- )
- );
+ fs.writeFileSync(path, view, "utf8");
+ console.log(chalk.green(`Successfully created "${path}"`));
} catch (err) {
console.error(
- chalk.red(`Failed to write "${outputDir}/${item.id}.api.mdx"`),
+ chalk.red(`Failed to write "${path}"`),
chalk.yellow(err)
);
}
@@ -401,23 +436,27 @@ custom_edit_url: null
}
}
}
-
if (item.type === "tag") {
- if (!fs.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
+ let path = `${outputDir}/${item.id}.tag.mdx`;
+ if (sidebarOptions?.nested) {
+ path = `${outputDir}/${item.tag.name!}/index.mdx`;
+
+ if (sidebarOptions.groupPathsBy === "tagGroup") {
+ //get the tagGroup of the tag
+ tagGroups.forEach((tagGroup) => {
+ if (tagGroup.tags.includes(item.tag.name!)) {
+ path = `${outputDir}/${tagGroup.name}/index.mdx`;
+ }
+ });
+ }
+ }
+ if (!fs.existsSync(path)) {
try {
- fs.writeFileSync(
- `${outputDir}/${item.id}.tag.mdx`,
- tagUtils,
- "utf8"
- );
- console.log(
- chalk.green(
- `Successfully created "${outputDir}/${item.id}.tag.mdx"`
- )
- );
+ fs.writeFileSync(path, tagUtils, "utf8");
+ console.log(chalk.green(`Successfully created "${path}"`));
} catch (err) {
console.error(
- chalk.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`),
+ chalk.red(`Failed to write "${path}"`),
chalk.yellow(err)
);
}
@@ -479,15 +518,17 @@ custom_edit_url: null
async function cleanApiDocs(options: APIOptions) {
const { outputDir } = options;
const apiDir = posixPath(path.join(siteDir, outputDir));
- const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
- cwd: path.resolve(apiDir),
- deep: 1,
- });
+ const apiMdxFiles = await Globby(
+ ["**/*.api.mdx", "**/*.index.mdx", "**/*.info.mdx", "**/*.tag.mdx"],
+ {
+ cwd: path.resolve(apiDir),
+ }
+ );
const sidebarFile = await Globby(["sidebar.js", "sidebar.ts"], {
cwd: path.resolve(apiDir),
deep: 1,
});
- apiMdxFiles.map((mdx) =>
+ apiMdxFiles.forEach((mdx) =>
fs.unlink(`${apiDir}/${mdx}`, (err) => {
if (err) {
console.error(
@@ -512,7 +553,7 @@ custom_edit_url: null
}
}
- sidebarFile.map((sidebar) =>
+ sidebarFile.forEach((sidebar) =>
fs.unlink(`${apiDir}/${sidebar}`, (err) => {
if (err) {
console.error(
diff --git a/packages/docusaurus-plugin-openapi-docs/src/options.ts b/packages/docusaurus-plugin-openapi-docs/src/options.ts
index ff114de7f..07a3af16f 100644
--- a/packages/docusaurus-plugin-openapi-docs/src/options.ts
+++ b/packages/docusaurus-plugin-openapi-docs/src/options.ts
@@ -18,6 +18,7 @@ const sidebarOptions = Joi.object({
sidebarCollapsible: Joi.boolean(),
sidebarCollapsed: Joi.boolean(),
sidebarGenerators: sidebarGenerators,
+ nested: Joi.boolean(),
});
const markdownGenerators = Joi.object({
diff --git a/packages/docusaurus-plugin-openapi-docs/src/types.ts b/packages/docusaurus-plugin-openapi-docs/src/types.ts
index 43367bbaa..c4dfd9605 100644
--- a/packages/docusaurus-plugin-openapi-docs/src/types.ts
+++ b/packages/docusaurus-plugin-openapi-docs/src/types.ts
@@ -74,6 +74,7 @@ export interface SidebarOptions {
sidebarCollapsible?: boolean;
sidebarCollapsed?: boolean;
sidebarGenerators?: SidebarGenerators;
+ nested?: boolean;
}
export interface APIVersionOptions {