@accelbyte/codegen 1.0.0-alpha.9 → 1.0.0-beta.6

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.
@@ -5,8 +5,8 @@ import fs__default from 'fs';
5
5
  import * as path from 'path';
6
6
  import path__default from 'path';
7
7
  import SwaggerParser from '@apidevtools/swagger-parser';
8
- import _ from 'lodash';
9
8
  import { applyPatch } from 'fast-json-patch';
9
+ import _ from 'lodash';
10
10
  import * as https from 'https';
11
11
 
12
12
  const SwaggersConfig = z.array(z.array(z.string()));
@@ -51,6 +51,9 @@ class CliParser {
51
51
  static isAdmin = () => {
52
52
  return CliParser.instance().argv.admin;
53
53
  };
54
+ static getSnippetOutputPath = () => {
55
+ return CliParser.instance().argv.snippetOutput;
56
+ };
54
57
  }
55
58
 
56
59
  const getImportableVarMap = () => ({
@@ -78,15 +81,15 @@ const generateImports = (body, importStatements) => {
78
81
  ${importStatements.sort().join("\n")}`;
79
82
  };
80
83
  const templateClass = (className, body, importStatements) => `/**
81
- * DON'T EDIT THIS FILE, it is AUTO GENERATED
82
- */
83
- ${generateImports(body, importStatements)}
84
+ * DON'T EDIT THIS FILE, it is AUTO GENERATED
85
+ */
86
+ ${generateImports(body, importStatements)}
84
87
 
85
- export class ${className} {
86
- // @ts-ignore
87
- constructor(private axiosInstance: AxiosInstance, private namespace: string, private cache = false) {}
88
+ export class ${className} {
89
+ // @ts-ignore
90
+ constructor(private axiosInstance: AxiosInstance, private namespace: string, private cache = false) {}
88
91
  ${body}
89
- }
92
+ }
90
93
  `;
91
94
 
92
95
  const templateJsdocFile = (apiName, body) => `
@@ -97,7 +100,24 @@ ${body}
97
100
  \`\`\`
98
101
  `.replace(/, \)/g, ")").trim();
99
102
 
103
+ const REMOVED_KEYWORDS = [
104
+ "/admin/",
105
+ "/public/",
106
+ "/v1/",
107
+ "/v2/",
108
+ "/v3/",
109
+ "/v4/",
110
+ "/v5/",
111
+ "/namespace/",
112
+ "/namespaces/",
113
+ "/{namespace}/"
114
+ ];
100
115
  class ParserUtils {
116
+ static generateClassName = (tag) => {
117
+ const className = _.upperFirst(_.camelCase(tag));
118
+ const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
119
+ return { className, classGenName };
120
+ };
101
121
  static parseQueryParamAttributeDefault = (definition) => {
102
122
  const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
103
123
  const defaultValue = definition.type === "string" ? `'${definition.default}'` : definition.default;
@@ -238,34 +258,59 @@ class ParserUtils {
238
258
  }
239
259
  return parameters.filter((parameter) => parameter.in === "path");
240
260
  }
241
- static generateClassMethod({
242
- path: path2,
243
- endpoint,
244
- httpMethod,
245
- className
246
- }) {
247
- let replacedIdsPath = path2;
248
- if (endpoint.parameters) {
249
- for (const parameter of endpoint.parameters) {
250
- if (parameter.in === "path") {
251
- replacedIdsPath = replacedIdsPath.replace("{" + parameter.name + "}", "By" + ParserUtils.toTitleCaseWord(parameter.name));
252
- replacedIdsPath = replacedIdsPath.replace("/iam", "");
253
- replacedIdsPath = replacedIdsPath.replace("/odin-config", "");
254
- }
261
+ static generateNaturalLangMethod = ({ servicePrefix, path: path2, httpMethod, isForm, existingMethods }) => {
262
+ let path_ = path2;
263
+ path_ = path_.replace(`/${servicePrefix}/`, "/");
264
+ REMOVED_KEYWORDS.forEach((prefix) => {
265
+ path_ = path_.replace(prefix, "/");
266
+ });
267
+ path_ = path_.substring(1);
268
+ const isPlural = httpMethod === "get" && !(path2.slice(-1) === "}");
269
+ if (!isPlural) {
270
+ path_ = replaceAll(path_, "ies/", "y/");
271
+ path_ = replaceAll(path_, "s/", "/");
272
+ if (path_.indexOf("status") < 0) {
273
+ path_ = path_.replace(/ies$/, "y");
274
+ path_ = path_.replace(/s$/, "");
255
275
  }
256
276
  }
257
- let classMethod = httpMethod + "/" + replacedIdsPath;
258
- classMethod = _.camelCase(classMethod);
259
- classMethod = classMethod.replace("PublicNamespacesByNamespace", "Ns");
260
- classMethod = classMethod.replace("AdminNamespacesByNamespace", "AdminNs");
261
- const searchWord = "NamespacesByNamespace";
262
- const nsExistInsideMethod = classMethod.indexOf(searchWord) > 0 && classMethod.indexOf(searchWord) + searchWord.length < classMethod.length;
263
- const excludedClasses = ["Policies"];
264
- if (nsExistInsideMethod && !excludedClasses.includes(className)) {
265
- classMethod = classMethod.replace(searchWord, "");
277
+ const arrLastWords = path_.split("}/");
278
+ let lastWords = arrLastWords[arrLastWords.length - 1];
279
+ const extractLastWord = (lastWords_) => {
280
+ let res = lastWords_;
281
+ res = res.split("/{")[0];
282
+ return res;
283
+ };
284
+ lastWords = extractLastWord(lastWords);
285
+ if (lastWords.indexOf("{") >= 0 && arrLastWords.length > 1) {
286
+ lastWords = arrLastWords[arrLastWords.length - 2];
287
+ lastWords = extractLastWord(lastWords);
266
288
  }
267
- return classMethod;
268
- }
289
+ const listBeforeLastWords = [];
290
+ let foundParam = false;
291
+ const listByParams = [];
292
+ const pathElements = path_.split("/");
293
+ pathElements.slice().reverse().forEach((item) => {
294
+ if (item.indexOf("}") >= 0) {
295
+ foundParam = true;
296
+ let param = item.replace("{", "");
297
+ param = param.replace("}", "");
298
+ param = "Byword" + _.upperFirst(param);
299
+ listByParams.push(param);
300
+ } else if (!foundParam) {
301
+ if (lastWords.indexOf(item) === -1) {
302
+ listBeforeLastWords.push(item);
303
+ }
304
+ } else {
305
+ foundParam = false;
306
+ }
307
+ });
308
+ const genPath = _.upperFirst(lastWords) + "/" + listBeforeLastWords.join("/") + listByParams.reverse().join("/");
309
+ let generatedMethod = _.camelCase(mappedMethod(httpMethod, isForm) + genPath);
310
+ generatedMethod = replaceAll(generatedMethod, "Byword", "_By");
311
+ generatedMethod = resolveConflicts(path2, generatedMethod, existingMethods);
312
+ return generatedMethod;
313
+ };
269
314
  static filterBodyParams(parameters) {
270
315
  if (Array.isArray(parameters) && parameters.length > 0) {
271
316
  return parameters.filter((parameter) => parameter.in === "body" || parameter.in === "formData");
@@ -291,6 +336,9 @@ class ParserUtils {
291
336
  const jsdocFile = templateJsdocFile(nameArray[0], apiBuffer);
292
337
  fs__default.writeFileSync(`${distDir}/docs/${nameArray[0]}.md`, jsdocFile);
293
338
  }
339
+ static writeSnippetFile(distDir, name, docBuffer) {
340
+ fs__default.writeFileSync(`${distDir}/${name}.json`, docBuffer);
341
+ }
294
342
  static writeDefinitionFile(distDir, name, buffer) {
295
343
  ParserUtils.mkdirIfNotExist(distDir);
296
344
  fs__default.writeFileSync(path__default.join(distDir, `${name}.ts`), ParserUtils.prependCopyrightHeader(buffer));
@@ -299,6 +347,16 @@ class ParserUtils {
299
347
  ParserUtils.mkdirIfNotExist(distDir);
300
348
  fs__default.writeFileSync(path__default.join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
301
349
  }
350
+ static writeVersionFile(distDir, fileName, serviceName, apiInfo, buildDate) {
351
+ const ver = apiInfo.version ? `'${apiInfo.version}'` : void 0;
352
+ fs__default.writeFileSync(`${distDir}/${fileName}`, `export default {
353
+ title: '${serviceName}',
354
+ name: '${apiInfo.title}',
355
+ version: ${ver},
356
+ buildDate: '${buildDate}'
357
+ }
358
+ `);
359
+ }
302
360
  static toCamelCase(str) {
303
361
  return str.split("/").map(function(word, index) {
304
362
  if (index === 0) {
@@ -332,6 +390,29 @@ class ParserUtils {
332
390
  }
333
391
  const swaggerContent = JSON.parse(fs__default.readFileSync(swaggerFilePath, "utf8"));
334
392
  const swaggerPatchFileContent = JSON.parse(fs__default.readFileSync(possibleSwaggerPatchFilePath, "utf8"));
393
+ for (const patchEntry of swaggerPatchFileContent) {
394
+ const segments = patchEntry.path.split("/").filter(Boolean);
395
+ let currentNode = swaggerContent;
396
+ let aggregatedPath = "";
397
+ for (let i = 0; i < segments.length; i++) {
398
+ const segment = segments[i];
399
+ aggregatedPath += `/${segment}`;
400
+ const effectiveSegment = segment.replace(/(~1)/g, "/").replace(/(~0)/g, "~");
401
+ if (!currentNode[effectiveSegment]) {
402
+ if (i + 1 === segments.length && patchEntry.op === "add") ; else {
403
+ throw new Error([
404
+ `JSON patch error: operation "${patchEntry.op}" on path "${aggregatedPath}" fails because the path doesn't exist in ${swaggerFilePath}. This may be caused by:
405
+ `,
406
+ "1. The related service has patched the service, so patch is no longer needed.",
407
+ "2. There is a breaking change on the service that causes the path to change.\n",
408
+ `In any case, revisit this file: "${possibleSwaggerPatchFilePath}", then try again.
409
+ `
410
+ ].join("\n"));
411
+ }
412
+ }
413
+ currentNode = currentNode[effectiveSegment];
414
+ }
415
+ }
335
416
  const { newDocument } = applyPatch(swaggerContent, swaggerPatchFileContent);
336
417
  fs__default.writeFileSync(swaggerPatchedFilePath, JSON.stringify(newDocument, null, 2));
337
418
  }
@@ -349,6 +430,70 @@ class ParserUtils {
349
430
  ${content}`;
350
431
  };
351
432
  }
433
+ const replaceAll = (string, search, replace) => {
434
+ return string.split(search).join(replace);
435
+ };
436
+ const mappedMethod = (httpMethod, isForm) => {
437
+ if (httpMethod === "get") {
438
+ return "fetch";
439
+ } else if (httpMethod === "post" && isForm) {
440
+ return "post";
441
+ } else if (httpMethod === "post") {
442
+ return "create";
443
+ } else if (httpMethod === "put") {
444
+ return "update";
445
+ } else if (httpMethod === "patch") {
446
+ return "patch";
447
+ } else if (httpMethod === "delete") {
448
+ return "delete";
449
+ }
450
+ };
451
+ const resolveConflicts = (path2, generatedMethod, existingMethods) => {
452
+ try {
453
+ testConflict(path2, generatedMethod, existingMethods);
454
+ } catch (e) {
455
+ if (path2.indexOf("/namespaces/") >= 0) {
456
+ generatedMethod += "_ByNS";
457
+ }
458
+ }
459
+ try {
460
+ testConflict(path2, generatedMethod, existingMethods);
461
+ } catch (e) {
462
+ if (path2.indexOf("/v4/") >= 0) {
463
+ generatedMethod += "_v4";
464
+ }
465
+ }
466
+ try {
467
+ testConflict(path2, generatedMethod, existingMethods);
468
+ } catch (e) {
469
+ if (path2.indexOf("/v3/") >= 0) {
470
+ generatedMethod += "_v3";
471
+ }
472
+ }
473
+ try {
474
+ testConflict(path2, generatedMethod, existingMethods);
475
+ } catch (e) {
476
+ if (path2.indexOf("/v2/") >= 0) {
477
+ generatedMethod += "_v2";
478
+ }
479
+ }
480
+ try {
481
+ testConflict(path2, generatedMethod, existingMethods);
482
+ } catch (e) {
483
+ if (path2.indexOf("/admin/") >= 0) {
484
+ generatedMethod += "_admin";
485
+ }
486
+ }
487
+ testConflict(path2, generatedMethod, existingMethods);
488
+ return generatedMethod;
489
+ };
490
+ const testConflict = (path2, generatedMethod, existingMethods) => {
491
+ if (existingMethods[generatedMethod]) {
492
+ const conflictingMethod = { path: path2, generatedMethod };
493
+ throw Error(`Duplicate method conflict in ${JSON.stringify(conflictingMethod)},
494
+ existingMethods: ${JSON.stringify(existingMethods, null, 2)}`);
495
+ }
496
+ };
352
497
 
353
498
  const Schema = z.object({
354
499
  $ref: z.string().nullish(),
@@ -440,50 +585,6 @@ z.object({
440
585
  }).nullish()
441
586
  });
442
587
 
443
- const templateJsdocMethod = ({
444
- classMethod,
445
- httpMethod,
446
- path,
447
- pathParams,
448
- bodyParams,
449
- queryParams
450
- }) => {
451
- let jsdoc = "";
452
- let methodSignature = "";
453
- let newPath = path;
454
- for (const p of pathParams) {
455
- methodSignature += p.name + ", ";
456
- newPath = newPath.replace("{" + p.name + "}", `' + ${p.name} + '`);
457
- jsdoc += `
458
- * @pathParam '${p.name}${p.required ? "" : "?"}' - ${p.description}`;
459
- }
460
- let payloads = "";
461
- for (const p of bodyParams) {
462
- methodSignature += p.name + ", ";
463
- payloads += p.name;
464
- jsdoc += `
465
- * @payload '${p.name}${p.required ? "" : "?"}' - ${p.description} ${p?.schema?.properties ? "=> " + JSON.stringify(p.schema.properties) : ""}`;
466
- }
467
- for (const p of queryParams) {
468
- const optionalMark = p.required ? "" : "?";
469
- methodSignature += p.name + optionalMark + ", ";
470
- jsdoc += `
471
- * @queryParam '${p.name}${p.required ? "" : "?"}' - ${p.description}`;
472
- }
473
- let queryString = "";
474
- for (const p of queryParams) {
475
- queryString += `${p.name}=__&`;
476
- }
477
- queryString = queryString.length > 0 ? "?" + queryString : "";
478
- return `
479
- /**
480
- * ${httpMethod.toUpperCase()} '${newPath}${queryString}' ${payloads ? "payload: '" + payloads + "'" : ""}
481
- * ${jsdoc}
482
- */
483
- ${classMethod}(${methodSignature}): Promise
484
- `;
485
- };
486
-
487
588
  const templateMethod = ({
488
589
  classMethod,
489
590
  description,
@@ -498,6 +599,9 @@ const templateMethod = ({
498
599
  let methodSignature = "";
499
600
  let newPath = `'${path}'`;
500
601
  let dependencies = [];
602
+ let snippetString = "";
603
+ let snippetMethodSignature = "";
604
+ let snippetCurl = "";
501
605
  for (const pathParam of pathParams) {
502
606
  const type = ParserUtils.parseType(pathParam);
503
607
  if (pathParam.name !== "namespace") {
@@ -512,11 +616,20 @@ const templateMethod = ({
512
616
  }
513
617
  }
514
618
  }
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'`;
515
620
  let dataType = null;
516
621
  if (httpMethod !== "get") {
517
622
  dataType = ParserUtils.parseBodyParamsType(bodyParams);
518
623
  dependencies = ParserUtils.parseBodyParamsImports(bodyParams);
519
624
  methodSignature += dataType ? `data: ${dataType},` : "";
625
+ const snippetParams = bodyParams?.map((ob) => {
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}}`;
520
633
  }
521
634
  const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
522
635
  const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
@@ -552,20 +665,23 @@ const templateMethod = ({
552
665
  const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
553
666
  const methodGenerics = resolvedResponseClass !== "unknown" ? `<T = ${resolvedResponseClass}>` : "";
554
667
  const responseType = resolvedResponseClass !== "unknown" ? `T` : "unknown";
668
+ const generateMethodName = () => `${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>>`;
669
+ const generateSnippetMethodName = () => `${methodName}(${snippetMethodSignature})`;
670
+ snippetString += `${generateSnippetMethodName()}`;
555
671
  const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
556
672
  methodImpl = `${descriptionText}
557
- ${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>> {
673
+ ${generateMethodName()} {
558
674
  ${queryParamsDefault}
559
675
  const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
560
676
  const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
561
677
 
562
- ${httpMethod === "get" ? `const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
678
+ ${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
563
679
 
564
680
  if (!this.cache) {
565
681
  return SdkCache.withoutCache(res)
566
682
  }
567
683
  const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
568
- return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? `return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})` : ""}
684
+ return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})` : ""}
569
685
  }
570
686
  `;
571
687
  if (!isGuardInvoked) {
@@ -578,7 +694,7 @@ ${httpMethod === "get" ? `const res = () => Validate.responseType(() => resultPr
578
694
  }
579
695
  `;
580
696
  }
581
- return [methodImpl, dependencies];
697
+ return [methodImpl, dependencies, snippetString, snippetCurl];
582
698
  };
583
699
 
584
700
  class TemplateZod {
@@ -594,32 +710,32 @@ class TemplateZod {
594
710
  }
595
711
  let imports = "";
596
712
  for (const cl of Array.from(this.importClasses).sort()) {
597
- imports += ` import { ${cl} } from './${cl}'
713
+ imports += `import { ${cl} } from './${cl}'
598
714
  `;
599
715
  }
600
716
  let exportedVariableString;
601
717
  let exportedTypeString;
602
718
  if (containsRecursiveType) {
603
719
  exportedVariableString = `
604
- export const ${fileName}: z.ZodType<${fileName}> = z.lazy(() =>
720
+ export const ${fileName}: z.ZodType<${fileName}> = z.lazy(() =>
605
721
  ${content.schemaString}
606
722
  )
607
723
  `;
608
724
  exportedTypeString = `
609
- export type ${fileName} = {
725
+ export interface ${fileName} {
610
726
  ${content.typeString}
611
- }
612
- `;
727
+ }
728
+ `;
613
729
  } else {
614
730
  exportedVariableString = `export const ${fileName} = ${content.schemaString}`;
615
- exportedTypeString = `export type ${fileName} = z.TypeOf<typeof ${fileName}>`;
731
+ exportedTypeString = `export interface ${fileName} extends z.TypeOf<typeof ${fileName}> {}`;
616
732
  }
617
733
  const template = `import { z } from 'zod'
618
- ${imports}
734
+ ${imports}
619
735
 
620
- ${exportedVariableString}
736
+ ${exportedVariableString}
621
737
 
622
- ${exportedTypeString}
738
+ ${exportedTypeString}
623
739
  `;
624
740
  return { buffer: template, duplicateFound: this.duplicateFound };
625
741
  };
@@ -776,11 +892,11 @@ class TemplateZodArray {
776
892
  render = (name) => {
777
893
  const cls = name.replace("Array", "");
778
894
  const template = `import { z } from 'zod'
779
- import { ${cls} } from './${cls}'
895
+ import { ${cls} } from './${cls}'
780
896
 
781
- export const ${name} = z.array(${cls})
897
+ export const ${name} = z.array(${cls})
782
898
 
783
- export type ${name} = z.TypeOf<typeof ${name}>
899
+ export interface ${name} extends z.TypeOf<typeof ${name}> {}
784
900
  `;
785
901
  return template;
786
902
  };
@@ -815,24 +931,37 @@ const extractEnumObject = (type, isRequired, enumArr) => {
815
931
  };
816
932
  };
817
933
 
934
+ const BUILD_DATE = new Date().toISOString();
818
935
  class CodeGenerator {
819
936
  static getPatchedDir = () => path__default.join(CliParser.getSwaggersOutputPath(), "patched");
820
937
  static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
821
938
  static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
939
+ static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
940
+ static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
822
941
  static iterateApi = async (api) => {
823
942
  const apiBufferByTag = {};
824
- const jsDocApiBufferByTag = {};
825
943
  const dependenciesByTag = {};
826
944
  const classImports = {};
827
945
  let arrayDefinitions = [];
828
- for (const path2 in api.paths) {
946
+ const snippetMap = {};
947
+ const mapClassMethods = {};
948
+ const sortedPathsByLength = new Map(Object.entries(api.paths).sort((a, b) => {
949
+ if (a[0].length === b[0].length) {
950
+ return a[0].localeCompare(b[0]);
951
+ } else {
952
+ return a[0].length - b[0].length;
953
+ }
954
+ }));
955
+ const sortedKeys = Array.from(sortedPathsByLength.keys());
956
+ const servicePrefix = CodeGenerator.getServicePrefix(sortedKeys);
957
+ console.log("ServicePrefix", servicePrefix, ", Paths:", sortedKeys);
958
+ for (const [path2, operation] of sortedPathsByLength) {
829
959
  const isAdminEndpoint = path2.indexOf("/admin/") > -1;
830
960
  if (CliParser.isAdmin() && !isAdminEndpoint) {
831
961
  continue;
832
962
  } else if (!CliParser.isAdmin() && isAdminEndpoint) {
833
963
  continue;
834
964
  }
835
- const operation = api.paths[path2];
836
965
  const httpMethods = Object.keys(operation);
837
966
  for (const httpMethod of httpMethods) {
838
967
  const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
@@ -842,59 +971,67 @@ class CodeGenerator {
842
971
  if (!endpoint.tags) {
843
972
  continue;
844
973
  }
974
+ if (endpoint.deprecated) {
975
+ continue;
976
+ }
845
977
  const [tag] = endpoint.tags;
978
+ mapClassMethods[tag] = mapClassMethods[tag] ? mapClassMethods[tag] : {};
979
+ const isForm = endpoint.consumes && endpoint.consumes[0] === "application/x-www-form-urlencoded";
980
+ const classMethod = ParserUtils.generateNaturalLangMethod({
981
+ servicePrefix,
982
+ path: path2,
983
+ httpMethod,
984
+ isForm,
985
+ existingMethods: mapClassMethods[tag]
986
+ });
987
+ mapClassMethods[tag][classMethod] = `${path2} ${httpMethod}`;
988
+ snippetMap[path2] = snippetMap[path2] ? snippetMap[path2] : {};
846
989
  const description = endpoint.description;
847
- const isDeprecated = endpoint.deprecated;
848
990
  const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
849
- const className = _.upperFirst(_.camelCase(tag));
991
+ const { className, classGenName } = ParserUtils.generateClassName(tag);
850
992
  classImports[className] = classImports[className] ? classImports[className] : {};
851
- if (!isDeprecated) {
852
- if (responseClass) {
853
- const importTypeClass = ParserUtils.parseRefType(responseClass);
854
- classImports[className][importTypeClass] = `import { ${importTypeClass} } from './definitions/${importTypeClass}'`;
855
- }
856
- if (responseClass && responseClass.endsWith("Array")) {
857
- arrayDefinitions.push(responseClass);
858
- }
859
- const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
860
- const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
861
- const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
862
- let bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
863
- const classMethod = ParserUtils.generateClassMethod({
864
- path: path2,
865
- endpoint,
866
- httpMethod,
867
- className
868
- });
869
- if (endpoint.requestBody) {
870
- bodyParams = [
871
- {
872
- name: "body",
873
- in: "body",
874
- schema: endpoint.requestBody.content["application/json"].schema
875
- }
876
- ];
877
- }
878
- const pathWithBase = `${api.basePath ?? ""}${path2}`;
879
- const [generatedMethodString, importStatements] = templateMethod({
880
- classMethod,
881
- description,
882
- httpMethod,
883
- path: pathWithBase,
884
- pathParams,
885
- bodyParams,
886
- queryParams,
887
- isFormUrlEncoded,
888
- responseClass
889
- });
890
- apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
891
- jsDocApiBufferByTag[tag] = (jsDocApiBufferByTag[tag] || "") + templateJsdocMethod({ classMethod, httpMethod, path: path2, pathParams, bodyParams, queryParams });
892
- dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
993
+ if (responseClass) {
994
+ const importTypeClass = ParserUtils.parseRefType(responseClass);
995
+ classImports[className][importTypeClass] = `import { ${importTypeClass} } from './definitions/${importTypeClass}'`;
996
+ }
997
+ if (responseClass && responseClass.endsWith("Array")) {
998
+ arrayDefinitions.push(responseClass);
893
999
  }
1000
+ const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
1001
+ const pathWithBase = `${api.basePath ?? ""}${path2}`;
1002
+ const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
1003
+ const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
1004
+ let bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
1005
+ if (endpoint.requestBody) {
1006
+ bodyParams = [
1007
+ {
1008
+ name: "body",
1009
+ in: "body",
1010
+ schema: endpoint.requestBody.content["application/json"].schema
1011
+ }
1012
+ ];
1013
+ }
1014
+ const [generatedMethodString, importStatements, snippetString, snippetCurl] = templateMethod({
1015
+ classMethod,
1016
+ description,
1017
+ httpMethod,
1018
+ path: pathWithBase,
1019
+ pathParams,
1020
+ bodyParams,
1021
+ queryParams,
1022
+ isFormUrlEncoded,
1023
+ responseClass
1024
+ });
1025
+ apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
1026
+ dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
1027
+ snippetMap[path2][httpMethod] = {
1028
+ 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>`,
1029
+ shell: snippetCurl
1030
+ };
894
1031
  }
895
1032
  }
896
1033
  arrayDefinitions = [...new Set(arrayDefinitions)];
897
- return { apiBufferByTag, jsDocApiBufferByTag, dependenciesByTag, classImports, arrayDefinitions };
1034
+ return { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap };
898
1035
  };
899
1036
  static main = async (nameArray) => {
900
1037
  const serviceName = nameArray[0];
@@ -902,7 +1039,6 @@ class CodeGenerator {
902
1039
  const parser = new SwaggerParser();
903
1040
  const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
904
1041
  const DIST_DIR = `${generatedFolder}/${serviceName}`;
905
- const DIST_DOCS_DIR = path__default.join(DIST_DIR, "docs");
906
1042
  const DIST_DEFINITION_DIR = path__default.join(DIST_DIR, "definitions");
907
1043
  const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
908
1044
  const swaggerPatchedFilePath = `${CodeGenerator.getPatchedDir()}/${swaggerFile}`;
@@ -910,17 +1046,19 @@ class CodeGenerator {
910
1046
  ParserUtils.applyPatchIfExists(swaggerFilePath, swaggerPatchFilePath, swaggerPatchedFilePath, CodeGenerator.getPatchedDir());
911
1047
  const api = await parser.parse(swaggerPatchedFilePath);
912
1048
  const indexImportsSet = /* @__PURE__ */ new Set();
913
- console.log("\n----------\n API name: %s, Version: %s schemes %s", api, api.info.title, api.info.version, api.schemes);
1049
+ console.log("----------\nGenerating API:", { title: api.info.title, version: api.info.version });
914
1050
  ParserUtils.mkdirIfNotExist(DIST_DIR);
915
- ParserUtils.mkdirIfNotExist(DIST_DOCS_DIR);
916
1051
  ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
917
- const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions } = await CodeGenerator.iterateApi(api);
1052
+ ParserUtils.writeVersionFile(DIST_DIR, "Version.ts", serviceName, api.info, BUILD_DATE);
1053
+ const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap } = await CodeGenerator.iterateApi(api);
1054
+ if (CliParser.getSnippetOutputPath()) {
1055
+ ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify(snippetMap, null, 2));
1056
+ }
918
1057
  const targetSrcFolder = `${CliParser.getOutputPath()}/`;
919
1058
  for (const tag in apiBufferByTag) {
920
- const className = _.upperFirst(_.camelCase(tag));
1059
+ const { className, classGenName } = ParserUtils.generateClassName(tag);
921
1060
  const apiBuffer = apiBufferByTag[tag];
922
1061
  const imports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
923
- const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
924
1062
  ParserUtils.writeClassFile(DIST_DIR, classGenName, apiBuffer, imports);
925
1063
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_DIR, `${classGenName}`), targetSrcFolder));
926
1064
  }
@@ -952,7 +1090,7 @@ class CodeGenerator {
952
1090
  ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, arrayClass, buffer);
953
1091
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_DEFINITION_DIR, arrayClass), targetSrcFolder));
954
1092
  }
955
- console.log("\n----------\nCOMPLETED.\n----------\n\n");
1093
+ console.log("\nCOMPLETED\n----------\n\n");
956
1094
  return indexImportsSet;
957
1095
  };
958
1096
  }
@@ -979,7 +1117,7 @@ class SwaggerDownloader {
979
1117
  });
980
1118
  });
981
1119
  request.on("error", (err) => {
982
- console.log(`SwaggerDownloader dl failed for "${targetFileName}" and "${url}"`, err);
1120
+ console.log(`SwaggerDownloader failed for "${targetFileName}" and "${url}"`, err);
983
1121
  });
984
1122
  };
985
1123
  static main = () => {