docusaurus-plugin-openapi-docs 1.0.1 → 1.0.4
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 +110 -21
- package/lib/index.d.ts +7 -1
- package/lib/index.js +257 -22
- package/lib/markdown/createAuthentication.d.ts +2 -0
- package/lib/markdown/createAuthentication.js +139 -0
- package/lib/markdown/createContactInfo.d.ts +2 -0
- package/lib/markdown/createContactInfo.js +49 -0
- package/lib/markdown/createLicense.d.ts +2 -0
- package/lib/markdown/createLicense.js +33 -0
- package/lib/markdown/createParamsDetails.js +2 -0
- package/lib/markdown/createSchemaDetails.js +6 -1
- package/lib/markdown/createStatusCodes.js +1 -1
- package/lib/markdown/createTermsOfService.d.ts +1 -0
- package/lib/markdown/createTermsOfService.js +32 -0
- package/lib/markdown/index.d.ts +3 -2
- package/lib/markdown/index.js +17 -3
- package/lib/openapi/createExample.js +59 -49
- package/lib/openapi/openapi.d.ts +5 -4
- package/lib/openapi/openapi.js +94 -50
- package/lib/openapi/openapi.test.js +0 -6
- package/lib/openapi/types.d.ts +5 -1
- package/lib/openapi/utils/loadAndBundleSpec.d.ts +3 -0
- package/lib/openapi/utils/loadAndBundleSpec.js +44 -0
- package/lib/openapi/utils/types.d.ts +306 -0
- package/lib/{markdown/createRequestBodyTable.js → openapi/utils/types.js} +0 -6
- package/lib/options.d.ts +0 -2
- package/lib/options.js +36 -7
- package/lib/sidebars/index.d.ts +2 -1
- package/lib/sidebars/index.js +91 -35
- package/lib/sidebars/utils.d.ts +2 -0
- package/lib/sidebars/utils.js +31 -0
- package/lib/types.d.ts +35 -11
- package/package.json +10 -9
- package/src/index.ts +332 -25
- package/src/markdown/createAuthentication.ts +160 -0
- package/src/markdown/createContactInfo.ts +52 -0
- package/src/markdown/createLicense.ts +34 -0
- package/src/markdown/createParamsDetails.ts +2 -0
- package/src/markdown/createSchemaDetails.ts +8 -2
- package/src/markdown/createStatusCodes.ts +1 -1
- package/src/markdown/createTermsOfService.ts +30 -0
- package/src/markdown/index.ts +23 -3
- package/src/openapi/createExample.ts +59 -50
- package/src/openapi/openapi.test.ts +0 -6
- package/src/openapi/openapi.ts +115 -53
- package/src/openapi/types.ts +5 -1
- package/src/openapi/utils/loadAndBundleSpec.ts +62 -0
- package/src/openapi/utils/types.ts +303 -0
- package/src/options.ts +41 -8
- package/src/{markdown/createRequestBodyTable.ts → postman-collection.d.ts} +2 -9
- package/src/sidebars/index.ts +116 -36
- package/src/sidebars/utils.ts +29 -0
- package/src/types.ts +36 -10
- package/lib/markdown/createFullWidthTable.d.ts +0 -2
- package/lib/markdown/createFullWidthTable.js +0 -18
- package/lib/markdown/createParamsTable.d.ts +0 -7
- package/lib/markdown/createParamsTable.js +0 -80
- package/lib/markdown/createRequestBodyTable.d.ts +0 -6
- package/lib/markdown/createSchemaTable.d.ts +0 -14
- package/lib/markdown/createSchemaTable.js +0 -217
- package/src/markdown/createFullWidthTable.ts +0 -16
- package/src/markdown/createParamsTable.ts +0 -102
- package/src/markdown/createSchemaTable.ts +0 -275
- package/src/openapi/__fixtures__/examples/yogurtstore/_category_.json +0 -4
- package/src/openapi/__fixtures__/examples/yogurtstore/froyo.yaml +0 -13
- package/src/openapi/__fixtures__/examples/yogurtstore/nested/nested.yaml +0 -13
package/src/index.ts
CHANGED
|
@@ -13,27 +13,79 @@ import { Globby } from "@docusaurus/utils";
|
|
|
13
13
|
import chalk from "chalk";
|
|
14
14
|
import { render } from "mustache";
|
|
15
15
|
|
|
16
|
-
import { createApiPageMD, createInfoPageMD } from "./markdown";
|
|
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
|
|
|
21
|
-
export
|
|
22
|
+
export function isURL(str: string): boolean {
|
|
23
|
+
return /^(https?:)\/\//m.test(str);
|
|
24
|
+
}
|
|
25
|
+
|
|
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(
|
|
22
62
|
context: LoadContext,
|
|
23
63
|
options: PluginOptions
|
|
24
64
|
): Plugin<LoadedContent> {
|
|
25
|
-
|
|
26
|
-
|
|
65
|
+
const { config, docPluginId } = 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, docPluginId);
|
|
73
|
+
const docRouteBasePath = docData ? docData.routeBasePath : undefined;
|
|
74
|
+
const docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
|
|
27
75
|
|
|
28
76
|
async function generateApiDocs(options: APIOptions) {
|
|
29
77
|
let { specPath, outputDir, template, sidebarOptions } = options;
|
|
30
78
|
|
|
31
|
-
const contentPath =
|
|
79
|
+
const contentPath = isURL(specPath)
|
|
80
|
+
? specPath
|
|
81
|
+
: path.resolve(siteDir, specPath);
|
|
32
82
|
|
|
33
83
|
try {
|
|
34
84
|
const openapiFiles = await readOpenapiFiles(contentPath, {});
|
|
35
|
-
const loadedApi = await processOpenapiFiles(
|
|
36
|
-
|
|
85
|
+
const [loadedApi, tags] = await processOpenapiFiles(
|
|
86
|
+
openapiFiles,
|
|
87
|
+
sidebarOptions!
|
|
88
|
+
);
|
|
37
89
|
if (!fs.existsSync(outputDir)) {
|
|
38
90
|
try {
|
|
39
91
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -49,9 +101,11 @@ export default function pluginOpenAPI(
|
|
|
49
101
|
// TODO: figure out better way to set default
|
|
50
102
|
if (Object.keys(sidebarOptions ?? {}).length > 0) {
|
|
51
103
|
const sidebarSlice = generateSidebarSlice(
|
|
52
|
-
sidebarOptions!,
|
|
104
|
+
sidebarOptions!,
|
|
53
105
|
options,
|
|
54
|
-
loadedApi
|
|
106
|
+
loadedApi,
|
|
107
|
+
tags,
|
|
108
|
+
docPath
|
|
55
109
|
);
|
|
56
110
|
|
|
57
111
|
const sidebarSliceTemplate = template
|
|
@@ -81,7 +135,12 @@ export default function pluginOpenAPI(
|
|
|
81
135
|
? fs.readFileSync(template).toString()
|
|
82
136
|
: `---
|
|
83
137
|
id: {{{id}}}
|
|
138
|
+
{{^api}}
|
|
139
|
+
sidebar_label: Introduction
|
|
140
|
+
{{/api}}
|
|
141
|
+
{{#api}}
|
|
84
142
|
sidebar_label: {{{title}}}
|
|
143
|
+
{{/api}}
|
|
85
144
|
{{^api}}
|
|
86
145
|
sidebar_position: 0
|
|
87
146
|
{{/api}}
|
|
@@ -95,19 +154,73 @@ api: {{{json}}}
|
|
|
95
154
|
{{#api.method}}
|
|
96
155
|
sidebar_class_name: "{{{api.method}}} api-method"
|
|
97
156
|
{{/api.method}}
|
|
157
|
+
{{#infoPath}}
|
|
158
|
+
info_path: {{{infoPath}}}
|
|
159
|
+
{{/infoPath}}
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
{{{markdown}}}
|
|
163
|
+
`;
|
|
164
|
+
|
|
165
|
+
const infoMdTemplate = template
|
|
166
|
+
? fs.readFileSync(template).toString()
|
|
167
|
+
: `---
|
|
168
|
+
id: {{{id}}}
|
|
169
|
+
sidebar_label: {{{title}}}
|
|
170
|
+
hide_title: true
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
{{{markdown}}}
|
|
174
|
+
|
|
175
|
+
\`\`\`mdx-code-block
|
|
176
|
+
import DocCardList from '@theme/DocCardList';
|
|
177
|
+
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
178
|
+
|
|
179
|
+
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
180
|
+
\`\`\`
|
|
181
|
+
`;
|
|
182
|
+
|
|
183
|
+
const tagMdTemplate = template
|
|
184
|
+
? fs.readFileSync(template).toString()
|
|
185
|
+
: `---
|
|
186
|
+
id: {{{id}}}
|
|
187
|
+
title: {{{description}}}
|
|
188
|
+
description: {{{description}}}
|
|
98
189
|
---
|
|
99
190
|
|
|
100
191
|
{{{markdown}}}
|
|
192
|
+
|
|
193
|
+
\`\`\`mdx-code-block
|
|
194
|
+
import DocCardList from '@theme/DocCardList';
|
|
195
|
+
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
196
|
+
|
|
197
|
+
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
198
|
+
\`\`\`
|
|
101
199
|
`;
|
|
102
200
|
|
|
103
201
|
loadedApi.map(async (item) => {
|
|
104
202
|
const markdown =
|
|
105
|
-
item.type === "api"
|
|
203
|
+
item.type === "api"
|
|
204
|
+
? createApiPageMD(item)
|
|
205
|
+
: item.type === "info"
|
|
206
|
+
? createInfoPageMD(item)
|
|
207
|
+
: createTagPageMD(item);
|
|
106
208
|
item.markdown = markdown;
|
|
107
209
|
if (item.type === "api") {
|
|
108
210
|
item.json = JSON.stringify(item.api);
|
|
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;
|
|
109
218
|
}
|
|
219
|
+
|
|
110
220
|
const view = render(mdTemplate, item);
|
|
221
|
+
const utils = render(infoMdTemplate, item);
|
|
222
|
+
// eslint-disable-next-line testing-library/render-result-naming-convention
|
|
223
|
+
const tagUtils = render(tagMdTemplate, item);
|
|
111
224
|
|
|
112
225
|
if (item.type === "api") {
|
|
113
226
|
if (!fs.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
|
|
@@ -129,15 +242,49 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
129
242
|
|
|
130
243
|
// TODO: determine if we actually want/need this
|
|
131
244
|
if (item.type === "info") {
|
|
132
|
-
if (!fs.existsSync(`${outputDir}
|
|
245
|
+
if (!fs.existsSync(`${outputDir}/${item.id}.info.mdx`)) {
|
|
246
|
+
try {
|
|
247
|
+
sidebarOptions?.categoryLinkSource === "info" // Only use utils template if set to "info"
|
|
248
|
+
? fs.writeFileSync(
|
|
249
|
+
`${outputDir}/${item.id}.info.mdx`,
|
|
250
|
+
utils,
|
|
251
|
+
"utf8"
|
|
252
|
+
)
|
|
253
|
+
: fs.writeFileSync(
|
|
254
|
+
`${outputDir}/${item.id}.info.mdx`,
|
|
255
|
+
view,
|
|
256
|
+
"utf8"
|
|
257
|
+
);
|
|
258
|
+
console.log(
|
|
259
|
+
chalk.green(
|
|
260
|
+
`Successfully created "${outputDir}/${item.id}.info.mdx"`
|
|
261
|
+
)
|
|
262
|
+
);
|
|
263
|
+
} catch (err) {
|
|
264
|
+
console.error(
|
|
265
|
+
chalk.red(`Failed to write "${outputDir}/${item.id}.info.mdx"`),
|
|
266
|
+
chalk.yellow(err)
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
if (item.type === "tag") {
|
|
273
|
+
if (!fs.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
|
|
133
274
|
try {
|
|
134
|
-
fs.writeFileSync(
|
|
275
|
+
fs.writeFileSync(
|
|
276
|
+
`${outputDir}/${item.id}.tag.mdx`,
|
|
277
|
+
tagUtils,
|
|
278
|
+
"utf8"
|
|
279
|
+
);
|
|
135
280
|
console.log(
|
|
136
|
-
chalk.green(
|
|
281
|
+
chalk.green(
|
|
282
|
+
`Successfully created "${outputDir}/${item.id}.tag.mdx"`
|
|
283
|
+
)
|
|
137
284
|
);
|
|
138
285
|
} catch (err) {
|
|
139
286
|
console.error(
|
|
140
|
-
chalk.red(`Failed to write "${outputDir}
|
|
287
|
+
chalk.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`),
|
|
141
288
|
chalk.yellow(err)
|
|
142
289
|
);
|
|
143
290
|
}
|
|
@@ -145,6 +292,7 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
145
292
|
}
|
|
146
293
|
return;
|
|
147
294
|
});
|
|
295
|
+
|
|
148
296
|
return;
|
|
149
297
|
} catch (e) {
|
|
150
298
|
console.error(chalk.red(`Loading of api failed for "${contentPath}"`));
|
|
@@ -155,11 +303,13 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
155
303
|
async function cleanApiDocs(options: APIOptions) {
|
|
156
304
|
const { outputDir } = options;
|
|
157
305
|
const apiDir = path.join(siteDir, outputDir);
|
|
158
|
-
const apiMdxFiles = await Globby(["*.api.mdx"], {
|
|
306
|
+
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
159
307
|
cwd: path.resolve(apiDir),
|
|
308
|
+
deep: 1,
|
|
160
309
|
});
|
|
161
310
|
const sidebarFile = await Globby(["sidebar.js"], {
|
|
162
311
|
cwd: path.resolve(apiDir),
|
|
312
|
+
deep: 1,
|
|
163
313
|
});
|
|
164
314
|
apiMdxFiles.map((mdx) =>
|
|
165
315
|
fs.unlink(`${apiDir}/${mdx}`, (err) => {
|
|
@@ -190,21 +340,66 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
190
340
|
);
|
|
191
341
|
}
|
|
192
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
|
+
|
|
193
384
|
return {
|
|
194
|
-
name: `docusaurus-plugin-openapi`,
|
|
385
|
+
name: `docusaurus-plugin-openapi-docs`,
|
|
195
386
|
|
|
196
387
|
extendCli(cli): void {
|
|
197
388
|
cli
|
|
198
389
|
.command(`gen-api-docs`)
|
|
199
|
-
.description(
|
|
200
|
-
|
|
201
|
-
"[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).`
|
|
202
392
|
)
|
|
393
|
+
.usage("<id>")
|
|
203
394
|
.arguments("<id>")
|
|
204
395
|
.action(async (id) => {
|
|
205
396
|
if (id === "all") {
|
|
206
397
|
if (config[id]) {
|
|
207
|
-
console.error(
|
|
398
|
+
console.error(
|
|
399
|
+
chalk.red(
|
|
400
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
401
|
+
)
|
|
402
|
+
);
|
|
208
403
|
} else {
|
|
209
404
|
Object.keys(config).forEach(async function (key) {
|
|
210
405
|
await generateApiDocs(config[key]);
|
|
@@ -212,24 +407,91 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
212
407
|
}
|
|
213
408
|
} else if (!config[id]) {
|
|
214
409
|
console.error(
|
|
215
|
-
chalk.red(`ID ${id} does not exist in
|
|
410
|
+
chalk.red(`ID '${id}' does not exist in OpenAPI docs config.`)
|
|
216
411
|
);
|
|
217
412
|
} else {
|
|
218
413
|
await generateApiDocs(config[id]);
|
|
219
414
|
}
|
|
220
415
|
});
|
|
221
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
|
+
|
|
222
480
|
cli
|
|
223
481
|
.command(`clean-api-docs`)
|
|
224
|
-
.description(
|
|
225
|
-
|
|
226
|
-
"[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).`
|
|
227
484
|
)
|
|
485
|
+
.usage("<id>")
|
|
228
486
|
.arguments("<id>")
|
|
229
487
|
.action(async (id) => {
|
|
230
488
|
if (id === "all") {
|
|
231
489
|
if (config[id]) {
|
|
232
|
-
console.error(
|
|
490
|
+
console.error(
|
|
491
|
+
chalk.red(
|
|
492
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
493
|
+
)
|
|
494
|
+
);
|
|
233
495
|
} else {
|
|
234
496
|
Object.keys(config).forEach(async function (key) {
|
|
235
497
|
await cleanApiDocs(config[key]);
|
|
@@ -239,6 +501,51 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
239
501
|
await cleanApiDocs(config[id]);
|
|
240
502
|
}
|
|
241
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
|
+
});
|
|
242
544
|
},
|
|
243
545
|
};
|
|
244
546
|
}
|
|
547
|
+
|
|
548
|
+
pluginOpenAPIDocs.validateOptions = ({ options, validate }: any) => {
|
|
549
|
+
const validatedOptions = validate(OptionsSchema, options);
|
|
550
|
+
return validatedOptions;
|
|
551
|
+
};
|
|
@@ -0,0 +1,160 @@
|
|
|
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 { OAuthFlowObject, SecuritySchemeObject } from "../openapi/types";
|
|
9
|
+
import { createDescription } from "./createDescription";
|
|
10
|
+
import { create, guard } from "./utils";
|
|
11
|
+
|
|
12
|
+
export function createAuthentication(securitySchemes: SecuritySchemeObject) {
|
|
13
|
+
if (!securitySchemes || !Object.keys(securitySchemes).length) return "";
|
|
14
|
+
|
|
15
|
+
const createAuthenticationTable = (securityScheme: any) => {
|
|
16
|
+
const { bearerFormat, flows, name, scheme, type } = securityScheme;
|
|
17
|
+
|
|
18
|
+
const createSecuritySchemeTypeRow = () =>
|
|
19
|
+
create("tr", {
|
|
20
|
+
children: [
|
|
21
|
+
create("th", { children: "Security Scheme Type:" }),
|
|
22
|
+
create("td", { children: type }),
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const createOAuthFlowRows = () => {
|
|
27
|
+
const flowRows = Object.entries(flows).map(([flowType, flowObj]) => {
|
|
28
|
+
const { authorizationUrl, tokenUrl, refreshUrl, scopes } =
|
|
29
|
+
flowObj as OAuthFlowObject;
|
|
30
|
+
|
|
31
|
+
return create("tr", {
|
|
32
|
+
children: [
|
|
33
|
+
create("th", { children: `${flowType} OAuth Flow:` }),
|
|
34
|
+
create("td", {
|
|
35
|
+
children: [
|
|
36
|
+
guard(tokenUrl, () =>
|
|
37
|
+
create("p", { children: `Token URL: ${tokenUrl}` })
|
|
38
|
+
),
|
|
39
|
+
guard(authorizationUrl, () =>
|
|
40
|
+
create("p", {
|
|
41
|
+
children: `Authorization URL: ${authorizationUrl}`,
|
|
42
|
+
})
|
|
43
|
+
),
|
|
44
|
+
guard(refreshUrl, () =>
|
|
45
|
+
create("p", { children: `Refresh URL: ${refreshUrl}` })
|
|
46
|
+
),
|
|
47
|
+
create("span", { children: "Scopes:" }),
|
|
48
|
+
create("ul", {
|
|
49
|
+
children: Object.entries(scopes).map(([scope, description]) =>
|
|
50
|
+
create("li", { children: `${scope}: ${description}` })
|
|
51
|
+
),
|
|
52
|
+
}),
|
|
53
|
+
],
|
|
54
|
+
}),
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return flowRows.join("");
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
switch (type) {
|
|
63
|
+
case "apiKey":
|
|
64
|
+
return create("div", {
|
|
65
|
+
children: [
|
|
66
|
+
create("table", {
|
|
67
|
+
children: create("tbody", {
|
|
68
|
+
children: [
|
|
69
|
+
createSecuritySchemeTypeRow(),
|
|
70
|
+
create("tr", {
|
|
71
|
+
children: [
|
|
72
|
+
create("th", { children: "Header parameter name:" }),
|
|
73
|
+
create("td", { children: name }),
|
|
74
|
+
],
|
|
75
|
+
}),
|
|
76
|
+
],
|
|
77
|
+
}),
|
|
78
|
+
}),
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
case "http":
|
|
82
|
+
return create("div", {
|
|
83
|
+
children: [
|
|
84
|
+
create("table", {
|
|
85
|
+
children: create("tbody", {
|
|
86
|
+
children: [
|
|
87
|
+
createSecuritySchemeTypeRow(),
|
|
88
|
+
create("tr", {
|
|
89
|
+
children: [
|
|
90
|
+
create("th", { children: "HTTP Authorization Scheme:" }),
|
|
91
|
+
create("td", { children: scheme }),
|
|
92
|
+
],
|
|
93
|
+
}),
|
|
94
|
+
create("tr", {
|
|
95
|
+
children: [
|
|
96
|
+
create("th", { children: "Bearer format:" }),
|
|
97
|
+
create("td", { children: bearerFormat }),
|
|
98
|
+
],
|
|
99
|
+
}),
|
|
100
|
+
],
|
|
101
|
+
}),
|
|
102
|
+
}),
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
case "oauth2":
|
|
106
|
+
return create("div", {
|
|
107
|
+
children: [
|
|
108
|
+
create("table", {
|
|
109
|
+
children: create("tbody", {
|
|
110
|
+
children: [
|
|
111
|
+
createSecuritySchemeTypeRow(),
|
|
112
|
+
createOAuthFlowRows(),
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
115
|
+
}),
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
default:
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const formatTabLabel = (str: string) => {
|
|
124
|
+
const formattedLabel = str
|
|
125
|
+
.replace(/(_|-)/g, " ")
|
|
126
|
+
.trim()
|
|
127
|
+
.replace(/\w\S*/g, (str) => str.charAt(0).toUpperCase() + str.substr(1))
|
|
128
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
129
|
+
.replace(/([A-Z])([A-Z][a-z])/g, "$1 $2");
|
|
130
|
+
|
|
131
|
+
const isOAuth = formattedLabel.toLowerCase().includes("oauth2");
|
|
132
|
+
const isApiKey = formattedLabel.toLowerCase().includes("api");
|
|
133
|
+
|
|
134
|
+
return isOAuth ? "OAuth 2.0" : isApiKey ? "API Key" : formattedLabel;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return create("div", {
|
|
138
|
+
children: [
|
|
139
|
+
create("h2", {
|
|
140
|
+
children: "Authentication",
|
|
141
|
+
id: "authentication",
|
|
142
|
+
style: { marginBottom: "1rem" },
|
|
143
|
+
}),
|
|
144
|
+
create("Tabs", {
|
|
145
|
+
children: Object.entries(securitySchemes).map(
|
|
146
|
+
([schemeType, schemeObj]) =>
|
|
147
|
+
create("TabItem", {
|
|
148
|
+
label: formatTabLabel(schemeType),
|
|
149
|
+
value: `${schemeType}`,
|
|
150
|
+
children: [
|
|
151
|
+
createDescription(schemeObj.description),
|
|
152
|
+
createAuthenticationTable(schemeObj),
|
|
153
|
+
],
|
|
154
|
+
})
|
|
155
|
+
),
|
|
156
|
+
}),
|
|
157
|
+
],
|
|
158
|
+
style: { marginBottom: "2rem" },
|
|
159
|
+
});
|
|
160
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
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 { ContactObject } from "../openapi/types";
|
|
9
|
+
import { create, guard } from "./utils";
|
|
10
|
+
|
|
11
|
+
export function createContactInfo(contact: ContactObject) {
|
|
12
|
+
if (!contact || !Object.keys(contact).length) return "";
|
|
13
|
+
const { name, url, email } = contact;
|
|
14
|
+
|
|
15
|
+
return create("div", {
|
|
16
|
+
style: {
|
|
17
|
+
display: "flex",
|
|
18
|
+
flexDirection: "column",
|
|
19
|
+
marginBottom: "var(--ifm-paragraph-margin-bottom)",
|
|
20
|
+
},
|
|
21
|
+
children: [
|
|
22
|
+
create("h3", {
|
|
23
|
+
style: {
|
|
24
|
+
marginBottom: "0.25rem",
|
|
25
|
+
},
|
|
26
|
+
children: "Contact",
|
|
27
|
+
}),
|
|
28
|
+
create("span", {
|
|
29
|
+
children: [
|
|
30
|
+
guard(name, () => `${name}: `),
|
|
31
|
+
guard(email, () =>
|
|
32
|
+
create("a", {
|
|
33
|
+
href: `mailto:${email}`,
|
|
34
|
+
children: `${email}`,
|
|
35
|
+
})
|
|
36
|
+
),
|
|
37
|
+
],
|
|
38
|
+
}),
|
|
39
|
+
guard(url, () =>
|
|
40
|
+
create("span", {
|
|
41
|
+
children: [
|
|
42
|
+
"URL: ",
|
|
43
|
+
create("a", {
|
|
44
|
+
href: `${url}`,
|
|
45
|
+
children: `${url}`,
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
),
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
}
|