@accelbyte/codegen 1.0.5 → 2.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import yargs from 'yargs';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
import * as fs from 'fs';
|
|
4
|
-
import fs__default, {
|
|
4
|
+
import fs__default, { writeFileSync, readFileSync } from 'fs';
|
|
5
5
|
import * as path from 'path';
|
|
6
6
|
import path__default from 'path';
|
|
7
7
|
import SwaggerParser from '@apidevtools/swagger-parser';
|
|
@@ -55,6 +55,9 @@ class CliParser {
|
|
|
55
55
|
static getSnippetOutputPath = () => {
|
|
56
56
|
return CliParser.instance().argv.snippetOutput;
|
|
57
57
|
};
|
|
58
|
+
static skipVersionSync = () => {
|
|
59
|
+
return CliParser.instance().argv.skipVersionSync;
|
|
60
|
+
};
|
|
58
61
|
}
|
|
59
62
|
|
|
60
63
|
const getImportableVarMap$1 = () => ({
|
|
@@ -123,6 +126,79 @@ export function ${className}(sdk: AccelbyteSDK, args?: ApiArgs) {
|
|
|
123
126
|
`;
|
|
124
127
|
};
|
|
125
128
|
|
|
129
|
+
const VersionBumpType = z.enum(["CUTOFF", "RELEASE", "HOTFIX"]);
|
|
130
|
+
class VersionHelpers {
|
|
131
|
+
static getNextVersion = ({
|
|
132
|
+
codegenVersion,
|
|
133
|
+
serviceVersion,
|
|
134
|
+
predefinedMajorVersion,
|
|
135
|
+
versionBumpType,
|
|
136
|
+
sdkVersion,
|
|
137
|
+
nextPrereleaseId
|
|
138
|
+
}) => {
|
|
139
|
+
if (versionBumpType !== void 0) {
|
|
140
|
+
const parsed = VersionBumpType.safeParse(versionBumpType);
|
|
141
|
+
if (!parsed.success) {
|
|
142
|
+
throw new Error(`Invalid process.env.VERSION_BUMP_TYPE: ${versionBumpType}`);
|
|
143
|
+
}
|
|
144
|
+
if ((parsed.data === "HOTFIX" || parsed.data === "RELEASE") && nextPrereleaseId) {
|
|
145
|
+
throw new Error(`process.env.PRERELEASE_ID should be empty when process.env.VERSION_BUMP_TYPE is "HOTFIX" or "PRELEASE".`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const codegenSemvers = semver.parse(codegenVersion);
|
|
149
|
+
const serviceSemvers = semver.parse(serviceVersion);
|
|
150
|
+
const sdkSemvers = semver.parse(sdkVersion);
|
|
151
|
+
if (codegenSemvers === null) {
|
|
152
|
+
throw new Error(`Invalid codegen version: ${codegenVersion}`);
|
|
153
|
+
}
|
|
154
|
+
if (serviceSemvers === null) {
|
|
155
|
+
throw new Error(`Invalid service version: ${serviceVersion}`);
|
|
156
|
+
}
|
|
157
|
+
if (sdkSemvers === null) {
|
|
158
|
+
throw new Error(`Invalid sdk version: ${sdkVersion}`);
|
|
159
|
+
}
|
|
160
|
+
const { major: currentMajor, minor: currentMinor, patch: currentPatch, prerelease: currentPrerelease } = sdkSemvers;
|
|
161
|
+
const nextMajor = codegenSemvers.major + predefinedMajorVersion;
|
|
162
|
+
const shouldResetVersion = nextMajor !== currentMajor;
|
|
163
|
+
let nextMinor = currentMinor;
|
|
164
|
+
let nextPatch = currentPatch;
|
|
165
|
+
switch (versionBumpType) {
|
|
166
|
+
case VersionBumpType.Enum.CUTOFF: {
|
|
167
|
+
nextMinor++;
|
|
168
|
+
nextPatch = 0;
|
|
169
|
+
break;
|
|
170
|
+
}
|
|
171
|
+
case VersionBumpType.Enum.RELEASE:
|
|
172
|
+
break;
|
|
173
|
+
case VersionBumpType.Enum.HOTFIX: {
|
|
174
|
+
nextPatch++;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
if (shouldResetVersion) {
|
|
179
|
+
nextMinor = 0;
|
|
180
|
+
nextPatch = 0;
|
|
181
|
+
}
|
|
182
|
+
let nextVersion = [
|
|
183
|
+
codegenSemvers.major + predefinedMajorVersion,
|
|
184
|
+
nextMinor,
|
|
185
|
+
nextPatch
|
|
186
|
+
].join(".");
|
|
187
|
+
if (nextPrereleaseId) {
|
|
188
|
+
if (nextMinor !== currentMinor || nextMajor !== currentMajor) {
|
|
189
|
+
nextVersion += `-${nextPrereleaseId}.0`;
|
|
190
|
+
} else {
|
|
191
|
+
if (currentPrerelease.length)
|
|
192
|
+
nextVersion += `-${currentPrerelease.join(".")}`;
|
|
193
|
+
nextVersion = semver.inc(nextVersion, "prerelease", void 0, nextPrereleaseId);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return nextVersion;
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const codegenPackageJsonPath = path__default.join(__dirname, "../package.json");
|
|
201
|
+
const codegenPackageJSON = JSON.parse(fs__default.readFileSync(codegenPackageJsonPath, "utf-8"));
|
|
126
202
|
const UNDEFINED_SWAGGER_SEMVER = "0.0.0";
|
|
127
203
|
const REMOVED_KEYWORDS = [
|
|
128
204
|
"/admin/",
|
|
@@ -140,14 +216,14 @@ class ParserUtils {
|
|
|
140
216
|
static replaceAll = (string, search, replace) => {
|
|
141
217
|
return string.split(search).join(replace);
|
|
142
218
|
};
|
|
143
|
-
static generateClassName = (tag) => {
|
|
219
|
+
static generateClassName = (tag, isAdmin) => {
|
|
144
220
|
const className = _.upperFirst(_.camelCase(tag));
|
|
145
|
-
const classGenName =
|
|
221
|
+
const classGenName = isAdmin ? className + "Admin$" : className + "$";
|
|
146
222
|
return { className, classGenName };
|
|
147
223
|
};
|
|
148
|
-
static generateApiName = (tag) => {
|
|
224
|
+
static generateApiName = (tag, isAdmin) => {
|
|
149
225
|
const apiName = _.upperFirst(_.camelCase(tag));
|
|
150
|
-
const apiGenName =
|
|
226
|
+
const apiGenName = isAdmin ? apiName + "AdminApi" : apiName + "Api";
|
|
151
227
|
return { apiName, apiGenName };
|
|
152
228
|
};
|
|
153
229
|
static parseQueryParamAttributeDefault = (definition) => {
|
|
@@ -247,6 +323,12 @@ class ParserUtils {
|
|
|
247
323
|
if (definition?.schema?.type && definition.schema.type === "array") {
|
|
248
324
|
return `${attrName}${required}: ${definition.schema.items.type ?? "any"}[]`;
|
|
249
325
|
}
|
|
326
|
+
if (definition.type && definition.type === "file") {
|
|
327
|
+
return `${attrName}${required}: File`;
|
|
328
|
+
}
|
|
329
|
+
if (definition?.schema?.type && definition.schema.type === "file") {
|
|
330
|
+
return `${attrName}${required}: File`;
|
|
331
|
+
}
|
|
250
332
|
if (definition.type && definition.type) {
|
|
251
333
|
return `${attrName}${required}: ${definition.type} | null`;
|
|
252
334
|
}
|
|
@@ -426,42 +508,21 @@ class ParserUtils {
|
|
|
426
508
|
ParserUtils.mkdirIfNotExist(distDir);
|
|
427
509
|
fs__default.writeFileSync(path__default.join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
|
|
428
510
|
}
|
|
429
|
-
static
|
|
430
|
-
|
|
431
|
-
const pathToChangelog = path__default.join(currDir, "./CHANGELOG.md");
|
|
432
|
-
let fileContent = readFileSync(pathToChangelog, "utf-8");
|
|
433
|
-
const date = new Date().toISOString().slice(0, 10);
|
|
434
|
-
fileContent = "### " + packageVersion + " - " + date + `
|
|
435
|
-
|
|
436
|
-
- code-generated update
|
|
437
|
-
|
|
438
|
-
` + fileContent.trim();
|
|
439
|
-
fs__default.writeFileSync(pathToChangelog, fileContent, "utf-8");
|
|
440
|
-
}
|
|
441
|
-
static syncPackageVersion(apiInfo, isAdminWebSdk, prereleaseId) {
|
|
442
|
-
if (isAdminWebSdk) {
|
|
511
|
+
static syncPackageVersion(apiInfo, skipVersionSync, prereleaseId) {
|
|
512
|
+
if (skipVersionSync)
|
|
443
513
|
return;
|
|
444
|
-
}
|
|
445
514
|
const currDir = process.cwd();
|
|
446
515
|
const { packageJSON, pathToPackageJSON } = ParserUtils.getPackageJSONInfo(currDir);
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
nextSemver += `-${id}.${rest.join(".")}`;
|
|
456
|
-
}
|
|
457
|
-
if (!prereleaseId) {
|
|
458
|
-
nextSemver = semver.inc(nextSemver, "patch");
|
|
459
|
-
} else {
|
|
460
|
-
nextSemver = semver.inc(nextSemver, "prerelease", void 0, prereleaseId);
|
|
461
|
-
}
|
|
516
|
+
const nextSemver = VersionHelpers.getNextVersion({
|
|
517
|
+
codegenVersion: codegenPackageJSON.version,
|
|
518
|
+
serviceVersion: apiInfo["x-version"] || apiInfo.version || UNDEFINED_SWAGGER_SEMVER,
|
|
519
|
+
predefinedMajorVersion: packageJSON.predefinedMajorVersion || 0,
|
|
520
|
+
versionBumpType: process.env.VERSION_BUMP_TYPE,
|
|
521
|
+
sdkVersion: packageJSON.version,
|
|
522
|
+
nextPrereleaseId: prereleaseId
|
|
523
|
+
});
|
|
462
524
|
packageJSON.version = nextSemver;
|
|
463
525
|
writeFileSync(pathToPackageJSON, JSON.stringify(packageJSON, null, 2));
|
|
464
|
-
ParserUtils.syncChangelog(packageJSON.version);
|
|
465
526
|
}
|
|
466
527
|
static getPackageJSONInfo(dir) {
|
|
467
528
|
const pathToPackageJSON = path__default.join(dir, "./package.json");
|
|
@@ -540,7 +601,9 @@ class ParserUtils {
|
|
|
540
601
|
${content}`;
|
|
541
602
|
};
|
|
542
603
|
static sortPathParamsByPath = (pathParams, path2) => {
|
|
543
|
-
|
|
604
|
+
const params = path2.match(/{\w*}/g) || [];
|
|
605
|
+
const cleanParams = params.map((param) => param.replace("{", "").replace("}", ""));
|
|
606
|
+
return pathParams.sort((a, b) => cleanParams.indexOf(a.name) - cleanParams.indexOf(b.name));
|
|
544
607
|
};
|
|
545
608
|
}
|
|
546
609
|
const mappedMethod = (httpMethod, isForm) => {
|
|
@@ -608,205 +671,6 @@ const isSwaggerIntegerType = (type) => {
|
|
|
608
671
|
return type === "integer" || type === "int";
|
|
609
672
|
};
|
|
610
673
|
|
|
611
|
-
const Schema = z.object({
|
|
612
|
-
$ref: z.string().nullish(),
|
|
613
|
-
type: z.union([z.literal("array"), z.literal("object"), z.literal("file"), z.literal("string"), z.literal("boolean"), z.literal("integer")]).nullish(),
|
|
614
|
-
items: z.object({
|
|
615
|
-
$ref: z.string().nullish(),
|
|
616
|
-
type: z.string().nullish()
|
|
617
|
-
}).nullish(),
|
|
618
|
-
properties: z.union([z.array(z.string()).nullish(), z.record(z.object({ type: z.string() })).nullish()]),
|
|
619
|
-
description: z.string().nullish(),
|
|
620
|
-
additionalProperties: z.object({
|
|
621
|
-
type: z.string().nullish()
|
|
622
|
-
}).nullish()
|
|
623
|
-
});
|
|
624
|
-
const Definition = z.object({
|
|
625
|
-
required: z.array(z.string()).nullish(),
|
|
626
|
-
properties: z.record(z.object({
|
|
627
|
-
type: z.string()
|
|
628
|
-
})).nullish()
|
|
629
|
-
});
|
|
630
|
-
const Definitions = z.record(Definition);
|
|
631
|
-
const EndpointParametersType = z.enum(["apiKey", "boolean", "int", "integer", "number", "string", "array", "file"]);
|
|
632
|
-
const EndpointParametersIn = z.enum(["body", "formData", "header", "path", "query"]);
|
|
633
|
-
const EndpointParameters = z.object({
|
|
634
|
-
type: EndpointParametersType.nullish(),
|
|
635
|
-
description: z.string().nullish(),
|
|
636
|
-
name: z.string(),
|
|
637
|
-
in: EndpointParametersIn,
|
|
638
|
-
required: z.boolean().nullish(),
|
|
639
|
-
schema: Schema.nullish(),
|
|
640
|
-
default: z.union([z.boolean(), z.string(), z.number(), z.array(z.any())]).nullish(),
|
|
641
|
-
enum: z.array(z.union([z.boolean(), z.string(), z.number()])).nullish(),
|
|
642
|
-
items: z.object({
|
|
643
|
-
type: z.string(),
|
|
644
|
-
enum: z.array(z.any()).nullish()
|
|
645
|
-
}).nullish()
|
|
646
|
-
});
|
|
647
|
-
const Endpoint = z.object({
|
|
648
|
-
description: z.string().nullish(),
|
|
649
|
-
consumes: z.array(z.string()).nullish(),
|
|
650
|
-
produces: z.array(z.string()).nullish(),
|
|
651
|
-
tags: z.array(z.string()).nullish(),
|
|
652
|
-
summary: z.string().nullish(),
|
|
653
|
-
operationId: z.string(),
|
|
654
|
-
deprecated: z.boolean().nullish(),
|
|
655
|
-
responses: z.record(z.object({
|
|
656
|
-
description: z.string().nullish(),
|
|
657
|
-
schema: Schema.nullish(),
|
|
658
|
-
content: z.object({
|
|
659
|
-
"application/json": z.object({
|
|
660
|
-
schema: Schema.nullish()
|
|
661
|
-
})
|
|
662
|
-
}).nullish()
|
|
663
|
-
})),
|
|
664
|
-
parameters: z.array(EndpointParameters).nullish(),
|
|
665
|
-
requestBody: z.object({
|
|
666
|
-
required: z.boolean(),
|
|
667
|
-
content: z.object({
|
|
668
|
-
"application/json": z.object({
|
|
669
|
-
schema: Schema.nullish()
|
|
670
|
-
})
|
|
671
|
-
}).nullish()
|
|
672
|
-
}).nullish()
|
|
673
|
-
});
|
|
674
|
-
const Operation = z.object({
|
|
675
|
-
get: Endpoint.nullish(),
|
|
676
|
-
post: Endpoint.nullish(),
|
|
677
|
-
patch: Endpoint.nullish(),
|
|
678
|
-
delete: Endpoint.nullish(),
|
|
679
|
-
put: Endpoint.nullish()
|
|
680
|
-
});
|
|
681
|
-
const Paths = z.record(Operation);
|
|
682
|
-
z.object({
|
|
683
|
-
paths: Paths,
|
|
684
|
-
definitions: Definitions,
|
|
685
|
-
basePath: z.string(),
|
|
686
|
-
info: z.object({
|
|
687
|
-
description: z.string(),
|
|
688
|
-
title: z.string(),
|
|
689
|
-
contact: z.object({
|
|
690
|
-
name: z.string(),
|
|
691
|
-
url: z.string(),
|
|
692
|
-
email: z.string()
|
|
693
|
-
}),
|
|
694
|
-
version: z.string()
|
|
695
|
-
}),
|
|
696
|
-
schemes: z.array(z.string()).nullish(),
|
|
697
|
-
components: z.object({
|
|
698
|
-
schemas: Definitions
|
|
699
|
-
}).nullish()
|
|
700
|
-
});
|
|
701
|
-
|
|
702
|
-
const templateMethod = ({
|
|
703
|
-
classMethod,
|
|
704
|
-
description,
|
|
705
|
-
httpMethod,
|
|
706
|
-
path,
|
|
707
|
-
pathParams,
|
|
708
|
-
bodyParams,
|
|
709
|
-
queryParams,
|
|
710
|
-
isFormUrlEncoded,
|
|
711
|
-
responseClass
|
|
712
|
-
}) => {
|
|
713
|
-
let methodParams = "";
|
|
714
|
-
let methodParamsNoTypes = "";
|
|
715
|
-
let newPath = `'${path}'`;
|
|
716
|
-
let importStatements = [];
|
|
717
|
-
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path);
|
|
718
|
-
for (const pathParam of sortedPathParams) {
|
|
719
|
-
const type = ParserUtils.parseType(pathParam);
|
|
720
|
-
if (pathParam.name !== "namespace") {
|
|
721
|
-
methodParams += pathParam.name + `:${type}, `;
|
|
722
|
-
methodParamsNoTypes += pathParam.name + ", ";
|
|
723
|
-
}
|
|
724
|
-
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
725
|
-
if (path.match(`{${pathParam.name}}`)) {
|
|
726
|
-
if (type === "string") {
|
|
727
|
-
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
728
|
-
} else {
|
|
729
|
-
newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
}
|
|
733
|
-
let dataType = null;
|
|
734
|
-
if (httpMethod !== "get") {
|
|
735
|
-
dataType = ParserUtils.parseBodyParamsType(bodyParams);
|
|
736
|
-
importStatements = ParserUtils.parseBodyParamsImports(bodyParams);
|
|
737
|
-
methodParams += dataType ? `data: ${dataType},` : "";
|
|
738
|
-
methodParamsNoTypes += dataType ? `data,` : "";
|
|
739
|
-
}
|
|
740
|
-
const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
|
|
741
|
-
const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
|
|
742
|
-
const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as SDKRequestConfig` : "const params = {} as SDKRequestConfig";
|
|
743
|
-
const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
|
|
744
|
-
const isDelete = ["delete"].includes(httpMethod);
|
|
745
|
-
let dataPayload = "{params}";
|
|
746
|
-
const descriptionText = description ? `
|
|
747
|
-
/**
|
|
748
|
-
* ${description.replace(/\n/g, "\n * ")}
|
|
749
|
-
*/` : "";
|
|
750
|
-
let formPayloadString = "";
|
|
751
|
-
if (isFormUrlEncoded) {
|
|
752
|
-
formPayloadString = ``;
|
|
753
|
-
const params = "{ ...params, headers: { ...params.headers, 'content-type': 'application/x-www-form-urlencoded' } }";
|
|
754
|
-
dataPayload = dataType ? `CodeGenUtil.getFormUrlEncodedData(data), ${params}` : `null, ${params}`;
|
|
755
|
-
} else if (isPostPutPatch) {
|
|
756
|
-
dataPayload = dataType ? `data, {params}` : "null, {params}";
|
|
757
|
-
} else if (isDelete) {
|
|
758
|
-
dataPayload = dataType ? `{data, params}` : "{params}";
|
|
759
|
-
}
|
|
760
|
-
const isFileUpload = methodParams.indexOf("data: {file") > -1;
|
|
761
|
-
const resolvedResponseClass = responseClass || "unknown";
|
|
762
|
-
const resolvedResponseClassValidated = responseClass || "z.unknown()";
|
|
763
|
-
methodParams = (queryParamsType ? `${methodParams} ${queryParamsType}` : methodParams).replace(/,\s*$/, "");
|
|
764
|
-
methodParamsNoTypes = queryParamsType ? `${methodParamsNoTypes} queryParams` : methodParamsNoTypes;
|
|
765
|
-
let methodImpl = "";
|
|
766
|
-
const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
|
|
767
|
-
const cachedFetchMethod = classMethod;
|
|
768
|
-
const deprecateTag = isCacheFetch ? `/**
|
|
769
|
-
* @deprecated Use "${classMethod}()" instead.
|
|
770
|
-
*/` : "";
|
|
771
|
-
const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
|
|
772
|
-
const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
|
|
773
|
-
const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
|
|
774
|
-
const generateMethodName = () => `${methodName}(${methodParams}): Promise<${responseSyncType}<${responseType}>>`;
|
|
775
|
-
const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
|
|
776
|
-
methodImpl = `${descriptionText}
|
|
777
|
-
${generateMethodName()} {
|
|
778
|
-
${queryParamsDefault}
|
|
779
|
-
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
780
|
-
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
781
|
-
|
|
782
|
-
${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')
|
|
783
|
-
|
|
784
|
-
if (!this.cache) {
|
|
785
|
-
return SdkCache.withoutCache(res)
|
|
786
|
-
}
|
|
787
|
-
const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
|
|
788
|
-
return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')` : ""}
|
|
789
|
-
}
|
|
790
|
-
`;
|
|
791
|
-
if (!isGuardInvoked) {
|
|
792
|
-
methodImpl = `${descriptionText}
|
|
793
|
-
${deprecateTag}
|
|
794
|
-
TODO_${classMethod}(${methodParams}): Promise<AxiosResponse<${resolvedResponseClass}>> {
|
|
795
|
-
${queryParamsDefault}
|
|
796
|
-
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
797
|
-
return this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
798
|
-
}
|
|
799
|
-
`;
|
|
800
|
-
}
|
|
801
|
-
const res = {
|
|
802
|
-
methodImpl,
|
|
803
|
-
methodParams,
|
|
804
|
-
methodParamsNoTypes,
|
|
805
|
-
importStatements
|
|
806
|
-
};
|
|
807
|
-
return res;
|
|
808
|
-
};
|
|
809
|
-
|
|
810
674
|
class TemplateZod {
|
|
811
675
|
duplicates;
|
|
812
676
|
duplicateFound = false;
|
|
@@ -891,7 +755,13 @@ ${exportedTypeString}
|
|
|
891
755
|
const schemaAttribute = name ? `'${name}':` : "";
|
|
892
756
|
const typeAttribute = name ? `'${name}'${typeRequired}:` : "";
|
|
893
757
|
const type = definition?.type;
|
|
894
|
-
if (
|
|
758
|
+
if (definition.properties) {
|
|
759
|
+
const result = this.parseToZodSchema(definition, requiredAttrs);
|
|
760
|
+
return {
|
|
761
|
+
schemaString: `${schemaAttribute} ${result.schemaString}${schemaRequired}`,
|
|
762
|
+
typeString: `${typeAttribute} ${result.typeString}${typeNullishability}`
|
|
763
|
+
};
|
|
764
|
+
} else if (type) {
|
|
895
765
|
if (type === "object" && definition.additionalProperties) {
|
|
896
766
|
const zodAttribute = this.parseToZodAttribute("", definition.additionalProperties, [""]);
|
|
897
767
|
return {
|
|
@@ -967,12 +837,6 @@ ${exportedTypeString}
|
|
|
967
837
|
typeString: `${typeAttribute} ${result.typeString}`
|
|
968
838
|
};
|
|
969
839
|
}
|
|
970
|
-
} else if (definition.properties) {
|
|
971
|
-
const result = this.parseToZodSchema(definition, requiredAttrs);
|
|
972
|
-
return {
|
|
973
|
-
schemaString: `${schemaAttribute} ${result.schemaString}${schemaRequired}`,
|
|
974
|
-
typeString: `${typeAttribute} ${result.typeString}${typeNullishability}`
|
|
975
|
-
};
|
|
976
840
|
}
|
|
977
841
|
const ref = definition.$ref;
|
|
978
842
|
let model = `z.record(z.any())`;
|
|
@@ -1059,29 +923,250 @@ const extractEnumObject = (type, isRequired, enumArr) => {
|
|
|
1059
923
|
};
|
|
1060
924
|
};
|
|
1061
925
|
|
|
1062
|
-
const
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
926
|
+
const templateApiIndex = (serviceName, serviceNameTitle, apiList) => {
|
|
927
|
+
let imports = "";
|
|
928
|
+
let returnStatement = "";
|
|
929
|
+
for (const cl of apiList) {
|
|
930
|
+
imports += `
|
|
931
|
+
import { ${cl} } from './${serviceName}/${cl}.js'`;
|
|
932
|
+
returnStatement += `
|
|
933
|
+
${cl}, `;
|
|
934
|
+
}
|
|
935
|
+
return `/**
|
|
936
|
+
* AUTO GENERATED
|
|
937
|
+
*/
|
|
938
|
+
${imports}
|
|
939
|
+
|
|
940
|
+
const apis = {
|
|
941
|
+
${returnStatement}
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
export const ${ParserUtils.convertDashesToTitleCase(serviceNameTitle)} = apis
|
|
945
|
+
`;
|
|
946
|
+
};
|
|
947
|
+
|
|
948
|
+
const Schema = z.object({
|
|
949
|
+
$ref: z.string().nullish(),
|
|
950
|
+
type: z.union([z.literal("array"), z.literal("object"), z.literal("file"), z.literal("string"), z.literal("boolean"), z.literal("integer")]).nullish(),
|
|
951
|
+
items: z.object({
|
|
952
|
+
$ref: z.string().nullish(),
|
|
953
|
+
type: z.string().nullish()
|
|
954
|
+
}).nullish(),
|
|
955
|
+
properties: z.union([z.array(z.string()).nullish(), z.record(z.object({ type: z.string() })).nullish()]),
|
|
956
|
+
description: z.string().nullish(),
|
|
957
|
+
additionalProperties: z.object({
|
|
958
|
+
type: z.string().nullish()
|
|
959
|
+
}).nullish()
|
|
960
|
+
});
|
|
961
|
+
const Definition = z.object({
|
|
962
|
+
required: z.array(z.string()).nullish(),
|
|
963
|
+
properties: z.record(z.object({
|
|
964
|
+
type: z.string()
|
|
965
|
+
})).nullish()
|
|
966
|
+
});
|
|
967
|
+
const Definitions = z.record(Definition);
|
|
968
|
+
const EndpointParametersType = z.enum(["apiKey", "boolean", "int", "integer", "number", "string", "array", "file"]);
|
|
969
|
+
const EndpointParametersIn = z.enum(["body", "formData", "header", "path", "query"]);
|
|
970
|
+
const EndpointParameters = z.object({
|
|
971
|
+
type: EndpointParametersType.nullish(),
|
|
972
|
+
description: z.string().nullish(),
|
|
973
|
+
name: z.string(),
|
|
974
|
+
in: EndpointParametersIn,
|
|
975
|
+
required: z.boolean().nullish(),
|
|
976
|
+
schema: Schema.nullish(),
|
|
977
|
+
default: z.union([z.boolean(), z.string(), z.number(), z.array(z.any())]).nullish(),
|
|
978
|
+
enum: z.array(z.union([z.boolean(), z.string(), z.number()])).nullish(),
|
|
979
|
+
items: z.object({
|
|
980
|
+
type: z.string(),
|
|
981
|
+
enum: z.array(z.any()).nullish()
|
|
982
|
+
}).nullish()
|
|
983
|
+
});
|
|
984
|
+
const Endpoint = z.object({
|
|
985
|
+
description: z.string().nullish(),
|
|
986
|
+
consumes: z.array(z.string()).nullish(),
|
|
987
|
+
produces: z.array(z.string()).nullish(),
|
|
988
|
+
tags: z.array(z.string()).nullish(),
|
|
989
|
+
summary: z.string().nullish(),
|
|
990
|
+
operationId: z.string(),
|
|
991
|
+
deprecated: z.boolean().nullish(),
|
|
992
|
+
responses: z.record(z.object({
|
|
993
|
+
description: z.string().nullish(),
|
|
994
|
+
schema: Schema.nullish(),
|
|
995
|
+
content: z.object({
|
|
996
|
+
"application/json": z.object({
|
|
997
|
+
schema: Schema.nullish()
|
|
998
|
+
})
|
|
999
|
+
}).nullish()
|
|
1000
|
+
})),
|
|
1001
|
+
parameters: z.array(EndpointParameters).nullish(),
|
|
1002
|
+
requestBody: z.object({
|
|
1003
|
+
required: z.boolean(),
|
|
1004
|
+
content: z.object({
|
|
1005
|
+
"application/json": z.object({
|
|
1006
|
+
schema: Schema.nullish()
|
|
1007
|
+
})
|
|
1008
|
+
}).nullish()
|
|
1009
|
+
}).nullish()
|
|
1010
|
+
});
|
|
1011
|
+
const Operation = z.object({
|
|
1012
|
+
get: Endpoint.nullish(),
|
|
1013
|
+
post: Endpoint.nullish(),
|
|
1014
|
+
patch: Endpoint.nullish(),
|
|
1015
|
+
delete: Endpoint.nullish(),
|
|
1016
|
+
put: Endpoint.nullish()
|
|
1017
|
+
});
|
|
1018
|
+
const Paths = z.record(Operation);
|
|
1019
|
+
z.object({
|
|
1020
|
+
paths: Paths,
|
|
1021
|
+
definitions: Definitions,
|
|
1022
|
+
basePath: z.string(),
|
|
1023
|
+
info: z.object({
|
|
1024
|
+
description: z.string(),
|
|
1025
|
+
title: z.string(),
|
|
1026
|
+
contact: z.object({
|
|
1027
|
+
name: z.string(),
|
|
1028
|
+
url: z.string(),
|
|
1029
|
+
email: z.string()
|
|
1030
|
+
}),
|
|
1031
|
+
version: z.string()
|
|
1032
|
+
}),
|
|
1033
|
+
schemes: z.array(z.string()).nullish(),
|
|
1034
|
+
components: z.object({
|
|
1035
|
+
schemas: Definitions
|
|
1036
|
+
}).nullish()
|
|
1037
|
+
});
|
|
1038
|
+
|
|
1039
|
+
const templateMethod = ({
|
|
1040
|
+
classMethod,
|
|
1041
|
+
description,
|
|
1042
|
+
httpMethod,
|
|
1043
|
+
path,
|
|
1044
|
+
pathParams,
|
|
1045
|
+
bodyParams,
|
|
1046
|
+
queryParams,
|
|
1047
|
+
isFormUrlEncoded,
|
|
1048
|
+
responseClass
|
|
1049
|
+
}) => {
|
|
1050
|
+
let methodParams = "";
|
|
1051
|
+
let methodParamsNoTypes = "";
|
|
1052
|
+
let newPath = `'${path}'`;
|
|
1053
|
+
let importStatements = [];
|
|
1054
|
+
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path);
|
|
1055
|
+
for (const pathParam of sortedPathParams) {
|
|
1056
|
+
const type = ParserUtils.parseType(pathParam);
|
|
1057
|
+
if (pathParam.name !== "namespace") {
|
|
1058
|
+
methodParams += pathParam.name + `:${type}, `;
|
|
1059
|
+
methodParamsNoTypes += pathParam.name + ", ";
|
|
1060
|
+
}
|
|
1061
|
+
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
1062
|
+
if (path.match(`{${pathParam.name}}`)) {
|
|
1063
|
+
if (type === "string") {
|
|
1064
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
1065
|
+
} else {
|
|
1066
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
}
|
|
1070
|
+
let dataType = null;
|
|
1071
|
+
if (httpMethod !== "get") {
|
|
1072
|
+
dataType = ParserUtils.parseBodyParamsType(bodyParams);
|
|
1073
|
+
importStatements = ParserUtils.parseBodyParamsImports(bodyParams);
|
|
1074
|
+
methodParams += dataType ? `data: ${dataType},` : "";
|
|
1075
|
+
methodParamsNoTypes += dataType ? `data,` : "";
|
|
1076
|
+
}
|
|
1077
|
+
const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
|
|
1078
|
+
const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
|
|
1079
|
+
const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as SDKRequestConfig` : "const params = {} as SDKRequestConfig";
|
|
1080
|
+
const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
|
|
1081
|
+
const isDelete = ["delete"].includes(httpMethod);
|
|
1082
|
+
let dataPayload = "{params}";
|
|
1083
|
+
const descriptionText = description ? `
|
|
1084
|
+
/**
|
|
1085
|
+
* ${description.replace(/\n/g, "\n * ")}
|
|
1086
|
+
*/` : "";
|
|
1087
|
+
let formPayloadString = "";
|
|
1088
|
+
if (isFormUrlEncoded) {
|
|
1089
|
+
formPayloadString = ``;
|
|
1090
|
+
const params = "{ ...params, headers: { ...params.headers, 'content-type': 'application/x-www-form-urlencoded' } }";
|
|
1091
|
+
dataPayload = dataType ? `CodeGenUtil.getFormUrlEncodedData(data), ${params}` : `null, ${params}`;
|
|
1092
|
+
} else if (isPostPutPatch) {
|
|
1093
|
+
dataPayload = dataType ? `data, {params}` : "null, {params}";
|
|
1094
|
+
} else if (isDelete) {
|
|
1095
|
+
dataPayload = dataType ? `{data, params}` : "{params}";
|
|
1096
|
+
}
|
|
1097
|
+
const isFileUpload = methodParams.indexOf("data: {file") > -1;
|
|
1098
|
+
const resolvedResponseClass = responseClass || "unknown";
|
|
1099
|
+
const resolvedResponseClassValidated = responseClass || "z.unknown()";
|
|
1100
|
+
methodParams = (queryParamsType ? `${methodParams} ${queryParamsType}` : methodParams).replace(/,\s*$/, "");
|
|
1101
|
+
methodParamsNoTypes = queryParamsType ? `${methodParamsNoTypes} queryParams` : methodParamsNoTypes;
|
|
1102
|
+
let methodImpl = "";
|
|
1103
|
+
const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
|
|
1104
|
+
const cachedFetchMethod = classMethod;
|
|
1105
|
+
const deprecateTag = isCacheFetch ? `/**
|
|
1106
|
+
* @deprecated Use "${classMethod}()" instead.
|
|
1107
|
+
*/` : "";
|
|
1108
|
+
const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
|
|
1109
|
+
const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
|
|
1110
|
+
const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
|
|
1111
|
+
const generateMethodName = () => `${methodName}(${methodParams}): Promise<${responseSyncType}<${responseType}>>`;
|
|
1112
|
+
const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
|
|
1113
|
+
methodImpl = `${descriptionText}
|
|
1114
|
+
${generateMethodName()} {
|
|
1115
|
+
${queryParamsDefault}
|
|
1116
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
1117
|
+
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
1118
|
+
|
|
1119
|
+
${httpMethod === "get" ? ` const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')
|
|
1120
|
+
|
|
1121
|
+
if (!this.cache) {
|
|
1122
|
+
return SdkCache.withoutCache(res)
|
|
1123
|
+
}
|
|
1124
|
+
const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
|
|
1125
|
+
return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? ` return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')` : ""}
|
|
1126
|
+
}
|
|
1127
|
+
`;
|
|
1128
|
+
if (!isGuardInvoked) {
|
|
1129
|
+
methodImpl = `${descriptionText}
|
|
1130
|
+
${deprecateTag}
|
|
1131
|
+
TODO_${classMethod}(${methodParams}): Promise<AxiosResponse<${resolvedResponseClass}>> {
|
|
1132
|
+
${queryParamsDefault}
|
|
1133
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
1134
|
+
return this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
1135
|
+
}
|
|
1136
|
+
`;
|
|
1137
|
+
}
|
|
1138
|
+
const res = {
|
|
1139
|
+
methodImpl,
|
|
1140
|
+
methodParams,
|
|
1141
|
+
methodParamsNoTypes,
|
|
1142
|
+
importStatements
|
|
1143
|
+
};
|
|
1144
|
+
return res;
|
|
1145
|
+
};
|
|
1146
|
+
|
|
1147
|
+
const templateApiMethod = ({
|
|
1148
|
+
classMethod,
|
|
1149
|
+
description,
|
|
1150
|
+
httpMethod,
|
|
1151
|
+
path,
|
|
1152
|
+
pathParams,
|
|
1153
|
+
bodyParams,
|
|
1154
|
+
responseClass,
|
|
1155
|
+
classGenName,
|
|
1156
|
+
methodParams,
|
|
1157
|
+
methodParamsNoTypes
|
|
1158
|
+
}) => {
|
|
1159
|
+
let methodSignature = "";
|
|
1160
|
+
let newPath = `'${path}'`;
|
|
1161
|
+
let snippetSdk = "";
|
|
1162
|
+
let snippetShell = "";
|
|
1163
|
+
for (const pathParam of pathParams) {
|
|
1164
|
+
const type = ParserUtils.parseType(pathParam);
|
|
1165
|
+
if (pathParam.name !== "namespace") {
|
|
1166
|
+
methodSignature += pathParam.name + `:${type}, `;
|
|
1167
|
+
}
|
|
1168
|
+
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
1169
|
+
if (path.match(`{${pathParam.name}}`)) {
|
|
1085
1170
|
if (type === "string") {
|
|
1086
1171
|
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
1087
1172
|
} else {
|
|
@@ -1120,28 +1205,6 @@ const templateApiMethod = ({
|
|
|
1120
1205
|
return [methodImpl, snippetSdk, snippetShell];
|
|
1121
1206
|
};
|
|
1122
1207
|
|
|
1123
|
-
const templateApiIndex = (serviceName, serviceNameTitle, apiList) => {
|
|
1124
|
-
let imports = "";
|
|
1125
|
-
let returnStatement = "";
|
|
1126
|
-
for (const cl of apiList) {
|
|
1127
|
-
imports += `
|
|
1128
|
-
import { ${cl} } from './${serviceName}/${cl}.js'`;
|
|
1129
|
-
returnStatement += `
|
|
1130
|
-
${cl}, `;
|
|
1131
|
-
}
|
|
1132
|
-
return `/**
|
|
1133
|
-
* AUTO GENERATED
|
|
1134
|
-
*/
|
|
1135
|
-
${imports}
|
|
1136
|
-
|
|
1137
|
-
const apis = {
|
|
1138
|
-
${returnStatement}
|
|
1139
|
-
}
|
|
1140
|
-
|
|
1141
|
-
export const ${ParserUtils.convertDashesToTitleCase(serviceNameTitle)} = apis
|
|
1142
|
-
`;
|
|
1143
|
-
};
|
|
1144
|
-
|
|
1145
1208
|
const templateSdkSnippet = (serviceNameTitle, apiName, methodSnippet) => {
|
|
1146
1209
|
const methodArr = methodSnippet.split("//");
|
|
1147
1210
|
let normMethod = normalizeMethodSnippet(methodArr[0].trim(), "data:");
|
|
@@ -1181,21 +1244,33 @@ const normalizeMethodSnippet = (methodInput, splitWord) => {
|
|
|
1181
1244
|
};
|
|
1182
1245
|
|
|
1183
1246
|
const GIT_URL = "https://github.com/AccelByte/accelbyte-web-sdk/blob/main/packages";
|
|
1184
|
-
class
|
|
1185
|
-
static getPatchedDir = () => path__default.join(CliParser.getSwaggersOutputPath(), "patched");
|
|
1186
|
-
static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
|
|
1187
|
-
static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
|
|
1188
|
-
static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
|
|
1247
|
+
class SwaggerReaderHelpers {
|
|
1189
1248
|
static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
|
|
1190
|
-
static
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
const
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1249
|
+
static parseAllEndpoints = async ({
|
|
1250
|
+
api,
|
|
1251
|
+
sdkName,
|
|
1252
|
+
serviceName
|
|
1253
|
+
}) => {
|
|
1254
|
+
const result = {
|
|
1255
|
+
admin: {
|
|
1256
|
+
arrayDefinitions: [],
|
|
1257
|
+
snippetMap: {},
|
|
1258
|
+
tagToClassImportsRecord: {},
|
|
1259
|
+
tagToEndpointClassesRecord: {},
|
|
1260
|
+
tagToSdkClientRecord: {},
|
|
1261
|
+
tagToSdkFunctionNamesRecord: {},
|
|
1262
|
+
tagToSdkImportsRecord: {}
|
|
1263
|
+
},
|
|
1264
|
+
public: {
|
|
1265
|
+
arrayDefinitions: [],
|
|
1266
|
+
snippetMap: {},
|
|
1267
|
+
tagToClassImportsRecord: {},
|
|
1268
|
+
tagToEndpointClassesRecord: {},
|
|
1269
|
+
tagToSdkClientRecord: {},
|
|
1270
|
+
tagToSdkFunctionNamesRecord: {},
|
|
1271
|
+
tagToSdkImportsRecord: {}
|
|
1272
|
+
}
|
|
1273
|
+
};
|
|
1199
1274
|
const sortedPathsByLength = new Map(Object.entries(api.paths).sort((a, b) => {
|
|
1200
1275
|
if (a[0].length === b[0].length) {
|
|
1201
1276
|
return a[0].localeCompare(b[0]);
|
|
@@ -1204,55 +1279,62 @@ class CodeGenerator {
|
|
|
1204
1279
|
}
|
|
1205
1280
|
}));
|
|
1206
1281
|
const sortedKeys = Array.from(sortedPathsByLength.keys());
|
|
1207
|
-
const servicePrefix =
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
} else if (path2.indexOf("/healthz") >= 0) {
|
|
1282
|
+
const servicePrefix = SwaggerReaderHelpers.getServicePrefix(sortedKeys);
|
|
1283
|
+
const tagToClassMethodsMap = {
|
|
1284
|
+
admin: {},
|
|
1285
|
+
public: {}
|
|
1286
|
+
};
|
|
1287
|
+
for (const [path, operation] of sortedPathsByLength) {
|
|
1288
|
+
if (path.indexOf("/healthz") >= 0) {
|
|
1215
1289
|
continue;
|
|
1216
1290
|
}
|
|
1291
|
+
const isAdminEndpoint = path.indexOf("/admin/") > -1;
|
|
1292
|
+
const picked = isAdminEndpoint ? result.admin : result.public;
|
|
1293
|
+
const {
|
|
1294
|
+
arrayDefinitions,
|
|
1295
|
+
snippetMap,
|
|
1296
|
+
tagToClassImportsRecord,
|
|
1297
|
+
tagToEndpointClassesRecord,
|
|
1298
|
+
tagToSdkClientRecord,
|
|
1299
|
+
tagToSdkFunctionNamesRecord,
|
|
1300
|
+
tagToSdkImportsRecord
|
|
1301
|
+
} = picked;
|
|
1302
|
+
const tagToClassMethodsMapByType = isAdminEndpoint ? tagToClassMethodsMap.admin : tagToClassMethodsMap.public;
|
|
1217
1303
|
const httpMethods = Object.keys(operation);
|
|
1218
1304
|
for (const httpMethod of httpMethods) {
|
|
1219
1305
|
const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
|
|
1220
|
-
console.error(JSON.stringify({ path
|
|
1306
|
+
console.error(JSON.stringify({ path, httpMethod }, null, 2));
|
|
1221
1307
|
throw error;
|
|
1222
1308
|
});
|
|
1223
|
-
if (!endpoint.tags)
|
|
1309
|
+
if (!endpoint.tags || endpoint.deprecated)
|
|
1224
1310
|
continue;
|
|
1225
|
-
}
|
|
1226
|
-
if (endpoint.deprecated) {
|
|
1227
|
-
continue;
|
|
1228
|
-
}
|
|
1229
1311
|
const [tag] = endpoint.tags;
|
|
1230
|
-
|
|
1312
|
+
const pathWithBase = `${api.basePath ?? ""}${path}`;
|
|
1313
|
+
tagToClassMethodsMapByType[tag] = tagToClassMethodsMapByType[tag] ? tagToClassMethodsMapByType[tag] : {};
|
|
1231
1314
|
const isForm = endpoint.consumes && endpoint.consumes[0] === "application/x-www-form-urlencoded";
|
|
1232
1315
|
const classMethod = ParserUtils.generateNaturalLangMethod({
|
|
1233
1316
|
servicePrefix,
|
|
1234
|
-
path
|
|
1317
|
+
path,
|
|
1235
1318
|
httpMethod,
|
|
1236
1319
|
isForm,
|
|
1237
|
-
existingMethods:
|
|
1320
|
+
existingMethods: tagToClassMethodsMapByType[tag]
|
|
1238
1321
|
});
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
description = description
|
|
1322
|
+
tagToClassMethodsMapByType[tag][classMethod] = `${path} ${httpMethod}`;
|
|
1323
|
+
if (!snippetMap[pathWithBase]) {
|
|
1324
|
+
snippetMap[pathWithBase] = {};
|
|
1325
|
+
}
|
|
1326
|
+
const description = endpoint.description?.replace(/\s+/g, " ") || "";
|
|
1244
1327
|
const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
|
|
1245
|
-
const { className, classGenName } = ParserUtils.generateClassName(tag);
|
|
1246
|
-
|
|
1328
|
+
const { className, classGenName } = ParserUtils.generateClassName(tag, isAdminEndpoint);
|
|
1329
|
+
tagToClassImportsRecord[className] = tagToClassImportsRecord[className] ? tagToClassImportsRecord[className] : {};
|
|
1247
1330
|
if (responseClass) {
|
|
1248
1331
|
const importTypeClass = ParserUtils.parseRefType(responseClass);
|
|
1249
|
-
|
|
1332
|
+
tagToClassImportsRecord[className][importTypeClass] = `import { ${importTypeClass} } from '../definitions/${importTypeClass}.js'`;
|
|
1250
1333
|
}
|
|
1251
1334
|
if (responseClass && responseClass.endsWith("Array")) {
|
|
1252
1335
|
arrayDefinitions.push(responseClass);
|
|
1253
1336
|
}
|
|
1254
1337
|
const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
|
|
1255
|
-
const pathWithBase = `${api.basePath ?? ""}${path2}`;
|
|
1256
1338
|
const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
|
|
1257
1339
|
const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
|
|
1258
1340
|
let bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
|
|
@@ -1276,8 +1358,8 @@ class CodeGenerator {
|
|
|
1276
1358
|
isFormUrlEncoded,
|
|
1277
1359
|
responseClass
|
|
1278
1360
|
});
|
|
1279
|
-
|
|
1280
|
-
const [
|
|
1361
|
+
tagToEndpointClassesRecord[tag] = (tagToEndpointClassesRecord[tag] || "") + methodImpl;
|
|
1362
|
+
const [generatedMethodString, snippetMethod, snippetShell] = templateApiMethod({
|
|
1281
1363
|
classMethod,
|
|
1282
1364
|
description,
|
|
1283
1365
|
httpMethod,
|
|
@@ -1289,32 +1371,37 @@ class CodeGenerator {
|
|
|
1289
1371
|
methodParams,
|
|
1290
1372
|
methodParamsNoTypes
|
|
1291
1373
|
});
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1374
|
+
tagToSdkClientRecord[tag] = (tagToSdkClientRecord[tag] || "") + generatedMethodString;
|
|
1375
|
+
tagToSdkFunctionNamesRecord[tag] = (tagToSdkFunctionNamesRecord[tag] || "") + classMethod + ",";
|
|
1376
|
+
tagToSdkImportsRecord[tag] = tagToSdkImportsRecord[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...tagToSdkImportsRecord[tag]])] : [...new Set(importStatements)];
|
|
1295
1377
|
const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
|
|
1296
|
-
const { apiGenName } = ParserUtils.generateApiName(tag);
|
|
1378
|
+
const { apiGenName } = ParserUtils.generateApiName(tag, isAdminEndpoint);
|
|
1297
1379
|
const resultSnippet = templateSdkSnippet(serviceNameTitle, apiGenName, snippetMethod);
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1380
|
+
const currentSnippetMap = {};
|
|
1381
|
+
snippetMap[pathWithBase][httpMethod] = currentSnippetMap;
|
|
1382
|
+
if (!isAdminEndpoint) {
|
|
1383
|
+
currentSnippetMap.web = !isAdminEndpoint ? resultSnippet : "";
|
|
1384
|
+
currentSnippetMap.webGit = !isAdminEndpoint ? GIT_URL + `/sdk-${sdkName}/src/generated-public/${serviceName}/${apiGenName}.ts` : "";
|
|
1385
|
+
}
|
|
1386
|
+
currentSnippetMap.shell = snippetShell;
|
|
1303
1387
|
}
|
|
1304
1388
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
classBufferByTag,
|
|
1310
|
-
dependenciesByTag,
|
|
1311
|
-
classImports,
|
|
1312
|
-
arrayDefinitions,
|
|
1313
|
-
snippetMap
|
|
1314
|
-
};
|
|
1389
|
+
for (const key in result) {
|
|
1390
|
+
result[key].arrayDefinitions = Array.from(new Set(result[key].arrayDefinitions));
|
|
1391
|
+
}
|
|
1392
|
+
return result;
|
|
1315
1393
|
};
|
|
1394
|
+
}
|
|
1395
|
+
|
|
1396
|
+
class CodeGenerator {
|
|
1397
|
+
static getPatchedDir = () => path__default.join(CliParser.getSwaggersOutputPath(), "patched");
|
|
1398
|
+
static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
|
|
1399
|
+
static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
|
|
1400
|
+
static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
|
|
1401
|
+
static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
|
|
1316
1402
|
static main = async (nameArray) => {
|
|
1317
1403
|
const serviceName = nameArray[0];
|
|
1404
|
+
const sdkName = nameArray[1];
|
|
1318
1405
|
const swaggerFile = nameArray[2];
|
|
1319
1406
|
const parser = new SwaggerParser();
|
|
1320
1407
|
const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
|
|
@@ -1324,31 +1411,44 @@ class CodeGenerator {
|
|
|
1324
1411
|
const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
|
|
1325
1412
|
const api = await parser.parse(swaggerFilePath);
|
|
1326
1413
|
const indexImportsSet = /* @__PURE__ */ new Set();
|
|
1327
|
-
|
|
1414
|
+
const apiInfo = { ...api.info, "x-version": api["x-version"]?.version };
|
|
1415
|
+
console.log("----------\nGenerating API:", { title: apiInfo.title, version: apiInfo.version });
|
|
1328
1416
|
ParserUtils.mkdirIfNotExist(DIST_DIR);
|
|
1329
1417
|
ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
|
|
1330
1418
|
ParserUtils.mkdirIfNotExist(DIST_ENDPOINTS_DIR);
|
|
1331
|
-
ParserUtils.syncPackageVersion(
|
|
1332
|
-
const
|
|
1419
|
+
ParserUtils.syncPackageVersion(apiInfo, CliParser.skipVersionSync(), process.env.PRERELEASE_ID);
|
|
1420
|
+
const parsedInformation = await SwaggerReaderHelpers.parseAllEndpoints({ api, sdkName, serviceName });
|
|
1421
|
+
const parsedInformationByType = CliParser.isAdmin() ? parsedInformation.admin : parsedInformation.public;
|
|
1422
|
+
const {
|
|
1423
|
+
arrayDefinitions,
|
|
1424
|
+
tagToClassImportsRecord,
|
|
1425
|
+
tagToEndpointClassesRecord,
|
|
1426
|
+
tagToSdkClientRecord,
|
|
1427
|
+
tagToSdkFunctionNamesRecord,
|
|
1428
|
+
tagToSdkImportsRecord
|
|
1429
|
+
} = parsedInformationByType;
|
|
1333
1430
|
if (CliParser.getSnippetOutputPath()) {
|
|
1334
1431
|
try {
|
|
1335
|
-
ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify(
|
|
1432
|
+
ParserUtils.writeSnippetFile(CodeGenerator.getGeneratedSnippetsFolder(), api.info.title, JSON.stringify({
|
|
1433
|
+
...parsedInformation.public.snippetMap,
|
|
1434
|
+
...parsedInformation.admin.snippetMap
|
|
1435
|
+
}, null, 2));
|
|
1336
1436
|
} catch (err) {
|
|
1337
1437
|
console.log("Generating snippets", err);
|
|
1338
1438
|
}
|
|
1339
1439
|
}
|
|
1340
1440
|
const targetSrcFolder = `${CliParser.getOutputPath()}/`;
|
|
1341
1441
|
const apiList = [];
|
|
1342
|
-
for (const tag in
|
|
1343
|
-
const { className, classGenName } = ParserUtils.generateClassName(tag);
|
|
1344
|
-
const classBuffer =
|
|
1345
|
-
const imports = [.../* @__PURE__ */ new Set([...
|
|
1346
|
-
const apiImports = [.../* @__PURE__ */ new Set([...
|
|
1442
|
+
for (const tag in tagToEndpointClassesRecord) {
|
|
1443
|
+
const { className, classGenName } = ParserUtils.generateClassName(tag, CliParser.isAdmin());
|
|
1444
|
+
const classBuffer = tagToEndpointClassesRecord[tag];
|
|
1445
|
+
const imports = [.../* @__PURE__ */ new Set([...tagToSdkImportsRecord[tag], ...Object.values(tagToClassImportsRecord[className])])];
|
|
1446
|
+
const apiImports = [.../* @__PURE__ */ new Set([...tagToSdkImportsRecord[tag], ...Object.values(tagToClassImportsRecord[className])])];
|
|
1347
1447
|
apiImports.push(`import { ${classGenName} } from './endpoints/${classGenName}.js'`);
|
|
1348
1448
|
ParserUtils.writeClassFile(DIST_ENDPOINTS_DIR, classGenName, classBuffer, imports);
|
|
1349
|
-
const apiBuffer =
|
|
1350
|
-
const { apiGenName } = ParserUtils.generateApiName(tag);
|
|
1351
|
-
ParserUtils.writeApiFile(DIST_DIR, apiGenName, apiBuffer, apiImports,
|
|
1449
|
+
const apiBuffer = tagToSdkClientRecord[tag];
|
|
1450
|
+
const { apiGenName } = ParserUtils.generateApiName(tag, CliParser.isAdmin());
|
|
1451
|
+
ParserUtils.writeApiFile(DIST_DIR, apiGenName, apiBuffer, apiImports, tagToSdkFunctionNamesRecord[tag]);
|
|
1352
1452
|
apiList.push(apiGenName);
|
|
1353
1453
|
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_ENDPOINTS_DIR, `${classGenName}`), targetSrcFolder));
|
|
1354
1454
|
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path__default.join(DIST_DIR, `${apiGenName}`), targetSrcFolder));
|
|
@@ -1418,33 +1518,36 @@ class SwaggerDownloader {
|
|
|
1418
1518
|
});
|
|
1419
1519
|
});
|
|
1420
1520
|
};
|
|
1421
|
-
static downloadFile = (targetFileName, url) => {
|
|
1521
|
+
static downloadFile = async (targetFileName, url) => {
|
|
1422
1522
|
const destFile = SwaggerDownloader.getDestFile(targetFileName);
|
|
1423
1523
|
let data = "";
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
data
|
|
1524
|
+
return new Promise((resolve) => {
|
|
1525
|
+
const request = https.get(url, function(response) {
|
|
1526
|
+
response.on("data", (chunk) => {
|
|
1527
|
+
data += chunk;
|
|
1528
|
+
});
|
|
1529
|
+
response.on("end", () => {
|
|
1530
|
+
if (response.statusCode !== 200) {
|
|
1531
|
+
console.log(`SwaggerDownload error with status code: ${response.statusCode}`);
|
|
1532
|
+
} else {
|
|
1533
|
+
fs.writeFileSync(destFile, JSON.stringify(JSON.parse(data), null, 2), "utf-8");
|
|
1534
|
+
SwaggerDownloader.postSanitizeDownloadedFile(destFile);
|
|
1535
|
+
console.log(`SwaggerDownload ${url} completed with status code: ${response.statusCode}`);
|
|
1536
|
+
}
|
|
1537
|
+
resolve(void 0);
|
|
1538
|
+
});
|
|
1427
1539
|
});
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
console.log(`SwaggerDownload error with status code: ${response.statusCode}`);
|
|
1431
|
-
} else {
|
|
1432
|
-
fs.writeFileSync(destFile, JSON.stringify(JSON.parse(data), null, 2), "utf-8");
|
|
1433
|
-
SwaggerDownloader.postSanitizeDownloadedFile(destFile);
|
|
1434
|
-
console.log(`SwaggerDownload ${url} completed with status code: ${response.statusCode}`);
|
|
1435
|
-
}
|
|
1540
|
+
request.on("error", (err) => {
|
|
1541
|
+
console.log(`SwaggerDownloader failed for "${targetFileName}" and "${url}"`, err);
|
|
1436
1542
|
});
|
|
1437
1543
|
});
|
|
1438
|
-
request.on("error", (err) => {
|
|
1439
|
-
console.log(`SwaggerDownloader failed for "${targetFileName}" and "${url}"`, err);
|
|
1440
|
-
});
|
|
1441
1544
|
};
|
|
1442
|
-
static main = () => {
|
|
1545
|
+
static main = async () => {
|
|
1443
1546
|
const swaggers = CliParser.getConfigFile();
|
|
1444
1547
|
for (const ref in swaggers) {
|
|
1445
1548
|
const targetFileName = swaggers[ref][2];
|
|
1446
1549
|
const url = swaggers[ref][3];
|
|
1447
|
-
SwaggerDownloader.downloadFile(targetFileName, url);
|
|
1550
|
+
await SwaggerDownloader.downloadFile(targetFileName, url);
|
|
1448
1551
|
}
|
|
1449
1552
|
};
|
|
1450
1553
|
}
|