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/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,13 +16,15 @@ 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;
|
|
23
23
|
next?: ApiNavLink;
|
|
24
24
|
id: string;
|
|
25
25
|
unversionedId: string;
|
|
26
|
+
infoId?: string;
|
|
27
|
+
infoPath?: string;
|
|
26
28
|
title: string;
|
|
27
29
|
description: string;
|
|
28
30
|
source: string;
|
|
@@ -52,6 +54,14 @@ export interface InfoPageMetadata extends ApiMetadataBase {
|
|
|
52
54
|
type: "info";
|
|
53
55
|
info: ApiInfo;
|
|
54
56
|
markdown?: string;
|
|
57
|
+
securitySchemes?: {
|
|
58
|
+
[key: string]: SecuritySchemeObject;
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
export interface TagPageMetadata extends ApiMetadataBase {
|
|
62
|
+
type: "tag";
|
|
63
|
+
tag: TagObject;
|
|
64
|
+
markdown?: string;
|
|
55
65
|
}
|
|
56
66
|
export declare type ApiInfo = InfoObject;
|
|
57
67
|
export interface ApiNavLink {
|
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.3",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"openapi",
|
|
@@ -28,20 +28,21 @@
|
|
|
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
|
+
"@redocly/openapi-core": "^1.0.0-beta.100",
|
|
45
46
|
"@types/js-yaml": "^4.0.5",
|
|
46
47
|
"@types/mustache": "^4.1.2",
|
|
47
48
|
"chalk": "^4.1.2",
|
|
@@ -52,6 +53,7 @@
|
|
|
52
53
|
"json-schema-merge-allof": "^0.8.1",
|
|
53
54
|
"lodash": "^4.17.20",
|
|
54
55
|
"mustache": "^4.2.0",
|
|
56
|
+
"swagger2openapi": "^7.0.8",
|
|
55
57
|
"webpack": "^5.61.0"
|
|
56
58
|
},
|
|
57
59
|
"peerDependencies": {
|
|
@@ -60,5 +62,5 @@
|
|
|
60
62
|
"engines": {
|
|
61
63
|
"node": ">=14"
|
|
62
64
|
},
|
|
63
|
-
"gitHead": "
|
|
65
|
+
"gitHead": "618a438ec42148f525fb92cb11d291ce50d2ad06"
|
|
64
66
|
}
|
package/src/index.ts
CHANGED
|
@@ -13,11 +13,15 @@ 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";
|
|
20
20
|
|
|
21
|
+
export function isURL(str: string): boolean {
|
|
22
|
+
return /^(https?:)\/\//m.test(str);
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
export default function pluginOpenAPI(
|
|
22
26
|
context: LoadContext,
|
|
23
27
|
options: PluginOptions
|
|
@@ -28,11 +32,16 @@ export default function pluginOpenAPI(
|
|
|
28
32
|
async function generateApiDocs(options: APIOptions) {
|
|
29
33
|
let { specPath, outputDir, template, sidebarOptions } = options;
|
|
30
34
|
|
|
31
|
-
const contentPath =
|
|
35
|
+
const contentPath = isURL(specPath)
|
|
36
|
+
? specPath
|
|
37
|
+
: path.resolve(siteDir, specPath);
|
|
32
38
|
|
|
33
39
|
try {
|
|
34
40
|
const openapiFiles = await readOpenapiFiles(contentPath, {});
|
|
35
|
-
const [loadedApi, tags] = await processOpenapiFiles(
|
|
41
|
+
const [loadedApi, tags] = await processOpenapiFiles(
|
|
42
|
+
openapiFiles,
|
|
43
|
+
sidebarOptions!
|
|
44
|
+
);
|
|
36
45
|
if (!fs.existsSync(outputDir)) {
|
|
37
46
|
try {
|
|
38
47
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
@@ -100,6 +109,9 @@ api: {{{json}}}
|
|
|
100
109
|
{{#api.method}}
|
|
101
110
|
sidebar_class_name: "{{{api.method}}} api-method"
|
|
102
111
|
{{/api.method}}
|
|
112
|
+
{{#infoPath}}
|
|
113
|
+
info_path: {{{infoPath}}}
|
|
114
|
+
{{/infoPath}}
|
|
103
115
|
---
|
|
104
116
|
|
|
105
117
|
{{{markdown}}}
|
|
@@ -119,19 +131,45 @@ hide_title: true
|
|
|
119
131
|
import DocCardList from '@theme/DocCardList';
|
|
120
132
|
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
121
133
|
|
|
134
|
+
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
135
|
+
\`\`\`
|
|
136
|
+
`;
|
|
137
|
+
|
|
138
|
+
const tagMdTemplate = template
|
|
139
|
+
? fs.readFileSync(template).toString()
|
|
140
|
+
: `---
|
|
141
|
+
id: {{{id}}}
|
|
142
|
+
title: {{{description}}}
|
|
143
|
+
description: {{{description}}}
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
{{{markdown}}}
|
|
147
|
+
|
|
148
|
+
\`\`\`mdx-code-block
|
|
149
|
+
import DocCardList from '@theme/DocCardList';
|
|
150
|
+
import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
151
|
+
|
|
122
152
|
<DocCardList items={useCurrentSidebarCategory().items}/>
|
|
123
153
|
\`\`\`
|
|
124
154
|
`;
|
|
125
155
|
|
|
126
156
|
loadedApi.map(async (item) => {
|
|
127
157
|
const markdown =
|
|
128
|
-
item.type === "api"
|
|
158
|
+
item.type === "api"
|
|
159
|
+
? createApiPageMD(item)
|
|
160
|
+
: item.type === "info"
|
|
161
|
+
? createInfoPageMD(item)
|
|
162
|
+
: createTagPageMD(item);
|
|
129
163
|
item.markdown = markdown;
|
|
130
164
|
if (item.type === "api") {
|
|
131
165
|
item.json = JSON.stringify(item.api);
|
|
166
|
+
if (item.infoId) item.infoPath = `${outputDir}/${item.infoId}`;
|
|
132
167
|
}
|
|
168
|
+
|
|
133
169
|
const view = render(mdTemplate, item);
|
|
134
170
|
const utils = render(infoMdTemplate, item);
|
|
171
|
+
// eslint-disable-next-line testing-library/render-result-naming-convention
|
|
172
|
+
const tagUtils = render(tagMdTemplate, item);
|
|
135
173
|
|
|
136
174
|
if (item.type === "api") {
|
|
137
175
|
if (!fs.existsSync(`${outputDir}/${item.id}.api.mdx`)) {
|
|
@@ -179,8 +217,31 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
179
217
|
}
|
|
180
218
|
}
|
|
181
219
|
}
|
|
220
|
+
|
|
221
|
+
if (item.type === "tag") {
|
|
222
|
+
if (!fs.existsSync(`${outputDir}/${item.id}.tag.mdx`)) {
|
|
223
|
+
try {
|
|
224
|
+
fs.writeFileSync(
|
|
225
|
+
`${outputDir}/${item.id}.tag.mdx`,
|
|
226
|
+
tagUtils,
|
|
227
|
+
"utf8"
|
|
228
|
+
);
|
|
229
|
+
console.log(
|
|
230
|
+
chalk.green(
|
|
231
|
+
`Successfully created "${outputDir}/${item.id}.tag.mdx"`
|
|
232
|
+
)
|
|
233
|
+
);
|
|
234
|
+
} catch (err) {
|
|
235
|
+
console.error(
|
|
236
|
+
chalk.red(`Failed to write "${outputDir}/${item.id}.tag.mdx"`),
|
|
237
|
+
chalk.yellow(err)
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
182
242
|
return;
|
|
183
243
|
});
|
|
244
|
+
|
|
184
245
|
return;
|
|
185
246
|
} catch (e) {
|
|
186
247
|
console.error(chalk.red(`Loading of api failed for "${contentPath}"`));
|
|
@@ -191,7 +252,7 @@ import {useCurrentSidebarCategory} from '@docusaurus/theme-common';
|
|
|
191
252
|
async function cleanApiDocs(options: APIOptions) {
|
|
192
253
|
const { outputDir } = options;
|
|
193
254
|
const apiDir = path.join(siteDir, outputDir);
|
|
194
|
-
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx"], {
|
|
255
|
+
const apiMdxFiles = await Globby(["*.api.mdx", "*.info.mdx", "*.tag.mdx"], {
|
|
195
256
|
cwd: path.resolve(apiDir),
|
|
196
257
|
});
|
|
197
258
|
const sidebarFile = await Globby(["sidebar.js"], {
|
|
@@ -0,0 +1,160 @@
|
|
|
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 { OAuthFlowObject, SecuritySchemeObject } from "../openapi/types";
|
|
9
|
+
import { createDescription } from "./createDescription";
|
|
10
|
+
import { create, guard } from "./utils";
|
|
11
|
+
|
|
12
|
+
export function createAuthentication(securitySchemes: SecuritySchemeObject) {
|
|
13
|
+
if (!securitySchemes || !Object.keys(securitySchemes).length) return "";
|
|
14
|
+
|
|
15
|
+
const createAuthenticationTable = (securityScheme: any) => {
|
|
16
|
+
const { bearerFormat, flows, name, scheme, type } = securityScheme;
|
|
17
|
+
|
|
18
|
+
const createSecuritySchemeTypeRow = () =>
|
|
19
|
+
create("tr", {
|
|
20
|
+
children: [
|
|
21
|
+
create("th", { children: "Security Scheme Type:" }),
|
|
22
|
+
create("td", { children: type }),
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
const createOAuthFlowRows = () => {
|
|
27
|
+
const flowRows = Object.entries(flows).map(([flowType, flowObj]) => {
|
|
28
|
+
const { authorizationUrl, tokenUrl, refreshUrl, scopes } =
|
|
29
|
+
flowObj as OAuthFlowObject;
|
|
30
|
+
|
|
31
|
+
return create("tr", {
|
|
32
|
+
children: [
|
|
33
|
+
create("th", { children: `${flowType} OAuth Flow:` }),
|
|
34
|
+
create("td", {
|
|
35
|
+
children: [
|
|
36
|
+
guard(tokenUrl, () =>
|
|
37
|
+
create("p", { children: `Token URL: ${tokenUrl}` })
|
|
38
|
+
),
|
|
39
|
+
guard(authorizationUrl, () =>
|
|
40
|
+
create("p", {
|
|
41
|
+
children: `Authorization URL: ${authorizationUrl}`,
|
|
42
|
+
})
|
|
43
|
+
),
|
|
44
|
+
guard(refreshUrl, () =>
|
|
45
|
+
create("p", { children: `Refresh URL: ${refreshUrl}` })
|
|
46
|
+
),
|
|
47
|
+
create("span", { children: "Scopes:" }),
|
|
48
|
+
create("ul", {
|
|
49
|
+
children: Object.entries(scopes).map(([scope, description]) =>
|
|
50
|
+
create("li", { children: `${scope}: ${description}` })
|
|
51
|
+
),
|
|
52
|
+
}),
|
|
53
|
+
],
|
|
54
|
+
}),
|
|
55
|
+
],
|
|
56
|
+
});
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
return flowRows.join("");
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
switch (type) {
|
|
63
|
+
case "apiKey":
|
|
64
|
+
return create("div", {
|
|
65
|
+
children: [
|
|
66
|
+
create("table", {
|
|
67
|
+
children: create("tbody", {
|
|
68
|
+
children: [
|
|
69
|
+
createSecuritySchemeTypeRow(),
|
|
70
|
+
create("tr", {
|
|
71
|
+
children: [
|
|
72
|
+
create("th", { children: "Header parameter name:" }),
|
|
73
|
+
create("td", { children: name }),
|
|
74
|
+
],
|
|
75
|
+
}),
|
|
76
|
+
],
|
|
77
|
+
}),
|
|
78
|
+
}),
|
|
79
|
+
],
|
|
80
|
+
});
|
|
81
|
+
case "http":
|
|
82
|
+
return create("div", {
|
|
83
|
+
children: [
|
|
84
|
+
create("table", {
|
|
85
|
+
children: create("tbody", {
|
|
86
|
+
children: [
|
|
87
|
+
createSecuritySchemeTypeRow(),
|
|
88
|
+
create("tr", {
|
|
89
|
+
children: [
|
|
90
|
+
create("th", { children: "HTTP Authorization Scheme:" }),
|
|
91
|
+
create("td", { children: scheme }),
|
|
92
|
+
],
|
|
93
|
+
}),
|
|
94
|
+
create("tr", {
|
|
95
|
+
children: [
|
|
96
|
+
create("th", { children: "Bearer format:" }),
|
|
97
|
+
create("td", { children: bearerFormat }),
|
|
98
|
+
],
|
|
99
|
+
}),
|
|
100
|
+
],
|
|
101
|
+
}),
|
|
102
|
+
}),
|
|
103
|
+
],
|
|
104
|
+
});
|
|
105
|
+
case "oauth2":
|
|
106
|
+
return create("div", {
|
|
107
|
+
children: [
|
|
108
|
+
create("table", {
|
|
109
|
+
children: create("tbody", {
|
|
110
|
+
children: [
|
|
111
|
+
createSecuritySchemeTypeRow(),
|
|
112
|
+
createOAuthFlowRows(),
|
|
113
|
+
],
|
|
114
|
+
}),
|
|
115
|
+
}),
|
|
116
|
+
],
|
|
117
|
+
});
|
|
118
|
+
default:
|
|
119
|
+
return "";
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const formatTabLabel = (str: string) => {
|
|
124
|
+
const formattedLabel = str
|
|
125
|
+
.replace(/(_|-)/g, " ")
|
|
126
|
+
.trim()
|
|
127
|
+
.replace(/\w\S*/g, (str) => str.charAt(0).toUpperCase() + str.substr(1))
|
|
128
|
+
.replace(/([a-z])([A-Z])/g, "$1 $2")
|
|
129
|
+
.replace(/([A-Z])([A-Z][a-z])/g, "$1 $2");
|
|
130
|
+
|
|
131
|
+
const isOAuth = formattedLabel.toLowerCase().includes("oauth2");
|
|
132
|
+
const isApiKey = formattedLabel.toLowerCase().includes("api");
|
|
133
|
+
|
|
134
|
+
return isOAuth ? "OAuth 2.0" : isApiKey ? "API Key" : formattedLabel;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
return create("div", {
|
|
138
|
+
children: [
|
|
139
|
+
create("h2", {
|
|
140
|
+
children: "Authentication",
|
|
141
|
+
id: "authentication",
|
|
142
|
+
style: { marginBottom: "1rem" },
|
|
143
|
+
}),
|
|
144
|
+
create("Tabs", {
|
|
145
|
+
children: Object.entries(securitySchemes).map(
|
|
146
|
+
([schemeType, schemeObj]) =>
|
|
147
|
+
create("TabItem", {
|
|
148
|
+
label: formatTabLabel(schemeType),
|
|
149
|
+
value: `${schemeType}`,
|
|
150
|
+
children: [
|
|
151
|
+
createDescription(schemeObj.description),
|
|
152
|
+
createAuthenticationTable(schemeObj),
|
|
153
|
+
],
|
|
154
|
+
})
|
|
155
|
+
),
|
|
156
|
+
}),
|
|
157
|
+
],
|
|
158
|
+
style: { marginBottom: "2rem" },
|
|
159
|
+
});
|
|
160
|
+
}
|
package/src/markdown/index.ts
CHANGED
|
@@ -7,8 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
import { escape } from "lodash";
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
|
|
10
|
+
import {
|
|
11
|
+
ContactObject,
|
|
12
|
+
LicenseObject,
|
|
13
|
+
SecuritySchemeObject,
|
|
14
|
+
} from "../openapi/types";
|
|
15
|
+
import { ApiPageMetadata, InfoPageMetadata, TagPageMetadata } from "../types";
|
|
16
|
+
import { createAuthentication } from "./createAuthentication";
|
|
12
17
|
import { createContactInfo } from "./createContactInfo";
|
|
13
18
|
import { createDeprecationNotice } from "./createDeprecationNotice";
|
|
14
19
|
import { createDescription } from "./createDescription";
|
|
@@ -50,13 +55,21 @@ export function createApiPageMD({
|
|
|
50
55
|
|
|
51
56
|
export function createInfoPageMD({
|
|
52
57
|
info: { title, version, description, contact, license, termsOfService },
|
|
58
|
+
securitySchemes,
|
|
53
59
|
}: InfoPageMetadata) {
|
|
54
60
|
return render([
|
|
61
|
+
`import Tabs from "@theme/Tabs";\n`,
|
|
62
|
+
`import TabItem from "@theme/TabItem";\n`,
|
|
55
63
|
createVersionBadge(version),
|
|
56
64
|
`# ${escape(title)}\n\n`,
|
|
57
65
|
createDescription(description),
|
|
66
|
+
createAuthentication(securitySchemes as unknown as SecuritySchemeObject),
|
|
58
67
|
createContactInfo(contact as ContactObject),
|
|
59
68
|
createTermsOfService(termsOfService),
|
|
60
69
|
createLicense(license as LicenseObject),
|
|
61
70
|
]);
|
|
62
71
|
}
|
|
72
|
+
|
|
73
|
+
export function createTagPageMD({ tag: { description } }: TagPageMetadata) {
|
|
74
|
+
return render([createDescription(description)]);
|
|
75
|
+
}
|
|
@@ -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
|
});
|