@accelbyte/codegen 1.0.0-alpha.1 → 1.0.0-alpha.11

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.
@@ -78,15 +78,15 @@ const generateImports = (body, importStatements) => {
78
78
  ${importStatements.sort().join("\n")}`;
79
79
  };
80
80
  const templateClass = (className, body, importStatements) => `/**
81
- * DON'T EDIT THIS FILE, it is AUTO GENERATED
82
- */
83
- ${generateImports(body, importStatements)}
81
+ * DON'T EDIT THIS FILE, it is AUTO GENERATED
82
+ */
83
+ ${generateImports(body, importStatements)}
84
84
 
85
- export class ${className} {
86
- // @ts-ignore
87
- constructor(private axiosInstance: AxiosInstance, private namespace: string, private cache = false) {}
85
+ export class ${className} {
86
+ // @ts-ignore
87
+ constructor(private axiosInstance: AxiosInstance, private namespace: string, private cache = false) {}
88
88
  ${body}
89
- }
89
+ }
90
90
  `;
91
91
 
92
92
  const templateJsdocFile = (apiName, body) => `
@@ -98,44 +98,34 @@ ${body}
98
98
  `.replace(/, \)/g, ")").trim();
99
99
 
100
100
  class ParserUtils {
101
- static parseQueryParamAttributeDefault = (name, definition) => {
102
- const attrName = name.slice(name.lastIndexOf(".") + 1);
101
+ static parseQueryParamAttributeDefault = (definition) => {
102
+ const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
103
103
  const defaultValue = definition.type === "string" ? `'${definition.default}'` : definition.default;
104
104
  return `${attrName}: ${defaultValue}`;
105
105
  };
106
- static parseType = (type) => {
107
- if (type === "integer")
106
+ static parseType = (pathParam) => {
107
+ if (pathParam.type === "int" || pathParam.type === "integer" || pathParam?.schema?.type === "integer")
108
108
  return "number";
109
- if (type === "array")
110
- return "any[]";
111
- return type;
109
+ if (pathParam.type === "array")
110
+ return `${pathParam.items.type ?? "any"}[]`;
111
+ if (pathParam?.schema?.type === "array")
112
+ return `${pathParam.schema.items.type ?? "any"}[]`;
113
+ if (pathParam?.schema?.type)
114
+ return pathParam.schema.type;
115
+ return pathParam.type;
112
116
  };
113
117
  static parseQueryParamsType = (queryParams) => {
114
- return queryParams.map((p) => ParserUtils.parseAttributeType(p.name, p)).join(",");
118
+ return queryParams.map((queryParam) => ParserUtils.parseAttributeType(queryParam)).join(",");
115
119
  };
116
120
  static isAnyQueryParamRequired = (queryParams) => {
117
- queryParams.forEach((p) => {
118
- if (p.required) {
119
- return true;
120
- }
121
- });
122
- return false;
121
+ return queryParams.some((queryParam) => queryParam.required);
123
122
  };
124
123
  static parseQueryParamsDefault = (queryParams) => {
125
- const result = queryParams.filter((p) => !!p.default).map((p) => ParserUtils.parseQueryParamAttributeDefault(p.name, p)).join(",");
124
+ const result = queryParams.filter((queryParam) => !!queryParam.default && !queryParam.required).map(ParserUtils.parseQueryParamAttributeDefault).join(",");
126
125
  return result ? `${result},` : "";
127
126
  };
128
127
  static parseBodyParamsImports = (bodyParams) => {
129
- const ret = bodyParams.map((p) => {
130
- if (p?.schema?.$ref)
131
- return ParserUtils.parseRefImport(p.schema.$ref, p);
132
- if (p?.schema?.items?.$ref)
133
- return ParserUtils.parseRefImport(p.schema.items.$ref, p);
134
- if (p?.$ref)
135
- return ParserUtils.parseRefImport(p.$ref, p);
136
- return null;
137
- }).filter((p) => !!p);
138
- return ret;
128
+ return bodyParams.map(ParserUtils.parseRefImport).filter(Boolean);
139
129
  };
140
130
  static parseImportDir = ($ref) => {
141
131
  let ref = $ref.replace(".", "/");
@@ -148,7 +138,11 @@ class ParserUtils {
148
138
  return ref.slice(0, ref.lastIndexOf("/")).replace("#", ".");
149
139
  }
150
140
  };
151
- static parseRefImport = ($ref, p) => {
141
+ static parseRefImport = (bodyParam) => {
142
+ const $ref = bodyParam?.schema?.$ref || bodyParam?.schema?.items?.$ref;
143
+ if (!$ref) {
144
+ return null;
145
+ }
152
146
  const type = ParserUtils.parseRefType($ref);
153
147
  return `import { ${type} } from './definitions/${type}'`;
154
148
  };
@@ -158,60 +152,72 @@ class ParserUtils {
158
152
  ref = ref.slice(0, -1);
159
153
  }
160
154
  const val = ref.slice(ref.lastIndexOf("/") + 1);
161
- return _.upperFirst(_.camelCase(val));
155
+ return _.upperFirst(_.camelCase(val)).replace(/( \w)/g, (group) => group.replace(" ", "").toUpperCase());
162
156
  };
163
- static parseAttributeType = (name, definition) => {
157
+ static parseAttributeType = (definition) => {
164
158
  const required = definition.required ? "" : "?";
165
- const attrName = name.slice(name.lastIndexOf(".") + 1);
166
- if (definition.enums) {
167
- const enums = definition.enums.map((enm) => definition.type === "string" ? `'${enm}'` : enm).join(" | ");
159
+ const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
160
+ if (definition.enum) {
161
+ const enums = definition.enum.map((enm) => definition.type === "string" ? `'${enm}'` : enm).join(" | ");
168
162
  return `${attrName}${required}: ${enums}`;
169
163
  }
170
- if (definition.type && definition.type === "integer") {
164
+ if (definition.type && ParserUtils.parseType(definition) === "number") {
165
+ return `${attrName}${required}: number`;
166
+ }
167
+ if (definition?.schema?.type && ParserUtils.parseType(definition) === "number") {
171
168
  return `${attrName}${required}: number`;
172
169
  }
173
170
  if (definition.type && definition.type === "array") {
174
171
  return `${attrName}${required}: ${definition.items.type ?? "any"}[]`;
175
172
  }
173
+ if (definition?.schema?.type && definition.schema.type === "array") {
174
+ return `${attrName}${required}: ${definition.schema.items.type ?? "any"}[]`;
175
+ }
176
176
  if (definition.type && definition.type) {
177
177
  return `${attrName}${required}: ${definition.type} | null`;
178
178
  }
179
+ if (definition?.schema?.type && definition.schema.type) {
180
+ return `${attrName}${required}: ${definition.schema.type} | null`;
181
+ }
179
182
  return `${attrName}${required}: any`;
180
183
  };
181
184
  static parseBodyParamsType = (bodyParams) => {
182
- const [p] = bodyParams;
183
- if (!p)
185
+ const [bodyParam] = bodyParams;
186
+ if (!bodyParam)
184
187
  return null;
185
- if (bodyParams.length > 0 && p?.name !== "body" && !p?.schema) {
186
- let retBodyParams = `{${bodyParams.map((p2) => ParserUtils.parseAttributeType(p2.name, p2)).join(",")}}`;
188
+ if (bodyParams.length > 0 && bodyParam?.name !== "body" && !bodyParam?.schema) {
189
+ let retBodyParams = `{${bodyParams.map((bodyParam2) => ParserUtils.parseAttributeType(bodyParam2)).join(",")}}`;
187
190
  retBodyParams = retBodyParams.replace("file?: file", "file?: File");
188
191
  return retBodyParams;
189
192
  }
190
- if (p?.schema?.type === "array" && !p?.schema?.items?.$ref) {
191
- return `${p.schema.items.type ?? "any"}[]`;
193
+ if (bodyParam?.schema?.type === "array" && !bodyParam?.schema?.items?.$ref) {
194
+ return `${bodyParam.schema.items.type ?? "any"}[]`;
192
195
  }
193
- if (p?.schema?.type === "array" && p?.schema?.items?.$ref) {
194
- return `${ParserUtils.parseRefType(p.schema.items.$ref)}[]`;
196
+ if (bodyParam?.schema?.type === "array" && bodyParam?.schema?.items?.$ref) {
197
+ return `${ParserUtils.parseRefType(bodyParam.schema.items.$ref)}[]`;
195
198
  }
196
- if (p?.schema.$ref) {
197
- return ParserUtils.parseRefType(p.schema.$ref);
199
+ if (bodyParam?.schema.$ref) {
200
+ return ParserUtils.parseRefType(bodyParam.schema.$ref);
198
201
  }
199
- if (p?.schema?.additionalProperties?.type === "object") {
202
+ if (bodyParam?.schema?.additionalProperties?.type === "object") {
200
203
  return "any";
201
204
  }
202
205
  return null;
203
206
  };
204
- static get2xxResponse(methodEntity, path2) {
207
+ static get2xxResponse(methodEntity) {
205
208
  const keys = Object.keys(methodEntity);
206
209
  let responseClass = null;
207
210
  keys.forEach((key) => {
208
211
  if (String(key).startsWith("2")) {
209
212
  const sch = methodEntity[key].schema;
213
+ const schV3 = methodEntity[key].content && methodEntity[key].content["application/json"].schema;
210
214
  if (sch?.$ref) {
211
215
  responseClass = ParserUtils.parseRefType(sch.$ref);
212
216
  } else if (sch?.type === "array" && sch.items?.$ref) {
213
217
  responseClass = ParserUtils.parseRefType(sch.items.$ref);
214
218
  responseClass = `${responseClass}Array`;
219
+ } else if (schV3?.$ref) {
220
+ responseClass = ParserUtils.parseRefType(schV3.$ref);
215
221
  } else ;
216
222
  }
217
223
  });
@@ -226,24 +232,23 @@ class ParserUtils {
226
232
  }
227
233
  return contentTypes.includes("application/x-www-form-urlencoded");
228
234
  }
229
- static getPathParams(parametersArray) {
230
- if (!parametersArray) {
235
+ static filterPathParams(parameters) {
236
+ if (!parameters) {
231
237
  return [];
232
238
  }
233
- const res = [];
234
- for (const p of parametersArray) {
235
- if (p.in === "path") {
236
- res.push(p);
237
- }
238
- }
239
- return res;
239
+ return parameters.filter((parameter) => parameter.in === "path");
240
240
  }
241
- static generateClassMethod(path2, parametersArray, httpMethod, className) {
241
+ static generateClassMethod({
242
+ path: path2,
243
+ endpoint,
244
+ httpMethod,
245
+ className
246
+ }) {
242
247
  let replacedIdsPath = path2;
243
- if (parametersArray) {
244
- for (const p of parametersArray) {
245
- if (p.in === "path") {
246
- replacedIdsPath = replacedIdsPath.replace("{" + p.name + "}", "By" + ParserUtils.toTitleCaseWord(p.name));
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));
247
252
  replacedIdsPath = replacedIdsPath.replace("/iam", "");
248
253
  replacedIdsPath = replacedIdsPath.replace("/odin-config", "");
249
254
  }
@@ -251,8 +256,8 @@ class ParserUtils {
251
256
  }
252
257
  let classMethod = httpMethod + "/" + replacedIdsPath;
253
258
  classMethod = _.camelCase(classMethod);
254
- classMethod = classMethod.replace("PublicNamespacesByNamespace", "");
255
- classMethod = classMethod.replace("AdminNamespacesByNamespace", "Admin");
259
+ classMethod = classMethod.replace("PublicNamespacesByNamespace", "Ns");
260
+ classMethod = classMethod.replace("AdminNamespacesByNamespace", "AdminNs");
256
261
  const searchWord = "NamespacesByNamespace";
257
262
  const nsExistInsideMethod = classMethod.indexOf(searchWord) > 0 && classMethod.indexOf(searchWord) + searchWord.length < classMethod.length;
258
263
  const excludedClasses = ["Policies"];
@@ -261,24 +266,17 @@ class ParserUtils {
261
266
  }
262
267
  return classMethod;
263
268
  }
264
- static getBodyParams(parametersArray) {
265
- if (!parametersArray)
266
- return [];
267
- if (!_.isArray(parametersArray) && parametersArray)
268
- return [parametersArray].filter((p) => p.in === "body" || p.in === "formData");
269
- return parametersArray.filter((p) => p.in === "body" || p.in === "formData");
269
+ static filterBodyParams(parameters) {
270
+ if (Array.isArray(parameters) && parameters.length > 0) {
271
+ return parameters.filter((parameter) => parameter.in === "body" || parameter.in === "formData");
272
+ }
273
+ return [];
270
274
  }
271
- static getQueryParameters(parametersArray) {
272
- if (!parametersArray) {
275
+ static filterQueryParameters(parameters) {
276
+ if (!parameters) {
273
277
  return [];
274
278
  }
275
- const res = [];
276
- for (const p of parametersArray) {
277
- if (p.in === "query") {
278
- res.push(p);
279
- }
280
- }
281
- return res;
279
+ return parameters.filter((parameter) => parameter.in === "query");
282
280
  }
283
281
  static mkdirIfNotExist(dirToCreate) {
284
282
  if (!fs__default.existsSync(dirToCreate)) {
@@ -334,16 +332,32 @@ class ParserUtils {
334
332
  }
335
333
  const swaggerContent = JSON.parse(fs__default.readFileSync(swaggerFilePath, "utf8"));
336
334
  const swaggerPatchFileContent = JSON.parse(fs__default.readFileSync(possibleSwaggerPatchFilePath, "utf8"));
335
+ for (const patchEntry of swaggerPatchFileContent) {
336
+ const segments = patchEntry.path.split("/").filter(Boolean);
337
+ let currentNode = swaggerContent;
338
+ let aggregatedPath = "";
339
+ for (let i = 0; i < segments.length; i++) {
340
+ const segment = segments[i];
341
+ aggregatedPath += `/${segment}`;
342
+ const effectiveSegment = segment.replace(/(~1)/g, "/").replace(/(~0)/g, "~");
343
+ if (!currentNode[effectiveSegment]) {
344
+ if (i + 1 === segments.length && patchEntry.op === "add") ; else {
345
+ throw new Error([
346
+ `JSON patch error: operation "${patchEntry.op}" on path "${aggregatedPath}" fails because the path doesn't exist in ${swaggerFilePath}. This may be caused by:
347
+ `,
348
+ "1. The related service has patched the service, so patch is no longer needed.",
349
+ "2. There is a breaking change on the service that causes the path to change.\n",
350
+ `In any case, revisit this file: "${possibleSwaggerPatchFilePath}", then try again.
351
+ `
352
+ ].join("\n"));
353
+ }
354
+ }
355
+ currentNode = currentNode[effectiveSegment];
356
+ }
357
+ }
337
358
  const { newDocument } = applyPatch(swaggerContent, swaggerPatchFileContent);
338
359
  fs__default.writeFileSync(swaggerPatchedFilePath, JSON.stringify(newDocument, null, 2));
339
360
  }
340
- static mapKeys(map_) {
341
- const methods_ = [];
342
- for (const m in map_) {
343
- methods_.push(m);
344
- }
345
- return methods_;
346
- }
347
361
  static getRelativePathToWebSdkSrcFolder(srcFolder, targetSrcFolder) {
348
362
  const replaced = srcFolder.replace(/\\/g, "/");
349
363
  return replaced.replace(/\\/g, "/").replace(targetSrcFolder, "./");
@@ -359,7 +373,104 @@ ${content}`;
359
373
  };
