docusaurus-plugin-openapi-docs 1.0.2 → 1.0.3
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 +2 -2
- package/lib/index.d.ts +1 -0
- package/lib/index.js +50 -4
- package/lib/markdown/createAuthentication.d.ts +2 -0
- package/lib/markdown/createAuthentication.js +139 -0
- package/lib/markdown/index.d.ts +3 -2
- package/lib/markdown/index.js +10 -2
- package/lib/openapi/createExample.js +59 -49
- package/lib/openapi/openapi.d.ts +3 -3
- package/lib/openapi/openapi.js +71 -41
- package/lib/openapi/openapi.test.js +0 -6
- package/lib/openapi/utils/loadAndBundleSpec.d.ts +3 -0
- package/lib/openapi/utils/loadAndBundleSpec.js +44 -0
- package/lib/openapi/utils/types.d.ts +306 -0
- package/lib/openapi/utils/types.js +8 -0
- package/lib/sidebars/index.js +26 -22
- package/lib/types.d.ts +12 -2
- package/package.json +10 -8
- package/src/index.ts +66 -5
- package/src/markdown/createAuthentication.ts +160 -0
- package/src/markdown/index.ts +15 -2
- package/src/openapi/createExample.ts +59 -50
- package/src/openapi/openapi.test.ts +0 -6
- package/src/openapi/openapi.ts +85 -39
- package/src/openapi/utils/loadAndBundleSpec.ts +62 -0
- package/src/openapi/utils/types.ts +303 -0
- package/src/sidebars/index.ts +29 -22
- package/src/types.ts +13 -1
- package/src/openapi/__fixtures__/examples/yogurtstore/_category_.json +0 -4
- package/src/openapi/__fixtures__/examples/yogurtstore/froyo.yaml +0 -13
- package/src/openapi/__fixtures__/examples/yogurtstore/nested/nested.yaml +0 -13
package/src/openapi/openapi.ts
CHANGED
|
@@ -13,13 +13,20 @@ import sdk from "@paloaltonetworks/postman-collection";
|
|
|
13
13
|
import Collection from "@paloaltonetworks/postman-collection";
|
|
14
14
|
import chalk from "chalk";
|
|
15
15
|
import fs from "fs-extra";
|
|
16
|
-
import yaml from "js-yaml";
|
|
17
16
|
import JsonRefs from "json-refs";
|
|
18
17
|
import { kebabCase } from "lodash";
|
|
19
18
|
|
|
20
|
-
import {
|
|
19
|
+
import { isURL } from "../index";
|
|
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";
|
|
29
|
+
import { loadAndBundleSpec } from "./utils/loadAndBundleSpec";
|
|
23
30
|
|
|
24
31
|
/**
|
|
25
32
|
* Finds any reference objects in the OpenAPI definition and resolves them to a finalized value.
|
|
@@ -75,13 +82,45 @@ async function createPostmanCollection(
|
|
|
75
82
|
|
|
76
83
|
type PartialPage<T> = Omit<T, "permalink" | "source" | "sourceDirName">;
|
|
77
84
|
|
|
78
|
-
function createItems(
|
|
85
|
+
function createItems(
|
|
86
|
+
openapiData: OpenApiObject,
|
|
87
|
+
sidebarOptions: SidebarOptions
|
|
88
|
+
): ApiMetadata[] {
|
|
79
89
|
// TODO: Find a better way to handle this
|
|
80
90
|
let items: PartialPage<ApiMetadata>[] = [];
|
|
91
|
+
const infoId = kebabCase(openapiData.info.title);
|
|
92
|
+
|
|
93
|
+
if (sidebarOptions?.categoryLinkSource === "tag") {
|
|
94
|
+
// Only create an tag pages if categoryLinkSource set to tag.
|
|
95
|
+
const tags: TagObject[] = openapiData.tags ?? [];
|
|
96
|
+
// eslint-disable-next-line array-callback-return
|
|
97
|
+
tags
|
|
98
|
+
.filter((tag) => !tag.description?.includes("SchemaDefinition"))
|
|
99
|
+
// eslint-disable-next-line array-callback-return
|
|
100
|
+
.map((tag) => {
|
|
101
|
+
const description = getTagDisplayName(
|
|
102
|
+
tag.name!,
|
|
103
|
+
openapiData.tags ?? []
|
|
104
|
+
);
|
|
105
|
+
const tagId = kebabCase(tag.name);
|
|
106
|
+
const tagPage: PartialPage<TagPageMetadata> = {
|
|
107
|
+
type: "tag",
|
|
108
|
+
id: tagId,
|
|
109
|
+
unversionedId: tagId,
|
|
110
|
+
title: description ?? "",
|
|
111
|
+
description: description ?? "",
|
|
112
|
+
slug: "/" + tagId,
|
|
113
|
+
frontMatter: {},
|
|
114
|
+
tag: {
|
|
115
|
+
...tag,
|
|
116
|
+
},
|
|
117
|
+
};
|
|
118
|
+
items.push(tagPage);
|
|
119
|
+
});
|
|
120
|
+
}
|
|
81
121
|
|
|
82
|
-
// Only create an info page if we have a description.
|
|
83
122
|
if (openapiData.info.description) {
|
|
84
|
-
|
|
123
|
+
// Only create an info page if we have a description.
|
|
85
124
|
const infoPage: PartialPage<InfoPageMetadata> = {
|
|
86
125
|
type: "info",
|
|
87
126
|
id: infoId,
|
|
@@ -90,6 +129,7 @@ function createItems(openapiData: OpenApiObject): ApiMetadata[] {
|
|
|
90
129
|
description: openapiData.info.description,
|
|
91
130
|
slug: "/" + infoId,
|
|
92
131
|
frontMatter: {},
|
|
132
|
+
securitySchemes: openapiData.components?.securitySchemes,
|
|
93
133
|
info: {
|
|
94
134
|
...openapiData.info,
|
|
95
135
|
tags: openapiData.tags?.map((tagName) =>
|
|
@@ -145,6 +185,7 @@ function createItems(openapiData: OpenApiObject): ApiMetadata[] {
|
|
|
145
185
|
const apiPage: PartialPage<ApiPageMetadata> = {
|
|
146
186
|
type: "api",
|
|
147
187
|
id: baseId,
|
|
188
|
+
infoId: infoId ?? "",
|
|
148
189
|
unversionedId: baseId,
|
|
149
190
|
title: title,
|
|
150
191
|
description: description ?? "",
|
|
@@ -186,7 +227,7 @@ function bindCollectionToApiItems(
|
|
|
186
227
|
.replace(/:([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
|
|
187
228
|
|
|
188
229
|
const apiItem = items.find((item) => {
|
|
189
|
-
if (item.type === "info") {
|
|
230
|
+
if (item.type === "info" || item.type === "tag") {
|
|
190
231
|
return false;
|
|
191
232
|
}
|
|
192
233
|
return item.api.path === path && item.api.method === method;
|
|
@@ -208,36 +249,39 @@ export async function readOpenapiFiles(
|
|
|
208
249
|
openapiPath: string,
|
|
209
250
|
_options: {}
|
|
210
251
|
): Promise<OpenApiFiles[]> {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
sources.
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
252
|
+
if (!isURL(openapiPath)) {
|
|
253
|
+
const stat = await fs.lstat(openapiPath);
|
|
254
|
+
if (stat.isDirectory()) {
|
|
255
|
+
console.warn(
|
|
256
|
+
chalk.yellow(
|
|
257
|
+
"WARNING: Loading a directory of OpenAPI definitions is experimental and subject to unannounced breaking changes."
|
|
258
|
+
)
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
// TODO: Add config for inlcude/ignore
|
|
262
|
+
const allFiles = await Globby(["**/*.{json,yaml,yml}"], {
|
|
263
|
+
cwd: openapiPath,
|
|
264
|
+
ignore: GlobExcludeDefault,
|
|
265
|
+
deep: 1,
|
|
266
|
+
});
|
|
267
|
+
const sources = allFiles.filter((x) => !x.includes("_category_")); // todo: regex exclude?
|
|
268
|
+
return Promise.all(
|
|
269
|
+
sources.map(async (source) => {
|
|
270
|
+
// TODO: make a function for this
|
|
271
|
+
const fullPath = path.join(openapiPath, source);
|
|
272
|
+
const data = (await loadAndBundleSpec(
|
|
273
|
+
fullPath
|
|
274
|
+
)) as OpenApiObjectWithRef;
|
|
275
|
+
return {
|
|
276
|
+
source: fullPath, // This will be aliased in process.
|
|
277
|
+
sourceDirName: path.dirname(source),
|
|
278
|
+
data,
|
|
279
|
+
};
|
|
280
|
+
})
|
|
281
|
+
);
|
|
282
|
+
}
|
|
238
283
|
}
|
|
239
|
-
const
|
|
240
|
-
const data = yaml.load(openapiString) as OpenApiObjectWithRef;
|
|
284
|
+
const data = (await loadAndBundleSpec(openapiPath)) as OpenApiObjectWithRef;
|
|
241
285
|
return [
|
|
242
286
|
{
|
|
243
287
|
source: openapiPath, // This will be aliased in process.
|
|
@@ -248,10 +292,11 @@ export async function readOpenapiFiles(
|
|
|
248
292
|
}
|
|
249
293
|
|
|
250
294
|
export async function processOpenapiFiles(
|
|
251
|
-
files: OpenApiFiles[]
|
|
295
|
+
files: OpenApiFiles[],
|
|
296
|
+
sidebarOptions: SidebarOptions
|
|
252
297
|
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
253
298
|
const promises = files.map(async (file) => {
|
|
254
|
-
const processedFile = await processOpenapiFile(file.data);
|
|
299
|
+
const processedFile = await processOpenapiFile(file.data, sidebarOptions);
|
|
255
300
|
const itemsObjectsArray = processedFile[0].map((item) => ({
|
|
256
301
|
...item,
|
|
257
302
|
}));
|
|
@@ -271,11 +316,12 @@ export async function processOpenapiFiles(
|
|
|
271
316
|
}
|
|
272
317
|
|
|
273
318
|
export async function processOpenapiFile(
|
|
274
|
-
openapiDataWithRefs: OpenApiObjectWithRef
|
|
319
|
+
openapiDataWithRefs: OpenApiObjectWithRef,
|
|
320
|
+
sidebarOptions: SidebarOptions
|
|
275
321
|
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
276
322
|
const openapiData = await resolveRefs(openapiDataWithRefs);
|
|
277
323
|
const postmanCollection = await createPostmanCollection(openapiData);
|
|
278
|
-
const items = createItems(openapiData);
|
|
324
|
+
const items = createItems(openapiData, sidebarOptions);
|
|
279
325
|
|
|
280
326
|
bindCollectionToApiItems(items, postmanCollection);
|
|
281
327
|
|
|
@@ -0,0 +1,62 @@
|
|
|
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
|
+
// @ts-nocheck
|
|
9
|
+
|
|
10
|
+
import type { Source, Document } from "@redocly/openapi-core";
|
|
11
|
+
import { bundle } from "@redocly/openapi-core/lib/bundle";
|
|
12
|
+
import type { ResolvedConfig } from "@redocly/openapi-core/lib/config";
|
|
13
|
+
import { Config } from "@redocly/openapi-core/lib/config/config";
|
|
14
|
+
import { convertObj } from "swagger2openapi";
|
|
15
|
+
|
|
16
|
+
import { OpenAPISpec } from "./types";
|
|
17
|
+
|
|
18
|
+
export async function loadAndBundleSpec(
|
|
19
|
+
specUrlOrObject: object | string
|
|
20
|
+
): Promise<OpenAPISpec> {
|
|
21
|
+
const config = new Config({} as ResolvedConfig);
|
|
22
|
+
const bundleOpts = {
|
|
23
|
+
config,
|
|
24
|
+
base: process.cwd(),
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (typeof specUrlOrObject === "object" && specUrlOrObject !== null) {
|
|
28
|
+
bundleOpts["doc"] = {
|
|
29
|
+
source: { absoluteRef: "" } as Source,
|
|
30
|
+
parsed: specUrlOrObject,
|
|
31
|
+
} as Document;
|
|
32
|
+
} else {
|
|
33
|
+
bundleOpts["ref"] = specUrlOrObject;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// Force dereference ?
|
|
37
|
+
// bundleOpts["dereference"] = true;
|
|
38
|
+
|
|
39
|
+
const {
|
|
40
|
+
bundle: { parsed },
|
|
41
|
+
} = await bundle(bundleOpts);
|
|
42
|
+
return parsed.swagger !== undefined ? convertSwagger2OpenAPI(parsed) : parsed;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function convertSwagger2OpenAPI(spec: any): Promise<OpenAPISpec> {
|
|
46
|
+
console.warn(
|
|
47
|
+
"[ReDoc Compatibility mode]: Converting OpenAPI 2.0 to OpenAPI 3.0"
|
|
48
|
+
);
|
|
49
|
+
return new Promise<OpenAPISpec>((resolve, reject) =>
|
|
50
|
+
convertObj(
|
|
51
|
+
spec,
|
|
52
|
+
{ patch: true, warnOnly: true, text: "{}", anchors: true },
|
|
53
|
+
(err, res) => {
|
|
54
|
+
// TODO: log any warnings
|
|
55
|
+
if (err) {
|
|
56
|
+
return reject(err);
|
|
57
|
+
}
|
|
58
|
+
resolve(res && (res.openapi as any));
|
|
59
|
+
}
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
}
|
|
@@ -0,0 +1,303 @@
|
|
|
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
|
+
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
|
|
9
|
+
|
|
10
|
+
export interface OpenAPISpec {
|
|
11
|
+
openapi: string;
|
|
12
|
+
info: OpenAPIInfo;
|
|
13
|
+
servers?: OpenAPIServer[];
|
|
14
|
+
paths: OpenAPIPaths;
|
|
15
|
+
components?: OpenAPIComponents;
|
|
16
|
+
security?: OpenAPISecurityRequirement[];
|
|
17
|
+
tags?: OpenAPITag[];
|
|
18
|
+
externalDocs?: OpenAPIExternalDocumentation;
|
|
19
|
+
"x-webhooks"?: OpenAPIPaths;
|
|
20
|
+
webhooks?: OpenAPIPaths;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface OpenAPIInfo {
|
|
24
|
+
title: string;
|
|
25
|
+
version: string;
|
|
26
|
+
|
|
27
|
+
description?: string;
|
|
28
|
+
summary?: string;
|
|
29
|
+
termsOfService?: string;
|
|
30
|
+
contact?: OpenAPIContact;
|
|
31
|
+
license?: OpenAPILicense;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface OpenAPIServer {
|
|
35
|
+
url: string;
|
|
36
|
+
description?: string;
|
|
37
|
+
variables?: { [name: string]: OpenAPIServerVariable };
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface OpenAPIServerVariable {
|
|
41
|
+
enum?: string[];
|
|
42
|
+
default: string;
|
|
43
|
+
description?: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface OpenAPIPaths {
|
|
47
|
+
[path: string]: OpenAPIPath;
|
|
48
|
+
}
|
|
49
|
+
export interface OpenAPIRef {
|
|
50
|
+
$ref: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export type Referenced<T> = OpenAPIRef | T;
|
|
54
|
+
|
|
55
|
+
export interface OpenAPIPath {
|
|
56
|
+
summary?: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
get?: OpenAPIOperation;
|
|
59
|
+
put?: OpenAPIOperation;
|
|
60
|
+
post?: OpenAPIOperation;
|
|
61
|
+
delete?: OpenAPIOperation;
|
|
62
|
+
options?: OpenAPIOperation;
|
|
63
|
+
head?: OpenAPIOperation;
|
|
64
|
+
patch?: OpenAPIOperation;
|
|
65
|
+
trace?: OpenAPIOperation;
|
|
66
|
+
servers?: OpenAPIServer[];
|
|
67
|
+
parameters?: Array<Referenced<OpenAPIParameter>>;
|
|
68
|
+
$ref?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface OpenAPIXCodeSample {
|
|
72
|
+
lang: string;
|
|
73
|
+
label?: string;
|
|
74
|
+
source: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface OpenAPIOperation {
|
|
78
|
+
tags?: string[];
|
|
79
|
+
summary?: string;
|
|
80
|
+
description?: string;
|
|
81
|
+
externalDocs?: OpenAPIExternalDocumentation;
|
|
82
|
+
operationId?: string;
|
|
83
|
+
parameters?: Array<Referenced<OpenAPIParameter>>;
|
|
84
|
+
requestBody?: Referenced<OpenAPIRequestBody>;
|
|
85
|
+
responses: OpenAPIResponses;
|
|
86
|
+
callbacks?: { [name: string]: Referenced<OpenAPICallback> };
|
|
87
|
+
deprecated?: boolean;
|
|
88
|
+
security?: OpenAPISecurityRequirement[];
|
|
89
|
+
servers?: OpenAPIServer[];
|
|
90
|
+
"x-codeSamples"?: OpenAPIXCodeSample[];
|
|
91
|
+
"x-code-samples"?: OpenAPIXCodeSample[]; // deprecated
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface OpenAPIParameter {
|
|
95
|
+
name: string;
|
|
96
|
+
in?: OpenAPIParameterLocation;
|
|
97
|
+
description?: string;
|
|
98
|
+
required?: boolean;
|
|
99
|
+
deprecated?: boolean;
|
|
100
|
+
allowEmptyValue?: boolean;
|
|
101
|
+
style?: OpenAPIParameterStyle;
|
|
102
|
+
explode?: boolean;
|
|
103
|
+
allowReserved?: boolean;
|
|
104
|
+
schema?: Referenced<OpenAPISchema>;
|
|
105
|
+
example?: any;
|
|
106
|
+
examples?: { [media: string]: Referenced<OpenAPIExample> };
|
|
107
|
+
content?: { [media: string]: OpenAPIMediaType };
|
|
108
|
+
encoding?: Record<string, OpenAPIEncoding>;
|
|
109
|
+
const?: any;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface OpenAPIExample {
|
|
113
|
+
value: any;
|
|
114
|
+
summary?: string;
|
|
115
|
+
description?: string;
|
|
116
|
+
externalValue?: string;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface OpenAPISchema {
|
|
120
|
+
$ref?: string;
|
|
121
|
+
type?: string | string[];
|
|
122
|
+
properties?: { [name: string]: OpenAPISchema };
|
|
123
|
+
patternProperties?: { [name: string]: OpenAPISchema };
|
|
124
|
+
additionalProperties?: boolean | OpenAPISchema;
|
|
125
|
+
unevaluatedProperties?: boolean | OpenAPISchema;
|
|
126
|
+
description?: string;
|
|
127
|
+
default?: any;
|
|
128
|
+
items?: OpenAPISchema | OpenAPISchema[] | boolean;
|
|
129
|
+
required?: string[];
|
|
130
|
+
readOnly?: boolean;
|
|
131
|
+
writeOnly?: boolean;
|
|
132
|
+
deprecated?: boolean;
|
|
133
|
+
format?: string;
|
|
134
|
+
externalDocs?: OpenAPIExternalDocumentation;
|
|
135
|
+
discriminator?: OpenAPIDiscriminator;
|
|
136
|
+
nullable?: boolean;
|
|
137
|
+
oneOf?: OpenAPISchema[];
|
|
138
|
+
anyOf?: OpenAPISchema[];
|
|
139
|
+
allOf?: OpenAPISchema[];
|
|
140
|
+
not?: OpenAPISchema;
|
|
141
|
+
|
|
142
|
+
title?: string;
|
|
143
|
+
multipleOf?: number;
|
|
144
|
+
maximum?: number;
|
|
145
|
+
exclusiveMaximum?: boolean | number;
|
|
146
|
+
minimum?: number;
|
|
147
|
+
exclusiveMinimum?: boolean | number;
|
|
148
|
+
maxLength?: number;
|
|
149
|
+
minLength?: number;
|
|
150
|
+
pattern?: string;
|
|
151
|
+
maxItems?: number;
|
|
152
|
+
minItems?: number;
|
|
153
|
+
uniqueItems?: boolean;
|
|
154
|
+
maxProperties?: number;
|
|
155
|
+
minProperties?: number;
|
|
156
|
+
enum?: any[];
|
|
157
|
+
example?: any;
|
|
158
|
+
|
|
159
|
+
if?: OpenAPISchema;
|
|
160
|
+
else?: OpenAPISchema;
|
|
161
|
+
then?: OpenAPISchema;
|
|
162
|
+
examples?: any[];
|
|
163
|
+
const?: string;
|
|
164
|
+
contentEncoding?: string;
|
|
165
|
+
contentMediaType?: string;
|
|
166
|
+
prefixItems?: OpenAPISchema[];
|
|
167
|
+
additionalItems?: OpenAPISchema | boolean;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
export interface OpenAPIDiscriminator {
|
|
171
|
+
propertyName: string;
|
|
172
|
+
mapping?: { [name: string]: string };
|
|
173
|
+
"x-explicitMappingOnly"?: boolean;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export interface OpenAPIMediaType {
|
|
177
|
+
schema?: Referenced<OpenAPISchema>;
|
|
178
|
+
example?: any;
|
|
179
|
+
examples?: { [name: string]: Referenced<OpenAPIExample> };
|
|
180
|
+
encoding?: { [field: string]: OpenAPIEncoding };
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface OpenAPIEncoding {
|
|
184
|
+
contentType: string;
|
|
185
|
+
headers?: { [name: string]: Referenced<OpenAPIHeader> };
|
|
186
|
+
style: OpenAPIParameterStyle;
|
|
187
|
+
explode: boolean;
|
|
188
|
+
allowReserved: boolean;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export type OpenAPIParameterLocation = "query" | "header" | "path" | "cookie";
|
|
192
|
+
export type OpenAPIParameterStyle =
|
|
193
|
+
| "matrix"
|
|
194
|
+
| "label"
|
|
195
|
+
| "form"
|
|
196
|
+
| "simple"
|
|
197
|
+
| "spaceDelimited"
|
|
198
|
+
| "pipeDelimited"
|
|
199
|
+
| "deepObject";
|
|
200
|
+
|
|
201
|
+
export interface OpenAPIRequestBody {
|
|
202
|
+
description?: string;
|
|
203
|
+
required?: boolean;
|
|
204
|
+
content: { [mime: string]: OpenAPIMediaType };
|
|
205
|
+
|
|
206
|
+
"x-examples"?: {
|
|
207
|
+
[mime: string]: { [name: string]: Referenced<OpenAPIExample> };
|
|
208
|
+
};
|
|
209
|
+
"x-example"?: { [mime: string]: any };
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface OpenAPIResponses {
|
|
213
|
+
[code: string]: Referenced<OpenAPIResponse>;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export interface OpenAPIResponse
|
|
217
|
+
extends Pick<OpenAPIRequestBody, "description" | "x-examples" | "x-example"> {
|
|
218
|
+
headers?: { [name: string]: Referenced<OpenAPIHeader> };
|
|
219
|
+
links?: { [name: string]: Referenced<OpenAPILink> };
|
|
220
|
+
content?: { [mime: string]: OpenAPIMediaType };
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export interface OpenAPILink {
|
|
224
|
+
$ref?: string;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
export type OpenAPIHeader = Omit<OpenAPIParameter, "in" | "name">;
|
|
228
|
+
|
|
229
|
+
export interface OpenAPICallback {
|
|
230
|
+
[name: string]: OpenAPIPath;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export interface OpenAPIComponents {
|
|
234
|
+
schemas?: { [name: string]: Referenced<OpenAPISchema> };
|
|
235
|
+
responses?: { [name: string]: Referenced<OpenAPIResponse> };
|
|
236
|
+
parameters?: { [name: string]: Referenced<OpenAPIParameter> };
|
|
237
|
+
examples?: { [name: string]: Referenced<OpenAPIExample> };
|
|
238
|
+
requestBodies?: { [name: string]: Referenced<OpenAPIRequestBody> };
|
|
239
|
+
headers?: { [name: string]: Referenced<OpenAPIHeader> };
|
|
240
|
+
securitySchemes?: { [name: string]: Referenced<OpenAPISecurityScheme> };
|
|
241
|
+
links?: { [name: string]: Referenced<OpenAPILink> };
|
|
242
|
+
callbacks?: { [name: string]: Referenced<OpenAPICallback> };
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
export interface OpenAPISecurityRequirement {
|
|
246
|
+
[name: string]: string[];
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export interface OpenAPISecurityScheme {
|
|
250
|
+
type: "apiKey" | "http" | "oauth2" | "openIdConnect";
|
|
251
|
+
description?: string;
|
|
252
|
+
name?: string;
|
|
253
|
+
in?: "query" | "header" | "cookie";
|
|
254
|
+
scheme?: string;
|
|
255
|
+
bearerFormat: string;
|
|
256
|
+
flows: {
|
|
257
|
+
implicit?: {
|
|
258
|
+
refreshUrl?: string;
|
|
259
|
+
scopes: Record<string, string>;
|
|
260
|
+
authorizationUrl: string;
|
|
261
|
+
};
|
|
262
|
+
password?: {
|
|
263
|
+
refreshUrl?: string;
|
|
264
|
+
scopes: Record<string, string>;
|
|
265
|
+
tokenUrl: string;
|
|
266
|
+
};
|
|
267
|
+
clientCredentials?: {
|
|
268
|
+
refreshUrl?: string;
|
|
269
|
+
scopes: Record<string, string>;
|
|
270
|
+
tokenUrl: string;
|
|
271
|
+
};
|
|
272
|
+
authorizationCode?: {
|
|
273
|
+
refreshUrl?: string;
|
|
274
|
+
scopes: Record<string, string>;
|
|
275
|
+
tokenUrl: string;
|
|
276
|
+
};
|
|
277
|
+
};
|
|
278
|
+
openIdConnectUrl?: string;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export interface OpenAPITag {
|
|
282
|
+
name: string;
|
|
283
|
+
description?: string;
|
|
284
|
+
externalDocs?: OpenAPIExternalDocumentation;
|
|
285
|
+
"x-displayName"?: string;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export interface OpenAPIExternalDocumentation {
|
|
289
|
+
description?: string;
|
|
290
|
+
url: string;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export interface OpenAPIContact {
|
|
294
|
+
name?: string;
|
|
295
|
+
url?: string;
|
|
296
|
+
email?: string;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
export interface OpenAPILicense {
|
|
300
|
+
name: string;
|
|
301
|
+
url?: string;
|
|
302
|
+
identifier?: string;
|
|
303
|
+
}
|
package/src/sidebars/index.ts
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import {
|
|
9
9
|
ProcessedSidebar,
|
|
10
|
+
SidebarItemCategory,
|
|
10
11
|
SidebarItemCategoryLinkConfig,
|
|
11
12
|
SidebarItemDoc,
|
|
12
13
|
} from "@docusaurus/plugin-content-docs/src/sidebars/types";
|
|
@@ -99,7 +100,9 @@ function groupByTags(
|
|
|
99
100
|
const tagged = apiTags
|
|
100
101
|
.map((tag) => {
|
|
101
102
|
// Map info object to tag
|
|
102
|
-
const
|
|
103
|
+
const taggedInfoObject = intros.find((i) =>
|
|
104
|
+
i.tags ? i.tags.includes(tag) : undefined
|
|
105
|
+
);
|
|
103
106
|
const tagObject = tags.flat().find(
|
|
104
107
|
(t) =>
|
|
105
108
|
(tag === t.name || tag === t["x-displayName"]) ?? {
|
|
@@ -110,21 +113,19 @@ function groupByTags(
|
|
|
110
113
|
|
|
111
114
|
// TODO: perhaps move this into a getLinkConfig() function
|
|
112
115
|
let linkConfig = undefined;
|
|
113
|
-
if (
|
|
116
|
+
if (taggedInfoObject !== undefined && categoryLinkSource === "info") {
|
|
114
117
|
linkConfig = {
|
|
115
118
|
type: "doc",
|
|
116
|
-
id: `${basePath}/${
|
|
119
|
+
id: `${basePath}/${taggedInfoObject.id}`,
|
|
117
120
|
} as SidebarItemCategoryLinkConfig;
|
|
118
121
|
}
|
|
119
122
|
|
|
120
123
|
// TODO: perhaps move this into a getLinkConfig() function
|
|
121
124
|
if (tagObject !== undefined && categoryLinkSource === "tag") {
|
|
122
|
-
const
|
|
125
|
+
const tagId = kebabCase(tagObject.name);
|
|
123
126
|
linkConfig = {
|
|
124
|
-
type: "
|
|
125
|
-
|
|
126
|
-
description: linkDescription,
|
|
127
|
-
slug: "/category/" + kebabCase(tag),
|
|
127
|
+
type: "doc",
|
|
128
|
+
id: `${basePath}/${tagId}`,
|
|
128
129
|
} as SidebarItemCategoryLinkConfig;
|
|
129
130
|
}
|
|
130
131
|
|
|
@@ -150,18 +151,24 @@ function groupByTags(
|
|
|
150
151
|
})
|
|
151
152
|
.filter((item) => item.items.length > 0); // Filter out any categories with no items.
|
|
152
153
|
|
|
153
|
-
//
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
154
|
+
// Handle items with no tag
|
|
155
|
+
const untaggedItems = apiItems
|
|
156
|
+
.filter(({ api }) => api.tags === undefined || api.tags.length === 0)
|
|
157
|
+
.map(createDocItem);
|
|
158
|
+
let untagged: SidebarItemCategory[] = [];
|
|
159
|
+
if (untaggedItems.length > 0) {
|
|
160
|
+
untagged = [
|
|
161
|
+
{
|
|
162
|
+
type: "category" as const,
|
|
163
|
+
label: "UNTAGGED",
|
|
164
|
+
collapsible: sidebarCollapsible!,
|
|
165
|
+
collapsed: sidebarCollapsed!,
|
|
166
|
+
items: apiItems
|
|
167
|
+
.filter(({ api }) => api.tags === undefined || api.tags.length === 0)
|
|
168
|
+
.map(createDocItem),
|
|
169
|
+
},
|
|
170
|
+
];
|
|
171
|
+
}
|
|
165
172
|
|
|
166
173
|
// Shift root intro doc to top of sidebar
|
|
167
174
|
// TODO: Add input validation for categoryLinkSource options
|
|
@@ -169,7 +176,7 @@ function groupByTags(
|
|
|
169
176
|
tagged.unshift(rootIntroDoc as any);
|
|
170
177
|
}
|
|
171
178
|
|
|
172
|
-
return [...tagged];
|
|
179
|
+
return [...tagged, ...untagged];
|
|
173
180
|
}
|
|
174
181
|
|
|
175
182
|
export default function generateSidebarSlice(
|
|
@@ -179,7 +186,7 @@ export default function generateSidebarSlice(
|
|
|
179
186
|
tags: TagObject[]
|
|
180
187
|
) {
|
|
181
188
|
let sidebarSlice: ProcessedSidebar = [];
|
|
182
|
-
if (sidebarOptions.groupPathsBy === "
|
|
189
|
+
if (sidebarOptions.groupPathsBy === "tag") {
|
|
183
190
|
sidebarSlice = groupByTags(
|
|
184
191
|
api as ApiPageMetadata[],
|
|
185
192
|
sidebarOptions,
|
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;
|
|
@@ -47,6 +48,8 @@ export interface ApiMetadataBase {
|
|
|
47
48
|
//
|
|
48
49
|
id: string; // TODO legacy versioned id => try to remove
|
|
49
50
|
unversionedId: string; // TODO new unversioned id => try to rename to "id"
|
|
51
|
+
infoId?: string;
|
|
52
|
+
infoPath?: string;
|
|
50
53
|
title: string;
|
|
51
54
|
description: string;
|
|
52
55
|
source: string; // @site aliased source => "@site/docs/folder/subFolder/subSubFolder/myDoc.md"
|
|
@@ -79,6 +82,15 @@ export interface InfoPageMetadata extends ApiMetadataBase {
|
|
|
79
82
|
type: "info";
|
|
80
83
|
info: ApiInfo;
|
|
81
84
|
markdown?: string;
|
|
85
|
+
securitySchemes?: {
|
|
86
|
+
[key: string]: SecuritySchemeObject;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export interface TagPageMetadata extends ApiMetadataBase {
|
|
91
|
+
type: "tag";
|
|
92
|
+
tag: TagObject;
|
|
93
|
+
markdown?: string;
|
|
82
94
|
}
|
|
83
95
|
|
|
84
96
|
export type ApiInfo = InfoObject;
|