@accelbyte/codegen 1.0.0-alpha.1
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 +40 -0
- package/README.md +143 -0
- package/dist/accelbyte-codegen.js +972 -0
- package/dist/accelbyte-codegen.js.map +1 -0
- package/dist/accelbyte-codegen.mjs +941 -0
- package/dist/accelbyte-codegen.mjs.map +1 -0
- package/package.json +35 -0
|
@@ -0,0 +1,972 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
4
|
+
|
|
5
|
+
var yargs = require('yargs');
|
|
6
|
+
var zod = require('zod');
|
|
7
|
+
var fs = require('fs');
|
|
8
|
+
var path = require('path');
|
|
9
|
+
var SwaggerParser = require('@apidevtools/swagger-parser');
|
|
10
|
+
var _ = require('lodash');
|
|
11
|
+
var fastJsonPatch = require('fast-json-patch');
|
|
12
|
+
var https = require('https');
|
|
13
|
+
|
|
14
|
+
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
15
|
+
|
|
16
|
+
function _interopNamespace(e) {
|
|
17
|
+
if (e && e.__esModule) return e;
|
|
18
|
+
var n = Object.create(null);
|
|
19
|
+
if (e) {
|
|
20
|
+
Object.keys(e).forEach(function (k) {
|
|
21
|
+
if (k !== 'default') {
|
|
22
|
+
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
23
|
+
Object.defineProperty(n, k, d.get ? d : {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return e[k]; }
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
n["default"] = e;
|
|
31
|
+
return Object.freeze(n);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var yargs__default = /*#__PURE__*/_interopDefaultLegacy(yargs);
|
|
35
|
+
var fs__default = /*#__PURE__*/_interopDefaultLegacy(fs);
|
|
36
|
+
var fs__namespace = /*#__PURE__*/_interopNamespace(fs);
|
|
37
|
+
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
38
|
+
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
39
|
+
var SwaggerParser__default = /*#__PURE__*/_interopDefaultLegacy(SwaggerParser);
|
|
40
|
+
var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
|
|
41
|
+
var https__namespace = /*#__PURE__*/_interopNamespace(https);
|
|
42
|
+
|
|
43
|
+
const SwaggersConfig = zod.z.array(zod.z.array(zod.z.string()));
|
|
44
|
+
class CliParser {
|
|
45
|
+
static _instance;
|
|
46
|
+
argv;
|
|
47
|
+
constructor(yargs) {
|
|
48
|
+
this.argv = yargs.parse();
|
|
49
|
+
}
|
|
50
|
+
static createInstance = (yargs) => {
|
|
51
|
+
CliParser._instance = new CliParser(yargs);
|
|
52
|
+
return CliParser._instance;
|
|
53
|
+
};
|
|
54
|
+
static instance = (yargs) => {
|
|
55
|
+
if (!CliParser._instance && yargs) {
|
|
56
|
+
return CliParser.createInstance(yargs);
|
|
57
|
+
}
|
|
58
|
+
return CliParser._instance;
|
|
59
|
+
};
|
|
60
|
+
static getConfigPath = () => {
|
|
61
|
+
return CliParser.instance().argv.config;
|
|
62
|
+
};
|
|
63
|
+
static getConfigFile = () => {
|
|
64
|
+
const configPath = CliParser.getConfigPath();
|
|
65
|
+
if (!configPath)
|
|
66
|
+
throw new Error("Missing config file");
|
|
67
|
+
const config = JSON.parse(fs__default["default"].readFileSync(configPath, "utf8"));
|
|
68
|
+
if (!SwaggersConfig.safeParse(config).success) {
|
|
69
|
+
throw new Error("Wrong config file format");
|
|
70
|
+
}
|
|
71
|
+
return config;
|
|
72
|
+
};
|
|
73
|
+
static getOutputPath = () => {
|
|
74
|
+
return CliParser.instance().argv.output;
|
|
75
|
+
};
|
|
76
|
+
static getSwaggersOutputPath = () => {
|
|
77
|
+
return CliParser.instance().argv.swaggersOutput;
|
|
78
|
+
};
|
|
79
|
+
static getResolvedSwaggersOutputPath = () => {
|
|
80
|
+
return path__namespace.resolve(CliParser.getSwaggersOutputPath());
|
|
81
|
+
};
|
|
82
|
+
static isAdmin = () => {
|
|
83
|
+
return CliParser.instance().argv.admin;
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const getImportableVarMap = () => ({
|
|
88
|
+
"@accelbyte/sdk": ["CodeGenUtil", "SdkCache", "IResponse", "IResponseWithSync", "Validate"],
|
|
89
|
+
axios: ["AxiosRequestConfig", "AxiosResponse"],
|
|
90
|
+
zod: ["z"]
|
|
91
|
+
});
|
|
92
|
+
const makeNewImportVarMap = () => ({
|
|
93
|
+
axios: ["AxiosInstance"],
|
|
94
|
+
"@accelbyte/sdk": ["SDKRequestConfig"]
|
|
95
|
+
});
|
|
96
|
+
const generateImports = (body, importStatements) => {
|
|
97
|
+
const usedImportVarMap = makeNewImportVarMap();
|
|
98
|
+
const importableVarMap = getImportableVarMap();
|
|
99
|
+
for (const [moduleSource, importableVars] of Object.entries(importableVarMap)) {
|
|
100
|
+
for (const importableVar of importableVars) {
|
|
101
|
+
const importVarRegex = new RegExp(`(?<![\\d\\w_])${importableVar}(?![\\d\\w_])`);
|
|
102
|
+
if (body.match(importVarRegex)) {
|
|
103
|
+
usedImportVarMap[moduleSource] = [...usedImportVarMap[moduleSource] || [], importableVar];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
const generatedImports = Object.keys(usedImportVarMap).sort().map((moduleSource) => `import { ${usedImportVarMap[moduleSource].sort().join(", ")} } from '${moduleSource}'`).join("\n");
|
|
108
|
+
return `${generatedImports}
|
|
109
|
+
${importStatements.sort().join("\n")}`;
|
|
110
|
+
};
|
|
111
|
+
const templateClass = (className, body, importStatements) => `/**
|
|
112
|
+
* DON'T EDIT THIS FILE, it is AUTO GENERATED
|
|
113
|
+
*/
|
|
114
|
+
${generateImports(body, importStatements)}
|
|
115
|
+
|
|
116
|
+
export class ${className} {
|
|
117
|
+
// @ts-ignore
|
|
118
|
+
constructor(private axiosInstance: AxiosInstance, private namespace: string, private cache = false) {}
|
|
119
|
+
${body}
|
|
120
|
+
}
|
|
121
|
+
`;
|
|
122
|
+
|
|
123
|
+
const templateJsdocFile = (apiName, body) => `
|
|
124
|
+
\`\`\`
|
|
125
|
+
SDK.getService('${apiName}', authHeader):
|
|
126
|
+
${body}
|
|
127
|
+
|
|
128
|
+
\`\`\`
|
|
129
|
+
`.replace(/, \)/g, ")").trim();
|
|
130
|
+
|
|
131
|
+
class ParserUtils {
|
|
132
|
+
static parseQueryParamAttributeDefault = (name, definition) => {
|
|
133
|
+
const attrName = name.slice(name.lastIndexOf(".") + 1);
|
|
134
|
+
const defaultValue = definition.type === "string" ? `'${definition.default}'` : definition.default;
|
|
135
|
+
return `${attrName}: ${defaultValue}`;
|
|
136
|
+
};
|
|
137
|
+
static parseType = (type) => {
|
|
138
|
+
if (type === "integer")
|
|
139
|
+
return "number";
|
|
140
|
+
if (type === "array")
|
|
141
|
+
return "any[]";
|
|
142
|
+
return type;
|
|
143
|
+
};
|
|
144
|
+
static parseQueryParamsType = (queryParams) => {
|
|
145
|
+
return queryParams.map((p) => ParserUtils.parseAttributeType(p.name, p)).join(",");
|
|
146
|
+
};
|
|
147
|
+
static isAnyQueryParamRequired = (queryParams) => {
|
|
148
|
+
queryParams.forEach((p) => {
|
|
149
|
+
if (p.required) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
return false;
|
|
154
|
+
};
|
|
155
|
+
static parseQueryParamsDefault = (queryParams) => {
|
|
156
|
+
const result = queryParams.filter((p) => !!p.default).map((p) => ParserUtils.parseQueryParamAttributeDefault(p.name, p)).join(",");
|
|
157
|
+
return result ? `${result},` : "";
|
|
158
|
+
};
|
|
159
|
+
static parseBodyParamsImports = (bodyParams) => {
|
|
160
|
+
const ret = bodyParams.map((p) => {
|
|
161
|
+
if (p?.schema?.$ref)
|
|
162
|
+
return ParserUtils.parseRefImport(p.schema.$ref, p);
|
|
163
|
+
if (p?.schema?.items?.$ref)
|
|
164
|
+
return ParserUtils.parseRefImport(p.schema.items.$ref, p);
|
|
165
|
+
if (p?.$ref)
|
|
166
|
+
return ParserUtils.parseRefImport(p.$ref, p);
|
|
167
|
+
return null;
|
|
168
|
+
}).filter((p) => !!p);
|
|
169
|
+
return ret;
|
|
170
|
+
};
|
|
171
|
+
static parseImportDir = ($ref) => {
|
|
172
|
+
let ref = $ref.replace(".", "/");
|
|
173
|
+
if (ref[ref.length - 1] === "." || ref[ref.length - 1] === "/") {
|
|
174
|
+
ref = ref.slice(0, -1);
|
|
175
|
+
}
|
|
176
|
+
if (!ref.includes("/")) {
|
|
177
|
+
return "";
|
|
178
|
+
} else {
|
|
179
|
+
return ref.slice(0, ref.lastIndexOf("/")).replace("#", ".");
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
static parseRefImport = ($ref, p) => {
|
|
183
|
+
const type = ParserUtils.parseRefType($ref);
|
|
184
|
+
return `import { ${type} } from './definitions/${type}'`;
|
|
185
|
+
};
|
|
186
|
+
static parseRefType = ($ref) => {
|
|
187
|
+
let ref = $ref.replace(".", "/");
|
|
188
|
+
if (ref[ref.length - 1] === "." || ref[ref.length - 1] === "/") {
|
|
189
|
+
ref = ref.slice(0, -1);
|
|
190
|
+
}
|
|
191
|
+
const val = ref.slice(ref.lastIndexOf("/") + 1);
|
|
192
|
+
return ___default["default"].upperFirst(___default["default"].camelCase(val));
|
|
193
|
+
};
|
|
194
|
+
static parseAttributeType = (name, definition) => {
|
|
195
|
+
const required = definition.required ? "" : "?";
|
|
196
|
+
const attrName = name.slice(name.lastIndexOf(".") + 1);
|
|
197
|
+
if (definition.enums) {
|
|
198
|
+
const enums = definition.enums.map((enm) => definition.type === "string" ? `'${enm}'` : enm).join(" | ");
|
|
199
|
+
return `${attrName}${required}: ${enums}`;
|
|
200
|
+
}
|
|
201
|
+
if (definition.type && definition.type === "integer") {
|
|
202
|
+
return `${attrName}${required}: number`;
|
|
203
|
+
}
|
|
204
|
+
if (definition.type && definition.type === "array") {
|
|
205
|
+
return `${attrName}${required}: ${definition.items.type ?? "any"}[]`;
|
|
206
|
+
}
|
|
207
|
+
if (definition.type && definition.type) {
|
|
208
|
+
return `${attrName}${required}: ${definition.type} | null`;
|
|
209
|
+
}
|
|
210
|
+
return `${attrName}${required}: any`;
|
|
211
|
+
};
|
|
212
|
+
static parseBodyParamsType = (bodyParams) => {
|
|
213
|
+
const [p] = bodyParams;
|
|
214
|
+
if (!p)
|
|
215
|
+
return null;
|
|
216
|
+
if (bodyParams.length > 0 && p?.name !== "body" && !p?.schema) {
|
|
217
|
+
let retBodyParams = `{${bodyParams.map((p2) => ParserUtils.parseAttributeType(p2.name, p2)).join(",")}}`;
|
|
218
|
+
retBodyParams = retBodyParams.replace("file?: file", "file?: File");
|
|
219
|
+
return retBodyParams;
|
|
220
|
+
}
|
|
221
|
+
if (p?.schema?.type === "array" && !p?.schema?.items?.$ref) {
|
|
222
|
+
return `${p.schema.items.type ?? "any"}[]`;
|
|
223
|
+
}
|
|
224
|
+
if (p?.schema?.type === "array" && p?.schema?.items?.$ref) {
|
|
225
|
+
return `${ParserUtils.parseRefType(p.schema.items.$ref)}[]`;
|
|
226
|
+
}
|
|
227
|
+
if (p?.schema.$ref) {
|
|
228
|
+
return ParserUtils.parseRefType(p.schema.$ref);
|
|
229
|
+
}
|
|
230
|
+
if (p?.schema?.additionalProperties?.type === "object") {
|
|
231
|
+
return "any";
|
|
232
|
+
}
|
|
233
|
+
return null;
|
|
234
|
+
};
|
|
235
|
+
static get2xxResponse(methodEntity, path2) {
|
|
236
|
+
const keys = Object.keys(methodEntity);
|
|
237
|
+
let responseClass = null;
|
|
238
|
+
keys.forEach((key) => {
|
|
239
|
+
if (String(key).startsWith("2")) {
|
|
240
|
+
const sch = methodEntity[key].schema;
|
|
241
|
+
if (sch?.$ref) {
|
|
242
|
+
responseClass = ParserUtils.parseRefType(sch.$ref);
|
|
243
|
+
} else if (sch?.type === "array" && sch.items?.$ref) {
|
|
244
|
+
responseClass = ParserUtils.parseRefType(sch.items.$ref);
|
|
245
|
+
responseClass = `${responseClass}Array`;
|
|
246
|
+
} else ;
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
return responseClass;
|
|
250
|
+
}
|
|
251
|
+
static isFormUrlEncoded(httpMethod, contentTypes) {
|
|
252
|
+
if (!contentTypes || contentTypes.length < 1) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
if (!["post", "put", "patch"].includes(httpMethod)) {
|
|
256
|
+
return false;
|
|
257
|
+
}
|
|
258
|
+
return contentTypes.includes("application/x-www-form-urlencoded");
|
|
259
|
+
}
|
|
260
|
+
static getPathParams(parametersArray) {
|
|
261
|
+
if (!parametersArray) {
|
|
262
|
+
return [];
|
|
263
|
+
}
|
|
264
|
+
const res = [];
|
|
265
|
+
for (const p of parametersArray) {
|
|
266
|
+
if (p.in === "path") {
|
|
267
|
+
res.push(p);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
return res;
|
|
271
|
+
}
|
|
272
|
+
static generateClassMethod(path2, parametersArray, httpMethod, className) {
|
|
273
|
+
let replacedIdsPath = path2;
|
|
274
|
+
if (parametersArray) {
|
|
275
|
+
for (const p of parametersArray) {
|
|
276
|
+
if (p.in === "path") {
|
|
277
|
+
replacedIdsPath = replacedIdsPath.replace("{" + p.name + "}", "By" + ParserUtils.toTitleCaseWord(p.name));
|
|
278
|
+
replacedIdsPath = replacedIdsPath.replace("/iam", "");
|
|
279
|
+
replacedIdsPath = replacedIdsPath.replace("/odin-config", "");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
let classMethod = httpMethod + "/" + replacedIdsPath;
|
|
284
|
+
classMethod = ___default["default"].camelCase(classMethod);
|
|
285
|
+
classMethod = classMethod.replace("PublicNamespacesByNamespace", "");
|
|
286
|
+
classMethod = classMethod.replace("AdminNamespacesByNamespace", "Admin");
|
|
287
|
+
const searchWord = "NamespacesByNamespace";
|
|
288
|
+
const nsExistInsideMethod = classMethod.indexOf(searchWord) > 0 && classMethod.indexOf(searchWord) + searchWord.length < classMethod.length;
|
|
289
|
+
const excludedClasses = ["Policies"];
|
|
290
|
+
if (nsExistInsideMethod && !excludedClasses.includes(className)) {
|
|
291
|
+
classMethod = classMethod.replace(searchWord, "");
|
|
292
|
+
}
|
|
293
|
+
return classMethod;
|
|
294
|
+
}
|
|
295
|
+
static getBodyParams(parametersArray) {
|
|
296
|
+
if (!parametersArray)
|
|
297
|
+
return [];
|
|
298
|
+
if (!___default["default"].isArray(parametersArray) && parametersArray)
|
|
299
|
+
return [parametersArray].filter((p) => p.in === "body" || p.in === "formData");
|
|
300
|
+
return parametersArray.filter((p) => p.in === "body" || p.in === "formData");
|
|
301
|
+
}
|
|
302
|
+
static getQueryParameters(parametersArray) {
|
|
303
|
+
if (!parametersArray) {
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
306
|
+
const res = [];
|
|
307
|
+
for (const p of parametersArray) {
|
|
308
|
+
if (p.in === "query") {
|
|
309
|
+
res.push(p);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return res;
|
|
313
|
+
}
|
|
314
|
+
static mkdirIfNotExist(dirToCreate) {
|
|
315
|
+
if (!fs__default["default"].existsSync(dirToCreate)) {
|
|
316
|
+
fs__default["default"].mkdirSync(dirToCreate, { recursive: true });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
static writeClassFile(distDir, apiName, apiBuffer, imports) {
|
|
320
|
+
const fileContent = templateClass(apiName, apiBuffer, imports);
|
|
321
|
+
fs__default["default"].writeFileSync(`${distDir}/${apiName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
|
|
322
|
+
}
|
|
323
|
+
static writeJsdocFile(distDir, nameArray, apiBuffer) {
|
|
324
|
+
const jsdocFile = templateJsdocFile(nameArray[0], apiBuffer);
|
|
325
|
+
fs__default["default"].writeFileSync(`${distDir}/docs/${nameArray[0]}.md`, jsdocFile);
|
|
326
|
+
}
|
|
327
|
+
static writeDefinitionFile(distDir, name, buffer) {
|
|
328
|
+
ParserUtils.mkdirIfNotExist(distDir);
|
|
329
|
+
fs__default["default"].writeFileSync(path__default["default"].join(distDir, `${name}.ts`), ParserUtils.prependCopyrightHeader(buffer));
|
|
330
|
+
}
|
|
331
|
+
static writeAllImportsFile(distDir, buffer, isAdminWebSdk) {
|
|
332
|
+
ParserUtils.mkdirIfNotExist(distDir);
|
|
333
|
+
fs__default["default"].writeFileSync(path__default["default"].join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
|
|
334
|
+
}
|
|
335
|
+
static toCamelCase(str) {
|
|
336
|
+
return str.split("/").map(function(word, index) {
|
|
337
|
+
if (index === 0) {
|
|
338
|
+
return word.toLowerCase();
|
|
339
|
+
}
|
|
340
|
+
return ParserUtils.toCamelCaseWord(word);
|
|
341
|
+
}).join("");
|
|
342
|
+
}
|
|
343
|
+
static toCamelCaseWord(word) {
|
|
344
|
+
if (!word) {
|
|
345
|
+
return "";
|
|
346
|
+
}
|
|
347
|
+
word = word.replace(/(-\w)/g, (m) => m[1].toUpperCase());
|
|
348
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
349
|
+
}
|
|
350
|
+
static toTitleCaseWord(word) {
|
|
351
|
+
if (!word) {
|
|
352
|
+
return "";
|
|
353
|
+
}
|
|
354
|
+
return word.replace(/\w\S*/g, (txt) => {
|
|
355
|
+
return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
static applyPatchIfExists(swaggerFilePath, possibleSwaggerPatchFilePath, swaggerPatchedFilePath, swaggerPatchedDir) {
|
|
359
|
+
if (!fs__default["default"].existsSync(swaggerPatchedDir)) {
|
|
360
|
+
fs__default["default"].mkdirSync(swaggerPatchedDir, { recursive: true });
|
|
361
|
+
}
|
|
362
|
+
if (!fs__default["default"].existsSync(possibleSwaggerPatchFilePath)) {
|
|
363
|
+
fs__default["default"].copyFileSync(swaggerFilePath, swaggerPatchedFilePath);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const swaggerContent = JSON.parse(fs__default["default"].readFileSync(swaggerFilePath, "utf8"));
|
|
367
|
+
const swaggerPatchFileContent = JSON.parse(fs__default["default"].readFileSync(possibleSwaggerPatchFilePath, "utf8"));
|
|
368
|
+
const { newDocument } = fastJsonPatch.applyPatch(swaggerContent, swaggerPatchFileContent);
|
|
369
|
+
fs__default["default"].writeFileSync(swaggerPatchedFilePath, JSON.stringify(newDocument, null, 2));
|
|
370
|
+
}
|
|
371
|
+
static mapKeys(map_) {
|
|
372
|
+
const methods_ = [];
|
|
373
|
+
for (const m in map_) {
|
|
374
|
+
methods_.push(m);
|
|
375
|
+
}
|
|
376
|
+
return methods_;
|
|
377
|
+
}
|
|
378
|
+
static getRelativePathToWebSdkSrcFolder(srcFolder, targetSrcFolder) {
|
|
379
|
+
const replaced = srcFolder.replace(/\\/g, "/");
|
|
380
|
+
return replaced.replace(/\\/g, "/").replace(targetSrcFolder, "./");
|
|
381
|
+
}
|
|
382
|
+
static prependCopyrightHeader = (content) => {
|
|
383
|
+
const currentYear = new Date().getFullYear();
|
|
384
|
+
return `/*
|
|
385
|
+
* Copyright (c) 2022${currentYear > 2022 ? `-${currentYear}` : ""} AccelByte Inc. All Rights Reserved
|
|
386
|
+
* This is licensed software from AccelByte Inc, for limitations
|
|
387
|
+
* and restrictions contact your company contract manager.
|
|
388
|
+
*/
|
|
389
|
+
${content}`;
|
|
390
|
+
};
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const templateJsdocMethod = (classMethod, httpMethod, path, pathParams, bodyParams, queryParams) => {
|
|
394
|
+
let jsdoc = "";
|
|
395
|
+
let methodSignature = "";
|
|
396
|
+
let newPath = path;
|
|
397
|
+
for (const p of pathParams) {
|
|
398
|
+
methodSignature += p.name + ", ";
|
|
399
|
+
newPath = newPath.replace("{" + p.name + "}", `' + ${p.name} + '`);
|
|
400
|
+
jsdoc += `
|
|
401
|
+
* @pathParam '${p.name}${p.required ? "" : "?"}' - ${p.description}`;
|
|
402
|
+
}
|
|
403
|
+
let payloads = "";
|
|
404
|
+
for (const p of bodyParams) {
|
|
405
|
+
methodSignature += p.name + ", ";
|
|
406
|
+
payloads += p.name;
|
|
407
|
+
jsdoc += `
|
|
408
|
+
* @payload '${p.name}${p.required ? "" : "?"}' - ${p.description} ${p?.schema?.properties ? "=> " + JSON.stringify(p.schema.properties) : ""}`;
|
|
409
|
+
}
|
|
410
|
+
for (const p of queryParams) {
|
|
411
|
+
const optionalMark = p.required ? "" : "?";
|
|
412
|
+
methodSignature += p.name + optionalMark + ", ";
|
|
413
|
+
jsdoc += `
|
|
414
|
+
* @queryParam '${p.name}${p.required ? "" : "?"}' - ${p.description}`;
|
|
415
|
+
}
|
|
416
|
+
let queryString = "";
|
|
417
|
+
for (const p of queryParams) {
|
|
418
|
+
queryString += `${p.name}=__&`;
|
|
419
|
+
}
|
|
420
|
+
queryString = queryString.length > 0 ? "?" + queryString : "";
|
|
421
|
+
return `
|
|
422
|
+
/**
|
|
423
|
+
* ${httpMethod.toUpperCase()} '${newPath}${queryString}' ${payloads ? "payload: '" + payloads + "'" : ""}
|
|
424
|
+
* ${jsdoc}
|
|
425
|
+
*/
|
|
426
|
+
${classMethod}(${methodSignature}): Promise
|
|
427
|
+
`;
|
|
428
|
+
};
|
|
429
|
+
|
|
430
|
+
const templateMethod = (classMethod, description, httpMethod, path, pathParams, bodyParams, queryParams, isFormUrlEncoded, responseClass) => {
|
|
431
|
+
let methodSignature = "";
|
|
432
|
+
let newPath = `'${path}'`;
|
|
433
|
+
let dependencies = [];
|
|
434
|
+
for (const p of pathParams) {
|
|
435
|
+
const type = ParserUtils.parseType(p.type);
|
|
436
|
+
if (p.name !== "namespace") {
|
|
437
|
+
methodSignature += p.name + `:${type}, `;
|
|
438
|
+
}
|
|
439
|
+
const pName = p.name === "namespace" ? "this.namespace" : p.name;
|
|
440
|
+
if (path.match(`{${p.name}}`)) {
|
|
441
|
+
if (type === "string") {
|
|
442
|
+
newPath = `${newPath}.replace('{${p.name}}', ${pName})`;
|
|
443
|
+
} else {
|
|
444
|
+
newPath = `${newPath}.replace('{${p.name}}', String(${pName}))`;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
let dataType = null;
|
|
449
|
+
if (httpMethod !== "get") {
|
|
450
|
+
dataType = ParserUtils.parseBodyParamsType(bodyParams);
|
|
451
|
+
dependencies = ParserUtils.parseBodyParamsImports(bodyParams);
|
|
452
|
+
methodSignature += dataType ? `data: ${dataType},` : "";
|
|
453
|
+
}
|
|
454
|
+
ParserUtils.isAnyQueryParamRequired(queryParams);
|
|
455
|
+
const queryParamsType = queryParams.length ? `queryParams${"?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
|
|
456
|
+
const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as SDKRequestConfig` : "const params = {} as SDKRequestConfig";
|
|
457
|
+
const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
|
|
458
|
+
const isDelete = ["delete"].includes(httpMethod);
|
|
459
|
+
let dataPayload = "{params}";
|
|
460
|
+
const descriptionText = description ? `
|
|
461
|
+
/**
|
|
462
|
+
* ${(description || "").replace(/\n/g, "\n * ")}
|
|
463
|
+
*/` : "";
|
|
464
|
+
let formPayloadString = "";
|
|
465
|
+
if (isFormUrlEncoded) {
|
|
466
|
+
formPayloadString = ``;
|
|
467
|
+
const params = "{ ...params, headers: { ...params.headers, 'content-type': 'application/x-www-form-urlencoded' } }";
|
|
468
|
+
dataPayload = dataType ? `CodeGenUtil.getFormUrlEncodedData(data), ${params}` : `null, ${params}`;
|
|
469
|
+
} else if (isPostPutPatch) {
|
|
470
|
+
dataPayload = dataType ? `data, {params}` : "null, {params}";
|
|
471
|
+
} else if (isDelete) {
|
|
472
|
+
dataPayload = dataType ? `{data, params}` : "{params}";
|
|
473
|
+
}
|
|
474
|
+
const isFileUpload = methodSignature.indexOf("data: {file") > -1;
|
|
475
|
+
const resolvedResponseClass = responseClass || "unknown";
|
|
476
|
+
const resolvedResponseClassValidated = responseClass || "z.unknown()";
|
|
477
|
+
const parameters = (queryParamsType ? `${methodSignature} ${queryParamsType}` : methodSignature).replace(/,\s*$/, "");
|
|
478
|
+
let methodImpl = "";
|
|
479
|
+
const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
|
|
480
|
+
const isCacheFetchUnknown = ["get"].includes(httpMethod) && resolvedResponseClass === "unknown";
|
|
481
|
+
const cachedFetchMethod = classMethod.replace("get", "fetch");
|
|
482
|
+
const deprecateTag = isCacheFetch ? `/**
|
|
483
|
+
* @deprecated Use "${cachedFetchMethod}()" instead.
|
|
484
|
+
*/` : "";
|
|
485
|
+
let isGuardInvoked = false;
|
|
486
|
+
if (isCacheFetch) {
|
|
487
|
+
methodImpl = `${descriptionText}
|
|
488
|
+
${cachedFetchMethod}<T = ${resolvedResponseClass}>(${parameters}): Promise<IResponseWithSync<T>> {
|
|
489
|
+
${queryParamsDefault}
|
|
490
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
491
|
+
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
492
|
+
|
|
493
|
+
const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
|
|
494
|
+
|
|
495
|
+
if (!this.cache) {
|
|
496
|
+
return SdkCache.withoutCache(res)
|
|
497
|
+
}
|
|
498
|
+
const key = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
|
|
499
|
+
return SdkCache.withCache(key, res)
|
|
500
|
+
}
|
|
501
|
+
`;
|
|
502
|
+
isGuardInvoked = true;
|
|
503
|
+
}
|
|
504
|
+
if (isCacheFetchUnknown) {
|
|
505
|
+
methodImpl = `${descriptionText}
|
|
506
|
+
${cachedFetchMethod}(${parameters}): Promise<IResponseWithSync<unknown>> {
|
|
507
|
+
${queryParamsDefault}
|
|
508
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
509
|
+
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
510
|
+
|
|
511
|
+
const res = () => Validate.responseType(() => resultPromise, z.unknown())
|
|
512
|
+
|
|
513
|
+
if (!this.cache) {
|
|
514
|
+
return SdkCache.withoutCache(res)
|
|
515
|
+
}
|
|
516
|
+
const key = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
|
|
517
|
+
return SdkCache.withCache(key, res)
|
|
518
|
+
}
|
|
519
|
+
`;
|
|
520
|
+
isGuardInvoked = true;
|
|
521
|
+
}
|
|
522
|
+
const withTypeGuard = ["post", "put", "patch", "delete"].includes(httpMethod) && resolvedResponseClass !== "unknown";
|
|
523
|
+
if (withTypeGuard) {
|
|
524
|
+
methodImpl = `${descriptionText}
|
|
525
|
+
${classMethod}<T = ${resolvedResponseClass}>(${parameters}): Promise<IResponse<T>> {
|
|
526
|
+
${queryParamsDefault}
|
|
527
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
528
|
+
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
529
|
+
|
|
530
|
+
return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
|
|
531
|
+
}
|
|
532
|
+
`;
|
|
533
|
+
isGuardInvoked = true;
|
|
534
|
+
}
|
|
535
|
+
const withTypeGuardUnknown = ["post", "put", "patch", "delete"].includes(httpMethod) && resolvedResponseClass === "unknown";
|
|
536
|
+
if (withTypeGuardUnknown) {
|
|
537
|
+
methodImpl = `${descriptionText}
|
|
538
|
+
${classMethod}(${parameters}): Promise<IResponse<unknown>> {
|
|
539
|
+
${queryParamsDefault}
|
|
540
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
541
|
+
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
542
|
+
|
|
543
|
+
return Validate.responseType(() => resultPromise, z.unknown())
|
|
544
|
+
}
|
|
545
|
+
`;
|
|
546
|
+
isGuardInvoked = true;
|
|
547
|
+
}
|
|
548
|
+
if (!isGuardInvoked) {
|
|
549
|
+
methodImpl = `${descriptionText}
|
|
550
|
+
${deprecateTag}
|
|
551
|
+
TODO_${classMethod}<T = ${resolvedResponseClass}>(${parameters}): Promise<AxiosResponse<T>> {
|
|
552
|
+
${queryParamsDefault}
|
|
553
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
554
|
+
return this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
555
|
+
}
|
|
556
|
+
`;
|
|
557
|
+
}
|
|
558
|
+
return [methodImpl, dependencies];
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
class TemplateZod {
|
|
562
|
+
duplicates;
|
|
563
|
+
duplicateFound = false;
|
|
564
|
+
importClasses = /* @__PURE__ */ new Set();
|
|
565
|
+
render = (name, definition, duplicates) => {
|
|
566
|
+
this.duplicates = duplicates;
|
|
567
|
+
const content = this.parseToZodSchema(definition, definition.required || []);
|
|
568
|
+
const containsRecursiveType = this.importClasses.has(name);
|
|
569
|
+
if (containsRecursiveType) {
|
|
570
|
+
this.importClasses.delete(name);
|
|
571
|
+
}
|
|
572
|
+
let imports = "";
|
|
573
|
+
for (const cl of Array.from(this.importClasses).sort()) {
|
|
574
|
+
imports += ` import { ${cl} } from './${cl}'
|
|
575
|
+
`;
|
|
576
|
+
}
|
|
577
|
+
let exportedVariableString;
|
|
578
|
+
let exportedTypeString;
|
|
579
|
+
if (containsRecursiveType) {
|
|
580
|
+
exportedVariableString = `
|
|
581
|
+
export const ${name}: z.ZodType<${name}> = z.lazy(() =>
|
|
582
|
+
${content.schemaString}
|
|
583
|
+
)
|
|
584
|
+
`;
|
|
585
|
+
exportedTypeString = `
|
|
586
|
+
export type ${name} = {
|
|
587
|
+
${content.typeString}
|
|
588
|
+
}
|
|
589
|
+
`;
|
|
590
|
+
} else {
|
|
591
|
+
exportedVariableString = `export const ${name} = ${content.schemaString}`;
|
|
592
|
+
exportedTypeString = `export type ${name} = z.TypeOf<typeof ${name}>`;
|
|
593
|
+
}
|
|
594
|
+
const template = `import { z } from 'zod'
|
|
595
|
+
${imports}
|
|
596
|
+
|
|
597
|
+
${exportedVariableString}
|
|
598
|
+
|
|
599
|
+
${exportedTypeString}
|
|
600
|
+
`;
|
|
601
|
+
return { buffer: template, duplicateFound: this.duplicateFound };
|
|
602
|
+
};
|
|
603
|
+
parseToZodSchema = (definition, requiredAttrs) => {
|
|
604
|
+
if (definition.additionalProperties) {
|
|
605
|
+
return this.parseToZodAttribute("", definition, []);
|
|
606
|
+
}
|
|
607
|
+
if (!definition.properties) {
|
|
608
|
+
return {
|
|
609
|
+
schemaString: "z.any()",
|
|
610
|
+
typeString: "any"
|
|
611
|
+
};
|
|
612
|
+
}
|
|
613
|
+
const properties = Object.entries(definition.properties);
|
|
614
|
+
const schemaFields = [];
|
|
615
|
+
const typeFields = [];
|
|
616
|
+
for (const property of properties) {
|
|
617
|
+
const [name, definition2] = property;
|
|
618
|
+
const result = this.parseToZodAttribute(name, definition2, requiredAttrs);
|
|
619
|
+
schemaFields.push(result.schemaString);
|
|
620
|
+
typeFields.push(result.typeString);
|
|
621
|
+
}
|
|
622
|
+
return {
|
|
623
|
+
schemaString: `z.object({${schemaFields.join(",")}})`,
|
|
624
|
+
typeString: typeFields.join(";")
|
|
625
|
+
};
|
|
626
|
+
};
|
|
627
|
+
parseToZodAttribute = (name, definition, requiredAttrs) => {
|
|
628
|
+
const isRequired = requiredAttrs.includes(name) || name === "";
|
|
629
|
+
const schemaRequired = isRequired ? "" : ".nullish()";
|
|
630
|
+
const typeRequired = isRequired ? "" : "?";
|
|
631
|
+
const typeNullishability = isRequired ? "" : " | null | undefined";
|
|
632
|
+
const schemaAttribute = name ? `'${name}':` : "";
|
|
633
|
+
const typeAttribute = name ? `'${name}'${typeRequired}:` : "";
|
|
634
|
+
const type = definition?.type;
|
|
635
|
+
if (type) {
|
|
636
|
+
if (type === "object" && definition.additionalProperties) {
|
|
637
|
+
const zodAttribute = this.parseToZodAttribute("", definition.additionalProperties, [""]);
|
|
638
|
+
return {
|
|
639
|
+
schemaString: `${schemaAttribute} z.record(${zodAttribute.schemaString})${schemaRequired}`,
|
|
640
|
+
typeString: `${typeAttribute} Record<string, ${zodAttribute.typeString}>${typeNullishability}`
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
if (type === "object" && !definition.additionalProperties && !name) {
|
|
644
|
+
return {
|
|
645
|
+
schemaString: `z.any()`,
|
|
646
|
+
typeString: "any"
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
if (type === "object" && !definition.additionalProperties) {
|
|
650
|
+
return {
|
|
651
|
+
schemaString: `${schemaAttribute} z.record(z.any())${schemaRequired}`,
|
|
652
|
+
typeString: `${typeAttribute} Record<string, any>${typeNullishability}`
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
if (type === "integer" || type === "number") {
|
|
656
|
+
const effectiveType = getZodNumberType(type);
|
|
657
|
+
return {
|
|
658
|
+
schemaString: `${schemaAttribute} z.${effectiveType.schemaString}()${schemaRequired}`,
|
|
659
|
+
typeString: `${typeAttribute} ${effectiveType.typeString}${typeNullishability}`
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
if (type === "array") {
|
|
663
|
+
const ref2 = definition.items?.$ref;
|
|
664
|
+
let model2;
|
|
665
|
+
if (ref2) {
|
|
666
|
+
const refType = ParserUtils.parseRefType(ref2);
|
|
667
|
+
this.importClasses.add(refType);
|
|
668
|
+
model2 = {
|
|
669
|
+
schemaString: refType,
|
|
670
|
+
typeString: refType
|
|
671
|
+
};
|
|
672
|
+
} else {
|
|
673
|
+
const items = definition.items;
|
|
674
|
+
model2 = this.parseEnumItems(items);
|
|
675
|
+
}
|
|
676
|
+
return {
|
|
677
|
+
schemaString: `${schemaAttribute} z.array(${model2.schemaString})${schemaRequired}`,
|
|
678
|
+
typeString: `${typeAttribute} ${model2.typeString}[]${typeNullishability}`
|
|
679
|
+
};
|
|
680
|
+
}
|
|
681
|
+
if (type !== "object") {
|
|
682
|
+
const result = extractEnumObject(type, isRequired, definition.enum);
|
|
683
|
+
return {
|
|
684
|
+
schemaString: `${schemaAttribute} ${result.schemaString}`,
|
|
685
|
+
typeString: `${typeAttribute} ${result.typeString}`
|
|
686
|
+
};
|
|
687
|
+
}
|
|
688
|
+
} else if (definition.properties) {
|
|
689
|
+
const result = this.parseToZodSchema(definition, requiredAttrs);
|
|
690
|
+
return {
|
|
691
|
+
schemaString: `${schemaAttribute} ${result.schemaString}${schemaRequired}`,
|
|
692
|
+
typeString: `${typeAttribute} ${result.typeString}${typeNullishability}`
|
|
693
|
+
};
|
|
694
|
+
}
|
|
695
|
+
const ref = definition.$ref;
|
|
696
|
+
let model = `z.record(z.any())`;
|
|
697
|
+
if (ref) {
|
|
698
|
+
model = ParserUtils.parseRefType(ref);
|
|
699
|
+
const fullModelName = ref.replace("#/definitions/", "");
|
|
700
|
+
this.duplicateFound = this.duplicates.has(fullModelName);
|
|
701
|
+
if (this.duplicateFound) {
|
|
702
|
+
model = this.duplicates.get(fullModelName);
|
|
703
|
+
}
|
|
704
|
+
this.importClasses.add(model);
|
|
705
|
+
model = `${model}`;
|
|
706
|
+
}
|
|
707
|
+
return {
|
|
708
|
+
schemaString: `${schemaAttribute} ${model}${schemaRequired}`,
|
|
709
|
+
typeString: `${typeAttribute} ${model}${typeNullishability}`
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
parseEnumItems = (items) => {
|
|
713
|
+
if (items.enum) {
|
|
714
|
+
const enumStr = items.enum.map((e) => {
|
|
715
|
+
return `"${e}"`;
|
|
716
|
+
});
|
|
717
|
+
return {
|
|
718
|
+
schemaString: `z.enum([${enumStr}])`,
|
|
719
|
+
typeString: `(${enumStr.join(" | ")})`
|
|
720
|
+
};
|
|
721
|
+
}
|
|
722
|
+
if (items.type === "object") {
|
|
723
|
+
return this.parseToZodSchema(items, items.required);
|
|
724
|
+
}
|
|
725
|
+
let effectiveType;
|
|
726
|
+
if (items.type === "integer" || items.type === "number") {
|
|
727
|
+
effectiveType = getZodNumberType(items.type);
|
|
728
|
+
} else {
|
|
729
|
+
effectiveType = { typeString: items.type, schemaString: items.type };
|
|
730
|
+
}
|
|
731
|
+
return {
|
|
732
|
+
schemaString: `z.${effectiveType.schemaString}()`,
|
|
733
|
+
typeString: effectiveType.typeString
|
|
734
|
+
};
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
class TemplateZodArray {
|
|
738
|
+
render = (name) => {
|
|
739
|
+
const cls = name.replace("Array", "");
|
|
740
|
+
const template = `import { z } from 'zod'
|
|
741
|
+
import { ${cls} } from './${cls}'
|
|
742
|
+
|
|
743
|
+
export const ${name} = z.array(${cls})
|
|
744
|
+
|
|
745
|
+
export type ${name} = z.TypeOf<typeof ${name}>
|
|
746
|
+
`;
|
|
747
|
+
return template;
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
const getZodNumberType = (type) => {
|
|
751
|
+
if (type === "integer") {
|
|
752
|
+
return {
|
|
753
|
+
schemaString: "number().int",
|
|
754
|
+
typeString: "number"
|
|
755
|
+
};
|
|
756
|
+
}
|
|
757
|
+
return {
|
|
758
|
+
schemaString: type,
|
|
759
|
+
typeString: type
|
|
760
|
+
};
|
|
761
|
+
};
|
|
762
|
+
const extractEnumObject = (type, isRequired, enumArr) => {
|
|
763
|
+
const schemaRequired = isRequired ? "" : ".nullish()";
|
|
764
|
+
const typeNullishability = isRequired ? "" : " | null | undefined";
|
|
765
|
+
if (enumArr) {
|
|
766
|
+
const enumStr = enumArr.map((e) => {
|
|
767
|
+
return `"${e}"`;
|
|
768
|
+
});
|
|
769
|
+
return {
|
|
770
|
+
schemaString: `z.enum([${enumStr}])${schemaRequired}`,
|
|
771
|
+
typeString: `(${enumStr.join(" | ")}${typeNullishability})`
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
return {
|
|
775
|
+
schemaString: `z.${type}()${schemaRequired}`,
|
|
776
|
+
typeString: `${type}${typeNullishability}`
|
|
777
|
+
};
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
class CodeGenerator {
|
|
781
|
+
static getPatchedDir = () => path__default["default"].join(CliParser.getSwaggersOutputPath(), "patched");
|
|
782
|
+
static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
|
|
783
|
+
static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
|
|
784
|
+
static iterateApi = (api) => {
|
|
785
|
+
const apiBufferByTag = {};
|
|
786
|
+
const jsDocApiBufferByTag = {};
|
|
787
|
+
const dependenciesByTag = {};
|
|
788
|
+
const classImports = {};
|
|
789
|
+
let arrayDefinitions = [];
|
|
790
|
+
for (const path2 in api.paths) {
|
|
791
|
+
const isAdminEndpoint = path2.indexOf("/admin/") > -1;
|
|
792
|
+
if (CliParser.isAdmin() && !isAdminEndpoint) {
|
|
793
|
+
continue;
|
|
794
|
+
} else if (!CliParser.isAdmin() && isAdminEndpoint) {
|
|
795
|
+
continue;
|
|
796
|
+
}
|
|
797
|
+
const entity = api.paths[path2];
|
|
798
|
+
const methods = ParserUtils.mapKeys(entity);
|
|
799
|
+
for (const httpMethod of methods) {
|
|
800
|
+
const e = entity[httpMethod];
|
|
801
|
+
const [tag] = e.tags;
|
|
802
|
+
const description = e.description;
|
|
803
|
+
const isDeprecated = e.deprecated;
|
|
804
|
+
const responseClass = ParserUtils.get2xxResponse(e.responses, path2);
|
|
805
|
+
const className = ___default["default"].upperFirst(___default["default"].camelCase(tag));
|
|
806
|
+
classImports[className] = classImports[className] ? classImports[className] : {};
|
|
807
|
+
if (!isDeprecated) {
|
|
808
|
+
if (responseClass) {
|
|
809
|
+
const importTypeClass = ParserUtils.parseRefType(responseClass);
|
|
810
|
+
classImports[className][importTypeClass] = `import { ${importTypeClass} } from './definitions/${importTypeClass}'`;
|
|
811
|
+
}
|
|
812
|
+
if (responseClass && responseClass.endsWith("Array")) {
|
|
813
|
+
arrayDefinitions.push(responseClass);
|
|
814
|
+
}
|
|
815
|
+
const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, e.consumes);
|
|
816
|
+
const queryParams = ParserUtils.getQueryParameters(e.parameters);
|
|
817
|
+
const pathParams = ParserUtils.getPathParams(e.parameters);
|
|
818
|
+
const bodyParams = ParserUtils.getBodyParams(e.parameters);
|
|
819
|
+
const classMethod = ParserUtils.generateClassMethod(path2, e.parameters, httpMethod, className);
|
|
820
|
+
const baseAndPath = `${api.basePath ?? ""}${path2}`;
|
|
821
|
+
const [generatedMethodString, importStatements] = templateMethod(classMethod, description, httpMethod, baseAndPath, pathParams, bodyParams, queryParams, isFormUrlEncoded, responseClass);
|
|
822
|
+
apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
|
|
823
|
+
jsDocApiBufferByTag[tag] = (jsDocApiBufferByTag[tag] || "") + templateJsdocMethod(classMethod, httpMethod, path2, pathParams, bodyParams, queryParams);
|
|
824
|
+
dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
arrayDefinitions = [...new Set(arrayDefinitions)];
|
|
829
|
+
return { apiBufferByTag, jsDocApiBufferByTag, dependenciesByTag, classImports, arrayDefinitions };
|
|
830
|
+
};
|
|
831
|
+
static main = async (nameArray) => {
|
|
832
|
+
const serviceName = nameArray[0];
|
|
833
|
+
const swaggerFile = nameArray[2];
|
|
834
|
+
const parser = new SwaggerParser__default["default"]();
|
|
835
|
+
const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
|
|
836
|
+
const DIST_DIR = `${generatedFolder}/${serviceName}`;
|
|
837
|
+
const DIST_DOCS_DIR = path__default["default"].join(DIST_DIR, "docs");
|
|
838
|
+
const DIST_DEFINITION_DIR = path__default["default"].join(DIST_DIR, "definitions");
|
|
839
|
+
const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
|
|
840
|
+
const swaggerPatchedFilePath = `${CodeGenerator.getPatchedDir()}/${swaggerFile}`;
|
|
841
|
+
const swaggerPatchFilePath = `${swaggerFilePath}patch`;
|
|
842
|
+
ParserUtils.applyPatchIfExists(swaggerFilePath, swaggerPatchFilePath, swaggerPatchedFilePath, CodeGenerator.getPatchedDir());
|
|
843
|
+
const api = await parser.parse(swaggerPatchedFilePath);
|
|
844
|
+
const indexImportsSet = /* @__PURE__ */ new Set();
|
|
845
|
+
console.log("\n----------\n API name: %s, Version: %s schemes %s", api, api.info.title, api.info.version, api.schemes);
|
|
846
|
+
ParserUtils.mkdirIfNotExist(DIST_DIR);
|
|
847
|
+
ParserUtils.mkdirIfNotExist(DIST_DOCS_DIR);
|
|
848
|
+
ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
|
|
849
|
+
const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions } = CodeGenerator.iterateApi(api);
|
|
850
|
+
const targetSrcFolder = `${CliParser.getOutputPath()}/`;
|
|
851
|
+
for (const tag in apiBufferByTag) {
|
|
852
|
+
const className = ___default["default"].upperFirst(___default["default"].camelCase(tag));
|
|
853
|
+
const apiBuffer = apiBufferByTag[tag];
|
|
854
|
+
const imports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
|
|
855
|
+
const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
|
|
856
|
+
ParserUtils.writeClassFile(DIST_DIR, classGenName, apiBuffer, imports);
|
|
857
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default["default"].join(DIST_DIR, `${classGenName}`), targetSrcFolder));
|
|
858
|
+
}
|
|
859
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
860
|
+
for (const ref in api.definitions) {
|
|
861
|
+
const definition = api.definitions[ref];
|
|
862
|
+
let fileName = ParserUtils.parseRefType(ref);
|
|
863
|
+
const fileExist = fs__default["default"].existsSync(path__default["default"].join(DIST_DEFINITION_DIR, `${fileName}.ts`));
|
|
864
|
+
if (fileExist) {
|
|
865
|
+
fileName = ParserUtils.toCamelCaseWord(ref).replace(".", "").replace(".", "");
|
|
866
|
+
duplicates.set(ref, fileName);
|
|
867
|
+
}
|
|
868
|
+
const { buffer } = new TemplateZod().render(fileName, definition, /* @__PURE__ */ new Map());
|
|
869
|
+
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, fileName, buffer);
|
|
870
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default["default"].join(DIST_DEFINITION_DIR, fileName), targetSrcFolder));
|
|
871
|
+
}
|
|
872
|
+
for (const ref in api.definitions) {
|
|
873
|
+
const definition = api.definitions[ref];
|
|
874
|
+
const fileName = ParserUtils.parseRefType(ref);
|
|
875
|
+
const { buffer, duplicateFound } = new TemplateZod().render(fileName, definition, duplicates);
|
|
876
|
+
if (duplicateFound) {
|
|
877
|
+
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, fileName, buffer);
|
|
878
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default["default"].join(DIST_DEFINITION_DIR, fileName), targetSrcFolder));
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
for (const arrayClass of arrayDefinitions) {
|
|
882
|
+
const buffer = new TemplateZodArray().render(arrayClass);
|
|
883
|
+
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, arrayClass, buffer);
|
|
884
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default["default"].join(DIST_DEFINITION_DIR, arrayClass), targetSrcFolder));
|
|
885
|
+
}
|
|
886
|
+
console.log("\n----------\nCOMPLETED.\n----------\n\n");
|
|
887
|
+
return indexImportsSet;
|
|
888
|
+
};
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
class SwaggerDownloader {
|
|
892
|
+
static getDestFile = (targetFileName) => {
|
|
893
|
+
const destPath = CliParser.getResolvedSwaggersOutputPath();
|
|
894
|
+
const destFile = path__namespace.join(destPath, targetFileName);
|
|
895
|
+
if (fs__namespace.existsSync(destFile))
|
|
896
|
+
return destFile;
|
|
897
|
+
if (!fs__namespace.existsSync(destPath))
|
|
898
|
+
fs__namespace.mkdirSync(destPath);
|
|
899
|
+
fs__namespace.writeFileSync(destFile, "");
|
|
900
|
+
return destFile;
|
|
901
|
+
};
|
|
902
|
+
static downloadFile = (targetFileName, url) => {
|
|
903
|
+
const destFile = SwaggerDownloader.getDestFile(targetFileName);
|
|
904
|
+
const file = fs__namespace.createWriteStream(destFile);
|
|
905
|
+
const request = https__namespace.get(url, function(response) {
|
|
906
|
+
response.pipe(file);
|
|
907
|
+
file.on("finish", () => {
|
|
908
|
+
file.close();
|
|
909
|
+
console.log(`SwaggerDownload ${url} completed`);
|
|
910
|
+
});
|
|
911
|
+
});
|
|
912
|
+
request.on("error", (err) => {
|
|
913
|
+
console.log(`SwaggerDownloader dl failed for "${targetFileName}" and "${url}"`, err);
|
|
914
|
+
});
|
|
915
|
+
};
|
|
916
|
+
static main = () => {
|
|
917
|
+
const swaggers = CliParser.getConfigFile();
|
|
918
|
+
for (const ref in swaggers) {
|
|
919
|
+
const targetFileName = swaggers[ref][2];
|
|
920
|
+
const url = swaggers[ref][3];
|
|
921
|
+
SwaggerDownloader.downloadFile(targetFileName, url);
|
|
922
|
+
}
|
|
923
|
+
console.log("\n----------\n SwaggerDownloader COMPLETED.\n----------\n\n");
|
|
924
|
+
};
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
yargs__default["default"].command("download-swaggers", "Download swaggers JSON files", (yargs2) => {
|
|
928
|
+
CliParser.createInstance(yargs2);
|
|
929
|
+
SwaggerDownloader.main();
|
|
930
|
+
}).command("generate-code", "Generate code based on downloaded swagger files", async (yargs2) => {
|
|
931
|
+
yargs2.check(({ output, swaggersOutput }) => {
|
|
932
|
+
if (!output?.trim()) {
|
|
933
|
+
throw new Error("output is required for generate-code");
|
|
934
|
+
}
|
|
935
|
+
return true;
|
|
936
|
+
});
|
|
937
|
+
CliParser.createInstance(yargs2);
|
|
938
|
+
const arrayOfSets = await Promise.all(CliParser.getConfigFile().map((config) => CodeGenerator.main(config)));
|
|
939
|
+
const indexImportsSet = /* @__PURE__ */ new Set();
|
|
940
|
+
const filenamesSet = /* @__PURE__ */ new Set();
|
|
941
|
+
for (const set of arrayOfSets) {
|
|
942
|
+
set.forEach((value) => {
|
|
943
|
+
const fileName = path__default["default"].basename(value);
|
|
944
|
+
if (!filenamesSet.has(fileName)) {
|
|
945
|
+
indexImportsSet.add(value);
|
|
946
|
+
filenamesSet.add(fileName);
|
|
947
|
+
}
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
const indexImportsArray = Array.from(indexImportsSet);
|
|
951
|
+
const filesToImport = indexImportsArray.map((fileToImport) => {
|
|
952
|
+
return `export * from '${fileToImport.replace("\\", "/")}'`;
|
|
953
|
+
});
|
|
954
|
+
ParserUtils.writeAllImportsFile(CliParser.getOutputPath(), filesToImport.join("\n"), CliParser.isAdmin());
|
|
955
|
+
}).option("config", {
|
|
956
|
+
description: "Config file providing backend services URL.",
|
|
957
|
+
type: "string",
|
|
958
|
+
demandOption: true
|
|
959
|
+
}).option("swaggersOutput", {
|
|
960
|
+
description: "Output path for downloaded swaggers JSON files.",
|
|
961
|
+
type: "string",
|
|
962
|
+
demandOption: true
|
|
963
|
+
}).option("output", {
|
|
964
|
+
description: "Output path for generated code. Required for generate-code",
|
|
965
|
+
type: "string"
|
|
966
|
+
}).option("admin", {
|
|
967
|
+
description: "Only generate /admin endpoints.",
|
|
968
|
+
type: "boolean",
|
|
969
|
+
default: false,
|
|
970
|
+
demandOption: false
|
|
971
|
+
}).demandCommand(1).help().argv;
|
|
972
|
+
//# sourceMappingURL=accelbyte-codegen.js.map
|