docusaurus-plugin-openapi-docs 0.0.0-359 → 0.0.0-362
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.js +37 -3
- package/lib/markdown/index.d.ts +2 -1
- package/lib/markdown/index.js +5 -1
- package/lib/openapi/createExample.js +59 -49
- package/lib/openapi/openapi.d.ts +3 -3
- package/lib/openapi/openapi.js +43 -17
- package/lib/sidebars/index.js +3 -5
- package/lib/types.d.ts +7 -2
- package/package.json +8 -8
- package/src/index.ts +54 -4
- package/src/markdown/index.ts +5 -1
- package/src/openapi/createExample.ts +59 -50
- package/src/openapi/openapi.ts +48 -8
- package/src/sidebars/index.ts +3 -5
- package/src/types.ts +8 -1
package/lib/index.js
CHANGED
|
@@ -25,7 +25,7 @@ function pluginOpenAPI(context, options) {
|
|
|
25
25
|
const contentPath = path_1.default.resolve(siteDir, specPath);
|
|
26
26
|
try {
|
|
27
27
|
const openapiFiles = await (0, openapi_1.readOpenapiFiles)(contentPath, {});
|
|
28
|
-
const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles);
|
|
28
|
+
const [loadedApi, tags] = await (0, openapi_1.processOpenapiFiles)(openapiFiles, sidebarOptions);
|
|
29
29
|
if (!fs_1.default.existsSync(outputDir)) {
|
|
30
30
|
try {
|
|
31
31
|
fs_1.default.mkdirSync(outputDir, { recursive: true });
|
|
@@ -96,17 +96,40 @@ hide_title: true
|
|
|
96
96
|
import DocCardList from '@theme/DocCardList';
|
|
97
97
|
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
98
98
|
|
|
99
|
+
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
100
|
+
\`\`\`
|
|
101
|
+
`;
|
|
102
|
+
const tagMdTemplate = template
|
|
103
|
+
? fs_1.default.readFileSync(template).toString()
|
|
104
|
+
: `---
|
|
105
|
+
id: {{{id}}}
|
|
106
|
+
title: {{{description}}}
|
|
107
|
+
description: {{{description}}}
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
{{{markdown}}}
|
|
111
|
+
|
|
112
|
+
\`\`\`mdx-code-block
|
|
113
|
+
import DocCardList from '@theme/DocCardList';
|
|
114
|
+
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
115
|
+
|
|
99
116
|
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
100
117
|
\`\`\`
|
|
101
118
|
`;
|
|
102
119
|
loadedApi.map(async (item) => {
|
|
103
|
-
const markdown = item.type === "api"
|
|
120
|
+
const markdown = item.type === "api"
|
|
121
|
+
? (0, markdown_1.createApiPageMD)(item)
|
|
122
|
+
: item.type === "info"
|
|
123
|
+
? (0, markdown_1.createInfoPageMD)(item)
|
|
124
|
+
: (0, markdown_1.createTagPageMD)(item);
|
|
104
125
|
item.markdown = markdown;
|
|
105
126
|
if (item.type === "api") {
|
|
106
127
|
item.json = JSON.stringify(item.api);
|
|
107
128
|
}
|
|
108
129
|
const view = (0, mustache_1.render)(mdTemplate, item);
|
|
109
130
|
const utils = (0, mustache_1.render)(infoMdTemplate, item);
|
|
131
|
+
// eslint-disable-next-line testing-library/render-result-naming-convention
|
|
132
|
+
const tagUtils = (0, mustache_1.render)(tagMdTemplate, item);
|
|
110
133
|
if (item.type === "api") {
|
|
111
134
|
if (!fs_1.default.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
|
|
112
135
|
try {
|
|
@@ -132,6 +155,17 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
132
155
|
}
|
|
133
156
|
}
|
|
134
157
|
}
|
|
158
|
+
if (item.type === "tag") {
|
|
159
|
+
if (!fs_1.default.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
|
|
160
|
+
try {
|
|
161
|
+
fs_1.default.writeFileSync(`${outputDir}/${item.id}.tag.mdx`, tagUtils, "utf8");
|
|
162
|
+
console.log(chalk_1.default.green(`Successfully created "${outputDir}/${item.id}.tag.mdx"`));
|
|
163
|
+
}
|
|
164
|
+
catch (err) {
|
|
165
|
+
console.error(chalk_1.default.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`), chalk_1.default.yellow(err));
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
135
169
|
return;
|
|
136
170
|
});
|
|
137
171
|
return;
|
|
@@ -144,7 +178,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
144
178
|
async function cleanApiDocs(options) {
|
|
145
179
|
const { outputDir } = options;
|
|
146
180
|
const apiDir = path_1.default.join(siteDir, outputDir);
|
|
147
|
-
const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx"], {
|
|
181
|
+
const apiMdxFiles = await (0, utils_1.Globby)(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
148
182
|
cwd: path_1.default.resolve(apiDir),
|
|
149
183
|
});
|
|
150
184
|
const sidebarFile = await (0, utils_1.Globby)(["sidebar.js"], {
|
package/lib/markdown/index.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
import { ApiPageMetadata, InfoPageMetadata } from "../types";
|
|
1
|
+
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
|
|
2
2
|
export declare function createApiPageMD({ title, api: { deprecated, "x-deprecated-description": deprecatedDescription, description, parameters, requestBody, responses, }, }: ApiPageMetadata): string;
|
|
3
3
|
export declare function createInfoPageMD({ info: { title, version, description, contact, license, termsOfService }, }: InfoPageMetadata): string;
|
|
4
|
+
export declare function createTagPageMD({ tag: { description } }: TagPageMetadata): 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.createInfoPageMD = exports.createApiPageMD = void 0;
|
|
9
|
+
exports.createTagPageMD = exports.createInfoPageMD = exports.createApiPageMD = void 0;
|
|
10
10
|
const lodash_1 = require("lodash");
|
|
11
11
|
const createContactInfo_1 = require("./createContactInfo");
|
|
12
12
|
const createDeprecationNotice_1 = require("./createDeprecationNotice");
|
|
@@ -47,3 +47,7 @@ function createInfoPageMD({ info: { title, version, description, contact, licens
|
|
|
47
47
|
]);
|
|
48
48
|
}
|
|
49
49
|
exports.createInfoPageMD = createInfoPageMD;
|
|
50
|
+
function createTagPageMD({ tag: { description } }) {
|
|
51
|
+
return (0, utils_1.render)([(0, createDescription_1.createDescription)(description)]);
|
|
52
|
+
}
|
|
53
|
+
exports.createTagPageMD = createTagPageMD;
|
|
@@ -5,8 +5,12 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
* ========================================================================== */
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
8
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
12
|
exports.sampleFromSchema = void 0;
|
|
13
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
14
|
const primitives = {
|
|
11
15
|
string: {
|
|
12
16
|
default: () => "string",
|
|
@@ -31,64 +35,70 @@ const primitives = {
|
|
|
31
35
|
array: {},
|
|
32
36
|
};
|
|
33
37
|
const sampleFromSchema = (schema = {}) => {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (allOf) {
|
|
39
|
-
// TODO: We are just assuming it will always be an object for now
|
|
40
|
-
let obj = {
|
|
41
|
-
type: "object",
|
|
42
|
-
properties: {},
|
|
43
|
-
required: [], // NOTE: We shouldn't need to worry about required
|
|
44
|
-
};
|
|
45
|
-
for (let item of allOf) {
|
|
46
|
-
if (item.properties) {
|
|
47
|
-
obj.properties = {
|
|
48
|
-
...obj.properties,
|
|
49
|
-
...item.properties,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
return (0, exports.sampleFromSchema)(obj);
|
|
54
|
-
}
|
|
55
|
-
if (!type) {
|
|
56
|
-
if (properties) {
|
|
57
|
-
type = "object";
|
|
38
|
+
try {
|
|
39
|
+
let { type, example, allOf, properties, items } = schema;
|
|
40
|
+
if (example !== undefined) {
|
|
41
|
+
return example;
|
|
58
42
|
}
|
|
59
|
-
|
|
60
|
-
|
|
43
|
+
if (allOf) {
|
|
44
|
+
// TODO: We are just assuming it will always be an object for now
|
|
45
|
+
let obj = {
|
|
46
|
+
type: "object",
|
|
47
|
+
properties: {},
|
|
48
|
+
required: [], // NOTE: We shouldn't need to worry about required
|
|
49
|
+
};
|
|
50
|
+
for (let item of allOf) {
|
|
51
|
+
if (item.properties) {
|
|
52
|
+
obj.properties = {
|
|
53
|
+
...obj.properties,
|
|
54
|
+
...item.properties,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return (0, exports.sampleFromSchema)(obj);
|
|
61
59
|
}
|
|
62
|
-
|
|
63
|
-
|
|
60
|
+
if (!type) {
|
|
61
|
+
if (properties) {
|
|
62
|
+
type = "object";
|
|
63
|
+
}
|
|
64
|
+
else if (items) {
|
|
65
|
+
type = "array";
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
64
70
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
+
if (type === "object") {
|
|
72
|
+
let obj = {};
|
|
73
|
+
for (let [name, prop] of Object.entries(properties !== null && properties !== void 0 ? properties : {})) {
|
|
74
|
+
if (prop.deprecated) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
obj[name] = (0, exports.sampleFromSchema)(prop);
|
|
71
78
|
}
|
|
72
|
-
obj
|
|
79
|
+
return obj;
|
|
73
80
|
}
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
81
|
+
if (type === "array") {
|
|
82
|
+
if (Array.isArray(items === null || items === void 0 ? void 0 : items.anyOf)) {
|
|
83
|
+
return items === null || items === void 0 ? void 0 : items.anyOf.map((item) => (0, exports.sampleFromSchema)(item));
|
|
84
|
+
}
|
|
85
|
+
if (Array.isArray(items === null || items === void 0 ? void 0 : items.oneOf)) {
|
|
86
|
+
return items === null || items === void 0 ? void 0 : items.oneOf.map((item) => (0, exports.sampleFromSchema)(item));
|
|
87
|
+
}
|
|
88
|
+
return [(0, exports.sampleFromSchema)(items)];
|
|
79
89
|
}
|
|
80
|
-
if (
|
|
81
|
-
|
|
90
|
+
if (schema.enum) {
|
|
91
|
+
if (schema.default) {
|
|
92
|
+
return schema.default;
|
|
93
|
+
}
|
|
94
|
+
return normalizeArray(schema.enum)[0];
|
|
82
95
|
}
|
|
83
|
-
return
|
|
96
|
+
return primitive(schema);
|
|
84
97
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
return normalizeArray(schema.enum)[0];
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.error(chalk_1.default.yellow("WARNING: failed to create example from schema object:", err));
|
|
100
|
+
return;
|
|
90
101
|
}
|
|
91
|
-
return primitive(schema);
|
|
92
102
|
};
|
|
93
103
|
exports.sampleFromSchema = sampleFromSchema;
|
|
94
104
|
function primitive(schema = {}) {
|
package/lib/openapi/openapi.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiMetadata } from "../types";
|
|
1
|
+
import { ApiMetadata, SidebarOptions } from "../types";
|
|
2
2
|
import { OpenApiObjectWithRef, TagObject } from "./types";
|
|
3
3
|
interface OpenApiFiles {
|
|
4
4
|
source: string;
|
|
@@ -6,7 +6,7 @@ interface OpenApiFiles {
|
|
|
6
6
|
data: OpenApiObjectWithRef;
|
|
7
7
|
}
|
|
8
8
|
export declare function readOpenapiFiles(openapiPath: string, _options: {}): Promise<OpenApiFiles[]>;
|
|
9
|
-
export declare function processOpenapiFiles(files: OpenApiFiles[]): Promise<[ApiMetadata[], TagObject[]]>;
|
|
10
|
-
export declare function processOpenapiFile(openapiDataWithRefs: OpenApiObjectWithRef): Promise<[ApiMetadata[], TagObject[]]>;
|
|
9
|
+
export declare function processOpenapiFiles(files: OpenApiFiles[], sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[]]>;
|
|
10
|
+
export declare function processOpenapiFile(openapiDataWithRefs: OpenApiObjectWithRef, sidebarOptions: SidebarOptions): Promise<[ApiMetadata[], TagObject[]]>;
|
|
11
11
|
export declare function getTagDisplayName(tagName: string, tags: TagObject[]): string;
|
|
12
12
|
export {};
|
package/lib/openapi/openapi.js
CHANGED
|
@@ -63,12 +63,38 @@ async function createPostmanCollection(openapiData) {
|
|
|
63
63
|
}
|
|
64
64
|
return await jsonToCollection(data);
|
|
65
65
|
}
|
|
66
|
-
function createItems(openapiData) {
|
|
67
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o;
|
|
66
|
+
function createItems(openapiData, sidebarOptions) {
|
|
67
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
|
|
68
68
|
// TODO: Find a better way to handle this
|
|
69
69
|
let items = [];
|
|
70
|
-
|
|
70
|
+
if ((sidebarOptions === null || sidebarOptions === void 0 ? void 0 : sidebarOptions.categoryLinkSource) === "tag") {
|
|
71
|
+
// Only create an tag pages if categoryLinkSource set to tag.
|
|
72
|
+
const tags = (_a = openapiData.tags) !== null && _a !== void 0 ? _a : [];
|
|
73
|
+
// eslint-disable-next-line array-callback-return
|
|
74
|
+
tags
|
|
75
|
+
.filter((tag) => { var _a; return !((_a = tag.description) === null || _a === void 0 ? void 0 : _a.includes("SchemaDefinition")); })
|
|
76
|
+
// eslint-disable-next-line array-callback-return
|
|
77
|
+
.map((tag) => {
|
|
78
|
+
var _a;
|
|
79
|
+
const description = getTagDisplayName(tag.name, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []);
|
|
80
|
+
const tagId = (0, lodash_1.kebabCase)(tag.name);
|
|
81
|
+
const tagPage = {
|
|
82
|
+
type: "tag",
|
|
83
|
+
id: tagId,
|
|
84
|
+
unversionedId: tagId,
|
|
85
|
+
title: description !== null && description !== void 0 ? description : "",
|
|
86
|
+
description: description !== null && description !== void 0 ? description : "",
|
|
87
|
+
slug: "/" + tagId,
|
|
88
|
+
frontMatter: {},
|
|
89
|
+
tag: {
|
|
90
|
+
...tag,
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
items.push(tagPage);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
71
96
|
if (openapiData.info.description) {
|
|
97
|
+
// Only create an info page if we have a description.
|
|
72
98
|
const infoId = (0, lodash_1.kebabCase)(openapiData.info.title);
|
|
73
99
|
const infoPage = {
|
|
74
100
|
type: "info",
|
|
@@ -80,8 +106,8 @@ function createItems(openapiData) {
|
|
|
80
106
|
frontMatter: {},
|
|
81
107
|
info: {
|
|
82
108
|
...openapiData.info,
|
|
83
|
-
tags: (
|
|
84
|
-
title: (
|
|
109
|
+
tags: (_b = openapiData.tags) === null || _b === void 0 ? void 0 : _b.map((tagName) => { var _a; return getTagDisplayName(tagName.name, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []); }),
|
|
110
|
+
title: (_c = openapiData.info.title) !== null && _c !== void 0 ? _c : "Introduction",
|
|
85
111
|
},
|
|
86
112
|
};
|
|
87
113
|
items.push(infoPage);
|
|
@@ -89,16 +115,16 @@ function createItems(openapiData) {
|
|
|
89
115
|
for (let [path, pathObject] of Object.entries(openapiData.paths)) {
|
|
90
116
|
const { $ref, description, parameters, servers, summary, ...rest } = pathObject;
|
|
91
117
|
for (let [method, operationObject] of Object.entries({ ...rest })) {
|
|
92
|
-
const title = (
|
|
118
|
+
const title = (_e = (_d = operationObject.summary) !== null && _d !== void 0 ? _d : operationObject.operationId) !== null && _e !== void 0 ? _e : "Missing summary";
|
|
93
119
|
if (operationObject.description === undefined) {
|
|
94
120
|
operationObject.description =
|
|
95
|
-
(
|
|
121
|
+
(_g = (_f = operationObject.summary) !== null && _f !== void 0 ? _f : operationObject.operationId) !== null && _g !== void 0 ? _g : "";
|
|
96
122
|
}
|
|
97
123
|
const baseId = (0, lodash_1.kebabCase)(title);
|
|
98
|
-
const servers = (
|
|
99
|
-
const security = (
|
|
124
|
+
const servers = (_j = (_h = operationObject.servers) !== null && _h !== void 0 ? _h : pathObject.servers) !== null && _j !== void 0 ? _j : openapiData.servers;
|
|
125
|
+
const security = (_k = operationObject.security) !== null && _k !== void 0 ? _k : openapiData.security;
|
|
100
126
|
// Add security schemes so we know how to handle security.
|
|
101
|
-
const securitySchemes = (
|
|
127
|
+
const securitySchemes = (_l = openapiData.components) === null || _l === void 0 ? void 0 : _l.securitySchemes;
|
|
102
128
|
// Make sure schemes are lowercase. See: https://github.com/cloud-annotations/docusaurus-plugin-openapi/issues/79
|
|
103
129
|
if (securitySchemes) {
|
|
104
130
|
for (let securityScheme of Object.values(securitySchemes)) {
|
|
@@ -108,7 +134,7 @@ function createItems(openapiData) {
|
|
|
108
134
|
}
|
|
109
135
|
}
|
|
110
136
|
let jsonRequestBodyExample;
|
|
111
|
-
const body = (
|
|
137
|
+
const body = (_o = (_m = operationObject.requestBody) === null || _m === void 0 ? void 0 : _m.content) === null || _o === void 0 ? void 0 : _o["application/json"];
|
|
112
138
|
if (body === null || body === void 0 ? void 0 : body.schema) {
|
|
113
139
|
jsonRequestBodyExample = (0, createExample_1.sampleFromSchema)(body.schema);
|
|
114
140
|
}
|
|
@@ -124,7 +150,7 @@ function createItems(openapiData) {
|
|
|
124
150
|
frontMatter: {},
|
|
125
151
|
api: {
|
|
126
152
|
...defaults,
|
|
127
|
-
tags: (
|
|
153
|
+
tags: (_p = operationObject.tags) === null || _p === void 0 ? void 0 : _p.map((tagName) => { var _a; return getTagDisplayName(tagName, (_a = openapiData.tags) !== null && _a !== void 0 ? _a : []); }),
|
|
128
154
|
method,
|
|
129
155
|
path,
|
|
130
156
|
servers,
|
|
@@ -149,7 +175,7 @@ function bindCollectionToApiItems(items, postmanCollection) {
|
|
|
149
175
|
.getPath({ unresolved: true }) // unresolved returns "/:variableName" instead of "/<type>"
|
|
150
176
|
.replace(/:([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
|
|
151
177
|
const apiItem = items.find((item) => {
|
|
152
|
-
if (item.type === "info") {
|
|
178
|
+
if (item.type === "info" || item.type === "tag") {
|
|
153
179
|
return false;
|
|
154
180
|
}
|
|
155
181
|
return item.api.path === path && item.api.method === method;
|
|
@@ -192,9 +218,9 @@ async function readOpenapiFiles(openapiPath, _options) {
|
|
|
192
218
|
];
|
|
193
219
|
}
|
|
194
220
|
exports.readOpenapiFiles = readOpenapiFiles;
|
|
195
|
-
async function processOpenapiFiles(files) {
|
|
221
|
+
async function processOpenapiFiles(files, sidebarOptions) {
|
|
196
222
|
const promises = files.map(async (file) => {
|
|
197
|
-
const processedFile = await processOpenapiFile(file.data);
|
|
223
|
+
const processedFile = await processOpenapiFile(file.data, sidebarOptions);
|
|
198
224
|
const itemsObjectsArray = processedFile[0].map((item) => ({
|
|
199
225
|
...item,
|
|
200
226
|
}));
|
|
@@ -213,10 +239,10 @@ async function processOpenapiFiles(files) {
|
|
|
213
239
|
return [items, tags];
|
|
214
240
|
}
|
|
215
241
|
exports.processOpenapiFiles = processOpenapiFiles;
|
|
216
|
-
async function processOpenapiFile(openapiDataWithRefs) {
|
|
242
|
+
async function processOpenapiFile(openapiDataWithRefs, sidebarOptions) {
|
|
217
243
|
const openapiData = await resolveRefs(openapiDataWithRefs);
|
|
218
244
|
const postmanCollection = await createPostmanCollection(openapiData);
|
|
219
|
-
const items = createItems(openapiData);
|
|
245
|
+
const items = createItems(openapiData, sidebarOptions);
|
|
220
246
|
bindCollectionToApiItems(items, postmanCollection);
|
|
221
247
|
let tags = [];
|
|
222
248
|
if (openapiData.tags !== undefined) {
|
package/lib/sidebars/index.js
CHANGED
|
@@ -85,12 +85,10 @@ function groupByTags(items, sidebarOptions, options, tags) {
|
|
|
85
85
|
}
|
|
86
86
|
// TODO: perhaps move this into a getLinkConfig() function
|
|
87
87
|
if (tagObject !== undefined && categoryLinkSource === "tag") {
|
|
88
|
-
const
|
|
88
|
+
const tagId = (0, lodash_1.kebabCase)(tagObject.name);
|
|
89
89
|
linkConfig = {
|
|
90
|
-
type: "
|
|
91
|
-
|
|
92
|
-
description: linkDescription,
|
|
93
|
-
slug: "/category/" + (0, lodash_1.kebabCase)(tag),
|
|
90
|
+
type: "doc",
|
|
91
|
+
id: `${basePath}/${tagId}`,
|
|
94
92
|
};
|
|
95
93
|
}
|
|
96
94
|
// Default behavior
|
package/lib/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type Request from "@paloaltonetworks/postman-collection";
|
|
2
|
-
import { InfoObject, OperationObject, SecuritySchemeObject } from "./openapi/types";
|
|
2
|
+
import { InfoObject, OperationObject, 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;
|
|
@@ -16,7 +16,7 @@ export interface APIOptions {
|
|
|
16
16
|
export interface LoadedContent {
|
|
17
17
|
loadedApi: ApiMetadata[];
|
|
18
18
|
}
|
|
19
|
-
export declare type ApiMetadata = ApiPageMetadata | InfoPageMetadata;
|
|
19
|
+
export declare type ApiMetadata = ApiPageMetadata | InfoPageMetadata | TagPageMetadata;
|
|
20
20
|
export interface ApiMetadataBase {
|
|
21
21
|
sidebar?: string;
|
|
22
22
|
previous?: ApiNavLink;
|
|
@@ -53,6 +53,11 @@ export interface InfoPageMetadata extends ApiMetadataBase {
|
|
|
53
53
|
info: ApiInfo;
|
|
54
54
|
markdown?: string;
|
|
55
55
|
}
|
|
56
|
+
export interface TagPageMetadata extends ApiMetadataBase {
|
|
57
|
+
type: "tag";
|
|
58
|
+
tag: TagObject;
|
|
59
|
+
markdown?: string;
|
|
60
|
+
}
|
|
56
61
|
export declare type ApiInfo = InfoObject;
|
|
57
62
|
export interface ApiNavLink {
|
|
58
63
|
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-362",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"openapi",
|
|
@@ -28,18 +28,18 @@
|
|
|
28
28
|
"watch": "tsc --watch"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@docusaurus/module-type-aliases": "2.0.0-beta.
|
|
32
|
-
"@docusaurus/types": "2.0.0-beta.
|
|
31
|
+
"@docusaurus/module-type-aliases": "2.0.0-beta.21",
|
|
32
|
+
"@docusaurus/types": "2.0.0-beta.21",
|
|
33
33
|
"@types/fs-extra": "^9.0.13",
|
|
34
34
|
"@types/json-schema": "^7.0.9",
|
|
35
35
|
"@types/lodash": "^4.14.176",
|
|
36
36
|
"utility-types": "^3.10.0"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@docusaurus/mdx-loader": "2.0.0-beta.
|
|
40
|
-
"@docusaurus/plugin-content-docs": "2.0.0-beta.
|
|
41
|
-
"@docusaurus/utils": "2.0.0-beta.
|
|
42
|
-
"@docusaurus/utils-validation": "2.0.0-beta.
|
|
39
|
+
"@docusaurus/mdx-loader": "2.0.0-beta.21",
|
|
40
|
+
"@docusaurus/plugin-content-docs": "2.0.0-beta.21",
|
|
41
|
+
"@docusaurus/utils": "2.0.0-beta.21",
|
|
42
|
+
"@docusaurus/utils-validation": "2.0.0-beta.21",
|
|
43
43
|
"@paloaltonetworks/openapi-to-postmanv2": "3.1.0-hotfix.1",
|
|
44
44
|
"@paloaltonetworks/postman-collection": "^4.1.0",
|
|
45
45
|
"@types/js-yaml": "^4.0.5",
|
|
@@ -60,5 +60,5 @@
|
|
|
60
60
|
"engines": {
|
|
61
61
|
"node": ">=14"
|
|
62
62
|
},
|
|
63
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "b887778ce634dfbc7f723721ffacef03679cec7e"
|
|
64
64
|
}
|
package/src/index.ts
CHANGED
|
@@ -13,7 +13,7 @@ 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
18
|
import generateSidebarSlice from "./sidebars";
|
|
19
19
|
import type { PluginOptions, LoadedContent, APIOptions } from "./types";
|
|
@@ -32,7 +32,10 @@ export default function pluginOpenAPI(
|
|
|
32
32
|
|
|
33
33
|
try {
|
|
34
34
|
const openapiFiles = await readOpenapiFiles(contentPath, {});
|
|
35
|
-
const [loadedApi, tags] = await processOpenapiFiles(
|
|
35
|
+
const [loadedApi, tags] = await processOpenapiFiles(
|
|
36
|
+
openapiFiles,
|
|
37
|
+
sidebarOptions!
|
|
38
|
+
);
|
|
36
39
|
if (!fs.existsSync(outputDir)) {
|
|
37
40
|
try {
|
|
38
41
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -119,19 +122,43 @@ hide_title: true
|
|
|
119
122
|
import DocCardList from '@theme/DocCardList';
|
|
120
123
|
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
121
124
|
|
|
125
|
+
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
126
|
+
\`\`\`
|
|
127
|
+
`;
|
|
128
|
+
|
|
129
|
+
const tagMdTemplate = template
|
|
130
|
+
? fs.readFileSync(template).toString()
|
|
131
|
+
: `---
|
|
132
|
+
id: {{{id}}}
|
|
133
|
+
title: {{{description}}}
|
|
134
|
+
description: {{{description}}}
|
|
135
|
+
---
|
|
136
|
+
|
|
137
|
+
{{{markdown}}}
|
|
138
|
+
|
|
139
|
+
\`\`\`mdx-code-block
|
|
140
|
+
import DocCardList from '@theme/DocCardList';
|
|
141
|
+
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
142
|
+
|
|
122
143
|
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
123
144
|
\`\`\`
|
|
124
145
|
`;
|
|
125
146
|
|
|
126
147
|
loadedApi.map(async (item) => {
|
|
127
148
|
const markdown =
|
|
128
|
-
item.type === "api"
|
|
149
|
+
item.type === "api"
|
|
150
|
+
? createApiPageMD(item)
|
|
151
|
+
: item.type === "info"
|
|
152
|
+
? createInfoPageMD(item)
|
|
153
|
+
: createTagPageMD(item);
|
|
129
154
|
item.markdown = markdown;
|
|
130
155
|
if (item.type === "api") {
|
|
131
156
|
item.json = JSON.stringify(item.api);
|
|
132
157
|
}
|
|
133
158
|
const view = render(mdTemplate, item);
|
|
134
159
|
const utils = render(infoMdTemplate, item);
|
|
160
|
+
// eslint-disable-next-line testing-library/render-result-naming-convention
|
|
161
|
+
const tagUtils = render(tagMdTemplate, item);
|
|
135
162
|
|
|
136
163
|
if (item.type === "api") {
|
|
137
164
|
if (!fs.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
|
|
@@ -179,8 +206,31 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
179
206
|
}
|
|
180
207
|
}
|
|
181
208
|
}
|
|
209
|
+
|
|
210
|
+
if (item.type === "tag") {
|
|
211
|
+
if (!fs.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
|
|
212
|
+
try {
|
|
213
|
+
fs.writeFileSync(
|
|
214
|
+
`${outputDir}/${item.id}.tag.mdx`,
|
|
215
|
+
tagUtils,
|
|
216
|
+
"utf8"
|
|
217
|
+
);
|
|
218
|
+
console.log(
|
|
219
|
+
chalk.green(
|
|
220
|
+
`Successfully created "${outputDir}/${item.id}.tag.mdx"`
|
|
221
|
+
)
|
|
222
|
+
);
|
|
223
|
+
} catch (err) {
|
|
224
|
+
console.error(
|
|
225
|
+
chalk.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`),
|
|
226
|
+
chalk.yellow(err)
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
182
231
|
return;
|
|
183
232
|
});
|
|
233
|
+
|
|
184
234
|
return;
|
|
185
235
|
} catch (e) {
|
|
186
236
|
console.error(chalk.red(`Loading of api failed for "${contentPath}"`));
|
|
@@ -191,7 +241,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
191
241
|
async function cleanApiDocs(options: APIOptions) {
|
|
192
242
|
const { outputDir } = options;
|
|
193
243
|
const apiDir = path.join(siteDir, outputDir);
|
|
194
|
-
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx"], {
|
|
244
|
+
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
195
245
|
cwd: path.resolve(apiDir),
|
|
196
246
|
});
|
|
197
247
|
const sidebarFile = await Globby(["sidebar.js"], {
|
package/src/markdown/index.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
import { escape } from "lodash";
|
|
9
9
|
|
|
10
10
|
import { ContactObject, LicenseObject } from "../openapi/types";
|
|
11
|
-
import { ApiPageMetadata, InfoPageMetadata } from "../types";
|
|
11
|
+
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
|
|
12
12
|
import { createContactInfo } from "./createContactInfo";
|
|
13
13
|
import { createDeprecationNotice } from "./createDeprecationNotice";
|
|
14
14
|
import { createDescription } from "./createDescription";
|
|
@@ -60,3 +60,7 @@ export function createInfoPageMD({
|
|
|
60
60
|
createLicense(license as LicenseObject),
|
|
61
61
|
]);
|
|
62
62
|
}
|
|
63
|
+
|
|
64
|
+
export function createTagPageMD({ tag: { description } }: TagPageMetadata) {
|
|
65
|
+
return render([createDescription(description)]);
|
|
66
|
+
}
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
|
|
8
10
|
import { SchemaObject } from "./types";
|
|
9
11
|
|
|
10
12
|
interface OASTypeToTypeMap {
|
|
@@ -48,71 +50,78 @@ const primitives: Primitives = {
|
|
|
48
50
|
};
|
|
49
51
|
|
|
50
52
|
export const sampleFromSchema = (schema: SchemaObject = {}): any => {
|
|
51
|
-
|
|
53
|
+
try {
|
|
54
|
+
let { type, example, allOf, properties, items } = schema;
|
|
52
55
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
+
if (example !== undefined) {
|
|
57
|
+
return example;
|
|
58
|
+
}
|
|
56
59
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
if (allOf) {
|
|
61
|
+
// TODO: We are just assuming it will always be an object for now
|
|
62
|
+
let obj: SchemaObject = {
|
|
63
|
+
type: "object",
|
|
64
|
+
properties: {},
|
|
65
|
+
required: [], // NOTE: We shouldn't need to worry about required
|
|
66
|
+
};
|
|
67
|
+
for (let item of allOf) {
|
|
68
|
+
if (item.properties) {
|
|
69
|
+
obj.properties = {
|
|
70
|
+
...obj.properties,
|
|
71
|
+
...item.properties,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
70
74
|
}
|
|
75
|
+
return sampleFromSchema(obj);
|
|
71
76
|
}
|
|
72
|
-
return sampleFromSchema(obj);
|
|
73
|
-
}
|
|
74
77
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
78
|
+
if (!type) {
|
|
79
|
+
if (properties) {
|
|
80
|
+
type = "object";
|
|
81
|
+
} else if (items) {
|
|
82
|
+
type = "array";
|
|
83
|
+
} else {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
82
86
|
}
|
|
83
|
-
}
|
|
84
87
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
if (type === "object") {
|
|
89
|
+
let obj: any = {};
|
|
90
|
+
for (let [name, prop] of Object.entries(properties ?? {})) {
|
|
91
|
+
if (prop.deprecated) {
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
obj[name] = sampleFromSchema(prop);
|
|
90
95
|
}
|
|
91
|
-
obj
|
|
96
|
+
return obj;
|
|
92
97
|
}
|
|
93
|
-
return obj;
|
|
94
|
-
}
|
|
95
98
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
99
|
+
if (type === "array") {
|
|
100
|
+
if (Array.isArray(items?.anyOf)) {
|
|
101
|
+
return items?.anyOf.map((item) => sampleFromSchema(item));
|
|
102
|
+
}
|
|
100
103
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
if (Array.isArray(items?.oneOf)) {
|
|
105
|
+
return items?.oneOf.map((item) => sampleFromSchema(item));
|
|
106
|
+
}
|
|
104
107
|
|
|
105
|
-
|
|
106
|
-
|
|
108
|
+
return [sampleFromSchema(items)];
|
|
109
|
+
}
|
|
107
110
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
+
if (schema.enum) {
|
|
112
|
+
if (schema.default) {
|
|
113
|
+
return schema.default;
|
|
114
|
+
}
|
|
115
|
+
return normalizeArray(schema.enum)[0];
|
|
111
116
|
}
|
|
112
|
-
return normalizeArray(schema.enum)[0];
|
|
113
|
-
}
|
|
114
117
|
|
|
115
|
-
|
|
118
|
+
return primitive(schema);
|
|
119
|
+
} catch (err) {
|
|
120
|
+
console.error(
|
|
121
|
+
chalk.yellow("WARNING: failed to create example from schema object:", err)
|
|
122
|
+
);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
116
125
|
};
|
|
117
126
|
|
|
118
127
|
function primitive(schema: SchemaObject = {}) {
|
package/src/openapi/openapi.ts
CHANGED
|
@@ -17,7 +17,13 @@ import yaml from "js-yaml";
|
|
|
17
17
|
import JsonRefs from "json-refs";
|
|
18
18
|
import { kebabCase } from "lodash";
|
|
19
19
|
|
|
20
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
ApiMetadata,
|
|
22
|
+
ApiPageMetadata,
|
|
23
|
+
InfoPageMetadata,
|
|
24
|
+
SidebarOptions,
|
|
25
|
+
TagPageMetadata,
|
|
26
|
+
} from "../types";
|
|
21
27
|
import { sampleFromSchema } from "./createExample";
|
|
22
28
|
import { OpenApiObject, OpenApiObjectWithRef, TagObject } from "./types";
|
|
23
29
|
|
|
@@ -75,12 +81,44 @@ async function createPostmanCollection(
|
|
|
75
81
|
|
|
76
82
|
type PartialPage<T> = Omit<T, "permalink" | "source" | "sourceDirName">;
|
|
77
83
|
|
|
78
|
-
function createItems(
|
|
84
|
+
function createItems(
|
|
85
|
+
openapiData: OpenApiObject,
|
|
86
|
+
sidebarOptions: SidebarOptions
|
|
87
|
+
): ApiMetadata[] {
|
|
79
88
|
// TODO: Find a better way to handle this
|
|
80
89
|
let items: PartialPage<ApiMetadata>[] = [];
|
|
81
90
|
|
|
82
|
-
|
|
91
|
+
if (sidebarOptions?.categoryLinkSource === "tag") {
|
|
92
|
+
// Only create an tag pages if categoryLinkSource set to tag.
|
|
93
|
+
const tags: TagObject[] = openapiData.tags ?? [];
|
|
94
|
+
// eslint-disable-next-line array-callback-return
|
|
95
|
+
tags
|
|
96
|
+
.filter((tag) => !tag.description?.includes("SchemaDefinition"))
|
|
97
|
+
// eslint-disable-next-line array-callback-return
|
|
98
|
+
.map((tag) => {
|
|
99
|
+
const description = getTagDisplayName(
|
|
100
|
+
tag.name!,
|
|
101
|
+
openapiData.tags ?? []
|
|
102
|
+
);
|
|
103
|
+
const tagId = kebabCase(tag.name);
|
|
104
|
+
const tagPage: PartialPage<TagPageMetadata> = {
|
|
105
|
+
type: "tag",
|
|
106
|
+
id: tagId,
|
|
107
|
+
unversionedId: tagId,
|
|
108
|
+
title: description ?? "",
|
|
109
|
+
description: description ?? "",
|
|
110
|
+
slug: "/" + tagId,
|
|
111
|
+
frontMatter: {},
|
|
112
|
+
tag: {
|
|
113
|
+
...tag,
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
items.push(tagPage);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
83
120
|
if (openapiData.info.description) {
|
|
121
|
+
// Only create an info page if we have a description.
|
|
84
122
|
const infoId = kebabCase(openapiData.info.title);
|
|
85
123
|
const infoPage: PartialPage<InfoPageMetadata> = {
|
|
86
124
|
type: "info",
|
|
@@ -186,7 +224,7 @@ function bindCollectionToApiItems(
|
|
|
186
224
|
.replace(/:([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
|
|
187
225
|
|
|
188
226
|
const apiItem = items.find((item) => {
|
|
189
|
-
if (item.type === "info") {
|
|
227
|
+
if (item.type === "info" || item.type === "tag") {
|
|
190
228
|
return false;
|
|
191
229
|
}
|
|
192
230
|
return item.api.path === path && item.api.method === method;
|
|
@@ -248,10 +286,11 @@ export async function readOpenapiFiles(
|
|
|
248
286
|
}
|
|
249
287
|
|
|
250
288
|
export async function processOpenapiFiles(
|
|
251
|
-
files: OpenApiFiles[]
|
|
289
|
+
files: OpenApiFiles[],
|
|
290
|
+
sidebarOptions: SidebarOptions
|
|
252
291
|
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
253
292
|
const promises = files.map(async (file) => {
|
|
254
|
-
const processedFile = await processOpenapiFile(file.data);
|
|
293
|
+
const processedFile = await processOpenapiFile(file.data, sidebarOptions);
|
|
255
294
|
const itemsObjectsArray = processedFile[0].map((item) => ({
|
|
256
295
|
...item,
|
|
257
296
|
}));
|
|
@@ -271,11 +310,12 @@ export async function processOpenapiFiles(
|
|
|
271
310
|
}
|
|
272
311
|
|
|
273
312
|
export async function processOpenapiFile(
|
|
274
|
-
openapiDataWithRefs: OpenApiObjectWithRef
|
|
313
|
+
openapiDataWithRefs: OpenApiObjectWithRef,
|
|
314
|
+
sidebarOptions: SidebarOptions
|
|
275
315
|
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
276
316
|
const openapiData = await resolveRefs(openapiDataWithRefs);
|
|
277
317
|
const postmanCollection = await createPostmanCollection(openapiData);
|
|
278
|
-
const items = createItems(openapiData);
|
|
318
|
+
const items = createItems(openapiData, sidebarOptions);
|
|
279
319
|
|
|
280
320
|
bindCollectionToApiItems(items, postmanCollection);
|
|
281
321
|
|
package/src/sidebars/index.ts
CHANGED
|
@@ -122,12 +122,10 @@ function groupByTags(
|
|
|
122
122
|
|
|
123
123
|
// TODO: perhaps move this into a getLinkConfig() function
|
|
124
124
|
if (tagObject !== undefined && categoryLinkSource === "tag") {
|
|
125
|
-
const
|
|
125
|
+
const tagId = kebabCase(tagObject.name);
|
|
126
126
|
linkConfig = {
|
|
127
|
-
type: "
|
|
128
|
-
|
|
129
|
-
description: linkDescription,
|
|
130
|
-
slug: "/category/" + kebabCase(tag),
|
|
127
|
+
type: "doc",
|
|
128
|
+
id: `${basePath}/${tagId}`,
|
|
131
129
|
} as SidebarItemCategoryLinkConfig;
|
|
132
130
|
}
|
|
133
131
|
|
package/src/types.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
InfoObject,
|
|
12
12
|
OperationObject,
|
|
13
13
|
SecuritySchemeObject,
|
|
14
|
+
TagObject,
|
|
14
15
|
} from "./openapi/types";
|
|
15
16
|
|
|
16
17
|
export type {
|
|
@@ -38,7 +39,7 @@ export interface LoadedContent {
|
|
|
38
39
|
// loadedDocs: DocPageMetadata[]; TODO: cleanup
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
export type ApiMetadata = ApiPageMetadata | InfoPageMetadata;
|
|
42
|
+
export type ApiMetadata = ApiPageMetadata | InfoPageMetadata | TagPageMetadata;
|
|
42
43
|
|
|
43
44
|
export interface ApiMetadataBase {
|
|
44
45
|
sidebar?: string;
|
|
@@ -81,6 +82,12 @@ export interface InfoPageMetadata extends ApiMetadataBase {
|
|
|
81
82
|
markdown?: string;
|
|
82
83
|
}
|
|
83
84
|
|
|
85
|
+
export interface TagPageMetadata extends ApiMetadataBase {
|
|
86
|
+
type: "tag";
|
|
87
|
+
tag: TagObject;
|
|
88
|
+
markdown?: string;
|
|
89
|
+
}
|
|
90
|
+
|
|
84
91
|
export type ApiInfo = InfoObject;
|
|
85
92
|
|
|
86
93
|
export interface ApiNavLink {
|