vls-openapi-generator 1.15.0 → 2.0.0
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/.eslintcache +1 -1
- package/dist/generate-openapi.js +129 -55
- package/dist/lambda-type.d.ts +0 -6
- package/dist/openapi-type.d.ts +11 -14
- package/dist/postman-service.d.ts +6 -6
- package/package.json +7 -5
- package/release.config.js +1 -1
- package/src/generate-openapi.ts +203 -74
- package/src/lambda-type.ts +0 -7
- package/src/openapi-type.ts +10 -10
package/.eslintcache
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
[{"/__w/vls-
|
|
1
|
+
[{"/__w/vls-packages/vls-packages/.commitlintrc.js":"1","/__w/vls-packages/vls-packages/dist/generate-openapi.js":"2","/__w/vls-packages/vls-packages/dist/index.js":"3","/__w/vls-packages/vls-packages/dist/lambda-type.js":"4","/__w/vls-packages/vls-packages/dist/openapi-type.js":"5","/__w/vls-packages/vls-packages/dist/postman-service.js":"6","/__w/vls-packages/vls-packages/dist/upload-openapi.js":"7","/__w/vls-packages/vls-packages/eslint.config.mjs":"8","/__w/vls-packages/vls-packages/release.config.js":"9","/__w/vls-packages/vls-packages/src/generate-openapi.ts":"10","/__w/vls-packages/vls-packages/src/index.ts":"11","/__w/vls-packages/vls-packages/src/lambda-type.ts":"12","/__w/vls-packages/vls-packages/src/openapi-type.ts":"13","/__w/vls-packages/vls-packages/src/postman-service.ts":"14","/__w/vls-packages/vls-packages/src/upload-openapi.ts":"15"},{"size":103,"mtime":1767342111724,"results":"16","hashOfConfig":"17"},{"size":9432,"mtime":1767342117884,"results":"18","hashOfConfig":"17"},{"size":530,"mtime":1767342117932,"results":"19","hashOfConfig":"17"},{"size":77,"mtime":1767342117844,"results":"20","hashOfConfig":"17"},{"size":77,"mtime":1767342117848,"results":"21","hashOfConfig":"17"},{"size":3073,"mtime":1767342117900,"results":"22","hashOfConfig":"17"},{"size":5361,"mtime":1767342117928,"results":"23","hashOfConfig":"17"},{"size":1247,"mtime":1767342111724,"results":"24","hashOfConfig":"17"},{"size":414,"mtime":1767342111728,"results":"25","hashOfConfig":"17"},{"size":9628,"mtime":1767342111728,"results":"26","hashOfConfig":"27"},{"size":441,"mtime":1767342111728,"results":"28","hashOfConfig":"27"},{"size":90,"mtime":1767342111728,"results":"29","hashOfConfig":"27"},{"size":1630,"mtime":1767342111728,"results":"30","hashOfConfig":"27"},{"size":3666,"mtime":1767342111728,"results":"31","hashOfConfig":"27"},{"size":3960,"mtime":1767342111728,"results":"32","hashOfConfig":"27"},{"filePath":"33","messages":"34","suppressedMessages":"35","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"47mvrp",{"filePath":"36","messages":"37","suppressedMessages":"38","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"39","messages":"40","suppressedMessages":"41","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"42","messages":"43","suppressedMessages":"44","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"45","messages":"46","suppressedMessages":"47","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"48","messages":"49","suppressedMessages":"50","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"51","messages":"52","suppressedMessages":"53","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"54","messages":"55","suppressedMessages":"56","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"57","messages":"58","suppressedMessages":"59","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"60","messages":"61","suppressedMessages":"62","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"1js9mgi",{"filePath":"63","messages":"64","suppressedMessages":"65","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"66","messages":"67","suppressedMessages":"68","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"69","messages":"70","suppressedMessages":"71","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"72","messages":"73","suppressedMessages":"74","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},{"filePath":"75","messages":"76","suppressedMessages":"77","errorCount":0,"fatalErrorCount":0,"warningCount":0,"fixableErrorCount":0,"fixableWarningCount":0},"/__w/vls-packages/vls-packages/.commitlintrc.js",[],[],"/__w/vls-packages/vls-packages/dist/generate-openapi.js",[],[],"/__w/vls-packages/vls-packages/dist/index.js",[],[],"/__w/vls-packages/vls-packages/dist/lambda-type.js",[],[],"/__w/vls-packages/vls-packages/dist/openapi-type.js",[],[],"/__w/vls-packages/vls-packages/dist/postman-service.js",[],[],"/__w/vls-packages/vls-packages/dist/upload-openapi.js",[],[],"/__w/vls-packages/vls-packages/eslint.config.mjs",[],[],"/__w/vls-packages/vls-packages/release.config.js",[],[],"/__w/vls-packages/vls-packages/src/generate-openapi.ts",[],[],"/__w/vls-packages/vls-packages/src/index.ts",[],[],"/__w/vls-packages/vls-packages/src/lambda-type.ts",[],[],"/__w/vls-packages/vls-packages/src/openapi-type.ts",[],[],"/__w/vls-packages/vls-packages/src/postman-service.ts",[],[],"/__w/vls-packages/vls-packages/src/upload-openapi.ts",[],[]]
|
package/dist/generate-openapi.js
CHANGED
|
@@ -34,13 +34,14 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.generateOpenAPI = void 0;
|
|
37
|
-
const zod_openapi_1 = require("
|
|
37
|
+
const zod_openapi_1 = require("zod-openapi");
|
|
38
38
|
const node_child_process_1 = require("node:child_process");
|
|
39
39
|
const node_fs_1 = require("node:fs");
|
|
40
40
|
require("module-alias/register.js");
|
|
41
41
|
const path = __importStar(require("node:path"));
|
|
42
42
|
const node_util_1 = require("node:util");
|
|
43
43
|
const zod_1 = require("zod");
|
|
44
|
+
const axios_1 = require("axios");
|
|
44
45
|
const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
|
|
45
46
|
const HANDLERS_DIR = path.join(process.cwd(), 'dist', 'src', 'handlers');
|
|
46
47
|
const SCHEMAS_DIR = path.join(process.cwd(), 'dist', 'src', 'schemas');
|
|
@@ -64,7 +65,7 @@ const generateOpenAPI = async () => {
|
|
|
64
65
|
if (fileName.match(/^([a-z]+-)+queue-(publisher|consumer)$/)) {
|
|
65
66
|
continue;
|
|
66
67
|
}
|
|
67
|
-
const {
|
|
68
|
+
const { requestSchema, successfulResponseSchema, errorResponseSchema, OPENAPI_CONFIG: openAPIConfig } = (await Promise.resolve(`${path.join(SCHEMAS_DIR, fileName + '.js')}`).then(s => __importStar(require(s))).catch((error) => {
|
|
68
69
|
console.error(error);
|
|
69
70
|
return {};
|
|
70
71
|
}));
|
|
@@ -75,69 +76,142 @@ const generateOpenAPI = async () => {
|
|
|
75
76
|
continue;
|
|
76
77
|
}
|
|
77
78
|
const { LAMBDA_CONFIG } = (await Promise.resolve(`${path.join(HANDLERS_DIR, `${fileName}.js`)}`).then(s => __importStar(require(s))));
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
79
|
+
const responses = {};
|
|
80
|
+
for (const label in successfulResponseSchema) {
|
|
81
|
+
const response = successfulResponseSchema[label];
|
|
82
|
+
responses[`Success - ${axios_1.HttpStatusCode[response.status]} - ${label}`] = {
|
|
83
|
+
description: axios_1.HttpStatusCode[response.status].toString(),
|
|
84
|
+
content: {
|
|
85
|
+
'application/json': {
|
|
86
|
+
schema: response.type === 'mindbehind'
|
|
87
|
+
? (0, zod_openapi_1.createSchema)(zod_1.z.object({
|
|
88
|
+
content: zod_1.z.object({
|
|
89
|
+
params: response.parameters,
|
|
90
|
+
modules: response.modules,
|
|
91
|
+
fallback: zod_1.z.literal(false)
|
|
92
|
+
})
|
|
93
|
+
}), {
|
|
94
|
+
openapiVersion: '3.1.1',
|
|
95
|
+
io: 'output'
|
|
96
|
+
}).schema
|
|
97
|
+
: (0, zod_openapi_1.createSchema)(response.parameters, {
|
|
98
|
+
openapiVersion: '3.1.1',
|
|
99
|
+
io: 'output'
|
|
100
|
+
}).schema
|
|
101
|
+
}
|
|
87
102
|
}
|
|
88
|
-
|
|
89
|
-
name: key,
|
|
90
|
-
in: 'query',
|
|
91
|
-
schema: properties[key]
|
|
92
|
-
});
|
|
93
|
-
}
|
|
103
|
+
};
|
|
94
104
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
105
|
+
for (const label in errorResponseSchema) {
|
|
106
|
+
const response = errorResponseSchema[label];
|
|
107
|
+
responses[`Error - ${axios_1.HttpStatusCode[response.status]} - ${label}`] = {
|
|
108
|
+
description: axios_1.HttpStatusCode[response.status].toString(),
|
|
109
|
+
content: {
|
|
110
|
+
'application/json': {
|
|
111
|
+
schema: response.type === 'mindbehind'
|
|
112
|
+
? (0, zod_openapi_1.createSchema)(zod_1.z.object({
|
|
113
|
+
content: zod_1.z.object({
|
|
114
|
+
params: response.parameters,
|
|
115
|
+
modules: response.modules,
|
|
116
|
+
fallback: zod_1.z.literal(false)
|
|
117
|
+
})
|
|
118
|
+
}), {
|
|
119
|
+
openapiVersion: '3.1.1',
|
|
120
|
+
io: 'output'
|
|
121
|
+
}).schema
|
|
122
|
+
: (0, zod_openapi_1.createSchema)(response.parameters, {
|
|
123
|
+
openapiVersion: '3.1.1',
|
|
124
|
+
io: 'output'
|
|
125
|
+
}).schema
|
|
107
126
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
const parameters = [];
|
|
131
|
+
const bodySchemas = [];
|
|
132
|
+
const headersSchemas = [];
|
|
133
|
+
const queryParametersSchemas = [];
|
|
134
|
+
for (const label in requestSchema) {
|
|
135
|
+
const { body, headers, queryParameters } = requestSchema[label];
|
|
136
|
+
if (!(body instanceof zod_1.z.ZodNever)) {
|
|
137
|
+
bodySchemas.push(body.meta({
|
|
138
|
+
title: label
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
if (!(headers instanceof zod_1.z.ZodNever)) {
|
|
142
|
+
headersSchemas.push(headers.meta({
|
|
143
|
+
title: label
|
|
144
|
+
}));
|
|
145
|
+
}
|
|
146
|
+
if (!(queryParameters instanceof zod_1.z.ZodNever)) {
|
|
147
|
+
queryParametersSchemas.push(queryParameters.meta({
|
|
148
|
+
title: label
|
|
149
|
+
}));
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const bodyComponent = bodySchemas.length !== 0
|
|
153
|
+
? (0, zod_openapi_1.createSchema)(zod_1.z.union(bodySchemas), {
|
|
154
|
+
openapiVersion: '3.1.1',
|
|
155
|
+
io: 'input'
|
|
156
|
+
})
|
|
157
|
+
: null;
|
|
158
|
+
const headersComponent = headersSchemas.length !== 0
|
|
159
|
+
? (0, zod_openapi_1.createSchema)(zod_1.z.union(headersSchemas), {
|
|
160
|
+
openapiVersion: '3.1.1',
|
|
161
|
+
io: 'input'
|
|
162
|
+
})
|
|
163
|
+
: null;
|
|
164
|
+
const queryParametersComponent = queryParametersSchemas.length !== 0
|
|
165
|
+
? (0, zod_openapi_1.createSchema)(zod_1.z.union(queryParametersSchemas), {
|
|
166
|
+
openapiVersion: '3.1.1',
|
|
167
|
+
io: 'input'
|
|
168
|
+
})
|
|
169
|
+
: null;
|
|
170
|
+
if (queryParametersComponent) {
|
|
171
|
+
explodeObject(queryParametersComponent.schema, parameters, 'query');
|
|
172
|
+
}
|
|
173
|
+
if (headersComponent) {
|
|
174
|
+
explodeObject(headersComponent.schema, parameters, 'header');
|
|
175
|
+
}
|
|
176
|
+
for (const method of LAMBDA_CONFIG?.api?.methods ?? ['POST']) {
|
|
177
|
+
existingOpenAPIFile.paths['/' + fileName] = {
|
|
178
|
+
[method.toLowerCase()]: {
|
|
179
|
+
tags: openAPIConfig.tags,
|
|
180
|
+
parameters: parameters,
|
|
181
|
+
requestBody: bodyComponent
|
|
182
|
+
? {
|
|
183
|
+
content: {
|
|
184
|
+
'application/json': {
|
|
185
|
+
schema: bodyComponent.schema
|
|
186
|
+
}
|
|
115
187
|
}
|
|
116
188
|
}
|
|
117
|
-
|
|
189
|
+
: undefined,
|
|
190
|
+
responses
|
|
118
191
|
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
121
194
|
}
|
|
122
195
|
await node_fs_1.promises.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
|
|
123
196
|
console.info('Open API documentation generated successfully');
|
|
124
197
|
};
|
|
125
198
|
exports.generateOpenAPI = generateOpenAPI;
|
|
126
|
-
function
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
199
|
+
function explodeObject(schema, parameters, type, isRequiredIncluded = true) {
|
|
200
|
+
if (!('type' in schema) || schema.type !== 'object') {
|
|
201
|
+
parameters.push({
|
|
202
|
+
name: '-',
|
|
203
|
+
in: type,
|
|
204
|
+
schema: schema,
|
|
205
|
+
required: true
|
|
206
|
+
});
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
for (const element in schema.properties) {
|
|
210
|
+
parameters.push({
|
|
211
|
+
name: element,
|
|
212
|
+
in: type,
|
|
213
|
+
schema: schema.properties[element],
|
|
214
|
+
required: isRequiredIncluded ? schema.required?.includes(element) ?? false : false
|
|
215
|
+
});
|
|
141
216
|
}
|
|
142
|
-
return (0, zod_openapi_1.generateSchema)(eventResponseParametersSchema ?? zod_1.z.object({}), undefined, '3.0');
|
|
143
217
|
}
|
package/dist/lambda-type.d.ts
CHANGED
package/dist/openapi-type.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSchema } from 'zod-openapi';
|
|
2
2
|
export type OpenAPI = {
|
|
3
|
-
openapi: '3.
|
|
3
|
+
openapi: '3.1.1';
|
|
4
4
|
info: {
|
|
5
5
|
title: string;
|
|
6
6
|
version: string;
|
|
@@ -16,26 +16,23 @@ export type OpenAPI = {
|
|
|
16
16
|
parameters: {
|
|
17
17
|
name: string;
|
|
18
18
|
in: 'query';
|
|
19
|
-
schema: ReturnType<typeof
|
|
19
|
+
schema: ReturnType<typeof createSchema>['schema'];
|
|
20
20
|
}[] | undefined;
|
|
21
21
|
requestBody: {
|
|
22
22
|
required: true;
|
|
23
23
|
content: {
|
|
24
24
|
'application/json': {
|
|
25
|
-
schema: ReturnType<typeof
|
|
25
|
+
schema: ReturnType<typeof createSchema>['schema'];
|
|
26
26
|
};
|
|
27
27
|
};
|
|
28
28
|
} | undefined;
|
|
29
|
-
responses: {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
} | undefined;
|
|
37
|
-
};
|
|
38
|
-
};
|
|
29
|
+
responses: Record<number, {
|
|
30
|
+
content: {
|
|
31
|
+
'application/json': {
|
|
32
|
+
schema: ReturnType<typeof createSchema>['schema'];
|
|
33
|
+
};
|
|
34
|
+
} | undefined;
|
|
35
|
+
}>;
|
|
39
36
|
tags: string[];
|
|
40
37
|
}>>>;
|
|
41
38
|
};
|
|
@@ -26,13 +26,13 @@ export declare class PostmanService {
|
|
|
26
26
|
};
|
|
27
27
|
}>;
|
|
28
28
|
createCollection: (partnerName: string) => Promise<string>;
|
|
29
|
-
deleteFolder: (collectionID: string, folderID: string) => Promise<import("axios").AxiosResponse<any, any
|
|
30
|
-
createFolder: (collectionID: string, folderName: string) => Promise<import("axios").AxiosResponse<any, any
|
|
31
|
-
updateCollection: (collectionID: string, collection: object) => Promise<import("axios").AxiosResponse<any, any
|
|
29
|
+
deleteFolder: (collectionID: string, folderID: string) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
30
|
+
createFolder: (collectionID: string, folderName: string) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
31
|
+
updateCollection: (collectionID: string, collection: object) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
32
32
|
updateVariablesCollection: (collectionID: string, variables: {
|
|
33
33
|
key: string;
|
|
34
34
|
value: string;
|
|
35
|
-
}[]) => Promise<import("axios").AxiosResponse<any, any
|
|
35
|
+
}[]) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
36
36
|
getAllEnvironments: () => Promise<{
|
|
37
37
|
environments: {
|
|
38
38
|
id: string;
|
|
@@ -42,9 +42,9 @@ export declare class PostmanService {
|
|
|
42
42
|
createEnvironment: (name: string, values: {
|
|
43
43
|
key: string;
|
|
44
44
|
value: string;
|
|
45
|
-
}[]) => Promise<import("axios").AxiosResponse<any, any
|
|
45
|
+
}[]) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
46
46
|
updateEnvironment: (id: string, name: string, values: {
|
|
47
47
|
key: string;
|
|
48
48
|
value: string;
|
|
49
|
-
}[]) => Promise<import("axios").AxiosResponse<any, any
|
|
49
|
+
}[]) => Promise<import("axios").AxiosResponse<any, any>>;
|
|
50
50
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vls-openapi-generator",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -15,10 +15,10 @@
|
|
|
15
15
|
"license": "ISC",
|
|
16
16
|
"description": "VLS Open API Generator",
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"@anatine/zod-openapi": "^2.2.7",
|
|
19
|
-
"axios": "^1.12.0",
|
|
20
18
|
"module-alias": "^2.2.3",
|
|
21
|
-
"openapi-to-postmanv2": "^4.25.0"
|
|
19
|
+
"openapi-to-postmanv2": "^4.25.0",
|
|
20
|
+
"zod": "^4.2.1",
|
|
21
|
+
"zod-openapi": "^5.4.5"
|
|
22
22
|
},
|
|
23
23
|
"devDependencies": {
|
|
24
24
|
"@commitlint/config-conventional": "^19.5.0",
|
|
@@ -27,13 +27,15 @@
|
|
|
27
27
|
"@semantic-release/npm": "^12.0.1",
|
|
28
28
|
"@types/node": "^20.14.8",
|
|
29
29
|
"@types/openapi-to-postmanv2": "^3.2.4",
|
|
30
|
+
"axios": "^1.8.3",
|
|
30
31
|
"commitlint": "^19.5.0",
|
|
31
32
|
"eslint": "^9.12.0",
|
|
32
33
|
"husky": "^9.1.6",
|
|
33
34
|
"prettier": "^2.7.1",
|
|
34
35
|
"semantic-release": "^24.1.2",
|
|
35
36
|
"typescript": "^5.6.3",
|
|
36
|
-
"typescript-eslint": "^8.9.0"
|
|
37
|
+
"typescript-eslint": "^8.9.0",
|
|
38
|
+
"vls-sam-template-generator": "^2.22.0"
|
|
37
39
|
},
|
|
38
40
|
"bin": {
|
|
39
41
|
"vls-openapi-generator": "dist/index.js"
|
package/release.config.js
CHANGED
package/src/generate-openapi.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSchema, ZodOpenApiSchemaObject } from 'zod-openapi';
|
|
2
2
|
import { exec } from 'node:child_process';
|
|
3
3
|
import { promises as fs } from 'node:fs';
|
|
4
4
|
import 'module-alias/register.js';
|
|
5
5
|
import * as path from 'node:path';
|
|
6
6
|
import { promisify } from 'node:util';
|
|
7
7
|
import { z } from 'zod';
|
|
8
|
-
import {
|
|
8
|
+
import { OpenAPIConfig } from './lambda-type';
|
|
9
9
|
import { OpenAPI } from './openapi-type';
|
|
10
|
+
import type { LambdaConfig } from 'vls-sam-template-generator';
|
|
11
|
+
import { HttpStatusCode } from 'axios';
|
|
10
12
|
|
|
11
13
|
const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
|
|
12
14
|
const HANDLERS_DIR = path.join(process.cwd(), 'dist', 'src', 'handlers');
|
|
@@ -43,20 +45,18 @@ export const generateOpenAPI = async (): Promise<void> => {
|
|
|
43
45
|
}
|
|
44
46
|
|
|
45
47
|
const {
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
eventResponseModulesSchema,
|
|
48
|
+
requestSchema,
|
|
49
|
+
successfulResponseSchema,
|
|
50
|
+
errorResponseSchema,
|
|
50
51
|
OPENAPI_CONFIG: openAPIConfig
|
|
51
52
|
} = (await import(path.join(SCHEMAS_DIR, fileName + '.js')).catch((error) => {
|
|
52
53
|
console.error(error);
|
|
53
54
|
|
|
54
55
|
return {};
|
|
55
56
|
})) as {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
queryParametersSchema?: OpenApiZodAny;
|
|
57
|
+
requestSchema: RequestSchema;
|
|
58
|
+
successfulResponseSchema?: ResponseSchema;
|
|
59
|
+
errorResponseSchema?: ResponseSchema;
|
|
60
60
|
OPENAPI_CONFIG: OpenAPIConfig;
|
|
61
61
|
};
|
|
62
62
|
|
|
@@ -72,58 +72,157 @@ export const generateOpenAPI = async (): Promise<void> => {
|
|
|
72
72
|
LAMBDA_CONFIG?: LambdaConfig;
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
eventResponseParametersSchema,
|
|
80
|
-
eventResponseModulesSchema
|
|
81
|
-
);
|
|
75
|
+
const responses: Record<
|
|
76
|
+
string,
|
|
77
|
+
{ description: string; content: { 'application/json': { schema: ZodOpenApiSchemaObject } } }
|
|
78
|
+
> = {};
|
|
82
79
|
|
|
83
|
-
const
|
|
80
|
+
for (const label in successfulResponseSchema) {
|
|
81
|
+
const response = successfulResponseSchema[label];
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
83
|
+
responses[`Success - ${HttpStatusCode[response.status]} - ${label}`] = {
|
|
84
|
+
description: HttpStatusCode[response.status].toString(),
|
|
85
|
+
content: {
|
|
86
|
+
'application/json': {
|
|
87
|
+
schema:
|
|
88
|
+
response.type === 'mindbehind'
|
|
89
|
+
? createSchema(
|
|
90
|
+
z.object({
|
|
91
|
+
content: z.object({
|
|
92
|
+
params: response.parameters,
|
|
93
|
+
modules: response.modules,
|
|
94
|
+
fallback: z.literal(false)
|
|
95
|
+
})
|
|
96
|
+
}),
|
|
97
|
+
{
|
|
98
|
+
openapiVersion: '3.1.1',
|
|
99
|
+
io: 'output'
|
|
100
|
+
}
|
|
101
|
+
).schema
|
|
102
|
+
: createSchema(response.parameters, {
|
|
103
|
+
openapiVersion: '3.1.1',
|
|
104
|
+
io: 'output'
|
|
105
|
+
}).schema
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
for (const label in errorResponseSchema) {
|
|
112
|
+
const response = errorResponseSchema[label];
|
|
88
113
|
|
|
89
|
-
|
|
90
|
-
|
|
114
|
+
responses[`Error - ${HttpStatusCode[response.status]} - ${label}`] = {
|
|
115
|
+
description: HttpStatusCode[response.status].toString(),
|
|
116
|
+
content: {
|
|
117
|
+
'application/json': {
|
|
118
|
+
schema:
|
|
119
|
+
response.type === 'mindbehind'
|
|
120
|
+
? createSchema(
|
|
121
|
+
z.object({
|
|
122
|
+
content: z.object({
|
|
123
|
+
params: response.parameters,
|
|
124
|
+
modules: response.modules,
|
|
125
|
+
fallback: z.literal(false)
|
|
126
|
+
})
|
|
127
|
+
}),
|
|
128
|
+
{
|
|
129
|
+
openapiVersion: '3.1.1',
|
|
130
|
+
io: 'output'
|
|
131
|
+
}
|
|
132
|
+
).schema
|
|
133
|
+
: createSchema(response.parameters, {
|
|
134
|
+
openapiVersion: '3.1.1',
|
|
135
|
+
io: 'output'
|
|
136
|
+
}).schema
|
|
137
|
+
}
|
|
91
138
|
}
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
const parameters: Parameter[] = [];
|
|
143
|
+
|
|
144
|
+
const bodySchemas = [];
|
|
145
|
+
const headersSchemas = [];
|
|
146
|
+
const queryParametersSchemas = [];
|
|
92
147
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
148
|
+
for (const label in requestSchema) {
|
|
149
|
+
const { body, headers, queryParameters } = requestSchema[label];
|
|
150
|
+
|
|
151
|
+
if (!(body instanceof z.ZodNever)) {
|
|
152
|
+
bodySchemas.push(
|
|
153
|
+
body.meta({
|
|
154
|
+
title: label
|
|
155
|
+
})
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (!(headers instanceof z.ZodNever)) {
|
|
160
|
+
headersSchemas.push(
|
|
161
|
+
headers.meta({
|
|
162
|
+
title: label
|
|
163
|
+
})
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (!(queryParameters instanceof z.ZodNever)) {
|
|
168
|
+
queryParametersSchemas.push(
|
|
169
|
+
queryParameters.meta({
|
|
170
|
+
title: label
|
|
171
|
+
})
|
|
172
|
+
);
|
|
98
173
|
}
|
|
99
174
|
}
|
|
100
175
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
176
|
+
const bodyComponent =
|
|
177
|
+
bodySchemas.length !== 0
|
|
178
|
+
? createSchema(z.union(bodySchemas), {
|
|
179
|
+
openapiVersion: '3.1.1',
|
|
180
|
+
io: 'input'
|
|
181
|
+
})
|
|
182
|
+
: null;
|
|
183
|
+
|
|
184
|
+
const headersComponent =
|
|
185
|
+
headersSchemas.length !== 0
|
|
186
|
+
? createSchema(z.union(headersSchemas), {
|
|
187
|
+
openapiVersion: '3.1.1',
|
|
188
|
+
io: 'input'
|
|
189
|
+
})
|
|
190
|
+
: null;
|
|
191
|
+
|
|
192
|
+
const queryParametersComponent =
|
|
193
|
+
queryParametersSchemas.length !== 0
|
|
194
|
+
? createSchema(z.union(queryParametersSchemas), {
|
|
195
|
+
openapiVersion: '3.1.1',
|
|
196
|
+
io: 'input'
|
|
197
|
+
})
|
|
198
|
+
: null;
|
|
199
|
+
|
|
200
|
+
if (queryParametersComponent) {
|
|
201
|
+
explodeObject(queryParametersComponent.schema, parameters, 'query');
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (headersComponent) {
|
|
205
|
+
explodeObject(headersComponent.schema, parameters, 'header');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
for (const method of LAMBDA_CONFIG?.api?.methods ?? ['POST']) {
|
|
209
|
+
existingOpenAPIFile.paths['/' + fileName] = {
|
|
210
|
+
[method.toLowerCase()]: {
|
|
211
|
+
tags: openAPIConfig.tags,
|
|
212
|
+
parameters: parameters,
|
|
213
|
+
requestBody: bodyComponent
|
|
214
|
+
? {
|
|
215
|
+
content: {
|
|
216
|
+
'application/json': {
|
|
217
|
+
schema: bodyComponent.schema
|
|
218
|
+
}
|
|
111
219
|
}
|
|
112
220
|
}
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
responses: {
|
|
116
|
-
'200': {
|
|
117
|
-
description: `Successful response.`,
|
|
118
|
-
content: {
|
|
119
|
-
'application/json': {
|
|
120
|
-
schema: eventResponseComponent
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
}
|
|
221
|
+
: undefined,
|
|
222
|
+
responses
|
|
124
223
|
}
|
|
125
|
-
}
|
|
126
|
-
}
|
|
224
|
+
};
|
|
225
|
+
}
|
|
127
226
|
}
|
|
128
227
|
|
|
129
228
|
await fs.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
|
|
@@ -131,30 +230,60 @@ export const generateOpenAPI = async (): Promise<void> => {
|
|
|
131
230
|
console.info('Open API documentation generated successfully');
|
|
132
231
|
};
|
|
133
232
|
|
|
134
|
-
function
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
233
|
+
function explodeObject(
|
|
234
|
+
schema: ZodOpenApiSchemaObject,
|
|
235
|
+
parameters: Parameter[],
|
|
236
|
+
type: 'header' | 'query',
|
|
237
|
+
isRequiredIncluded = true
|
|
138
238
|
) {
|
|
139
|
-
if (
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
modules: extendApi(z.array(z.unknown()), {
|
|
149
|
-
example: []
|
|
150
|
-
})
|
|
151
|
-
}),
|
|
152
|
-
fallback: z.boolean().default(false)
|
|
153
|
-
}),
|
|
154
|
-
undefined,
|
|
155
|
-
'3.0'
|
|
156
|
-
);
|
|
239
|
+
if (!('type' in schema) || schema.type !== 'object') {
|
|
240
|
+
parameters.push({
|
|
241
|
+
name: '-',
|
|
242
|
+
in: type,
|
|
243
|
+
schema: schema,
|
|
244
|
+
required: true
|
|
245
|
+
} as const);
|
|
246
|
+
|
|
247
|
+
return;
|
|
157
248
|
}
|
|
158
249
|
|
|
159
|
-
|
|
250
|
+
for (const element in schema.properties) {
|
|
251
|
+
parameters.push({
|
|
252
|
+
name: element,
|
|
253
|
+
in: type,
|
|
254
|
+
schema: schema.properties[element],
|
|
255
|
+
required: isRequiredIncluded ? schema.required?.includes(element) ?? false : false
|
|
256
|
+
} as const);
|
|
257
|
+
}
|
|
160
258
|
}
|
|
259
|
+
|
|
260
|
+
type Parameter = {
|
|
261
|
+
name: string;
|
|
262
|
+
in: 'query' | 'header';
|
|
263
|
+
schema: unknown;
|
|
264
|
+
required: boolean;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
type RequestSchema = Record<
|
|
268
|
+
string,
|
|
269
|
+
{
|
|
270
|
+
body: z.ZodType;
|
|
271
|
+
queryParameters: z.ZodObject | z.ZodNever;
|
|
272
|
+
headers: z.ZodObject | z.ZodNever;
|
|
273
|
+
}
|
|
274
|
+
>;
|
|
275
|
+
|
|
276
|
+
type ResponseSchema = Record<
|
|
277
|
+
string,
|
|
278
|
+
| {
|
|
279
|
+
type: 'mindbehind';
|
|
280
|
+
status: keyof typeof HttpStatusCode;
|
|
281
|
+
parameters: z.ZodType;
|
|
282
|
+
modules: z.ZodArray;
|
|
283
|
+
}
|
|
284
|
+
| {
|
|
285
|
+
type: 'api';
|
|
286
|
+
status: keyof typeof HttpStatusCode;
|
|
287
|
+
parameters: z.ZodType;
|
|
288
|
+
}
|
|
289
|
+
>;
|
package/src/lambda-type.ts
CHANGED
package/src/openapi-type.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createSchema } from 'zod-openapi';
|
|
2
2
|
|
|
3
3
|
export type OpenAPI = {
|
|
4
|
-
openapi: '3.
|
|
4
|
+
openapi: '3.1.1';
|
|
5
5
|
info: { title: string; version: string };
|
|
6
6
|
servers: [{ url: string }, { url: string }, { url: string }];
|
|
7
7
|
paths: Record<
|
|
@@ -14,7 +14,7 @@ export type OpenAPI = {
|
|
|
14
14
|
| {
|
|
15
15
|
name: string;
|
|
16
16
|
in: 'query';
|
|
17
|
-
schema: ReturnType<typeof
|
|
17
|
+
schema: ReturnType<typeof createSchema>['schema'];
|
|
18
18
|
}[]
|
|
19
19
|
| undefined;
|
|
20
20
|
requestBody:
|
|
@@ -22,23 +22,23 @@ export type OpenAPI = {
|
|
|
22
22
|
required: true;
|
|
23
23
|
content: {
|
|
24
24
|
'application/json': {
|
|
25
|
-
schema: ReturnType<typeof
|
|
25
|
+
schema: ReturnType<typeof createSchema>['schema'];
|
|
26
26
|
};
|
|
27
27
|
};
|
|
28
28
|
}
|
|
29
29
|
| undefined;
|
|
30
|
-
responses:
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
responses: Record<
|
|
31
|
+
number,
|
|
32
|
+
{
|
|
33
33
|
content:
|
|
34
34
|
| {
|
|
35
35
|
'application/json': {
|
|
36
|
-
schema: ReturnType<typeof
|
|
36
|
+
schema: ReturnType<typeof createSchema>['schema'];
|
|
37
37
|
};
|
|
38
38
|
}
|
|
39
39
|
| undefined;
|
|
40
|
-
}
|
|
41
|
-
|
|
40
|
+
}
|
|
41
|
+
>;
|
|
42
42
|
tags: string[];
|
|
43
43
|
}
|
|
44
44
|
>
|