@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.
@@ -7,8 +7,8 @@ var zod = require('zod');
7
7
  var fs = require('fs');
8
8
  var path = require('path');
9
9
  var SwaggerParser = require('@apidevtools/swagger-parser');
10
- var _ = require('lodash');
11
10
  var fastJsonPatch = require('fast-json-patch');
11
+ var _ = require('lodash');
12
12
  var https = require('https');
13
13
 
14
14
  function _interopNamespaceDefault(e) {
@@ -74,6 +74,9 @@ class CliParser {
74
74
  static isAdmin = () => {
75
75
  return CliParser.instance().argv.admin;
76
76
  };
77
+ static getSnippetOutputPath = () => {
78
+ return CliParser.instance().argv.snippetOutput;
79
+ };
77
80
  }
78
81
 
79
82
  const getImportableVarMap = () => ({
@@ -101,15 +104,15 @@ const generateImports = (body, importStatements) => {
101
104
  ${importStatements.sort().join("\n")}`;
102
105
  };
103
106
  const templateClass = (className, body, importStatements) => `/**
104
- * DON'T EDIT THIS FILE, it is AUTO GENERATED
105
- */
106
- ${generateImports(body, importStatements)}
107
+ * DON'T EDIT THIS FILE, it is AUTO GENERATED
108
+ */
109
+ ${generateImports(body, importStatements)}
107
110
 
108
- export class ${className} {
109
- // @ts-ignore
110
- constructor(private axiosInstance: AxiosInstance, private namespace: string, private cache = false) {}
111
+ export class ${className} {
112
+ // @ts-ignore
113
+ constructor(private axiosInstance: AxiosInstance, private namespace: string, private cache = false) {}
111
114
  ${body}
112
- }
115
+ }
113
116
  `;
114
117
 
115
118
  const templateJsdocFile = (apiName, body) => `
@@ -120,7 +123,24 @@ ${body}
120
123
  \`\`\`
121
124
  `.replace(/, \)/g, ")").trim();
122
125
 
126
+ const REMOVED_KEYWORDS = [
127
+ "/admin/",
128
+ "/public/",
129
+ "/v1/",
130
+ "/v2/",
131
+ "/v3/",
132
+ "/v4/",
133
+ "/v5/",
134
+ "/namespace/",
135
+ "/namespaces/",
136
+ "/{namespace}/"
137
+ ];
123
138
  class ParserUtils {
139
+ static generateClassName = (tag) => {
140
+ const className = _.upperFirst(_.camelCase(tag));
141
+ const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
142
+ return { className, classGenName };
143
+ };
124
144
  static parseQueryParamAttributeDefault = (definition) => {
125
145
  const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
126
146
  const defaultValue = definition.type === "string" ? `'${definition.default}'` : definition.default;
@@ -261,34 +281,59 @@ class ParserUtils {
261
281
  }
262
282
  return parameters.filter((parameter) => parameter.in === "path");
263
283
  }
264
- static generateClassMethod({
265
- path: path2,
266
- endpoint,
267
- httpMethod,
268
- className
269
- }) {
270
- let replacedIdsPath = path2;
271
- if (endpoint.parameters) {
272
- for (const parameter of endpoint.parameters) {
273
- if (parameter.in === "path") {
274
- replacedIdsPath = replacedIdsPath.replace("{" + parameter.name + "}", "By" + ParserUtils.toTitleCaseWord(parameter.name));
275
- replacedIdsPath = replacedIdsPath.replace("/iam", "");
276
- replacedIdsPath = replacedIdsPath.replace("/odin-config", "");
277
- }
284
+ static generateNaturalLangMethod = ({ servicePrefix, path: path2, httpMethod, isForm, existingMethods }) => {
285
+ let path_ = path2;
286
+ path_ = path_.replace(`/${servicePrefix}/`, "/");
287
+ REMOVED_KEYWORDS.forEach((prefix) => {
288
+ path_ = path_.replace(prefix, "/");
289
+ });
290
+ path_ = path_.substring(1);
291
+ const isPlural = httpMethod === "get" && !(path2.slice(-1) === "}");
292
+ if (!isPlural) {
293
+ path_ = replaceAll(path_, "ies/", "y/");
294
+ path_ = replaceAll(path_, "s/", "/");
295
+ if (path_.indexOf("status") < 0) {
296
+ path_ = path_.replace(/ies$/, "y");
297
+ path_ = path_.replace(/s$/, "");
278
298
  }
279
299
  }
280
- let classMethod = httpMethod + "/" + replacedIdsPath;
281
- classMethod = _.camelCase(classMethod);
282
- classMethod = classMethod.replace("PublicNamespacesByNamespace", "Ns");
283
- classMethod = classMethod.replace("AdminNamespacesByNamespace", "AdminNs");
284
- const searchWord = "NamespacesByNamespace";
285
- const nsExistInsideMethod = classMethod.indexOf(searchWord) > 0 && classMethod.indexOf(searchWord) + searchWord.length < classMethod.length;
286
- const excludedClasses = ["Policies"];
287
- if (nsExistInsideMethod && !excludedClasses.includes(className)) {
288
- classMethod = classMethod.replace(searchWord, "");
300
+ const arrLastWords = path_.split("}/");
301
+ let lastWords = arrLastWords[arrLastWords.length - 1];
302
+ const extractLastWord = (lastWords_) => {
303
+ let res = lastWords_;
304
+ res = res.split("/{")[0];
305
+ return res;
306
+ };
307
+ lastWords = extractLastWord(lastWords);
308
+ if (lastWords.indexOf("{") >= 0 && arrLastWords.length > 1) {
309
+ lastWords = arrLastWords[arrLastWords.length - 2];
310
+ lastWords = extractLastWord(lastWords);
289
311
  }
290
- return classMethod;
291
- }
312
+ const listBeforeLastWords = [];
313
+ let foundParam = false;
314
+ const listByParams = [];
315
+ const pathElements = path_.split("/");
316
+ pathElements.slice().reverse().forEach((item) => {
317
+ if (item.indexOf("}") >= 0) {
318
+ foundParam = true;
319
+ let param = item.replace("{", "");
320
+ param = param.replace("}", "");
321
+ param = "Byword" + _.upperFirst(param);
322
+ listByParams.push(param);
323
+ } else if (!foundParam) {
324
+ if (lastWords.indexOf(item) === -1) {
325
+ listBeforeLastWords.push(item);
326
+ }
327
+ } else {
328
+ foundParam = false;
329
+ }
330
+ });
331
+ const genPath = _.upperFirst(lastWords) + "/" + listBeforeLastWords.join("/") + listByParams.reverse().join("/");
332
+ let generatedMethod = _.camelCase(mappedMethod(httpMethod, isForm) + genPath);
333
+ generatedMethod = replaceAll(generatedMethod, "Byword", "_By");
334
+ generatedMethod = resolveConflicts(path2, generatedMethod, existingMethods);
335
+ return generatedMethod;
336
+ };
292
337
  static filterBodyParams(parameters) {
293
338
  if (Array.isArray(parameters) && parameters.length > 0) {
294
339
  return parameters.filter((parameter) => parameter.in === "body" || parameter.in === "formData");
@@ -314,6 +359,9 @@ class ParserUtils {
314
359
  const jsdocFile = templateJsdocFile(nameArray[0], apiBuffer);
315
360
  fs.writeFileSync(`${distDir}/docs/${nameArray[0]}.md`, jsdocFile);
316
361
  }
362
+ static writeSnippetFile(distDir, name, docBuffer) {
363
+ fs.writeFileSync(`${distDir}/${name}.json`, docBuffer);
364
+ }
317
365
  static writeDefinitionFile(distDir, name, buffer) {
318
366
  ParserUtils.mkdirIfNotExist(distDir);
319
367
  fs.writeFileSync(path.join(distDir, `${name}.ts`), ParserUtils.prependCopyrightHeader(buffer));
@@ -322,6 +370,16 @@ class ParserUtils {
322
370
  ParserUtils.mkdirIfNotExist(distDir);
323
371
  fs.writeFileSync(path.join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
324
372
  }
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
+ `);
382
+ }
325
383
  static toCamelCase(str) {
326
384
  return str.split("/").map(function(word, index) {
327
385
  if (index === 0) {
@@ -355,6 +413,29 @@ class ParserUtils {
355
413
  }
356
414
  const swaggerContent = JSON.parse(fs.readFileSync(swaggerFilePath, "utf8"));
357
415
  const swaggerPatchFileContent = JSON.parse(fs.readFileSync(possibleSwaggerPatchFilePath, "utf8"));
416
+ for (const patchEntry of swaggerPatchFileContent) {
417
+ const segments = patchEntry.path.split("/").filter(Boolean);
418
+ let currentNode = swaggerContent;
419
+ let aggregatedPath = "";
420
+ for (let i = 0; i < segments.length; i++) {
421
+ const segment = segments[i];
422
+ aggregatedPath += `/${segment}`;
423
+ const effectiveSegment = segment.replace(/(~1)/g, "/").replace(/(~0)/g, "~");
424
+ if (!currentNode[effectiveSegment]) {
425
+ if (i + 1 === segments.length && patchEntry.op === "add") ; else {
426
+ throw new Error([
427
+ `JSON patch error: operation "${patchEntry.op}" on path "${aggregatedPath}" fails because the path doesn't exist in ${swaggerFilePath}. This may be caused by:
428
+ `,
429
+ "1. The related service has patched the service, so patch is no longer needed.",
430
+ "2. There is a breaking change on the service that causes the path to change.\n",
431
+ `In any case, revisit this file: "${possibleSwaggerPatchFilePath}", then try again.
432
+ `
433
+ ].join("\n"));
434
+ }
435
+ }
436
+ currentNode = currentNode[effectiveSegment];
437
+ }
438
+ }
358
439
  const { newDocument } = fastJsonPatch.applyPatch(swaggerContent, swaggerPatchFileContent);
359
440
  fs.writeFileSync(swaggerPatchedFilePath, JSON.stringify(newDocument, null, 2));
360
441
  }
@@ -372,6 +453,70 @@ class ParserUtils {
372
453
  ${content}`;
373
454
  };
374
455
  }
456
+ const replaceAll = (string, search, replace) => {
457
+ return string.split(search).join(replace);
458
+ };
459
+ const mappedMethod = (httpMethod, isForm) => {
460
+ if (httpMethod === "get") {
461
+ return "fetch";
462
+ } else if (httpMethod === "post" && isForm) {
463
+ return "post";
464
+ } else if (httpMethod === "post") {
465
+ return "create";
466
+ } else if (httpMethod === "put") {
467
+ return "update";
468
+ } else if (httpMethod === "patch") {
469
+ return "patch";
470
+ } else if (httpMethod === "delete") {
471
+ return "delete";
472
+ }
473
+ };
474
+ const resolveConflicts = (path2, generatedMethod, existingMethods) => {
475
+ try {
476
+ testConflict(path2, generatedMethod, existingMethods);
477
+ } catch (e) {
478
+ if (path2.indexOf("/namespaces/") >= 0) {
479
+ generatedMethod += "_ByNS";
480
+ }
481
+ }
482
+ try {
483
+ testConflict(path2, generatedMethod, existingMethods);
484
+ } catch (e) {
485
+ if (path2.indexOf("/v4/") >= 0) {
486
+ generatedMethod += "_v4";
487
+ }
488
+ }
489
+ try {
490
+ testConflict(path2, generatedMethod, existingMethods);
491
+ } catch (e) {
492
+ if (path2.indexOf("/v3/") >= 0) {
493
+ generatedMethod += "_v3";
494
+ }
495
+ }
496
+ try {
497
+ testConflict(path2, generatedMethod, existingMethods);
498
+ } catch (e) {
499
+ if (path2.indexOf("/v2/") >= 0) {
500
+ generatedMethod += "_v2";
501
+ }
502
+ }
503
+ try {
504
+ testConflict(path2, generatedMethod, existingMethods);
505
+ } catch (e) {
506
+ if (path2.indexOf("/admin/") >= 0) {
507
+ generatedMethod += "_admin";
508
+ }
509
+ }
510
+ testConflict(path2, generatedMethod, existingMethods);
511
+ return generatedMethod;
512
+ };
513
+ const testConflict = (path2, generatedMethod, existingMethods) => {
514
+ if (existingMethods[generatedMethod]) {
515
+ const conflictingMethod = { path: path2, generatedMethod };
516
+ throw Error(`Duplicate method conflict in ${JSON.stringify(conflictingMethod)},
517
+ existingMethods: ${JSON.stringify(existingMethods, null, 2)}`);
518
+ }
519
+ };
375
520
 
376
521
  const Schema = zod.z.object({
377
522
  $ref: zod.z.string().nullish(),
@@ -463,50 +608,6 @@ zod.z.object({
463
608
  }).nullish()
464
609
  });
465
610
 
466
- const templateJsdocMethod = ({
467
- classMethod,
468
- httpMethod,
469
- path,
470
- pathParams,
471
- bodyParams,
472
- queryParams
473
- }) => {
474
- let jsdoc = "";
475
- let methodSignature = "";
476
- let newPath = path;
477
- for (const p of pathParams) {
478
- methodSignature += p.name + ", ";
479
- newPath = newPath.replace("{" + p.name + "}", `' + ${p.name} + '`);
480
- jsdoc += `
481
- * @pathParam '${p.name}${p.required ? "" : "?"}' - ${p.description}`;
482
- }
483
- let payloads = "";
484
- for (const p of bodyParams) {
485
- methodSignature += p.name + ", ";
486
- payloads += p.name;
487
- jsdoc += `
488
- * @payload '${p.name}${p.required ? "" : "?"}' - ${p.description} ${p?.schema?.properties ? "=> " + JSON.stringify(p.schema.properties) : ""}`;
489
- }
490
- for (const p of queryParams) {
491
- const optionalMark = p.required ? "" : "?";
492
- methodSignature += p.name + optionalMark + ", ";
493
- jsdoc += `
494
- * @queryParam '${p.name}${p.required ? "" : "?"}' - ${p.description}`;
495
- }
496
- let queryString = "";
497
- for (const p of queryParams) {
498
- queryString += `${p.name}=__&`;
499
- }
500
- queryString = queryString.length > 0 ? "?" + queryString : "";
501
- return `
502
- /**
503
- * ${httpMethod.toUpperCase()} '${newPath}${queryString}' ${payloads ? "payload: '" + payloads + "'" : ""}
504
- * ${jsdoc}
505
- */
506
- ${classMethod}(${methodSignature}): Promise
507
- `;
508
- };
509
-
510
611
  const templateMethod = ({
511
612
  classMethod,
512
613
  description,
@@ -521,6 +622,9 @@ const templateMethod = ({
521
622
  let methodSignature = "";
522
623
  let newPath = `'${path}'`;
523
624
  let dependencies = [];
625
+ let snippetString = "";
626
+ let snippetMethodSignature = "";
627
+ let snippetCurl = "";
524
628
  for (const pathParam of pathParams) {
525
629
  const type = ParserUtils.parseType(pathParam);
526
630
  if (pathParam.name !== "namespace") {
@@ -535,11 +639,20 @@ const templateMethod = ({
535
639
  }
536
640
  }
537
641
  }
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'`;
538
643
  let dataType = null;
539
644
  if (httpMethod !== "get") {
540
645
  dataType = ParserUtils.parseBodyParamsType(bodyParams);
541
646
  dependencies = ParserUtils.parseBodyParamsImports(bodyParams);
542
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}}`;
543
656
  }
544
657
  const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
545
658
  const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
@@ -575,20 +688,23 @@ const templateMethod = ({
575
688
  const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
576
689
  const methodGenerics = resolvedResponseClass !== "unknown" ? `<T = ${resolvedResponseClass}>` : "";
577
690
  const responseType = resolvedResponseClass !== "unknown" ? `T` : "unknown";
691
+ const generateMethodName = () => `${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>>`;
692
+ const generateSnippetMethodName = () => `${methodName}(${snippetMethodSignature})`;
693
+ snippetString += `${generateSnippetMethodName()}`;
578
694
  const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
579
695
  methodImpl = `${descriptionText}
580
- ${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>> {
696
+ ${generateMethodName()} {
581
697
  ${queryParamsDefault}
582
698
  const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
583
699
  const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
584
700
 
585
- ${httpMethod === "get" ? `const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
701
+ ${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
586
702
 
587
703
  if (!this.cache) {
588
704
  return SdkCache.withoutCache(res)
589
705
  }
590
706
  const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
591
- return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? `return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})` : ""}
707
+ return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})` : ""}
592
708
  }
593
709
  `;
594
710
  if (!isGuardInvoked) {
@@ -601,7 +717,7 @@ ${httpMethod === "get" ? `const res = () => Validate.responseType(() => resultPr
601
717
  }
602
718
  `;
603
719
  }
604
- return [methodImpl, dependencies];
720
+ return [methodImpl, dependencies, snippetString, snippetCurl];
605
721
  };
606
722
 
607
723
  class TemplateZod {
@@ -617,32 +733,32 @@ class TemplateZod {
617
733
  }
618
734
  let imports = "";
619
735
  for (const cl of Array.from(this.importClasses).sort()) {
620
- imports += ` import { ${cl} } from './${cl}'
736
+ imports += `import { ${cl} } from './${cl}'
621
737
  `;
622
738
  }
623
739
  let exportedVariableString;
624
740
  let exportedTypeString;
625
741
  if (containsRecursiveType) {
626
742
  exportedVariableString = `
627
- export const ${fileName}: z.ZodType<${fileName}> = z.lazy(() =>
743
+ export const ${fileName}: z.ZodType<${fileName}> = z.lazy(() =>
628
744
  ${content.schemaString}
629
745
  )
630
746
  `;
631
747
  exportedTypeString = `
632
- export type ${fileName} = {
748
+ export interface ${fileName} {
633
749
  ${content.typeString}
634
- }
635
- `;
750
+ }
751
+ `;
636
752
  } else {
637
753
  exportedVariableString = `export const ${fileName} = ${content.schemaString}`;
638
- exportedTypeString = `export type ${fileName} = z.TypeOf<typeof ${fileName}>`;
754
+ exportedTypeString = `export interface ${fileName} extends z.TypeOf<typeof ${fileName}> {}`;
639
755
  }
640
756
  const template = `import { z } from 'zod'
641
- ${imports}
757
+ ${imports}
642
758
 
643
- ${exportedVariableString}
759
+ ${exportedVariableString}
644
760
 
645
- ${exportedTypeString}
761
+ ${exportedTypeString}
646
762
  `;
647
763
  return { buffer: template, duplicateFound: this.duplicateFound };
648
764
  };
@@ -799,11 +915,11 @@ class TemplateZodArray {
799
915
  render = (name) => {
800
916
  const cls = name.replace("Array", "");
801
917
  const template = `import { z } from 'zod'
802
- import { ${cls} } from './${cls}'
918
+ import { ${cls} } from './${cls}'
803
919
 
804
- export const ${name} = z.array(${cls})
920
+ export const ${name} = z.array(${cls})
805
921
 
806
- export type ${name} = z.TypeOf<typeof ${name}>
922
+ export interface ${name} extends z.TypeOf<typeof ${name}> {}
807
923
  `;
808
924
  return template;
809
925
  };
@@ -838,24 +954,37 @@ const extractEnumObject = (type, isRequired, enumArr) => {
838
954
  };
839
955
  };
840
956
 
957
+ const BUILD_DATE = new Date().toISOString();
841
958
  class CodeGenerator {
842
959
  static getPatchedDir = () => path.join(CliParser.getSwaggersOutputPath(), "patched");
843
960
  static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
844
961
  static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
962
+ static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
963
+ static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
845
964
  static iterateApi = async (api) => {
846
965
  const apiBufferByTag = {};
847
- const jsDocApiBufferByTag = {};
848
966
  const dependenciesByTag = {};
849
967
  const classImports = {};
850
968
  let arrayDefinitions = [];
851
- for (const path2 in api.paths) {
969
+ const snippetMap = {};
970
+ const mapClassMethods = {};
971
+ const sortedPathsByLength = new Map(Object.entries(api.paths).sort((a, b) => {
972
+ if (a[0].length === b[0].length) {
973
+ return a[0].localeCompare(b[0]);
974
+ } else {
975
+ return a[0].length - b[0].length;
976
+ }
977
+ }));
978
+ const sortedKeys = Array.from(sortedPathsByLength.keys());
979
+ const servicePrefix = CodeGenerator.getServicePrefix(sortedKeys);
980
+ console.log("ServicePrefix", servicePrefix, ", Paths:", sortedKeys);
981
+ for (const [path2, operation] of sortedPathsByLength) {
852
982
  const isAdminEndpoint = path2.indexOf("/admin/") > -1;
853
983
  if (CliParser.isAdmin() && !isAdminEndpoint) {
854
984
  continue;
855
985
  } else if (!CliParser.isAdmin() && isAdminEndpoint) {
856
986
  continue;
857
987
  }
858
- const operation = api.paths[path2];
859
988
  const httpMethods = Object.keys(operation);
860
989
  for (const httpMethod of httpMethods) {
861
990
  const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
@@ -865,59 +994,67 @@ class CodeGenerator {
865
994
  if (!endpoint.tags) {
866
995
  continue;
867
996
  }
997
+ if (endpoint.deprecated) {
998
+ continue;
999
+ }
868
1000
  const [tag] = endpoint.tags;
1001
+ mapClassMethods[tag] = mapClassMethods[tag] ? mapClassMethods[tag] : {};
1002
+ const isForm = endpoint.consumes && endpoint.consumes[0] === "application/x-www-form-urlencoded";
1003
+ const classMethod = ParserUtils.generateNaturalLangMethod({
1004
+ servicePrefix,
1005
+ path: path2,
1006
+ httpMethod,
1007
+ isForm,
1008
+ existingMethods: mapClassMethods[tag]
1009
+ });
1010
+ mapClassMethods[tag][classMethod] = `${path2} ${httpMethod}`;
1011
+ snippetMap[path2] = snippetMap[path2] ? snippetMap[path2] : {};
869
1012
  const description = endpoint.description;
870
- const isDeprecated = endpoint.deprecated;
871
1013
  const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
872
- const className = _.upperFirst(_.camelCase(tag));
1014
+ const { className, classGenName } = ParserUtils.generateClassName(tag);
873
1015
  classImports[className] = classImports[className] ? classImports[className] : {};
874
- if (!isDeprecated) {
875
- if (responseClass) {
876
- const importTypeClass = ParserUtils.parseRefType(responseClass);
877
- classImports[className][importTypeClass] = `import { ${importTypeClass} } from './definitions/${importTypeClass}'`;
878
- }
879
- if (responseClass && responseClass.endsWith("Array")) {
880
- arrayDefinitions.push(responseClass);
881
- }
882
- const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
883
- const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
884
- const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
885
- let bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
886
- const classMethod = ParserUtils.generateClassMethod({
887
- path: path2,
888
- endpoint,
889
- httpMethod,
890
- className
891
- });
892
- if (endpoint.requestBody) {
893
- bodyParams = [
894
- {
895
- name: "body",
896
- in: "body",
897
- schema: endpoint.requestBody.content["application/json"].schema
898
- }
899
- ];
900
- }
901
- const pathWithBase = `${api.basePath ?? ""}${path2}`;
902
- const [generatedMethodString, importStatements] = templateMethod({
903
- classMethod,
904
- description,
905
- httpMethod,
906
- path: pathWithBase,
907
- pathParams,
908
- bodyParams,
909
- queryParams,
910
- isFormUrlEncoded,
911
- responseClass
912
- });
913
- apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
914
- jsDocApiBufferByTag[tag] = (jsDocApiBufferByTag[tag] || "") + templateJsdocMethod({ classMethod, httpMethod, path: path2, pathParams, bodyParams, queryParams });
915
- dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
1016
+ if (responseClass) {
1017
+ const importTypeClass = ParserUtils.parseRefType(responseClass);
1018
+ classImports[className][importTypeClass] = `import { ${importTypeClass} } from './definitions/${importTypeClass}'`;
1019
+ }
1020
+ if (responseClass && responseClass.endsWith("Array")) {
1021
+ arrayDefinitions.push(responseClass);
916
1022
  }
1023
+ const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
1024
+ const pathWithBase = `${api.basePath ?? ""}${path2}`;
1025
+ const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
1026
+ const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
1027
+ let bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
1028
+ if (endpoint.requestBody) {
1029
+ bodyParams = [
1030
+ {
1031
+ name: "body",
1032
+ in: "body",
1033
+ schema: endpoint.requestBody.content["application/json"].schema
1034
+ }
1035
+ ];
1036
+ }
1037
+ const [generatedMethodString, importStatements, snippetString, snippetCurl] = templateMethod({
1038
+ classMethod,
1039
+ description,
1040
+ httpMethod,
1041
+ path: pathWithBase,
1042
+ pathParams,
1043
+ bodyParams,
1044
+ queryParams,
1045
+ isFormUrlEncoded,
1046
+ responseClass
1047
+ });
1048
+ apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
1049
+ dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
1050
+ snippetMap[path2][httpMethod] = {
1051
+ 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>`,
1052
+ shell: snippetCurl
1053
+ };
917
1054
  }
918
1055
  }
919
1056
  arrayDefinitions = [...new Set(arrayDefinitions)];
920
- return { apiBufferByTag, jsDocApiBufferByTag, dependenciesByTag, classImports, arrayDefinitions };
1057
+ return { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap };
921
1058
  };
922
1059
  static main = async (nameArray) => {
923
1060
  const serviceName = nameArray[0];
@@ -925,7 +1062,6 @@ class CodeGenerator {
925
1062
  const parser = new SwaggerParser();
926
1063
  const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
927
1064
  const DIST_DIR = `${generatedFolder}/${serviceName}`;
928
- const DIST_DOCS_DIR = path.join(DIST_DIR, "docs");
929
1065
  const DIST_DEFINITION_DIR = path.join(DIST_DIR, "definitions");
930
1066
  const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
931
1067
  const swaggerPatchedFilePath = `${CodeGenerator.getPatchedDir()}/${swaggerFile}`;
@@ -933,17 +1069,19 @@ class CodeGenerator {
933
1069
  ParserUtils.applyPatchIfExists(swaggerFilePath, swaggerPatchFilePath, swaggerPatchedFilePath, CodeGenerator.getPatchedDir());
934
1070
  const api = await parser.parse(swaggerPatchedFilePath);
935
1071
  const indexImportsSet = /* @__PURE__ */ new Set();
936
- console.log("\n----------\n API name: %s, Version: %s schemes %s", api, api.info.title, api.info.version, api.schemes);
1072
+ console.log("----------\nGenerating API:", { title: api.info.title, version: api.info.version });
937
1073
  ParserUtils.mkdirIfNotExist(DIST_DIR);
938
- ParserUtils.mkdirIfNotExist(DIST_DOCS_DIR);
939
1074
  ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
940
- const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions } = await CodeGenerator.iterateApi(api);
1075
+ ParserUtils.writeVersionFile(DIST_DIR, "Version.ts", serviceName, api.info, BUILD_DATE);
1076
+ const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions, snippetMap } = await CodeGenerator.iterateApi(api);
1077
+ if (CliParser.getSnippetOutputPath()) {
1078
+ ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify(snippetMap, null, 2));
1079
+ }
941
1080
  const targetSrcFolder = `${CliParser.getOutputPath()}/`;
942
1081
  for (const tag in apiBufferByTag) {
943
- const className = _.upperFirst(_.camelCase(tag));
1082
+ const { className, classGenName } = ParserUtils.generateClassName(tag);
944
1083
  const apiBuffer = apiBufferByTag[tag];
945
1084
  const imports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
946
- const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
947
1085
  ParserUtils.writeClassFile(DIST_DIR, classGenName, apiBuffer, imports);
948
1086
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DIR, `${classGenName}`), targetSrcFolder));
949
1087
  }
@@ -975,7 +1113,7 @@ class CodeGenerator {
975
1113
  ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, arrayClass, buffer);
976
1114
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DEFINITION_DIR, arrayClass), targetSrcFolder));
977
1115
  }
978
- console.log("\n----------\nCOMPLETED.\n----------\n\n");
1116
+ console.log("\nCOMPLETED\n----------\n\n");
979
1117
  return indexImportsSet;
980
1118
  };
981
1119
  }
@@ -1002,7 +1140,7 @@ class SwaggerDownloader {
1002
1140
  });
1003
1141
  });
1004
1142
  request.on("error", (err) => {
1005
- console.log(`SwaggerDownloader dl failed for "${targetFileName}" and "${url}"`, err);
1143
+ console.log(`SwaggerDownloader failed for "${targetFileName}" and "${url}"`, err);
1006
1144
  });
1007
1145
  };
1008
1146
  static main = () => {