@visulima/jsdoc-open-api 3.0.0-alpha.4 → 3.0.0-alpha.5
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/CHANGELOG.md +33 -0
- package/LICENSE.md +1 -1
- package/dist/cli/command/generate-command.d.cts +7 -0
- package/dist/cli/command/generate-command.d.mts +7 -0
- package/dist/cli/command/generate-command.d.ts +7 -0
- package/dist/cli/command/init-command.d.cts +2 -0
- package/dist/cli/command/init-command.d.mts +2 -0
- package/dist/cli/command/init-command.d.ts +2 -0
- package/dist/cli/commander/command/generate-command.d.cts +3 -0
- package/dist/cli/commander/command/generate-command.d.mts +3 -0
- package/dist/cli/commander/command/generate-command.d.ts +3 -0
- package/dist/cli/commander/command/init-command.d.cts +3 -0
- package/dist/cli/commander/command/init-command.d.mts +3 -0
- package/dist/cli/commander/command/init-command.d.ts +3 -0
- package/dist/cli/commander/index.cjs +11 -0
- package/dist/cli/commander/index.d.cts +2 -0
- package/dist/cli/commander/index.d.mts +2 -7
- package/dist/cli/commander/index.d.ts +2 -7
- package/dist/cli/commander/index.mjs +2 -30
- package/dist/cli/index.cjs +11 -0
- package/dist/cli/index.d.cts +2 -0
- package/dist/cli/index.d.mts +2 -10
- package/dist/cli/index.d.ts +2 -10
- package/dist/cli/index.mjs +2 -4
- package/dist/constants.d.cts +1 -0
- package/dist/constants.d.mts +1 -0
- package/dist/constants.d.ts +1 -0
- package/dist/exported.d.cts +198 -0
- package/dist/exported.d.mts +198 -0
- package/dist/exported.d.ts +198 -0
- package/dist/index.cjs +19 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.mts +7 -248
- package/dist/index.d.ts +7 -248
- package/dist/index.mjs +6 -85
- package/dist/jsdoc/comments-to-open-api.d.cts +6 -0
- package/dist/jsdoc/comments-to-open-api.d.mts +6 -0
- package/dist/jsdoc/comments-to-open-api.d.ts +6 -0
- package/dist/packem_shared/SpecBuilder-B7YiF7zR.mjs +61 -0
- package/dist/packem_shared/SpecBuilder-CCESkmm5.cjs +63 -0
- package/dist/packem_shared/SwaggerCompilerPlugin-BEbFO9Dt.mjs +86 -0
- package/dist/packem_shared/SwaggerCompilerPlugin-BHbHAPK-.cjs +88 -0
- package/dist/packem_shared/customizer-CoMXMU7a.mjs +8 -0
- package/dist/packem_shared/customizer-DDFwFqJl.cjs +10 -0
- package/dist/packem_shared/generateCommand-B1t3VSDX.mjs +15 -0
- package/dist/packem_shared/generateCommand-CZEFuXr9.mjs +83 -0
- package/dist/packem_shared/generateCommand-CmyavGTZ.cjs +17 -0
- package/dist/packem_shared/generateCommand-Cu0UQUh8.cjs +85 -0
- package/dist/packem_shared/initCommand-B6Z9EXHP.mjs +15 -0
- package/dist/packem_shared/initCommand-Ch-72dKZ.cjs +65 -0
- package/dist/packem_shared/initCommand-D3yVEMwO.cjs +17 -0
- package/dist/packem_shared/initCommand-zE4VRDGW.mjs +63 -0
- package/dist/packem_shared/jsDocumentCommentsToOpenApi-C8kxIQH2.cjs +334 -0
- package/dist/packem_shared/jsDocumentCommentsToOpenApi-eOlxMuMO.mjs +328 -0
- package/dist/packem_shared/parseFile-BJwu_na4.cjs +42 -0
- package/dist/packem_shared/parseFile-Bxis7tbW.mjs +35 -0
- package/dist/packem_shared/swaggerJsDocumentCommentsToOpenApi-Cb5s1J29.mjs +130 -0
- package/dist/packem_shared/swaggerJsDocumentCommentsToOpenApi-JFymRz50.cjs +137 -0
- package/dist/packem_shared/validate-DZHaKH07.mjs +30 -0
- package/dist/packem_shared/validate-FKieC3ln.cjs +37 -0
- package/dist/packem_shared/yamlLoc-BLoIYoXs.cjs +14 -0
- package/dist/packem_shared/yamlLoc-Cmx4vbRt.mjs +12 -0
- package/dist/parse-file.d.cts +9 -0
- package/dist/parse-file.d.mts +9 -0
- package/dist/parse-file.d.ts +9 -0
- package/dist/spec-builder.d.cts +14 -0
- package/dist/spec-builder.d.mts +14 -0
- package/dist/spec-builder.d.ts +14 -0
- package/dist/swagger-jsdoc/comments-to-open-api.d.cts +6 -0
- package/dist/swagger-jsdoc/comments-to-open-api.d.mts +6 -0
- package/dist/swagger-jsdoc/comments-to-open-api.d.ts +6 -0
- package/dist/swagger-jsdoc/organize-swagger-object.d.cts +7 -0
- package/dist/swagger-jsdoc/organize-swagger-object.d.mts +7 -0
- package/dist/swagger-jsdoc/organize-swagger-object.d.ts +7 -0
- package/dist/swagger-jsdoc/utils.d.cts +21 -0
- package/dist/swagger-jsdoc/utils.d.mts +21 -0
- package/dist/swagger-jsdoc/utils.d.ts +21 -0
- package/dist/util/customizer.d.cts +2 -0
- package/dist/util/customizer.d.mts +2 -0
- package/dist/util/customizer.d.ts +2 -0
- package/dist/util/object-merge.d.cts +2 -0
- package/dist/util/object-merge.d.mts +2 -0
- package/dist/util/object-merge.d.ts +2 -0
- package/dist/util/yaml-loc.d.cts +2 -0
- package/dist/util/yaml-loc.d.mts +2 -0
- package/dist/util/yaml-loc.d.ts +2 -0
- package/dist/validate.d.cts +2 -0
- package/dist/validate.d.mts +2 -0
- package/dist/validate.d.ts +2 -0
- package/dist/webpack/swagger-compiler-plugin.d.cts +15 -0
- package/dist/webpack/swagger-compiler-plugin.d.mts +15 -0
- package/dist/webpack/swagger-compiler-plugin.d.ts +15 -0
- package/package.json +32 -19
- package/dist/chunk-2T6HMUIL.mjs +0 -1215
- package/dist/chunk-2T6HMUIL.mjs.map +0 -1
- package/dist/chunk-PTFTJY7I.js +0 -1233
- package/dist/chunk-PTFTJY7I.js.map +0 -1
- package/dist/chunk-RGP6RTJO.mjs +0 -142
- package/dist/chunk-RGP6RTJO.mjs.map +0 -1
- package/dist/chunk-RVCK3H3U.js +0 -149
- package/dist/chunk-RVCK3H3U.js.map +0 -1
- package/dist/cli/commander/index.js +0 -33
- package/dist/cli/commander/index.js.map +0 -1
- package/dist/cli/commander/index.mjs.map +0 -1
- package/dist/cli/index.js +0 -17
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/index.mjs.map +0 -1
- package/dist/index.js +0 -106
- package/dist/index.js.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { parse } from 'comment-parser';
|
|
2
|
+
import mergeWith from 'lodash.mergewith';
|
|
3
|
+
import { c as customizer } from './customizer-CoMXMU7a.mjs';
|
|
4
|
+
|
|
5
|
+
const fixSecurityObject = (thing) => {
|
|
6
|
+
if (thing.security) {
|
|
7
|
+
thing.security = Object.keys(thing.security).map((s) => {
|
|
8
|
+
return {
|
|
9
|
+
[s]: thing.security[s]
|
|
10
|
+
};
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
const primitiveTypes = /* @__PURE__ */ new Set(["array", "boolean", "integer", "number", "object", "string"]);
|
|
15
|
+
const formatMap = {
|
|
16
|
+
binary: "string",
|
|
17
|
+
byte: "string",
|
|
18
|
+
date: "string",
|
|
19
|
+
"date-time": "string",
|
|
20
|
+
double: "number",
|
|
21
|
+
float: "number",
|
|
22
|
+
int32: "integer",
|
|
23
|
+
int64: "integer",
|
|
24
|
+
password: "string"
|
|
25
|
+
};
|
|
26
|
+
const parseDescription = (tag) => {
|
|
27
|
+
const rawType = tag.type;
|
|
28
|
+
const isArray = rawType.endsWith("[]");
|
|
29
|
+
const parsedType = rawType.replace(/\[]$/, "");
|
|
30
|
+
const isPrimitive = primitiveTypes.has(parsedType);
|
|
31
|
+
const isFormat = Object.keys(formatMap).includes(parsedType);
|
|
32
|
+
let defaultValue;
|
|
33
|
+
if (tag.default) {
|
|
34
|
+
switch (parsedType) {
|
|
35
|
+
case "double":
|
|
36
|
+
case "float":
|
|
37
|
+
case "number": {
|
|
38
|
+
defaultValue = Number.parseFloat(tag.default);
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
case "int32":
|
|
42
|
+
case "int64":
|
|
43
|
+
case "integer": {
|
|
44
|
+
defaultValue = Number.parseInt(tag.default, 10);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
default: {
|
|
48
|
+
defaultValue = tag.default;
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
let rootType;
|
|
54
|
+
if (isPrimitive) {
|
|
55
|
+
rootType = { default: defaultValue, type: parsedType };
|
|
56
|
+
} else if (isFormat) {
|
|
57
|
+
rootType = {
|
|
58
|
+
default: defaultValue,
|
|
59
|
+
format: parsedType,
|
|
60
|
+
type: formatMap[parsedType]
|
|
61
|
+
};
|
|
62
|
+
} else {
|
|
63
|
+
rootType = { $ref: `#/components/schemas/${parsedType}` };
|
|
64
|
+
}
|
|
65
|
+
let schema = isArray ? {
|
|
66
|
+
items: {
|
|
67
|
+
...rootType
|
|
68
|
+
},
|
|
69
|
+
type: "array"
|
|
70
|
+
} : {
|
|
71
|
+
...rootType
|
|
72
|
+
};
|
|
73
|
+
if (parsedType === "") {
|
|
74
|
+
schema = void 0;
|
|
75
|
+
}
|
|
76
|
+
let description = tag.description.trim().replace(/^- /u, "");
|
|
77
|
+
if (description === "") {
|
|
78
|
+
description = void 0;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
description,
|
|
82
|
+
name: tag.name,
|
|
83
|
+
rawType,
|
|
84
|
+
required: !tag.optional,
|
|
85
|
+
schema
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
const tagsToObjects = (tags, verbose) => tags.map((tag) => {
|
|
89
|
+
const parsedResponse = parseDescription(tag);
|
|
90
|
+
let nameAndDescription = "";
|
|
91
|
+
if (parsedResponse.name) {
|
|
92
|
+
nameAndDescription += parsedResponse.name;
|
|
93
|
+
}
|
|
94
|
+
if (parsedResponse.description) {
|
|
95
|
+
nameAndDescription += ` ${parsedResponse.description.trim()}`;
|
|
96
|
+
}
|
|
97
|
+
switch (tag.tag) {
|
|
98
|
+
case "bodyComponent": {
|
|
99
|
+
return {
|
|
100
|
+
requestBody: {
|
|
101
|
+
$ref: `#/components/requestBodies/${parsedResponse.rawType}`
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
case "bodyContent": {
|
|
106
|
+
return {
|
|
107
|
+
requestBody: {
|
|
108
|
+
content: {
|
|
109
|
+
[parsedResponse.name.replace(String.raw`*\/*`, "*/*")]: {
|
|
110
|
+
schema: parsedResponse.schema
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
case "bodyDescription": {
|
|
117
|
+
return { requestBody: { description: nameAndDescription } };
|
|
118
|
+
}
|
|
119
|
+
case "bodyExample": {
|
|
120
|
+
const [contentType, example] = parsedResponse.name.split(".");
|
|
121
|
+
return {
|
|
122
|
+
requestBody: {
|
|
123
|
+
content: {
|
|
124
|
+
[contentType]: {
|
|
125
|
+
examples: {
|
|
126
|
+
[example]: {
|
|
127
|
+
$ref: `#/components/examples/${parsedResponse.rawType}`
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
case "bodyRequired": {
|
|
136
|
+
return { requestBody: { required: true } };
|
|
137
|
+
}
|
|
138
|
+
case "callback": {
|
|
139
|
+
return {
|
|
140
|
+
callbacks: {
|
|
141
|
+
[parsedResponse.name]: {
|
|
142
|
+
$ref: `#/components/callbacks/${parsedResponse.rawType}`
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
case "cookieParam":
|
|
148
|
+
case "headerParam":
|
|
149
|
+
case "pathParam":
|
|
150
|
+
case "queryParam": {
|
|
151
|
+
return {
|
|
152
|
+
parameters: [
|
|
153
|
+
{
|
|
154
|
+
description: parsedResponse.description,
|
|
155
|
+
in: tag.tag.replace(/Param$/u, ""),
|
|
156
|
+
name: parsedResponse.name,
|
|
157
|
+
required: parsedResponse.required,
|
|
158
|
+
schema: parsedResponse.schema
|
|
159
|
+
}
|
|
160
|
+
]
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
case "deprecated": {
|
|
164
|
+
return { deprecated: true };
|
|
165
|
+
}
|
|
166
|
+
case "description":
|
|
167
|
+
case "operationId":
|
|
168
|
+
case "summary": {
|
|
169
|
+
return { [tag.tag]: nameAndDescription };
|
|
170
|
+
}
|
|
171
|
+
case "externalDocs": {
|
|
172
|
+
return {
|
|
173
|
+
externalDocs: {
|
|
174
|
+
description: parsedResponse.description,
|
|
175
|
+
url: parsedResponse.name
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
case "paramComponent": {
|
|
180
|
+
return {
|
|
181
|
+
parameters: [{ $ref: `#/components/parameters/${parsedResponse.rawType}` }]
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
case "response": {
|
|
185
|
+
return {
|
|
186
|
+
responses: {
|
|
187
|
+
[parsedResponse.name]: {
|
|
188
|
+
description: parsedResponse.description
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
case "responseComponent": {
|
|
194
|
+
return {
|
|
195
|
+
responses: {
|
|
196
|
+
[parsedResponse.name]: {
|
|
197
|
+
$ref: `#/components/responses/${parsedResponse.rawType}`
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
case "responseContent": {
|
|
203
|
+
const [status, contentType] = parsedResponse.name.split(".");
|
|
204
|
+
return {
|
|
205
|
+
responses: {
|
|
206
|
+
[status]: {
|
|
207
|
+
content: {
|
|
208
|
+
[contentType]: {
|
|
209
|
+
schema: parsedResponse.schema
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
case "responseExample": {
|
|
217
|
+
const [status, contentType, example] = parsedResponse.name.split(".");
|
|
218
|
+
return {
|
|
219
|
+
responses: {
|
|
220
|
+
[status]: {
|
|
221
|
+
content: {
|
|
222
|
+
[contentType]: {
|
|
223
|
+
examples: {
|
|
224
|
+
[example]: {
|
|
225
|
+
$ref: `#/components/examples/${parsedResponse.rawType}`
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
case "responseHeader": {
|
|
235
|
+
const [status, header] = parsedResponse.name.split(".");
|
|
236
|
+
return {
|
|
237
|
+
responses: {
|
|
238
|
+
[status]: {
|
|
239
|
+
headers: {
|
|
240
|
+
[header]: {
|
|
241
|
+
description: parsedResponse.description,
|
|
242
|
+
schema: parsedResponse.schema
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
case "responseHeaderComponent": {
|
|
250
|
+
const [status, header] = parsedResponse.name.split(".");
|
|
251
|
+
return {
|
|
252
|
+
responses: {
|
|
253
|
+
[status]: {
|
|
254
|
+
headers: {
|
|
255
|
+
[header]: {
|
|
256
|
+
$ref: `#/components/headers/${parsedResponse.rawType}`
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
case "responseLink": {
|
|
264
|
+
const [status, link] = parsedResponse.name.split(".");
|
|
265
|
+
return {
|
|
266
|
+
responses: {
|
|
267
|
+
[status]: {
|
|
268
|
+
links: {
|
|
269
|
+
[link]: {
|
|
270
|
+
$ref: `#/components/links/${parsedResponse.rawType}`
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
case "security": {
|
|
278
|
+
const [security, scopeItem] = parsedResponse.name.split(".");
|
|
279
|
+
let scope = [];
|
|
280
|
+
if (scopeItem) {
|
|
281
|
+
scope = [scopeItem];
|
|
282
|
+
}
|
|
283
|
+
return {
|
|
284
|
+
security: { [security]: scope }
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
case "server": {
|
|
288
|
+
return {
|
|
289
|
+
servers: [
|
|
290
|
+
{
|
|
291
|
+
description: parsedResponse.description,
|
|
292
|
+
url: parsedResponse.name
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
case "tag": {
|
|
298
|
+
return { tags: [nameAndDescription] };
|
|
299
|
+
}
|
|
300
|
+
default: {
|
|
301
|
+
return {};
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
const commentsToOpenApi = (fileContents, verbose) => {
|
|
306
|
+
const openAPIRegex = /^(GET|PUT|POST|DELETE|OPTIONS|HEAD|PATCH|TRACE) \/.*$/;
|
|
307
|
+
const jsDocumentComments = parse(fileContents, { spacing: "preserve" });
|
|
308
|
+
return jsDocumentComments.filter((comment) => openAPIRegex.test(comment.description.trim())).map((comment) => {
|
|
309
|
+
const loc = comment.tags.length + 1;
|
|
310
|
+
const result = mergeWith({}, ...tagsToObjects(comment.tags), customizer);
|
|
311
|
+
fixSecurityObject(result);
|
|
312
|
+
const [method, path] = comment.description.split(" ");
|
|
313
|
+
const pathsObject = {
|
|
314
|
+
[path.trim()]: {
|
|
315
|
+
[method.toLowerCase().trim()]: {
|
|
316
|
+
...result
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
const spec = JSON.parse(JSON.stringify({ paths: pathsObject }));
|
|
321
|
+
return {
|
|
322
|
+
loc,
|
|
323
|
+
spec
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
export { commentsToOpenApi as default };
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const node_fs = require('node:fs');
|
|
4
|
+
const path = require('node:path');
|
|
5
|
+
const yaml = require('yaml');
|
|
6
|
+
const yamlLoc = require('./yamlLoc-BLoIYoXs.cjs');
|
|
7
|
+
|
|
8
|
+
const _interopDefaultCompat = e => e && typeof e === 'object' && 'default' in e ? e.default : e;
|
|
9
|
+
|
|
10
|
+
const path__default = /*#__PURE__*/_interopDefaultCompat(path);
|
|
11
|
+
const yaml__default = /*#__PURE__*/_interopDefaultCompat(yaml);
|
|
12
|
+
|
|
13
|
+
const ALLOWED_KEYS = /* @__PURE__ */ new Set(["components", "externalDocs", "info", "openapi", "paths", "security", "servers", "tags"]);
|
|
14
|
+
class ParseError extends Error {
|
|
15
|
+
filePath;
|
|
16
|
+
}
|
|
17
|
+
const parseFile = (file, commentsToOpenApi, verbose) => {
|
|
18
|
+
const fileContent = node_fs.readFileSync(file, { encoding: "utf8" });
|
|
19
|
+
const extension = path__default.extname(file);
|
|
20
|
+
if (extension === ".yaml" || extension === ".yml") {
|
|
21
|
+
const spec = yaml__default.parse(fileContent);
|
|
22
|
+
const invalidKeys = Object.keys(spec).filter((key) => !ALLOWED_KEYS.has(key));
|
|
23
|
+
if (invalidKeys.length > 0) {
|
|
24
|
+
const error = new ParseError(`Unexpected keys: ${invalidKeys.join(", ")}`);
|
|
25
|
+
error.filePath = file;
|
|
26
|
+
throw error;
|
|
27
|
+
}
|
|
28
|
+
if (Object.keys(spec).some((key) => ALLOWED_KEYS.has(key))) {
|
|
29
|
+
const loc = yamlLoc(fileContent);
|
|
30
|
+
return [{ loc, spec }];
|
|
31
|
+
}
|
|
32
|
+
return [];
|
|
33
|
+
}
|
|
34
|
+
try {
|
|
35
|
+
return commentsToOpenApi(fileContent, verbose);
|
|
36
|
+
} catch (error) {
|
|
37
|
+
error.filePath = file;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
module.exports = parseFile;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import yaml from 'yaml';
|
|
4
|
+
import yamlLoc from './yamlLoc-Cmx4vbRt.mjs';
|
|
5
|
+
|
|
6
|
+
const ALLOWED_KEYS = /* @__PURE__ */ new Set(["components", "externalDocs", "info", "openapi", "paths", "security", "servers", "tags"]);
|
|
7
|
+
class ParseError extends Error {
|
|
8
|
+
filePath;
|
|
9
|
+
}
|
|
10
|
+
const parseFile = (file, commentsToOpenApi, verbose) => {
|
|
11
|
+
const fileContent = readFileSync(file, { encoding: "utf8" });
|
|
12
|
+
const extension = path.extname(file);
|
|
13
|
+
if (extension === ".yaml" || extension === ".yml") {
|
|
14
|
+
const spec = yaml.parse(fileContent);
|
|
15
|
+
const invalidKeys = Object.keys(spec).filter((key) => !ALLOWED_KEYS.has(key));
|
|
16
|
+
if (invalidKeys.length > 0) {
|
|
17
|
+
const error = new ParseError(`Unexpected keys: ${invalidKeys.join(", ")}`);
|
|
18
|
+
error.filePath = file;
|
|
19
|
+
throw error;
|
|
20
|
+
}
|
|
21
|
+
if (Object.keys(spec).some((key) => ALLOWED_KEYS.has(key))) {
|
|
22
|
+
const loc = yamlLoc(fileContent);
|
|
23
|
+
return [{ loc, spec }];
|
|
24
|
+
}
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
return commentsToOpenApi(fileContent, verbose);
|
|
29
|
+
} catch (error) {
|
|
30
|
+
error.filePath = file;
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export { parseFile as default };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { parse } from 'comment-parser';
|
|
2
|
+
import mergeWith from 'lodash.mergewith';
|
|
3
|
+
import yaml from 'yaml';
|
|
4
|
+
import { c as customizer } from './customizer-CoMXMU7a.mjs';
|
|
5
|
+
|
|
6
|
+
const mergeDeep = (first, second) => mergeWith({}, first, second, (a, b) => b === null ? a : void 0);
|
|
7
|
+
const hasEmptyProperty = (object) => Object.keys(object).map((key) => object[key]).every((keyObject) => typeof keyObject === "object" && Object.keys(keyObject).every((key) => !(key in keyObject)));
|
|
8
|
+
const isTagPresentInTags = (tag, tags) => tags.some((targetTag) => tag.name === targetTag.name);
|
|
9
|
+
const getSwaggerVersionFromSpec = (tag) => {
|
|
10
|
+
switch (tag.tag) {
|
|
11
|
+
case "asyncapi": {
|
|
12
|
+
return "v4";
|
|
13
|
+
}
|
|
14
|
+
case "openapi": {
|
|
15
|
+
return "v3";
|
|
16
|
+
}
|
|
17
|
+
case "swagger": {
|
|
18
|
+
return "v2";
|
|
19
|
+
}
|
|
20
|
+
default: {
|
|
21
|
+
return "v2";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const organizeSwaggerObject = (swaggerObject, annotation, property) => {
|
|
27
|
+
if (property === "x-webhooks") {
|
|
28
|
+
swaggerObject[property] = annotation[property];
|
|
29
|
+
}
|
|
30
|
+
if (property.startsWith("x-")) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const commonProperties = [
|
|
34
|
+
"components",
|
|
35
|
+
"consumes",
|
|
36
|
+
"produces",
|
|
37
|
+
"paths",
|
|
38
|
+
"schemas",
|
|
39
|
+
"securityDefinitions",
|
|
40
|
+
"responses",
|
|
41
|
+
"parameters",
|
|
42
|
+
"definitions",
|
|
43
|
+
"channels"
|
|
44
|
+
];
|
|
45
|
+
if (commonProperties.includes(property)) {
|
|
46
|
+
Object.keys(annotation[property]).forEach((definition) => {
|
|
47
|
+
swaggerObject[property][definition] = mergeDeep(swaggerObject[property][definition], annotation[property][definition]);
|
|
48
|
+
});
|
|
49
|
+
} else if (property === "tags") {
|
|
50
|
+
const { tags } = annotation;
|
|
51
|
+
if (Array.isArray(tags)) {
|
|
52
|
+
tags.forEach((tag) => {
|
|
53
|
+
if (!isTagPresentInTags(tag, swaggerObject.tags)) {
|
|
54
|
+
swaggerObject.tags.push(tag);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
} else if (!isTagPresentInTags(tags, swaggerObject.tags)) {
|
|
58
|
+
swaggerObject.tags.push(tags);
|
|
59
|
+
}
|
|
60
|
+
} else if (property === "security") {
|
|
61
|
+
const { security } = annotation;
|
|
62
|
+
swaggerObject.security = security;
|
|
63
|
+
} else if (property.startsWith("/")) {
|
|
64
|
+
swaggerObject.paths[property] = mergeDeep(swaggerObject.paths[property], annotation[property]);
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const specificationTemplate = {
|
|
69
|
+
v2: ["paths", "definitions", "responses", "parameters", "securityDefinitions"],
|
|
70
|
+
v3: ["paths", "definitions", "responses", "parameters", "securityDefinitions", "components"],
|
|
71
|
+
v4: ["components", "channels"]
|
|
72
|
+
};
|
|
73
|
+
const tagsToObjects = (specs, verbose) => specs.map((spec) => {
|
|
74
|
+
const hasContent = spec.description !== "" || spec.name !== void 0 && (spec.name.startsWith("/") || spec.name.endsWith(":"));
|
|
75
|
+
if ((spec.tag === "openapi" || spec.tag === "swagger" || spec.tag === "asyncapi") && hasContent) {
|
|
76
|
+
let yamlContent = spec.description;
|
|
77
|
+
if (spec.name !== void 0 && (spec.name.startsWith("/") || spec.name.endsWith(":"))) {
|
|
78
|
+
yamlContent = yamlContent.trim() === "" ? spec.name : `${spec.name}
|
|
79
|
+
${yamlContent}`;
|
|
80
|
+
}
|
|
81
|
+
const parsed = yaml.parseDocument(yamlContent);
|
|
82
|
+
if (parsed.errors.length > 0) {
|
|
83
|
+
parsed.errors.map((error) => {
|
|
84
|
+
const newError = error;
|
|
85
|
+
newError.annotation = yamlContent;
|
|
86
|
+
return newError;
|
|
87
|
+
});
|
|
88
|
+
let errorString = "Error parsing YAML in @openapi spec:";
|
|
89
|
+
errorString += verbose ? parsed.errors.map(
|
|
90
|
+
(error) => `${error.toString()}
|
|
91
|
+
Imbedded within:
|
|
92
|
+
\`\`\`
|
|
93
|
+
${error.annotation?.replaceAll("\n", "\n ")}
|
|
94
|
+
\`\`\``
|
|
95
|
+
).join("\n") : parsed.errors.map((error) => error.toString()).join("\n");
|
|
96
|
+
throw new Error(errorString);
|
|
97
|
+
}
|
|
98
|
+
const parsedDocument = parsed.toJSON();
|
|
99
|
+
const specification = {
|
|
100
|
+
tags: []
|
|
101
|
+
};
|
|
102
|
+
specificationTemplate[getSwaggerVersionFromSpec(spec)].forEach((property) => {
|
|
103
|
+
specification[property] = specification[property] || {};
|
|
104
|
+
});
|
|
105
|
+
Object.keys(parsedDocument).forEach((property) => {
|
|
106
|
+
organizeSwaggerObject(specification, parsedDocument, property);
|
|
107
|
+
});
|
|
108
|
+
return specification;
|
|
109
|
+
}
|
|
110
|
+
return {};
|
|
111
|
+
});
|
|
112
|
+
const commentsToOpenApi = (fileContents, verbose) => {
|
|
113
|
+
const jsDocumentComments = parse(fileContents, { spacing: "preserve" });
|
|
114
|
+
return jsDocumentComments.map((comment) => {
|
|
115
|
+
const loc = comment.tags.length + 1;
|
|
116
|
+
const result = mergeWith({}, ...tagsToObjects(comment.tags, verbose), customizer);
|
|
117
|
+
["definitions", "responses", "parameters", "securityDefinitions", "components", "tags"].forEach((property) => {
|
|
118
|
+
if (result[property] !== void 0 && hasEmptyProperty(result[property])) {
|
|
119
|
+
delete result[property];
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
const spec = JSON.parse(JSON.stringify(result));
|
|
123
|
+
return {
|
|
124
|
+
loc,
|
|
125
|
+
spec
|
|
126
|
+
};
|
|
127
|
+
});
|
|
128
|
+
};
|
|
129
|
+
|
|
130
|
+
export { commentsToOpenApi as default };
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const commentParser = require('comment-parser');
|
|
4
|
+
const mergeWith = require('lodash.mergewith');
|
|
5
|
+
const yaml = require('yaml');
|
|
6
|
+
const customizer = require('./customizer-DDFwFqJl.cjs');
|
|
7
|
+
|
|
8
|
+
const _interopDefaultCompat = e => e && typeof e === 'object' && 'default' in e ? e.default : e;
|
|
9
|
+
|
|
10
|
+
const mergeWith__default = /*#__PURE__*/_interopDefaultCompat(mergeWith);
|
|
11
|
+
const yaml__default = /*#__PURE__*/_interopDefaultCompat(yaml);
|
|
12
|
+
|
|
13
|
+
const mergeDeep = (first, second) => mergeWith__default({}, first, second, (a, b) => b === null ? a : void 0);
|
|
14
|
+
const hasEmptyProperty = (object) => Object.keys(object).map((key) => object[key]).every((keyObject) => typeof keyObject === "object" && Object.keys(keyObject).every((key) => !(key in keyObject)));
|
|
15
|
+
const isTagPresentInTags = (tag, tags) => tags.some((targetTag) => tag.name === targetTag.name);
|
|
16
|
+
const getSwaggerVersionFromSpec = (tag) => {
|
|
17
|
+
switch (tag.tag) {
|
|
18
|
+
case "asyncapi": {
|
|
19
|
+
return "v4";
|
|
20
|
+
}
|
|
21
|
+
case "openapi": {
|
|
22
|
+
return "v3";
|
|
23
|
+
}
|
|
24
|
+
case "swagger": {
|
|
25
|
+
return "v2";
|
|
26
|
+
}
|
|
27
|
+
default: {
|
|
28
|
+
return "v2";
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const organizeSwaggerObject = (swaggerObject, annotation, property) => {
|
|
34
|
+
if (property === "x-webhooks") {
|
|
35
|
+
swaggerObject[property] = annotation[property];
|
|
36
|
+
}
|
|
37
|
+
if (property.startsWith("x-")) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const commonProperties = [
|
|
41
|
+
"components",
|
|
42
|
+
"consumes",
|
|
43
|
+
"produces",
|
|
44
|
+
"paths",
|
|
45
|
+
"schemas",
|
|
46
|
+
"securityDefinitions",
|
|
47
|
+
"responses",
|
|
48
|
+
"parameters",
|
|
49
|
+
"definitions",
|
|
50
|
+
"channels"
|
|
51
|
+
];
|
|
52
|
+
if (commonProperties.includes(property)) {
|
|
53
|
+
Object.keys(annotation[property]).forEach((definition) => {
|
|
54
|
+
swaggerObject[property][definition] = mergeDeep(swaggerObject[property][definition], annotation[property][definition]);
|
|
55
|
+
});
|
|
56
|
+
} else if (property === "tags") {
|
|
57
|
+
const { tags } = annotation;
|
|
58
|
+
if (Array.isArray(tags)) {
|
|
59
|
+
tags.forEach((tag) => {
|
|
60
|
+
if (!isTagPresentInTags(tag, swaggerObject.tags)) {
|
|
61
|
+
swaggerObject.tags.push(tag);
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
} else if (!isTagPresentInTags(tags, swaggerObject.tags)) {
|
|
65
|
+
swaggerObject.tags.push(tags);
|
|
66
|
+
}
|
|
67
|
+
} else if (property === "security") {
|
|
68
|
+
const { security } = annotation;
|
|
69
|
+
swaggerObject.security = security;
|
|
70
|
+
} else if (property.startsWith("/")) {
|
|
71
|
+
swaggerObject.paths[property] = mergeDeep(swaggerObject.paths[property], annotation[property]);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
const specificationTemplate = {
|
|
76
|
+
v2: ["paths", "definitions", "responses", "parameters", "securityDefinitions"],
|
|
77
|
+
v3: ["paths", "definitions", "responses", "parameters", "securityDefinitions", "components"],
|
|
78
|
+
v4: ["components", "channels"]
|
|
79
|
+
};
|
|
80
|
+
const tagsToObjects = (specs, verbose) => specs.map((spec) => {
|
|
81
|
+
const hasContent = spec.description !== "" || spec.name !== void 0 && (spec.name.startsWith("/") || spec.name.endsWith(":"));
|
|
82
|
+
if ((spec.tag === "openapi" || spec.tag === "swagger" || spec.tag === "asyncapi") && hasContent) {
|
|
83
|
+
let yamlContent = spec.description;
|
|
84
|
+
if (spec.name !== void 0 && (spec.name.startsWith("/") || spec.name.endsWith(":"))) {
|
|
85
|
+
yamlContent = yamlContent.trim() === "" ? spec.name : `${spec.name}
|
|
86
|
+
${yamlContent}`;
|
|
87
|
+
}
|
|
88
|
+
const parsed = yaml__default.parseDocument(yamlContent);
|
|
89
|
+
if (parsed.errors.length > 0) {
|
|
90
|
+
parsed.errors.map((error) => {
|
|
91
|
+
const newError = error;
|
|
92
|
+
newError.annotation = yamlContent;
|
|
93
|
+
return newError;
|
|
94
|
+
});
|
|
95
|
+
let errorString = "Error parsing YAML in @openapi spec:";
|
|
96
|
+
errorString += verbose ? parsed.errors.map(
|
|
97
|
+
(error) => `${error.toString()}
|
|
98
|
+
Imbedded within:
|
|
99
|
+
\`\`\`
|
|
100
|
+
${error.annotation?.replaceAll("\n", "\n ")}
|
|
101
|
+
\`\`\``
|
|
102
|
+
).join("\n") : parsed.errors.map((error) => error.toString()).join("\n");
|
|
103
|
+
throw new Error(errorString);
|
|
104
|
+
}
|
|
105
|
+
const parsedDocument = parsed.toJSON();
|
|
106
|
+
const specification = {
|
|
107
|
+
tags: []
|
|
108
|
+
};
|
|
109
|
+
specificationTemplate[getSwaggerVersionFromSpec(spec)].forEach((property) => {
|
|
110
|
+
specification[property] = specification[property] || {};
|
|
111
|
+
});
|
|
112
|
+
Object.keys(parsedDocument).forEach((property) => {
|
|
113
|
+
organizeSwaggerObject(specification, parsedDocument, property);
|
|
114
|
+
});
|
|
115
|
+
return specification;
|
|
116
|
+
}
|
|
117
|
+
return {};
|
|
118
|
+
});
|
|
119
|
+
const commentsToOpenApi = (fileContents, verbose) => {
|
|
120
|
+
const jsDocumentComments = commentParser.parse(fileContents, { spacing: "preserve" });
|
|
121
|
+
return jsDocumentComments.map((comment) => {
|
|
122
|
+
const loc = comment.tags.length + 1;
|
|
123
|
+
const result = mergeWith__default({}, ...tagsToObjects(comment.tags, verbose), customizer.customizer);
|
|
124
|
+
["definitions", "responses", "parameters", "securityDefinitions", "components", "tags"].forEach((property) => {
|
|
125
|
+
if (result[property] !== void 0 && hasEmptyProperty(result[property])) {
|
|
126
|
+
delete result[property];
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
const spec = JSON.parse(JSON.stringify(result));
|
|
130
|
+
return {
|
|
131
|
+
loc,
|
|
132
|
+
spec
|
|
133
|
+
};
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
module.exports = commentsToOpenApi;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import SwaggerParser from '@apidevtools/swagger-parser';
|
|
2
|
+
|
|
3
|
+
const DEFAULT_EXCLUDE = [
|
|
4
|
+
"coverage/**",
|
|
5
|
+
".github/**",
|
|
6
|
+
"**/*.d.ts",
|
|
7
|
+
"**/test{,s}/**",
|
|
8
|
+
"**/test{,-*}.{js,cjs,mjs,ts,tsx,jsx,yaml,yml}",
|
|
9
|
+
"**/*{.,-}test.{js,cjs,mjs,ts,tsx,jsx,yaml,yml}",
|
|
10
|
+
"**/__tests__/**",
|
|
11
|
+
"**/{ava,babel,nyc}.config.{js,cjs,mjs}",
|
|
12
|
+
"**/jest.config.{js,cjs,mjs,ts}",
|
|
13
|
+
"**/{karma,rollup,webpack}.config.js",
|
|
14
|
+
"**/.{eslint,mocha}rc.{js,cjs}",
|
|
15
|
+
"**/.{travis,yarnrc}.yml",
|
|
16
|
+
"**/{docker-compose,docker}.yml",
|
|
17
|
+
"**/.yamllint.{yaml,yml}",
|
|
18
|
+
"**/node_modules/**",
|
|
19
|
+
"**/{pnpm-workspace,pnpm-lock}.yaml",
|
|
20
|
+
"**/{package,package-lock}.json",
|
|
21
|
+
"**/yarn.lock",
|
|
22
|
+
"**/package.json5",
|
|
23
|
+
"**/.next/**"
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
const validate = async (spec) => {
|
|
27
|
+
await SwaggerParser.validate(spec);
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export { DEFAULT_EXCLUDE as D, validate as v };
|