@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.
@@ -79,18 +79,18 @@ class CliParser {
79
79
  };
80
80
  }
81
81
 
82
- const getImportableVarMap = () => ({
82
+ const getImportableVarMap$1 = () => ({
83
83
  "@accelbyte/sdk": ["CodeGenUtil", "SdkCache", "IResponse", "IResponseWithSync", "Validate"],
84
84
  axios: ["AxiosRequestConfig", "AxiosResponse"],
85
85
  zod: ["z"]
86
86
  });
87
- const makeNewImportVarMap = () => ({
87
+ const makeNewImportVarMap$1 = () => ({
88
88
  axios: ["AxiosInstance"],
89
89
  "@accelbyte/sdk": ["SDKRequestConfig"]
90
90
  });
91
- const generateImports = (body, importStatements) => {
92
- const usedImportVarMap = makeNewImportVarMap();
93
- const importableVarMap = getImportableVarMap();
91
+ const generateImports = (body, importStatements, makeNewImportVarMap2, getImportableVarMap2) => {
92
+ const usedImportVarMap = makeNewImportVarMap2;
93
+ const importableVarMap = getImportableVarMap2;
94
94
  for (const [moduleSource, importableVars] of Object.entries(importableVarMap)) {
95
95
  for (const importableVar of importableVars) {
96
96
  const importVarRegex = new RegExp(`(?<![\\d\\w_])${importableVar}(?![\\d\\w_])`);
@@ -103,10 +103,11 @@ const generateImports = (body, importStatements) => {
103
103
  return `${generatedImports}
104
104
  ${importStatements.sort().join("\n")}`;
105
105
  };
106
- const templateClass = (className, body, importStatements) => `/**
107
- * DON'T EDIT THIS FILE, it is AUTO GENERATED
106
+ const templateClass = (className, body, importStatements) => {
107
+ return `/**
108
+ * AUTO GENERATED
108
109
  */
109
- ${generateImports(body, importStatements)}
110
+ ${generateImports(body, importStatements, makeNewImportVarMap$1(), getImportableVarMap$1())}
110
111
 
111
112
  export class ${className} {
112
113
  // @ts-ignore
@@ -114,15 +115,37 @@ export class ${className} {
114
115
  ${body}
115
116
  }
116
117
  `;
118
+ };
117
119
 
118
- const templateJsdocFile = (apiName, body) => `
119
- \`\`\`
120
- SDK.getService('${apiName}', authHeader):
121
- ${body}
120
+ const getImportableVarMap = () => ({
121
+ "@accelbyte/sdk": ["CodeGenUtil", "SdkCache", "IResponse", "IResponseWithSync", "Validate", "ApiArgs", "Network", "AccelbyteSDK"]
122
+ });
123
+ const makeNewImportVarMap = () => ({
124
+ "@accelbyte/sdk": ["AccelbyteSDK", "ApiArgs", "ApiUtils"]
125
+ });
126
+ const templateApiClass = (className, body, importStatements, returnMethods) => {
127
+ return `/**
128
+ * AUTO GENERATED
129
+ */
130
+ /* eslint-disable camelcase */
131
+ ${generateImports(body, importStatements, makeNewImportVarMap(), getImportableVarMap())}
122
132
 
123
- \`\`\`
124
- `.replace(/, \)/g, ")").trim();
133
+ export function ${className}(sdk: AccelbyteSDK, args?: ApiArgs) {
134
+ const sdkAssembly = sdk.assembly()
135
+
136
+ const namespace = args?.namespace ? args?.namespace : sdkAssembly.namespace
137
+ const cache = args?.cache ? args?.cache : sdkAssembly.cache
138
+ const requestConfig = ApiUtils.mergedConfigs(sdkAssembly.config, args)
139
+ ${body}
140
+
141
+ return {
142
+ ${returnMethods}
143
+ }
144
+ }
145
+ `;
146
+ };
125
147
 
148
+ const UNDEFINED_SWAGGER_SEMVER = "0.0.0";
126
149
  const REMOVED_KEYWORDS = [
127
150
  "/admin/",
128
151
  "/public/",
@@ -136,39 +159,62 @@ const REMOVED_KEYWORDS = [
136
159
  "/{namespace}/"
137
160
  ];
138
161
  class ParserUtils {
162
+ static replaceAll = (string, search, replace) => {
163
+ return string.split(search).join(replace);
164
+ };
139
165
  static generateClassName = (tag) => {
140
166
  const className = _.upperFirst(_.camelCase(tag));
141
167
  const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
142
168
  return { className, classGenName };
143
169
  };
170
+ static generateApiName = (tag) => {
171
+ const apiName = _.upperFirst(_.camelCase(tag));
172
+ const apiGenName = CliParser.isAdmin() ? apiName + "AdminApi" : apiName + "Api";
173
+ return { apiName, apiGenName };
174
+ };
144
175
  static parseQueryParamAttributeDefault = (definition) => {
145
176
  const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
146
177
  const defaultValue = definition.type === "string" ? `'${definition.default}'` : definition.default;
147
178
  return `${attrName}: ${defaultValue}`;
148
179
  };
149
180
  static parseType = (pathParam) => {
150
- if (pathParam.type === "int" || pathParam.type === "integer" || pathParam?.schema?.type === "integer")
181
+ if (isSwaggerIntegerType(pathParam.type || pathParam?.schema?.type))
151
182
  return "number";
152
- if (pathParam.type === "array")
183
+ if (pathParam.type === "array") {
184
+ if (isSwaggerIntegerType(pathParam.items.type))
185
+ return "number[]";
153
186
  return `${pathParam.items.type ?? "any"}[]`;
154
- if (pathParam?.schema?.type === "array")
187
+ }
188
+ if (pathParam?.schema?.type === "array") {
189
+ if (isSwaggerIntegerType(pathParam.schema.items.type))
190
+ return "number[]";
155
191
  return `${pathParam.schema.items.type ?? "any"}[]`;
192
+ }
156
193
  if (pathParam?.schema?.type)
157
194
  return pathParam.schema.type;
158
195
  return pathParam.type;
159
196
  };
160
197
  static parseQueryParamsType = (queryParams) => {
161
- return queryParams.map((queryParam) => ParserUtils.parseAttributeType(queryParam)).join(",");
198
+ return queryParams.map((queryParam) => ParserUtils.parseAttributeType(queryParam)).join(", ");
162
199
  };
163
200
  static isAnyQueryParamRequired = (queryParams) => {
164
201
  return queryParams.some((queryParam) => queryParam.required);
165
202
  };
203
+ static convertDashesToTitleCase = (str) => {
204
+ const result = str.split("-").map((word, index) => {
205
+ if (index === 0) {
206
+ return word.charAt(0).toUpperCase() + word.slice(1);
207
+ }
208
+ return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
209
+ }).join("");
210
+ return result;
211
+ };
166
212
  static parseQueryParamsDefault = (queryParams) => {
167
213
  const result = queryParams.filter((queryParam) => !!queryParam.default && !queryParam.required).map(ParserUtils.parseQueryParamAttributeDefault).join(",");
168
214
  return result ? `${result},` : "";
169
215
  };
170
216
  static parseBodyParamsImports = (bodyParams) => {
171
- return bodyParams.map(ParserUtils.parseRefImport).filter(Boolean);
217
+ return bodyParams.map((bodyParams2) => ParserUtils.parseRefImport(bodyParams2)).filter(Boolean);
172
218
  };
173
219
  static parseImportDir = ($ref) => {
174
220
  let ref = $ref.replace(".", "/");
@@ -187,7 +233,7 @@ class ParserUtils {
187
233
  return null;
188
234
  }
189
235
  const type = ParserUtils.parseRefType($ref);
190
- return `import { ${type} } from './definitions/${type}'`;
236
+ return `import { ${type} } from '../definitions/${type}.js'`;
191
237
  };
192
238
  static parseRefType = ($ref) => {
193
239
  let ref = $ref.replace(".", "/");
@@ -234,6 +280,8 @@ class ParserUtils {
234
280
  return retBodyParams;
235
281
  }
236
282
  if (bodyParam?.schema?.type === "array" && !bodyParam?.schema?.items?.$ref) {
283
+ if (isSwaggerIntegerType(bodyParam.schema.items.type))
284
+ return "number[]";
237
285
  return `${bodyParam.schema.items.type ?? "any"}[]`;
238
286
  }
239
287
  if (bodyParam?.schema?.type === "array" && bodyParam?.schema?.items?.$ref) {
@@ -290,8 +338,8 @@ class ParserUtils {
290
338
  path_ = path_.substring(1);
291
339
  const isPlural = httpMethod === "get" && !(path2.slice(-1) === "}");
292
340
  if (!isPlural) {
293
- path_ = replaceAll(path_, "ies/", "y/");
294
- path_ = replaceAll(path_, "s/", "/");
341
+ path_ = ParserUtils.replaceAll(path_, "ies/", "y/");
342
+ path_ = ParserUtils.replaceAll(path_, "s/", "/");
295
343
  if (path_.indexOf("status") < 0) {
296
344
  path_ = path_.replace(/ies$/, "y");
297
345
  path_ = path_.replace(/s$/, "");
@@ -330,7 +378,7 @@ class ParserUtils {
330
378
  });
331
379
  const genPath = _.upperFirst(lastWords) + "/" + listBeforeLastWords.join("/") + listByParams.reverse().join("/");
332
380
  let generatedMethod = _.camelCase(mappedMethod(httpMethod, isForm) + genPath);
333
- generatedMethod = replaceAll(generatedMethod, "Byword", "_By");
381
+ generatedMethod = ParserUtils.replaceAll(generatedMethod, "Byword", "_By");
334
382
  generatedMethod = resolveConflicts(path2, generatedMethod, existingMethods);
335
383
  return generatedMethod;
336
384
  };
@@ -355,12 +403,22 @@ class ParserUtils {
355
403
  const fileContent = templateClass(apiName, apiBuffer, imports);
356
404
  fs.writeFileSync(`${distDir}/${apiName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
357
405
  }
358
- static writeJsdocFile(distDir, nameArray, apiBuffer) {
359
- const jsdocFile = templateJsdocFile(nameArray[0], apiBuffer);
360
- fs.writeFileSync(`${distDir}/docs/${nameArray[0]}.md`, jsdocFile);
406
+ static writeApiFile(distDir, apiName, apiBuffer, imports, returnMethods) {
407
+ const newImports = [];
408
+ imports.forEach((el, index) => {
409
+ newImports.push(el.replace("../definitions", "./definitions"));
410
+ });
411
+ const fileContent = templateApiClass(apiName, apiBuffer, newImports, returnMethods);
412
+ fs.writeFileSync(`${distDir}/${apiName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
413
+ }
414
+ static writeApiMainFile(distDir, serviceName, fileContent) {
415
+ fs.writeFileSync(`${distDir}/${serviceName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
361
416
  }
362
417
  static writeSnippetFile(distDir, name, docBuffer) {
363
- fs.writeFileSync(`${distDir}/${name}.json`, docBuffer);
418
+ let snippetFileName = ParserUtils.replaceAll(name, " ", "-").toLowerCase();
419
+ snippetFileName = snippetFileName.replace("justice-", "");
420
+ snippetFileName = "snippet-" + snippetFileName + ".json";
421
+ fs.writeFileSync(`${distDir}/${snippetFileName}`, docBuffer);
364
422
  }
365
423
  static writeDefinitionFile(distDir, name, buffer) {
366
424
  ParserUtils.mkdirIfNotExist(distDir);
@@ -370,15 +428,36 @@ class ParserUtils {
370
428
  ParserUtils.mkdirIfNotExist(distDir);
371
429
  fs.writeFileSync(path.join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
372
430
  }
373
- static writeVersionFile(distDir, fileName, serviceName, apiInfo, buildDate) {
374
- const ver = apiInfo.version ? `'${apiInfo.version}'` : void 0;
375
- fs.writeFileSync(`${distDir}/${fileName}`, `export default {
376
- title: '${serviceName}',
377
- name: '${apiInfo.title}',
378
- version: ${ver},
379
- buildDate: '${buildDate}'
380
- }
381
- `);
431
+ static syncChangelog(packageVersion) {
432
+ const currDir = process.cwd();
433
+ const pathToChangelog = path.join(currDir, "./CHANGELOG.md");
434
+ let fileContent = fs.readFileSync(pathToChangelog, "utf-8");
435
+ const date = new Date().toISOString().slice(0, 10);
436
+ fileContent = "### " + packageVersion + " - " + date + `
437
+
438
+ - code-generated update
439
+
440
+ ` + fileContent.trim();
441
+ fs.writeFileSync(pathToChangelog, fileContent, "utf-8");
442
+ }
443
+ static syncPackageVersion(apiInfo, isAdminWebSdk) {
444
+ if (isAdminWebSdk) {
445
+ return;
446
+ }
447
+ const currDir = process.cwd();
448
+ const { packageJSON, pathToPackageJSON } = ParserUtils.getPackageJSONInfo(currDir);
449
+ let swaggerVersion = apiInfo.version ? apiInfo.version : UNDEFINED_SWAGGER_SEMVER;
450
+ swaggerVersion = Number(swaggerVersion.replace(".", "").replace(".", ""));
451
+ swaggerVersion = isNaN(swaggerVersion) ? 0 : swaggerVersion;
452
+ const semver = packageJSON.version.split(".").map((numStr) => Number(numStr));
453
+ const newSemver = [semver[0], swaggerVersion, ++semver[2]];
454
+ packageJSON.version = newSemver[0] + "." + newSemver[1] + "." + newSemver[2];
455
+ fs.writeFileSync(pathToPackageJSON, JSON.stringify(packageJSON, null, 2));
456
+ ParserUtils.syncChangelog(packageJSON.version);
457
+ }
458
+ static getPackageJSONInfo(dir) {
459
+ const pathToPackageJSON = path.join(dir, "./package.json");
460
+ return { packageJSON: JSON.parse(fs.readFileSync(pathToPackageJSON, "utf-8")), pathToPackageJSON };
382
461
  }
383
462
  static toCamelCase(str) {
384
463
  return str.split("/").map(function(word, index) {
@@ -453,12 +532,9 @@ class ParserUtils {
453
532
  ${content}`;
454
533
  };
455
534
  }
456
- const replaceAll = (string, search, replace) => {
457
- return string.split(search).join(replace);
458
- };
459
535
  const mappedMethod = (httpMethod, isForm) => {
460
536
  if (httpMethod === "get") {
461
- return "fetch";
537
+ return "get";
462
538
  } else if (httpMethod === "post" && isForm) {
463
539
  return "post";
464
540
  } else if (httpMethod === "post") {
@@ -517,6 +593,9 @@ const testConflict = (path2, generatedMethod, existingMethods) => {
517
593
  existingMethods: ${JSON.stringify(existingMethods, null, 2)}`);
518
594
  }
519
595
  };
596
+ const isSwaggerIntegerType = (type) => {
597
+ return type === "integer" || type === "int";
598
+ };
520
599
 
521
600
  const Schema = zod.z.object({
522
601
  $ref: zod.z.string().nullish(),
@@ -619,16 +698,15 @@ const templateMethod = ({
619
698
  isFormUrlEncoded,
620
699
  responseClass
621
700
  }) => {
622
- let methodSignature = "";
701
+ let methodParams = "";
702
+ let methodParamsNoTypes = "";
623
703
  let newPath = `'${path}'`;
624
- let dependencies = [];
625
- let snippetString = "";
626
- let snippetMethodSignature = "";
627
- let snippetCurl = "";
704
+ let importStatements = [];
628
705
  for (const pathParam of pathParams) {
629
706
  const type = ParserUtils.parseType(pathParam);
630
707
  if (pathParam.name !== "namespace") {
631
- methodSignature += pathParam.name + `:${type}, `;
708
+ methodParams += pathParam.name + `:${type}, `;
709
+ methodParamsNoTypes += pathParam.name + ", ";
632
710
  }
633
711
  const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
634
712
  if (path.match(`{${pathParam.name}}`)) {
@@ -639,20 +717,12 @@ const templateMethod = ({
639
717
  }
640
718
  }
641
719
  }
642
- 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'`;
643
720
  let dataType = null;
644
721
  if (httpMethod !== "get") {
645
722
  dataType = ParserUtils.parseBodyParamsType(bodyParams);
646
- dependencies = ParserUtils.parseBodyParamsImports(bodyParams);
647
- methodSignature += dataType ? `data: ${dataType},` : "";
648
- const snippetParams = bodyParams?.map((ob) => {
649
- return ` <span class='sn-purple'>${ob.name}</span>`;
650
- });
651
- snippetMethodSignature += snippetParams ? `data: { ${snippetParams} }` : "";
652
- const curlParams = bodyParams?.map((ob) => {
653
- return ` <span class='sn-purple'>"${ob.name}": ""</span>`;
654
- });
655
- snippetCurl += ` --data-raw { ${curlParams}}`;
723
+ importStatements = ParserUtils.parseBodyParamsImports(bodyParams);
724
+ methodParams += dataType ? `data: ${dataType},` : "";
725
+ methodParamsNoTypes += dataType ? `data,` : "";
656
726
  }
657
727
  const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
658
728
  const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
@@ -662,7 +732,7 @@ const templateMethod = ({
662
732
  let dataPayload = "{params}";
663
733
  const descriptionText = description ? `
664
734
  /**
665
- * ${(description || "").replace(/\n/g, "\n * ")}
735
+ * ${description.replace(/\n/g, "\n * ")}
666
736
  */` : "";
667
737
  let formPayloadString = "";
668
738
  if (isFormUrlEncoded) {
@@ -674,23 +744,21 @@ const templateMethod = ({
674
744
  } else if (isDelete) {
675
745
  dataPayload = dataType ? `{data, params}` : "{params}";
676
746
  }
677
- const isFileUpload = methodSignature.indexOf("data: {file") > -1;
747
+ const isFileUpload = methodParams.indexOf("data: {file") > -1;
678
748
  const resolvedResponseClass = responseClass || "unknown";
679
749
  const resolvedResponseClassValidated = responseClass || "z.unknown()";
680
- const parameters = (queryParamsType ? `${methodSignature} ${queryParamsType}` : methodSignature).replace(/,\s*$/, "");
750
+ methodParams = (queryParamsType ? `${methodParams} ${queryParamsType}` : methodParams).replace(/,\s*$/, "");
751
+ methodParamsNoTypes = queryParamsType ? `${methodParamsNoTypes} queryParams` : methodParamsNoTypes;
681
752
  let methodImpl = "";
682
753
  const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
683
- const cachedFetchMethod = classMethod.replace("get", "fetch");
754
+ const cachedFetchMethod = classMethod;
684
755
  const deprecateTag = isCacheFetch ? `/**
685
- * @deprecated Use "${cachedFetchMethod}()" instead.
756
+ * @deprecated Use "${classMethod}()" instead.
686
757
  */` : "";
687
758
  const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
688
759
  const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
689
- const methodGenerics = resolvedResponseClass !== "unknown" ? `<T = ${resolvedResponseClass}>` : "";
690
- const responseType = resolvedResponseClass !== "unknown" ? `T` : "unknown";
691
- const generateMethodName = () => `${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>>`;
692
- const generateSnippetMethodName = () => `${methodName}(${snippetMethodSignature})`;
693
- snippetString += `${generateSnippetMethodName()}`;
760
+ const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
761
+ const generateMethodName = () => `${methodName}(${methodParams}): Promise<${responseSyncType}<${responseType}>>`;
694
762
  const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
695
763
  methodImpl = `${descriptionText}
696
764
  ${generateMethodName()} {
@@ -698,26 +766,32 @@ const templateMethod = ({
698
766
  const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
699
767
  const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
700
768
 
701
- ${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
769
+ ${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')
702
770
 
703
771
  if (!this.cache) {
704
772
  return SdkCache.withoutCache(res)
705
773
  }
706
774
  const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
707
- return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})` : ""}
775
+ return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')` : ""}
708
776
  }
709
777
  `;
710
778
  if (!isGuardInvoked) {
711
779
  methodImpl = `${descriptionText}
712
780
  ${deprecateTag}
713
- TODO_${classMethod}<T = ${resolvedResponseClass}>(${parameters}): Promise<AxiosResponse<T>> {
781
+ TODO_${classMethod}(${methodParams}): Promise<AxiosResponse<${resolvedResponseClass}>> {
714
782
  ${queryParamsDefault}
715
783
  const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
716
784
  return this.axiosInstance.${httpMethod}(url, ${dataPayload})
717
785
  }
718
786
  `;
719
787
  }
720
- return [methodImpl, dependencies, snippetString, snippetCurl];
788
+ const res = {
789
+ methodImpl,
790
+ methodParams,
791
+ methodParamsNoTypes,
792
+ importStatements
793
+ };
794
+ return res;
721
795
  };
722
796
 
723
797
  class TemplateZod {
@@ -733,7 +807,7 @@ class TemplateZod {
733
807
  }
734
808
  let imports = "";
735
809
  for (const cl of Array.from(this.importClasses).sort()) {
736
- imports += `import { ${cl} } from './${cl}'
810
+ imports += `import { ${cl} } from './${cl}.js'
737
811
  `;
738
812
  }
739
813
  let exportedVariableString;
@@ -933,7 +1007,7 @@ class TemplateZodArray {
933
1007
  render = (name) => {
934
1008
  const cls = name.replace("Array", "");
935
1009
  const template = `import { z } from 'zod'
936
- import { ${cls} } from './${cls}'
1010
+ import { ${cls} } from './${cls}.js'
937
1011
 
938
1012
  export const ${name} = z.array(${cls})
939
1013
 
@@ -972,15 +1046,138 @@ const extractEnumObject = (type, isRequired, enumArr) => {
972
1046
  };
973
1047
  };
974
1048
 
975
- const BUILD_DATE = new Date().toISOString();
1049
+ const templateApiMethod = ({
1050
+ classMethod,
1051
+ description,
1052
+ httpMethod,
1053
+ path,
1054
+ pathParams,
1055
+ bodyParams,
1056
+ responseClass,
1057
+ classGenName,
1058
+ methodParams,
1059
+ methodParamsNoTypes
1060
+ }) => {
1061
+ let methodSignature = "";
1062
+ let newPath = `'${path}'`;
1063
+ let snippetSdk = "";
1064
+ let snippetShell = "";
1065
+ for (const pathParam of pathParams) {
1066
+ const type = ParserUtils.parseType(pathParam);
1067
+ if (pathParam.name !== "namespace") {
1068
+ methodSignature += pathParam.name + `:${type}, `;
1069
+ }
1070
+ const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
1071
+ if (path.match(`{${pathParam.name}}`)) {
1072
+ if (type === "string") {
1073
+ newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
1074
+ } else {
1075
+ newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
1076
+ }
1077
+ }
1078
+ }
1079
+ snippetShell = `curl --location --request \\
1080
+ ${httpMethod} '__DOMAIN__${path}' \\
1081
+ --header 'accept: application/json'`;
1082
+ if (httpMethod !== "get") {
1083
+ const curlParams = bodyParams?.map((ob) => {
1084
+ return ` "${ob.name}": ""`;
1085
+ });
1086
+ snippetShell += ` \\
1087
+ --data-raw '{ ${curlParams}}'`;
1088
+ }
1089
+ const descriptionText = description ? `
1090
+ /**
1091
+ * ${description.replace(/\n/g, "\n * ")}
1092
+ */` : "";
1093
+ const resolvedResponseClass = responseClass || "unknown";
1094
+ const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
1095
+ const methodImpl = `
1096
+ ${descriptionText}
1097
+ async function ${classMethod}(${methodParams}): Promise<${responseType}> {
1098
+ const $ = new ${classGenName}(Network.create(requestConfig), namespace, cache)
1099
+ const resp = await $.${classMethod}(${methodParamsNoTypes})
1100
+ if (resp.error) throw resp.error
1101
+ return resp.response.data
1102
+ }
1103
+ `;
1104
+ const snippetPromiseString = responseType !== "unknown" ? `Promise<${responseType}>` : "Promise";
1105
+ snippetSdk += `${classMethod}(${methodParams})
1106
+ // return ${snippetPromiseString}`;
1107
+ return [methodImpl, snippetSdk, snippetShell];
1108
+ };
1109
+
1110
+ const templateApiIndex = (serviceName, serviceNameTitle, apiList) => {
1111
+ let imports = "";
1112
+ let returnStatement = "";
1113
+ for (const cl of apiList) {
1114
+ imports += `
1115
+ import { ${cl} } from './${serviceName}/${cl}.js'`;
1116
+ returnStatement += `
1117
+ ${cl}, `;
1118
+ }
1119
+ return `/**
1120
+ * AUTO GENERATED
1121
+ */
1122
+ ${imports}
1123
+
1124
+ const apis = {
1125
+ ${returnStatement}
1126
+ }
1127
+
1128
+ export const ${ParserUtils.convertDashesToTitleCase(serviceNameTitle)} = apis
1129
+ `;
1130
+ };
1131
+
1132
+ const templateSdkSnippet = (serviceNameTitle, apiName, methodSnippet) => {
1133
+ const methodArr = methodSnippet.split("//");
1134
+ let normMethod = normalizeMethodSnippet(methodArr[0].trim(), "data:");
1135
+ normMethod = normalizeMethodSnippet(normMethod, "queryParams:");
1136
+ normMethod = normalizeMethodSnippet(normMethod, "queryParams?:");
1137
+ normMethod += "\n\n//" + methodArr[1];
1138
+ const sdkSnippet = `import { Accelbyte } from '@accelbyte/sdk'
1139
+ import { ${serviceNameTitle} } from '@accelbyte/sdk-${serviceNameTitle.toLowerCase()}'
1140
+
1141
+ const sdk = Accelbyte.SDK({
1142
+ baseURL: 'https://demo.accelbyte.io',
1143
+ clientId: '77f88506b6174c3ea4d925f5b4096ce8',
1144
+ namespace: 'accelbyte',
1145
+ redirectURI: 'http://localhost:3030'
1146
+ })
1147
+
1148
+ ${serviceNameTitle}.${apiName}(sdk)
1149
+ .${normMethod}`;
1150
+ return sdkSnippet;
1151
+ };
1152
+ const normalizeMethodSnippet = (methodInput, splitWord) => {
1153
+ const split1 = methodInput.split(splitWord);
1154
+ if (!split1[1]) {
1155
+ return methodInput;
1156
+ }
1157
+ let split2 = split1[1].trim();
1158
+ split2 = ParserUtils.replaceAll(split2, "{", "");
1159
+ split2 = ParserUtils.replaceAll(split2, "})", "");
1160
+ split2 = split2.split(",");
1161
+ let params = "";
1162
+ split2.forEach((p) => {
1163
+ params += "\n " + ParserUtils.replaceAll(p.trim(), ")", "") + ",";
1164
+ });
1165
+ params = params.slice(0, -1);
1166
+ const result = split1[0] + splitWord + " {" + params + "\n })";
1167
+ return result;
1168
+ };
1169
+
1170
+ const GIT_URL = "https://github.com/AccelByte/accelbyte-web-sdk/blob/main/packages";
976
1171
  class CodeGenerator {
977
1172
  static getPatchedDir = () => path.join(CliParser.getSwaggersOutputPath(), "patched");
978
1173
  static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
979
1174
  static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
980
1175
  static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
981
1176
  static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
982
- static iterateApi = async (api) => {
1177
+ static iterateApi = async (api, serviceName) => {
983
1178
  const apiBufferByTag = {};
1179
+ const apiArgumentsByTag = {};
1180
+ const classBufferByTag = {};
984
1181
  const dependenciesByTag = {};
985
1182
  const classImports = {};
986
1183
  let arrayDefinitions = [];
@@ -995,7 +1192,6 @@ class CodeGenerator {
995
1192
  }));
996
1193
  const sortedKeys = Array.from(sortedPathsByLength.keys());
997
1194
  const servicePrefix = CodeGenerator.getServicePrefix(sortedKeys);
998
- console.log("ServicePrefix", servicePrefix, ", Paths:", sortedKeys);
999
1195
  for (const [path2, operation] of sortedPathsByLength) {
1000
1196
  const isAdminEndpoint = path2.indexOf("/admin/") > -1;
1001
1197
  if (CliParser.isAdmin() && !isAdminEndpoint) {
@@ -1027,13 +1223,15 @@ class CodeGenerator {
1027
1223
  });
1028
1224
  mapClassMethods[tag][classMethod] = `${path2} ${httpMethod}`;
1029
1225
  snippetMap[path2] = snippetMap[path2] ? snippetMap[path2] : {};
1030
- const description = endpoint.description;
1226
+ let description = endpoint.description;
1227
+ description = description || "";
1228
+ description = description.replace(/\s+/g, " ");
1031
1229
  const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
1032
1230
  const { className, classGenName } = ParserUtils.generateClassName(tag);
1033
1231
  classImports[className] = classImports[className] ? classImports[className] : {};
1034
1232
  if (responseClass) {
1035
1233
  const importTypeClass = ParserUtils.parseRefType(responseClass);
1036
- classImports[className][importTypeClass] = `import { ${importTypeClass} } from './definitions/${importTypeClass}'`;
1234
+ classImports[className][importTypeClass] = `import { ${importTypeClass} } from '../definitions/${importTypeClass}.js'`;
1037
1235
  }
1038
1236
  if (responseClass && responseClass.endsWith("Array")) {
1039
1237
  arrayDefinitions.push(responseClass);
@@ -1052,7 +1250,7 @@ class CodeGenerator {
1052
1250
  }
1053
1251
  ];
1054
1252
  }
1055
- const [generatedMethodString, importStatements, snippetString, snippetCurl] = templateMethod({
1253
+ const { methodImpl, methodParams, methodParamsNoTypes, importStatements } = templateMethod({
1056
1254
  classMethod,
1057
1255
  description,
1058
1256
  httpMethod,
@@ -1063,16 +1261,42 @@ class CodeGenerator {
1063
1261
  isFormUrlEncoded,
1064
1262
  responseClass
1065
1263
  });
1066
- apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
1264
+ classBufferByTag[tag] = (classBufferByTag[tag] || "") + methodImpl;
1265
+ const [generatedMethodString1, snippetMethod, snippetShell] = templateApiMethod({
1266
+ classMethod,
1267
+ description,
1268
+ httpMethod,
1269
+ path: pathWithBase,
1270
+ pathParams,
1271
+ bodyParams,
1272
+ responseClass,
1273
+ classGenName,
1274
+ methodParams,
1275
+ methodParamsNoTypes
1276
+ });
1277
+ apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString1;
1278
+ apiArgumentsByTag[tag] = (apiArgumentsByTag[tag] || "") + classMethod + ",";
1067
1279
  dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
1280
+ const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
1281
+ const { apiGenName } = ParserUtils.generateApiName(tag);
1282
+ const resultSnippet = templateSdkSnippet(serviceNameTitle, apiGenName, snippetMethod);
1068
1283
  snippetMap[path2][httpMethod] = {
1069
- web: `<span class='sn-blue'>import</span> axios from 'axios'<br/><span class='sn-blue'>import</span> { <span class='sn-purple'>${classGenName}</span> } <span class='sn-blue'>from</span> <span class='sn-green'>'@accelbyte/sdk'</span><br/><br/><span class='sn-blue'>const</span> axios = <span class='sn-blue'>axios</span>.create({<span class='sn-purple'>clientId</span>, <span class='sn-purple'>redirectURI</span>, <span class='sn-purple'>baseURL</span>})<br/><br/><span class='sn-blue'>new</span> ${classGenName}(<span class='sn-purple'>axios</span>, <span class='sn-purple'>namespace</span>).<span class='method-name'>${snippetString}</span>`,
1070
- shell: snippetCurl
1284
+ web: resultSnippet,
1285
+ webGit: GIT_URL + `/sdk-${serviceName}/src/generated-public/${serviceName}/${apiGenName}.ts`,
1286
+ shell: snippetShell
1071
1287
  };
1072
1288
  }
1073
1289
  }
1074
1290
  arrayDefinitions = [...new Set(arrayDefinitions)];
1075
- return { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap };
1291
+ return {
1292
+ apiArgumentsByTag,
1293
+ apiBufferByTag,
1294
+ classBufferByTag,
1295
+ dependenciesByTag,
1296
+ classImports,
1297
+ arrayDefinitions,
1298
+ snippetMap
1299
+ };
1076
1300
  };
1077
1301
  static main = async (nameArray) => {
1078
1302
  const serviceName = nameArray[0];
@@ -1080,6 +1304,7 @@ class CodeGenerator {
1080
1304
  const parser = new SwaggerParser();
1081
1305
  const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
1082
1306
  const DIST_DIR = `${generatedFolder}/${serviceName}`;
1307
+ const DIST_ENDPOINTS_DIR = path.join(DIST_DIR, "endpoints");
1083
1308
  const DIST_DEFINITION_DIR = path.join(DIST_DIR, "definitions");
1084
1309
  const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
1085
1310
  const swaggerPatchedFilePath = `${CodeGenerator.getPatchedDir()}/${swaggerFile}`;
@@ -1090,19 +1315,32 @@ class CodeGenerator {
1090
1315
  console.log("----------\nGenerating API:", { title: api.info.title, version: api.info.version });
1091
1316
  ParserUtils.mkdirIfNotExist(DIST_DIR);
1092
1317
  ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
1093
- ParserUtils.writeVersionFile(DIST_DIR, "Version.ts", serviceName, api.info, BUILD_DATE);
1094
- const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap } = await CodeGenerator.iterateApi(api);
1318
+ ParserUtils.mkdirIfNotExist(DIST_ENDPOINTS_DIR);
1319
+ ParserUtils.syncPackageVersion(api.info, CliParser.isAdmin());
1320
+ const { apiArgumentsByTag, apiBufferByTag, classBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap } = await CodeGenerator.iterateApi(api, serviceName);
1095
1321
  if (CliParser.getSnippetOutputPath()) {
1096
1322
  ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify(snippetMap, null, 2));
1097
1323
  }
1098
1324
  const targetSrcFolder = `${CliParser.getOutputPath()}/`;
1099
- for (const tag in apiBufferByTag) {
1325
+ const apiList = [];
1326
+ for (const tag in classBufferByTag) {
1100
1327
  const { className, classGenName } = ParserUtils.generateClassName(tag);
1101
- const apiBuffer = apiBufferByTag[tag];
1328
+ const classBuffer = classBufferByTag[tag];
1102
1329
  const imports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
1103
- ParserUtils.writeClassFile(DIST_DIR, classGenName, apiBuffer, imports);
1104
- indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DIR, `${classGenName}`), targetSrcFolder));
1330
+ const apiImports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
1331
+ apiImports.push(`import { ${classGenName} } from './endpoints/${classGenName}.js'`);
1332
+ ParserUtils.writeClassFile(DIST_ENDPOINTS_DIR, classGenName, classBuffer, imports);
1333
+ const apiBuffer = apiBufferByTag[tag];
1334
+ const { apiGenName } = ParserUtils.generateApiName(tag);
1335
+ ParserUtils.writeApiFile(DIST_DIR, apiGenName, apiBuffer, apiImports, apiArgumentsByTag[tag]);
1336
+ apiList.push(apiGenName);
1337
+ indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_ENDPOINTS_DIR, `${classGenName}`), targetSrcFolder));
1338
+ indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DIR, `${apiGenName}`), targetSrcFolder));
1105
1339
  }
1340
+ const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
1341
+ const apiIndexBuff = templateApiIndex(serviceName, serviceNameTitle, apiList);
1342
+ ParserUtils.writeApiMainFile(generatedFolder, serviceNameTitle, apiIndexBuff);
1343
+ indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(generatedFolder, serviceNameTitle), targetSrcFolder));
1106
1344
  const duplicates = /* @__PURE__ */ new Map();
1107
1345
  const definitions = api?.components?.schemas || api.definitions;
1108
1346
  for (const ref in definitions) {
@@ -1147,6 +1385,22 @@ class SwaggerDownloader {
1147
1385
  fs__namespace.writeFileSync(destFile, "");
1148
1386
  return destFile;
1149
1387
  };
1388
+ static postSanitizeDownloadedFile = (filePath) => {
1389
+ const searchStr = ["%5B", "%5D", "%20", "%7B", "%7D"];
1390
+ fs__namespace.readFile(filePath, "utf8", (err, data) => {
1391
+ if (err)
1392
+ throw err;
1393
+ let result = data;
1394
+ searchStr.forEach((s) => {
1395
+ result = result.replace(new RegExp(s, "g"), " ");
1396
+ });
1397
+ fs__namespace.writeFile(filePath, result, "utf8", (err2) => {
1398
+ if (err2)
1399
+ throw err2;
1400
+ console.log("File updated successfully.");
1401
+ });
1402
+ });
1403
+ };
1150
1404
  static downloadFile = (targetFileName, url) => {
1151
1405
  const destFile = SwaggerDownloader.getDestFile(targetFileName);
1152
1406
  const file = fs__namespace.createWriteStream(destFile);
@@ -1154,6 +1408,7 @@ class SwaggerDownloader {
1154
1408
  response.pipe(file);
1155
1409
  file.on("finish", () => {
1156
1410
  file.close();
1411
+ SwaggerDownloader.postSanitizeDownloadedFile(destFile);
1157
1412
  console.log(`SwaggerDownload ${url} completed`);
1158
1413
  });
1159
1414
  });