docusaurus-plugin-openapi-docs 1.0.3 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +104 -15
- package/lib/index.d.ts +6 -1
- package/lib/index.js +181 -17
- package/lib/markdown/createParamsDetails.js +2 -0
- package/lib/markdown/createSchemaDetails.js +2 -0
- package/lib/markdown/index.js +1 -1
- package/lib/openapi/openapi.d.ts +2 -2
- package/lib/openapi/openapi.js +6 -3
- package/lib/openapi/openapi.test.js +1 -1
- package/lib/openapi/utils/loadAndBundleSpec.d.ts +1 -1
- package/lib/openapi/utils/loadAndBundleSpec.js +36 -1
- package/lib/options.d.ts +0 -2
- package/lib/options.js +36 -7
- package/lib/sidebars/index.d.ts +1 -1
- package/lib/sidebars/index.js +11 -10
- package/lib/sidebars/utils.d.ts +2 -0
- package/lib/sidebars/utils.js +31 -0
- package/lib/types.d.ts +22 -9
- package/package.json +3 -2
- package/src/index.ts +227 -17
- package/src/markdown/createParamsDetails.ts +2 -0
- package/src/markdown/createSchemaDetails.ts +2 -0
- package/src/markdown/index.ts +1 -1
- package/src/openapi/openapi.test.ts +1 -1
- package/src/openapi/openapi.ts +12 -3
- package/src/openapi/utils/loadAndBundleSpec.ts +32 -1
- package/src/options.ts +41 -8
- package/src/sidebars/index.ts +15 -10
- package/src/sidebars/utils.ts +29 -0
- package/src/types.ts +22 -8
package/lib/options.js
CHANGED
|
@@ -6,13 +6,42 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
* ========================================================================== */
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.OptionsSchema =
|
|
9
|
+
exports.OptionsSchema = void 0;
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
11
|
+
const sidebarOptions = utils_validation_1.Joi.object({
|
|
12
|
+
groupPathsBy: utils_validation_1.Joi.string().valid("tag"),
|
|
13
|
+
categoryLinkSource: utils_validation_1.Joi.string().valid("tag", "info"),
|
|
14
|
+
customProps: utils_validation_1.Joi.object(),
|
|
15
|
+
sidebarCollapsible: utils_validation_1.Joi.boolean(),
|
|
16
|
+
sidebarCollapsed: utils_validation_1.Joi.boolean(),
|
|
17
|
+
});
|
|
15
18
|
exports.OptionsSchema = utils_validation_1.Joi.object({
|
|
16
|
-
id: utils_validation_1.Joi.string().
|
|
17
|
-
|
|
19
|
+
id: utils_validation_1.Joi.string().required(),
|
|
20
|
+
docsPluginId: utils_validation_1.Joi.string().required(),
|
|
21
|
+
config: utils_validation_1.Joi.object()
|
|
22
|
+
.pattern(/^/, utils_validation_1.Joi.object({
|
|
23
|
+
specPath: utils_validation_1.Joi.string().required(),
|
|
24
|
+
outputDir: utils_validation_1.Joi.string().required(),
|
|
25
|
+
template: utils_validation_1.Joi.string(),
|
|
26
|
+
sidebarOptions: sidebarOptions,
|
|
27
|
+
version: utils_validation_1.Joi.string().when("versions", {
|
|
28
|
+
is: utils_validation_1.Joi.exist(),
|
|
29
|
+
then: utils_validation_1.Joi.required(),
|
|
30
|
+
}),
|
|
31
|
+
label: utils_validation_1.Joi.string().when("versions", {
|
|
32
|
+
is: utils_validation_1.Joi.exist(),
|
|
33
|
+
then: utils_validation_1.Joi.required(),
|
|
34
|
+
}),
|
|
35
|
+
baseUrl: utils_validation_1.Joi.string().when("versions", {
|
|
36
|
+
is: utils_validation_1.Joi.exist(),
|
|
37
|
+
then: utils_validation_1.Joi.required(),
|
|
38
|
+
}),
|
|
39
|
+
versions: utils_validation_1.Joi.object().pattern(/^/, utils_validation_1.Joi.object({
|
|
40
|
+
specPath: utils_validation_1.Joi.string().required(),
|
|
41
|
+
outputDir: utils_validation_1.Joi.string().required(),
|
|
42
|
+
label: utils_validation_1.Joi.string().required(),
|
|
43
|
+
baseUrl: utils_validation_1.Joi.string().required(),
|
|
44
|
+
})),
|
|
45
|
+
}))
|
|
46
|
+
.required(),
|
|
18
47
|
});
|
package/lib/sidebars/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ProcessedSidebar } from "@docusaurus/plugin-content-docs/src/sidebars/types";
|
|
2
2
|
import { TagObject } from "../openapi/types";
|
|
3
3
|
import type { SidebarOptions, APIOptions, ApiMetadata } from "../types";
|
|
4
|
-
export default function generateSidebarSlice(sidebarOptions: SidebarOptions, options: APIOptions, api: ApiMetadata[], tags: TagObject[]): ProcessedSidebar;
|
|
4
|
+
export default function generateSidebarSlice(sidebarOptions: SidebarOptions, options: APIOptions, api: ApiMetadata[], tags: TagObject[], docPath: string): ProcessedSidebar;
|
package/lib/sidebars/index.js
CHANGED
|
@@ -18,8 +18,8 @@ function isApiItem(item) {
|
|
|
18
18
|
function isInfoItem(item) {
|
|
19
19
|
return item.type === "info";
|
|
20
20
|
}
|
|
21
|
-
function groupByTags(items, sidebarOptions, options, tags) {
|
|
22
|
-
const { outputDir } = options;
|
|
21
|
+
function groupByTags(items, sidebarOptions, options, tags, docPath) {
|
|
22
|
+
const { outputDir, label } = options;
|
|
23
23
|
const { sidebarCollapsed, sidebarCollapsible, customProps, categoryLinkSource, } = sidebarOptions;
|
|
24
24
|
const apiItems = items.filter(isApiItem);
|
|
25
25
|
const infoItems = items.filter(isInfoItem);
|
|
@@ -35,10 +35,9 @@ function groupByTags(items, sidebarOptions, options, tags) {
|
|
|
35
35
|
const apiTags = (0, uniq_1.default)(apiItems
|
|
36
36
|
.flatMap((item) => item.api.tags)
|
|
37
37
|
.filter((item) => !!item));
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
.slice(outputDir.indexOf("/", 1))
|
|
41
|
-
.replace(/^\/+/g, "");
|
|
38
|
+
const basePath = docPath
|
|
39
|
+
? outputDir.split(docPath)[1].replace(/^\/+/g, "")
|
|
40
|
+
: outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
|
|
42
41
|
function createDocItem(item) {
|
|
43
42
|
var _a, _b;
|
|
44
43
|
const sidebar_label = item.frontMatter.sidebar_label;
|
|
@@ -46,7 +45,7 @@ function groupByTags(items, sidebarOptions, options, tags) {
|
|
|
46
45
|
const id = item.id;
|
|
47
46
|
return {
|
|
48
47
|
type: "doc",
|
|
49
|
-
id: `${basePath}/${item.id}`,
|
|
48
|
+
id: basePath === "" || undefined ? `${item.id}` : `${basePath}/${item.id}`,
|
|
50
49
|
label: (_b = (_a = sidebar_label) !== null && _a !== void 0 ? _a : title) !== null && _b !== void 0 ? _b : id,
|
|
51
50
|
customProps: customProps,
|
|
52
51
|
className: (0, clsx_1.default)({
|
|
@@ -96,7 +95,9 @@ function groupByTags(items, sidebarOptions, options, tags) {
|
|
|
96
95
|
linkConfig = {
|
|
97
96
|
type: "generated-index",
|
|
98
97
|
title: tag,
|
|
99
|
-
slug:
|
|
98
|
+
slug: label
|
|
99
|
+
? "/category/" + (0, lodash_1.kebabCase)(label) + "/" + (0, lodash_1.kebabCase)(tag)
|
|
100
|
+
: "/category/" + (0, lodash_1.kebabCase)(tag),
|
|
100
101
|
};
|
|
101
102
|
}
|
|
102
103
|
return {
|
|
@@ -136,10 +137,10 @@ function groupByTags(items, sidebarOptions, options, tags) {
|
|
|
136
137
|
}
|
|
137
138
|
return [...tagged, ...untagged];
|
|
138
139
|
}
|
|
139
|
-
function generateSidebarSlice(sidebarOptions, options, api, tags) {
|
|
140
|
+
function generateSidebarSlice(sidebarOptions, options, api, tags, docPath) {
|
|
140
141
|
let sidebarSlice = [];
|
|
141
142
|
if (sidebarOptions.groupPathsBy === "tag") {
|
|
142
|
-
sidebarSlice = groupByTags(api, sidebarOptions, options, tags);
|
|
143
|
+
sidebarSlice = groupByTags(api, sidebarOptions, options, tags, docPath);
|
|
143
144
|
}
|
|
144
145
|
return sidebarSlice;
|
|
145
146
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/* ============================================================================
|
|
3
|
+
* Copyright (c) Palo Alto Networks
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
* ========================================================================== */
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.versionCrumb = exports.versionSelector = void 0;
|
|
10
|
+
const mustache_1 = require("mustache");
|
|
11
|
+
function versionSelector(versions) {
|
|
12
|
+
const template = `<div class="dropdown dropdown--hoverable dropdown--right">
|
|
13
|
+
<button class="button button--block button--sm button--secondary"><span>Select API Version</span></button>
|
|
14
|
+
<ul class="dropdown__menu">
|
|
15
|
+
{{#.}}<li><a class="dropdown__link" href="{{{baseUrl}}}">{{{label}}}</a></li>{{/.}}
|
|
16
|
+
</ul>
|
|
17
|
+
</div>
|
|
18
|
+
`;
|
|
19
|
+
const view = (0, mustache_1.render)(template, versions);
|
|
20
|
+
return view;
|
|
21
|
+
}
|
|
22
|
+
exports.versionSelector = versionSelector;
|
|
23
|
+
function versionCrumb(version) {
|
|
24
|
+
const template = `<ul style="display: flex;" class="breadcrumbs breadcrumbs--sm">
|
|
25
|
+
<li style="margin-left: auto; margin-right: 0;" class="breadcrumbs__item breadcrumbs__item--active">
|
|
26
|
+
<a class="breadcrumbs__link"><span>{{{.}}}</span></a></li></ul>
|
|
27
|
+
`;
|
|
28
|
+
const view = (0, mustache_1.render)(template, version);
|
|
29
|
+
return view;
|
|
30
|
+
}
|
|
31
|
+
exports.versionCrumb = versionCrumb;
|
package/lib/types.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { InfoObject, OperationObject, SecuritySchemeObject, TagObject } from "./
|
|
|
3
3
|
export type { PropSidebarItemCategory, SidebarItemLink, PropSidebar, PropSidebarItem, } from "@docusaurus/plugin-content-docs-types";
|
|
4
4
|
export interface PluginOptions {
|
|
5
5
|
id?: string;
|
|
6
|
+
docsPluginId: string;
|
|
6
7
|
config: {
|
|
7
8
|
[key: string]: APIOptions;
|
|
8
9
|
};
|
|
@@ -12,6 +13,27 @@ export interface APIOptions {
|
|
|
12
13
|
outputDir: string;
|
|
13
14
|
template?: string;
|
|
14
15
|
sidebarOptions?: SidebarOptions;
|
|
16
|
+
version?: string;
|
|
17
|
+
label?: string;
|
|
18
|
+
baseUrl?: string;
|
|
19
|
+
versions?: {
|
|
20
|
+
[key: string]: APIVersionOptions;
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
export interface SidebarOptions {
|
|
24
|
+
groupPathsBy?: string;
|
|
25
|
+
categoryLinkSource?: string;
|
|
26
|
+
customProps?: {
|
|
27
|
+
[key: string]: unknown;
|
|
28
|
+
};
|
|
29
|
+
sidebarCollapsible?: boolean;
|
|
30
|
+
sidebarCollapsed?: boolean;
|
|
31
|
+
}
|
|
32
|
+
export interface APIVersionOptions {
|
|
33
|
+
specPath: string;
|
|
34
|
+
outputDir: string;
|
|
35
|
+
label: string;
|
|
36
|
+
baseUrl: string;
|
|
15
37
|
}
|
|
16
38
|
export interface LoadedContent {
|
|
17
39
|
loadedApi: ApiMetadata[];
|
|
@@ -68,12 +90,3 @@ export interface ApiNavLink {
|
|
|
68
90
|
title: string;
|
|
69
91
|
permalink: string;
|
|
70
92
|
}
|
|
71
|
-
export interface SidebarOptions {
|
|
72
|
-
groupPathsBy?: string;
|
|
73
|
-
categoryLinkSource?: string;
|
|
74
|
-
customProps?: {
|
|
75
|
-
[key: string]: unknown;
|
|
76
|
-
};
|
|
77
|
-
sidebarCollapsible?: boolean;
|
|
78
|
-
sidebarCollapsed?: boolean;
|
|
79
|
-
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "docusaurus-plugin-openapi-docs",
|
|
3
3
|
"description": "OpenAPI plugin for Docusaurus.",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.6",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"openapi",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"utility-types": "^3.10.0"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
+
"@apidevtools/json-schema-ref-parser": "^9.0.9",
|
|
39
40
|
"@docusaurus/mdx-loader": "2.0.0-beta.21",
|
|
40
41
|
"@docusaurus/plugin-content-docs": "2.0.0-beta.21",
|
|
41
42
|
"@docusaurus/utils": "2.0.0-beta.21",
|
|
@@ -62,5 +63,5 @@
|
|
|
62
63
|
"engines": {
|
|
63
64
|
"node": ">=14"
|
|
64
65
|
},
|
|
65
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "ff7622e334e96e7f39b0daf5ef2cb17bfa832834"
|
|
66
67
|
}
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { render } from "mustache";
|
|
|
15
15
|
|
|
16
16
|
import { createApiPageMD, createInfoPageMD, createTagPageMD } from "./markdown";
|
|
17
17
|
import { readOpenapiFiles, processOpenapiFiles } from "./openapi";
|
|
18
|
+
import { OptionsSchema } from "./options";
|
|
18
19
|
import generateSidebarSlice from "./sidebars";
|
|
19
20
|
import type { PluginOptions, LoadedContent, APIOptions } from "./types";
|
|
20
21
|
|
|
@@ -22,12 +23,55 @@ export function isURL(str: string): boolean {
|
|
|
22
23
|
return /^(https?:)\/\//m.test(str);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export
|
|
26
|
+
export function getDocsData(
|
|
27
|
+
dataArray: any[],
|
|
28
|
+
filter: string
|
|
29
|
+
): Object | undefined {
|
|
30
|
+
// eslint-disable-next-line array-callback-return
|
|
31
|
+
const filteredData = dataArray.filter((data) => {
|
|
32
|
+
if (data[0] === filter) {
|
|
33
|
+
return data[1];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Search plugin-content-docs instances
|
|
37
|
+
if (data[0] === "@docusaurus/plugin-content-docs") {
|
|
38
|
+
const pluginId = data[1].id ? data[1].id : "default";
|
|
39
|
+
if (pluginId === filter) {
|
|
40
|
+
return data[1];
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
})[0];
|
|
44
|
+
if (filteredData) {
|
|
45
|
+
// Search presets, e.g. "classic"
|
|
46
|
+
if (filteredData[0] === filter) {
|
|
47
|
+
return filteredData[1].docs;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// Search plugin-content-docs instances
|
|
51
|
+
if (filteredData[0] === "@docusaurus/plugin-content-docs") {
|
|
52
|
+
const pluginId = filteredData[1].id ? filteredData[1].id : "default";
|
|
53
|
+
if (pluginId === filter) {
|
|
54
|
+
return filteredData[1];
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export default function pluginOpenAPIDocs(
|
|
26
62
|
context: LoadContext,
|
|
27
63
|
options: PluginOptions
|
|
28
64
|
): Plugin<LoadedContent> {
|
|
29
|
-
|
|
30
|
-
|
|
65
|
+
const { config, docsPluginId } = options;
|
|
66
|
+
const { siteDir, siteConfig } = context;
|
|
67
|
+
|
|
68
|
+
// Get routeBasePath and path from plugin-content-docs or preset
|
|
69
|
+
const presets: any = siteConfig.presets;
|
|
70
|
+
const plugins: any = siteConfig.plugins;
|
|
71
|
+
const presetsPlugins = presets.concat(plugins);
|
|
72
|
+
const docData: any = getDocsData(presetsPlugins, docsPluginId);
|
|
73
|
+
const docRouteBasePath = docData ? docData.routeBasePath : undefined;
|
|
74
|
+
const docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
|
|
31
75
|
|
|
32
76
|
async function generateApiDocs(options: APIOptions) {
|
|
33
77
|
let { specPath, outputDir, template, sidebarOptions } = options;
|
|
@@ -37,7 +81,7 @@ export default function pluginOpenAPI(
|
|
|
37
81
|
: path.resolve(siteDir, specPath);
|
|
38
82
|
|
|
39
83
|
try {
|
|
40
|
-
const openapiFiles = await readOpenapiFiles(contentPath,
|
|
84
|
+
const openapiFiles = await readOpenapiFiles(contentPath, options);
|
|
41
85
|
const [loadedApi, tags] = await processOpenapiFiles(
|
|
42
86
|
openapiFiles,
|
|
43
87
|
sidebarOptions!
|
|
@@ -57,10 +101,11 @@ export default function pluginOpenAPI(
|
|
|
57
101
|
// TODO: figure out better way to set default
|
|
58
102
|
if (Object.keys(sidebarOptions ?? {}).length > 0) {
|
|
59
103
|
const sidebarSlice = generateSidebarSlice(
|
|
60
|
-
sidebarOptions!,
|
|
104
|
+
sidebarOptions!,
|
|
61
105
|
options,
|
|
62
106
|
loadedApi,
|
|
63
|
-
tags
|
|
107
|
+
tags,
|
|
108
|
+
docPath
|
|
64
109
|
);
|
|
65
110
|
|
|
66
111
|
const sidebarSliceTemplate = template
|
|
@@ -163,7 +208,13 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
163
208
|
item.markdown = markdown;
|
|
164
209
|
if (item.type === "api") {
|
|
165
210
|
item.json = JSON.stringify(item.api);
|
|
166
|
-
|
|
211
|
+
let infoBasePath = `${outputDir}/${item.infoId}`;
|
|
212
|
+
if (docRouteBasePath) {
|
|
213
|
+
infoBasePath = `${docRouteBasePath}/${outputDir
|
|
214
|
+
.split(docPath!)[1]
|
|
215
|
+
.replace(/^\/+/g, "")}/${item.infoId}`.replace(/^\/+/g, "");
|
|
216
|
+
}
|
|
217
|
+
if (item.infoId) item.infoPath = infoBasePath;
|
|
167
218
|
}
|
|
168
219
|
|
|
169
220
|
const view = render(mdTemplate, item);
|
|
@@ -254,9 +305,11 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
254
305
|
const apiDir = path.join(siteDir, outputDir);
|
|
255
306
|
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
256
307
|
cwd: path.resolve(apiDir),
|
|
308
|
+
deep: 1,
|
|
257
309
|
});
|
|
258
310
|
const sidebarFile = await Globby(["sidebar.js"], {
|
|
259
311
|
cwd: path.resolve(apiDir),
|
|
312
|
+
deep: 1,
|
|
260
313
|
});
|
|
261
314
|
apiMdxFiles.map((mdx) =>
|
|
262
315
|
fs.unlink(`${apiDir}/${mdx}`, (err) => {
|
|
@@ -287,21 +340,66 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
287
340
|
);
|
|
288
341
|
}
|
|
289
342
|
|
|
343
|
+
async function generateVersions(versions: object, outputDir: string) {
|
|
344
|
+
let versionsArray = [] as object[];
|
|
345
|
+
for (const [version, metadata] of Object.entries(versions)) {
|
|
346
|
+
versionsArray.push({
|
|
347
|
+
version: version,
|
|
348
|
+
label: metadata.label,
|
|
349
|
+
baseUrl: metadata.baseUrl,
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
const versionsJson = JSON.stringify(versionsArray, null, 2);
|
|
354
|
+
try {
|
|
355
|
+
fs.writeFileSync(`${outputDir}/versions.json`, versionsJson, "utf8");
|
|
356
|
+
console.log(
|
|
357
|
+
chalk.green(`Successfully created "${outputDir}/versions.json"`)
|
|
358
|
+
);
|
|
359
|
+
} catch (err) {
|
|
360
|
+
console.error(
|
|
361
|
+
chalk.red(`Failed to write "${outputDir}/versions.json"`),
|
|
362
|
+
chalk.yellow(err)
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
async function cleanVersions(outputDir: string) {
|
|
368
|
+
if (fs.existsSync(`${outputDir}/versions.json`)) {
|
|
369
|
+
fs.unlink(`${outputDir}/versions.json`, (err) => {
|
|
370
|
+
if (err) {
|
|
371
|
+
console.error(
|
|
372
|
+
chalk.red(`Cleanup failed for "${outputDir}/versions.json"`),
|
|
373
|
+
chalk.yellow(err)
|
|
374
|
+
);
|
|
375
|
+
} else {
|
|
376
|
+
console.log(
|
|
377
|
+
chalk.green(`Cleanup succeeded for "${outputDir}/versions.json"`)
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
290
384
|
return {
|
|
291
|
-
name: `docusaurus-plugin-openapi`,
|
|
385
|
+
name: `docusaurus-plugin-openapi-docs`,
|
|
292
386
|
|
|
293
387
|
extendCli(cli): void {
|
|
294
388
|
cli
|
|
295
389
|
.command(`gen-api-docs`)
|
|
296
|
-
.description(
|
|
297
|
-
|
|
298
|
-
"[options] <id key value in plugin config within docusaurus.config.js>"
|
|
390
|
+
.description(
|
|
391
|
+
`Generates OpenAPI docs in MDX file format and sidebar.js (if enabled).`
|
|
299
392
|
)
|
|
393
|
+
.usage("<id>")
|
|
300
394
|
.arguments("<id>")
|
|
301
395
|
.action(async (id) => {
|
|
302
396
|
if (id === "all") {
|
|
303
397
|
if (config[id]) {
|
|
304
|
-
console.error(
|
|
398
|
+
console.error(
|
|
399
|
+
chalk.red(
|
|
400
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
401
|
+
)
|
|
402
|
+
);
|
|
305
403
|
} else {
|
|
306
404
|
Object.keys(config).forEach(async function (key) {
|
|
307
405
|
await generateApiDocs(config[key]);
|
|
@@ -309,24 +407,91 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
309
407
|
}
|
|
310
408
|
} else if (!config[id]) {
|
|
311
409
|
console.error(
|
|
312
|
-
chalk.red(`ID ${id} does not exist in
|
|
410
|
+
chalk.red(`ID '${id}' does not exist in OpenAPI docs config.`)
|
|
313
411
|
);
|
|
314
412
|
} else {
|
|
315
413
|
await generateApiDocs(config[id]);
|
|
316
414
|
}
|
|
317
415
|
});
|
|
318
416
|
|
|
417
|
+
cli
|
|
418
|
+
.command(`gen-api-docs:version`)
|
|
419
|
+
.description(
|
|
420
|
+
`Generates versioned OpenAPI docs in MDX file format, versions.js and sidebar.js (if enabled).`
|
|
421
|
+
)
|
|
422
|
+
.usage("<id:version>")
|
|
423
|
+
.arguments("<id:version>")
|
|
424
|
+
.action(async (id) => {
|
|
425
|
+
const [parentId, versionId] = id.split(":");
|
|
426
|
+
const parentConfig = Object.assign({}, config[parentId]);
|
|
427
|
+
|
|
428
|
+
const version = parentConfig.version as string;
|
|
429
|
+
const label = parentConfig.label as string;
|
|
430
|
+
const baseUrl = parentConfig.baseUrl as string;
|
|
431
|
+
|
|
432
|
+
let parentVersion = {} as any;
|
|
433
|
+
parentVersion[version] = { label: label, baseUrl: baseUrl };
|
|
434
|
+
|
|
435
|
+
const { versions } = config[parentId] as any;
|
|
436
|
+
const mergedVersions = Object.assign(parentVersion, versions);
|
|
437
|
+
|
|
438
|
+
// Prepare for merge
|
|
439
|
+
delete parentConfig.versions;
|
|
440
|
+
delete parentConfig.version;
|
|
441
|
+
delete parentConfig.label;
|
|
442
|
+
delete parentConfig.baseUrl;
|
|
443
|
+
|
|
444
|
+
// TODO: handle when no versions are defined by version command is passed
|
|
445
|
+
if (versionId === "all") {
|
|
446
|
+
if (versions[id]) {
|
|
447
|
+
console.error(
|
|
448
|
+
chalk.red(
|
|
449
|
+
"Can't use id 'all' for OpenAPI docs versions configuration key."
|
|
450
|
+
)
|
|
451
|
+
);
|
|
452
|
+
} else {
|
|
453
|
+
await generateVersions(mergedVersions, parentConfig.outputDir);
|
|
454
|
+
Object.keys(versions).forEach(async (key) => {
|
|
455
|
+
const versionConfig = versions[key];
|
|
456
|
+
const mergedConfig = {
|
|
457
|
+
...parentConfig,
|
|
458
|
+
...versionConfig,
|
|
459
|
+
};
|
|
460
|
+
await generateApiDocs(mergedConfig);
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
} else if (!versions[versionId]) {
|
|
464
|
+
console.error(
|
|
465
|
+
chalk.red(
|
|
466
|
+
`Version ID '${versionId}' does not exist in OpenAPI docs versions config.`
|
|
467
|
+
)
|
|
468
|
+
);
|
|
469
|
+
} else {
|
|
470
|
+
const versionConfig = versions[versionId];
|
|
471
|
+
const mergedConfig = {
|
|
472
|
+
...parentConfig,
|
|
473
|
+
...versionConfig,
|
|
474
|
+
};
|
|
475
|
+
await generateVersions(mergedVersions, parentConfig.outputDir);
|
|
476
|
+
await generateApiDocs(mergedConfig);
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
|
|
319
480
|
cli
|
|
320
481
|
.command(`clean-api-docs`)
|
|
321
|
-
.description(
|
|
322
|
-
|
|
323
|
-
"[options] <id key value in plugin config within docusaurus.config.js>"
|
|
482
|
+
.description(
|
|
483
|
+
`Clears the generated OpenAPI docs MDX files and sidebar.js (if enabled).`
|
|
324
484
|
)
|
|
485
|
+
.usage("<id>")
|
|
325
486
|
.arguments("<id>")
|
|
326
487
|
.action(async (id) => {
|
|
327
488
|
if (id === "all") {
|
|
328
489
|
if (config[id]) {
|
|
329
|
-
console.error(
|
|
490
|
+
console.error(
|
|
491
|
+
chalk.red(
|
|
492
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
493
|
+
)
|
|
494
|
+
);
|
|
330
495
|
} else {
|
|
331
496
|
Object.keys(config).forEach(async function (key) {
|
|
332
497
|
await cleanApiDocs(config[key]);
|
|
@@ -336,6 +501,51 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
336
501
|
await cleanApiDocs(config[id]);
|
|
337
502
|
}
|
|
338
503
|
});
|
|
504
|
+
|
|
505
|
+
cli
|
|
506
|
+
.command(`clean-api-docs:version`)
|
|
507
|
+
.description(
|
|
508
|
+
`Clears the versioned, generated OpenAPI docs MDX files, versions.json and sidebar.js (if enabled).`
|
|
509
|
+
)
|
|
510
|
+
.usage("<id:version>")
|
|
511
|
+
.arguments("<id:version>")
|
|
512
|
+
.action(async (id) => {
|
|
513
|
+
const [parentId, versionId] = id.split(":");
|
|
514
|
+
const { versions } = config[parentId] as any;
|
|
515
|
+
|
|
516
|
+
const parentConfig = Object.assign({}, config[parentId]);
|
|
517
|
+
delete parentConfig.versions;
|
|
518
|
+
|
|
519
|
+
if (versionId === "all") {
|
|
520
|
+
if (versions[id]) {
|
|
521
|
+
chalk.red(
|
|
522
|
+
"Can't use id 'all' for OpenAPI docs versions configuration key."
|
|
523
|
+
);
|
|
524
|
+
} else {
|
|
525
|
+
await cleanVersions(parentConfig.outputDir);
|
|
526
|
+
Object.keys(versions).forEach(async (key) => {
|
|
527
|
+
const versionConfig = versions[key];
|
|
528
|
+
const mergedConfig = {
|
|
529
|
+
...parentConfig,
|
|
530
|
+
...versionConfig,
|
|
531
|
+
};
|
|
532
|
+
await cleanApiDocs(mergedConfig);
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
} else {
|
|
536
|
+
const versionConfig = versions[versionId];
|
|
537
|
+
const mergedConfig = {
|
|
538
|
+
...parentConfig,
|
|
539
|
+
...versionConfig,
|
|
540
|
+
};
|
|
541
|
+
await cleanApiDocs(mergedConfig);
|
|
542
|
+
}
|
|
543
|
+
});
|
|
339
544
|
},
|
|
340
545
|
};
|
|
341
546
|
}
|
|
547
|
+
|
|
548
|
+
pluginOpenAPIDocs.validateOptions = ({ options, validate }: any) => {
|
|
549
|
+
const validatedOptions = validate(OptionsSchema, options);
|
|
550
|
+
return validatedOptions;
|
|
551
|
+
};
|
package/src/markdown/index.ts
CHANGED
|
@@ -59,7 +59,7 @@ export function createInfoPageMD({
|
|
|
59
59
|
}: InfoPageMetadata) {
|
|
60
60
|
return render([
|
|
61
61
|
`import Tabs from "@theme/Tabs";\n`,
|
|
62
|
-
`import TabItem from "@theme/TabItem";\n`,
|
|
62
|
+
`import TabItem from "@theme/TabItem";\n\n`,
|
|
63
63
|
createVersionBadge(version),
|
|
64
64
|
`# ${escape(title)}\n\n`,
|
|
65
65
|
createDescription(description),
|
|
@@ -16,7 +16,7 @@ describe("openapi", () => {
|
|
|
16
16
|
it("readOpenapiFiles", async () => {
|
|
17
17
|
const results = await readOpenapiFiles(
|
|
18
18
|
path.join(__dirname, "__fixtures__/examples"),
|
|
19
|
-
{}
|
|
19
|
+
{ specPath: "./", outputDir: "./" }
|
|
20
20
|
);
|
|
21
21
|
const categoryMeta = results.find((x) =>
|
|
22
22
|
x.source.endsWith("_category_.json")
|
package/src/openapi/openapi.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { kebabCase } from "lodash";
|
|
|
19
19
|
import { isURL } from "../index";
|
|
20
20
|
import {
|
|
21
21
|
ApiMetadata,
|
|
22
|
+
APIOptions,
|
|
22
23
|
ApiPageMetadata,
|
|
23
24
|
InfoPageMetadata,
|
|
24
25
|
SidebarOptions,
|
|
@@ -247,8 +248,12 @@ interface OpenApiFiles {
|
|
|
247
248
|
|
|
248
249
|
export async function readOpenapiFiles(
|
|
249
250
|
openapiPath: string,
|
|
250
|
-
|
|
251
|
+
options: APIOptions
|
|
251
252
|
): Promise<OpenApiFiles[]> {
|
|
253
|
+
// TODO: determine if this should be an API option
|
|
254
|
+
// Forces the json-schema-ref-parser
|
|
255
|
+
const parseJsonRefs = true;
|
|
256
|
+
|
|
252
257
|
if (!isURL(openapiPath)) {
|
|
253
258
|
const stat = await fs.lstat(openapiPath);
|
|
254
259
|
if (stat.isDirectory()) {
|
|
@@ -270,7 +275,8 @@ export async function readOpenapiFiles(
|
|
|
270
275
|
// TODO: make a function for this
|
|
271
276
|
const fullPath = path.join(openapiPath, source);
|
|
272
277
|
const data = (await loadAndBundleSpec(
|
|
273
|
-
fullPath
|
|
278
|
+
fullPath,
|
|
279
|
+
parseJsonRefs
|
|
274
280
|
)) as OpenApiObjectWithRef;
|
|
275
281
|
return {
|
|
276
282
|
source: fullPath, // This will be aliased in process.
|
|
@@ -281,7 +287,10 @@ export async function readOpenapiFiles(
|
|
|
281
287
|
);
|
|
282
288
|
}
|
|
283
289
|
}
|
|
284
|
-
const data = (await loadAndBundleSpec(
|
|
290
|
+
const data = (await loadAndBundleSpec(
|
|
291
|
+
openapiPath,
|
|
292
|
+
parseJsonRefs
|
|
293
|
+
)) as OpenApiObjectWithRef;
|
|
285
294
|
return [
|
|
286
295
|
{
|
|
287
296
|
source: openapiPath, // This will be aliased in process.
|