docusaurus-plugin-openapi-docs 1.0.2 → 1.0.5
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 +106 -17
- package/lib/index.d.ts +7 -1
- package/lib/index.js +228 -18
- package/lib/markdown/createAuthentication.d.ts +2 -0
- package/lib/markdown/createAuthentication.js +139 -0
- package/lib/markdown/createParamsDetails.js +2 -0
- package/lib/markdown/createSchemaDetails.js +2 -0
- package/lib/markdown/index.d.ts +3 -2
- package/lib/markdown/index.js +10 -2
- package/lib/openapi/createExample.js +59 -49
- package/lib/openapi/openapi.d.ts +3 -3
- package/lib/openapi/openapi.js +71 -41
- package/lib/openapi/openapi.test.js +0 -6
- 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/openapi/utils/types.js +8 -0
- 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 +33 -30
- package/lib/sidebars/utils.d.ts +2 -0
- package/lib/sidebars/utils.js +31 -0
- package/lib/types.d.ts +34 -11
- package/package.json +10 -8
- package/src/index.ts +291 -20
- package/src/markdown/createAuthentication.ts +160 -0
- package/src/markdown/createParamsDetails.ts +2 -0
- package/src/markdown/createSchemaDetails.ts +2 -0
- package/src/markdown/index.ts +15 -2
- package/src/openapi/createExample.ts +59 -50
- package/src/openapi/openapi.test.ts +0 -6
- package/src/openapi/openapi.ts +85 -39
- package/src/openapi/utils/loadAndBundleSpec.ts +62 -0
- package/src/openapi/utils/types.ts +303 -0
- package/src/options.ts +41 -8
- package/src/sidebars/index.ts +40 -30
- package/src/sidebars/utils.ts +29 -0
- package/src/types.ts +35 -9
- 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,26 +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, tags] = await processOpenapiFiles(
|
|
85
|
+
const [loadedApi, tags] = await processOpenapiFiles(
|
|
86
|
+
openapiFiles,
|
|
87
|
+
sidebarOptions!
|
|
88
|
+
);
|
|
36
89
|
if (!fs.existsSync(outputDir)) {
|
|
37
90
|
try {
|
|
38
91
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -48,10 +101,11 @@ export default function pluginOpenAPI(
|
|
|
48
101
|
// TODO: figure out better way to set default
|
|
49
102
|
if (Object.keys(sidebarOptions ?? {}).length > 0) {
|
|
50
103
|
const sidebarSlice = generateSidebarSlice(
|
|
51
|
-
sidebarOptions!,
|
|
104
|
+
sidebarOptions!,
|
|
52
105
|
options,
|
|
53
106
|
loadedApi,
|
|
54
|
-
tags
|
|
107
|
+
tags,
|
|
108
|
+
docPath
|
|
55
109
|
);
|
|
56
110
|
|
|
57
111
|
const sidebarSliceTemplate = template
|
|
@@ -100,6 +154,9 @@ api: {{{json}}}
|
|
|
100
154
|
{{#api.method}}
|
|
101
155
|
sidebar_class_name: "{{{api.method}}} api-method"
|
|
102
156
|
{{/api.method}}
|
|
157
|
+
{{#infoPath}}
|
|
158
|
+
info_path: {{{infoPath}}}
|
|
159
|
+
{{/infoPath}}
|
|
103
160
|
---
|
|
104
161
|
|
|
105
162
|
{{{markdown}}}
|
|
@@ -119,19 +176,51 @@ hide_title: true
|
|
|
119
176
|
import DocCardList from '@theme/DocCardList';
|
|
120
177
|
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
121
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}}}
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
{{{markdown}}}
|
|
192
|
+
|
|
193
|
+
\`\`\`mdx-code-block
|
|
194
|
+
import DocCardList from '@theme/DocCardList';
|
|
195
|
+
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
196
|
+
|
|
122
197
|
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
123
198
|
\`\`\`
|
|
124
199
|
`;
|
|
125
200
|
|
|
126
201
|
loadedApi.map(async (item) => {
|
|
127
202
|
const markdown =
|
|
128
|
-
item.type === "api"
|
|
203
|
+
item.type === "api"
|
|
204
|
+
? createApiPageMD(item)
|
|
205
|
+
: item.type === "info"
|
|
206
|
+
? createInfoPageMD(item)
|
|
207
|
+
: createTagPageMD(item);
|
|
129
208
|
item.markdown = markdown;
|
|
130
209
|
if (item.type === "api") {
|
|
131
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;
|
|
132
218
|
}
|
|
219
|
+
|
|
133
220
|
const view = render(mdTemplate, item);
|
|
134
221
|
const utils = render(infoMdTemplate, item);
|
|
222
|
+
// eslint-disable-next-line testing-library/render-result-naming-convention
|
|
223
|
+
const tagUtils = render(tagMdTemplate, item);
|
|
135
224
|
|
|
136
225
|
if (item.type === "api") {
|
|
137
226
|
if (!fs.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
|
|
@@ -179,8 +268,31 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
179
268
|
}
|
|
180
269
|
}
|
|
181
270
|
}
|
|
271
|
+
|
|
272
|
+
if (item.type === "tag") {
|
|
273
|
+
if (!fs.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
|
|
274
|
+
try {
|
|
275
|
+
fs.writeFileSync(
|
|
276
|
+
`${outputDir}/${item.id}.tag.mdx`,
|
|
277
|
+
tagUtils,
|
|
278
|
+
"utf8"
|
|
279
|
+
);
|
|
280
|
+
console.log(
|
|
281
|
+
chalk.green(
|
|
282
|
+
`Successfully created "${outputDir}/${item.id}.tag.mdx"`
|
|
283
|
+
)
|
|
284
|
+
);
|
|
285
|
+
} catch (err) {
|
|
286
|
+
console.error(
|
|
287
|
+
chalk.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`),
|
|
288
|
+
chalk.yellow(err)
|
|
289
|
+
);
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
}
|
|
182
293
|
return;
|
|
183
294
|
});
|
|
295
|
+
|
|
184
296
|
return;
|
|
185
297
|
} catch (e) {
|
|
186
298
|
console.error(chalk.red(`Loading of api failed for "${contentPath}"`));
|
|
@@ -191,11 +303,13 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
191
303
|
async function cleanApiDocs(options: APIOptions) {
|
|
192
304
|
const { outputDir } = options;
|
|
193
305
|
const apiDir = path.join(siteDir, outputDir);
|
|
194
|
-
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx"], {
|
|
306
|
+
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
195
307
|
cwd: path.resolve(apiDir),
|
|
308
|
+
deep: 1,
|
|
196
309
|
});
|
|
197
310
|
const sidebarFile = await Globby(["sidebar.js"], {
|
|
198
311
|
cwd: path.resolve(apiDir),
|
|
312
|
+
deep: 1,
|
|
199
313
|
});
|
|
200
314
|
apiMdxFiles.map((mdx) =>
|
|
201
315
|
fs.unlink(`${apiDir}/${mdx}`, (err) => {
|
|
@@ -226,21 +340,66 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
226
340
|
);
|
|
227
341
|
}
|
|
228
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
|
+
|
|
229
384
|
return {
|
|
230
|
-
name: `docusaurus-plugin-openapi`,
|
|
385
|
+
name: `docusaurus-plugin-openapi-docs`,
|
|
231
386
|
|
|
232
387
|
extendCli(cli): void {
|
|
233
388
|
cli
|
|
234
389
|
.command(`gen-api-docs`)
|
|
235
|
-
.description(
|
|
236
|
-
|
|
237
|
-
"[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).`
|
|
238
392
|
)
|
|
393
|
+
.usage("<id>")
|
|
239
394
|
.arguments("<id>")
|
|
240
395
|
.action(async (id) => {
|
|
241
396
|
if (id === "all") {
|
|
242
397
|
if (config[id]) {
|
|
243
|
-
console.error(
|
|
398
|
+
console.error(
|
|
399
|
+
chalk.red(
|
|
400
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
401
|
+
)
|
|
402
|
+
);
|
|
244
403
|
} else {
|
|
245
404
|
Object.keys(config).forEach(async function (key) {
|
|
246
405
|
await generateApiDocs(config[key]);
|
|
@@ -248,24 +407,91 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
248
407
|
}
|
|
249
408
|
} else if (!config[id]) {
|
|
250
409
|
console.error(
|
|
251
|
-
chalk.red(`ID ${id} does not exist in
|
|
410
|
+
chalk.red(`ID '${id}' does not exist in OpenAPI docs config.`)
|
|
252
411
|
);
|
|
253
412
|
} else {
|
|
254
413
|
await generateApiDocs(config[id]);
|
|
255
414
|
}
|
|
256
415
|
});
|
|
257
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
|
+
|
|
258
480
|
cli
|
|
259
481
|
.command(`clean-api-docs`)
|
|
260
|
-
.description(
|
|
261
|
-
|
|
262
|
-
"[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).`
|
|
263
484
|
)
|
|
485
|
+
.usage("<id>")
|
|
264
486
|
.arguments("<id>")
|
|
265
487
|
.action(async (id) => {
|
|
266
488
|
if (id === "all") {
|
|
267
489
|
if (config[id]) {
|
|
268
|
-
console.error(
|
|
490
|
+
console.error(
|
|
491
|
+
chalk.red(
|
|
492
|
+
"Can't use id 'all' for OpenAPI docs configuration key."
|
|
493
|
+
)
|
|
494
|
+
);
|
|
269
495
|
} else {
|
|
270
496
|
Object.keys(config).forEach(async function (key) {
|
|
271
497
|
await cleanApiDocs(config[key]);
|
|
@@ -275,6 +501,51 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
275
501
|
await cleanApiDocs(config[id]);
|
|
276
502
|
}
|
|
277
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
|
+
});
|
|
278
544
|
},
|
|
279
545
|
};
|
|
280
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
|
+
}
|
package/src/markdown/index.ts
CHANGED
|
@@ -7,8 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
import { escape } from "lodash";
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
ContactObject,
|
|
12
|
+
LicenseObject,
|
|
13
|
+
SecuritySchemeObject,
|
|
14
|
+
} from "../openapi/types";
|
|
15
|
+
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
|
|
16
|
+
import { createAuthentication } from "./createAuthentication";
|
|
12
17
|
import { createContactInfo } from "./createContactInfo";
|
|
13
18
|
import { createDeprecationNotice } from "./createDeprecationNotice";
|
|
14
19
|
import { createDescription } from "./createDescription";
|
|
@@ -50,13 +55,21 @@ export function createApiPageMD({
|
|
|
50
55
|
|
|
51
56
|
export function createInfoPageMD({
|
|
52
57
|
info: { title, version, description, contact, license, termsOfService },
|
|
58
|
+
securitySchemes,
|
|
53
59
|
}: InfoPageMetadata) {
|
|
54
60
|
return render([
|
|
61
|
+
`import Tabs from "@theme/Tabs";\n`,
|
|
62
|
+
`import TabItem from "@theme/TabItem";\n\n`,
|
|
55
63
|
createVersionBadge(version),
|
|
56
64
|
`# ${escape(title)}\n\n`,
|
|
57
65
|
createDescription(description),
|
|
66
|
+
createAuthentication(securitySchemes as unknown as SecuritySchemeObject),
|
|
58
67
|
createContactInfo(contact as ContactObject),
|
|
59
68
|
createTermsOfService(termsOfService),
|
|
60
69
|
createLicense(license as LicenseObject),
|
|
61
70
|
]);
|
|
62
71
|
}
|
|
72
|
+
|
|
73
|
+
export function createTagPageMD({ tag: { description } }: TagPageMetadata) {
|
|
74
|
+
return render([createDescription(description)]);
|
|
75
|
+
}
|