docusaurus-plugin-openapi-docs 1.0.0 → 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 +8 -7
- package/lib/index.d.ts +1 -0
- package/lib/index.js +80 -9
- package/lib/markdown/createAuthentication.d.ts +2 -0
- package/lib/markdown/createAuthentication.js +139 -0
- 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 +3 -2
- package/lib/markdown/index.js +17 -3
- package/lib/openapi/createExample.js +59 -49
- package/lib/openapi/openapi.d.ts +5 -4
- package/lib/openapi/openapi.js +94 -50
- package/lib/openapi/openapi.test.js +0 -6
- package/lib/openapi/types.d.ts +5 -1
- 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/{markdown/createRequestBodyTable.js → openapi/utils/types.js} +0 -6
- package/lib/sidebars/index.d.ts +2 -1
- package/lib/sidebars/index.js +87 -30
- package/lib/types.d.ts +14 -3
- package/package.json +19 -11
- package/src/index.ts +108 -11
- package/src/markdown/createAuthentication.ts +160 -0
- 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 +23 -3
- package/src/openapi/createExample.ts +59 -50
- package/src/openapi/openapi.test.ts +0 -6
- package/src/openapi/openapi.ts +115 -53
- package/src/openapi/types.ts +5 -1
- package/src/openapi/utils/loadAndBundleSpec.ts +62 -0
- package/src/openapi/utils/types.ts +303 -0
- package/src/{markdown/createRequestBodyTable.ts → postman-collection.d.ts} +2 -9
- package/src/sidebars/index.ts +108 -31
- package/src/types.ts +15 -3
- 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/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/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
|
@@ -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 = {}) {
|
|
@@ -26,12 +26,6 @@ describe("openapi", () => {
|
|
|
26
26
|
const yaml = results.find((x) => x.source.endsWith("openapi.yaml"));
|
|
27
27
|
expect(yaml).toBeTruthy();
|
|
28
28
|
expect(yaml?.sourceDirName).toBe(".");
|
|
29
|
-
const froyo = results.find((x) => x.source.endsWith("froyo.yaml"));
|
|
30
|
-
expect(froyo).toBeTruthy();
|
|
31
|
-
expect(froyo?.sourceDirName).toBe("yogurtstore");
|
|
32
|
-
const nested = results.find((x) => x.source.endsWith("nested.yaml"));
|
|
33
|
-
expect(nested).toBeTruthy();
|
|
34
|
-
expect(nested?.sourceDirName).toBe("yogurtstore/nested");
|
|
35
29
|
});
|
|
36
30
|
});
|
|
37
31
|
});
|
package/src/openapi/openapi.ts
CHANGED
|
@@ -9,17 +9,24 @@ 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
|
-
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,22 +82,59 @@ 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) {
|
|
123
|
+
// Only create an info page if we have a description.
|
|
84
124
|
const infoPage: PartialPage<InfoPageMetadata> = {
|
|
85
125
|
type: "info",
|
|
86
|
-
id:
|
|
87
|
-
unversionedId:
|
|
88
|
-
title:
|
|
126
|
+
id: infoId,
|
|
127
|
+
unversionedId: infoId,
|
|
128
|
+
title: openapiData.info.title,
|
|
89
129
|
description: openapiData.info.description,
|
|
90
|
-
slug: "/
|
|
130
|
+
slug: "/" + infoId,
|
|
91
131
|
frontMatter: {},
|
|
132
|
+
securitySchemes: openapiData.components?.securitySchemes,
|
|
92
133
|
info: {
|
|
93
134
|
...openapiData.info,
|
|
135
|
+
tags: openapiData.tags?.map((tagName) =>
|
|
136
|
+
getTagDisplayName(tagName.name!, openapiData.tags ?? [])
|
|
137
|
+
),
|
|
94
138
|
title: openapiData.info.title ?? "Introduction",
|
|
95
139
|
},
|
|
96
140
|
};
|
|
@@ -141,6 +185,7 @@ function createItems(openapiData: OpenApiObject): ApiMetadata[] {
|
|
|
141
185
|
const apiPage: PartialPage<ApiPageMetadata> = {
|
|
142
186
|
type: "api",
|
|
143
187
|
id: baseId,
|
|
188
|
+
infoId: infoId ?? "",
|
|
144
189
|
unversionedId: baseId,
|
|
145
190
|
title: title,
|
|
146
191
|
description: description ?? "",
|
|
@@ -175,15 +220,14 @@ function bindCollectionToApiItems(
|
|
|
175
220
|
items: ApiMetadata[],
|
|
176
221
|
postmanCollection: sdk.Collection
|
|
177
222
|
) {
|
|
178
|
-
|
|
179
|
-
postmanCollection.forEachItem((item) => {
|
|
223
|
+
postmanCollection.forEachItem((item: any) => {
|
|
180
224
|
const method = item.request.method.toLowerCase();
|
|
181
225
|
const path = item.request.url
|
|
182
226
|
.getPath({ unresolved: true }) // unresolved returns "/:variableName" instead of "/<type>"
|
|
183
227
|
.replace(/:([a-z0-9-_]+)/gi, "{$1}"); // replace "/:variableName" with "/{variableName}"
|
|
184
228
|
|
|
185
229
|
const apiItem = items.find((item) => {
|
|
186
|
-
if (item.type === "info") {
|
|
230
|
+
if (item.type === "info" || item.type === "tag") {
|
|
187
231
|
return false;
|
|
188
232
|
}
|
|
189
233
|
return item.api.path === path && item.api.method === method;
|
|
@@ -205,36 +249,39 @@ export async function readOpenapiFiles(
|
|
|
205
249
|
openapiPath: string,
|
|
206
250
|
_options: {}
|
|
207
251
|
): Promise<OpenApiFiles[]> {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
sources.
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
+
}
|
|
235
283
|
}
|
|
236
|
-
const
|
|
237
|
-
const data = yaml.load(openapiString) as OpenApiObjectWithRef;
|
|
284
|
+
const data = (await loadAndBundleSpec(openapiPath)) as OpenApiObjectWithRef;
|
|
238
285
|
return [
|
|
239
286
|
{
|
|
240
287
|
source: openapiPath, // This will be aliased in process.
|
|
@@ -245,35 +292,50 @@ export async function readOpenapiFiles(
|
|
|
245
292
|
}
|
|
246
293
|
|
|
247
294
|
export async function processOpenapiFiles(
|
|
248
|
-
files: OpenApiFiles[]
|
|
249
|
-
|
|
295
|
+
files: OpenApiFiles[],
|
|
296
|
+
sidebarOptions: SidebarOptions
|
|
297
|
+
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
250
298
|
const promises = files.map(async (file) => {
|
|
251
|
-
const
|
|
252
|
-
|
|
299
|
+
const processedFile = await processOpenapiFile(file.data, sidebarOptions);
|
|
300
|
+
const itemsObjectsArray = processedFile[0].map((item) => ({
|
|
253
301
|
...item,
|
|
254
302
|
}));
|
|
303
|
+
const tags = processedFile[1];
|
|
304
|
+
return [itemsObjectsArray, tags];
|
|
255
305
|
});
|
|
256
306
|
const metadata = await Promise.all(promises);
|
|
257
|
-
const items = metadata
|
|
258
|
-
|
|
307
|
+
const items = metadata
|
|
308
|
+
.map(function (x) {
|
|
309
|
+
return x[0];
|
|
310
|
+
})
|
|
311
|
+
.flat();
|
|
312
|
+
const tags = metadata.map(function (x) {
|
|
313
|
+
return x[1];
|
|
314
|
+
});
|
|
315
|
+
return [items as ApiMetadata[], tags as TagObject[]];
|
|
259
316
|
}
|
|
260
317
|
|
|
261
318
|
export async function processOpenapiFile(
|
|
262
|
-
openapiDataWithRefs: OpenApiObjectWithRef
|
|
263
|
-
|
|
319
|
+
openapiDataWithRefs: OpenApiObjectWithRef,
|
|
320
|
+
sidebarOptions: SidebarOptions
|
|
321
|
+
): Promise<[ApiMetadata[], TagObject[]]> {
|
|
264
322
|
const openapiData = await resolveRefs(openapiDataWithRefs);
|
|
265
323
|
const postmanCollection = await createPostmanCollection(openapiData);
|
|
266
|
-
const items = createItems(openapiData);
|
|
324
|
+
const items = createItems(openapiData, sidebarOptions);
|
|
267
325
|
|
|
268
326
|
bindCollectionToApiItems(items, postmanCollection);
|
|
269
327
|
|
|
270
|
-
|
|
328
|
+
let tags: TagObject[] = [];
|
|
329
|
+
if (openapiData.tags !== undefined) {
|
|
330
|
+
tags = openapiData.tags;
|
|
331
|
+
}
|
|
332
|
+
return [items, tags];
|
|
271
333
|
}
|
|
272
334
|
|
|
273
335
|
// order for picking items as a display name of tags
|
|
274
336
|
const tagDisplayNameProperties = ["x-displayName", "name"] as const;
|
|
275
337
|
|
|
276
|
-
function getTagDisplayName(tagName: string, tags: TagObject[]): string {
|
|
338
|
+
export function getTagDisplayName(tagName: string, tags: TagObject[]): string {
|
|
277
339
|
// find the very own tagObject
|
|
278
340
|
const tagObject = tags.find((tagObject) => tagObject.name === tagName) ?? {
|
|
279
341
|
// 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 {
|
|
@@ -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
|
+
}
|