docusaurus-plugin-openapi-docs 1.0.1 → 1.0.2
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 +7 -6
- package/lib/index.js +32 -7
- package/lib/markdown/createContactInfo.d.ts +2 -0
- package/lib/markdown/createContactInfo.js +49 -0
- package/lib/markdown/createLicense.d.ts +2 -0
- package/lib/markdown/createLicense.js +33 -0
- package/lib/markdown/createSchemaDetails.js +4 -1
- package/lib/markdown/createStatusCodes.js +1 -1
- package/lib/markdown/createTermsOfService.d.ts +1 -0
- package/lib/markdown/createTermsOfService.js +32 -0
- package/lib/markdown/index.d.ts +1 -1
- package/lib/markdown/index.js +8 -2
- package/lib/openapi/openapi.d.ts +4 -3
- package/lib/openapi/openapi.js +35 -21
- package/lib/openapi/types.d.ts +5 -1
- package/lib/sidebars/index.d.ts +2 -1
- package/lib/sidebars/index.js +72 -19
- package/lib/types.d.ts +2 -1
- package/package.json +2 -3
- package/src/index.ts +44 -8
- package/src/markdown/createContactInfo.ts +52 -0
- package/src/markdown/createLicense.ts +34 -0
- package/src/markdown/createSchemaDetails.ts +6 -2
- package/src/markdown/createStatusCodes.ts +1 -1
- package/src/markdown/createTermsOfService.ts +30 -0
- package/src/markdown/index.ts +9 -2
- package/src/openapi/openapi.ts +32 -16
- package/src/openapi/types.ts +5 -1
- package/src/{markdown/createRequestBodyTable.ts → postman-collection.d.ts} +2 -9
- package/src/sidebars/index.ts +90 -20
- package/src/types.ts +2 -2
- package/lib/markdown/createFullWidthTable.d.ts +0 -2
- package/lib/markdown/createFullWidthTable.js +0 -18
- package/lib/markdown/createParamsTable.d.ts +0 -7
- package/lib/markdown/createParamsTable.js +0 -80
- package/lib/markdown/createRequestBodyTable.d.ts +0 -6
- package/lib/markdown/createRequestBodyTable.js +0 -14
- package/lib/markdown/createSchemaTable.d.ts +0 -14
- package/lib/markdown/createSchemaTable.js +0 -217
- package/src/markdown/createFullWidthTable.ts +0 -16
- package/src/markdown/createParamsTable.ts +0 -102
- package/src/markdown/createSchemaTable.ts +0 -275
package/lib/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type Request from "@paloaltonetworks/postman-collection";
|
|
2
2
|
import { InfoObject, OperationObject, SecuritySchemeObject } from "./openapi/types";
|
|
3
3
|
export type { PropSidebarItemCategory, SidebarItemLink, PropSidebar, PropSidebarItem, } from "@docusaurus/plugin-content-docs-types";
|
|
4
4
|
export interface PluginOptions {
|
|
@@ -60,6 +60,7 @@ export interface ApiNavLink {
|
|
|
60
60
|
}
|
|
61
61
|
export interface SidebarOptions {
|
|
62
62
|
groupPathsBy?: string;
|
|
63
|
+
categoryLinkSource?: string;
|
|
63
64
|
customProps?: {
|
|
64
65
|
[key: string]: unknown;
|
|
65
66
|
};
|
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": "1.0.
|
|
4
|
+
"version": "1.0.2",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"openapi",
|
|
@@ -33,7 +33,6 @@
|
|
|
33
33
|
"@types/fs-extra": "^9.0.13",
|
|
34
34
|
"@types/json-schema": "^7.0.9",
|
|
35
35
|
"@types/lodash": "^4.14.176",
|
|
36
|
-
"@types/postman-collection": "^3.5.7",
|
|
37
36
|
"utility-types": "^3.10.0"
|
|
38
37
|
},
|
|
39
38
|
"dependencies": {
|
|
@@ -61,5 +60,5 @@
|
|
|
61
60
|
"engines": {
|
|
62
61
|
"node": ">=14"
|
|
63
62
|
},
|
|
64
|
-
"gitHead": "
|
|
63
|
+
"gitHead": "526f2d10bc187bc7095ac70d5b1453b9b92c114f"
|
|
65
64
|
}
|
package/src/index.ts
CHANGED
|
@@ -32,8 +32,7 @@ export default function pluginOpenAPI(
|
|
|
32
32
|
|
|
33
33
|
try {
|
|
34
34
|
const openapiFiles = await readOpenapiFiles(contentPath, {});
|
|
35
|
-
const loadedApi = await processOpenapiFiles(openapiFiles);
|
|
36
|
-
|
|
35
|
+
const [loadedApi, tags] = await processOpenapiFiles(openapiFiles);
|
|
37
36
|
if (!fs.existsSync(outputDir)) {
|
|
38
37
|
try {
|
|
39
38
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -51,7 +50,8 @@ export default function pluginOpenAPI(
|
|
|
51
50
|
const sidebarSlice = generateSidebarSlice(
|
|
52
51
|
sidebarOptions!, // TODO: find a better way to handle null
|
|
53
52
|
options,
|
|
54
|
-
loadedApi
|
|
53
|
+
loadedApi,
|
|
54
|
+
tags
|
|
55
55
|
);
|
|
56
56
|
|
|
57
57
|
const sidebarSliceTemplate = template
|
|
@@ -81,7 +81,12 @@ export default function pluginOpenAPI(
|
|
|
81
81
|
? fs.readFileSync(template).toString()
|
|
82
82
|
: `---
|
|
83
83
|
id: {{{id}}}
|
|
84
|
+
{{^api}}
|
|
85
|
+
sidebar_label: Introduction
|
|
86
|
+
{{/api}}
|
|
87
|
+
{{#api}}
|
|
84
88
|
sidebar_label: {{{title}}}
|
|
89
|
+
{{/api}}
|
|
85
90
|
{{^api}}
|
|
86
91
|
sidebar_position: 0
|
|
87
92
|
{{/api}}
|
|
@@ -100,6 +105,24 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
100
105
|
{{{markdown}}}
|
|
101
106
|
`;
|
|
102
107
|
|
|
108
|
+
const infoMdTemplate = template
|
|
109
|
+
? fs.readFileSync(template).toString()
|
|
110
|
+
: `---
|
|
111
|
+
id: {{{id}}}
|
|
112
|
+
sidebar_label: {{{title}}}
|
|
113
|
+
hide_title: true
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
{{{markdown}}}
|
|
117
|
+
|
|
118
|
+
\`\`\`mdx-code-block
|
|
119
|
+
import DocCardList from '@theme/DocCardList';
|
|
120
|
+
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
121
|
+
|
|
122
|
+
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
123
|
+
\`\`\`
|
|
124
|
+
`;
|
|
125
|
+
|
|
103
126
|
loadedApi.map(async (item) => {
|
|
104
127
|
const markdown =
|
|
105
128
|
item.type === "api" ? createApiPageMD(item) : createInfoPageMD(item);
|
|
@@ -108,6 +131,7 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
108
131
|
item.json = JSON.stringify(item.api);
|
|
109
132
|
}
|
|
110
133
|
const view = render(mdTemplate, item);
|
|
134
|
+
const utils = render(infoMdTemplate, item);
|
|
111
135
|
|
|
112
136
|
if (item.type === "api") {
|
|
113
137
|
if (!fs.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
|
|
@@ -129,15 +153,27 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
129
153
|
|
|
130
154
|
// TODO: determine if we actually want/need this
|
|
131
155
|
if (item.type === "info") {
|
|
132
|
-
if (!fs.existsSync(`${outputDir}
|
|
156
|
+
if (!fs.existsSync(`${outputDir}/${item.id}.info.mdx`)) {
|
|
133
157
|
try {
|
|
134
|
-
|
|
158
|
+
sidebarOptions?.categoryLinkSource === "info" // Only use utils template if set to "info"
|
|
159
|
+
? fs.writeFileSync(
|
|
160
|
+
`${outputDir}/${item.id}.info.mdx`,
|
|
161
|
+
utils,
|
|
162
|
+
"utf8"
|
|
163
|
+
)
|
|
164
|
+
: fs.writeFileSync(
|
|
165
|
+
`${outputDir}/${item.id}.info.mdx`,
|
|
166
|
+
view,
|
|
167
|
+
"utf8"
|
|
168
|
+
);
|
|
135
169
|
console.log(
|
|
136
|
-
chalk.green(
|
|
170
|
+
chalk.green(
|
|
171
|
+
`Successfully created "${outputDir}/${item.id}.info.mdx"`
|
|
172
|
+
)
|
|
137
173
|
);
|
|
138
174
|
} catch (err) {
|
|
139
175
|
console.error(
|
|
140
|
-
chalk.red(`Failed to write "${outputDir}
|
|
176
|
+
chalk.red(`Failed to write "${outputDir}/${item.id}.info.mdx"`),
|
|
141
177
|
chalk.yellow(err)
|
|
142
178
|
);
|
|
143
179
|
}
|
|
@@ -155,7 +191,7 @@ sidebar_class_name: "{{{api.method}}} api-method"
|
|
|
155
191
|
async function cleanApiDocs(options: APIOptions) {
|
|
156
192
|
const { outputDir } = options;
|
|
157
193
|
const apiDir = path.join(siteDir, outputDir);
|
|
158
|
-
const apiMdxFiles = await Globby(["*.api.mdx"], {
|
|
194
|
+
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx"], {
|
|
159
195
|
cwd: path.resolve(apiDir),
|
|
160
196
|
});
|
|
161
197
|
const sidebarFile = await Globby(["sidebar.js"], {
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Copyright (c) Palo Alto Networks
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
import { ContactObject } from "../openapi/types";
|
|
9
|
+
import { create, guard } from "./utils";
|
|
10
|
+
|
|
11
|
+
export function createContactInfo(contact: ContactObject) {
|
|
12
|
+
if (!contact || !Object.keys(contact).length) return "";
|
|
13
|
+
const { name, url, email } = contact;
|
|
14
|
+
|
|
15
|
+
return create("div", {
|
|
16
|
+
style: {
|
|
17
|
+
display: "flex",
|
|
18
|
+
flexDirection: "column",
|
|
19
|
+
marginBottom: "var(--ifm-paragraph-margin-bottom)",
|
|
20
|
+
},
|
|
21
|
+
children: [
|
|
22
|
+
create("h3", {
|
|
23
|
+
style: {
|
|
24
|
+
marginBottom: "0.25rem",
|
|
25
|
+
},
|
|
26
|
+
children: "Contact",
|
|
27
|
+
}),
|
|
28
|
+
create("span", {
|
|
29
|
+
children: [
|
|
30
|
+
guard(name, () => `${name}: `),
|
|
31
|
+
guard(email, () =>
|
|
32
|
+
create("a", {
|
|
33
|
+
href: `mailto:${email}`,
|
|
34
|
+
children: `${email}`,
|
|
35
|
+
})
|
|
36
|
+
),
|
|
37
|
+
],
|
|
38
|
+
}),
|
|
39
|
+
guard(url, () =>
|
|
40
|
+
create("span", {
|
|
41
|
+
children: [
|
|
42
|
+
"URL: ",
|
|
43
|
+
create("a", {
|
|
44
|
+
href: `${url}`,
|
|
45
|
+
children: `${url}`,
|
|
46
|
+
}),
|
|
47
|
+
],
|
|
48
|
+
})
|
|
49
|
+
),
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Copyright (c) Palo Alto Networks
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
import { LicenseObject } from "../openapi/types";
|
|
9
|
+
import { create, guard } from "./utils";
|
|
10
|
+
|
|
11
|
+
export function createLicense(license: LicenseObject) {
|
|
12
|
+
if (!license || !Object.keys(license).length) return "";
|
|
13
|
+
const { name, url } = license;
|
|
14
|
+
|
|
15
|
+
return create("div", {
|
|
16
|
+
style: {
|
|
17
|
+
marginBottom: "var(--ifm-paragraph-margin-bottom)",
|
|
18
|
+
},
|
|
19
|
+
children: [
|
|
20
|
+
create("h3", {
|
|
21
|
+
style: {
|
|
22
|
+
marginBottom: "0.25rem",
|
|
23
|
+
},
|
|
24
|
+
children: "License",
|
|
25
|
+
}),
|
|
26
|
+
guard(url, () =>
|
|
27
|
+
create("a", {
|
|
28
|
+
href: url,
|
|
29
|
+
children: name ?? url,
|
|
30
|
+
})
|
|
31
|
+
),
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
}
|
|
@@ -242,7 +242,12 @@ interface Props {
|
|
|
242
242
|
}
|
|
243
243
|
|
|
244
244
|
export function createSchemaDetails({ title, body, ...rest }: Props) {
|
|
245
|
-
if (
|
|
245
|
+
if (
|
|
246
|
+
body === undefined ||
|
|
247
|
+
body.content === undefined ||
|
|
248
|
+
Object.keys(body).length === 0 ||
|
|
249
|
+
Object.keys(body.content).length === 0
|
|
250
|
+
) {
|
|
246
251
|
return undefined;
|
|
247
252
|
}
|
|
248
253
|
|
|
@@ -250,7 +255,6 @@ export function createSchemaDetails({ title, body, ...rest }: Props) {
|
|
|
250
255
|
// NOTE: We just pick a random content-type.
|
|
251
256
|
// How common is it to have multiple?
|
|
252
257
|
const randomFirstKey = Object.keys(body.content)[0];
|
|
253
|
-
|
|
254
258
|
const firstBody = body.content[randomFirstKey].schema;
|
|
255
259
|
|
|
256
260
|
if (firstBody === undefined) {
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* ============================================================================
|
|
2
|
+
* Copyright (c) Palo Alto Networks
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
* ========================================================================== */
|
|
7
|
+
|
|
8
|
+
import { create } from "./utils";
|
|
9
|
+
|
|
10
|
+
export function createTermsOfService(termsOfService: string | undefined) {
|
|
11
|
+
if (!termsOfService) return "";
|
|
12
|
+
|
|
13
|
+
return create("div", {
|
|
14
|
+
style: {
|
|
15
|
+
marginBottom: "var(--ifm-paragraph-margin-bottom)",
|
|
16
|
+
},
|
|
17
|
+
children: [
|
|
18
|
+
create("h3", {
|
|
19
|
+
style: {
|
|
20
|
+
marginBottom: "0.25rem",
|
|
21
|
+
},
|
|
22
|
+
children: "Terms of Service",
|
|
23
|
+
}),
|
|
24
|
+
create("a", {
|
|
25
|
+
href: `${termsOfService}`,
|
|
26
|
+
children: termsOfService,
|
|
27
|
+
}),
|
|
28
|
+
],
|
|
29
|
+
});
|
|
30
|
+
}
|
package/src/markdown/index.ts
CHANGED
|
@@ -7,12 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
import { escape } from "lodash";
|
|
9
9
|
|
|
10
|
+
import { ContactObject, LicenseObject } from "../openapi/types";
|
|
10
11
|
import { ApiPageMetadata, InfoPageMetadata } from "../types";
|
|
12
|
+
import { createContactInfo } from "./createContactInfo";
|
|
11
13
|
import { createDeprecationNotice } from "./createDeprecationNotice";
|
|
12
14
|
import { createDescription } from "./createDescription";
|
|
15
|
+
import { createLicense } from "./createLicense";
|
|
13
16
|
import { createParamsDetails } from "./createParamsDetails";
|
|
14
17
|
import { createRequestBodyDetails } from "./createRequestBodyDetails";
|
|
15
18
|
import { createStatusCodes } from "./createStatusCodes";
|
|
19
|
+
import { createTermsOfService } from "./createTermsOfService";
|
|
16
20
|
import { createVersionBadge } from "./createVersionBadge";
|
|
17
21
|
import { render } from "./utils";
|
|
18
22
|
|
|
@@ -30,7 +34,7 @@ export function createApiPageMD({
|
|
|
30
34
|
return render([
|
|
31
35
|
`import ParamsItem from "@theme/ParamsItem";\n`,
|
|
32
36
|
`import SchemaItem from "@theme/SchemaItem"\n`,
|
|
33
|
-
`import
|
|
37
|
+
`import ApiTabs from "@theme/ApiTabs";\n`,
|
|
34
38
|
`import TabItem from "@theme/TabItem";\n\n`,
|
|
35
39
|
`## ${escape(title)}\n\n`,
|
|
36
40
|
createDeprecationNotice({ deprecated, description: deprecatedDescription }),
|
|
@@ -45,11 +49,14 @@ export function createApiPageMD({
|
|
|
45
49
|
}
|
|
46
50
|
|
|
47
51
|
export function createInfoPageMD({
|
|
48
|
-
info: { title, version, description },
|
|
52
|
+
info: { title, version, description, contact, license, termsOfService },
|
|
49
53
|
}: InfoPageMetadata) {
|
|
50
54
|
return render([
|
|
51
55
|
createVersionBadge(version),
|
|
52
56
|
`# ${escape(title)}\n\n`,
|
|
53
57
|
createDescription(description),
|
|
58
|
+
createContactInfo(contact as ContactObject),
|
|
59
|
+
createTermsOfService(termsOfService),
|
|
60
|
+
createLicense(license as LicenseObject),
|
|
54
61
|
]);
|
|
55
62
|
}
|
package/src/openapi/openapi.ts
CHANGED
|
@@ -9,8 +9,8 @@ import path from "path";
|
|
|
9
9
|
|
|
10
10
|
import { Globby, GlobExcludeDefault } from "@docusaurus/utils";
|
|
11
11
|
import Converter from "@paloaltonetworks/openapi-to-postmanv2";
|
|
12
|
-
|
|
13
|
-
import
|
|
12
|
+
import sdk from "@paloaltonetworks/postman-collection";
|
|
13
|
+
import Collection from "@paloaltonetworks/postman-collection";
|
|
14
14
|
import chalk from "chalk";
|
|
15
15
|
import fs from "fs-extra";
|
|
16
16
|
import yaml from "js-yaml";
|
|
@@ -81,16 +81,20 @@ function createItems(openapiData: OpenApiObject): ApiMetadata[] {
|
|
|
81
81
|
|
|
82
82
|
// Only create an info page if we have a description.
|
|
83
83
|
if (openapiData.info.description) {
|
|
84
|
+
const infoId = kebabCase(openapiData.info.title);
|
|
84
85
|
const infoPage: PartialPage<InfoPageMetadata> = {
|
|
85
86
|
type: "info",
|
|
86
|
-
id:
|
|
87
|
-
unversionedId:
|
|
88
|
-
title:
|
|
87
|
+
id: infoId,
|
|
88
|
+
unversionedId: infoId,
|
|
89
|
+
title: openapiData.info.title,
|
|
89
90
|
description: openapiData.info.description,
|
|
90
|
-
slug: "/
|
|
91
|
+
slug: "/" + infoId,
|
|
91
92
|
frontMatter: {},
|
|
92
93
|
info: {
|
|
93
94
|
...openapiData.info,
|
|
95
|
+
tags: openapiData.tags?.map((tagName) =>
|
|
96
|
+
getTagDisplayName(tagName.name!, openapiData.tags ?? [])
|
|
97
|
+
),
|
|
94
98
|
title: openapiData.info.title ?? "Introduction",
|
|
95
99
|
},
|
|
96
100
|
};
|
|
@@ -175,8 +179,7 @@ function bindCollectionToApiItems(
|
|
|
175
179
|
items: ApiMetadata[],
|
|
176
180
|
postmanCollection: sdk.Collection
|
|
177
181
|
) {
|
|
178
|
-
|
|
179
|
-
postmanCollection.forEachItem((item) => {
|
|
182
|
+
postmanCollection.forEachItem((item: any) => {
|
|
180
183
|
const method = item.request.method.toLowerCase();
|
|
181
184
|
const path = item.request.url
|
|
182
185
|
.getPath({ unresolved: true }) // unresolved returns "/:variableName" instead of "/<type>"
|
|
@@ -246,34 +249,47 @@ export async function readOpenapiFiles(
|
|
|
246
249
|
|
|
247
250
|
export async function processOpenapiFiles(
|
|
248
251
|
files: OpenApiFiles[]
|
|
249
|
-
): Promise<ApiMetadata[]> {
|
|
252
|
+
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
250
253
|
const promises = files.map(async (file) => {
|
|
251
|
-
const
|
|
252
|
-
|
|
254
|
+
const processedFile = await processOpenapiFile(file.data);
|
|
255
|
+
const itemsObjectsArray = processedFile[0].map((item) => ({
|
|
253
256
|
...item,
|
|
254
257
|
}));
|
|
258
|
+
const tags = processedFile[1];
|
|
259
|
+
return [itemsObjectsArray, tags];
|
|
255
260
|
});
|
|
256
261
|
const metadata = await Promise.all(promises);
|
|
257
|
-
const items = metadata
|
|
258
|
-
|
|
262
|
+
const items = metadata
|
|
263
|
+
.map(function (x) {
|
|
264
|
+
return x[0];
|
|
265
|
+
})
|
|
266
|
+
.flat();
|
|
267
|
+
const tags = metadata.map(function (x) {
|
|
268
|
+
return x[1];
|
|
269
|
+
});
|
|
270
|
+
return [items as ApiMetadata[], tags as TagObject[]];
|
|
259
271
|
}
|
|
260
272
|
|
|
261
273
|
export async function processOpenapiFile(
|
|
262
274
|
openapiDataWithRefs: OpenApiObjectWithRef
|
|
263
|
-
): Promise<ApiMetadata[]> {
|
|
275
|
+
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
264
276
|
const openapiData = await resolveRefs(openapiDataWithRefs);
|
|
265
277
|
const postmanCollection = await createPostmanCollection(openapiData);
|
|
266
278
|
const items = createItems(openapiData);
|
|
267
279
|
|
|
268
280
|
bindCollectionToApiItems(items, postmanCollection);
|
|
269
281
|
|
|
270
|
-
|
|
282
|
+
let tags: TagObject[] = [];
|
|
283
|
+
if (openapiData.tags !== undefined) {
|
|
284
|
+
tags = openapiData.tags;
|
|
285
|
+
}
|
|
286
|
+
return [items, tags];
|
|
271
287
|
}
|
|
272
288
|
|
|
273
289
|
// order for picking items as a display name of tags
|
|
274
290
|
const tagDisplayNameProperties = ["x-displayName", "name"] as const;
|
|
275
291
|
|
|
276
|
-
function getTagDisplayName(tagName: string, tags: TagObject[]): string {
|
|
292
|
+
export function getTagDisplayName(tagName: string, tags: TagObject[]): string {
|
|
277
293
|
// find the very own tagObject
|
|
278
294
|
const tagObject = tags.find((tagObject) => tagObject.name === tagName) ?? {
|
|
279
295
|
// if none found, just fake one
|
package/src/openapi/types.ts
CHANGED
|
@@ -40,6 +40,7 @@ export interface InfoObject {
|
|
|
40
40
|
contact?: ContactObject;
|
|
41
41
|
license?: LicenseObject;
|
|
42
42
|
version: string;
|
|
43
|
+
tags?: String[];
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
export interface ContactObject {
|
|
@@ -182,6 +183,7 @@ export interface ParameterObject {
|
|
|
182
183
|
examples?: Map<ExampleObject>;
|
|
183
184
|
//
|
|
184
185
|
content?: Map<MediaTypeObject>;
|
|
186
|
+
param?: Object;
|
|
185
187
|
// ignoring stylings: matrix, label, form, simple, spaceDelimited,
|
|
186
188
|
// pipeDelimited and deepObject
|
|
187
189
|
}
|
|
@@ -293,7 +295,7 @@ export type HeaderObject = Omit<ParameterObject, "name" | "in">;
|
|
|
293
295
|
export type HeaderObjectWithRef = Omit<ParameterObjectWithRef, "name" | "in">;
|
|
294
296
|
|
|
295
297
|
export interface TagObject {
|
|
296
|
-
name
|
|
298
|
+
name?: string;
|
|
297
299
|
description?: string;
|
|
298
300
|
externalDocs?: ExternalDocumentationObject;
|
|
299
301
|
"x-displayName"?: string;
|
|
@@ -399,6 +401,8 @@ export interface HttpSecuritySchemeObject {
|
|
|
399
401
|
description?: string;
|
|
400
402
|
scheme: string;
|
|
401
403
|
bearerFormat?: string;
|
|
404
|
+
name?: string;
|
|
405
|
+
in?: string;
|
|
402
406
|
}
|
|
403
407
|
|
|
404
408
|
export interface Oauth2SecuritySchemeObject {
|
|
@@ -5,13 +5,6 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
interface Props {
|
|
11
|
-
title: string;
|
|
12
|
-
body: any;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export function createRequestBodyTable({ title, body }: Props) {
|
|
16
|
-
return createSchemaTable({ title, body });
|
|
8
|
+
declare module "@paloaltonetworks/postman-collection" {
|
|
9
|
+
export default any;
|
|
17
10
|
}
|
package/src/sidebars/index.ts
CHANGED
|
@@ -7,11 +7,14 @@
|
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
ProcessedSidebar,
|
|
10
|
+
SidebarItemCategoryLinkConfig,
|
|
10
11
|
SidebarItemDoc,
|
|
11
12
|
} from "@docusaurus/plugin-content-docs/src/sidebars/types";
|
|
12
13
|
import clsx from "clsx";
|
|
14
|
+
import { kebabCase } from "lodash";
|
|
13
15
|
import uniq from "lodash/uniq";
|
|
14
16
|
|
|
17
|
+
import { TagObject } from "../openapi/types";
|
|
15
18
|
import type {
|
|
16
19
|
SidebarOptions,
|
|
17
20
|
APIOptions,
|
|
@@ -23,28 +26,37 @@ function isApiItem(item: ApiMetadata): item is ApiMetadata {
|
|
|
23
26
|
return item.type === "api";
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
function isInfoItem(item: ApiMetadata): item is ApiMetadata {
|
|
30
|
+
return item.type === "info";
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
function groupByTags(
|
|
27
34
|
items: ApiPageMetadata[],
|
|
28
35
|
sidebarOptions: SidebarOptions,
|
|
29
|
-
options: APIOptions
|
|
36
|
+
options: APIOptions,
|
|
37
|
+
tags: TagObject[]
|
|
30
38
|
): ProcessedSidebar {
|
|
31
|
-
// TODO: Figure out how to handle these
|
|
32
|
-
// const intros = items.filter(isInfoItem).map((item) => {
|
|
33
|
-
// return {
|
|
34
|
-
// type: "link" as const,
|
|
35
|
-
// label: item.title,
|
|
36
|
-
// href: item.permalink,
|
|
37
|
-
// docId: item.id,
|
|
38
|
-
// };
|
|
39
|
-
// });
|
|
40
|
-
|
|
41
39
|
const { outputDir } = options;
|
|
42
|
-
const {
|
|
40
|
+
const {
|
|
41
|
+
sidebarCollapsed,
|
|
42
|
+
sidebarCollapsible,
|
|
43
|
+
customProps,
|
|
44
|
+
categoryLinkSource,
|
|
45
|
+
} = sidebarOptions;
|
|
43
46
|
|
|
44
47
|
const apiItems = items.filter(isApiItem);
|
|
48
|
+
const infoItems = items.filter(isInfoItem);
|
|
49
|
+
const intros = infoItems.map((item: any) => {
|
|
50
|
+
return {
|
|
51
|
+
id: item.id,
|
|
52
|
+
title: item.title,
|
|
53
|
+
description: item.description,
|
|
54
|
+
tags: item.info.tags,
|
|
55
|
+
};
|
|
56
|
+
});
|
|
45
57
|
|
|
46
58
|
// TODO: make sure we only take the first tag
|
|
47
|
-
const
|
|
59
|
+
const apiTags = uniq(
|
|
48
60
|
apiItems
|
|
49
61
|
.flatMap((item) => item.api.tags)
|
|
50
62
|
.filter((item): item is string => !!item)
|
|
@@ -74,11 +86,61 @@ function groupByTags(
|
|
|
74
86
|
};
|
|
75
87
|
}
|
|
76
88
|
|
|
77
|
-
|
|
89
|
+
let rootIntroDoc = undefined;
|
|
90
|
+
if (infoItems.length === 1) {
|
|
91
|
+
const infoItem = infoItems[0];
|
|
92
|
+
const id = infoItem.id;
|
|
93
|
+
rootIntroDoc = {
|
|
94
|
+
type: "doc" as const,
|
|
95
|
+
id: `${basePath}/${id}`,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const tagged = apiTags
|
|
78
100
|
.map((tag) => {
|
|
101
|
+
// Map info object to tag
|
|
102
|
+
const infoObject = intros.find((i) => i.tags.includes(tag));
|
|
103
|
+
const tagObject = tags.flat().find(
|
|
104
|
+
(t) =>
|
|
105
|
+
(tag === t.name || tag === t["x-displayName"]) ?? {
|
|
106
|
+
name: tag,
|
|
107
|
+
description: `${tag} Index`,
|
|
108
|
+
}
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
// TODO: perhaps move this into a getLinkConfig() function
|
|
112
|
+
let linkConfig = undefined;
|
|
113
|
+
if (infoObject !== undefined && categoryLinkSource === "info") {
|
|
114
|
+
linkConfig = {
|
|
115
|
+
type: "doc",
|
|
116
|
+
id: `${basePath}/${infoObject.id}`,
|
|
117
|
+
} as SidebarItemCategoryLinkConfig;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// TODO: perhaps move this into a getLinkConfig() function
|
|
121
|
+
if (tagObject !== undefined && categoryLinkSource === "tag") {
|
|
122
|
+
const linkDescription = tagObject?.description;
|
|
123
|
+
linkConfig = {
|
|
124
|
+
type: "generated-index" as "generated-index",
|
|
125
|
+
title: tag,
|
|
126
|
+
description: linkDescription,
|
|
127
|
+
slug: "/category/" + kebabCase(tag),
|
|
128
|
+
} as SidebarItemCategoryLinkConfig;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Default behavior
|
|
132
|
+
if (categoryLinkSource === undefined) {
|
|
133
|
+
linkConfig = {
|
|
134
|
+
type: "generated-index" as "generated-index",
|
|
135
|
+
title: tag,
|
|
136
|
+
slug: "/category/" + kebabCase(tag),
|
|
137
|
+
} as SidebarItemCategoryLinkConfig;
|
|
138
|
+
}
|
|
139
|
+
|
|
79
140
|
return {
|
|
80
141
|
type: "category" as const,
|
|
81
142
|
label: tag,
|
|
143
|
+
link: linkConfig,
|
|
82
144
|
collapsible: sidebarCollapsible,
|
|
83
145
|
collapsed: sidebarCollapsed,
|
|
84
146
|
items: apiItems
|
|
@@ -88,33 +150,41 @@ function groupByTags(
|
|
|
88
150
|
})
|
|
89
151
|
.filter((item) => item.items.length > 0); // Filter out any categories with no items.
|
|
90
152
|
|
|
153
|
+
// TODO: determine how we want to handle these
|
|
91
154
|
// const untagged = [
|
|
92
|
-
// // TODO: determine if needed and how
|
|
93
155
|
// {
|
|
94
156
|
// type: "category" as const,
|
|
95
157
|
// label: "UNTAGGED",
|
|
96
|
-
//
|
|
97
|
-
//
|
|
158
|
+
// collapsible: sidebarCollapsible,
|
|
159
|
+
// collapsed: sidebarCollapsed,
|
|
98
160
|
// items: apiItems
|
|
99
|
-
// //@ts-ignore
|
|
100
161
|
// .filter(({ api }) => api.tags === undefined || api.tags.length === 0)
|
|
101
162
|
// .map(createDocItem),
|
|
102
163
|
// },
|
|
103
164
|
// ];
|
|
165
|
+
|
|
166
|
+
// Shift root intro doc to top of sidebar
|
|
167
|
+
// TODO: Add input validation for categoryLinkSource options
|
|
168
|
+
if (rootIntroDoc && categoryLinkSource !== "info") {
|
|
169
|
+
tagged.unshift(rootIntroDoc as any);
|
|
170
|
+
}
|
|
171
|
+
|
|
104
172
|
return [...tagged];
|
|
105
173
|
}
|
|
106
174
|
|
|
107
175
|
export default function generateSidebarSlice(
|
|
108
176
|
sidebarOptions: SidebarOptions,
|
|
109
177
|
options: APIOptions,
|
|
110
|
-
api: ApiMetadata[]
|
|
178
|
+
api: ApiMetadata[],
|
|
179
|
+
tags: TagObject[]
|
|
111
180
|
) {
|
|
112
181
|
let sidebarSlice: ProcessedSidebar = [];
|
|
113
182
|
if (sidebarOptions.groupPathsBy === "tags") {
|
|
114
183
|
sidebarSlice = groupByTags(
|
|
115
184
|
api as ApiPageMetadata[],
|
|
116
185
|
sidebarOptions,
|
|
117
|
-
options
|
|
186
|
+
options,
|
|
187
|
+
tags
|
|
118
188
|
);
|
|
119
189
|
}
|
|
120
190
|
return sidebarSlice;
|
package/src/types.ts
CHANGED
|
@@ -5,8 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
* ========================================================================== */
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
import type { Request } from "@paloaltonetworks/postman-collection";
|
|
8
|
+
import type Request from "@paloaltonetworks/postman-collection";
|
|
10
9
|
|
|
11
10
|
import {
|
|
12
11
|
InfoObject,
|
|
@@ -91,6 +90,7 @@ export interface ApiNavLink {
|
|
|
91
90
|
|
|
92
91
|
export interface SidebarOptions {
|
|
93
92
|
groupPathsBy?: string;
|
|
93
|
+
categoryLinkSource?: string;
|
|
94
94
|
customProps?: { [key: string]: unknown };
|
|
95
95
|
sidebarCollapsible?: boolean;
|
|
96
96
|
sidebarCollapsed?: boolean;
|