@accelbyte/codegen 2.0.0-beta.1 → 2.0.0-beta.10

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.
@@ -55,6 +55,9 @@ class CliParser {
55
55
  static getSnippetOutputPath = () => {
56
56
  return CliParser.instance().argv.snippetOutput;
57
57
  };
58
+ static skipVersionSync = () => {
59
+ return CliParser.instance().argv.skipVersionSync;
60
+ };
58
61
  }
59
62
 
60
63
  const getImportableVarMap$1 = () => ({
@@ -123,15 +126,25 @@ export function ${className}(sdk: AccelbyteSDK, args?: ApiArgs) {
123
126
  `;
124
127
  };
125
128
 
129
+ const VersionBumpType = z.enum(["CUTOFF", "RELEASE", "HOTFIX"]);
126
130
  class VersionHelpers {
127
131
  static getNextVersion = ({
128
132
  codegenVersion,
129
133
  serviceVersion,
130
134
  predefinedMajorVersion,
131
- predefinedMinorVersion,
135
+ versionBumpType,
132
136
  sdkVersion,
133
137
  nextPrereleaseId
134
138
  }) => {
139
+ if (versionBumpType !== void 0) {
140
+ const parsed = VersionBumpType.safeParse(versionBumpType);
141
+ if (!parsed.success) {
142
+ throw new Error(`Invalid process.env.VERSION_BUMP_TYPE: ${versionBumpType}`);
143
+ }
144
+ if ((parsed.data === "HOTFIX" || parsed.data === "RELEASE") && nextPrereleaseId) {
145
+ throw new Error(`process.env.PRERELEASE_ID should be empty when process.env.VERSION_BUMP_TYPE is "HOTFIX" or "PRELEASE".`);
146
+ }
147
+ }
135
148
  const codegenSemvers = semver.parse(codegenVersion);
136
149
  const serviceSemvers = semver.parse(serviceVersion);
137
150
  const sdkSemvers = semver.parse(sdkVersion);
@@ -144,20 +157,39 @@ class VersionHelpers {
144
157
  if (sdkSemvers === null) {
145
158
  throw new Error(`Invalid sdk version: ${sdkVersion}`);
146
159
  }
147
- const nextMajor = codegenSemvers.minor + predefinedMajorVersion;
148
- const nextMinor = codegenSemvers.minor + predefinedMinorVersion;
149
- const nextPatch = codegenSemvers.patch + serviceSemvers.patch;
150
- const { major: currentMajor, minor: currentMinor, patch: currentPatch } = sdkSemvers;
160
+ const { major: currentMajor, minor: currentMinor, patch: currentPatch, prerelease: currentPrerelease } = sdkSemvers;
161
+ const nextMajor = codegenSemvers.major + predefinedMajorVersion;
162
+ const shouldResetVersion = nextMajor !== currentMajor;
163
+ let nextMinor = currentMinor;
164
+ let nextPatch = currentPatch;
165
+ switch (versionBumpType) {
166
+ case VersionBumpType.Enum.CUTOFF: {
167
+ nextMinor++;
168
+ nextPatch = 0;
169
+ break;
170
+ }
171
+ case VersionBumpType.Enum.RELEASE:
172
+ break;
173
+ case VersionBumpType.Enum.HOTFIX: {
174
+ nextPatch++;
175
+ break;
176
+ }
177
+ }
178
+ if (shouldResetVersion) {
179
+ nextMinor = 0;
180
+ nextPatch = 0;
181
+ }
151
182
  let nextVersion = [
152
183
  codegenSemvers.major + predefinedMajorVersion,
153
184
  nextMinor,
154
185
  nextPatch
155
186
  ].join(".");
156
187
  if (nextPrereleaseId) {
157
- if (nextMinor !== currentMinor || nextPatch !== currentPatch || nextMajor !== currentMajor) {
188
+ if (nextMinor !== currentMinor || nextMajor !== currentMajor) {
158
189
  nextVersion += `-${nextPrereleaseId}.0`;
159
190
  } else {
160
- nextVersion += `-${sdkSemvers.prerelease.join(".")}`;
191
+ if (currentPrerelease.length)
192
+ nextVersion += `-${currentPrerelease.join(".")}`;
161
193
  nextVersion = semver.inc(nextVersion, "prerelease", void 0, nextPrereleaseId);
162
194
  }
163
195
  }
@@ -184,14 +216,14 @@ class ParserUtils {
184
216
  static replaceAll = (string, search, replace) => {
185
217
  return string.split(search).join(replace);
186
218
  };
187
- static generateClassName = (tag) => {
219
+ static generateClassName = (tag, isAdmin) => {
188
220
  const className = _.upperFirst(_.camelCase(tag));
189
- const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
221
+ const classGenName = isAdmin ? className + "Admin$" : className + "$";
190
222
  return { className, classGenName };
191
223
  };
192
- static generateApiName = (tag) => {
224
+ static generateApiName = (tag, isAdmin) => {
193
225
  const apiName = _.upperFirst(_.camelCase(tag));
194
- const apiGenName = CliParser.isAdmin() ? apiName + "AdminApi" : apiName + "Api";
226
+ const apiGenName = isAdmin ? apiName + "AdminApi" : apiName + "Api";
195
227
  return { apiName, apiGenName };
196
228
  };
197
229
  static parseQueryParamAttributeDefault = (definition) => {
@@ -291,6 +323,12 @@ class ParserUtils {
291
323
  if (definition?.schema?.type && definition.schema.type === "array") {
292
324
  return `${attrName}${required}: ${definition.schema.items.type ?? "any"}[]`;
293
325
  }
326
+ if (definition.type && definition.type === "file") {
327
+ return `${attrName}${required}: File`;
328
+ }
329
+ if (definition?.schema?.type && definition.schema.type === "file") {
330
+ return `${attrName}${required}: File`;
331
+ }
294
332
  if (definition.type && definition.type) {
295
333
  return `${attrName}${required}: ${definition.type} | null`;
296
334
  }
@@ -470,17 +508,16 @@ class ParserUtils {
470
508
  ParserUtils.mkdirIfNotExist(distDir);
471
509
  fs__default.writeFileSync(path__default.join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
472
510
  }
473
- static syncPackageVersion(apiInfo, isAdminWebSdk, prereleaseId) {
474
- if (isAdminWebSdk) {
511
+ static syncPackageVersion(apiInfo, skipVersionSync, prereleaseId) {
512
+ if (skipVersionSync)
475
513
  return;
476
- }
477
514
  const currDir = process.cwd();
478
515
  const { packageJSON, pathToPackageJSON } = ParserUtils.getPackageJSONInfo(currDir);
479
516
  const nextSemver = VersionHelpers.getNextVersion({
480
517
  codegenVersion: codegenPackageJSON.version,
481
518
  serviceVersion: apiInfo["x-version"] || apiInfo.version || UNDEFINED_SWAGGER_SEMVER,
482
- predefinedMajorVersion: packageJSON.predefinedMajorVersion,
483
- predefinedMinorVersion: packageJSON.predefinedMinorVersion,
519
+ predefinedMajorVersion: packageJSON.predefinedMajorVersion || 0,
520
+ versionBumpType: process.env.VERSION_BUMP_TYPE,
484
521
  sdkVersion: packageJSON.version,
485
522
  nextPrereleaseId: prereleaseId
486
523
  });
@@ -564,7 +601,9 @@ class ParserUtils {
564
601
  ${content}`;
565
602
  };
566
603
  static sortPathParamsByPath = (pathParams, path2) => {
567
- return pathParams.sort((a, b) => path2.indexOf(a.name) - path2.indexOf(b.name));
604
+ const params = path2.match(/{\w*}/g) || [];
605
+ const cleanParams = params.map((param) => param.replace("{", "").replace("}", ""));
606
+ return pathParams.sort((a, b) => cleanParams.indexOf(a.name) - cleanParams.indexOf(b.name));
568
607
  };
569
608
  }
570
609
  const mappedMethod = (httpMethod, isForm) => {
@@ -632,205 +671,6 @@ const isSwaggerIntegerType = (type) => {
632
671
  return type === "integer" || type === "int";
633
672
  };
634
673
 
635
- const Schema = z.object({
636
- $ref: z.string().nullish(),
637
- type: z.union([z.literal("array"), z.literal("object"), z.literal("file"), z.literal("string"), z.literal("boolean"), z.literal("integer")]).nullish(),
638
- items: z.object({
639
- $ref: z.string().nullish(),
640
- type: z.string().nullish()
641
- }).nullish(),
642
- properties: z.union([z.array(z.string()).nullish(), z.record(z.object({ type: z.string() })).nullish()]),
643
- description: z.string().nullish(),
644
- additionalProperties: z.object({
645
- type: z.string().nullish()
646
- }).nullish()
647
- });
648
- const Definition = z.object({
649
- required: z.array(z.string()).nullish(),
650
- properties: z.record(z.object({
651
- type: z.string()
652
- })).nullish()
653
- });
654
- const Definitions = z.record(Definition);
655
- const EndpointParametersType = z.enum(["apiKey", "boolean", "int", "integer", "number", "string", "array", "file"]);
656
- const EndpointParametersIn = z.enum(["body", "formData", "header", "path", "query"]);
657
- const EndpointParameters = z.object({
658
- type: EndpointParametersType.nullish(),
659
- description: z.string().nullish(),
660
- name: z.string(),
661
- in: EndpointParametersIn,
662
- required: z.boolean().nullish(),
663
- schema: Schema.nullish(),
664
- default: z.union([z.boolean(), z.string(), z.number(), z.array(z.any())]).nullish(),
665
- enum: z.array(z.union([z.boolean(), z.string(), z.number()])).nullish(),
666
- items: z.object({
667
- type: z.string(),
668
- enum: z.array(z.any()).nullish()
669
- }).nullish()
670
- });
671
- const Endpoint = z.object({
672
- description: z.string().nullish(),
673
- consumes: z.array(z.string()).nullish(),
674
- produces: z.array(z.string()).nullish(),
675
- tags: z.array(z.string()).nullish(),
676
- summary: z.string().nullish(),
677
- operationId: z.string(),
678
- deprecated: z.boolean().nullish(),
679
- responses: z.record(z.object({
680
- description: z.string().nullish(),
681
- schema: Schema.nullish(),
682
- content: z.object({
683
- "application/json": z.object({
684
- schema: Schema.nullish()
685
- })
686
- }).nullish()
687
- })),
688
- parameters: z.array(EndpointParameters).nullish(),
689
- requestBody: z.object({
690
- required: z.boolean(),
691
- content: z.object({
692
- "application/json": z.object({
693
- schema: Schema.nullish()
694
- })
695
- }).nullish()
696
- }).nullish()
697
- });
698
- const Operation = z.object({
699
- get: Endpoint.nullish(),
700
- post: Endpoint.nullish(),
701
- patch: Endpoint.nullish(),
702
- delete: Endpoint.nullish(),
703
- put: Endpoint.nullish()
704
- });
705
- const Paths = z.record(Operation);
706
- z.object({
707
- paths: Paths,
708
- definitions: Definitions,
709
- basePath: z.string(),
710
- info: z.object({
711
- description: z.string(),
712
- title: z.string(),
713
- contact: z.object({
714
- name: z.string(),
715
- url: z.string(),
716
- email: z.string()
717
- }),
718
- version: z.string()
719
- }),
720
- schemes: z.array(z.string()).nullish(),
721
- components: z.object({
722
- schemas: Definitions
723
- }).nullish()
724
- });
725
-
726
- const templateMethod = ({
727
- classMethod,
728
- description,
729
- httpMethod,
730
- path,
731
- pathParams,
732
- bodyParams,
733
- queryParams,
734
- isFormUrlEncoded,
735
- responseClass
736
- }) => {
737
- let methodParams = "";
738
- let methodParamsNoTypes = "";
739
- let newPath = `'${path}'`;
740
- let importStatements = [];
741
- const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path);
742
- for (const pathParam of sortedPathParams) {
743
- const type = ParserUtils.parseType(pathParam);
744
- if (pathParam.name !== "namespace") {
745
- methodParams += pathParam.name + `:${type}, `;
746
- methodParamsNoTypes += pathParam.name + ", ";
747
- }
748
- const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
749
- if (path.match(`{${pathParam.name}}`)) {
750
- if (type === "string") {
751
- newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
752
- } else {
753
- newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
754
- }
755
- }
756
- }
757
- let dataType = null;
758
- if (httpMethod !== "get") {
759
- dataType = ParserUtils.parseBodyParamsType(bodyParams);
760
- importStatements = ParserUtils.parseBodyParamsImports(bodyParams);
761
- methodParams += dataType ? `data: ${dataType},` : "";
762
- methodParamsNoTypes += dataType ? `data,` : "";
763
- }
764
- const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
765
- const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
766
- const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as SDKRequestConfig` : "const params = {} as SDKRequestConfig";
767
- const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
768
- const isDelete = ["delete"].includes(httpMethod);
769
- let dataPayload = "{params}";
770
- const descriptionText = description ? `
771
- /**
772
- * ${description.replace(/\n/g, "\n * ")}
773
- */` : "";
774
- let formPayloadString = "";
775
- if (isFormUrlEncoded) {
776
- formPayloadString = ``;
777
- const params = "{ ...params, headers: { ...params.headers, 'content-type': 'application/x-www-form-urlencoded' } }";
778
- dataPayload = dataType ? `CodeGenUtil.getFormUrlEncodedData(data), ${params}` : `null, ${params}`;
779
- } else if (isPostPutPatch) {
780
- dataPayload = dataType ? `data, {params}` : "null, {params}";
781
- } else if (isDelete) {
782
- dataPayload = dataType ? `{data, params}` : "{params}";
783
- }
784
- const isFileUpload = methodParams.indexOf("data: {file") > -1;
785
- const resolvedResponseClass = responseClass || "unknown";
786
- const resolvedResponseClassValidated = responseClass || "z.unknown()";
787
- methodParams = (queryParamsType ? `${methodParams} ${queryParamsType}` : methodParams).replace(/,\s*$/, "");
788
- methodParamsNoTypes = queryParamsType ? `${methodParamsNoTypes} queryParams` : methodParamsNoTypes;
789
- let methodImpl = "";
790
- const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
791
- const cachedFetchMethod = classMethod;
792
- const deprecateTag = isCacheFetch ? `/**
793
- * @deprecated Use "${classMethod}()" instead.
794
- */` : "";
795
- const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
796
- const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
797
- const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
798
- const generateMethodName = () => `${methodName}(${methodParams}): Promise<${responseSyncType}<${responseType}>>`;
799
- const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
800
- methodImpl = `${descriptionText}
801
- ${generateMethodName()} {
802
- ${queryParamsDefault}
803
- const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
804
- const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
805
-
806
- ${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')
807
-
808
- if (!this.cache) {
809
- return SdkCache.withoutCache(res)
810
- }
811
- const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
812
- return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')` : ""}
813
- }
814
- `;
815
- if (!isGuardInvoked) {
816
- methodImpl = `${descriptionText}
817
- ${deprecateTag}
818
- TODO_${classMethod}(${methodParams}): Promise<AxiosResponse<${resolvedResponseClass}>> {
819
- ${queryParamsDefault}
820
- const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
821
- return this.axiosInstance.${httpMethod}(url, ${dataPayload})
822
- }
823
- `;
824
- }
825
- const res = {
826
- methodImpl,
827
- methodParams,
828
- methodParamsNoTypes,
829
- importStatements
830
- };
831
- return res;
832
- };
833
-
834
674
  class TemplateZod {
835
675
  duplicates;
836
676
  duplicateFound = false;
@@ -915,7 +755,13 @@ ${exportedTypeString}
915
755
  const schemaAttribute = name ? `'${name}':` : "";
916
756
  const typeAttribute = name ? `'${name}'${typeRequired}:` : "";
917
757
  const type = definition?.type;
918
- if (type) {
758
+ if (definition.properties) {
759
+ const result = this.parseToZodSchema(definition, requiredAttrs);
760
+ return {
761
+ schemaString: `${schemaAttribute} ${result.schemaString}${schemaRequired}`,
762
+ typeString: `${typeAttribute} ${result.typeString}${typeNullishability}`
763
+ };
764
+ } else if (type) {
919
765
  if (type === "object" && definition.additionalProperties) {
920
766
  const zodAttribute = this.parseToZodAttribute("", definition.additionalProperties, [""]);
921
767
  return {
@@ -991,12 +837,6 @@ ${exportedTypeString}
991
837
  typeString: `${typeAttribute} ${result.typeString}`
992
838
  };
993
839
  }
994
- } else if (definition.properties) {
995
- const result = this.parseToZodSchema(definition, requiredAttrs);
996
- return {
997
- schemaString: `${schemaAttribute} ${result.schemaString}${schemaRequired}`,
998
- typeString: `${typeAttribute} ${result.typeString}${typeNullishability}`
999
- };
1000
840
  }
1001
841
  const ref = definition.$ref;
1002
842
  let model = `z.record(z.any())`;
@@ -1083,6 +923,227 @@ const extractEnumObject = (type, isRequired, enumArr) => {
1083
923
  };
1084
924
  };
1085
925
 
926
+ const templateApiIndex = (serviceName, serviceNameTitle, apiList) => {
927
+ let imports = "";
928
+ let returnStatement = "";
929
+ for (const cl of apiList) {
930
+ imports += `
931
+ import { ${cl} } from './${serviceName}/${cl}.js'`;
932
+ returnStatement += `
933
+ ${cl}, `;
934
+ }
935
+ return `/**
936
+ * AUTO GENERATED
937
+ */
938
+ ${imports}
939
+
940
+ const apis = {
941
+ ${returnStatement}
942
+ }
943
+
944
+ export const ${ParserUtils.convertDashesToTitleCase(serviceNameTitle)} = apis
945
+ `;
946
+ };
947
+
948
+ const Schema = z.object({
949
+ $ref: z.string().nullish(),
950
+ type: z.union([z.literal("array"), z.literal("object"), z.literal("file"), z.literal("string"), z.literal("boolean"), z.literal("integer")]).nullish(),
951
+ items: z.object({
952
+ $ref: z.string().nullish(),
953
+ type: z.string().nullish()
954
+ }).nullish(),
955
+ properties: z.union([z.array(z.string()).nullish(), z.record(z.object({ type: z.string() })).nullish()]),
956
+ description: z.string().nullish(),
957
+ additionalProperties: z.object({
958
+ type: z.string().nullish()
959
+ }).nullish()
960
+ });
961
+ const Definition = z.object({
962
+ required: z.array(z.string()).nullish(),
963
+ properties: z.record(z.object({
964
+ type: z.string()
965
+ })).nullish()
966
+ });
967
+ const Definitions = z.record(Definition);
968
+ const EndpointParametersType = z.enum(["apiKey", "boolean", "int", "integer", "number", "string", "array", "file"]);
969
+ const EndpointParametersIn = z.enum(["body", "formData", "header", "path", "query"]);
970
+ const EndpointParameters = z.object({
971
+ type: EndpointParametersType.nullish(),
972
+ description: z.string().nullish(),
973
+ name: z.string(),
974
+ in: EndpointParametersIn,
975
+ required: z.boolean().nullish(),
976
+ schema: Schema.nullish(),
977
+ default: z.union([z.boolean(), z.string(), z.number(), z.array(z.any())]).nullish(),
978
+ enum: z.array(z.union([z.boolean(), z.string(), z.number()])).nullish(),
979
+ items: z.object({
980
+ type: z.string(),
981
+ enum: z.array(z.any()).nullish()
982
+ }).nullish()
983
+ });
984
+ const Endpoint = z.object({
985
+ description: z.string().nullish(),
986
+ consumes: z.array(z.string()).nullish(),
987
+ produces: z.array(z.string()).nullish(),
988
+ tags: z.array(z.string()).nullish(),
989
+ summary: z.string().nullish(),
990
+ operationId: z.string(),
991
+ deprecated: z.boolean().nullish(),
992
+ responses: z.record(z.object({
993
+ description: z.string().nullish(),
994
+ schema: Schema.nullish(),
995
+ content: z.object({
996
+ "application/json": z.object({
997
+ schema: Schema.nullish()
998
+ })
999
+ }).nullish()
1000
+ })),
1001
+ parameters: z.array(EndpointParameters).nullish(),
1002
+ requestBody: z.object({
1003
+ required: z.boolean(),
1004
+ content: z.object({
1005
+ "application/json": z.object({
1006
+ schema: Schema.nullish()
1007
+ })
1008
+ }).nullish()
1009
+ }).nullish()
1010
+ });
1011
+ const Operation = z.object({
1012
+ get: Endpoint.nullish(),
1013
+ post: Endpoint.nullish(),
1014
+ patch: Endpoint.nullish(),
1015
+ delete: Endpoint.nullish(),
1016
+ put: Endpoint.nullish()
1017
+ });
1018
+ const Paths = z.record(Operation);
1019
+ z.object({
1020
+ paths: Paths,
1021
+ definitions: Definitions,
1022
+ basePath: z.string(),
1023
+ info: z.object({
1024
+ description: z.string(),
1025
+ title: z.string(),
1026
+ contact: z.object({
1027
+ name: z.string(),
1028
+ url: z.string(),
1029
+ email: z.string()
1030
+ }),
1031
+ version: z.string()
1032
+ }),
1033
+ schemes: z.array(z.string()).nullish(),
1034
+ components: z.object({
1035
+ schemas: Definitions
1036
+ }).nullish()
1037
+ });
1038
+
1039
+ const templateMethod = ({
1040
+ classMethod,
1041
+ description,
1042
+ httpMethod,
1043
+ path,
1044
+ pathParams,
1045
+ bodyParams,
1046
+ queryParams,
1047
+ isFormUrlEncoded,
1048
+ responseClass
1049
+ }) => {
1050
+ let methodParams = "";
1051
+ let methodParamsNoTypes = "";
1052
+ let newPath = `'${path}'`;
1053
+ let importStatements = [];
1054
+ const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path);
1055
+ for (const pathParam of sortedPathParams) {
1056
+ const type = ParserUtils.parseType(pathParam);
1057
+ if (pathParam.name !== "namespace") {
1058
+ methodParams += pathParam.name + `:${type}, `;
1059
+ methodParamsNoTypes += pathParam.name + ", ";
1060
+ }
1061
+ const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
1062
+ if (path.match(`{${pathParam.name}}`)) {
1063
+ if (type === "string") {
1064
+ newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
1065
+ } else {
1066
+ newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
1067
+ }
1068
+ }
1069
+ }
1070
+ let dataType = null;
1071
+ if (httpMethod !== "get") {
1072
+ dataType = ParserUtils.parseBodyParamsType(bodyParams);
1073
+ importStatements = ParserUtils.parseBodyParamsImports(bodyParams);
1074
+ methodParams += dataType ? `data: ${dataType},` : "";
1075
+ methodParamsNoTypes += dataType ? `data,` : "";
1076
+ }
1077
+ const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
1078
+ const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
1079
+ const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as SDKRequestConfig` : "const params = {} as SDKRequestConfig";
1080
+ const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
1081
+ const isDelete = ["delete"].includes(httpMethod);
1082
+ let dataPayload = "{params}";
1083
+ const descriptionText = description ? `
1084
+ /**
1085
+ * ${description.replace(/\n/g, "\n * ")}
1086
+ */` : "";
1087
+ let formPayloadString = "";
1088
+ if (isFormUrlEncoded) {
1089
+ formPayloadString = ``;
1090
+ const params = "{ ...params, headers: { ...params.headers, 'content-type': 'application/x-www-form-urlencoded' } }";
1091
+ dataPayload = dataType ? `CodeGenUtil.getFormUrlEncodedData(data), ${params}` : `null, ${params}`;
1092
+ } else if (isPostPutPatch) {
1093
+ dataPayload = dataType ? `data, {params}` : "null, {params}";
1094
+ } else if (isDelete) {
1095
+ dataPayload = dataType ? `{data, params}` : "{params}";
1096
+ }
1097
+ const isFileUpload = methodParams.indexOf("data: {file") > -1;
1098
+ const resolvedResponseClass = responseClass || "unknown";
1099
+ const resolvedResponseClassValidated = responseClass || "z.unknown()";
1100
+ methodParams = (queryParamsType ? `${methodParams} ${queryParamsType}` : methodParams).replace(/,\s*$/, "");
1101
+ methodParamsNoTypes = queryParamsType ? `${methodParamsNoTypes} queryParams` : methodParamsNoTypes;
1102
+ let methodImpl = "";
1103
+ const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
1104
+ const cachedFetchMethod = classMethod;
1105
+ const deprecateTag = isCacheFetch ? `/**
1106
+ * @deprecated Use "${classMethod}()" instead.
1107
+ */` : "";
1108
+ const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
1109
+ const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
1110
+ const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
1111
+ const generateMethodName = () => `${methodName}(${methodParams}): Promise<${responseSyncType}<${responseType}>>`;
1112
+ const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
1113
+ methodImpl = `${descriptionText}
1114
+ ${generateMethodName()} {
1115
+ ${queryParamsDefault}
1116
+ const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
1117
+ const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
1118
+
1119
+ ${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')
1120
+
1121
+ if (!this.cache) {
1122
+ return SdkCache.withoutCache(res)
1123
+ }
1124
+ const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
1125
+ return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')` : ""}
1126
+ }
1127
+ `;
1128
+ if (!isGuardInvoked) {
1129
+ methodImpl = `${descriptionText}
1130
+ ${deprecateTag}
1131
+ TODO_${classMethod}(${methodParams}): Promise<AxiosResponse<${resolvedResponseClass}>> {
1132
+ ${queryParamsDefault}
1133
+ const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
1134
+ return this.axiosInstance.${httpMethod}(url, ${dataPayload})
1135
+ }
1136
+ `;
1137
+ }
1138
+ const res = {
1139
+ methodImpl,
1140
+ methodParams,
1141
+ methodParamsNoTypes,
1142
+ importStatements
1143
+ };
1144
+ return res;
1145
+ };
1146
+
1086
1147
  const templateApiMethod = ({
1087
1148
  classMethod,
1088
1149
  description,
@@ -1144,28 +1205,6 @@ const templateApiMethod = ({
1144
1205
  return [methodImpl, snippetSdk, snippetShell];
1145
1206
  };
1146
1207
 
1147
- const templateApiIndex = (serviceName, serviceNameTitle, apiList) => {
1148
- let imports = "";
1149
- let returnStatement = "";
1150
- for (const cl of apiList) {
1151
- imports += `
1152
- import { ${cl} } from './${serviceName}/${cl}.js'`;
1153
- returnStatement += `
1154
- ${cl}, `;
1155
- }
1156
- return `/**
1157
- * AUTO GENERATED
1158
- */
1159
- ${imports}
1160
-
1161
- const apis = {
1162
- ${returnStatement}
1163
- }
1164
-
1165
- export const ${ParserUtils.convertDashesToTitleCase(serviceNameTitle)} = apis
1166
- `;
1167
- };
1168
-
1169
1208
  const templateSdkSnippet = (serviceNameTitle, apiName, methodSnippet) => {
1170
1209
  const methodArr = methodSnippet.split("//");
1171
1210
  let normMethod = normalizeMethodSnippet(methodArr[0].trim(), "data:");
@@ -1205,21 +1244,33 @@ const normalizeMethodSnippet = (methodInput, splitWord) => {
1205
1244
  };
1206
1245
 
1207
1246
  const GIT_URL = "https://github.com/AccelByte/accelbyte-web-sdk/blob/main/packages";
1208
- class CodeGenerator {
1209
- static getPatchedDir = () => path__default.join(CliParser.getSwaggersOutputPath(), "patched");
1210
- static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
1211
- static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
1212
- static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
1247
+ class SwaggerReaderHelpers {
1213
1248
  static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
1214
- static iterateApi = async (api, serviceName) => {
1215
- const apiBufferByTag = {};
1216
- const apiArgumentsByTag = {};
1217
- const classBufferByTag = {};
1218
- const dependenciesByTag = {};
1219
- const classImports = {};
1220
- let arrayDefinitions = [];
1221
- const snippetMap = {};
1222
- const mapClassMethods = {};
1249
+ static parseAllEndpoints = async ({
1250
+ api,
1251
+ sdkName,
1252
+ serviceName
1253
+ }) => {
1254
+ const result = {
1255
+ admin: {
1256
+ arrayDefinitions: [],
1257
+ snippetMap: {},
1258
+ tagToClassImportsRecord: {},
1259
+ tagToEndpointClassesRecord: {},
1260
+ tagToSdkClientRecord: {},
1261
+ tagToSdkFunctionNamesRecord: {},
1262
+ tagToSdkImportsRecord: {}
1263
+ },
1264
+ public: {
1265
+ arrayDefinitions: [],
1266
+ snippetMap: {},
1267
+ tagToClassImportsRecord: {},
1268
+ tagToEndpointClassesRecord: {},
1269
+ tagToSdkClientRecord: {},
1270
+ tagToSdkFunctionNamesRecord: {},
1271
+ tagToSdkImportsRecord: {}
1272
+ }
1273
+ };
1223
1274
  const sortedPathsByLength = new Map(Object.entries(api.paths).sort((a, b) => {
1224
1275
  if (a[0].length === b[0].length) {
1225
1276
  return a[0].localeCompare(b[0]);
@@ -1228,55 +1279,62 @@ class CodeGenerator {
1228
1279
  }
1229
1280
  }));
1230
1281
  const sortedKeys = Array.from(sortedPathsByLength.keys());
1231
- const servicePrefix = CodeGenerator.getServicePrefix(sortedKeys);
1232
- for (const [path2, operation] of sortedPathsByLength) {
1233
- const isAdminEndpoint = path2.indexOf("/admin/") > -1;
1234
- if (CliParser.isAdmin() && !isAdminEndpoint) {
1235
- continue;
1236
- } else if (!CliParser.isAdmin() && isAdminEndpoint) {
1237
- continue;
1238
- } else if (path2.indexOf("/healthz") >= 0) {
1282
+ const servicePrefix = SwaggerReaderHelpers.getServicePrefix(sortedKeys);
1283
+ const tagToClassMethodsMap = {
1284
+ admin: {},
1285
+ public: {}
1286
+ };
1287
+ for (const [path, operation] of sortedPathsByLength) {
1288
+ if (path.indexOf("/healthz") >= 0) {
1239
1289
  continue;
1240
1290
  }
1291
+ const isAdminEndpoint = path.indexOf("/admin/") > -1;
1292
+ const picked = isAdminEndpoint ? result.admin : result.public;
1293
+ const {
1294
+ arrayDefinitions,
1295
+ snippetMap,
1296
+ tagToClassImportsRecord,
1297
+ tagToEndpointClassesRecord,
1298
+ tagToSdkClientRecord,
1299
+ tagToSdkFunctionNamesRecord,
1300
+ tagToSdkImportsRecord
1301
+ } = picked;
1302
+ const tagToClassMethodsMapByType = isAdminEndpoint ? tagToClassMethodsMap.admin : tagToClassMethodsMap.public;
1241
1303
  const httpMethods = Object.keys(operation);
1242
1304
  for (const httpMethod of httpMethods) {
1243
1305
  const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
1244
- console.error(JSON.stringify({ path: path2, httpMethod }, null, 2));
1306
+ console.error(JSON.stringify({ path, httpMethod }, null, 2));
1245
1307
  throw error;
1246
1308
  });
1247
- if (!endpoint.tags) {
1248
- continue;
1249
- }
1250
- if (endpoint.deprecated) {
1309
+ if (!endpoint.tags || endpoint.deprecated)
1251
1310
  continue;
1252
- }
1253
1311
  const [tag] = endpoint.tags;
1254
- mapClassMethods[tag] = mapClassMethods[tag] ? mapClassMethods[tag] : {};
1312
+ const pathWithBase = `${api.basePath ?? ""}${path}`;
1313
+ tagToClassMethodsMapByType[tag] = tagToClassMethodsMapByType[tag] ? tagToClassMethodsMapByType[tag] : {};
1255
1314
  const isForm = endpoint.consumes && endpoint.consumes[0] === "application/x-www-form-urlencoded";
1256
1315
  const classMethod = ParserUtils.generateNaturalLangMethod({
1257
1316
  servicePrefix,
1258
- path: path2,
1317
+ path,
1259
1318
  httpMethod,
1260
1319
  isForm,
1261
- existingMethods: mapClassMethods[tag]
1320
+ existingMethods: tagToClassMethodsMapByType[tag]
1262
1321
  });
1263
- mapClassMethods[tag][classMethod] = `${path2} ${httpMethod}`;
1264
- snippetMap[path2] = snippetMap[path2] ? snippetMap[path2] : {};
1265
- let description = endpoint.description;
1266
- description = description || "";
1267
- description = description.replace(/\s+/g, " ");
1322
+ tagToClassMethodsMapByType[tag][classMethod] = `${path} ${httpMethod}`;
1323
+ if (!snippetMap[pathWithBase]) {
1324
+ snippetMap[pathWithBase] = {};
1325
+ }
1326
+ const description = endpoint.description?.replace(/\s+/g, " ") || "";
1268
1327
  const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
1269
- const { className, classGenName } = ParserUtils.generateClassName(tag);
1270
- classImports[className] = classImports[className] ? classImports[className] : {};
1328
+ const { className, classGenName } = ParserUtils.generateClassName(tag, isAdminEndpoint);
1329
+ tagToClassImportsRecord[className] = tagToClassImportsRecord[className] ? tagToClassImportsRecord[className] : {};
1271
1330
  if (responseClass) {
1272
1331
  const importTypeClass = ParserUtils.parseRefType(responseClass);
1273
- classImports[className][importTypeClass] = `import { ${importTypeClass} } from '../definitions/${importTypeClass}.js'`;
1332
+ tagToClassImportsRecord[className][importTypeClass] = `import { ${importTypeClass} } from '../definitions/${importTypeClass}.js'`;
1274
1333
  }
1275
1334
  if (responseClass && responseClass.endsWith("Array")) {
1276
1335
  arrayDefinitions.push(responseClass);
1277
1336
  }
1278
1337
  const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
1279
- const pathWithBase = `${api.basePath ?? ""}${path2}`;
1280
1338
  const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
1281
1339
  const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
1282
1340
  let bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
@@ -1300,8 +1358,8 @@ class CodeGenerator {
1300
1358
  isFormUrlEncoded,
1301
1359
  responseClass
1302
1360
  });
1303
- classBufferByTag[tag] = (classBufferByTag[tag] || "") + methodImpl;
1304
- const [generatedMethodString1, snippetMethod, snippetShell] = templateApiMethod({
1361
+ tagToEndpointClassesRecord[tag] = (tagToEndpointClassesRecord[tag] || "") + methodImpl;
1362
+ const [generatedMethodString, snippetMethod, snippetShell] = templateApiMethod({
1305
1363
  classMethod,
1306
1364
  description,
1307
1365
  httpMethod,
@@ -1313,32 +1371,37 @@ class CodeGenerator {
1313
1371
  methodParams,
1314
1372
  methodParamsNoTypes
1315
1373
  });
1316
- apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString1;
1317
- apiArgumentsByTag[tag] = (apiArgumentsByTag[tag] || "") + classMethod + ",";
1318
- dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
1374
+ tagToSdkClientRecord[tag] = (tagToSdkClientRecord[tag] || "") + generatedMethodString;
1375
+ tagToSdkFunctionNamesRecord[tag] = (tagToSdkFunctionNamesRecord[tag] || "") + classMethod + ",";
1376
+ tagToSdkImportsRecord[tag] = tagToSdkImportsRecord[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...tagToSdkImportsRecord[tag]])] : [...new Set(importStatements)];
1319
1377
  const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
1320
- const { apiGenName } = ParserUtils.generateApiName(tag);
1378
+ const { apiGenName } = ParserUtils.generateApiName(tag, isAdminEndpoint);
1321
1379
  const resultSnippet = templateSdkSnippet(serviceNameTitle, apiGenName, snippetMethod);
1322
- snippetMap[path2][httpMethod] = {
1323
- web: resultSnippet,
1324
- webGit: GIT_URL + `/sdk-${serviceName}/src/generated-public/${serviceName}/${apiGenName}.ts`,
1325
- shell: snippetShell
1326
- };
1380
+ const currentSnippetMap = {};
1381
+ snippetMap[pathWithBase][httpMethod] = currentSnippetMap;
1382
+ if (!isAdminEndpoint) {
1383
+ currentSnippetMap.web = !isAdminEndpoint ? resultSnippet : "";
1384
+ currentSnippetMap.webGit = !isAdminEndpoint ? GIT_URL + `/sdk-${sdkName}/src/generated-public/${serviceName}/${apiGenName}.ts` : "";
1385
+ }
1386
+ currentSnippetMap.shell = snippetShell;
1327
1387
  }
1328
1388
  }
1329
- arrayDefinitions = [...new Set(arrayDefinitions)];
1330
- return {
1331
- apiArgumentsByTag,
1332
- apiBufferByTag,
1333
- classBufferByTag,
1334
- dependenciesByTag,
1335
- classImports,
1336
- arrayDefinitions,
1337
- snippetMap
1338
- };
1389
+ for (const key in result) {
1390
+ result[key].arrayDefinitions = Array.from(new Set(result[key].arrayDefinitions));
1391
+ }
1392
+ return result;
1339
1393
  };
1394
+ }
1395
+
1396
+ class CodeGenerator {
1397
+ static getPatchedDir = () => path__default.join(CliParser.getSwaggersOutputPath(), "patched");
1398
+ static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
1399
+ static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
1400
+ static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
1401
+ static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
1340
1402
  static main = async (nameArray) => {
1341
1403
  const serviceName = nameArray[0];
1404
+ const sdkName = nameArray[1];
1342
1405
  const swaggerFile = nameArray[2];
1343
1406
  const parser = new SwaggerParser();
1344
1407
  const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
@@ -1353,27 +1416,39 @@ class CodeGenerator {
1353
1416
  ParserUtils.mkdirIfNotExist(DIST_DIR);
1354
1417
  ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
1355
1418
  ParserUtils.mkdirIfNotExist(DIST_ENDPOINTS_DIR);
1356
- ParserUtils.syncPackageVersion(apiInfo, CliParser.isAdmin(), process.env.PRERELEASE_ID);
1357
- const { apiArgumentsByTag, apiBufferByTag, classBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap } = await CodeGenerator.iterateApi(api, serviceName);
1419
+ ParserUtils.syncPackageVersion(apiInfo, CliParser.skipVersionSync(), process.env.PRERELEASE_ID);
1420
+ const parsedInformation = await SwaggerReaderHelpers.parseAllEndpoints({ api, sdkName, serviceName });
1421
+ const parsedInformationByType = CliParser.isAdmin() ? parsedInformation.admin : parsedInformation.public;
1422
+ const {
1423
+ arrayDefinitions,
1424
+ tagToClassImportsRecord,
1425
+ tagToEndpointClassesRecord,
1426
+ tagToSdkClientRecord,
1427
+ tagToSdkFunctionNamesRecord,
1428
+ tagToSdkImportsRecord
1429
+ } = parsedInformationByType;
1358
1430
  if (CliParser.getSnippetOutputPath()) {
1359
1431
  try {
1360
- ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify(snippetMap, null, 2));
1432
+ ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify({
1433
+ ...parsedInformation.public.snippetMap,
1434
+ ...parsedInformation.admin.snippetMap
1435
+ }, null, 2));
1361
1436
  } catch (err) {
1362
1437
  console.log("Generating snippets", err);
1363
1438
  }
1364
1439
  }
1365
1440
  const targetSrcFolder = `${CliParser.getOutputPath()}/`;
1366
1441
  const apiList = [];
1367
- for (const tag in classBufferByTag) {
1368
- const { className, classGenName } = ParserUtils.generateClassName(tag);
1369
- const classBuffer = classBufferByTag[tag];
1370
- const imports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
1371
- const apiImports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
1442
+ for (const tag in tagToEndpointClassesRecord) {
1443
+ const { className, classGenName } = ParserUtils.generateClassName(tag, CliParser.isAdmin());
1444
+ const classBuffer = tagToEndpointClassesRecord[tag];
1445
+ const imports = [.../* @__PURE__ */ new Set([...tagToSdkImportsRecord[tag], ...Object.values(tagToClassImportsRecord[className])])];
1446
+ const apiImports = [.../* @__PURE__ */ new Set([...tagToSdkImportsRecord[tag], ...Object.values(tagToClassImportsRecord[className])])];
1372
1447
  apiImports.push(`import { ${classGenName} } from './endpoints/${classGenName}.js'`);
1373
1448
  ParserUtils.writeClassFile(DIST_ENDPOINTS_DIR, classGenName, classBuffer, imports);
1374
- const apiBuffer = apiBufferByTag[tag];
1375
- const { apiGenName } = ParserUtils.generateApiName(tag);
1376
- ParserUtils.writeApiFile(DIST_DIR, apiGenName, apiBuffer, apiImports, apiArgumentsByTag[tag]);
1449
+ const apiBuffer = tagToSdkClientRecord[tag];
1450
+ const { apiGenName } = ParserUtils.generateApiName(tag, CliParser.isAdmin());
1451
+ ParserUtils.writeApiFile(DIST_DIR, apiGenName, apiBuffer, apiImports, tagToSdkFunctionNamesRecord[tag]);
1377
1452
  apiList.push(apiGenName);
1378
1453
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_ENDPOINTS_DIR, `${classGenName}`), targetSrcFolder));
1379
1454
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_DIR, `${apiGenName}`), targetSrcFolder));