docusaurus-plugin-openapi-docs 0.0.0-372 → 0.0.0-376
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/lib/index.d.ts +5 -1
- package/lib/index.js +133 -12
- package/lib/markdown/createParamsDetails.js +2 -0
- package/lib/markdown/createSchemaDetails.js +2 -0
- package/lib/markdown/index.js +1 -1
- package/lib/options.d.ts +0 -2
- package/lib/options.js +36 -7
- package/lib/sidebars/index.js +5 -6
- package/lib/sidebars/utils.d.ts +2 -0
- package/lib/sidebars/utils.js +31 -0
- package/lib/types.d.ts +13 -0
- package/package.json +2 -2
- package/src/index.ts +172 -12
- package/src/markdown/createParamsDetails.ts +2 -0
- package/src/markdown/createSchemaDetails.ts +2 -0
- package/src/markdown/index.ts +1 -1
- package/src/options.ts +41 -8
- package/src/sidebars/index.ts +6 -5
- package/src/sidebars/utils.ts +29 -0
- package/src/types.ts +14 -0
package/lib/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { LoadContext, Plugin } from "@docusaurus/types";
|
|
2
2
|
import type { PluginOptions, LoadedContent } from "./types";
|
|
3
3
|
export declare function isURL(str: string): boolean;
|
|
4
|
-
|
|
4
|
+
declare function pluginOpenAPIDocs(context: LoadContext, options: PluginOptions): Plugin<LoadedContent>;
|
|
5
|
+
declare namespace pluginOpenAPIDocs {
|
|
6
|
+
var validateOptions: ({ options, validate }: any) => any;
|
|
7
|
+
}
|
|
8
|
+
export default pluginOpenAPIDocs;
|
package/lib/index.js
CHANGED
|
@@ -17,12 +17,13 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
17
17
|
const mustache_1 = require("mustache");
|
|
18
18
|
const markdown_1 = require("./markdown");
|
|
19
19
|
const openapi_1 = require("./openapi");
|
|
20
|
+
const options_1 = require("./options");
|
|
20
21
|
const sidebars_1 = __importDefault(require("./sidebars"));
|
|
21
22
|
function isURL(str) {
|
|
22
23
|
return /^(https?:)\/\//m.test(str);
|
|
23
24
|
}
|
|
24
25
|
exports.isURL = isURL;
|
|
25
|
-
function
|
|
26
|
+
function pluginOpenAPIDocs(context, options) {
|
|
26
27
|
let { config } = options;
|
|
27
28
|
let { siteDir } = context;
|
|
28
29
|
async function generateApiDocs(options) {
|
|
@@ -44,8 +45,7 @@ function pluginOpenAPI(context, options) {
|
|
|
44
45
|
}
|
|
45
46
|
// TODO: figure out better way to set default
|
|
46
47
|
if (Object.keys(sidebarOptions !== null && sidebarOptions !== void 0 ? sidebarOptions : {}).length > 0) {
|
|
47
|
-
const sidebarSlice = (0, sidebars_1.default)(sidebarOptions,
|
|
48
|
-
options, loadedApi, tags);
|
|
48
|
+
const sidebarSlice = (0, sidebars_1.default)(sidebarOptions, options, loadedApi, tags);
|
|
49
49
|
const sidebarSliceTemplate = template
|
|
50
50
|
? fs_1.default.readFileSync(template).toString()
|
|
51
51
|
: `module.exports = {{{slice}}};`;
|
|
@@ -192,9 +192,11 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
192
192
|
const apiDir = path_1.default.join(siteDir, outputDir);
|
|
193
193
|
const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
194
194
|
cwd: path_1.default.resolve(apiDir),
|
|
195
|
+
deep: 1,
|
|
195
196
|
});
|
|
196
197
|
const sidebarFile = await (0, utils_1.Globby)(["sidebar.js"], {
|
|
197
198
|
cwd: path_1.default.resolve(apiDir),
|
|
199
|
+
deep: 1,
|
|
198
200
|
});
|
|
199
201
|
apiMdxFiles.map((mdx) => fs_1.default.unlink(`${apiDir}/${mdx}`, (err) => {
|
|
200
202
|
if (err) {
|
|
@@ -213,18 +215,48 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
213
215
|
}
|
|
214
216
|
}));
|
|
215
217
|
}
|
|
218
|
+
async function generateVersions(versions, outputDir) {
|
|
219
|
+
let versionsArray = [];
|
|
220
|
+
for (const [version, metadata] of Object.entries(versions)) {
|
|
221
|
+
versionsArray.push({
|
|
222
|
+
version: version,
|
|
223
|
+
label: metadata.label,
|
|
224
|
+
baseUrl: metadata.baseUrl,
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
const versionsJson = JSON.stringify(versionsArray, null, 2);
|
|
228
|
+
try {
|
|
229
|
+
fs_1.default.writeFileSync(`${outputDir}/versions.json`, versionsJson, "utf8");
|
|
230
|
+
console.log(chalk_1.default.green(`Successfully created "${outputDir}/versions.json"`));
|
|
231
|
+
}
|
|
232
|
+
catch (err) {
|
|
233
|
+
console.error(chalk_1.default.red(`Failed to write "${outputDir}/versions.json"`), chalk_1.default.yellow(err));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async function cleanVersions(outputDir) {
|
|
237
|
+
if (fs_1.default.existsSync(`${outputDir}/versions.json`)) {
|
|
238
|
+
fs_1.default.unlink(`${outputDir}/versions.json`, (err) => {
|
|
239
|
+
if (err) {
|
|
240
|
+
console.error(chalk_1.default.red(`Cleanup failed for "${outputDir}/versions.json"`), chalk_1.default.yellow(err));
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
console.log(chalk_1.default.green(`Cleanup succeeded for "${outputDir}/versions.json"`));
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
}
|
|
216
248
|
return {
|
|
217
|
-
name: `docusaurus-plugin-openapi`,
|
|
249
|
+
name: `docusaurus-plugin-openapi-docs`,
|
|
218
250
|
extendCli(cli) {
|
|
219
251
|
cli
|
|
220
252
|
.command(`gen-api-docs`)
|
|
221
|
-
.description(`Generates
|
|
222
|
-
.usage("
|
|
253
|
+
.description(`Generates OpenAPI docs in MDX file format and sidebar.js (if enabled).`)
|
|
254
|
+
.usage("<id>")
|
|
223
255
|
.arguments("<id>")
|
|
224
256
|
.action(async (id) => {
|
|
225
257
|
if (id === "all") {
|
|
226
258
|
if (config[id]) {
|
|
227
|
-
console.error(chalk_1.default.red("Can't use id 'all' for
|
|
259
|
+
console.error(chalk_1.default.red("Can't use id 'all' for OpenAPI docs configuration key."));
|
|
228
260
|
}
|
|
229
261
|
else {
|
|
230
262
|
Object.keys(config).forEach(async function (key) {
|
|
@@ -233,21 +265,71 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
233
265
|
}
|
|
234
266
|
}
|
|
235
267
|
else if (!config[id]) {
|
|
236
|
-
console.error(chalk_1.default.red(`ID ${id} does not exist in
|
|
268
|
+
console.error(chalk_1.default.red(`ID '${id}' does not exist in OpenAPI docs config.`));
|
|
237
269
|
}
|
|
238
270
|
else {
|
|
239
271
|
await generateApiDocs(config[id]);
|
|
240
272
|
}
|
|
241
273
|
});
|
|
274
|
+
cli
|
|
275
|
+
.command(`gen-api-docs:version`)
|
|
276
|
+
.description(`Generates versioned OpenAPI docs in MDX file format, versions.js and sidebar.js (if enabled).`)
|
|
277
|
+
.usage("<id:version>")
|
|
278
|
+
.arguments("<id:version>")
|
|
279
|
+
.action(async (id) => {
|
|
280
|
+
const [parentId, versionId] = id.split(":");
|
|
281
|
+
const parentConfig = Object.assign({}, config[parentId]);
|
|
282
|
+
const version = parentConfig.version;
|
|
283
|
+
const label = parentConfig.label;
|
|
284
|
+
const baseUrl = parentConfig.baseUrl;
|
|
285
|
+
let parentVersion = {};
|
|
286
|
+
parentVersion[version] = { label: label, baseUrl: baseUrl };
|
|
287
|
+
const { versions } = config[parentId];
|
|
288
|
+
const mergedVersions = Object.assign(parentVersion, versions);
|
|
289
|
+
// Prepare for merge
|
|
290
|
+
delete parentConfig.versions;
|
|
291
|
+
delete parentConfig.version;
|
|
292
|
+
delete parentConfig.label;
|
|
293
|
+
delete parentConfig.baseUrl;
|
|
294
|
+
// TODO: handle when no versions are defined by version command is passed
|
|
295
|
+
if (versionId === "all") {
|
|
296
|
+
if (versions[id]) {
|
|
297
|
+
console.error(chalk_1.default.red("Can't use id 'all' for OpenAPI docs versions configuration key."));
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
await generateVersions(mergedVersions, parentConfig.outputDir);
|
|
301
|
+
Object.keys(versions).forEach(async (key) => {
|
|
302
|
+
const versionConfig = versions[key];
|
|
303
|
+
const mergedConfig = {
|
|
304
|
+
...parentConfig,
|
|
305
|
+
...versionConfig,
|
|
306
|
+
};
|
|
307
|
+
await generateApiDocs(mergedConfig);
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
else if (!versions[versionId]) {
|
|
312
|
+
console.error(chalk_1.default.red(`Version ID '${versionId}' does not exist in OpenAPI docs versions config.`));
|
|
313
|
+
}
|
|
314
|
+
else {
|
|
315
|
+
const versionConfig = versions[versionId];
|
|
316
|
+
const mergedConfig = {
|
|
317
|
+
...parentConfig,
|
|
318
|
+
...versionConfig,
|
|
319
|
+
};
|
|
320
|
+
await generateVersions(mergedVersions, parentConfig.outputDir);
|
|
321
|
+
await generateApiDocs(mergedConfig);
|
|
322
|
+
}
|
|
323
|
+
});
|
|
242
324
|
cli
|
|
243
325
|
.command(`clean-api-docs`)
|
|
244
|
-
.description(`Clears the
|
|
245
|
-
.usage("
|
|
326
|
+
.description(`Clears the generated OpenAPI docs MDX files and sidebar.js (if enabled).`)
|
|
327
|
+
.usage("<id>")
|
|
246
328
|
.arguments("<id>")
|
|
247
329
|
.action(async (id) => {
|
|
248
330
|
if (id === "all") {
|
|
249
331
|
if (config[id]) {
|
|
250
|
-
console.error(chalk_1.default.red("Can't use id 'all' for
|
|
332
|
+
console.error(chalk_1.default.red("Can't use id 'all' for OpenAPI docs configuration key."));
|
|
251
333
|
}
|
|
252
334
|
else {
|
|
253
335
|
Object.keys(config).forEach(async function (key) {
|
|
@@ -259,7 +341,46 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
259
341
|
await cleanApiDocs(config[id]);
|
|
260
342
|
}
|
|
261
343
|
});
|
|
344
|
+
cli
|
|
345
|
+
.command(`clean-api-docs:version`)
|
|
346
|
+
.description(`Clears the versioned, generated OpenAPI docs MDX files, versions.json and sidebar.js (if enabled).`)
|
|
347
|
+
.usage("<id:version>")
|
|
348
|
+
.arguments("<id:version>")
|
|
349
|
+
.action(async (id) => {
|
|
350
|
+
const [parentId, versionId] = id.split(":");
|
|
351
|
+
const { versions } = config[parentId];
|
|
352
|
+
const parentConfig = Object.assign({}, config[parentId]);
|
|
353
|
+
delete parentConfig.versions;
|
|
354
|
+
if (versionId === "all") {
|
|
355
|
+
if (versions[id]) {
|
|
356
|
+
chalk_1.default.red("Can't use id 'all' for OpenAPI docs versions configuration key.");
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
await cleanVersions(parentConfig.outputDir);
|
|
360
|
+
Object.keys(versions).forEach(async (key) => {
|
|
361
|
+
const versionConfig = versions[key];
|
|
362
|
+
const mergedConfig = {
|
|
363
|
+
...parentConfig,
|
|
364
|
+
...versionConfig,
|
|
365
|
+
};
|
|
366
|
+
await cleanApiDocs(mergedConfig);
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
else {
|
|
371
|
+
const versionConfig = versions[versionId];
|
|
372
|
+
const mergedConfig = {
|
|
373
|
+
...parentConfig,
|
|
374
|
+
...versionConfig,
|
|
375
|
+
};
|
|
376
|
+
await cleanApiDocs(mergedConfig);
|
|
377
|
+
}
|
|
378
|
+
});
|
|
262
379
|
},
|
|
263
380
|
};
|
|
264
381
|
}
|
|
265
|
-
exports.default =
|
|
382
|
+
exports.default = pluginOpenAPIDocs;
|
|
383
|
+
pluginOpenAPIDocs.validateOptions = ({ options, validate }) => {
|
|
384
|
+
const validatedOptions = validate(options_1.OptionsSchema, options);
|
|
385
|
+
return validatedOptions;
|
|
386
|
+
};
|
|
@@ -19,6 +19,8 @@ function createParamsDetails({ parameters, type }) {
|
|
|
19
19
|
return undefined;
|
|
20
20
|
}
|
|
21
21
|
return (0, createDetails_1.createDetails)({
|
|
22
|
+
"data-collapsed": false,
|
|
23
|
+
open: true,
|
|
22
24
|
style: { marginBottom: "1rem" },
|
|
23
25
|
children: [
|
|
24
26
|
(0, createDetailsSummary_1.createDetailsSummary)({
|
package/lib/markdown/index.js
CHANGED
|
@@ -40,7 +40,7 @@ exports.createApiPageMD = createApiPageMD;
|
|
|
40
40
|
function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, securitySchemes, }) {
|
|
41
41
|
return (0, utils_1.render)([
|
|
42
42
|
`import Tabs from "@theme/Tabs";\n`,
|
|
43
|
-
`import TabItem from "@theme/TabItem";\n`,
|
|
43
|
+
`import TabItem from "@theme/TabItem";\n\n`,
|
|
44
44
|
(0, createVersionBadge_1.createVersionBadge)(version),
|
|
45
45
|
`# ${(0, lodash_1.escape)(title)}\n\n`,
|
|
46
46
|
(0, createDescription_1.createDescription)(description),
|
package/lib/options.d.ts
CHANGED
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
|
+
contentDocsPath: utils_validation_1.Joi.string(),
|
|
13
|
+
groupPathsBy: utils_validation_1.Joi.string().valid("tag"),
|
|
14
|
+
categoryLinkSource: utils_validation_1.Joi.string().valid("tag", "info"),
|
|
15
|
+
customProps: utils_validation_1.Joi.object(),
|
|
16
|
+
sidebarCollapsible: utils_validation_1.Joi.boolean(),
|
|
17
|
+
sidebarCollapsed: utils_validation_1.Joi.boolean(),
|
|
18
|
+
}).with("groupPathsBy", "contentDocsPath");
|
|
15
19
|
exports.OptionsSchema = utils_validation_1.Joi.object({
|
|
16
|
-
id: utils_validation_1.Joi.string().
|
|
17
|
-
config: utils_validation_1.Joi.object()
|
|
20
|
+
id: 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.js
CHANGED
|
@@ -20,7 +20,7 @@ function isInfoItem(item) {
|
|
|
20
20
|
}
|
|
21
21
|
function groupByTags(items, sidebarOptions, options, tags) {
|
|
22
22
|
const { outputDir } = options;
|
|
23
|
-
const { sidebarCollapsed, sidebarCollapsible, customProps, categoryLinkSource, } = sidebarOptions;
|
|
23
|
+
const { sidebarCollapsed, sidebarCollapsible, customProps, categoryLinkSource, contentDocsPath, } = sidebarOptions;
|
|
24
24
|
const apiItems = items.filter(isApiItem);
|
|
25
25
|
const infoItems = items.filter(isInfoItem);
|
|
26
26
|
const intros = infoItems.map((item) => {
|
|
@@ -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 = contentDocsPath
|
|
39
|
+
? outputDir.split(contentDocsPath)[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)({
|
|
@@ -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
|
@@ -12,6 +12,18 @@ export interface APIOptions {
|
|
|
12
12
|
outputDir: string;
|
|
13
13
|
template?: string;
|
|
14
14
|
sidebarOptions?: SidebarOptions;
|
|
15
|
+
version?: string;
|
|
16
|
+
label?: string;
|
|
17
|
+
baseUrl?: string;
|
|
18
|
+
versions?: {
|
|
19
|
+
[key: string]: APIVersionOptions;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface APIVersionOptions {
|
|
23
|
+
specPath: string;
|
|
24
|
+
outputDir: string;
|
|
25
|
+
label: string;
|
|
26
|
+
baseUrl: string;
|
|
15
27
|
}
|
|
16
28
|
export interface LoadedContent {
|
|
17
29
|
loadedApi: ApiMetadata[];
|
|
@@ -69,6 +81,7 @@ export interface ApiNavLink {
|
|
|
69
81
|
permalink: string;
|
|
70
82
|
}
|
|
71
83
|
export interface SidebarOptions {
|
|
84
|
+
contentDocsPath?: string;
|
|
72
85
|
groupPathsBy?: string;
|
|
73
86
|
categoryLinkSource?: string;
|
|
74
87
|
customProps?: {
|
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": "0.0.0-
|
|
4
|
+
"version": "0.0.0-376",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"openapi",
|
|
@@ -62,5 +62,5 @@
|
|
|
62
62
|
"engines": {
|
|
63
63
|
"node": ">=14"
|
|
64
64
|
},
|
|
65
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "1a772d94e5e7075dff6f522aef9aab9303a0e007"
|
|
66
66
|
}
|
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,7 +23,7 @@ export function isURL(str: string): boolean {
|
|
|
22
23
|
return /^(https?:)\/\//m.test(str);
|
|
23
24
|
}
|
|
24
25
|
|
|
25
|
-
export default function
|
|
26
|
+
export default function pluginOpenAPIDocs(
|
|
26
27
|
context: LoadContext,
|
|
27
28
|
options: PluginOptions
|
|
28
29
|
): Plugin<LoadedContent> {
|
|
@@ -57,7 +58,7 @@ export default function pluginOpenAPI(
|
|
|
57
58
|
// TODO: figure out better way to set default
|
|
58
59
|
if (Object.keys(sidebarOptions ?? {}).length > 0) {
|
|
59
60
|
const sidebarSlice = generateSidebarSlice(
|
|
60
|
-
sidebarOptions!,
|
|
61
|
+
sidebarOptions!,
|
|
61
62
|
options,
|
|
62
63
|
loadedApi,
|
|
63
64
|
tags
|
|
@@ -254,9 +255,11 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
254
255
|
const apiDir = path.join(siteDir, outputDir);
|
|
255
256
|
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
256
257
|
cwd: path.resolve(apiDir),
|
|
258
|
+
deep: 1,
|
|
257
259
|
});
|
|
258
260
|
const sidebarFile = await Globby(["sidebar.js"], {
|
|
259
261
|
cwd: path.resolve(apiDir),
|
|
262
|
+
deep: 1,
|
|
260
263
|
});
|
|
261
264
|
apiMdxFiles.map((mdx) =>
|
|
262
265
|
fs.unlink(`${apiDir}/${mdx}`, (err) => {
|
|
@@ -287,21 +290,66 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
287
290
|
);
|
|
288
291
|
}
|
|
289
292
|
|
|
293
|
+
async function generateVersions(versions: object, outputDir: string) {
|
|
294
|
+
let versionsArray = [] as object[];
|
|
295
|
+
for (const [version, metadata] of Object.entries(versions)) {
|
|
296
|
+
versionsArray.push({
|
|
297
|
+
version: version,
|
|
298
|
+
label: metadata.label,
|
|
299
|
+
baseUrl: metadata.baseUrl,
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
const versionsJson = JSON.stringify(versionsArray, null, 2);
|
|
304
|
+
try {
|
|
305
|
+
fs.writeFileSync(`${outputDir}/versions.json`, versionsJson, "utf8");
|
|
306
|
+
console.log(
|
|
307
|
+
chalk.green(`Successfully created "${outputDir}/versions.json"`)
|
|
308
|
+
);
|
|
309
|
+
} catch (err) {
|
|
310
|
+
console.error(
|
|
311
|
+
chalk.red(`Failed to write "${outputDir}/versions.json"`),
|
|
312
|
+
chalk.yellow(err)
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
async function cleanVersions(outputDir: string) {
|
|
318
|
+
if (fs.existsSync(`${outputDir}/versions.json`)) {
|
|
319
|
+
fs.unlink(`${outputDir}/versions.json`, (err) => {
|
|
320
|
+
if (err) {
|
|
321
|
+
console.error(
|
|
322
|
+
chalk.red(`Cleanup failed for "${outputDir}/versions.json"`),
|
|
323
|
+
chalk.yellow(err)
|
|
324
|
+
);
|
|
325
|
+
} else {
|
|
326
|
+
console.log(
|
|
327
|
+
chalk.green(`Cleanup succeeded for "${outputDir}/versions.json"`)
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
290
334
|
return {
|
|
291
|
-
name: `docusaurus-plugin-openapi`,
|
|
335
|
+
name: `docusaurus-plugin-openapi-docs`,
|
|
292
336
|
|
|
293
337
|
extendCli(cli): void {
|
|
294
338
|
cli
|
|
295
339
|
.command(`gen-api-docs`)
|
|
296
|
-
.description(
|
|
297
|
-
|
|
298
|
-
"[options] <id key value in plugin config within docusaurus.config.js>"
|
|
340
|
+
.description(
|
|
341
|
+
`Generates OpenAPI docs in MDX file format and sidebar.js (if enabled).`
|
|
299
342
|
)
|
|
343
|
+
.usage("<id>")
|
|
300
344
|
.arguments("<id>")
|
|
301
345
|
.action(async (id) => {
|
|
302
346
|
if (id === "all") {
|
|
303
347
|
if (config[id]) {
|
|
304
|
-
console.error(
|
|
348
|
+
console.error(
|
|
349
|
+
chalk.red(
|
|
350
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
351
|
+
)
|
|
352
|
+
);
|
|
305
353
|
} else {
|
|
306
354
|
Object.keys(config).forEach(async function (key) {
|
|
307
355
|
await generateApiDocs(config[key]);
|
|
@@ -309,24 +357,91 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
309
357
|
}
|
|
310
358
|
} else if (!config[id]) {
|
|
311
359
|
console.error(
|
|
312
|
-
chalk.red(`ID ${id} does not exist in
|
|
360
|
+
chalk.red(`ID '${id}' does not exist in OpenAPI docs config.`)
|
|
313
361
|
);
|
|
314
362
|
} else {
|
|
315
363
|
await generateApiDocs(config[id]);
|
|
316
364
|
}
|
|
317
365
|
});
|
|
318
366
|
|
|
367
|
+
cli
|
|
368
|
+
.command(`gen-api-docs:version`)
|
|
369
|
+
.description(
|
|
370
|
+
`Generates versioned OpenAPI docs in MDX file format, versions.js and sidebar.js (if enabled).`
|
|
371
|
+
)
|
|
372
|
+
.usage("<id:version>")
|
|
373
|
+
.arguments("<id:version>")
|
|
374
|
+
.action(async (id) => {
|
|
375
|
+
const [parentId, versionId] = id.split(":");
|
|
376
|
+
const parentConfig = Object.assign({}, config[parentId]);
|
|
377
|
+
|
|
378
|
+
const version = parentConfig.version as string;
|
|
379
|
+
const label = parentConfig.label as string;
|
|
380
|
+
const baseUrl = parentConfig.baseUrl as string;
|
|
381
|
+
|
|
382
|
+
let parentVersion = {} as any;
|
|
383
|
+
parentVersion[version] = { label: label, baseUrl: baseUrl };
|
|
384
|
+
|
|
385
|
+
const { versions } = config[parentId] as any;
|
|
386
|
+
const mergedVersions = Object.assign(parentVersion, versions);
|
|
387
|
+
|
|
388
|
+
// Prepare for merge
|
|
389
|
+
delete parentConfig.versions;
|
|
390
|
+
delete parentConfig.version;
|
|
391
|
+
delete parentConfig.label;
|
|
392
|
+
delete parentConfig.baseUrl;
|
|
393
|
+
|
|
394
|
+
// TODO: handle when no versions are defined by version command is passed
|
|
395
|
+
if (versionId === "all") {
|
|
396
|
+
if (versions[id]) {
|
|
397
|
+
console.error(
|
|
398
|
+
chalk.red(
|
|
399
|
+
"Can't use id 'all' for OpenAPI docs versions configuration key."
|
|
400
|
+
)
|
|
401
|
+
);
|
|
402
|
+
} else {
|
|
403
|
+
await generateVersions(mergedVersions, parentConfig.outputDir);
|
|
404
|
+
Object.keys(versions).forEach(async (key) => {
|
|
405
|
+
const versionConfig = versions[key];
|
|
406
|
+
const mergedConfig = {
|
|
407
|
+
...parentConfig,
|
|
408
|
+
...versionConfig,
|
|
409
|
+
};
|
|
410
|
+
await generateApiDocs(mergedConfig);
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
} else if (!versions[versionId]) {
|
|
414
|
+
console.error(
|
|
415
|
+
chalk.red(
|
|
416
|
+
`Version ID '${versionId}' does not exist in OpenAPI docs versions config.`
|
|
417
|
+
)
|
|
418
|
+
);
|
|
419
|
+
} else {
|
|
420
|
+
const versionConfig = versions[versionId];
|
|
421
|
+
const mergedConfig = {
|
|
422
|
+
...parentConfig,
|
|
423
|
+
...versionConfig,
|
|
424
|
+
};
|
|
425
|
+
await generateVersions(mergedVersions, parentConfig.outputDir);
|
|
426
|
+
await generateApiDocs(mergedConfig);
|
|
427
|
+
}
|
|
428
|
+
});
|
|
429
|
+
|
|
319
430
|
cli
|
|
320
431
|
.command(`clean-api-docs`)
|
|
321
|
-
.description(
|
|
322
|
-
|
|
323
|
-
"[options] <id key value in plugin config within docusaurus.config.js>"
|
|
432
|
+
.description(
|
|
433
|
+
`Clears the generated OpenAPI docs MDX files and sidebar.js (if enabled).`
|
|
324
434
|
)
|
|
435
|
+
.usage("<id>")
|
|
325
436
|
.arguments("<id>")
|
|
326
437
|
.action(async (id) => {
|
|
327
438
|
if (id === "all") {
|
|
328
439
|
if (config[id]) {
|
|
329
|
-
console.error(
|
|
440
|
+
console.error(
|
|
441
|
+
chalk.red(
|
|
442
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
443
|
+
)
|
|
444
|
+
);
|
|
330
445
|
} else {
|
|
331
446
|
Object.keys(config).forEach(async function (key) {
|
|
332
447
|
await cleanApiDocs(config[key]);
|
|
@@ -336,6 +451,51 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
336
451
|
await cleanApiDocs(config[id]);
|
|
337
452
|
}
|
|
338
453
|
});
|
|
454
|
+
|
|
455
|
+
cli
|
|
456
|
+
.command(`clean-api-docs:version`)
|
|
457
|
+
.description(
|
|
458
|
+
`Clears the versioned, generated OpenAPI docs MDX files, versions.json and sidebar.js (if enabled).`
|
|
459
|
+
)
|
|
460
|
+
.usage("<id:version>")
|
|
461
|
+
.arguments("<id:version>")
|
|
462
|
+
.action(async (id) => {
|
|
463
|
+
const [parentId, versionId] = id.split(":");
|
|
464
|
+
const { versions } = config[parentId] as any;
|
|
465
|
+
|
|
466
|
+
const parentConfig = Object.assign({}, config[parentId]);
|
|
467
|
+
delete parentConfig.versions;
|
|
468
|
+
|
|
469
|
+
if (versionId === "all") {
|
|
470
|
+
if (versions[id]) {
|
|
471
|
+
chalk.red(
|
|
472
|
+
"Can't use id 'all' for OpenAPI docs versions configuration key."
|
|
473
|
+
);
|
|
474
|
+
} else {
|
|
475
|
+
await cleanVersions(parentConfig.outputDir);
|
|
476
|
+
Object.keys(versions).forEach(async (key) => {
|
|
477
|
+
const versionConfig = versions[key];
|
|
478
|
+
const mergedConfig = {
|
|
479
|
+
...parentConfig,
|
|
480
|
+
...versionConfig,
|
|
481
|
+
};
|
|
482
|
+
await cleanApiDocs(mergedConfig);
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
} else {
|
|
486
|
+
const versionConfig = versions[versionId];
|
|
487
|
+
const mergedConfig = {
|
|
488
|
+
...parentConfig,
|
|
489
|
+
...versionConfig,
|
|
490
|
+
};
|
|
491
|
+
await cleanApiDocs(mergedConfig);
|
|
492
|
+
}
|
|
493
|
+
});
|
|
339
494
|
},
|
|
340
495
|
};
|
|
341
496
|
}
|
|
497
|
+
|
|
498
|
+
pluginOpenAPIDocs.validateOptions = ({ options, validate }: any) => {
|
|
499
|
+
const validatedOptions = validate(OptionsSchema, options);
|
|
500
|
+
return validatedOptions;
|
|
501
|
+
};
|
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),
|
package/src/options.ts
CHANGED
|
@@ -7,14 +7,47 @@
|
|
|
7
7
|
|
|
8
8
|
import { Joi } from "@docusaurus/utils-validation";
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
const sidebarOptions = Joi.object({
|
|
11
|
+
contentDocsPath: Joi.string(),
|
|
12
|
+
groupPathsBy: Joi.string().valid("tag"),
|
|
13
|
+
categoryLinkSource: Joi.string().valid("tag", "info"),
|
|
14
|
+
customProps: Joi.object(),
|
|
15
|
+
sidebarCollapsible: Joi.boolean(),
|
|
16
|
+
sidebarCollapsed: Joi.boolean(),
|
|
17
|
+
}).with("groupPathsBy", "contentDocsPath");
|
|
16
18
|
|
|
17
19
|
export const OptionsSchema = Joi.object({
|
|
18
|
-
id: Joi.string().
|
|
19
|
-
config: Joi.object()
|
|
20
|
+
id: Joi.string().required(),
|
|
21
|
+
config: Joi.object()
|
|
22
|
+
.pattern(
|
|
23
|
+
/^/,
|
|
24
|
+
Joi.object({
|
|
25
|
+
specPath: Joi.string().required(),
|
|
26
|
+
outputDir: Joi.string().required(),
|
|
27
|
+
template: Joi.string(),
|
|
28
|
+
sidebarOptions: sidebarOptions,
|
|
29
|
+
version: Joi.string().when("versions", {
|
|
30
|
+
is: Joi.exist(),
|
|
31
|
+
then: Joi.required(),
|
|
32
|
+
}),
|
|
33
|
+
label: Joi.string().when("versions", {
|
|
34
|
+
is: Joi.exist(),
|
|
35
|
+
then: Joi.required(),
|
|
36
|
+
}),
|
|
37
|
+
baseUrl: Joi.string().when("versions", {
|
|
38
|
+
is: Joi.exist(),
|
|
39
|
+
then: Joi.required(),
|
|
40
|
+
}),
|
|
41
|
+
versions: Joi.object().pattern(
|
|
42
|
+
/^/,
|
|
43
|
+
Joi.object({
|
|
44
|
+
specPath: Joi.string().required(),
|
|
45
|
+
outputDir: Joi.string().required(),
|
|
46
|
+
label: Joi.string().required(),
|
|
47
|
+
baseUrl: Joi.string().required(),
|
|
48
|
+
})
|
|
49
|
+
),
|
|
50
|
+
})
|
|
51
|
+
)
|
|
52
|
+
.required(),
|
|
20
53
|
});
|
package/src/sidebars/index.ts
CHANGED
|
@@ -43,6 +43,7 @@ function groupByTags(
|
|
|
43
43
|
sidebarCollapsible,
|
|
44
44
|
customProps,
|
|
45
45
|
categoryLinkSource,
|
|
46
|
+
contentDocsPath,
|
|
46
47
|
} = sidebarOptions;
|
|
47
48
|
|
|
48
49
|
const apiItems = items.filter(isApiItem);
|
|
@@ -63,10 +64,9 @@ function groupByTags(
|
|
|
63
64
|
.filter((item): item is string => !!item)
|
|
64
65
|
);
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
.slice(outputDir.indexOf("/", 1))
|
|
69
|
-
.replace(/^\/+/g, "");
|
|
67
|
+
const basePath = contentDocsPath
|
|
68
|
+
? outputDir.split(contentDocsPath!)[1].replace(/^\/+/g, "")
|
|
69
|
+
: outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
|
|
70
70
|
|
|
71
71
|
function createDocItem(item: ApiPageMetadata): SidebarItemDoc {
|
|
72
72
|
const sidebar_label = item.frontMatter.sidebar_label;
|
|
@@ -74,7 +74,8 @@ function groupByTags(
|
|
|
74
74
|
const id = item.id;
|
|
75
75
|
return {
|
|
76
76
|
type: "doc" as const,
|
|
77
|
-
id:
|
|
77
|
+
id:
|
|
78
|
+
basePath === "" || undefined ? `${item.id}` : `${basePath}/${item.id}`,
|
|
78
79
|
label: (sidebar_label as string) ?? title ?? id,
|
|
79
80
|
customProps: customProps,
|
|
80
81
|
className: clsx(
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Copyright (c) Palo Alto Networks
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
import { render } from "mustache";
|
|
9
|
+
|
|
10
|
+
export function versionSelector(versions: object[]) {
|
|
11
|
+
const template = `<div class="dropdown dropdown--hoverable dropdown--right">
|
|
12
|
+
<button class="button button--block button--sm button--secondary"><span>Select API Version</span></button>
|
|
13
|
+
<ul class="dropdown__menu">
|
|
14
|
+
{{#.}}<li><a class="dropdown__link" href="{{{baseUrl}}}">{{{label}}}</a></li>{{/.}}
|
|
15
|
+
</ul>
|
|
16
|
+
</div>
|
|
17
|
+
`;
|
|
18
|
+
const view = render(template, versions);
|
|
19
|
+
return view;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function versionCrumb(version: string) {
|
|
23
|
+
const template = `<ul style="display: flex;" class="breadcrumbs breadcrumbs--sm">
|
|
24
|
+
<li style="margin-left: auto; margin-right: 0;" class="breadcrumbs__item breadcrumbs__item--active">
|
|
25
|
+
<a class="breadcrumbs__link"><span>{{{.}}}</span></a></li></ul>
|
|
26
|
+
`;
|
|
27
|
+
const view = render(template, version);
|
|
28
|
+
return view;
|
|
29
|
+
}
|
package/src/types.ts
CHANGED
|
@@ -32,6 +32,19 @@ export interface APIOptions {
|
|
|
32
32
|
outputDir: string;
|
|
33
33
|
template?: string;
|
|
34
34
|
sidebarOptions?: SidebarOptions;
|
|
35
|
+
version?: string;
|
|
36
|
+
label?: string;
|
|
37
|
+
baseUrl?: string;
|
|
38
|
+
versions?: {
|
|
39
|
+
[key: string]: APIVersionOptions;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface APIVersionOptions {
|
|
44
|
+
specPath: string;
|
|
45
|
+
outputDir: string;
|
|
46
|
+
label: string;
|
|
47
|
+
baseUrl: string;
|
|
35
48
|
}
|
|
36
49
|
|
|
37
50
|
export interface LoadedContent {
|
|
@@ -101,6 +114,7 @@ export interface ApiNavLink {
|
|
|
101
114
|
}
|
|
102
115
|
|
|
103
116
|
export interface SidebarOptions {
|
|
117
|
+
contentDocsPath?: string;
|
|
104
118
|
groupPathsBy?: string;
|
|
105
119
|
categoryLinkSource?: string;
|
|
106
120
|
customProps?: { [key: string]: unknown };
|