360
374
  }
361
375
 
362
- const templateJsdocMethod = (classMethod, httpMethod, path, pathParams, bodyParams, queryParams) => {
376
+ const Schema = z.object({
377
+ $ref: z.string().nullish(),
378
+ type: z.union([z.literal("array"), z.literal("object"), z.literal("file"), z.literal("string"), z.literal("boolean"), z.literal("integer")]).nullish(),
379
+ items: z.object({
380
+ $ref: z.string().nullish(),
381
+ type: z.string().nullish()
382
+ }).nullish(),
383
+ properties: z.union([z.array(z.string()).nullish(), z.record(z.object({ type: z.string() })).nullish()]),
384
+ description: z.string().nullish(),
385
+ additionalProperties: z.object({
386
+ type: z.string().nullish()
387
+ }).nullish()
388
+ });
389
+ const Definition = z.object({
390
+ required: z.array(z.string()).nullish(),
391
+ properties: z.record(z.object({
392
+ type: z.string()
393
+ })).nullish()
394
+ });
395
+ const Definitions = z.record(Definition);
396
+ const EndpointParametersType = z.enum(["apiKey", "boolean", "int", "integer", "number", "string", "array", "file"]);
397
+ const EndpointParametersIn = z.enum(["body", "formData", "header", "path", "query"]);
398
+ const EndpointParameters = z.object({
399
+ type: EndpointParametersType.nullish(),
400
+ description: z.string().nullish(),
401
+ name: z.string(),
402
+ in: EndpointParametersIn,
403
+ required: z.boolean().nullish(),
404
+ schema: Schema.nullish(),
405
+ default: z.union([z.boolean(), z.string(), z.number()]).nullish(),
406
+ enum: z.array(z.union([z.boolean(), z.string(), z.number()])).nullish(),
407
+ items: z.object({
408
+ type: z.string()
409
+ }).nullish()
410
+ });
411
+ const Endpoint = z.object({
412
+ description: z.string().nullish(),
413
+ consumes: z.array(z.string()).nullish(),
414
+ produces: z.array(z.string()).nullish(),
415
+ tags: z.array(z.string()).nullish(),
416
+ summary: z.string().nullish(),
417
+ operationId: z.string(),
418
+ deprecated: z.boolean().nullish(),
419
+ responses: z.record(z.object({
420
+ description: z.string().nullish(),
421
+ schema: Schema.nullish(),
422
+ content: z.object({
423
+ "application/json": z.object({
424
+ schema: Schema.nullish()
425
+ })
426
+ }).nullish()
427
+ })),
428
+ parameters: z.array(EndpointParameters).nullish(),
429
+ requestBody: z.object({
430
+ required: z.boolean(),
431
+ content: z.object({
432
+ "application/json": z.object({
433
+ schema: Schema.nullish()
434
+ })
435
+ }).nullish()
436
+ }).nullish()
437
+ });
438
+ const Operation = z.object({
439
+ get: Endpoint.nullish(),
440
+ post: Endpoint.nullish(),
441
+ patch: Endpoint.nullish(),
442
+ delete: Endpoint.nullish(),
443
+ put: Endpoint.nullish()
444
+ });
445
+ const Paths = z.record(Operation);
446
+ z.object({
447
+ paths: Paths,
448
+ definitions: Definitions,
449
+ basePath: z.string(),
450
+ info: z.object({
451
+ description: z.string(),
452
+ title: z.string(),
453
+ contact: z.object({
454
+ name: z.string(),
455
+ url: z.string(),
456
+ email: z.string()
457
+ }),
458
+ version: z.string()
459
+ }),
460
+ schemes: z.array(z.string()).nullish(),
461
+ components: z.object({
462
+ schemas: Definitions
463
+ }).nullish()
464
+ });
465
+
466
+ const templateJsdocMethod = ({
467
+ classMethod,
468
+ httpMethod,
469
+ path,
470
+ pathParams,
471
+ bodyParams,
472
+ queryParams
473
+ }) => {
363
474
  let jsdoc = "";
364
475
  let methodSignature = "";
365
476
  let newPath = path;
@@ -396,21 +507,31 @@ const templateJsdocMethod = (classMethod, httpMethod, path, pathParams, bodyPara
396
507
  `;
397
508
  };
398
509
 
399
- const templateMethod = (classMethod, description, httpMethod, path, pathParams, bodyParams, queryParams, isFormUrlEncoded, responseClass) => {
510
+ const templateMethod = ({
511
+ classMethod,
512
+ description,
513
+ httpMethod,
514
+ path,
515
+ pathParams,
516
+ bodyParams,
517
+ queryParams,
518
+ isFormUrlEncoded,
519
+ responseClass
520
+ }) => {
400
521
  let methodSignature = "";
401
522
  let newPath = `'${path}'`;
402
523
  let dependencies = [];
403
- for (const p of pathParams) {
404
- const type = ParserUtils.parseType(p.type);
405
- if (p.name !== "namespace") {
406
- methodSignature += p.name + `:${type}, `;
524
+ for (const pathParam of pathParams) {
525
+ const type = ParserUtils.parseType(pathParam);
526
+ if (pathParam.name !== "namespace") {
527
+ methodSignature += pathParam.name + `:${type}, `;
407
528
  }
408
- const pName = p.name === "namespace" ? "this.namespace" : p.name;
409
- if (path.match(`{${p.name}}`)) {
529
+ const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
530
+ if (path.match(`{${pathParam.name}}`)) {
410
531
  if (type === "string") {
411
- newPath = `${newPath}.replace('{${p.name}}', ${pName})`;
532
+ newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
412
533
  } else {
413
- newPath = `${newPath}.replace('{${p.name}}', String(${pName}))`;
534
+ newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
414
535
  }
415
536
  }
416
537
  }
@@ -420,8 +541,8 @@ const templateMethod = (classMethod, description, httpMethod, path, pathParams,
420
541
  dependencies = ParserUtils.parseBodyParamsImports(bodyParams);
421
542
  methodSignature += dataType ? `data: ${dataType},` : "";
422
543
  }
423
- ParserUtils.isAnyQueryParamRequired(queryParams);
424
- const queryParamsType = queryParams.length ? `queryParams${"?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
544
+ const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
545
+ const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
425
546
  const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as SDKRequestConfig` : "const params = {} as SDKRequestConfig";
426
547
  const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
427
548
  const isDelete = ["delete"].includes(httpMethod);
@@ -446,74 +567,30 @@ const templateMethod = (classMethod, description, httpMethod, path, pathParams,
446
567
  const parameters = (queryParamsType ? `${methodSignature} ${queryParamsType}` : methodSignature).replace(/,\s*$/, "");
447
568
  let methodImpl = "";
448
569
  const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
449
- const isCacheFetchUnknown = ["get"].includes(httpMethod) && resolvedResponseClass === "unknown";
450
570
  const cachedFetchMethod = classMethod.replace("get", "fetch");
451
571
  const deprecateTag = isCacheFetch ? `/**
452
572
  * @deprecated Use "${cachedFetchMethod}()" instead.
453
573
  */` : "";
454
- let isGuardInvoked = false;
455
- if (isCacheFetch) {
456
- methodImpl = `${descriptionText}
457
- ${cachedFetchMethod}<T = ${resolvedResponseClass}>(${parameters}): Promise<IResponseWithSync<T>> {
574
+ const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
575
+ const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
576
+ const methodGenerics = resolvedResponseClass !== "unknown" ? `<T = ${resolvedResponseClass}>` : "";
577
+ const responseType = resolvedResponseClass !== "unknown" ? `T` : "unknown";
578
+ const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
579
+ methodImpl = `${descriptionText}
580
+ ${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>> {
458
581
  ${queryParamsDefault}
459
582
  const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
460
583
  const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
461
-
462
- const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
463
584
 
464
- if (!this.cache) {
465
- return SdkCache.withoutCache(res)
466
- }
467
- const key = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
468
- return SdkCache.withCache(key, res)
469
- }
470
- `;
471
- isGuardInvoked = true;
472
- }
473
- if (isCacheFetchUnknown) {
474
- methodImpl = `${descriptionText}
475
- ${cachedFetchMethod}(${parameters}): Promise<IResponseWithSync<unknown>> {
476
- ${queryParamsDefault}
477
- const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
478
- const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
479
-
480
- const res = () => Validate.responseType(() => resultPromise, z.unknown())
585
+ ${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
481
586
 
482
587
  if (!this.cache) {
483
588
  return SdkCache.withoutCache(res)
484
589
  }
485
- const key = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
486
- return SdkCache.withCache(key, res)
487
- }
488
- `;
489
- isGuardInvoked = true;
490
- }
491
- const withTypeGuard = ["post", "put", "patch", "delete"].includes(httpMethod) && resolvedResponseClass !== "unknown";
492
- if (withTypeGuard) {
493
- methodImpl = `${descriptionText}
494
- ${classMethod}<T = ${resolvedResponseClass}>(${parameters}): Promise<IResponse<T>> {
495
- ${queryParamsDefault}
496
- const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
497
- const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
498
-
499
- return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
500
- }
501
- `;
502
- isGuardInvoked = true;
503
- }
504
- const withTypeGuardUnknown = ["post", "put", "patch", "delete"].includes(httpMethod) && resolvedResponseClass === "unknown";
505
- if (withTypeGuardUnknown) {
506
- methodImpl = `${descriptionText}
507
- ${classMethod}(${parameters}): Promise<IResponse<unknown>> {
508
- ${queryParamsDefault}
509
- const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
510
- const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
511
-
512
- return Validate.responseType(() => resultPromise, z.unknown())
590
+ 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})` : ""}
513
592
  }
514
593
  `;
515
- isGuardInvoked = true;
516
- }
517
594
  if (!isGuardInvoked) {
518
595
  methodImpl = `${descriptionText}
519
596
  ${deprecateTag}
@@ -531,41 +608,41 @@ class TemplateZod {
531
608
  duplicates;
532
609
  duplicateFound = false;
533
610
  importClasses = /* @__PURE__ */ new Set();
534
- render = (name, definition, duplicates) => {
611
+ render = (fileName, definition, duplicates) => {
535
612
  this.duplicates = duplicates;
536
613
  const content = this.parseToZodSchema(definition, definition.required || []);
537
- const containsRecursiveType = this.importClasses.has(name);
614
+ const containsRecursiveType = this.importClasses.has(fileName);
538
615
  if (containsRecursiveType) {
539
- this.importClasses.delete(name);
616
+ this.importClasses.delete(fileName);
540
617
  }
541
618
  let imports = "";
542
619
  for (const cl of Array.from(this.importClasses).sort()) {
543
- imports += ` import { ${cl} } from './${cl}'
620
+ imports += `import { ${cl} } from './${cl}'
544
621
  `;
545
622
  }
546
623
  let exportedVariableString;
547
624
  let exportedTypeString;
548
625
  if (containsRecursiveType) {
549
626
  exportedVariableString = `
550
- export const ${name}: z.ZodType<${name}> = z.lazy(() =>
627
+ export const ${fileName}: z.ZodType<${fileName}> = z.lazy(() =>
551
628
  ${content.schemaString}
552
629
  )
553
630
  `;
554
631
  exportedTypeString = `
555
- export type ${name} = {
632
+ export type ${fileName} = {
556
633
  ${content.typeString}
557
- }
558
- `;
634
+ }
635
+ `;
559
636
  } else {
560
- exportedVariableString = `export const ${name} = ${content.schemaString}`;
561
- exportedTypeString = `export type ${name} = z.TypeOf<typeof ${name}>`;
637
+ exportedVariableString = `export const ${fileName} = ${content.schemaString}`;
638
+ exportedTypeString = `export type ${fileName} = z.TypeOf<typeof ${fileName}>`;
562
639
  }
563
640
  const template = `import { z } from 'zod'
564
- ${imports}
641
+ ${imports}
565
642
 
566
- ${exportedVariableString}
643
+ ${exportedVariableString}
567
644
 
568
- ${exportedTypeString}
645
+ ${exportedTypeString}
569
646
  `;
570
647
  return { buffer: template, duplicateFound: this.duplicateFound };
571
648
  };
@@ -573,13 +650,17 @@ class TemplateZod {
573
650
  if (definition.additionalProperties) {
574
651
  return this.parseToZodAttribute("", definition, []);
575
652
  }
576
- if (!definition.properties) {
653
+ let properties;
654
+ if (definition.properties) {
655
+ properties = Object.entries(definition.properties);
656
+ } else if (definition.items?.properties) {
657
+ properties = Object.entries(definition.items.properties);
658
+ } else {
577
659
  return {
578
660
  schemaString: "z.any()",
579
661
  typeString: "any"
580
662
  };
581
663
  }
582
- const properties = Object.entries(definition.properties);
583
664
  const schemaFields = [];
584
665
  const typeFields = [];
585
666
  for (const property of properties) {
@@ -588,6 +669,12 @@ class TemplateZod {
588
669
  schemaFields.push(result.schemaString);
589
670
  typeFields.push(result.typeString);
590
671
  }
672
+ if (definition?.type === "array") {
673
+ return {
674
+ schemaString: `z.array(z.object({${schemaFields.join(",")}}))`,
675
+ typeString: typeFields.join(";")
676
+ };
677
+ }
591
678
  return {
592
679
  schemaString: `z.object({${schemaFields.join(",")}})`,
593
680
  typeString: typeFields.join(";")
@@ -629,7 +716,8 @@ class TemplateZod {
629
716
  };
630
717
  }
631
718
  if (type === "array") {
632
- const ref2 = definition.items?.$ref;
719
+ const items = definition.items;
720
+ const ref2 = items?.$ref;
633
721
  let model2;
634
722
  if (ref2) {
635
723
  const refType = ParserUtils.parseRefType(ref2);
@@ -638,9 +726,13 @@ class TemplateZod {
638
726
  schemaString: refType,
639
727
  typeString: refType
640
728
  };
641
- } else {
642
- const items = definition.items;
729
+ } else if (items) {
643
730
  model2 = this.parseEnumItems(items);
731
+ } else {
732
+ return {
733
+ schemaString: `${schemaAttribute} z.array(z.any())${schemaRequired}`,
734
+ typeString: `${typeAttribute} any[]${typeNullishability}`
735
+ };
644
736
  }
645
737
  return {
646
738
  schemaString: `${schemaAttribute} z.array(${model2.schemaString})${schemaRequired}`,
@@ -707,11 +799,11 @@ class TemplateZodArray {
707
799
  render = (name) => {
708
800
  const cls = name.replace("Array", "");
709
801
  const template = `import { z } from 'zod'
710
- import { ${cls} } from './${cls}'
802
+ import { ${cls} } from './${cls}'
711
803
 
712
- export const ${name} = z.array(${cls})
804
+ export const ${name} = z.array(${cls})
713
805
 
714
- export type ${name} = z.TypeOf<typeof ${name}>
806
+ export type ${name} = z.TypeOf<typeof ${name}>
715
807
  `;
716
808
  return template;
717
809
  };
@@ -750,7 +842,7 @@ class CodeGenerator {
750
842
  static getPatchedDir = () => path__default.join(CliParser.getSwaggersOutputPath(), "patched");
751
843
  static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
752
844
  static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
753
- static iterateApi = (api) => {
845
+ static iterateApi = async (api) => {
754
846
  const apiBufferByTag = {};
755
847
  const jsDocApiBufferByTag = {};
756
848
  const dependenciesByTag = {};
@@ -763,14 +855,20 @@ class CodeGenerator {
763
855
  } else if (!CliParser.isAdmin() && isAdminEndpoint) {
764
856
  continue;
765
857
  }
766
- const entity = api.paths[path2];
767
- const methods = ParserUtils.mapKeys(entity);
768
- for (const httpMethod of methods) {
769
- const e = entity[httpMethod];
770
- const [tag] = e.tags;
771
- const description = e.description;
772
- const isDeprecated = e.deprecated;
773
- const responseClass = ParserUtils.get2xxResponse(e.responses, path2);
858
+ const operation = api.paths[path2];
859
+ const httpMethods = Object.keys(operation);
860
+ for (const httpMethod of httpMethods) {
861
+ const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
862
+ console.error(JSON.stringify({ path: path2, httpMethod }, null, 2));
863
+ throw error;
864
+ });
865
+ if (!endpoint.tags) {
866
+ continue;
867
+ }
868
+ const [tag] = endpoint.tags;
869
+ const description = endpoint.description;
870
+ const isDeprecated = endpoint.deprecated;
871
+ const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
774
872
  const className = _.upperFirst(_.camelCase(tag));
775
873
  classImports[className] = classImports[className] ? classImports[className] : {};
776
874
  if (!isDeprecated) {
@@ -781,15 +879,39 @@ class CodeGenerator {
781
879
  if (responseClass && responseClass.endsWith("Array")) {
782
880
  arrayDefinitions.push(responseClass);
783
881
  }
784
- const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, e.consumes);
785
- const queryParams = ParserUtils.getQueryParameters(e.parameters);
786
- const pathParams = ParserUtils.getPathParams(e.parameters);
787
- const bodyParams = ParserUtils.getBodyParams(e.parameters);
788
- const classMethod = ParserUtils.generateClassMethod(path2, e.parameters, httpMethod, className);
789
- const baseAndPath = `${api.basePath ?? ""}${path2}`;
790
- const [generatedMethodString, importStatements] = templateMethod(classMethod, description, httpMethod, baseAndPath, pathParams, bodyParams, queryParams, isFormUrlEncoded, responseClass);
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
+ });
791
913
  apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
792
- jsDocApiBufferByTag[tag] = (jsDocApiBufferByTag[tag] || "") + templateJsdocMethod(classMethod, httpMethod, path2, pathParams, bodyParams, queryParams);
914
+ jsDocApiBufferByTag[tag] = (jsDocApiBufferByTag[tag] || "") + templateJsdocMethod({ classMethod, httpMethod, path: path2, pathParams, bodyParams, queryParams });
793
915
  dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
794
916
  }
795
917
  }
@@ -815,7 +937,7 @@ class CodeGenerator {
815
937
  ParserUtils.mkdirIfNotExist(DIST_DIR);
816
938
  ParserUtils.mkdirIfNotExist(DIST_DOCS_DIR);
817
939
  ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
818
- const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions } = CodeGenerator.iterateApi(api);
940
+ const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions } = await CodeGenerator.iterateApi(api);
819
941
  const targetSrcFolder = `${CliParser.getOutputPath()}/`;
820
942
  for (const tag in apiBufferByTag) {
821
943
  const className = _.upperFirst(_.camelCase(tag));
@@ -826,8 +948,9 @@ class CodeGenerator {
826
948
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_DIR, `${classGenName}`), targetSrcFolder));
827
949
  }
828
950
  const duplicates = /* @__PURE__ */ new Map();
829
- for (const ref in api.definitions) {
830
- const definition = api.definitions[ref];
951
+ const definitions = api?.components?.schemas || api.definitions;
952
+ for (const ref in definitions) {
953
+ const definition = definitions[ref];
831
954
  let fileName = ParserUtils.parseRefType(ref);
832
955
  const fileExist = fs__default.existsSync(path__default.join(DIST_DEFINITION_DIR, `${fileName}.ts`));
833
956
  if (fileExist) {
@@ -838,8 +961,8 @@ class CodeGenerator {
838
961
  ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, fileName, buffer);
839
962
  indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_DEFINITION_DIR, fileName), targetSrcFolder));
840
963
  }
841
- for (const ref in api.definitions) {
842
- const definition = api.definitions[ref];
964
+ for (const ref in definitions) {
965
+ const definition = definitions[ref];
843
966
  const fileName = ParserUtils.parseRefType(ref);
844
967
  const { buffer, duplicateFound } = new TemplateZod().render(fileName, definition, duplicates);
845
968
  if (duplicateFound) {