docusaurus-plugin-openapi-docs 0.0.0-698 → 0.0.0-700
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 +1 -0
- package/lib/index.js +61 -8
- package/lib/markdown/index.d.ts +2 -1
- package/lib/markdown/index.js +17 -1
- package/lib/openapi/openapi.d.ts +3 -3
- package/lib/openapi/openapi.js +59 -6
- package/lib/openapi/openapi.test.js +2 -0
- package/lib/openapi/types.d.ts +5 -0
- package/lib/options.js +2 -1
- package/lib/sidebars/index.d.ts +2 -2
- package/lib/sidebars/index.js +50 -10
- package/lib/types.d.ts +15 -2
- package/package.json +2 -2
- package/src/index.ts +113 -10
- package/src/markdown/index.ts +23 -2
- package/src/openapi/__fixtures__/examples/openapi.yaml +29 -0
- package/src/openapi/openapi.test.ts +3 -0
- package/src/openapi/openapi.ts +75 -7
- package/src/openapi/types.ts +6 -0
- package/src/options.ts +2 -1
- package/src/sidebars/index.ts +71 -16
- package/src/types.ts +21 -1
package/README.md
CHANGED
|
@@ -159,6 +159,7 @@ The `docusaurus-plugin-openapi-docs` plugin can be configured with the following
|
|
|
159
159
|
| `baseUrl` | `string` | `null` | _Optional:_ Version base URL used when generating version selector dropdown menu. |
|
|
160
160
|
| `versions` | `object` | `null` | _Optional:_ Set of options for versioning configuration. See below for a list of supported options. |
|
|
161
161
|
| `markdownGenerators` | `object` | `null` | _Optional:_ Customize MDX content with a set of options for specifying markdown generator functions. See below for a list of supported options. |
|
|
162
|
+
| `showSchemas` | `boolean` | `null` | _Optional:_ If set to `true`, generates schema pages and adds them to the sidebar. |
|
|
162
163
|
|
|
163
164
|
`sidebarOptions` can be configured with the following options:
|
|
164
165
|
|
package/lib/index.js
CHANGED
|
@@ -77,7 +77,7 @@ function pluginOpenAPIDocs(context, options) {
|
|
|
77
77
|
let docRouteBasePath = docData ? docData.routeBasePath : undefined;
|
|
78
78
|
let docPath = docData ? (docData.path ? docData.path : "docs") : undefined;
|
|
79
79
|
async function generateApiDocs(options, pluginId) {
|
|
80
|
-
var _a, _b, _c;
|
|
80
|
+
var _a, _b, _c, _d;
|
|
81
81
|
let { specPath, outputDir, template, markdownGenerators, downloadUrl, sidebarOptions, } = options;
|
|
82
82
|
// Remove trailing slash before proceeding
|
|
83
83
|
outputDir = outputDir.replace(/\/$/, "");
|
|
@@ -92,7 +92,7 @@ function pluginOpenAPIDocs(context, options) {
|
|
|
92
92
|
: path_1.default.resolve(siteDir, specPath);
|
|
93
93
|
try {
|
|
94
94
|
const openapiFiles = await (0, openapi_1.readOpenapiFiles)(contentPath);
|
|
95
|
-
const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles, options, sidebarOptions);
|
|
95
|
+
const [loadedApi, tags, tagGroups] = await (0, openapi_1.processOpenapiFiles)(openapiFiles, options, sidebarOptions);
|
|
96
96
|
if (!fs_1.default.existsSync(outputDir)) {
|
|
97
97
|
try {
|
|
98
98
|
fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
@@ -104,7 +104,7 @@ function pluginOpenAPIDocs(context, options) {
|
|
|
104
104
|
}
|
|
105
105
|
// TODO: figure out better way to set default
|
|
106
106
|
if (Object.keys(sidebarOptions !== null && sidebarOptions !== void 0 ? sidebarOptions : {}).length > 0) {
|
|
107
|
-
const sidebarSlice = (0, sidebars_1.default)(sidebarOptions, options, loadedApi, tags, docPath);
|
|
107
|
+
const sidebarSlice = (0, sidebars_1.default)(sidebarOptions, options, loadedApi, tags, docPath, tagGroups);
|
|
108
108
|
const sidebarSliceTemplate = `module.exports = {{{slice}}};`;
|
|
109
109
|
const view = (0, mustache_1.render)(sidebarSliceTemplate, {
|
|
110
110
|
slice: JSON.stringify(sidebarSlice),
|
|
@@ -195,20 +195,35 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
195
195
|
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
196
196
|
\`\`\`
|
|
197
197
|
`;
|
|
198
|
+
const schemaMdTemplate = `---
|
|
199
|
+
id: {{{id}}}
|
|
200
|
+
title: "{{{title}}}"
|
|
201
|
+
description: "{{{frontMatter.description}}}"
|
|
202
|
+
sidebar_label: "{{{title}}}"
|
|
203
|
+
hide_title: true
|
|
204
|
+
schema: true
|
|
205
|
+
custom_edit_url: null
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
{{{markdown}}}
|
|
209
|
+
`;
|
|
198
210
|
const apiPageGenerator = (_a = markdownGenerators === null || markdownGenerators === void 0 ? void 0 : markdownGenerators.createApiPageMD) !== null && _a !== void 0 ? _a : markdown_1.createApiPageMD;
|
|
199
211
|
const infoPageGenerator = (_b = markdownGenerators === null || markdownGenerators === void 0 ? void 0 : markdownGenerators.createInfoPageMD) !== null && _b !== void 0 ? _b : markdown_1.createInfoPageMD;
|
|
200
212
|
const tagPageGenerator = (_c = markdownGenerators === null || markdownGenerators === void 0 ? void 0 : markdownGenerators.createTagPageMD) !== null && _c !== void 0 ? _c : markdown_1.createTagPageMD;
|
|
213
|
+
const schemaPageGenerator = (_d = markdownGenerators === null || markdownGenerators === void 0 ? void 0 : markdownGenerators.createSchemaPageMD) !== null && _d !== void 0 ? _d : markdown_1.createSchemaPageMD;
|
|
214
|
+
const pageGeneratorByType = {
|
|
215
|
+
api: apiPageGenerator,
|
|
216
|
+
info: infoPageGenerator,
|
|
217
|
+
tag: tagPageGenerator,
|
|
218
|
+
schema: schemaPageGenerator,
|
|
219
|
+
};
|
|
201
220
|
loadedApi.map(async (item) => {
|
|
202
221
|
if (item.type === "info") {
|
|
203
222
|
if (downloadUrl && isURL(downloadUrl)) {
|
|
204
223
|
item.downloadUrl = downloadUrl;
|
|
205
224
|
}
|
|
206
225
|
}
|
|
207
|
-
const markdown = item.type
|
|
208
|
-
? apiPageGenerator(item)
|
|
209
|
-
: item.type === "info"
|
|
210
|
-
? infoPageGenerator(item)
|
|
211
|
-
: tagPageGenerator(item);
|
|
226
|
+
const markdown = pageGeneratorByType[item.type](item);
|
|
212
227
|
item.markdown = markdown;
|
|
213
228
|
if (item.type === "api") {
|
|
214
229
|
// opportunity to compress JSON
|
|
@@ -274,6 +289,32 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
274
289
|
}
|
|
275
290
|
}
|
|
276
291
|
}
|
|
292
|
+
if (item.type === "schema") {
|
|
293
|
+
if (!fs_1.default.existsSync(`${outputDir}/schemas/${item.id}.schema.mdx`)) {
|
|
294
|
+
if (!fs_1.default.existsSync(`${outputDir}/schemas`)) {
|
|
295
|
+
try {
|
|
296
|
+
fs_1.default.mkdirSync(`${outputDir}/schemas`, { recursive: true });
|
|
297
|
+
console.log(chalk_1.default.green(`Successfully created "${outputDir}/schemas"`));
|
|
298
|
+
}
|
|
299
|
+
catch (err) {
|
|
300
|
+
console.error(chalk_1.default.red(`Failed to create "${outputDir}/schemas"`), chalk_1.default.yellow(err));
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
try {
|
|
304
|
+
// kebabCase(arg) returns 0-length string when arg is undefined
|
|
305
|
+
if (item.id.length === 0) {
|
|
306
|
+
throw Error("Schema must have title defined");
|
|
307
|
+
}
|
|
308
|
+
// eslint-disable-next-line testing-library/render-result-naming-convention
|
|
309
|
+
const schemaView = (0, mustache_1.render)(schemaMdTemplate, item);
|
|
310
|
+
fs_1.default.writeFileSync(`${outputDir}/schemas/${item.id}.schema.mdx`, schemaView, "utf8");
|
|
311
|
+
console.log(chalk_1.default.green(`Successfully created "${outputDir}/${item.id}.schema.mdx"`));
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
console.error(chalk_1.default.red(`Failed to write "${outputDir}/${item.id}.schema.mdx"`), chalk_1.default.yellow(err));
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
277
318
|
return;
|
|
278
319
|
});
|
|
279
320
|
return;
|
|
@@ -290,6 +331,10 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
290
331
|
cwd: path_1.default.resolve(apiDir),
|
|
291
332
|
deep: 1,
|
|
292
333
|
});
|
|
334
|
+
const schemaMdxFiles = await (0, utils_1.Globby)(["*.schema.mdx"], {
|
|
335
|
+
cwd: path_1.default.resolve(apiDir, "schemas"),
|
|
336
|
+
deep: 1,
|
|
337
|
+
});
|
|
293
338
|
const sidebarFile = await (0, utils_1.Globby)(["sidebar.js"], {
|
|
294
339
|
cwd: path_1.default.resolve(apiDir),
|
|
295
340
|
deep: 1,
|
|
@@ -302,6 +347,14 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
302
347
|
console.log(chalk_1.default.green(`Cleanup succeeded for "${apiDir}/${mdx}"`));
|
|
303
348
|
}
|
|
304
349
|
}));
|
|
350
|
+
schemaMdxFiles.map((mdx) => fs_1.default.unlink(`${apiDir}/schemas/${mdx}`, (err) => {
|
|
351
|
+
if (err) {
|
|
352
|
+
console.error(chalk_1.default.red(`Cleanup failed for "${apiDir}/schemas/${mdx}"`), chalk_1.default.yellow(err));
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
console.log(chalk_1.default.green(`Cleanup succeeded for "${apiDir}/schemas/${mdx}"`));
|
|
356
|
+
}
|
|
357
|
+
}));
|
|
305
358
|
sidebarFile.map((sidebar) => fs_1.default.unlink(`${apiDir}/${sidebar}`, (err) => {
|
|
306
359
|
if (err) {
|
|
307
360
|
console.error(chalk_1.default.red(`Cleanup failed for "${apiDir}/${sidebar}"`), chalk_1.default.yellow(err));
|
package/lib/markdown/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
|
|
1
|
+
import { ApiPageMetadata, InfoPageMetadata, SchemaPageMetadata, TagPageMetadata } from "../types";
|
|
2
2
|
export declare function createApiPageMD({ title, api: { deprecated, "x-deprecated-description": deprecatedDescription, description, method, path, extensions, parameters, requestBody, responses, callbacks, }, infoPath, frontMatter, }: ApiPageMetadata): string;
|
|
3
3
|
export declare function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService, logo, darkLogo, }, securitySchemes, downloadUrl, }: InfoPageMetadata): string;
|
|
4
4
|
export declare function createTagPageMD({ tag: { description } }: TagPageMetadata): string;
|
|
5
|
+
export declare function createSchemaPageMD({ schema }: SchemaPageMetadata): string;
|
package/lib/markdown/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
* ========================================================================== */
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.createTagPageMD = exports.createInfoPageMD = exports.createApiPageMD = void 0;
|
|
9
|
+
exports.createSchemaPageMD = exports.createTagPageMD = exports.createInfoPageMD = exports.createApiPageMD = void 0;
|
|
10
10
|
const createAuthentication_1 = require("./createAuthentication");
|
|
11
11
|
const createAuthorization_1 = require("./createAuthorization");
|
|
12
12
|
const createCallbacks_1 = require("./createCallbacks");
|
|
@@ -21,6 +21,7 @@ const createMethodEndpoint_1 = require("./createMethodEndpoint");
|
|
|
21
21
|
const createParamsDetails_1 = require("./createParamsDetails");
|
|
22
22
|
const createRequestBodyDetails_1 = require("./createRequestBodyDetails");
|
|
23
23
|
const createRequestHeader_1 = require("./createRequestHeader");
|
|
24
|
+
const createSchema_1 = require("./createSchema");
|
|
24
25
|
const createStatusCodes_1 = require("./createStatusCodes");
|
|
25
26
|
const createTermsOfService_1 = require("./createTermsOfService");
|
|
26
27
|
const createVendorExtensions_1 = require("./createVendorExtensions");
|
|
@@ -84,3 +85,18 @@ function createTagPageMD({ tag: { description } }) {
|
|
|
84
85
|
return (0, utils_1.render)([(0, createDescription_1.createDescription)(description)]);
|
|
85
86
|
}
|
|
86
87
|
exports.createTagPageMD = createTagPageMD;
|
|
88
|
+
function createSchemaPageMD({ schema }) {
|
|
89
|
+
const { title = "", description } = schema;
|
|
90
|
+
return (0, utils_1.render)([
|
|
91
|
+
`import DiscriminatorTabs from "@theme/DiscriminatorTabs";\n`,
|
|
92
|
+
`import SchemaItem from "@theme/SchemaItem";\n`,
|
|
93
|
+
`import SchemaTabs from "@theme/SchemaTabs";\n`,
|
|
94
|
+
`import TabItem from "@theme/TabItem";\n\n`,
|
|
95
|
+
(0, createHeading_1.createHeading)(title.replace(utils_1.lessThan, "<").replace(utils_1.greaterThan, ">")),
|
|
96
|
+
(0, createDescription_1.createDescription)(description),
|
|
97
|
+
(0, utils_1.create)("ul", {
|
|
98
|
+
children: (0, createSchema_1.createNodes)(schema, "response"),
|
|
99
|
+
}),
|
|
100
|
+
]);
|
|
101
|
+
}
|
|
102
|
+
exports.createSchemaPageMD = createSchemaPageMD;
|
package/lib/openapi/openapi.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { ApiMetadata, APIOptions, SidebarOptions } from "../types";
|
|
2
|
-
import { OpenApiObject, TagObject } from "./types";
|
|
2
|
+
import { OpenApiObject, TagGroupObject, TagObject } from "./types";
|
|
3
3
|
interface OpenApiFiles {
|
|
4
4
|
source: string;
|
|
5
5
|
sourceDirName: string;
|
|
6
6
|
data: OpenApiObject;
|
|
7
7
|
}
|
|
8
8
|
export declare function readOpenapiFiles(openapiPath: string): Promise<OpenApiFiles[]>;
|
|
9
|
-
export declare function processOpenapiFiles(files: OpenApiFiles[], options: APIOptions, sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[][]]>;
|
|
10
|
-
export declare function processOpenapiFile(openapiData: OpenApiObject, options: APIOptions, sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[]]>;
|
|
9
|
+
export declare function processOpenapiFiles(files: OpenApiFiles[], options: APIOptions, sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[][], TagGroupObject[]]>;
|
|
10
|
+
export declare function processOpenapiFile(openapiData: OpenApiObject, options: APIOptions, sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[], TagGroupObject[]]>;
|
|
11
11
|
export declare function getTagDisplayName(tagName: string, tags: TagObject[]): string;
|
|
12
12
|
export {};
|
package/lib/openapi/openapi.js
CHANGED
|
@@ -61,7 +61,7 @@ async function createPostmanCollection(openapiData) {
|
|
|
61
61
|
return await jsonToCollection(data);
|
|
62
62
|
}
|
|
63
63
|
function createItems(openapiData, options, sidebarOptions) {
|
|
64
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0;
|
|
64
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _0, _1, _2, _3, _4;
|
|
65
65
|
// TODO: Find a better way to handle this
|
|
66
66
|
let items = [];
|
|
67
67
|
const infoIdSpaces = openapiData.info.title.replace(" ", "-").toLowerCase();
|
|
@@ -324,9 +324,42 @@ function createItems(openapiData, options, sidebarOptions) {
|
|
|
324
324
|
items.push(apiPage);
|
|
325
325
|
}
|
|
326
326
|
}
|
|
327
|
+
if ((options === null || options === void 0 ? void 0 : options.showSchemas) === true) {
|
|
328
|
+
// Gather schemas
|
|
329
|
+
for (let [schema, schemaObject] of Object.entries((_1 = (_0 = openapiData === null || openapiData === void 0 ? void 0 : openapiData.components) === null || _0 === void 0 ? void 0 : _0.schemas) !== null && _1 !== void 0 ? _1 : {})) {
|
|
330
|
+
const baseIdSpaces = (_3 = (_2 = schemaObject === null || schemaObject === void 0 ? void 0 : schemaObject.title) === null || _2 === void 0 ? void 0 : _2.replace(" ", "-").toLowerCase()) !== null && _3 !== void 0 ? _3 : "";
|
|
331
|
+
const baseId = (0, kebabCase_1.default)(baseIdSpaces);
|
|
332
|
+
const schemaDescription = schemaObject.description;
|
|
333
|
+
let splitDescription;
|
|
334
|
+
if (schemaDescription) {
|
|
335
|
+
splitDescription = schemaDescription.match(/[^\r\n]+/g);
|
|
336
|
+
}
|
|
337
|
+
const schemaPage = {
|
|
338
|
+
type: "schema",
|
|
339
|
+
id: baseId,
|
|
340
|
+
infoId: infoId !== null && infoId !== void 0 ? infoId : "",
|
|
341
|
+
unversionedId: baseId,
|
|
342
|
+
title: schemaObject.title
|
|
343
|
+
? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
|
|
344
|
+
: schema,
|
|
345
|
+
description: schemaObject.description
|
|
346
|
+
? schemaObject.description.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
|
|
347
|
+
: "",
|
|
348
|
+
frontMatter: {
|
|
349
|
+
description: splitDescription
|
|
350
|
+
? splitDescription[0]
|
|
351
|
+
.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
|
|
352
|
+
.replace(/\s+$/, "")
|
|
353
|
+
: "",
|
|
354
|
+
},
|
|
355
|
+
schema: schemaObject,
|
|
356
|
+
};
|
|
357
|
+
items.push(schemaPage);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
327
360
|
if ((sidebarOptions === null || sidebarOptions === void 0 ? void 0 : sidebarOptions.categoryLinkSource) === "tag") {
|
|
328
361
|
// Get global tags
|
|
329
|
-
const tags = (
|
|
362
|
+
const tags = (_4 = openapiData.tags) !== null && _4 !== void 0 ? _4 : [];
|
|
330
363
|
// Get operation tags
|
|
331
364
|
const apiItems = items.filter((item) => {
|
|
332
365
|
return item.type === "api";
|
|
@@ -375,7 +408,9 @@ function bindCollectionToApiItems(items, postmanCollection) {
|
|
|
375
408
|
.getPath({ unresolved: true }) // unresolved returns "/:variableName" instead of "/<type>"
|
|
376
409
|
.replace(/(?<![a-z0-9-_]+):([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
|
|
377
410
|
const apiItem = items.find((item) => {
|
|
378
|
-
if (item.type === "info" ||
|
|
411
|
+
if (item.type === "info" ||
|
|
412
|
+
item.type === "tag" ||
|
|
413
|
+
item.type === "schema") {
|
|
379
414
|
return false;
|
|
380
415
|
}
|
|
381
416
|
return item.api.path === path && item.api.method === method;
|
|
@@ -426,7 +461,8 @@ async function processOpenapiFiles(files, options, sidebarOptions) {
|
|
|
426
461
|
...item,
|
|
427
462
|
}));
|
|
428
463
|
const tags = processedFile[1];
|
|
429
|
-
|
|
464
|
+
const tagGroups = processedFile[2];
|
|
465
|
+
return [itemsObjectsArray, tags, tagGroups];
|
|
430
466
|
}
|
|
431
467
|
console.warn(chalk_1.default.yellow(`WARNING: the following OpenAPI spec returned undefined: ${file.source}`));
|
|
432
468
|
return [];
|
|
@@ -449,7 +485,20 @@ async function processOpenapiFiles(files, options, sidebarOptions) {
|
|
|
449
485
|
// Remove undefined tags due to transient parsing errors
|
|
450
486
|
return x !== undefined;
|
|
451
487
|
});
|
|
452
|
-
|
|
488
|
+
const tagGroups = metadata
|
|
489
|
+
.map(function (x) {
|
|
490
|
+
return x[2];
|
|
491
|
+
})
|
|
492
|
+
.flat()
|
|
493
|
+
.filter(function (x) {
|
|
494
|
+
// Remove undefined tags due to transient parsing errors
|
|
495
|
+
return x !== undefined;
|
|
496
|
+
});
|
|
497
|
+
return [
|
|
498
|
+
items,
|
|
499
|
+
tags,
|
|
500
|
+
tagGroups,
|
|
501
|
+
];
|
|
453
502
|
}
|
|
454
503
|
exports.processOpenapiFiles = processOpenapiFiles;
|
|
455
504
|
async function processOpenapiFile(openapiData, options, sidebarOptions) {
|
|
@@ -460,7 +509,11 @@ async function processOpenapiFile(openapiData, options, sidebarOptions) {
|
|
|
460
509
|
if (openapiData.tags !== undefined) {
|
|
461
510
|
tags = openapiData.tags;
|
|
462
511
|
}
|
|
463
|
-
|
|
512
|
+
let tagGroups = [];
|
|
513
|
+
if (openapiData["x-tagGroups"] !== undefined) {
|
|
514
|
+
tagGroups = openapiData["x-tagGroups"];
|
|
515
|
+
}
|
|
516
|
+
return [items, tags, tagGroups];
|
|
464
517
|
}
|
|
465
518
|
exports.processOpenapiFile = processOpenapiFile;
|
|
466
519
|
// order for picking items as a display name of tags
|
|
@@ -24,6 +24,8 @@ describe("openapi", () => {
|
|
|
24
24
|
const yaml = results.find((x) => x.source.endsWith("openapi.yaml"));
|
|
25
25
|
expect(yaml).toBeTruthy();
|
|
26
26
|
expect(yaml === null || yaml === void 0 ? void 0 : yaml.sourceDirName).toBe(".");
|
|
27
|
+
expect(yaml === null || yaml === void 0 ? void 0 : yaml.data.tags).toBeDefined();
|
|
28
|
+
expect(yaml === null || yaml === void 0 ? void 0 : yaml.data["x-tagGroups"]).toBeDefined();
|
|
27
29
|
});
|
|
28
30
|
});
|
|
29
31
|
});
|
package/lib/openapi/types.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface OpenApiObject {
|
|
|
13
13
|
externalDocs?: ExternalDocumentationObject;
|
|
14
14
|
swagger?: string;
|
|
15
15
|
"x-webhooks"?: PathsObject;
|
|
16
|
+
"x-tagGroups"?: TagGroupObject[];
|
|
16
17
|
}
|
|
17
18
|
export interface OpenApiObjectWithRef {
|
|
18
19
|
openapi: string;
|
|
@@ -252,6 +253,10 @@ export interface TagObject {
|
|
|
252
253
|
externalDocs?: ExternalDocumentationObject;
|
|
253
254
|
"x-displayName"?: string;
|
|
254
255
|
}
|
|
256
|
+
export interface TagGroupObject {
|
|
257
|
+
name: string;
|
|
258
|
+
tags: string[];
|
|
259
|
+
}
|
|
255
260
|
export interface ReferenceObject {
|
|
256
261
|
$ref: string;
|
|
257
262
|
}
|
package/lib/options.js
CHANGED
|
@@ -9,7 +9,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
9
9
|
exports.OptionsSchema = void 0;
|
|
10
10
|
const utils_validation_1 = require("@docusaurus/utils-validation");
|
|
11
11
|
const sidebarOptions = utils_validation_1.Joi.object({
|
|
12
|
-
groupPathsBy: utils_validation_1.Joi.string().valid("tag"),
|
|
12
|
+
groupPathsBy: utils_validation_1.Joi.string().valid("tag", "tagGroup"),
|
|
13
13
|
categoryLinkSource: utils_validation_1.Joi.string().valid("tag", "info", "auto"),
|
|
14
14
|
customProps: utils_validation_1.Joi.object(),
|
|
15
15
|
sidebarCollapsible: utils_validation_1.Joi.boolean(),
|
|
@@ -34,6 +34,7 @@ exports.OptionsSchema = utils_validation_1.Joi.object({
|
|
|
34
34
|
showExtensions: utils_validation_1.Joi.boolean(),
|
|
35
35
|
sidebarOptions: sidebarOptions,
|
|
36
36
|
markdownGenerators: markdownGenerators,
|
|
37
|
+
showSchemas: utils_validation_1.Joi.boolean(),
|
|
37
38
|
version: utils_validation_1.Joi.string().when("versions", {
|
|
38
39
|
is: utils_validation_1.Joi.exist(),
|
|
39
40
|
then: utils_validation_1.Joi.required(),
|
package/lib/sidebars/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { ProcessedSidebar } from "@docusaurus/plugin-content-docs/src/sidebars/types";
|
|
2
|
-
import { TagObject } from "../openapi/types";
|
|
2
|
+
import { TagGroupObject, 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[][], docPath: string): ProcessedSidebar;
|
|
4
|
+
export default function generateSidebarSlice(sidebarOptions: SidebarOptions, options: APIOptions, api: ApiMetadata[], tags: TagObject[][], docPath: string, tagGroups?: TagGroupObject[]): ProcessedSidebar;
|
package/lib/sidebars/index.js
CHANGED
|
@@ -20,6 +20,9 @@ function isApiItem(item) {
|
|
|
20
20
|
function isInfoItem(item) {
|
|
21
21
|
return item.type === "info";
|
|
22
22
|
}
|
|
23
|
+
function isSchemaItem(item) {
|
|
24
|
+
return item.type === "schema";
|
|
25
|
+
}
|
|
23
26
|
function groupByTags(items, sidebarOptions, options, tags, docPath) {
|
|
24
27
|
let { outputDir, label } = options;
|
|
25
28
|
// Remove trailing slash before proceeding
|
|
@@ -27,6 +30,7 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
|
|
|
27
30
|
const { sidebarCollapsed, sidebarCollapsible, customProps, categoryLinkSource, } = sidebarOptions;
|
|
28
31
|
const apiItems = items.filter(isApiItem);
|
|
29
32
|
const infoItems = items.filter(isInfoItem);
|
|
33
|
+
const schemaItems = items.filter(isSchemaItem);
|
|
30
34
|
const intros = infoItems.map((item) => {
|
|
31
35
|
return {
|
|
32
36
|
id: item.id,
|
|
@@ -48,7 +52,7 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
|
|
|
48
52
|
apiTags.push(tag.name);
|
|
49
53
|
}
|
|
50
54
|
});
|
|
51
|
-
apiTags = (
|
|
55
|
+
// apiTags = uniq(apiTags.concat(operationTags));
|
|
52
56
|
const basePath = docPath
|
|
53
57
|
? outputDir.split(docPath)[1].replace(/^\/+/g, "")
|
|
54
58
|
: outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
|
|
@@ -56,16 +60,21 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
|
|
|
56
60
|
var _a, _b;
|
|
57
61
|
const sidebar_label = item.frontMatter.sidebar_label;
|
|
58
62
|
const title = item.title;
|
|
59
|
-
const id = item.id;
|
|
63
|
+
const id = item.type === "schema" ? `schemas/${item.id}` : item.id;
|
|
64
|
+
const className = item.type === "api"
|
|
65
|
+
? (0, clsx_1.default)({
|
|
66
|
+
"menu__list-item--deprecated": item.api.deprecated,
|
|
67
|
+
"api-method": !!item.api.method,
|
|
68
|
+
}, item.api.method)
|
|
69
|
+
: (0, clsx_1.default)({
|
|
70
|
+
"menu__list-item--deprecated": item.schema.deprecated,
|
|
71
|
+
});
|
|
60
72
|
return {
|
|
61
73
|
type: "doc",
|
|
62
|
-
id: basePath === "" || undefined ? `${
|
|
74
|
+
id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
|
|
63
75
|
label: (_b = (_a = sidebar_label) !== null && _a !== void 0 ? _a : title) !== null && _b !== void 0 ? _b : id,
|
|
64
76
|
customProps: customProps,
|
|
65
|
-
className:
|
|
66
|
-
"menu__list-item--deprecated": item.api.deprecated,
|
|
67
|
-
"api-method": !!item.api.method,
|
|
68
|
-
}, item.api.method),
|
|
77
|
+
className: className ? className : undefined,
|
|
69
78
|
};
|
|
70
79
|
}
|
|
71
80
|
let rootIntroDoc = undefined;
|
|
@@ -147,16 +156,47 @@ function groupByTags(items, sidebarOptions, options, tags, docPath) {
|
|
|
147
156
|
},
|
|
148
157
|
];
|
|
149
158
|
}
|
|
159
|
+
let schemas = [];
|
|
160
|
+
if (schemaItems.length > 0) {
|
|
161
|
+
schemas = [
|
|
162
|
+
{
|
|
163
|
+
type: "category",
|
|
164
|
+
label: "Schemas",
|
|
165
|
+
collapsible: sidebarCollapsible,
|
|
166
|
+
collapsed: sidebarCollapsed,
|
|
167
|
+
items: schemaItems.map(createDocItem),
|
|
168
|
+
},
|
|
169
|
+
];
|
|
170
|
+
}
|
|
150
171
|
// Shift root intro doc to top of sidebar
|
|
151
172
|
// TODO: Add input validation for categoryLinkSource options
|
|
152
173
|
if (rootIntroDoc && categoryLinkSource !== "info") {
|
|
153
174
|
tagged.unshift(rootIntroDoc);
|
|
154
175
|
}
|
|
155
|
-
return [...tagged, ...untagged];
|
|
176
|
+
return [...tagged, ...untagged, ...schemas];
|
|
156
177
|
}
|
|
157
|
-
function generateSidebarSlice(sidebarOptions, options, api, tags, docPath) {
|
|
178
|
+
function generateSidebarSlice(sidebarOptions, options, api, tags, docPath, tagGroups) {
|
|
158
179
|
let sidebarSlice = [];
|
|
159
|
-
if (sidebarOptions.groupPathsBy === "
|
|
180
|
+
if (sidebarOptions.groupPathsBy === "tagGroup") {
|
|
181
|
+
tagGroups === null || tagGroups === void 0 ? void 0 : tagGroups.forEach((tagGroup) => {
|
|
182
|
+
//filter tags only included in group
|
|
183
|
+
const filteredTags = [];
|
|
184
|
+
tags[0].forEach((tag) => {
|
|
185
|
+
if (tagGroup.tags.includes(tag.name)) {
|
|
186
|
+
filteredTags.push(tag);
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
const groupCategory = {
|
|
190
|
+
type: "category",
|
|
191
|
+
label: tagGroup.name,
|
|
192
|
+
collapsible: true,
|
|
193
|
+
collapsed: true,
|
|
194
|
+
items: groupByTags(api, sidebarOptions, options, [filteredTags], docPath),
|
|
195
|
+
};
|
|
196
|
+
sidebarSlice.push(groupCategory);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
else if (sidebarOptions.groupPathsBy === "tag") {
|
|
160
200
|
sidebarSlice = groupByTags(api, sidebarOptions, options, tags, docPath);
|
|
161
201
|
}
|
|
162
202
|
return sidebarSlice;
|
package/lib/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type Request from "@paloaltonetworks/postman-collection";
|
|
2
|
-
import { InfoObject, OperationObject, SecuritySchemeObject, TagObject } from "./openapi/types";
|
|
2
|
+
import { InfoObject, OperationObject, SchemaObject, SecuritySchemeObject, TagObject } from "./openapi/types";
|
|
3
3
|
export type { PropSidebarItemCategory, SidebarItemLink, PropSidebar, PropSidebarItem, } from "@docusaurus/plugin-content-docs-types";
|
|
4
4
|
export interface PluginOptions {
|
|
5
5
|
id?: string;
|
|
@@ -24,11 +24,13 @@ export interface APIOptions {
|
|
|
24
24
|
};
|
|
25
25
|
proxy?: string;
|
|
26
26
|
markdownGenerators?: MarkdownGenerator;
|
|
27
|
+
showSchemas?: boolean;
|
|
27
28
|
}
|
|
28
29
|
export interface MarkdownGenerator {
|
|
29
30
|
createApiPageMD?: (pageData: ApiPageMetadata) => string;
|
|
30
31
|
createInfoPageMD?: (pageData: InfoPageMetadata) => string;
|
|
31
32
|
createTagPageMD?: (pageData: TagPageMetadata) => string;
|
|
33
|
+
createSchemaPageMD?: (pageData: SchemaPageMetadata) => string;
|
|
32
34
|
}
|
|
33
35
|
export interface SidebarOptions {
|
|
34
36
|
groupPathsBy?: string;
|
|
@@ -48,7 +50,7 @@ export interface APIVersionOptions {
|
|
|
48
50
|
export interface LoadedContent {
|
|
49
51
|
loadedApi: ApiMetadata[];
|
|
50
52
|
}
|
|
51
|
-
export declare type ApiMetadata = ApiPageMetadata | InfoPageMetadata | TagPageMetadata;
|
|
53
|
+
export declare type ApiMetadata = ApiPageMetadata | InfoPageMetadata | TagPageMetadata | SchemaPageMetadata;
|
|
52
54
|
export interface ApiMetadataBase {
|
|
53
55
|
sidebar?: string;
|
|
54
56
|
previous?: ApiNavLink;
|
|
@@ -100,6 +102,17 @@ export interface TagPageMetadata extends ApiMetadataBase {
|
|
|
100
102
|
tag: TagObject;
|
|
101
103
|
markdown?: string;
|
|
102
104
|
}
|
|
105
|
+
export interface SchemaPageMetadata extends ApiMetadataBase {
|
|
106
|
+
type: "schema";
|
|
107
|
+
schema: SchemaObject;
|
|
108
|
+
markdown?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface TagGroupPageMetadata extends ApiMetadataBase {
|
|
111
|
+
type: "tagGroup";
|
|
112
|
+
name: string;
|
|
113
|
+
tags: TagObject[];
|
|
114
|
+
markdown?: string;
|
|
115
|
+
}
|
|
103
116
|
export declare type ApiInfo = InfoObject;
|
|
104
117
|
export interface ApiNavLink {
|
|
105
118
|
title: string;
|
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-700",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"openapi",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=14"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "309ea5d0c101d526975380a13915decebca3e86b"
|
|
64
64
|
}
|
package/src/index.ts
CHANGED
|
@@ -14,11 +14,25 @@ import { Globby, posixPath } from "@docusaurus/utils";
|
|
|
14
14
|
import chalk from "chalk";
|
|
15
15
|
import { render } from "mustache";
|
|
16
16
|
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
createApiPageMD,
|
|
19
|
+
createInfoPageMD,
|
|
20
|
+
createSchemaPageMD,
|
|
21
|
+
createTagPageMD,
|
|
22
|
+
} from "./markdown";
|
|
18
23
|
import { readOpenapiFiles, processOpenapiFiles } from "./openapi";
|
|
19
24
|
import { OptionsSchema } from "./options";
|
|
20
25
|
import generateSidebarSlice from "./sidebars";
|
|
21
|
-
import type {
|
|
26
|
+
import type {
|
|
27
|
+
PluginOptions,
|
|
28
|
+
LoadedContent,
|
|
29
|
+
APIOptions,
|
|
30
|
+
ApiMetadata,
|
|
31
|
+
ApiPageMetadata,
|
|
32
|
+
InfoPageMetadata,
|
|
33
|
+
TagPageMetadata,
|
|
34
|
+
SchemaPageMetadata,
|
|
35
|
+
} from "./types";
|
|
22
36
|
|
|
23
37
|
export function isURL(str: string): boolean {
|
|
24
38
|
return /^(https?:)\/\//m.test(str);
|
|
@@ -117,7 +131,7 @@ export default function pluginOpenAPIDocs(
|
|
|
117
131
|
|
|
118
132
|
try {
|
|
119
133
|
const openapiFiles = await readOpenapiFiles(contentPath);
|
|
120
|
-
const [loadedApi, tags] = await processOpenapiFiles(
|
|
134
|
+
const [loadedApi, tags, tagGroups] = await processOpenapiFiles(
|
|
121
135
|
openapiFiles,
|
|
122
136
|
options,
|
|
123
137
|
sidebarOptions!
|
|
@@ -141,7 +155,8 @@ export default function pluginOpenAPIDocs(
|
|
|
141
155
|
options,
|
|
142
156
|
loadedApi,
|
|
143
157
|
tags,
|
|
144
|
-
docPath
|
|
158
|
+
docPath,
|
|
159
|
+
tagGroups
|
|
145
160
|
);
|
|
146
161
|
|
|
147
162
|
const sidebarSliceTemplate = `module.exports = {{{slice}}};`;
|
|
@@ -244,12 +259,43 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
244
259
|
\`\`\`
|
|
245
260
|
`;
|
|
246
261
|
|
|
262
|
+
const schemaMdTemplate = `---
|
|
263
|
+
id: {{{id}}}
|
|
264
|
+
title: "{{{title}}}"
|
|
265
|
+
description: "{{{frontMatter.description}}}"
|
|
266
|
+
sidebar_label: "{{{title}}}"
|
|
267
|
+
hide_title: true
|
|
268
|
+
schema: true
|
|
269
|
+
custom_edit_url: null
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
{{{markdown}}}
|
|
273
|
+
`;
|
|
274
|
+
|
|
247
275
|
const apiPageGenerator =
|
|
248
276
|
markdownGenerators?.createApiPageMD ?? createApiPageMD;
|
|
249
277
|
const infoPageGenerator =
|
|
250
278
|
markdownGenerators?.createInfoPageMD ?? createInfoPageMD;
|
|
251
279
|
const tagPageGenerator =
|
|
252
280
|
markdownGenerators?.createTagPageMD ?? createTagPageMD;
|
|
281
|
+
const schemaPageGenerator =
|
|
282
|
+
markdownGenerators?.createSchemaPageMD ?? createSchemaPageMD;
|
|
283
|
+
|
|
284
|
+
const pageGeneratorByType: {
|
|
285
|
+
[key in ApiMetadata["type"]]: (
|
|
286
|
+
pageData: {
|
|
287
|
+
api: ApiPageMetadata;
|
|
288
|
+
info: InfoPageMetadata;
|
|
289
|
+
tag: TagPageMetadata;
|
|
290
|
+
schema: SchemaPageMetadata;
|
|
291
|
+
}[key]
|
|
292
|
+
) => string;
|
|
293
|
+
} = {
|
|
294
|
+
api: apiPageGenerator,
|
|
295
|
+
info: infoPageGenerator,
|
|
296
|
+
tag: tagPageGenerator,
|
|
297
|
+
schema: schemaPageGenerator,
|
|
298
|
+
};
|
|
253
299
|
|
|
254
300
|
loadedApi.map(async (item) => {
|
|
255
301
|
if (item.type === "info") {
|
|
@@ -257,12 +303,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
257
303
|
item.downloadUrl = downloadUrl;
|
|
258
304
|
}
|
|
259
305
|
}
|
|
260
|
-
const markdown =
|
|
261
|
-
item.type === "api"
|
|
262
|
-
? apiPageGenerator(item)
|
|
263
|
-
: item.type === "info"
|
|
264
|
-
? infoPageGenerator(item)
|
|
265
|
-
: tagPageGenerator(item);
|
|
306
|
+
const markdown = pageGeneratorByType[item.type](item as any);
|
|
266
307
|
item.markdown = markdown;
|
|
267
308
|
if (item.type === "api") {
|
|
268
309
|
// opportunity to compress JSON
|
|
@@ -363,6 +404,49 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
363
404
|
}
|
|
364
405
|
}
|
|
365
406
|
}
|
|
407
|
+
|
|
408
|
+
if (item.type === "schema") {
|
|
409
|
+
if (!fs.existsSync(`${outputDir}/schemas/${item.id}.schema.mdx`)) {
|
|
410
|
+
if (!fs.existsSync(`${outputDir}/schemas`)) {
|
|
411
|
+
try {
|
|
412
|
+
fs.mkdirSync(`${outputDir}/schemas`, { recursive: true });
|
|
413
|
+
console.log(
|
|
414
|
+
chalk.green(`Successfully created "${outputDir}/schemas"`)
|
|
415
|
+
);
|
|
416
|
+
} catch (err) {
|
|
417
|
+
console.error(
|
|
418
|
+
chalk.red(`Failed to create "${outputDir}/schemas"`),
|
|
419
|
+
chalk.yellow(err)
|
|
420
|
+
);
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
try {
|
|
424
|
+
// kebabCase(arg) returns 0-length string when arg is undefined
|
|
425
|
+
if (item.id.length === 0) {
|
|
426
|
+
throw Error("Schema must have title defined");
|
|
427
|
+
}
|
|
428
|
+
// eslint-disable-next-line testing-library/render-result-naming-convention
|
|
429
|
+
const schemaView = render(schemaMdTemplate, item);
|
|
430
|
+
fs.writeFileSync(
|
|
431
|
+
`${outputDir}/schemas/${item.id}.schema.mdx`,
|
|
432
|
+
schemaView,
|
|
433
|
+
"utf8"
|
|
434
|
+
);
|
|
435
|
+
console.log(
|
|
436
|
+
chalk.green(
|
|
437
|
+
`Successfully created "${outputDir}/${item.id}.schema.mdx"`
|
|
438
|
+
)
|
|
439
|
+
);
|
|
440
|
+
} catch (err) {
|
|
441
|
+
console.error(
|
|
442
|
+
chalk.red(
|
|
443
|
+
`Failed to write "${outputDir}/${item.id}.schema.mdx"`
|
|
444
|
+
),
|
|
445
|
+
chalk.yellow(err)
|
|
446
|
+
);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
}
|
|
366
450
|
return;
|
|
367
451
|
});
|
|
368
452
|
|
|
@@ -380,6 +464,10 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
380
464
|
cwd: path.resolve(apiDir),
|
|
381
465
|
deep: 1,
|
|
382
466
|
});
|
|
467
|
+
const schemaMdxFiles = await Globby(["*.schema.mdx"], {
|
|
468
|
+
cwd: path.resolve(apiDir, "schemas"),
|
|
469
|
+
deep: 1,
|
|
470
|
+
});
|
|
383
471
|
const sidebarFile = await Globby(["sidebar.js"], {
|
|
384
472
|
cwd: path.resolve(apiDir),
|
|
385
473
|
deep: 1,
|
|
@@ -397,6 +485,21 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
397
485
|
})
|
|
398
486
|
);
|
|
399
487
|
|
|
488
|
+
schemaMdxFiles.map((mdx) =>
|
|
489
|
+
fs.unlink(`${apiDir}/schemas/${mdx}`, (err) => {
|
|
490
|
+
if (err) {
|
|
491
|
+
console.error(
|
|
492
|
+
chalk.red(`Cleanup failed for "${apiDir}/schemas/${mdx}"`),
|
|
493
|
+
chalk.yellow(err)
|
|
494
|
+
);
|
|
495
|
+
} else {
|
|
496
|
+
console.log(
|
|
497
|
+
chalk.green(`Cleanup succeeded for "${apiDir}/schemas/${mdx}"`)
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
})
|
|
501
|
+
);
|
|
502
|
+
|
|
400
503
|
sidebarFile.map((sidebar) =>
|
|
401
504
|
fs.unlink(`${apiDir}/${sidebar}`, (err) => {
|
|
402
505
|
if (err) {
|
package/src/markdown/index.ts
CHANGED
|
@@ -11,7 +11,12 @@ import {
|
|
|
11
11
|
MediaTypeObject,
|
|
12
12
|
SecuritySchemeObject,
|
|
13
13
|
} from "../openapi/types";
|
|
14
|
-
import {
|
|
14
|
+
import {
|
|
15
|
+
ApiPageMetadata,
|
|
16
|
+
InfoPageMetadata,
|
|
17
|
+
SchemaPageMetadata,
|
|
18
|
+
TagPageMetadata,
|
|
19
|
+
} from "../types";
|
|
15
20
|
import { createAuthentication } from "./createAuthentication";
|
|
16
21
|
import { createAuthorization } from "./createAuthorization";
|
|
17
22
|
import { createCallbacks } from "./createCallbacks";
|
|
@@ -26,11 +31,12 @@ import { createMethodEndpoint } from "./createMethodEndpoint";
|
|
|
26
31
|
import { createParamsDetails } from "./createParamsDetails";
|
|
27
32
|
import { createRequestBodyDetails } from "./createRequestBodyDetails";
|
|
28
33
|
import { createRequestHeader } from "./createRequestHeader";
|
|
34
|
+
import { createNodes } from "./createSchema";
|
|
29
35
|
import { createStatusCodes } from "./createStatusCodes";
|
|
30
36
|
import { createTermsOfService } from "./createTermsOfService";
|
|
31
37
|
import { createVendorExtensions } from "./createVendorExtensions";
|
|
32
38
|
import { createVersionBadge } from "./createVersionBadge";
|
|
33
|
-
import { greaterThan, lessThan, render } from "./utils";
|
|
39
|
+
import { create, greaterThan, lessThan, render } from "./utils";
|
|
34
40
|
|
|
35
41
|
interface RequestBodyProps {
|
|
36
42
|
title: string;
|
|
@@ -130,3 +136,18 @@ export function createInfoPageMD({
|
|
|
130
136
|
export function createTagPageMD({ tag: { description } }: TagPageMetadata) {
|
|
131
137
|
return render([createDescription(description)]);
|
|
132
138
|
}
|
|
139
|
+
|
|
140
|
+
export function createSchemaPageMD({ schema }: SchemaPageMetadata) {
|
|
141
|
+
const { title = "", description } = schema;
|
|
142
|
+
return render([
|
|
143
|
+
`import DiscriminatorTabs from "@theme/DiscriminatorTabs";\n`,
|
|
144
|
+
`import SchemaItem from "@theme/SchemaItem";\n`,
|
|
145
|
+
`import SchemaTabs from "@theme/SchemaTabs";\n`,
|
|
146
|
+
`import TabItem from "@theme/TabItem";\n\n`,
|
|
147
|
+
createHeading(title.replace(lessThan, "<").replace(greaterThan, ">")),
|
|
148
|
+
createDescription(description),
|
|
149
|
+
create("ul", {
|
|
150
|
+
children: createNodes(schema, "response"),
|
|
151
|
+
}),
|
|
152
|
+
]);
|
|
153
|
+
}
|
|
@@ -11,3 +11,32 @@ paths:
|
|
|
11
11
|
responses:
|
|
12
12
|
200:
|
|
13
13
|
description: OK
|
|
14
|
+
|
|
15
|
+
tags:
|
|
16
|
+
- name: tag1
|
|
17
|
+
description: Everything about your Pets
|
|
18
|
+
x-displayName: Tag 1
|
|
19
|
+
- name: tag2
|
|
20
|
+
description: Tag 2 description
|
|
21
|
+
x-displayName: Tag 2
|
|
22
|
+
- name: tag3
|
|
23
|
+
description: Tag 3 description
|
|
24
|
+
x-displayName: Tag 3
|
|
25
|
+
- name: tag4
|
|
26
|
+
description: Tag 4 description
|
|
27
|
+
x-displayName: Tag 4
|
|
28
|
+
|
|
29
|
+
x-tagGroups:
|
|
30
|
+
- name: Tag 1 & 2
|
|
31
|
+
tags:
|
|
32
|
+
- tag1
|
|
33
|
+
- tag2
|
|
34
|
+
- name: Trinity
|
|
35
|
+
tags:
|
|
36
|
+
- tag1
|
|
37
|
+
- tag2
|
|
38
|
+
- tag3
|
|
39
|
+
- name: Last Two
|
|
40
|
+
tags:
|
|
41
|
+
- tag3
|
|
42
|
+
- tag4
|
|
@@ -28,6 +28,9 @@ describe("openapi", () => {
|
|
|
28
28
|
const yaml = results.find((x) => x.source.endsWith("openapi.yaml"));
|
|
29
29
|
expect(yaml).toBeTruthy();
|
|
30
30
|
expect(yaml?.sourceDirName).toBe(".");
|
|
31
|
+
|
|
32
|
+
expect(yaml?.data.tags).toBeDefined();
|
|
33
|
+
expect(yaml?.data["x-tagGroups"]).toBeDefined();
|
|
31
34
|
});
|
|
32
35
|
});
|
|
33
36
|
});
|
package/src/openapi/openapi.ts
CHANGED
|
@@ -24,11 +24,12 @@ import {
|
|
|
24
24
|
APIOptions,
|
|
25
25
|
ApiPageMetadata,
|
|
26
26
|
InfoPageMetadata,
|
|
27
|
+
SchemaPageMetadata,
|
|
27
28
|
SidebarOptions,
|
|
28
29
|
TagPageMetadata,
|
|
29
30
|
} from "../types";
|
|
30
31
|
import { sampleRequestFromSchema } from "./createRequestExample";
|
|
31
|
-
import { OpenApiObject, TagObject } from "./types";
|
|
32
|
+
import { OpenApiObject, TagGroupObject, TagObject } from "./types";
|
|
32
33
|
import { loadAndResolveSpec } from "./utils/loadAndResolveSpec";
|
|
33
34
|
|
|
34
35
|
/**
|
|
@@ -409,6 +410,46 @@ function createItems(
|
|
|
409
410
|
}
|
|
410
411
|
}
|
|
411
412
|
|
|
413
|
+
if (options?.showSchemas === true) {
|
|
414
|
+
// Gather schemas
|
|
415
|
+
for (let [schema, schemaObject] of Object.entries(
|
|
416
|
+
openapiData?.components?.schemas ?? {}
|
|
417
|
+
)) {
|
|
418
|
+
const baseIdSpaces =
|
|
419
|
+
schemaObject?.title?.replace(" ", "-").toLowerCase() ?? "";
|
|
420
|
+
const baseId = kebabCase(baseIdSpaces);
|
|
421
|
+
|
|
422
|
+
const schemaDescription = schemaObject.description;
|
|
423
|
+
let splitDescription: any;
|
|
424
|
+
if (schemaDescription) {
|
|
425
|
+
splitDescription = schemaDescription.match(/[^\r\n]+/g);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
const schemaPage: PartialPage<SchemaPageMetadata> = {
|
|
429
|
+
type: "schema",
|
|
430
|
+
id: baseId,
|
|
431
|
+
infoId: infoId ?? "",
|
|
432
|
+
unversionedId: baseId,
|
|
433
|
+
title: schemaObject.title
|
|
434
|
+
? schemaObject.title.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
|
|
435
|
+
: schema,
|
|
436
|
+
description: schemaObject.description
|
|
437
|
+
? schemaObject.description.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
|
|
438
|
+
: "",
|
|
439
|
+
frontMatter: {
|
|
440
|
+
description: splitDescription
|
|
441
|
+
? splitDescription[0]
|
|
442
|
+
.replace(/((?:^|[^\\])(?:\\{2})*)"/g, "$1'")
|
|
443
|
+
.replace(/\s+$/, "")
|
|
444
|
+
: "",
|
|
445
|
+
},
|
|
446
|
+
schema: schemaObject,
|
|
447
|
+
};
|
|
448
|
+
|
|
449
|
+
items.push(schemaPage);
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
412
453
|
if (sidebarOptions?.categoryLinkSource === "tag") {
|
|
413
454
|
// Get global tags
|
|
414
455
|
const tags: TagObject[] = openapiData.tags ?? [];
|
|
@@ -471,7 +512,11 @@ function bindCollectionToApiItems(
|
|
|
471
512
|
.getPath({ unresolved: true }) // unresolved returns "/:variableName" instead of "/<type>"
|
|
472
513
|
.replace(/(?<![a-z0-9-_]+):([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
|
|
473
514
|
const apiItem = items.find((item) => {
|
|
474
|
-
if (
|
|
515
|
+
if (
|
|
516
|
+
item.type === "info" ||
|
|
517
|
+
item.type === "tag" ||
|
|
518
|
+
item.type === "schema"
|
|
519
|
+
) {
|
|
475
520
|
return false;
|
|
476
521
|
}
|
|
477
522
|
return item.api.path === path && item.api.method === method;
|
|
@@ -534,7 +579,7 @@ export async function processOpenapiFiles(
|
|
|
534
579
|
files: OpenApiFiles[],
|
|
535
580
|
options: APIOptions,
|
|
536
581
|
sidebarOptions: SidebarOptions
|
|
537
|
-
): Promise<[ApiMetadata[], TagObject[][]]> {
|
|
582
|
+
): Promise<[ApiMetadata[], TagObject[][], TagGroupObject[]]> {
|
|
538
583
|
const promises = files.map(async (file) => {
|
|
539
584
|
if (file.data !== undefined) {
|
|
540
585
|
const processedFile = await processOpenapiFile(
|
|
@@ -546,7 +591,8 @@ export async function processOpenapiFiles(
|
|
|
546
591
|
...item,
|
|
547
592
|
}));
|
|
548
593
|
const tags = processedFile[1];
|
|
549
|
-
|
|
594
|
+
const tagGroups = processedFile[2];
|
|
595
|
+
return [itemsObjectsArray, tags, tagGroups];
|
|
550
596
|
}
|
|
551
597
|
console.warn(
|
|
552
598
|
chalk.yellow(
|
|
@@ -565,6 +611,7 @@ export async function processOpenapiFiles(
|
|
|
565
611
|
// Remove undefined items due to transient parsing errors
|
|
566
612
|
return x !== undefined;
|
|
567
613
|
});
|
|
614
|
+
|
|
568
615
|
const tags = metadata
|
|
569
616
|
.map(function (x) {
|
|
570
617
|
return x[1];
|
|
@@ -573,14 +620,29 @@ export async function processOpenapiFiles(
|
|
|
573
620
|
// Remove undefined tags due to transient parsing errors
|
|
574
621
|
return x !== undefined;
|
|
575
622
|
});
|
|
576
|
-
|
|
623
|
+
|
|
624
|
+
const tagGroups = metadata
|
|
625
|
+
.map(function (x) {
|
|
626
|
+
return x[2];
|
|
627
|
+
})
|
|
628
|
+
.flat()
|
|
629
|
+
.filter(function (x) {
|
|
630
|
+
// Remove undefined tags due to transient parsing errors
|
|
631
|
+
return x !== undefined;
|
|
632
|
+
});
|
|
633
|
+
|
|
634
|
+
return [
|
|
635
|
+
items as ApiMetadata[],
|
|
636
|
+
tags as TagObject[][],
|
|
637
|
+
tagGroups as TagGroupObject[],
|
|
638
|
+
];
|
|
577
639
|
}
|
|
578
640
|
|
|
579
641
|
export async function processOpenapiFile(
|
|
580
642
|
openapiData: OpenApiObject,
|
|
581
643
|
options: APIOptions,
|
|
582
644
|
sidebarOptions: SidebarOptions
|
|
583
|
-
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
645
|
+
): Promise<[ApiMetadata[], TagObject[], TagGroupObject[]]> {
|
|
584
646
|
const postmanCollection = await createPostmanCollection(openapiData);
|
|
585
647
|
const items = createItems(openapiData, options, sidebarOptions);
|
|
586
648
|
|
|
@@ -590,7 +652,13 @@ export async function processOpenapiFile(
|
|
|
590
652
|
if (openapiData.tags !== undefined) {
|
|
591
653
|
tags = openapiData.tags;
|
|
592
654
|
}
|
|
593
|
-
|
|
655
|
+
|
|
656
|
+
let tagGroups: TagGroupObject[] = [];
|
|
657
|
+
if (openapiData["x-tagGroups"] !== undefined) {
|
|
658
|
+
tagGroups = openapiData["x-tagGroups"];
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
return [items, tags, tagGroups];
|
|
594
662
|
}
|
|
595
663
|
|
|
596
664
|
// order for picking items as a display name of tags
|
package/src/openapi/types.ts
CHANGED
|
@@ -22,6 +22,7 @@ export interface OpenApiObject {
|
|
|
22
22
|
externalDocs?: ExternalDocumentationObject;
|
|
23
23
|
swagger?: string;
|
|
24
24
|
"x-webhooks"?: PathsObject;
|
|
25
|
+
"x-tagGroups"?: TagGroupObject[];
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
export interface OpenApiObjectWithRef {
|
|
@@ -311,6 +312,11 @@ export interface TagObject {
|
|
|
311
312
|
"x-displayName"?: string;
|
|
312
313
|
}
|
|
313
314
|
|
|
315
|
+
export interface TagGroupObject {
|
|
316
|
+
name: string;
|
|
317
|
+
tags: string[];
|
|
318
|
+
}
|
|
319
|
+
|
|
314
320
|
export interface ReferenceObject {
|
|
315
321
|
$ref: string;
|
|
316
322
|
}
|
package/src/options.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { Joi } from "@docusaurus/utils-validation";
|
|
9
9
|
|
|
10
10
|
const sidebarOptions = Joi.object({
|
|
11
|
-
groupPathsBy: Joi.string().valid("tag"),
|
|
11
|
+
groupPathsBy: Joi.string().valid("tag", "tagGroup"),
|
|
12
12
|
categoryLinkSource: Joi.string().valid("tag", "info", "auto"),
|
|
13
13
|
customProps: Joi.object(),
|
|
14
14
|
sidebarCollapsible: Joi.boolean(),
|
|
@@ -37,6 +37,7 @@ export const OptionsSchema = Joi.object({
|
|
|
37
37
|
showExtensions: Joi.boolean(),
|
|
38
38
|
sidebarOptions: sidebarOptions,
|
|
39
39
|
markdownGenerators: markdownGenerators,
|
|
40
|
+
showSchemas: Joi.boolean(),
|
|
40
41
|
version: Joi.string().when("versions", {
|
|
41
42
|
is: Joi.exist(),
|
|
42
43
|
then: Joi.required(),
|
package/src/sidebars/index.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import path from "path";
|
|
9
9
|
|
|
10
|
+
import { ProcessedSidebarItem } from "@docusaurus/plugin-content-docs/lib/sidebars/types";
|
|
10
11
|
import {
|
|
11
12
|
ProcessedSidebar,
|
|
12
13
|
SidebarItemCategory,
|
|
@@ -18,12 +19,13 @@ import clsx from "clsx";
|
|
|
18
19
|
import { kebabCase } from "lodash";
|
|
19
20
|
import uniq from "lodash/uniq";
|
|
20
21
|
|
|
21
|
-
import { TagObject } from "../openapi/types";
|
|
22
|
+
import { TagGroupObject, TagObject } from "../openapi/types";
|
|
22
23
|
import type {
|
|
23
24
|
SidebarOptions,
|
|
24
25
|
APIOptions,
|
|
25
26
|
ApiPageMetadata,
|
|
26
27
|
ApiMetadata,
|
|
28
|
+
SchemaPageMetadata,
|
|
27
29
|
} from "../types";
|
|
28
30
|
|
|
29
31
|
function isApiItem(item: ApiMetadata): item is ApiMetadata {
|
|
@@ -34,6 +36,10 @@ function isInfoItem(item: ApiMetadata): item is ApiMetadata {
|
|
|
34
36
|
return item.type === "info";
|
|
35
37
|
}
|
|
36
38
|
|
|
39
|
+
function isSchemaItem(item: ApiMetadata): item is ApiMetadata {
|
|
40
|
+
return item.type === "schema";
|
|
41
|
+
}
|
|
42
|
+
|
|
37
43
|
function groupByTags(
|
|
38
44
|
items: ApiPageMetadata[],
|
|
39
45
|
sidebarOptions: SidebarOptions,
|
|
@@ -55,6 +61,7 @@ function groupByTags(
|
|
|
55
61
|
|
|
56
62
|
const apiItems = items.filter(isApiItem);
|
|
57
63
|
const infoItems = items.filter(isInfoItem);
|
|
64
|
+
const schemaItems = items.filter(isSchemaItem);
|
|
58
65
|
const intros = infoItems.map((item: any) => {
|
|
59
66
|
return {
|
|
60
67
|
id: item.id,
|
|
@@ -80,28 +87,35 @@ function groupByTags(
|
|
|
80
87
|
apiTags.push(tag.name!);
|
|
81
88
|
}
|
|
82
89
|
});
|
|
83
|
-
apiTags = uniq(apiTags.concat(operationTags));
|
|
90
|
+
// apiTags = uniq(apiTags.concat(operationTags));
|
|
84
91
|
|
|
85
92
|
const basePath = docPath
|
|
86
93
|
? outputDir.split(docPath!)[1].replace(/^\/+/g, "")
|
|
87
94
|
: outputDir.slice(outputDir.indexOf("/", 1)).replace(/^\/+/g, "");
|
|
88
|
-
function createDocItem(
|
|
95
|
+
function createDocItem(
|
|
96
|
+
item: ApiPageMetadata | SchemaPageMetadata
|
|
97
|
+
): SidebarItemDoc {
|
|
89
98
|
const sidebar_label = item.frontMatter.sidebar_label;
|
|
90
99
|
const title = item.title;
|
|
91
|
-
const id = item.id;
|
|
100
|
+
const id = item.type === "schema" ? `schemas/${item.id}` : item.id;
|
|
101
|
+
const className =
|
|
102
|
+
item.type === "api"
|
|
103
|
+
? clsx(
|
|
104
|
+
{
|
|
105
|
+
"menu__list-item--deprecated": item.api.deprecated,
|
|
106
|
+
"api-method": !!item.api.method,
|
|
107
|
+
},
|
|
108
|
+
item.api.method
|
|
109
|
+
)
|
|
110
|
+
: clsx({
|
|
111
|
+
"menu__list-item--deprecated": item.schema.deprecated,
|
|
112
|
+
});
|
|
92
113
|
return {
|
|
93
114
|
type: "doc" as const,
|
|
94
|
-
id:
|
|
95
|
-
basePath === "" || undefined ? `${item.id}` : `${basePath}/${item.id}`,
|
|
115
|
+
id: basePath === "" || undefined ? `${id}` : `${basePath}/${id}`,
|
|
96
116
|
label: (sidebar_label as string) ?? title ?? id,
|
|
97
117
|
customProps: customProps,
|
|
98
|
-
className:
|
|
99
|
-
{
|
|
100
|
-
"menu__list-item--deprecated": item.api.deprecated,
|
|
101
|
-
"api-method": !!item.api.method,
|
|
102
|
-
},
|
|
103
|
-
item.api.method
|
|
104
|
-
),
|
|
118
|
+
className: className ? className : undefined,
|
|
105
119
|
};
|
|
106
120
|
}
|
|
107
121
|
|
|
@@ -201,13 +215,26 @@ function groupByTags(
|
|
|
201
215
|
];
|
|
202
216
|
}
|
|
203
217
|
|
|
218
|
+
let schemas: SidebarItemCategory[] = [];
|
|
219
|
+
if (schemaItems.length > 0) {
|
|
220
|
+
schemas = [
|
|
221
|
+
{
|
|
222
|
+
type: "category" as const,
|
|
223
|
+
label: "Schemas",
|
|
224
|
+
collapsible: sidebarCollapsible!,
|
|
225
|
+
collapsed: sidebarCollapsed!,
|
|
226
|
+
items: schemaItems.map(createDocItem),
|
|
227
|
+
},
|
|
228
|
+
];
|
|
229
|
+
}
|
|
230
|
+
|
|
204
231
|
// Shift root intro doc to top of sidebar
|
|
205
232
|
// TODO: Add input validation for categoryLinkSource options
|
|
206
233
|
if (rootIntroDoc && categoryLinkSource !== "info") {
|
|
207
234
|
tagged.unshift(rootIntroDoc as any);
|
|
208
235
|
}
|
|
209
236
|
|
|
210
|
-
return [...tagged, ...untagged];
|
|
237
|
+
return [...tagged, ...untagged, ...schemas];
|
|
211
238
|
}
|
|
212
239
|
|
|
213
240
|
export default function generateSidebarSlice(
|
|
@@ -215,11 +242,38 @@ export default function generateSidebarSlice(
|
|
|
215
242
|
options: APIOptions,
|
|
216
243
|
api: ApiMetadata[],
|
|
217
244
|
tags: TagObject[][],
|
|
218
|
-
docPath: string
|
|
245
|
+
docPath: string,
|
|
246
|
+
tagGroups?: TagGroupObject[]
|
|
219
247
|
) {
|
|
220
248
|
let sidebarSlice: ProcessedSidebar = [];
|
|
221
249
|
|
|
222
|
-
if (sidebarOptions.groupPathsBy === "
|
|
250
|
+
if (sidebarOptions.groupPathsBy === "tagGroup") {
|
|
251
|
+
tagGroups?.forEach((tagGroup) => {
|
|
252
|
+
//filter tags only included in group
|
|
253
|
+
const filteredTags: TagObject[] = [];
|
|
254
|
+
tags[0].forEach((tag) => {
|
|
255
|
+
if (tagGroup.tags.includes(tag.name as string)) {
|
|
256
|
+
filteredTags.push(tag);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
const groupCategory = {
|
|
261
|
+
type: "category" as const,
|
|
262
|
+
label: tagGroup.name,
|
|
263
|
+
collapsible: true,
|
|
264
|
+
collapsed: true,
|
|
265
|
+
items: groupByTags(
|
|
266
|
+
api as ApiPageMetadata[],
|
|
267
|
+
sidebarOptions,
|
|
268
|
+
options,
|
|
269
|
+
[filteredTags],
|
|
270
|
+
docPath
|
|
271
|
+
),
|
|
272
|
+
} as ProcessedSidebarItem;
|
|
273
|
+
|
|
274
|
+
sidebarSlice.push(groupCategory);
|
|
275
|
+
});
|
|
276
|
+
} else if (sidebarOptions.groupPathsBy === "tag") {
|
|
223
277
|
sidebarSlice = groupByTags(
|
|
224
278
|
api as ApiPageMetadata[],
|
|
225
279
|
sidebarOptions,
|
|
@@ -228,5 +282,6 @@ export default function generateSidebarSlice(
|
|
|
228
282
|
docPath
|
|
229
283
|
);
|
|
230
284
|
}
|
|
285
|
+
|
|
231
286
|
return sidebarSlice;
|
|
232
287
|
}
|
package/src/types.ts
CHANGED
|
@@ -10,6 +10,7 @@ import type Request from "@paloaltonetworks/postman-collection";
|
|
|
10
10
|
import {
|
|
11
11
|
InfoObject,
|
|
12
12
|
OperationObject,
|
|
13
|
+
SchemaObject,
|
|
13
14
|
SecuritySchemeObject,
|
|
14
15
|
TagObject,
|
|
15
16
|
} from "./openapi/types";
|
|
@@ -44,12 +45,14 @@ export interface APIOptions {
|
|
|
44
45
|
};
|
|
45
46
|
proxy?: string;
|
|
46
47
|
markdownGenerators?: MarkdownGenerator;
|
|
48
|
+
showSchemas?: boolean;
|
|
47
49
|
}
|
|
48
50
|
|
|
49
51
|
export interface MarkdownGenerator {
|
|
50
52
|
createApiPageMD?: (pageData: ApiPageMetadata) => string;
|
|
51
53
|
createInfoPageMD?: (pageData: InfoPageMetadata) => string;
|
|
52
54
|
createTagPageMD?: (pageData: TagPageMetadata) => string;
|
|
55
|
+
createSchemaPageMD?: (pageData: SchemaPageMetadata) => string;
|
|
53
56
|
}
|
|
54
57
|
|
|
55
58
|
export interface SidebarOptions {
|
|
@@ -72,7 +75,11 @@ export interface LoadedContent {
|
|
|
72
75
|
// loadedDocs: DocPageMetadata[]; TODO: cleanup
|
|
73
76
|
}
|
|
74
77
|
|
|
75
|
-
export type ApiMetadata =
|
|
78
|
+
export type ApiMetadata =
|
|
79
|
+
| ApiPageMetadata
|
|
80
|
+
| InfoPageMetadata
|
|
81
|
+
| TagPageMetadata
|
|
82
|
+
| SchemaPageMetadata;
|
|
76
83
|
|
|
77
84
|
export interface ApiMetadataBase {
|
|
78
85
|
sidebar?: string;
|
|
@@ -131,6 +138,19 @@ export interface TagPageMetadata extends ApiMetadataBase {
|
|
|
131
138
|
markdown?: string;
|
|
132
139
|
}
|
|
133
140
|
|
|
141
|
+
export interface SchemaPageMetadata extends ApiMetadataBase {
|
|
142
|
+
type: "schema";
|
|
143
|
+
schema: SchemaObject;
|
|
144
|
+
markdown?: string;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export interface TagGroupPageMetadata extends ApiMetadataBase {
|
|
148
|
+
type: "tagGroup";
|
|
149
|
+
name: string;
|
|
150
|
+
tags: TagObject[];
|
|
151
|
+
markdown?: string;
|
|
152
|
+
}
|
|
153
|
+
|
|
134
154
|
export type ApiInfo = InfoObject;
|
|
135
155
|
|
|
136
156
|
export interface ApiNavLink {
|