@accelbyte/codegen 1.0.0-beta.7 → 1.0.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/dist/accelbyte-codegen.js +344 -89
- package/dist/accelbyte-codegen.js.map +1 -1
- package/dist/accelbyte-codegen.mjs +345 -90
- package/dist/accelbyte-codegen.mjs.map +1 -1
- package/package.json +3 -21
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
|
-
import fs__default from 'fs';
|
|
4
|
+
import fs__default, { readFileSync, writeFileSync } from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import path__default from 'path';
|
|
7
7
|
import SwaggerParser from '@apidevtools/swagger-parser';
|
|
@@ -56,18 +56,18 @@ class CliParser {
|
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
const getImportableVarMap = () => ({
|
|
59
|
+
const getImportableVarMap$1 = () => ({
|
|
60
60
|
"@accelbyte/sdk": ["CodeGenUtil", "SdkCache", "IResponse", "IResponseWithSync", "Validate"],
|
|
61
61
|
axios: ["AxiosRequestConfig", "AxiosResponse"],
|
|
62
62
|
zod: ["z"]
|
|
63
63
|
});
|
|
64
|
-
const makeNewImportVarMap = () => ({
|
|
64
|
+
const makeNewImportVarMap$1 = () => ({
|
|
65
65
|
axios: ["AxiosInstance"],
|
|
66
66
|
"@accelbyte/sdk": ["SDKRequestConfig"]
|
|
67
67
|
});
|
|
68
|
-
const generateImports = (body, importStatements) => {
|
|
69
|
-
const usedImportVarMap =
|
|
70
|
-
const importableVarMap =
|
|
68
|
+
const generateImports = (body, importStatements, makeNewImportVarMap2, getImportableVarMap2) => {
|
|
69
|
+
const usedImportVarMap = makeNewImportVarMap2;
|
|
70
|
+
const importableVarMap = getImportableVarMap2;
|
|
71
71
|
for (const [moduleSource, importableVars] of Object.entries(importableVarMap)) {
|
|
72
72
|
for (const importableVar of importableVars) {
|
|
73
73
|
const importVarRegex = new RegExp(`(?<![\\d\\w_])${importableVar}(?![\\d\\w_])`);
|
|
@@ -80,10 +80,11 @@ const generateImports = (body, importStatements) => {
|
|
|
80
80
|
return `${generatedImports}
|
|
81
81
|
${importStatements.sort().join("\n")}`;
|
|
82
82
|
};
|
|
83
|
-
const templateClass = (className, body, importStatements) =>
|
|
84
|
-
|
|
83
|
+
const templateClass = (className, body, importStatements) => {
|
|
84
|
+
return `/**
|
|
85
|
+
* AUTO GENERATED
|
|
85
86
|
*/
|
|
86
|
-
${generateImports(body, importStatements)}
|
|
87
|
+
${generateImports(body, importStatements, makeNewImportVarMap$1(), getImportableVarMap$1())}
|
|
87
88
|
|
|
88
89
|
export class ${className} {
|
|
89
90
|
// @ts-ignore
|
|
@@ -91,15 +92,37 @@ export class ${className} {
|
|
|
91
92
|
${body}
|
|
92
93
|
}
|
|
93
94
|
`;
|
|
95
|
+
};
|
|
94
96
|
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
97
|
+
const getImportableVarMap = () => ({
|
|
98
|
+
"@accelbyte/sdk": ["CodeGenUtil", "SdkCache", "IResponse", "IResponseWithSync", "Validate", "ApiArgs", "Network", "AccelbyteSDK"]
|
|
99
|
+
});
|
|
100
|
+
const makeNewImportVarMap = () => ({
|
|
101
|
+
"@accelbyte/sdk": ["AccelbyteSDK", "ApiArgs", "ApiUtils"]
|
|
102
|
+
});
|
|
103
|
+
const templateApiClass = (className, body, importStatements, returnMethods) => {
|
|
104
|
+
return `/**
|
|
105
|
+
* AUTO GENERATED
|
|
106
|
+
*/
|
|
107
|
+
/* eslint-disable camelcase */
|
|
108
|
+
${generateImports(body, importStatements, makeNewImportVarMap(), getImportableVarMap())}
|
|
99
109
|
|
|
100
|
-
|
|
101
|
-
|
|
110
|
+
export function ${className}(sdk: AccelbyteSDK, args?: ApiArgs) {
|
|
111
|
+
const sdkAssembly = sdk.assembly()
|
|
112
|
+
|
|
113
|
+
const namespace = args?.namespace ? args?.namespace : sdkAssembly.namespace
|
|
114
|
+
const cache = args?.cache ? args?.cache : sdkAssembly.cache
|
|
115
|
+
const requestConfig = ApiUtils.mergedConfigs(sdkAssembly.config, args)
|
|
116
|
+
${body}
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
${returnMethods}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
};
|
|
102
124
|
|
|
125
|
+
const UNDEFINED_SWAGGER_SEMVER = "0.0.0";
|
|
103
126
|
const REMOVED_KEYWORDS = [
|
|
104
127
|
"/admin/",
|
|
105
128
|
"/public/",
|
|
@@ -113,39 +136,62 @@ const REMOVED_KEYWORDS = [
|
|
|
113
136
|
"/{namespace}/"
|
|
114
137
|
];
|
|
115
138
|
class ParserUtils {
|
|
139
|
+
static replaceAll = (string, search, replace) => {
|
|
140
|
+
return string.split(search).join(replace);
|
|
141
|
+
};
|
|
116
142
|
static generateClassName = (tag) => {
|
|
117
143
|
const className = _.upperFirst(_.camelCase(tag));
|
|
118
144
|
const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
|
|
119
145
|
return { className, classGenName };
|
|
120
146
|
};
|
|
147
|
+
static generateApiName = (tag) => {
|
|
148
|
+
const apiName = _.upperFirst(_.camelCase(tag));
|
|
149
|
+
const apiGenName = CliParser.isAdmin() ? apiName + "AdminApi" : apiName + "Api";
|
|
150
|
+
return { apiName, apiGenName };
|
|
151
|
+
};
|
|
121
152
|
static parseQueryParamAttributeDefault = (definition) => {
|
|
122
153
|
const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
|
|
123
154
|
const defaultValue = definition.type === "string" ? `'${definition.default}'` : definition.default;
|
|
124
155
|
return `${attrName}: ${defaultValue}`;
|
|
125
156
|
};
|
|
126
157
|
static parseType = (pathParam) => {
|
|
127
|
-
if (pathParam.type
|
|
158
|
+
if (isSwaggerIntegerType(pathParam.type || pathParam?.schema?.type))
|
|
128
159
|
return "number";
|
|
129
|
-
if (pathParam.type === "array")
|
|
160
|
+
if (pathParam.type === "array") {
|
|
161
|
+
if (isSwaggerIntegerType(pathParam.items.type))
|
|
162
|
+
return "number[]";
|
|
130
163
|
return `${pathParam.items.type ?? "any"}[]`;
|
|
131
|
-
|
|
164
|
+
}
|
|
165
|
+
if (pathParam?.schema?.type === "array") {
|
|
166
|
+
if (isSwaggerIntegerType(pathParam.schema.items.type))
|
|
167
|
+
return "number[]";
|
|
132
168
|
return `${pathParam.schema.items.type ?? "any"}[]`;
|
|
169
|
+
}
|
|
133
170
|
if (pathParam?.schema?.type)
|
|
134
171
|
return pathParam.schema.type;
|
|
135
172
|
return pathParam.type;
|
|
136
173
|
};
|
|
137
174
|
static parseQueryParamsType = (queryParams) => {
|
|
138
|
-
return queryParams.map((queryParam) => ParserUtils.parseAttributeType(queryParam)).join(",");
|
|
175
|
+
return queryParams.map((queryParam) => ParserUtils.parseAttributeType(queryParam)).join(", ");
|
|
139
176
|
};
|
|
140
177
|
static isAnyQueryParamRequired = (queryParams) => {
|
|
141
178
|
return queryParams.some((queryParam) => queryParam.required);
|
|
142
179
|
};
|
|
180
|
+
static convertDashesToTitleCase = (str) => {
|
|
181
|
+
const result = str.split("-").map((word, index) => {
|
|
182
|
+
if (index === 0) {
|
|
183
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
184
|
+
}
|
|
185
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
186
|
+
}).join("");
|
|
187
|
+
return result;
|
|
188
|
+
};
|
|
143
189
|
static parseQueryParamsDefault = (queryParams) => {
|
|
144
190
|
const result = queryParams.filter((queryParam) => !!queryParam.default && !queryParam.required).map(ParserUtils.parseQueryParamAttributeDefault).join(",");
|
|
145
191
|
return result ? `${result},` : "";
|
|
146
192
|
};
|
|
147
193
|
static parseBodyParamsImports = (bodyParams) => {
|
|
148
|
-
return bodyParams.map(ParserUtils.parseRefImport).filter(Boolean);
|
|
194
|
+
return bodyParams.map((bodyParams2) => ParserUtils.parseRefImport(bodyParams2)).filter(Boolean);
|
|
149
195
|
};
|
|
150
196
|
static parseImportDir = ($ref) => {
|
|
151
197
|
let ref = $ref.replace(".", "/");
|
|
@@ -164,7 +210,7 @@ class ParserUtils {
|
|
|
164
210
|
return null;
|
|
165
211
|
}
|
|
166
212
|
const type = ParserUtils.parseRefType($ref);
|
|
167
|
-
return `import { ${type} } from '
|
|
213
|
+
return `import { ${type} } from '../definitions/${type}.js'`;
|
|
168
214
|
};
|
|
169
215
|
static parseRefType = ($ref) => {
|
|
170
216
|
let ref = $ref.replace(".", "/");
|
|
@@ -211,6 +257,8 @@ class ParserUtils {
|
|
|
211
257
|
return retBodyParams;
|
|
212
258
|
}
|
|
213
259
|
if (bodyParam?.schema?.type === "array" && !bodyParam?.schema?.items?.$ref) {
|
|
260
|
+
if (isSwaggerIntegerType(bodyParam.schema.items.type))
|
|
261
|
+
return "number[]";
|
|
214
262
|
return `${bodyParam.schema.items.type ?? "any"}[]`;
|
|
215
263
|
}
|
|
216
264
|
if (bodyParam?.schema?.type === "array" && bodyParam?.schema?.items?.$ref) {
|
|
@@ -267,8 +315,8 @@ class ParserUtils {
|
|
|
267
315
|
path_ = path_.substring(1);
|
|
268
316
|
const isPlural = httpMethod === "get" && !(path2.slice(-1) === "}");
|
|
269
317
|
if (!isPlural) {
|
|
270
|
-
path_ = replaceAll(path_, "ies/", "y/");
|
|
271
|
-
path_ = replaceAll(path_, "s/", "/");
|
|
318
|
+
path_ = ParserUtils.replaceAll(path_, "ies/", "y/");
|
|
319
|
+
path_ = ParserUtils.replaceAll(path_, "s/", "/");
|
|
272
320
|
if (path_.indexOf("status") < 0) {
|
|
273
321
|
path_ = path_.replace(/ies$/, "y");
|
|
274
322
|
path_ = path_.replace(/s$/, "");
|
|
@@ -307,7 +355,7 @@ class ParserUtils {
|
|
|
307
355
|
});
|
|
308
356
|
const genPath = _.upperFirst(lastWords) + "/" + listBeforeLastWords.join("/") + listByParams.reverse().join("/");
|
|
309
357
|
let generatedMethod = _.camelCase(mappedMethod(httpMethod, isForm) + genPath);
|
|
310
|
-
generatedMethod = replaceAll(generatedMethod, "Byword", "_By");
|
|
358
|
+
generatedMethod = ParserUtils.replaceAll(generatedMethod, "Byword", "_By");
|
|
311
359
|
generatedMethod = resolveConflicts(path2, generatedMethod, existingMethods);
|
|
312
360
|
return generatedMethod;
|
|
313
361
|
};
|
|
@@ -332,12 +380,22 @@ class ParserUtils {
|
|
|
332
380
|
const fileContent = templateClass(apiName, apiBuffer, imports);
|
|
333
381
|
fs__default.writeFileSync(`${distDir}/${apiName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
|
|
334
382
|
}
|
|
335
|
-
static
|
|
336
|
-
const
|
|
337
|
-
|
|
383
|
+
static writeApiFile(distDir, apiName, apiBuffer, imports, returnMethods) {
|
|
384
|
+
const newImports = [];
|
|
385
|
+
imports.forEach((el, index) => {
|
|
386
|
+
newImports.push(el.replace("../definitions", "./definitions"));
|
|
387
|
+
});
|
|
388
|
+
const fileContent = templateApiClass(apiName, apiBuffer, newImports, returnMethods);
|
|
389
|
+
fs__default.writeFileSync(`${distDir}/${apiName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
|
|
390
|
+
}
|
|
391
|
+
static writeApiMainFile(distDir, serviceName, fileContent) {
|
|
392
|
+
fs__default.writeFileSync(`${distDir}/${serviceName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
|
|
338
393
|
}
|
|
339
394
|
static writeSnippetFile(distDir, name, docBuffer) {
|
|
340
|
-
|
|
395
|
+
let snippetFileName = ParserUtils.replaceAll(name, " ", "-").toLowerCase();
|
|
396
|
+
snippetFileName = snippetFileName.replace("justice-", "");
|
|
397
|
+
snippetFileName = "snippet-" + snippetFileName + ".json";
|
|
398
|
+
fs__default.writeFileSync(`${distDir}/${snippetFileName}`, docBuffer);
|
|
341
399
|
}
|
|
342
400
|
static writeDefinitionFile(distDir, name, buffer) {
|
|
343
401
|
ParserUtils.mkdirIfNotExist(distDir);
|
|
@@ -347,15 +405,36 @@ class ParserUtils {
|
|
|
347
405
|
ParserUtils.mkdirIfNotExist(distDir);
|
|
348
406
|
fs__default.writeFileSync(path__default.join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
|
|
349
407
|
}
|
|
350
|
-
static
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
408
|
+
static syncChangelog(packageVersion) {
|
|
409
|
+
const currDir = process.cwd();
|
|
410
|
+
const pathToChangelog = path__default.join(currDir, "./CHANGELOG.md");
|
|
411
|
+
let fileContent = readFileSync(pathToChangelog, "utf-8");
|
|
412
|
+
const date = new Date().toISOString().slice(0, 10);
|
|
413
|
+
fileContent = "### " + packageVersion + " - " + date + `
|
|
414
|
+
|
|
415
|
+
- code-generated update
|
|
416
|
+
|
|
417
|
+
` + fileContent.trim();
|
|
418
|
+
fs__default.writeFileSync(pathToChangelog, fileContent, "utf-8");
|
|
419
|
+
}
|
|
420
|
+
static syncPackageVersion(apiInfo, isAdminWebSdk) {
|
|
421
|
+
if (isAdminWebSdk) {
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
const currDir = process.cwd();
|
|
425
|
+
const { packageJSON, pathToPackageJSON } = ParserUtils.getPackageJSONInfo(currDir);
|
|
426
|
+
let swaggerVersion = apiInfo.version ? apiInfo.version : UNDEFINED_SWAGGER_SEMVER;
|
|
427
|
+
swaggerVersion = Number(swaggerVersion.replace(".", "").replace(".", ""));
|
|
428
|
+
swaggerVersion = isNaN(swaggerVersion) ? 0 : swaggerVersion;
|
|
429
|
+
const semver = packageJSON.version.split(".").map((numStr) => Number(numStr));
|
|
430
|
+
const newSemver = [semver[0], swaggerVersion, ++semver[2]];
|
|
431
|
+
packageJSON.version = newSemver[0] + "." + newSemver[1] + "." + newSemver[2];
|
|
432
|
+
writeFileSync(pathToPackageJSON, JSON.stringify(packageJSON, null, 2));
|
|
433
|
+
ParserUtils.syncChangelog(packageJSON.version);
|
|
434
|
+
}
|
|
435
|
+
static getPackageJSONInfo(dir) {
|
|
436
|
+
const pathToPackageJSON = path__default.join(dir, "./package.json");
|
|
437
|
+
return { packageJSON: JSON.parse(readFileSync(pathToPackageJSON, "utf-8")), pathToPackageJSON };
|
|
359
438
|
}
|
|
360
439
|
static toCamelCase(str) {
|
|
361
440
|
return str.split("/").map(function(word, index) {
|
|
@@ -430,12 +509,9 @@ class ParserUtils {
|
|
|
430
509
|
${content}`;
|
|
431
510
|
};
|
|
432
511
|
}
|
|
433
|
-
const replaceAll = (string, search, replace) => {
|
|
434
|
-
return string.split(search).join(replace);
|
|
435
|
-
};
|
|
436
512
|
const mappedMethod = (httpMethod, isForm) => {
|
|
437
513
|
if (httpMethod === "get") {
|
|
438
|
-
return "
|
|
514
|
+
return "get";
|
|
439
515
|
} else if (httpMethod === "post" && isForm) {
|
|
440
516
|
return "post";
|
|
441
517
|
} else if (httpMethod === "post") {
|
|
@@ -494,6 +570,9 @@ const testConflict = (path2, generatedMethod, existingMethods) => {
|
|
|
494
570
|
existingMethods: ${JSON.stringify(existingMethods, null, 2)}`);
|
|
495
571
|
}
|
|
496
572
|
};
|
|
573
|
+
const isSwaggerIntegerType = (type) => {
|
|
574
|
+
return type === "integer" || type === "int";
|
|
575
|
+
};
|
|
497
576
|
|
|
498
577
|
const Schema = z.object({
|
|
499
578
|
$ref: z.string().nullish(),
|
|
@@ -596,16 +675,15 @@ const templateMethod = ({
|
|
|
596
675
|
isFormUrlEncoded,
|
|
597
676
|
responseClass
|
|
598
677
|
}) => {
|
|
599
|
-
let
|
|
678
|
+
let methodParams = "";
|
|
679
|
+
let methodParamsNoTypes = "";
|
|
600
680
|
let newPath = `'${path}'`;
|
|
601
|
-
let
|
|
602
|
-
let snippetString = "";
|
|
603
|
-
let snippetMethodSignature = "";
|
|
604
|
-
let snippetCurl = "";
|
|
681
|
+
let importStatements = [];
|
|
605
682
|
for (const pathParam of pathParams) {
|
|
606
683
|
const type = ParserUtils.parseType(pathParam);
|
|
607
684
|
if (pathParam.name !== "namespace") {
|
|
608
|
-
|
|
685
|
+
methodParams += pathParam.name + `:${type}, `;
|
|
686
|
+
methodParamsNoTypes += pathParam.name + ", ";
|
|
609
687
|
}
|
|
610
688
|
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
611
689
|
if (path.match(`{${pathParam.name}}`)) {
|
|
@@ -616,20 +694,12 @@ const templateMethod = ({
|
|
|
616
694
|
}
|
|
617
695
|
}
|
|
618
696
|
}
|
|
619
|
-
snippetCurl = `<span class='sn-blue'>curl</span> --location --request <span class='sn-blue'>${httpMethod}</span> '<span class='sn-green'>__DOMAIN__${path}</span>' --header 'accept: application/json'`;
|
|
620
697
|
let dataType = null;
|
|
621
698
|
if (httpMethod !== "get") {
|
|
622
699
|
dataType = ParserUtils.parseBodyParamsType(bodyParams);
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
return ` <span class='sn-purple'>${ob.name}</span>`;
|
|
627
|
-
});
|
|
628
|
-
snippetMethodSignature += snippetParams ? `data: { ${snippetParams} }` : "";
|
|
629
|
-
const curlParams = bodyParams?.map((ob) => {
|
|
630
|
-
return ` <span class='sn-purple'>"${ob.name}": ""</span>`;
|
|
631
|
-
});
|
|
632
|
-
snippetCurl += ` --data-raw { ${curlParams}}`;
|
|
700
|
+
importStatements = ParserUtils.parseBodyParamsImports(bodyParams);
|
|
701
|
+
methodParams += dataType ? `data: ${dataType},` : "";
|
|
702
|
+
methodParamsNoTypes += dataType ? `data,` : "";
|
|
633
703
|
}
|
|
634
704
|
const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
|
|
635
705
|
const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
|
|
@@ -639,7 +709,7 @@ const templateMethod = ({
|
|
|
639
709
|
let dataPayload = "{params}";
|
|
640
710
|
const descriptionText = description ? `
|
|
641
711
|
/**
|
|
642
|
-
* ${
|
|
712
|
+
* ${description.replace(/\n/g, "\n * ")}
|
|
643
713
|
*/` : "";
|
|
644
714
|
let formPayloadString = "";
|
|
645
715
|
if (isFormUrlEncoded) {
|
|
@@ -651,23 +721,21 @@ const templateMethod = ({
|
|
|
651
721
|
} else if (isDelete) {
|
|
652
722
|
dataPayload = dataType ? `{data, params}` : "{params}";
|
|
653
723
|
}
|
|
654
|
-
const isFileUpload =
|
|
724
|
+
const isFileUpload = methodParams.indexOf("data: {file") > -1;
|
|
655
725
|
const resolvedResponseClass = responseClass || "unknown";
|
|
656
726
|
const resolvedResponseClassValidated = responseClass || "z.unknown()";
|
|
657
|
-
|
|
727
|
+
methodParams = (queryParamsType ? `${methodParams} ${queryParamsType}` : methodParams).replace(/,\s*$/, "");
|
|
728
|
+
methodParamsNoTypes = queryParamsType ? `${methodParamsNoTypes} queryParams` : methodParamsNoTypes;
|
|
658
729
|
let methodImpl = "";
|
|
659
730
|
const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
|
|
660
|
-
const cachedFetchMethod = classMethod
|
|
731
|
+
const cachedFetchMethod = classMethod;
|
|
661
732
|
const deprecateTag = isCacheFetch ? `/**
|
|
662
|
-
* @deprecated Use "${
|
|
733
|
+
* @deprecated Use "${classMethod}()" instead.
|
|
663
734
|
*/` : "";
|
|
664
735
|
const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
|
|
665
736
|
const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
|
|
666
|
-
const
|
|
667
|
-
const
|
|
668
|
-
const generateMethodName = () => `${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>>`;
|
|
669
|
-
const generateSnippetMethodName = () => `${methodName}(${snippetMethodSignature})`;
|
|
670
|
-
snippetString += `${generateSnippetMethodName()}`;
|
|
737
|
+
const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
|
|
738
|
+
const generateMethodName = () => `${methodName}(${methodParams}): Promise<${responseSyncType}<${responseType}>>`;
|
|
671
739
|
const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
|
|
672
740
|
methodImpl = `${descriptionText}
|
|
673
741
|
${generateMethodName()} {
|
|
@@ -675,26 +743,32 @@ const templateMethod = ({
|
|
|
675
743
|
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
676
744
|
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
677
745
|
|
|
678
|
-
${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
|
|
746
|
+
${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')
|
|
679
747
|
|
|
680
748
|
if (!this.cache) {
|
|
681
749
|
return SdkCache.withoutCache(res)
|
|
682
750
|
}
|
|
683
751
|
const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
|
|
684
|
-
return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})` : ""}
|
|
752
|
+
return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')` : ""}
|
|
685
753
|
}
|
|
686
754
|
`;
|
|
687
755
|
if (!isGuardInvoked) {
|
|
688
756
|
methodImpl = `${descriptionText}
|
|
689
757
|
${deprecateTag}
|
|
690
|
-
TODO_${classMethod}
|
|
758
|
+
TODO_${classMethod}(${methodParams}): Promise<AxiosResponse<${resolvedResponseClass}>> {
|
|
691
759
|
${queryParamsDefault}
|
|
692
760
|
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
693
761
|
return this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
694
762
|
}
|
|
695
763
|
`;
|
|
696
764
|
}
|
|
697
|
-
|
|
765
|
+
const res = {
|
|
766
|
+
methodImpl,
|
|
767
|
+
methodParams,
|
|
768
|
+
methodParamsNoTypes,
|
|
769
|
+
importStatements
|
|
770
|
+
};
|
|
771
|
+
return res;
|
|
698
772
|
};
|
|
699
773
|
|
|
700
774
|
class TemplateZod {
|
|
@@ -710,7 +784,7 @@ class TemplateZod {
|
|
|
710
784
|
}
|
|
711
785
|
let imports = "";
|
|
712
786
|
for (const cl of Array.from(this.importClasses).sort()) {
|
|
713
|
-
imports += `import { ${cl} } from './${cl}'
|
|
787
|
+
imports += `import { ${cl} } from './${cl}.js'
|
|
714
788
|
`;
|
|
715
789
|
}
|
|
716
790
|
let exportedVariableString;
|
|
@@ -910,7 +984,7 @@ class TemplateZodArray {
|
|
|
910
984
|
render = (name) => {
|
|
911
985
|
const cls = name.replace("Array", "");
|
|
912
986
|
const template = `import { z } from 'zod'
|
|
913
|
-
import { ${cls} } from './${cls}'
|
|
987
|
+
import { ${cls} } from './${cls}.js'
|
|
914
988
|
|
|
915
989
|
export const ${name} = z.array(${cls})
|
|
916
990
|
|
|
@@ -949,15 +1023,138 @@ const extractEnumObject = (type, isRequired, enumArr) => {
|
|
|
949
1023
|
};
|
|
950
1024
|
};
|
|
951
1025
|
|
|
952
|
-
const
|
|
1026
|
+
const templateApiMethod = ({
|
|
1027
|
+
classMethod,
|
|
1028
|
+
description,
|
|
1029
|
+
httpMethod,
|
|
1030
|
+
path,
|
|
1031
|
+
pathParams,
|
|
1032
|
+
bodyParams,
|
|
1033
|
+
responseClass,
|
|
1034
|
+
classGenName,
|
|
1035
|
+
methodParams,
|
|
1036
|
+
methodParamsNoTypes
|
|
1037
|
+
}) => {
|
|
1038
|
+
let methodSignature = "";
|
|
1039
|
+
let newPath = `'${path}'`;
|
|
1040
|
+
let snippetSdk = "";
|
|
1041
|
+
let snippetShell = "";
|
|
1042
|
+
for (const pathParam of pathParams) {
|
|
1043
|
+
const type = ParserUtils.parseType(pathParam);
|
|
1044
|
+
if (pathParam.name !== "namespace") {
|
|
1045
|
+
methodSignature += pathParam.name + `:${type}, `;
|
|
1046
|
+
}
|
|
1047
|
+
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
1048
|
+
if (path.match(`{${pathParam.name}}`)) {
|
|
1049
|
+
if (type === "string") {
|
|
1050
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
1051
|
+
} else {
|
|
1052
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
snippetShell = `curl --location --request \\
|
|
1057
|
+
${httpMethod} '__DOMAIN__${path}' \\
|
|
1058
|
+
--header 'accept: application/json'`;
|
|
1059
|
+
if (httpMethod !== "get") {
|
|
1060
|
+
const curlParams = bodyParams?.map((ob) => {
|
|
1061
|
+
return ` "${ob.name}": ""`;
|
|
1062
|
+
});
|
|
1063
|
+
snippetShell += ` \\
|
|
1064
|
+
--data-raw '{ ${curlParams}}'`;
|
|
1065
|
+
}
|
|
1066
|
+
const descriptionText = description ? `
|
|
1067
|
+
/**
|
|
1068
|
+
* ${description.replace(/\n/g, "\n * ")}
|
|
1069
|
+
*/` : "";
|
|
1070
|
+
const resolvedResponseClass = responseClass || "unknown";
|
|
1071
|
+
const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
|
|
1072
|
+
const methodImpl = `
|
|
1073
|
+
${descriptionText}
|
|
1074
|
+
async function ${classMethod}(${methodParams}): Promise<${responseType}> {
|
|
1075
|
+
const $ = new ${classGenName}(Network.create(requestConfig), namespace, cache)
|
|
1076
|
+
const resp = await $.${classMethod}(${methodParamsNoTypes})
|
|
1077
|
+
if (resp.error) throw resp.error
|
|
1078
|
+
return resp.response.data
|
|
1079
|
+
}
|
|
1080
|
+
`;
|
|
1081
|
+
const snippetPromiseString = responseType !== "unknown" ? `Promise<${responseType}>` : "Promise";
|
|
1082
|
+
snippetSdk += `${classMethod}(${methodParams})
|
|
1083
|
+
// return ${snippetPromiseString}`;
|
|
1084
|
+
return [methodImpl, snippetSdk, snippetShell];
|
|
1085
|
+
};
|
|
1086
|
+
|
|
1087
|
+
const templateApiIndex = (serviceName, serviceNameTitle, apiList) => {
|
|
1088
|
+
let imports = "";
|
|
1089
|
+
let returnStatement = "";
|
|
1090
|
+
for (const cl of apiList) {
|
|
1091
|
+
imports += `
|
|
1092
|
+
import { ${cl} } from './${serviceName}/${cl}.js'`;
|
|
1093
|
+
returnStatement += `
|
|
1094
|
+
${cl}, `;
|
|
1095
|
+
}
|
|
1096
|
+
return `/**
|
|
1097
|
+
* AUTO GENERATED
|
|
1098
|
+
*/
|
|
1099
|
+
${imports}
|
|
1100
|
+
|
|
1101
|
+
const apis = {
|
|
1102
|
+
${returnStatement}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
export const ${ParserUtils.convertDashesToTitleCase(serviceNameTitle)} = apis
|
|
1106
|
+
`;
|
|
1107
|
+
};
|
|
1108
|
+
|
|
1109
|
+
const templateSdkSnippet = (serviceNameTitle, apiName, methodSnippet) => {
|
|
1110
|
+
const methodArr = methodSnippet.split("//");
|
|
1111
|
+
let normMethod = normalizeMethodSnippet(methodArr[0].trim(), "data:");
|
|
1112
|
+
normMethod = normalizeMethodSnippet(normMethod, "queryParams:");
|
|
1113
|
+
normMethod = normalizeMethodSnippet(normMethod, "queryParams?:");
|
|
1114
|
+
normMethod += "\n\n//" + methodArr[1];
|
|
1115
|
+
const sdkSnippet = `import { Accelbyte } from '@accelbyte/sdk'
|
|
1116
|
+
import { ${serviceNameTitle} } from '@accelbyte/sdk-${serviceNameTitle.toLowerCase()}'
|
|
1117
|
+
|
|
1118
|
+
const sdk = Accelbyte.SDK({
|
|
1119
|
+
baseURL: 'https://demo.accelbyte.io',
|
|
1120
|
+
clientId: '77f88506b6174c3ea4d925f5b4096ce8',
|
|
1121
|
+
namespace: 'accelbyte',
|
|
1122
|
+
redirectURI: 'http://localhost:3030'
|
|
1123
|
+
})
|
|
1124
|
+
|
|
1125
|
+
${serviceNameTitle}.${apiName}(sdk)
|
|
1126
|
+
.${normMethod}`;
|
|
1127
|
+
return sdkSnippet;
|
|
1128
|
+
};
|
|
1129
|
+
const normalizeMethodSnippet = (methodInput, splitWord) => {
|
|
1130
|
+
const split1 = methodInput.split(splitWord);
|
|
1131
|
+
if (!split1[1]) {
|
|
1132
|
+
return methodInput;
|
|
1133
|
+
}
|
|
1134
|
+
let split2 = split1[1].trim();
|
|
1135
|
+
split2 = ParserUtils.replaceAll(split2, "{", "");
|
|
1136
|
+
split2 = ParserUtils.replaceAll(split2, "})", "");
|
|
1137
|
+
split2 = split2.split(",");
|
|
1138
|
+
let params = "";
|
|
1139
|
+
split2.forEach((p) => {
|
|
1140
|
+
params += "\n " + ParserUtils.replaceAll(p.trim(), ")", "") + ",";
|
|
1141
|
+
});
|
|
1142
|
+
params = params.slice(0, -1);
|
|
1143
|
+
const result = split1[0] + splitWord + " {" + params + "\n })";
|
|
1144
|
+
return result;
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
const GIT_URL = "https://github.com/AccelByte/accelbyte-web-sdk/blob/main/packages";
|
|
953
1148
|
class CodeGenerator {
|
|
954
1149
|
static getPatchedDir = () => path__default.join(CliParser.getSwaggersOutputPath(), "patched");
|
|
955
1150
|
static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
|
|
956
1151
|
static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
|
|
957
1152
|
static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
|
|
958
1153
|
static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
|
|
959
|
-
static iterateApi = async (api) => {
|
|
1154
|
+
static iterateApi = async (api, serviceName) => {
|
|
960
1155
|
const apiBufferByTag = {};
|
|
1156
|
+
const apiArgumentsByTag = {};
|
|
1157
|
+
const classBufferByTag = {};
|
|
961
1158
|
const dependenciesByTag = {};
|
|
962
1159
|
const classImports = {};
|
|
963
1160
|
let arrayDefinitions = [];
|
|
@@ -972,7 +1169,6 @@ class CodeGenerator {
|
|
|
972
1169
|
}));
|
|
973
1170
|
const sortedKeys = Array.from(sortedPathsByLength.keys());
|
|
974
1171
|
const servicePrefix = CodeGenerator.getServicePrefix(sortedKeys);
|
|
975
|
-
console.log("ServicePrefix", servicePrefix, ", Paths:", sortedKeys);
|
|
976
1172
|
for (const [path2, operation] of sortedPathsByLength) {
|
|
977
1173
|
const isAdminEndpoint = path2.indexOf("/admin/") > -1;
|
|
978
1174
|
if (CliParser.isAdmin() && !isAdminEndpoint) {
|
|
@@ -1004,13 +1200,15 @@ class CodeGenerator {
|
|
|
1004
1200
|
});
|
|
1005
1201
|
mapClassMethods[tag][classMethod] = `${path2} ${httpMethod}`;
|
|
1006
1202
|
snippetMap[path2] = snippetMap[path2] ? snippetMap[path2] : {};
|
|
1007
|
-
|
|
1203
|
+
let description = endpoint.description;
|
|
1204
|
+
description = description || "";
|
|
1205
|
+
description = description.replace(/\s+/g, " ");
|
|
1008
1206
|
const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
|
|
1009
1207
|
const { className, classGenName } = ParserUtils.generateClassName(tag);
|
|
1010
1208
|
classImports[className] = classImports[className] ? classImports[className] : {};
|
|
1011
1209
|
if (responseClass) {
|
|
1012
1210
|
const importTypeClass = ParserUtils.parseRefType(responseClass);
|
|
1013
|
-
classImports[className][importTypeClass] = `import { ${importTypeClass} } from '
|
|
1211
|
+
classImports[className][importTypeClass] = `import { ${importTypeClass} } from '../definitions/${importTypeClass}.js'`;
|
|
1014
1212
|
}
|
|
1015
1213
|
if (responseClass && responseClass.endsWith("Array")) {
|
|
1016
1214
|
arrayDefinitions.push(responseClass);
|
|
@@ -1029,7 +1227,7 @@ class CodeGenerator {
|
|
|
1029
1227
|
}
|
|
1030
1228
|
];
|
|
1031
1229
|
}
|
|
1032
|
-
const
|
|
1230
|
+
const { methodImpl, methodParams, methodParamsNoTypes, importStatements } = templateMethod({
|
|
1033
1231
|
classMethod,
|
|
1034
1232
|
description,
|
|
1035
1233
|
httpMethod,
|
|
@@ -1040,16 +1238,42 @@ class CodeGenerator {
|
|
|
1040
1238
|
isFormUrlEncoded,
|
|
1041
1239
|
responseClass
|
|
1042
1240
|
});
|
|
1043
|
-
|
|
1241
|
+
classBufferByTag[tag] = (classBufferByTag[tag] || "") + methodImpl;
|
|
1242
|
+
const [generatedMethodString1, snippetMethod, snippetShell] = templateApiMethod({
|
|
1243
|
+
classMethod,
|
|
1244
|
+
description,
|
|
1245
|
+
httpMethod,
|
|
1246
|
+
path: pathWithBase,
|
|
1247
|
+
pathParams,
|
|
1248
|
+
bodyParams,
|
|
1249
|
+
responseClass,
|
|
1250
|
+
classGenName,
|
|
1251
|
+
methodParams,
|
|
1252
|
+
methodParamsNoTypes
|
|
1253
|
+
});
|
|
1254
|
+
apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString1;
|
|
1255
|
+
apiArgumentsByTag[tag] = (apiArgumentsByTag[tag] || "") + classMethod + ",";
|
|
1044
1256
|
dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
|
|
1257
|
+
const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
|
|
1258
|
+
const { apiGenName } = ParserUtils.generateApiName(tag);
|
|
1259
|
+
const resultSnippet = templateSdkSnippet(serviceNameTitle, apiGenName, snippetMethod);
|
|
1045
1260
|
snippetMap[path2][httpMethod] = {
|
|
1046
|
-
web:
|
|
1047
|
-
|
|
1261
|
+
web: resultSnippet,
|
|
1262
|
+
webGit: GIT_URL + `/sdk-${serviceName}/src/generated-public/${serviceName}/${apiGenName}.ts`,
|
|
1263
|
+
shell: snippetShell
|
|
1048
1264
|
};
|
|
1049
1265
|
}
|
|
1050
1266
|
}
|
|
1051
1267
|
arrayDefinitions = [...new Set(arrayDefinitions)];
|
|
1052
|
-
return {
|
|
1268
|
+
return {
|
|
1269
|
+
apiArgumentsByTag,
|
|
1270
|
+
apiBufferByTag,
|
|
1271
|
+
classBufferByTag,
|
|
1272
|
+
dependenciesByTag,
|
|
1273
|
+
classImports,
|
|
1274
|
+
arrayDefinitions,
|
|
1275
|
+
snippetMap
|
|
1276
|
+
};
|
|
1053
1277
|
};
|
|
1054
1278
|
static main = async (nameArray) => {
|
|
1055
1279
|
const serviceName = nameArray[0];
|
|
@@ -1057,6 +1281,7 @@ class CodeGenerator {
|
|
|
1057
1281
|
const parser = new SwaggerParser();
|
|
1058
1282
|
const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
|
|
1059
1283
|
const DIST_DIR = `${generatedFolder}/${serviceName}`;
|
|
1284
|
+
const DIST_ENDPOINTS_DIR = path__default.join(DIST_DIR, "endpoints");
|
|
1060
1285
|
const DIST_DEFINITION_DIR = path__default.join(DIST_DIR, "definitions");
|
|
1061
1286
|
const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
|
|
1062
1287
|
const swaggerPatchedFilePath = `${CodeGenerator.getPatchedDir()}/${swaggerFile}`;
|
|
@@ -1067,19 +1292,32 @@ class CodeGenerator {
|
|
|
1067
1292
|
console.log("----------\nGenerating API:", { title: api.info.title, version: api.info.version });
|
|
1068
1293
|
ParserUtils.mkdirIfNotExist(DIST_DIR);
|
|
1069
1294
|
ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
|
|
1070
|
-
ParserUtils.
|
|
1071
|
-
|
|
1295
|
+
ParserUtils.mkdirIfNotExist(DIST_ENDPOINTS_DIR);
|
|
1296
|
+
ParserUtils.syncPackageVersion(api.info, CliParser.isAdmin());
|
|
1297
|
+
const { apiArgumentsByTag, apiBufferByTag, classBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap } = await CodeGenerator.iterateApi(api, serviceName);
|
|
1072
1298
|
if (CliParser.getSnippetOutputPath()) {
|
|
1073
1299
|
ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify(snippetMap, null, 2));
|
|
1074
1300
|
}
|
|
1075
1301
|
const targetSrcFolder = `${CliParser.getOutputPath()}/`;
|
|
1076
|
-
|
|
1302
|
+
const apiList = [];
|
|
1303
|
+
for (const tag in classBufferByTag) {
|
|
1077
1304
|
const { className, classGenName } = ParserUtils.generateClassName(tag);
|
|
1078
|
-
const
|
|
1305
|
+
const classBuffer = classBufferByTag[tag];
|
|
1079
1306
|
const imports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
|
|
1080
|
-
|
|
1081
|
-
|
|
1307
|
+
const apiImports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
|
|
1308
|
+
apiImports.push(`import { ${classGenName} } from './endpoints/${classGenName}.js'`);
|
|
1309
|
+
ParserUtils.writeClassFile(DIST_ENDPOINTS_DIR, classGenName, classBuffer, imports);
|
|
1310
|
+
const apiBuffer = apiBufferByTag[tag];
|
|
1311
|
+
const { apiGenName } = ParserUtils.generateApiName(tag);
|
|
1312
|
+
ParserUtils.writeApiFile(DIST_DIR, apiGenName, apiBuffer, apiImports, apiArgumentsByTag[tag]);
|
|
1313
|
+
apiList.push(apiGenName);
|
|
1314
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_ENDPOINTS_DIR, `${classGenName}`), targetSrcFolder));
|
|
1315
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_DIR, `${apiGenName}`), targetSrcFolder));
|
|
1082
1316
|
}
|
|
1317
|
+
const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
|
|
1318
|
+
const apiIndexBuff = templateApiIndex(serviceName, serviceNameTitle, apiList);
|
|
1319
|
+
ParserUtils.writeApiMainFile(generatedFolder, serviceNameTitle, apiIndexBuff);
|
|
1320
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(generatedFolder, serviceNameTitle), targetSrcFolder));
|
|
1083
1321
|
const duplicates = /* @__PURE__ */ new Map();
|
|
1084
1322
|
const definitions = api?.components?.schemas || api.definitions;
|
|
1085
1323
|
for (const ref in definitions) {
|
|
@@ -1124,6 +1362,22 @@ class SwaggerDownloader {
|
|
|
1124
1362
|
fs.writeFileSync(destFile, "");
|
|
1125
1363
|
return destFile;
|
|
1126
1364
|
};
|
|
1365
|
+
static postSanitizeDownloadedFile = (filePath) => {
|
|
1366
|
+
const searchStr = ["%5B", "%5D", "%20", "%7B", "%7D"];
|
|
1367
|
+
fs.readFile(filePath, "utf8", (err, data) => {
|
|
1368
|
+
if (err)
|
|
1369
|
+
throw err;
|
|
1370
|
+
let result = data;
|
|
1371
|
+
searchStr.forEach((s) => {
|
|
1372
|
+
result = result.replace(new RegExp(s, "g"), " ");
|
|
1373
|
+
});
|
|
1374
|
+
fs.writeFile(filePath, result, "utf8", (err2) => {
|
|
1375
|
+
if (err2)
|
|
1376
|
+
throw err2;
|
|
1377
|
+
console.log("File updated successfully.");
|
|
1378
|
+
});
|
|
1379
|
+
});
|
|
1380
|
+
};
|
|
1127
1381
|
static downloadFile = (targetFileName, url) => {
|
|
1128
1382
|
const destFile = SwaggerDownloader.getDestFile(targetFileName);
|
|
1129
1383
|
const file = fs.createWriteStream(destFile);
|
|
@@ -1131,6 +1385,7 @@ class SwaggerDownloader {
|
|
|
1131
1385
|
response.pipe(file);
|
|
1132
1386
|
file.on("finish", () => {
|
|
1133
1387
|
file.close();
|
|
1388
|
+
SwaggerDownloader.postSanitizeDownloadedFile(destFile);
|
|
1134
1389
|
console.log(`SwaggerDownload ${url} completed`);
|
|
1135
1390
|
});
|
|
1136
1391
|
});
|