@accelbyte/codegen 0.0.0-dev-20240828032938 → 0.0.0-dev-20240828055251
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.
|
@@ -0,0 +1,1910 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli.ts
|
|
4
|
+
import yargs from "yargs";
|
|
5
|
+
import path6 from "path";
|
|
6
|
+
|
|
7
|
+
// src/CliParser.ts
|
|
8
|
+
import fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
var SwaggersConfig = z.array(z.array(z.string()));
|
|
12
|
+
var CliParser = class _CliParser {
|
|
13
|
+
static _instance;
|
|
14
|
+
argv;
|
|
15
|
+
constructor(yargs2) {
|
|
16
|
+
this.argv = yargs2.parse();
|
|
17
|
+
}
|
|
18
|
+
static createInstance = (yargs2) => {
|
|
19
|
+
_CliParser._instance = new _CliParser(yargs2);
|
|
20
|
+
return _CliParser._instance;
|
|
21
|
+
};
|
|
22
|
+
static instance = (yargs2) => {
|
|
23
|
+
if (!_CliParser._instance && yargs2) {
|
|
24
|
+
return _CliParser.createInstance(yargs2);
|
|
25
|
+
}
|
|
26
|
+
return _CliParser._instance;
|
|
27
|
+
};
|
|
28
|
+
static getConfigPath = () => {
|
|
29
|
+
return _CliParser.instance().argv.config;
|
|
30
|
+
};
|
|
31
|
+
static getConfigFile = () => {
|
|
32
|
+
const configPath = _CliParser.getConfigPath();
|
|
33
|
+
if (!configPath) throw new Error("Missing config file");
|
|
34
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
35
|
+
if (!SwaggersConfig.safeParse(config).success) {
|
|
36
|
+
throw new Error("Wrong config file format");
|
|
37
|
+
}
|
|
38
|
+
return config;
|
|
39
|
+
};
|
|
40
|
+
static getOutputPath = () => {
|
|
41
|
+
return _CliParser.instance().argv.output;
|
|
42
|
+
};
|
|
43
|
+
static getSwaggersOutputPath = () => {
|
|
44
|
+
return _CliParser.instance().argv.swaggersOutput;
|
|
45
|
+
};
|
|
46
|
+
static getResolvedSwaggersOutputPath = () => {
|
|
47
|
+
return path.resolve(_CliParser.getSwaggersOutputPath());
|
|
48
|
+
};
|
|
49
|
+
static getSnippetOutputPath = () => {
|
|
50
|
+
return _CliParser.instance().argv.snippetOutput;
|
|
51
|
+
};
|
|
52
|
+
static skipReactQuery = () => {
|
|
53
|
+
return _CliParser.instance().argv.skipReactQuery;
|
|
54
|
+
};
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
// src/CodeGenerator.ts
|
|
58
|
+
import SwaggerParser from "@apidevtools/swagger-parser";
|
|
59
|
+
import fs4 from "fs";
|
|
60
|
+
import path4 from "path";
|
|
61
|
+
|
|
62
|
+
// src/ParserUtils.ts
|
|
63
|
+
import { applyPatch } from "fast-json-patch";
|
|
64
|
+
import fs3 from "fs";
|
|
65
|
+
import _ from "lodash";
|
|
66
|
+
import path3 from "path";
|
|
67
|
+
|
|
68
|
+
// src/helpers/utils.ts
|
|
69
|
+
import fs2 from "fs";
|
|
70
|
+
import path2 from "path";
|
|
71
|
+
var capitalize = (string) => {
|
|
72
|
+
return string.charAt(0).toUpperCase() + string.slice(1);
|
|
73
|
+
};
|
|
74
|
+
function isObject(o) {
|
|
75
|
+
return o instanceof Object && o.constructor === Object;
|
|
76
|
+
}
|
|
77
|
+
var getPermission = (endpoint) => {
|
|
78
|
+
const xSecurity = endpoint["x-security"];
|
|
79
|
+
let xSecurityPerm = void 0;
|
|
80
|
+
if (Array.isArray(xSecurity)) {
|
|
81
|
+
for (const obj of xSecurity) {
|
|
82
|
+
if (obj?.userPermissions) {
|
|
83
|
+
xSecurityPerm = obj.userPermissions;
|
|
84
|
+
}
|
|
85
|
+
if (obj?.groupPermissions) {
|
|
86
|
+
xSecurityPerm = obj.groupPermissions;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
} else if (isObject(xSecurity)) {
|
|
90
|
+
xSecurityPerm = xSecurity?.userPermission;
|
|
91
|
+
}
|
|
92
|
+
return xSecurityPerm;
|
|
93
|
+
};
|
|
94
|
+
var PermissionRegex = /\[(\w+)\]/;
|
|
95
|
+
var getPermissionType = (permission) => {
|
|
96
|
+
if (!permission) return null;
|
|
97
|
+
if (Array.isArray(permission)) {
|
|
98
|
+
const perm = permission?.[0];
|
|
99
|
+
if (!perm) return null;
|
|
100
|
+
const [_3, type2] = perm?.match(PermissionRegex);
|
|
101
|
+
return type2 || null;
|
|
102
|
+
}
|
|
103
|
+
const [_2, type] = permission?.match(PermissionRegex);
|
|
104
|
+
return type || null;
|
|
105
|
+
};
|
|
106
|
+
var removeAdminPrefix = (name) => name.startsWith("Admin") && name !== "Admin" ? name.replace(/^Admin/, "") : name;
|
|
107
|
+
function extractDescription(description, options) {
|
|
108
|
+
return description ? `
|
|
109
|
+
/**${options?.isDeprecated ? "\n * @deprecated" : ""}
|
|
110
|
+
* ${description.replace(/\*\//g, "*\\/").replace(/\n/g, "\n * ")}
|
|
111
|
+
*/` : "";
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// src/templates/template-class.ts
|
|
115
|
+
var getImportableVarMap = () => ({
|
|
116
|
+
"@accelbyte/sdk": ["CodeGenUtil", "Response", "Validate", "SdkSetConfigParam"],
|
|
117
|
+
axios: ["AxiosResponse"],
|
|
118
|
+
zod: ["z"]
|
|
119
|
+
});
|
|
120
|
+
var makeNewImportVarMap = () => ({
|
|
121
|
+
axios: ["AxiosInstance", "AxiosRequestConfig"],
|
|
122
|
+
"@accelbyte/sdk": ["SDKRequestConfig"]
|
|
123
|
+
});
|
|
124
|
+
var generateImports = (body, importStatements, makeNewImportVarMap3, getImportableVarMap3) => {
|
|
125
|
+
const usedImportVarMap = makeNewImportVarMap3;
|
|
126
|
+
const importableVarMap = getImportableVarMap3;
|
|
127
|
+
for (const [moduleSource, importableVars] of Object.entries(importableVarMap)) {
|
|
128
|
+
for (const importableVar of importableVars) {
|
|
129
|
+
const importVarRegex = new RegExp(`(?<![\\d\\w_])${importableVar}(?![\\d\\w_])`);
|
|
130
|
+
if (body.match(importVarRegex)) {
|
|
131
|
+
usedImportVarMap[moduleSource] = [...usedImportVarMap[moduleSource] || [], importableVar];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
const generatedImports = Object.keys(usedImportVarMap).sort().map((moduleSource) => {
|
|
136
|
+
return `import { ${usedImportVarMap[moduleSource].sort().join(", ")} } from '${moduleSource}'`;
|
|
137
|
+
}).join("\n");
|
|
138
|
+
return `${generatedImports}
|
|
139
|
+
${importStatements.sort().join("\n")}`;
|
|
140
|
+
};
|
|
141
|
+
var templateClass = (className, body, importStatements) => {
|
|
142
|
+
return `/**
|
|
143
|
+
* AUTO GENERATED
|
|
144
|
+
*/
|
|
145
|
+
${generateImports(body, importStatements, makeNewImportVarMap(), getImportableVarMap())}
|
|
146
|
+
|
|
147
|
+
export class ${className} {
|
|
148
|
+
// @ts-ignore
|
|
149
|
+
// prettier-ignore
|
|
150
|
+
constructor(private axiosInstance: AxiosInstance, private namespace: string, private useSchemaValidation = true) {}
|
|
151
|
+
${body}
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
// src/templates/template-api-class.ts
|
|
157
|
+
var getImportableVarMap2 = () => ({
|
|
158
|
+
"@accelbyte/sdk": ["CodeGenUtil", "Response", "Validate", "SdkSetConfigParam", "Network", "AccelByteSDK"],
|
|
159
|
+
axios: ["AxiosDefaults", "HeadersDefaults"]
|
|
160
|
+
});
|
|
161
|
+
var makeNewImportVarMap2 = () => ({
|
|
162
|
+
"@accelbyte/sdk": ["AccelByteSDK", "SdkSetConfigParam", "ApiUtils", "Network"],
|
|
163
|
+
axios: ["AxiosResponse"]
|
|
164
|
+
});
|
|
165
|
+
var templateApiClass = (className, body, importStatements, returnMethods) => {
|
|
166
|
+
const $className = className.replace(/Api$/, "$");
|
|
167
|
+
return `/**
|
|
168
|
+
* AUTO GENERATED
|
|
169
|
+
*/
|
|
170
|
+
/* eslint-disable camelcase */
|
|
171
|
+
// @ts-ignore -> ts-expect-error TS6133
|
|
172
|
+
${generateImports(body, importStatements, makeNewImportVarMap2(), getImportableVarMap2())}
|
|
173
|
+
${`import { ${$className} } from './endpoints/${$className}.js'
|
|
174
|
+
`}
|
|
175
|
+
|
|
176
|
+
export function ${className}(sdk: AccelByteSDK, args?: SdkSetConfigParam) {
|
|
177
|
+
const sdkAssembly = sdk.assembly()
|
|
178
|
+
|
|
179
|
+
const namespace = args?.coreConfig?.namespace ?? sdkAssembly.coreConfig.namespace
|
|
180
|
+
const requestConfig = ApiUtils.mergeAxiosConfigs(sdkAssembly.axiosConfig.request, args?.axiosConfig?.request)
|
|
181
|
+
const interceptors = args?.axiosConfig?.interceptors ?? sdkAssembly.axiosConfig.interceptors ?? []
|
|
182
|
+
const useSchemaValidation = sdkAssembly.coreConfig.useSchemaValidation
|
|
183
|
+
const axiosInstance = Network.create(requestConfig)
|
|
184
|
+
|
|
185
|
+
for (const interceptor of interceptors) {
|
|
186
|
+
if(interceptor.type === 'request') {
|
|
187
|
+
axiosInstance.interceptors.request.use(interceptor?.onRequest, interceptor.onError)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if(interceptor.type === 'response') {
|
|
191
|
+
axiosInstance.interceptors.response.use(interceptor?.onSuccess, interceptor.onError)
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
${body}
|
|
196
|
+
|
|
197
|
+
return {
|
|
198
|
+
${returnMethods}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
`;
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
// src/ParserQueryUtils.ts
|
|
205
|
+
var ParserQueryUtils = class {
|
|
206
|
+
/**
|
|
207
|
+
* convert csv 'aa,bb' into "aa='aa', bb='bb'"
|
|
208
|
+
*/
|
|
209
|
+
static createQueryKeys(classNameWithoutApi, csvMethodNames, sdkName) {
|
|
210
|
+
const keys = csvMethodNames.split(",");
|
|
211
|
+
const processedKeys = /* @__PURE__ */ new Set();
|
|
212
|
+
const enumString = keys.reduce((acc, key, index) => {
|
|
213
|
+
const trimmedKey = key.trim();
|
|
214
|
+
if (trimmedKey) {
|
|
215
|
+
const cleanedKey = trimmedKey.replace(/^(get|update|create|patch|delete|post|fetch)[_]?/, "");
|
|
216
|
+
if (!processedKeys.has(cleanedKey)) {
|
|
217
|
+
processedKeys.add(cleanedKey);
|
|
218
|
+
acc += `${cleanedKey} = '${capitalize(sdkName)}.${classNameWithoutApi}.${cleanedKey}'`;
|
|
219
|
+
if (index < keys.length - 1) {
|
|
220
|
+
acc += ",\n";
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return acc;
|
|
225
|
+
}, "");
|
|
226
|
+
return enumString;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
// src/templates/template-query.ts
|
|
231
|
+
var generateImports2 = (body, className) => {
|
|
232
|
+
const generatedImports = `import { AccelByteSDK, SdkSetConfigParam, ApiError } from '@accelbyte/sdk'
|
|
233
|
+
import { AxiosError, AxiosResponse } from 'axios'
|
|
234
|
+
// @ts-ignore
|
|
235
|
+
import { useQuery, UseQueryOptions, UseQueryResult, useMutation, UseMutationOptions, UseMutationResult } from '@tanstack/react-query'
|
|
236
|
+
import { ${className} } from "../${className}.js"
|
|
237
|
+
`;
|
|
238
|
+
return generatedImports;
|
|
239
|
+
};
|
|
240
|
+
var templateQuery = (className, body, importStatements, serviceNameTitle, returnMethods, paramImports, sdkName) => {
|
|
241
|
+
const classNameWithoutApi = className.replace("Api", "");
|
|
242
|
+
const queryKeys = ParserQueryUtils.createQueryKeys(classNameWithoutApi, returnMethods, sdkName);
|
|
243
|
+
const generatedImports = generateImports2(body, className);
|
|
244
|
+
return `/**
|
|
245
|
+
* AUTO GENERATED
|
|
246
|
+
*/
|
|
247
|
+
/* eslint-disable camelcase */
|
|
248
|
+
${generatedImports}
|
|
249
|
+
${filterUsedImports(paramImports, body)}
|
|
250
|
+
|
|
251
|
+
export enum Key_${classNameWithoutApi} {
|
|
252
|
+
${queryKeys}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
${body}
|
|
256
|
+
`;
|
|
257
|
+
};
|
|
258
|
+
function filterUsedImports(importArr, body) {
|
|
259
|
+
return importArr.filter((path7) => {
|
|
260
|
+
const start = path7.indexOf("{") + 1;
|
|
261
|
+
const end = path7.indexOf("}");
|
|
262
|
+
if (start > 0 && end > start) {
|
|
263
|
+
const importName = path7.slice(start, end).trim();
|
|
264
|
+
return body.includes(importName);
|
|
265
|
+
}
|
|
266
|
+
return false;
|
|
267
|
+
}).map((path7) => path7).join("\n") + "\n";
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// src/ParserUtils.ts
|
|
271
|
+
var REMOVED_KEYWORDS = [
|
|
272
|
+
"/admin/",
|
|
273
|
+
"/public/",
|
|
274
|
+
"/v1/",
|
|
275
|
+
"/v2/",
|
|
276
|
+
"/v3/",
|
|
277
|
+
"/v4/",
|
|
278
|
+
"/v5/",
|
|
279
|
+
"/namespace/",
|
|
280
|
+
"/namespaces/",
|
|
281
|
+
"/{namespace}/"
|
|
282
|
+
];
|
|
283
|
+
var ParserUtils = class _ParserUtils {
|
|
284
|
+
static getVersionSuffixFromPath(path7) {
|
|
285
|
+
const version2_3_4_etc = path7.match(/\/v([2-9]|[1-9]\d+)\/+/);
|
|
286
|
+
const methodSuffix = version2_3_4_etc ? `_v${version2_3_4_etc[1]}` : "";
|
|
287
|
+
return methodSuffix;
|
|
288
|
+
}
|
|
289
|
+
static replaceAll = (text, search, replace) => {
|
|
290
|
+
return text.split(search).join(replace);
|
|
291
|
+
};
|
|
292
|
+
static generateClassName = (tag, isAdmin) => {
|
|
293
|
+
const className = _.upperFirst(_.camelCase(tag));
|
|
294
|
+
const formattedApiName = removeAdminPrefix(className);
|
|
295
|
+
const classGenName = isAdmin ? formattedApiName + "Admin$" : formattedApiName + "$";
|
|
296
|
+
return { className: formattedApiName, classGenName };
|
|
297
|
+
};
|
|
298
|
+
static generateApiName = (tag, isAdmin) => {
|
|
299
|
+
const apiName = _.upperFirst(_.camelCase(tag));
|
|
300
|
+
const formattedApiName = removeAdminPrefix(apiName);
|
|
301
|
+
const apiGenName = isAdmin ? formattedApiName + "AdminApi" : formattedApiName + "Api";
|
|
302
|
+
return { apiName, apiGenName };
|
|
303
|
+
};
|
|
304
|
+
static parseQueryParamAttributeDefault = (definition) => {
|
|
305
|
+
const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
|
|
306
|
+
let defaultValue = definition.default;
|
|
307
|
+
if (definition.type === "array" && Array.isArray(definition.default)) {
|
|
308
|
+
const mappedDefaultValue = definition.default.map(
|
|
309
|
+
(defaultValue2) => typeof defaultValue2 === "string" ? `'${defaultValue2}'` : defaultValue2
|
|
310
|
+
);
|
|
311
|
+
defaultValue = `[${mappedDefaultValue.join(", ")}]`;
|
|
312
|
+
}
|
|
313
|
+
if (definition.type === "string") {
|
|
314
|
+
defaultValue = `'${definition.default}'`;
|
|
315
|
+
}
|
|
316
|
+
return `${attrName}: ${defaultValue}`;
|
|
317
|
+
};
|
|
318
|
+
static parseType = (pathParam) => {
|
|
319
|
+
if (isSwaggerIntegerType(pathParam.type || pathParam?.schema?.type)) return "number";
|
|
320
|
+
if (pathParam.type === "array") {
|
|
321
|
+
if (isSwaggerIntegerType(pathParam.items.type)) return "number[]";
|
|
322
|
+
return `${pathParam.items.type ?? "any"}[]`;
|
|
323
|
+
}
|
|
324
|
+
if (pathParam?.schema?.type === "array") {
|
|
325
|
+
if (isSwaggerIntegerType(pathParam.schema.items.type)) return "number[]";
|
|
326
|
+
return `${pathParam.schema.items.type ?? "any"}[]`;
|
|
327
|
+
}
|
|
328
|
+
if (pathParam?.schema?.type) return pathParam.schema.type;
|
|
329
|
+
return pathParam.type;
|
|
330
|
+
};
|
|
331
|
+
static parseQueryParamsType = (queryParams) => {
|
|
332
|
+
const result = queryParams.map((queryParam) => _ParserUtils.parseAttributeType(queryParam)).join(", ");
|
|
333
|
+
return result;
|
|
334
|
+
};
|
|
335
|
+
static isAnyQueryParamRequired = (queryParams) => {
|
|
336
|
+
return queryParams.some((queryParam) => queryParam.required);
|
|
337
|
+
};
|
|
338
|
+
static convertDashesToTitleCase = (str) => {
|
|
339
|
+
const result = str.split("-").map((word, index) => {
|
|
340
|
+
if (index === 0) {
|
|
341
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
342
|
+
}
|
|
343
|
+
return word.charAt(0).toUpperCase() + word.slice(1).toLowerCase();
|
|
344
|
+
}).join("");
|
|
345
|
+
return result;
|
|
346
|
+
};
|
|
347
|
+
static parseQueryParamsDefault = (queryParams) => {
|
|
348
|
+
const result = queryParams.filter((queryParam) => !!queryParam.default && !queryParam.required).map(_ParserUtils.parseQueryParamAttributeDefault).join(",");
|
|
349
|
+
return result ? `${result},` : "";
|
|
350
|
+
};
|
|
351
|
+
static parseBodyParamsImports = (bodyParams) => {
|
|
352
|
+
return bodyParams.map((bodyParams2) => _ParserUtils.parseRefImport(bodyParams2)).filter(Boolean);
|
|
353
|
+
};
|
|
354
|
+
static parseImportDir = ($ref) => {
|
|
355
|
+
let ref = $ref.replace(".", "/");
|
|
356
|
+
if (ref[ref.length - 1] === "." || ref[ref.length - 1] === "/") {
|
|
357
|
+
ref = ref.slice(0, -1);
|
|
358
|
+
}
|
|
359
|
+
if (!ref.includes("/")) {
|
|
360
|
+
return "";
|
|
361
|
+
} else {
|
|
362
|
+
return ref.slice(0, ref.lastIndexOf("/")).replace("#", ".");
|
|
363
|
+
}
|
|
364
|
+
};
|
|
365
|
+
static parseRefImport = (bodyParam) => {
|
|
366
|
+
const $ref = bodyParam?.schema?.$ref || bodyParam?.schema?.items?.$ref;
|
|
367
|
+
if (!$ref) {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
const type = _ParserUtils.parseRefType($ref);
|
|
371
|
+
return `import { ${type} } from '../../generated-definitions/${type}.js'`;
|
|
372
|
+
};
|
|
373
|
+
static parseRefType = ($ref) => {
|
|
374
|
+
let ref = $ref.replace(".", "/");
|
|
375
|
+
if (ref[ref.length - 1] === "." || ref[ref.length - 1] === "/") {
|
|
376
|
+
ref = ref.slice(0, -1);
|
|
377
|
+
}
|
|
378
|
+
const val = ref.slice(ref.lastIndexOf("/") + 1);
|
|
379
|
+
return _.upperFirst(_.camelCase(val)).replace(/( \w)/g, (group) => group.replace(" ", "").toUpperCase());
|
|
380
|
+
};
|
|
381
|
+
static parseAttributeType = (definition) => {
|
|
382
|
+
const required = definition.required ? "" : "?";
|
|
383
|
+
const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
|
|
384
|
+
if (definition.enum) {
|
|
385
|
+
const enums = definition.enum.map((enm) => definition.type === "string" ? `'${enm}'` : enm).join(" | ");
|
|
386
|
+
return `${attrName}${required}: ${enums}`;
|
|
387
|
+
}
|
|
388
|
+
if (definition.type && _ParserUtils.parseType(definition) === "number") {
|
|
389
|
+
return `${attrName}${required}: number`;
|
|
390
|
+
}
|
|
391
|
+
if (definition.type && _ParserUtils.parseType(definition) === "number[]") {
|
|
392
|
+
return `${attrName}${required}: number[]`;
|
|
393
|
+
}
|
|
394
|
+
if (definition?.schema?.type && _ParserUtils.parseType(definition) === "number") {
|
|
395
|
+
return `${attrName}${required}: number`;
|
|
396
|
+
}
|
|
397
|
+
if (definition.type && definition.type === "array") {
|
|
398
|
+
return `${attrName}${required}: ${definition.items.type ?? "any"}[]`;
|
|
399
|
+
}
|
|
400
|
+
if (definition?.schema?.type && definition.schema.type === "array") {
|
|
401
|
+
return `${attrName}${required}: ${definition.schema.items.type ?? "any"}[]`;
|
|
402
|
+
}
|
|
403
|
+
if (definition.type && definition.type === "file") {
|
|
404
|
+
return `${attrName}${required}: File`;
|
|
405
|
+
}
|
|
406
|
+
if (definition?.schema?.type && definition.schema.type === "file") {
|
|
407
|
+
return `${attrName}${required}: File`;
|
|
408
|
+
}
|
|
409
|
+
if (definition.type && definition.type) {
|
|
410
|
+
return `${attrName}${required}: ${definition.type} | null`;
|
|
411
|
+
}
|
|
412
|
+
if (definition?.schema?.type && definition.schema.type) {
|
|
413
|
+
return `${attrName}${required}: ${definition.schema.type} | null`;
|
|
414
|
+
}
|
|
415
|
+
return `${attrName}${required}: any`;
|
|
416
|
+
};
|
|
417
|
+
static parseBodyParamsType = (bodyParams) => {
|
|
418
|
+
const [bodyParam] = bodyParams;
|
|
419
|
+
if (!bodyParam) return null;
|
|
420
|
+
if (bodyParams.length > 0 && bodyParam?.name !== "body" && !bodyParam?.schema) {
|
|
421
|
+
let retBodyParams = `{${bodyParams.map((bodyParam2) => _ParserUtils.parseAttributeType(bodyParam2)).join(",")}}`;
|
|
422
|
+
retBodyParams = retBodyParams.replace("file?: file", "file?: File");
|
|
423
|
+
return retBodyParams;
|
|
424
|
+
}
|
|
425
|
+
if (bodyParam?.schema?.type === "array" && !bodyParam?.schema?.items?.$ref) {
|
|
426
|
+
if (isSwaggerIntegerType(bodyParam.schema.items.type)) return "number[]";
|
|
427
|
+
return `${bodyParam.schema.items.type ?? "any"}[]`;
|
|
428
|
+
}
|
|
429
|
+
if (bodyParam?.schema?.type === "array" && bodyParam?.schema?.items?.$ref) {
|
|
430
|
+
return `${_ParserUtils.parseRefType(bodyParam.schema.items.$ref)}[]`;
|
|
431
|
+
}
|
|
432
|
+
if (bodyParam?.schema?.$ref) {
|
|
433
|
+
return _ParserUtils.parseRefType(bodyParam.schema.$ref);
|
|
434
|
+
}
|
|
435
|
+
if (bodyParam?.schema?.additionalProperties?.type === "object") {
|
|
436
|
+
return "any";
|
|
437
|
+
}
|
|
438
|
+
return null;
|
|
439
|
+
};
|
|
440
|
+
static get2xxResponse(methodEntity) {
|
|
441
|
+
const keys = Object.keys(methodEntity);
|
|
442
|
+
let responseClass = null;
|
|
443
|
+
keys.forEach((key) => {
|
|
444
|
+
if (String(key).startsWith("2")) {
|
|
445
|
+
const sch = methodEntity[key].schema;
|
|
446
|
+
const schV3 = methodEntity[key].content && methodEntity[key].content["application/json"].schema;
|
|
447
|
+
if (sch?.$ref) {
|
|
448
|
+
responseClass = _ParserUtils.parseRefType(sch.$ref);
|
|
449
|
+
} else if (sch?.type === "array" && sch.items?.$ref) {
|
|
450
|
+
responseClass = _ParserUtils.parseRefType(sch.items.$ref);
|
|
451
|
+
responseClass = `${responseClass}Array`;
|
|
452
|
+
} else if (schV3?.$ref) {
|
|
453
|
+
responseClass = _ParserUtils.parseRefType(schV3.$ref);
|
|
454
|
+
} else {
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
});
|
|
458
|
+
return responseClass;
|
|
459
|
+
}
|
|
460
|
+
static isFormUrlEncoded(httpMethod, contentTypes) {
|
|
461
|
+
if (!contentTypes || contentTypes.length < 1) {
|
|
462
|
+
return false;
|
|
463
|
+
}
|
|
464
|
+
if (!["post", "put", "patch"].includes(httpMethod)) {
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
return contentTypes.includes("application/x-www-form-urlencoded");
|
|
468
|
+
}
|
|
469
|
+
static filterPathParams(parameters) {
|
|
470
|
+
if (!parameters) {
|
|
471
|
+
return [];
|
|
472
|
+
}
|
|
473
|
+
return parameters.filter((parameter) => parameter.in === "path");
|
|
474
|
+
}
|
|
475
|
+
/**
|
|
476
|
+
* This method converts this
|
|
477
|
+
* POST `/gdpr/public/namespaces/{namespace}/users/{userId}/requests/{requestDate}/generate`
|
|
478
|
+
*
|
|
479
|
+
* to this
|
|
480
|
+
* `createGenerateByRequestIdByUserId`
|
|
481
|
+
*/
|
|
482
|
+
static generateNaturalLangMethod = ({ servicePrefix, path: path7, httpMethod, isForm, existingMethods, permissionType }) => {
|
|
483
|
+
let path_ = path7;
|
|
484
|
+
path_ = path_.replace(`/${servicePrefix}/`, "/");
|
|
485
|
+
REMOVED_KEYWORDS.forEach((prefix) => {
|
|
486
|
+
path_ = path_.replace(prefix, "/");
|
|
487
|
+
});
|
|
488
|
+
path_ = path_.substring(1);
|
|
489
|
+
const isPlural = httpMethod === "get" && !(path7.slice(-1) === "}");
|
|
490
|
+
if (!isPlural) {
|
|
491
|
+
path_ = _ParserUtils.replaceAll(path_, "ies/", "y/");
|
|
492
|
+
path_ = _ParserUtils.replaceAll(path_, "s/", "/");
|
|
493
|
+
if (path_.indexOf("status") < 0) {
|
|
494
|
+
path_ = path_.replace(/ies$/, "y");
|
|
495
|
+
path_ = path_.replace(/s$/, "");
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
const arrLastWords = path_.split("}/");
|
|
499
|
+
let lastWords = arrLastWords[arrLastWords.length - 1];
|
|
500
|
+
const extractLastWord = (lastWords_) => {
|
|
501
|
+
let res = lastWords_;
|
|
502
|
+
res = res.split("/{")[0];
|
|
503
|
+
return res;
|
|
504
|
+
};
|
|
505
|
+
lastWords = extractLastWord(lastWords);
|
|
506
|
+
if (lastWords.indexOf("{") >= 0 && arrLastWords.length > 1) {
|
|
507
|
+
lastWords = arrLastWords[arrLastWords.length - 2];
|
|
508
|
+
lastWords = extractLastWord(lastWords);
|
|
509
|
+
}
|
|
510
|
+
const listBeforeLastWords = [];
|
|
511
|
+
let foundParam = false;
|
|
512
|
+
const listByParams = [];
|
|
513
|
+
const pathElements = path_.split("/");
|
|
514
|
+
pathElements.slice().reverse().forEach((item) => {
|
|
515
|
+
if (item.indexOf("}") >= 0) {
|
|
516
|
+
foundParam = true;
|
|
517
|
+
let param = item.replace("{", "");
|
|
518
|
+
param = param.replace("}", "");
|
|
519
|
+
param = "Byword" + _.upperFirst(param);
|
|
520
|
+
listByParams.push(param);
|
|
521
|
+
} else if (!foundParam) {
|
|
522
|
+
if (lastWords.indexOf(item) === -1) {
|
|
523
|
+
listBeforeLastWords.push(item);
|
|
524
|
+
}
|
|
525
|
+
} else {
|
|
526
|
+
foundParam = false;
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
const genPath = _.upperFirst(lastWords) + "/" + listBeforeLastWords.join("/") + listByParams.reverse().join("/");
|
|
530
|
+
let generatedMethod = _.camelCase(mappedMethod(httpMethod, isForm, permissionType) + genPath);
|
|
531
|
+
generatedMethod = _ParserUtils.replaceAll(generatedMethod, "Byword", "_By");
|
|
532
|
+
const testedGeneratedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(path7);
|
|
533
|
+
generatedMethod = resolveConflicts({ path: path7, generatedMethod, testedGeneratedMethod, existingMethods });
|
|
534
|
+
generatedMethod = generatedMethod + _ParserUtils.getVersionSuffixFromPath(path7);
|
|
535
|
+
return generatedMethod;
|
|
536
|
+
};
|
|
537
|
+
static filterBodyParams(parameters) {
|
|
538
|
+
if (Array.isArray(parameters) && parameters.length > 0) {
|
|
539
|
+
return parameters.filter((parameter) => parameter.in === "body" || parameter.in === "formData");
|
|
540
|
+
}
|
|
541
|
+
return [];
|
|
542
|
+
}
|
|
543
|
+
static filterQueryParameters(parameters) {
|
|
544
|
+
if (!parameters) {
|
|
545
|
+
return [];
|
|
546
|
+
}
|
|
547
|
+
return parameters.filter((parameter) => parameter.in === "query");
|
|
548
|
+
}
|
|
549
|
+
static mkdirIfNotExist(dirToCreate) {
|
|
550
|
+
if (!fs3.existsSync(dirToCreate)) {
|
|
551
|
+
fs3.mkdirSync(dirToCreate, { recursive: true });
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
static writeClassFile(distDir, apiName, apiBuffer, imports) {
|
|
555
|
+
const fileContent = templateClass(apiName, apiBuffer, imports);
|
|
556
|
+
fs3.writeFileSync(`${distDir}/${apiName}.ts`, _ParserUtils.prependCopyrightHeader(fileContent));
|
|
557
|
+
}
|
|
558
|
+
static writeAtomFile(distDir, apiName, fileContent) {
|
|
559
|
+
_ParserUtils.mkdirIfNotExist(distDir);
|
|
560
|
+
fs3.writeFileSync(`${distDir}/${apiName}.atom.ts`, _ParserUtils.prependCopyrightHeader(fileContent));
|
|
561
|
+
}
|
|
562
|
+
static writeQueryFile(distDir, apiName, apiBuffer, imports, serviceNameTitle, returnMethods, paramImports, sdkName) {
|
|
563
|
+
if (apiBuffer.length < 1) {
|
|
564
|
+
return null;
|
|
565
|
+
}
|
|
566
|
+
const queryFileName = `${apiName.replace("Api", "")}.query`;
|
|
567
|
+
_ParserUtils.mkdirIfNotExist(distDir);
|
|
568
|
+
const fileContent = templateQuery(apiName, apiBuffer, imports, serviceNameTitle, returnMethods, paramImports, sdkName);
|
|
569
|
+
fs3.writeFileSync(`${distDir}/${queryFileName}.ts`, _ParserUtils.prependCopyrightHeader(fileContent));
|
|
570
|
+
return queryFileName;
|
|
571
|
+
}
|
|
572
|
+
static writeXVersion(distDir, xversionJson, apiInfo) {
|
|
573
|
+
if (xversionJson) {
|
|
574
|
+
console.log("x-version:", xversionJson);
|
|
575
|
+
fs3.writeFileSync(`${distDir}/version.json`, JSON.stringify(xversionJson, null, 2));
|
|
576
|
+
} else {
|
|
577
|
+
const customVersion = {
|
|
578
|
+
...apiInfo,
|
|
579
|
+
gitHash: apiInfo.version
|
|
580
|
+
};
|
|
581
|
+
console.error(`!!!! Missing x-version for ${distDir} ${customVersion}`);
|
|
582
|
+
fs3.writeFileSync(`${distDir}/version.json`, JSON.stringify(customVersion, null, 2));
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
static writeApiFile(distDir, apiName, apiBuffer, imports, returnMethods) {
|
|
586
|
+
const newImports = [];
|
|
587
|
+
imports.forEach((el) => {
|
|
588
|
+
newImports.push(el.replace("../../generated-definitions", "../generated-definitions"));
|
|
589
|
+
});
|
|
590
|
+
const fileContent = templateApiClass(apiName, apiBuffer, newImports, returnMethods);
|
|
591
|
+
fs3.writeFileSync(`${distDir}/${apiName}.ts`, _ParserUtils.prependCopyrightHeader(fileContent));
|
|
592
|
+
}
|
|
593
|
+
static writeApiMainFile(distDir, serviceName, fileContent) {
|
|
594
|
+
fs3.writeFileSync(`${distDir}/${serviceName}.ts`, _ParserUtils.prependCopyrightHeader(fileContent));
|
|
595
|
+
}
|
|
596
|
+
static writeSnippetFile(distDir, name, docBuffer) {
|
|
597
|
+
let snippetFileName = _ParserUtils.replaceAll(name, " ", "-").toLowerCase();
|
|
598
|
+
snippetFileName = snippetFileName.replace("justice-", "");
|
|
599
|
+
snippetFileName = "snippet-" + snippetFileName + ".json";
|
|
600
|
+
fs3.writeFileSync(`${distDir}/${snippetFileName}`, docBuffer);
|
|
601
|
+
}
|
|
602
|
+
static writeDefinitionFile(distDir, name, buffer) {
|
|
603
|
+
_ParserUtils.mkdirIfNotExist(distDir);
|
|
604
|
+
fs3.writeFileSync(path3.join(distDir, `${name}.ts`), _ParserUtils.prependCopyrightHeader(buffer));
|
|
605
|
+
}
|
|
606
|
+
static writeAllImportsFile(distDir, buffer) {
|
|
607
|
+
_ParserUtils.mkdirIfNotExist(distDir);
|
|
608
|
+
fs3.writeFileSync(path3.join(distDir, "all-imports.ts"), _ParserUtils.prependCopyrightHeader(buffer));
|
|
609
|
+
}
|
|
610
|
+
static writeAllQueryImportsFile(distDir, buffer) {
|
|
611
|
+
_ParserUtils.mkdirIfNotExist(distDir);
|
|
612
|
+
fs3.writeFileSync(path3.join(distDir, "all-query-imports.ts"), _ParserUtils.prependCopyrightHeader(buffer));
|
|
613
|
+
}
|
|
614
|
+
static toCamelCase(str) {
|
|
615
|
+
return str.split("/").map(function(word, index) {
|
|
616
|
+
if (index === 0) {
|
|
617
|
+
return word.toLowerCase();
|
|
618
|
+
}
|
|
619
|
+
return _ParserUtils.toCamelCaseWord(word);
|
|
620
|
+
}).join("");
|
|
621
|
+
}
|
|
622
|
+
static toCamelCaseWord(word) {
|
|
623
|
+
if (!word) {
|
|
624
|
+
return "";
|
|
625
|
+
}
|
|
626
|
+
word = word.replace(/(-\w)/g, (m) => m[1].toUpperCase());
|
|
627
|
+
return word.charAt(0).toUpperCase() + word.slice(1);
|
|
628
|
+
}
|
|
629
|
+
static toTitleCaseWord(word) {
|
|
630
|
+
if (!word) {
|
|
631
|
+
return "";
|
|
632
|
+
}
|
|
633
|
+
return word.replace(/\w\S*/g, (txt) => {
|
|
634
|
+
return txt.charAt(0).toUpperCase() + txt.substring(1).toLowerCase();
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
static applyPatchIfExists(swaggerFilePath, possibleSwaggerPatchFilePath, swaggerPatchedFilePath, swaggerPatchedDir) {
|
|
638
|
+
if (!fs3.existsSync(swaggerPatchedDir)) {
|
|
639
|
+
fs3.mkdirSync(swaggerPatchedDir, { recursive: true });
|
|
640
|
+
}
|
|
641
|
+
if (!fs3.existsSync(possibleSwaggerPatchFilePath)) {
|
|
642
|
+
fs3.copyFileSync(swaggerFilePath, swaggerPatchedFilePath);
|
|
643
|
+
return;
|
|
644
|
+
}
|
|
645
|
+
const swaggerContent = JSON.parse(fs3.readFileSync(swaggerFilePath, "utf8"));
|
|
646
|
+
const swaggerPatchFileContent = JSON.parse(fs3.readFileSync(possibleSwaggerPatchFilePath, "utf8"));
|
|
647
|
+
for (const patchEntry of swaggerPatchFileContent) {
|
|
648
|
+
const segments = patchEntry.path.split("/").filter(Boolean);
|
|
649
|
+
let currentNode = swaggerContent;
|
|
650
|
+
let aggregatedPath = "";
|
|
651
|
+
for (let i = 0; i < segments.length; i++) {
|
|
652
|
+
const segment = segments[i];
|
|
653
|
+
aggregatedPath += `/${segment}`;
|
|
654
|
+
const effectiveSegment = segment.replace(/(~1)/g, "/").replace(/(~0)/g, "~");
|
|
655
|
+
if (!currentNode[effectiveSegment]) {
|
|
656
|
+
if (i + 1 === segments.length && patchEntry.op === "add") {
|
|
657
|
+
} else {
|
|
658
|
+
throw new Error(
|
|
659
|
+
[
|
|
660
|
+
`JSON patch error: operation "${patchEntry.op}" on path "${aggregatedPath}" fails because the path doesn't exist in ${swaggerFilePath}. This may be caused by:
|
|
661
|
+
`,
|
|
662
|
+
"1. The related service has patched the service, so patch is no longer needed.",
|
|
663
|
+
"2. There is a breaking change on the service that causes the path to change.\n",
|
|
664
|
+
`In any case, revisit this file: "${possibleSwaggerPatchFilePath}", then try again.
|
|
665
|
+
`
|
|
666
|
+
].join("\n")
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
currentNode = currentNode[effectiveSegment];
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
const { newDocument } = applyPatch(swaggerContent, swaggerPatchFileContent);
|
|
674
|
+
fs3.writeFileSync(swaggerPatchedFilePath, JSON.stringify(newDocument, null, 2));
|
|
675
|
+
}
|
|
676
|
+
static getRelativePathToWebSdkSrcFolder(srcFolder, targetSrcFolder) {
|
|
677
|
+
const replaced = srcFolder.replace(/\\/g, "/");
|
|
678
|
+
return replaced.replace(/\\/g, "/").replace(targetSrcFolder, "./");
|
|
679
|
+
}
|
|
680
|
+
static prependCopyrightHeader = (content) => {
|
|
681
|
+
const currentYear = (/* @__PURE__ */ new Date()).getFullYear();
|
|
682
|
+
return `/*
|
|
683
|
+
* Copyright (c) 2022${currentYear > 2022 ? `-${currentYear}` : ""} AccelByte Inc. All Rights Reserved
|
|
684
|
+
* This is licensed software from AccelByte Inc, for limitations
|
|
685
|
+
* and restrictions contact your company contract manager.
|
|
686
|
+
*/
|
|
687
|
+
${content}`;
|
|
688
|
+
};
|
|
689
|
+
static sortPathParamsByPath = (pathParams, path7) => {
|
|
690
|
+
const params = path7.match(/{\w*}/g) || [];
|
|
691
|
+
const cleanParams = params.map((param) => param.replace("{", "").replace("}", ""));
|
|
692
|
+
return pathParams.sort((a, b) => cleanParams.indexOf(a.name) - cleanParams.indexOf(b.name));
|
|
693
|
+
};
|
|
694
|
+
};
|
|
695
|
+
var mappedMethod = (httpMethod, isForm, permissionType) => {
|
|
696
|
+
if (httpMethod === "get") {
|
|
697
|
+
return "get";
|
|
698
|
+
} else if (httpMethod === "post" && isForm) {
|
|
699
|
+
return "post";
|
|
700
|
+
} else if (httpMethod === "post" && permissionType === "READ") {
|
|
701
|
+
return "fetch";
|
|
702
|
+
} else if (httpMethod === "post" && permissionType === "UPDATE") {
|
|
703
|
+
return "update";
|
|
704
|
+
} else if (httpMethod === "post") {
|
|
705
|
+
return "create";
|
|
706
|
+
} else if (httpMethod === "put") {
|
|
707
|
+
return "update";
|
|
708
|
+
} else if (httpMethod === "patch") {
|
|
709
|
+
return "patch";
|
|
710
|
+
} else if (httpMethod === "delete") {
|
|
711
|
+
return "delete";
|
|
712
|
+
}
|
|
713
|
+
};
|
|
714
|
+
var resolveConflicts = ({ path: path7, generatedMethod, testedGeneratedMethod, existingMethods }) => {
|
|
715
|
+
let _testedGenMethod = testedGeneratedMethod;
|
|
716
|
+
try {
|
|
717
|
+
testConflict(path7, _testedGenMethod, existingMethods);
|
|
718
|
+
} catch (e) {
|
|
719
|
+
if (path7.indexOf("/namespaces/") >= 0) {
|
|
720
|
+
generatedMethod += "_ByNS";
|
|
721
|
+
_testedGenMethod += "_ByNS";
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
try {
|
|
725
|
+
testConflict(path7, _testedGenMethod, existingMethods);
|
|
726
|
+
} catch (e) {
|
|
727
|
+
if (path7.indexOf("/admin/") >= 0) {
|
|
728
|
+
generatedMethod += "_admin";
|
|
729
|
+
_testedGenMethod += "_admin";
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
testConflict(path7, _testedGenMethod, existingMethods);
|
|
733
|
+
return generatedMethod;
|
|
734
|
+
};
|
|
735
|
+
var testConflict = (path7, generatedMethod, existingMethods) => {
|
|
736
|
+
if (existingMethods[generatedMethod]) {
|
|
737
|
+
const conflictingMethod = { path: path7, generatedMethod };
|
|
738
|
+
throw Error(
|
|
739
|
+
`Duplicate method conflict in ${JSON.stringify(conflictingMethod)},
|
|
740
|
+
existingMethods: ${JSON.stringify(existingMethods, null, 2)}`
|
|
741
|
+
);
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
var isSwaggerIntegerType = (type) => {
|
|
745
|
+
return type === "integer" || type === "int";
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
// src/Swagger.ts
|
|
749
|
+
import { z as z2 } from "zod";
|
|
750
|
+
var Schema = z2.object({
|
|
751
|
+
$ref: z2.string().nullish(),
|
|
752
|
+
type: z2.union([z2.literal("array"), z2.literal("object"), z2.literal("file"), z2.literal("string"), z2.literal("boolean"), z2.literal("integer")]).nullish(),
|
|
753
|
+
items: z2.object({
|
|
754
|
+
$ref: z2.string().nullish(),
|
|
755
|
+
type: z2.string().nullish()
|
|
756
|
+
}).nullish(),
|
|
757
|
+
properties: z2.union([z2.array(z2.string()).nullish(), z2.record(z2.object({ type: z2.string() })).nullish()]),
|
|
758
|
+
description: z2.string().nullish(),
|
|
759
|
+
additionalProperties: z2.object({
|
|
760
|
+
type: z2.string().nullish()
|
|
761
|
+
}).nullish()
|
|
762
|
+
});
|
|
763
|
+
var Definition = z2.object({
|
|
764
|
+
required: z2.array(z2.string()).nullish(),
|
|
765
|
+
properties: z2.record(
|
|
766
|
+
z2.object({
|
|
767
|
+
type: z2.string()
|
|
768
|
+
})
|
|
769
|
+
).nullish()
|
|
770
|
+
});
|
|
771
|
+
var Definitions = z2.record(Definition);
|
|
772
|
+
var EndpointParametersType = z2.enum(["apiKey", "boolean", "int", "integer", "number", "string", "array", "file"]);
|
|
773
|
+
var EndpointParametersIn = z2.enum(["body", "formData", "header", "path", "query"]);
|
|
774
|
+
var EndpointParameters = z2.object({
|
|
775
|
+
type: EndpointParametersType.nullish(),
|
|
776
|
+
description: z2.string().nullish(),
|
|
777
|
+
name: z2.string(),
|
|
778
|
+
in: EndpointParametersIn,
|
|
779
|
+
required: z2.boolean().nullish(),
|
|
780
|
+
schema: Schema.nullish(),
|
|
781
|
+
default: z2.union([z2.boolean(), z2.string(), z2.number(), z2.array(z2.any())]).nullish(),
|
|
782
|
+
enum: z2.array(z2.union([z2.boolean(), z2.string(), z2.number()])).nullish(),
|
|
783
|
+
items: z2.object({
|
|
784
|
+
type: z2.string(),
|
|
785
|
+
enum: z2.array(z2.any()).nullish()
|
|
786
|
+
}).nullish()
|
|
787
|
+
});
|
|
788
|
+
var Endpoint = z2.object({
|
|
789
|
+
description: z2.string().nullish(),
|
|
790
|
+
consumes: z2.array(z2.string()).nullish(),
|
|
791
|
+
produces: z2.array(z2.string()).nullish(),
|
|
792
|
+
tags: z2.array(z2.string()).nullish(),
|
|
793
|
+
summary: z2.string().nullish(),
|
|
794
|
+
operationId: z2.string(),
|
|
795
|
+
deprecated: z2.boolean().nullish(),
|
|
796
|
+
responses: z2.record(
|
|
797
|
+
z2.object({
|
|
798
|
+
description: z2.string().nullish(),
|
|
799
|
+
schema: Schema.nullish(),
|
|
800
|
+
content: z2.object({
|
|
801
|
+
"application/json": z2.object({
|
|
802
|
+
schema: Schema.nullish()
|
|
803
|
+
})
|
|
804
|
+
}).nullish()
|
|
805
|
+
})
|
|
806
|
+
),
|
|
807
|
+
parameters: z2.array(EndpointParameters).nullish(),
|
|
808
|
+
requestBody: z2.object({
|
|
809
|
+
required: z2.boolean().nullish(),
|
|
810
|
+
content: z2.object({
|
|
811
|
+
"application/json": z2.object({
|
|
812
|
+
schema: Schema.nullish()
|
|
813
|
+
}).nullish()
|
|
814
|
+
}).nullish()
|
|
815
|
+
}).nullish(),
|
|
816
|
+
// The proper type is z.array(z.record(z.array(z.string()))).nullish() but somehow there are endpoints with
|
|
817
|
+
// an object type instead of an array type, so, yeah.
|
|
818
|
+
//
|
|
819
|
+
// Services with this error: sdk-iam, sdk-ugc.
|
|
820
|
+
"x-security": z2.any().nullish()
|
|
821
|
+
});
|
|
822
|
+
var Operation2 = z2.object({
|
|
823
|
+
get: Endpoint.nullish(),
|
|
824
|
+
post: Endpoint.nullish(),
|
|
825
|
+
patch: Endpoint.nullish(),
|
|
826
|
+
delete: Endpoint.nullish(),
|
|
827
|
+
put: Endpoint.nullish()
|
|
828
|
+
});
|
|
829
|
+
var Paths = z2.record(Operation2);
|
|
830
|
+
var OpenApiSpec = z2.object({
|
|
831
|
+
paths: Paths,
|
|
832
|
+
definitions: Definitions,
|
|
833
|
+
basePath: z2.string(),
|
|
834
|
+
info: z2.object({
|
|
835
|
+
description: z2.string(),
|
|
836
|
+
title: z2.string(),
|
|
837
|
+
contact: z2.object({
|
|
838
|
+
name: z2.string(),
|
|
839
|
+
url: z2.string(),
|
|
840
|
+
email: z2.string()
|
|
841
|
+
}),
|
|
842
|
+
version: z2.string()
|
|
843
|
+
}),
|
|
844
|
+
schemes: z2.array(z2.string()).nullish(),
|
|
845
|
+
components: z2.object({
|
|
846
|
+
schemas: Definitions
|
|
847
|
+
}).nullish()
|
|
848
|
+
});
|
|
849
|
+
|
|
850
|
+
// src/templates/template-api-method.ts
|
|
851
|
+
var templateApiMethod = ({
|
|
852
|
+
classMethod,
|
|
853
|
+
description,
|
|
854
|
+
httpMethod,
|
|
855
|
+
path: path7,
|
|
856
|
+
pathParams,
|
|
857
|
+
bodyParams,
|
|
858
|
+
responseClass,
|
|
859
|
+
classGenName,
|
|
860
|
+
methodParams,
|
|
861
|
+
methodParamsNoTypes,
|
|
862
|
+
deprecated,
|
|
863
|
+
xSecurity
|
|
864
|
+
}) => {
|
|
865
|
+
let newPath = `'${path7}'`;
|
|
866
|
+
let snippetMethod = "";
|
|
867
|
+
for (const pathParam of pathParams) {
|
|
868
|
+
const type = ParserUtils.parseType(pathParam);
|
|
869
|
+
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
870
|
+
if (path7.match(`{${pathParam.name}}`)) {
|
|
871
|
+
if (type === "string") {
|
|
872
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
873
|
+
} else {
|
|
874
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
const snippetShellArgs = ["--location --request", `${httpMethod} '__DOMAIN__${path7}'`, "--header 'accept: application/json'"];
|
|
879
|
+
const snippetApiArgs = [];
|
|
880
|
+
if (xSecurity !== void 0 || path7.includes("/admin")) {
|
|
881
|
+
snippetShellArgs.push("--header 'Authorization: Bearer {access_token}'");
|
|
882
|
+
snippetApiArgs.push("{ config: { headers: { Authorization: 'Bearer {access_token}' } }}".trim());
|
|
883
|
+
}
|
|
884
|
+
if (httpMethod !== "get") {
|
|
885
|
+
const curlParams = bodyParams?.map((ob) => {
|
|
886
|
+
return ` "${ob.name}": ""`;
|
|
887
|
+
});
|
|
888
|
+
if (curlParams.length > 0) {
|
|
889
|
+
snippetShellArgs.push(`--data-raw '{ ${curlParams}}'`);
|
|
890
|
+
}
|
|
891
|
+
}
|
|
892
|
+
const snippetShell = `curl ${snippetShellArgs.join(" \\\n ")}`;
|
|
893
|
+
const descriptionText = extractDescription(description, { isDeprecated: deprecated });
|
|
894
|
+
const resolvedResponseClass = responseClass || "unknown";
|
|
895
|
+
const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
|
|
896
|
+
const methodImpl = `
|
|
897
|
+
${descriptionText}
|
|
898
|
+
async function ${classMethod}(${methodParams}): Promise<AxiosResponse<${responseType}>> {
|
|
899
|
+
const $ = new ${classGenName}(axiosInstance, namespace, useSchemaValidation)
|
|
900
|
+
const resp = await $.${classMethod}(${methodParamsNoTypes})
|
|
901
|
+
if (resp.error) throw resp.error
|
|
902
|
+
return resp.response
|
|
903
|
+
}
|
|
904
|
+
`;
|
|
905
|
+
const snippetPromiseString = responseType !== "unknown" ? `Promise<${responseType}>` : "Promise";
|
|
906
|
+
snippetMethod += `${classMethod}(${methodParams})
|
|
907
|
+
// return ${snippetPromiseString}`;
|
|
908
|
+
return {
|
|
909
|
+
generatedMethodString: methodImpl,
|
|
910
|
+
snippetApiArgs,
|
|
911
|
+
snippetMethod,
|
|
912
|
+
snippetShell
|
|
913
|
+
};
|
|
914
|
+
};
|
|
915
|
+
|
|
916
|
+
// src/templates/template-method.ts
|
|
917
|
+
var templateMethod = ({
|
|
918
|
+
classMethod,
|
|
919
|
+
description,
|
|
920
|
+
httpMethod,
|
|
921
|
+
path: path7,
|
|
922
|
+
pathParams,
|
|
923
|
+
bodyParams,
|
|
924
|
+
queryParams,
|
|
925
|
+
isFormUrlEncoded,
|
|
926
|
+
responseClass,
|
|
927
|
+
deprecated
|
|
928
|
+
}) => {
|
|
929
|
+
let methodParams = "";
|
|
930
|
+
let methodParamsNoTypes = "";
|
|
931
|
+
let newPath = `'${path7}'`;
|
|
932
|
+
let importStatements = [];
|
|
933
|
+
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path7);
|
|
934
|
+
for (const pathParam of sortedPathParams) {
|
|
935
|
+
const type = ParserUtils.parseType(pathParam);
|
|
936
|
+
if (pathParam.name !== "namespace") {
|
|
937
|
+
methodParams += pathParam.name + `:${type}, `;
|
|
938
|
+
methodParamsNoTypes += pathParam.name + ", ";
|
|
939
|
+
}
|
|
940
|
+
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
941
|
+
if (path7.match(`{${pathParam.name}}`)) {
|
|
942
|
+
if (type === "string") {
|
|
943
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
944
|
+
} else {
|
|
945
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
}
|
|
949
|
+
let dataType = null;
|
|
950
|
+
if (httpMethod !== "get") {
|
|
951
|
+
dataType = ParserUtils.parseBodyParamsType(bodyParams);
|
|
952
|
+
importStatements = ParserUtils.parseBodyParamsImports(bodyParams);
|
|
953
|
+
methodParams += dataType ? `data: ${dataType},` : "";
|
|
954
|
+
methodParamsNoTypes += dataType ? `data,` : "";
|
|
955
|
+
}
|
|
956
|
+
const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
|
|
957
|
+
const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
|
|
958
|
+
const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as AxiosRequestConfig` : "const params = {} as AxiosRequestConfig";
|
|
959
|
+
const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
|
|
960
|
+
const isDelete = ["delete"].includes(httpMethod);
|
|
961
|
+
let dataPayload = "{params}";
|
|
962
|
+
const descriptionText = extractDescription(description, { isDeprecated: deprecated });
|
|
963
|
+
let formPayloadString = "";
|
|
964
|
+
if (isFormUrlEncoded) {
|
|
965
|
+
formPayloadString = ``;
|
|
966
|
+
const params = "{ ...params, headers: { ...params.headers, 'content-type': 'application/x-www-form-urlencoded' } }";
|
|
967
|
+
dataPayload = dataType ? `CodeGenUtil.getFormUrlEncodedData(data), ${params}` : `null, ${params}`;
|
|
968
|
+
} else if (isPostPutPatch) {
|
|
969
|
+
dataPayload = dataType ? `data, {params}` : "null, {params}";
|
|
970
|
+
} else if (isDelete) {
|
|
971
|
+
dataPayload = dataType ? `{data, params}` : "{params}";
|
|
972
|
+
}
|
|
973
|
+
const isFileUpload = methodParams.indexOf("data: {file") > -1;
|
|
974
|
+
const resolvedResponseClass = responseClass || "unknown";
|
|
975
|
+
const resolvedResponseClassValidated = responseClass || "z.unknown()";
|
|
976
|
+
methodParams = (queryParamsType ? `${methodParams} ${queryParamsType}` : methodParams).replace(/,\s*$/, "");
|
|
977
|
+
methodParamsNoTypes = queryParamsType ? `${methodParamsNoTypes} queryParams` : methodParamsNoTypes;
|
|
978
|
+
const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
|
|
979
|
+
const responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
|
|
980
|
+
const responseSyncType = "Response";
|
|
981
|
+
const generatedMethodName = `${classMethod}(${methodParams}): Promise<${responseSyncType}<${responseType}>>`;
|
|
982
|
+
let methodImpl = `${descriptionText}
|
|
983
|
+
${generatedMethodName} {
|
|
984
|
+
${queryParamsDefault}
|
|
985
|
+
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
986
|
+
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
987
|
+
|
|
988
|
+
${` return Validate.validateOrReturnResponse(this.useSchemaValidation, () => resultPromise, ${resolvedResponseClassValidated}, '${resolvedResponseClassValidated}')`}
|
|
989
|
+
}
|
|
990
|
+
`;
|
|
991
|
+
if (!isGuardInvoked) {
|
|
992
|
+
methodImpl = ``;
|
|
993
|
+
}
|
|
994
|
+
const res = {
|
|
995
|
+
methodImpl,
|
|
996
|
+
methodParams,
|
|
997
|
+
methodParamsNoTypes,
|
|
998
|
+
importStatements
|
|
999
|
+
};
|
|
1000
|
+
return res;
|
|
1001
|
+
};
|
|
1002
|
+
|
|
1003
|
+
// src/templates/template-query-method.ts
|
|
1004
|
+
var POST_FETCH_INCLUDES_PATH = ["/table-query/"];
|
|
1005
|
+
var templateQueryMethod = ({
|
|
1006
|
+
classMethod,
|
|
1007
|
+
httpMethod,
|
|
1008
|
+
path: path7,
|
|
1009
|
+
pathParams,
|
|
1010
|
+
responseClass,
|
|
1011
|
+
methodParams,
|
|
1012
|
+
apiGenName
|
|
1013
|
+
}) => {
|
|
1014
|
+
const isPostFetch = httpMethod === "post" && (POST_FETCH_INCLUDES_PATH.some((p) => path7.includes(p)) || path7.endsWith("/list"));
|
|
1015
|
+
const isFetch = classMethod.startsWith("fetch");
|
|
1016
|
+
const isGet = httpMethod === "get" || isPostFetch || isFetch;
|
|
1017
|
+
const queryMethod = isGet ? "useQuery" : "useMutation";
|
|
1018
|
+
let mParams = "";
|
|
1019
|
+
let mParamsNoTypes = "";
|
|
1020
|
+
let newPath = `'${path7}'`;
|
|
1021
|
+
const sortedPathParams = ParserUtils.sortPathParamsByPath(pathParams, path7);
|
|
1022
|
+
for (const pathParam of sortedPathParams) {
|
|
1023
|
+
const type = ParserUtils.parseType(pathParam);
|
|
1024
|
+
if (pathParam.name !== "namespace") {
|
|
1025
|
+
mParams += pathParam.name + `:${type}, `;
|
|
1026
|
+
mParamsNoTypes += pathParam.name + ", ";
|
|
1027
|
+
}
|
|
1028
|
+
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
1029
|
+
if (path7.match(`{${pathParam.name}}`)) {
|
|
1030
|
+
if (type === "string") {
|
|
1031
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
1032
|
+
} else {
|
|
1033
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
const resolvedResponseClass = responseClass || "unknown";
|
|
1038
|
+
let _methodName = convertMethodNameToHook({ classMethod, apiGenName, isPostFetch, isFetch });
|
|
1039
|
+
const _responseType = resolvedResponseClass !== "unknown" ? `${resolvedResponseClass}` : "unknown";
|
|
1040
|
+
const _methodParams = methodParams && methodParams.length > 0 ? `& { ${methodParams} }` : "";
|
|
1041
|
+
const _methodParamsImpl = convertToMethodImplArgs(methodParams);
|
|
1042
|
+
const queryMethodImpl = `
|
|
1043
|
+
|
|
1044
|
+
export const ${_methodName} = (
|
|
1045
|
+
sdk: AccelByteSDK,
|
|
1046
|
+
input: SdkSetConfigParam ${_methodParams},
|
|
1047
|
+
options?: Omit<UseQueryOptions<${_responseType}, AxiosError<ApiError>>, 'queryKey'>,
|
|
1048
|
+
callback?: (data: AxiosResponse<${_responseType}>) => void
|
|
1049
|
+
): UseQueryResult<${_responseType}, AxiosError<ApiError>> => {
|
|
1050
|
+
//
|
|
1051
|
+
const queryFn = (
|
|
1052
|
+
sdk: AccelByteSDK,
|
|
1053
|
+
input: Parameters<typeof ${_methodName}>[1]
|
|
1054
|
+
) => async () => {
|
|
1055
|
+
const response =
|
|
1056
|
+
(await ${apiGenName}(sdk, { coreConfig: input.coreConfig, axiosConfig: input.axiosConfig }).
|
|
1057
|
+
${classMethod}(${_methodParamsImpl}))
|
|
1058
|
+
callback && callback(response)
|
|
1059
|
+
return response.data
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
return ${queryMethod}<${_responseType}, AxiosError<ApiError>>({
|
|
1063
|
+
queryKey: [${createQueryKey(apiGenName, classMethod)}, input],
|
|
1064
|
+
queryFn: queryFn(sdk, input),
|
|
1065
|
+
...options
|
|
1066
|
+
})
|
|
1067
|
+
}
|
|
1068
|
+
|
|
1069
|
+
`;
|
|
1070
|
+
const mutationMethodImpl = `
|
|
1071
|
+
|
|
1072
|
+
export const ${_methodName} = (
|
|
1073
|
+
sdk: AccelByteSDK,
|
|
1074
|
+
options?: Omit<UseMutationOptions<${_responseType}, AxiosError<ApiError>, SdkSetConfigParam ${_methodParams}>, 'mutationKey'>,
|
|
1075
|
+
callback?: (data: ${_responseType}) => void
|
|
1076
|
+
): UseMutationResult<${_responseType}, AxiosError<ApiError>, SdkSetConfigParam ${_methodParams}> => {
|
|
1077
|
+
//
|
|
1078
|
+
const mutationFn = async (input: SdkSetConfigParam ${_methodParams}) => {
|
|
1079
|
+
const response =
|
|
1080
|
+
(await ${apiGenName}(sdk, { coreConfig: input.coreConfig, axiosConfig: input.axiosConfig }).
|
|
1081
|
+
${classMethod}(${_methodParamsImpl}))
|
|
1082
|
+
callback && callback(response.data)
|
|
1083
|
+
return response.data
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
return useMutation({
|
|
1087
|
+
mutationKey: [${createQueryKey(apiGenName, classMethod)}],
|
|
1088
|
+
mutationFn,
|
|
1089
|
+
...options
|
|
1090
|
+
})
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
`;
|
|
1094
|
+
return isGet ? queryMethodImpl : mutationMethodImpl;
|
|
1095
|
+
};
|
|
1096
|
+
function createQueryKey(className, methodName) {
|
|
1097
|
+
const prefixRegex = /^(get|create|update|delete|patch|post|fetch)[_]?/i;
|
|
1098
|
+
const cleanedMethodName = methodName.replace(prefixRegex, "").trim();
|
|
1099
|
+
const finalMethodName = cleanedMethodName.charAt(0).toUpperCase() + cleanedMethodName.slice(1);
|
|
1100
|
+
return `Key_${className.replace("Api", "")}.${finalMethodName}`;
|
|
1101
|
+
}
|
|
1102
|
+
var prefixMappings = {
|
|
1103
|
+
get: "use",
|
|
1104
|
+
create: "useCreate",
|
|
1105
|
+
patch: "usePatch",
|
|
1106
|
+
update: "useUpdate",
|
|
1107
|
+
delete: "useDelete",
|
|
1108
|
+
post: "usePost",
|
|
1109
|
+
fetch: "useFetch"
|
|
1110
|
+
};
|
|
1111
|
+
function convertMethodNameToHook({
|
|
1112
|
+
classMethod,
|
|
1113
|
+
apiGenName,
|
|
1114
|
+
isPostFetch,
|
|
1115
|
+
isFetch
|
|
1116
|
+
}) {
|
|
1117
|
+
for (const [originalPrefix, newPrefix] of Object.entries(prefixMappings)) {
|
|
1118
|
+
if (classMethod.startsWith(originalPrefix)) {
|
|
1119
|
+
return `use${apiGenName}_${capitalize(classMethod)}`;
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
return classMethod;
|
|
1123
|
+
}
|
|
1124
|
+
function convertToMethodImplArgs(methodArgs) {
|
|
1125
|
+
const properties = methodArgs.split(/,\s*(?![^{}]*\})/).map((prop) => prop.trim()).filter(Boolean);
|
|
1126
|
+
const formattedProperties = [];
|
|
1127
|
+
properties.forEach((prop) => {
|
|
1128
|
+
if (prop.includes(": {")) {
|
|
1129
|
+
const propertyName = prop.split(": {")[0].replace("?", "").trim();
|
|
1130
|
+
formattedProperties.push(`input.${propertyName}`);
|
|
1131
|
+
} else {
|
|
1132
|
+
const colonIndex = prop.indexOf(":");
|
|
1133
|
+
const propertyName = prop.substring(0, colonIndex).replace("?", "").trim();
|
|
1134
|
+
formattedProperties.push(`input.${propertyName}`);
|
|
1135
|
+
}
|
|
1136
|
+
});
|
|
1137
|
+
return formattedProperties.join(", ");
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// src/templates/template-sdk-snippet.ts
|
|
1141
|
+
var templateSdkSnippet = ({
|
|
1142
|
+
serviceNameTitle,
|
|
1143
|
+
apiName,
|
|
1144
|
+
snippetMethod,
|
|
1145
|
+
snippetApiArgs: snippetApiArgsParam
|
|
1146
|
+
}) => {
|
|
1147
|
+
const methodArr = snippetMethod.split("//");
|
|
1148
|
+
const snippetApiArgs = ["sdk", ...snippetApiArgsParam];
|
|
1149
|
+
let normMethod = normalizeMethodSnippet(methodArr[0].trim(), "data:");
|
|
1150
|
+
normMethod = normalizeMethodSnippet(normMethod, "queryParams:");
|
|
1151
|
+
normMethod = normalizeMethodSnippet(normMethod, "queryParams?:");
|
|
1152
|
+
normMethod += "\n\n//" + methodArr[1];
|
|
1153
|
+
const sdkSnippet = `import { Accelbyte } from '@accelbyte/sdk'
|
|
1154
|
+
import { ${serviceNameTitle} } from '@accelbyte/sdk-${serviceNameTitle.toLowerCase()}'
|
|
1155
|
+
|
|
1156
|
+
const sdk = Accelbyte.SDK({
|
|
1157
|
+
options: {
|
|
1158
|
+
baseURL: 'https://demo.accelbyte.io',
|
|
1159
|
+
clientId: '77f88506b6174c3ea4d925f5b4096ce8',
|
|
1160
|
+
namespace: 'accelbyte',
|
|
1161
|
+
redirectURI: 'http://localhost:3030'
|
|
1162
|
+
}
|
|
1163
|
+
})
|
|
1164
|
+
|
|
1165
|
+
${serviceNameTitle}.${apiName}(${snippetApiArgs.join(", ")})
|
|
1166
|
+
.${normMethod}`;
|
|
1167
|
+
return sdkSnippet;
|
|
1168
|
+
};
|
|
1169
|
+
var normalizeMethodSnippet = (methodInput, splitWord) => {
|
|
1170
|
+
const split1 = methodInput.split(splitWord);
|
|
1171
|
+
if (!split1[1]) {
|
|
1172
|
+
return methodInput;
|
|
1173
|
+
}
|
|
1174
|
+
let split2 = split1[1].trim();
|
|
1175
|
+
split2 = ParserUtils.replaceAll(split2, "{", "");
|
|
1176
|
+
split2 = ParserUtils.replaceAll(split2, "})", "");
|
|
1177
|
+
split2 = split2.split(",");
|
|
1178
|
+
let params = "";
|
|
1179
|
+
split2.forEach((p) => {
|
|
1180
|
+
params += "\n " + ParserUtils.replaceAll(p.trim(), ")", "") + ",";
|
|
1181
|
+
});
|
|
1182
|
+
params = params.slice(0, -1);
|
|
1183
|
+
const result = split1[0] + splitWord + " {" + params + "\n })";
|
|
1184
|
+
return result;
|
|
1185
|
+
};
|
|
1186
|
+
|
|
1187
|
+
// src/helpers/SwaggerReaderHelpers.ts
|
|
1188
|
+
var GIT_URL = "https://github.com/AccelByte/accelbyte-web-sdk/blob/main/packages";
|
|
1189
|
+
var SwaggerReaderHelpers = class _SwaggerReaderHelpers {
|
|
1190
|
+
static getServicePrefix = (servicePaths) => servicePaths[servicePaths.length - 1].split("/")[1];
|
|
1191
|
+
static parseAllEndpoints = async ({
|
|
1192
|
+
api,
|
|
1193
|
+
sdkName,
|
|
1194
|
+
serviceName
|
|
1195
|
+
}) => {
|
|
1196
|
+
const result = {
|
|
1197
|
+
admin: {
|
|
1198
|
+
arrayDefinitions: [],
|
|
1199
|
+
snippetMap: {},
|
|
1200
|
+
tagToClassImportsRecord: {},
|
|
1201
|
+
tagToEndpointClassesRecord: {},
|
|
1202
|
+
tagToSdkClientRecord: {},
|
|
1203
|
+
tagToSdkFunctionNamesRecord: {},
|
|
1204
|
+
tagToSdkImportsRecord: {},
|
|
1205
|
+
tagToEndpointQueryRecord: {}
|
|
1206
|
+
},
|
|
1207
|
+
public: {
|
|
1208
|
+
arrayDefinitions: [],
|
|
1209
|
+
snippetMap: {},
|
|
1210
|
+
tagToClassImportsRecord: {},
|
|
1211
|
+
tagToEndpointClassesRecord: {},
|
|
1212
|
+
tagToSdkClientRecord: {},
|
|
1213
|
+
tagToSdkFunctionNamesRecord: {},
|
|
1214
|
+
tagToSdkImportsRecord: {},
|
|
1215
|
+
tagToEndpointQueryRecord: {}
|
|
1216
|
+
}
|
|
1217
|
+
};
|
|
1218
|
+
const sortedPathsByLength = new Map(
|
|
1219
|
+
Object.entries(api.paths).sort((a, b) => {
|
|
1220
|
+
if (a[0].length === b[0].length) {
|
|
1221
|
+
return a[0].localeCompare(b[0]);
|
|
1222
|
+
} else {
|
|
1223
|
+
return a[0].length - b[0].length;
|
|
1224
|
+
}
|
|
1225
|
+
})
|
|
1226
|
+
);
|
|
1227
|
+
const sortedKeys = Array.from(sortedPathsByLength.keys());
|
|
1228
|
+
const servicePrefix = _SwaggerReaderHelpers.getServicePrefix(sortedKeys);
|
|
1229
|
+
const tagToClassMethodsMap = {
|
|
1230
|
+
admin: {},
|
|
1231
|
+
public: {}
|
|
1232
|
+
};
|
|
1233
|
+
for (const [path7, operation] of sortedPathsByLength) {
|
|
1234
|
+
if (path7.indexOf("/healthz") >= 0) {
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1237
|
+
const isAdminEndpoint = path7.indexOf("/admin/") > -1;
|
|
1238
|
+
const picked = isAdminEndpoint ? result.admin : result.public;
|
|
1239
|
+
const {
|
|
1240
|
+
arrayDefinitions,
|
|
1241
|
+
snippetMap,
|
|
1242
|
+
tagToClassImportsRecord,
|
|
1243
|
+
tagToEndpointClassesRecord,
|
|
1244
|
+
tagToSdkClientRecord,
|
|
1245
|
+
tagToSdkFunctionNamesRecord,
|
|
1246
|
+
tagToSdkImportsRecord,
|
|
1247
|
+
tagToEndpointQueryRecord
|
|
1248
|
+
} = picked;
|
|
1249
|
+
const tagToClassMethodsMapByType = isAdminEndpoint ? tagToClassMethodsMap.admin : tagToClassMethodsMap.public;
|
|
1250
|
+
const generatedMethods = {};
|
|
1251
|
+
const httpMethods = Object.keys(operation);
|
|
1252
|
+
for (const httpMethod of httpMethods) {
|
|
1253
|
+
const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
|
|
1254
|
+
console.error(JSON.stringify({ path: path7, httpMethod }, null, 2));
|
|
1255
|
+
throw error;
|
|
1256
|
+
});
|
|
1257
|
+
if (!endpoint.tags) continue;
|
|
1258
|
+
const [tag] = endpoint.tags;
|
|
1259
|
+
const pathWithBase = `${api.basePath ?? ""}${path7}`;
|
|
1260
|
+
const permissionType = getPermissionType(getPermission(endpoint));
|
|
1261
|
+
tagToClassMethodsMapByType[tag] = tagToClassMethodsMapByType[tag] ? tagToClassMethodsMapByType[tag] : {};
|
|
1262
|
+
const isForm = endpoint.consumes && endpoint.consumes[0] === "application/x-www-form-urlencoded";
|
|
1263
|
+
const classMethod = ParserUtils.generateNaturalLangMethod({
|
|
1264
|
+
servicePrefix,
|
|
1265
|
+
path: path7,
|
|
1266
|
+
httpMethod,
|
|
1267
|
+
isForm,
|
|
1268
|
+
existingMethods: tagToClassMethodsMapByType[tag],
|
|
1269
|
+
permissionType
|
|
1270
|
+
});
|
|
1271
|
+
tagToClassMethodsMapByType[tag][classMethod] = `${path7} ${httpMethod}`;
|
|
1272
|
+
generatedMethods[`${path7} ${httpMethod}`] = `${classMethod}`;
|
|
1273
|
+
if (!snippetMap[pathWithBase]) {
|
|
1274
|
+
snippetMap[pathWithBase] = {};
|
|
1275
|
+
}
|
|
1276
|
+
const description = endpoint.description?.replace(/\s+/g, " ") || "";
|
|
1277
|
+
const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
|
|
1278
|
+
const { className, classGenName } = ParserUtils.generateClassName(tag, isAdminEndpoint);
|
|
1279
|
+
tagToClassImportsRecord[className] = tagToClassImportsRecord[className] ? tagToClassImportsRecord[className] : {};
|
|
1280
|
+
if (responseClass) {
|
|
1281
|
+
const importTypeClass = ParserUtils.parseRefType(responseClass);
|
|
1282
|
+
tagToClassImportsRecord[className][importTypeClass] = `import { ${importTypeClass} } from '../../generated-definitions/${importTypeClass}.js'`;
|
|
1283
|
+
}
|
|
1284
|
+
if (responseClass && responseClass.endsWith("Array")) {
|
|
1285
|
+
arrayDefinitions.push(responseClass);
|
|
1286
|
+
}
|
|
1287
|
+
const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
|
|
1288
|
+
const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
|
|
1289
|
+
const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
|
|
1290
|
+
let bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
|
|
1291
|
+
const deprecated = !!endpoint.deprecated;
|
|
1292
|
+
if (endpoint.requestBody) {
|
|
1293
|
+
bodyParams = [
|
|
1294
|
+
{
|
|
1295
|
+
name: "body",
|
|
1296
|
+
in: "body",
|
|
1297
|
+
schema: endpoint.requestBody.content["application/json"]?.schema
|
|
1298
|
+
}
|
|
1299
|
+
];
|
|
1300
|
+
}
|
|
1301
|
+
const { methodImpl, methodParams, methodParamsNoTypes, importStatements } = templateMethod({
|
|
1302
|
+
classMethod,
|
|
1303
|
+
description,
|
|
1304
|
+
httpMethod,
|
|
1305
|
+
path: pathWithBase,
|
|
1306
|
+
pathParams,
|
|
1307
|
+
bodyParams,
|
|
1308
|
+
queryParams,
|
|
1309
|
+
isFormUrlEncoded,
|
|
1310
|
+
responseClass,
|
|
1311
|
+
deprecated
|
|
1312
|
+
});
|
|
1313
|
+
tagToEndpointClassesRecord[tag] = (tagToEndpointClassesRecord[tag] || "") + methodImpl;
|
|
1314
|
+
const { apiGenName } = ParserUtils.generateApiName(tag, isAdminEndpoint);
|
|
1315
|
+
const queryMethodImpl = templateQueryMethod({
|
|
1316
|
+
classMethod,
|
|
1317
|
+
httpMethod,
|
|
1318
|
+
path: pathWithBase,
|
|
1319
|
+
pathParams,
|
|
1320
|
+
responseClass,
|
|
1321
|
+
methodParams,
|
|
1322
|
+
apiGenName
|
|
1323
|
+
});
|
|
1324
|
+
tagToEndpointQueryRecord[tag] = (tagToEndpointQueryRecord[tag] || "") + queryMethodImpl;
|
|
1325
|
+
const { generatedMethodString, snippetApiArgs, snippetMethod, snippetShell } = templateApiMethod({
|
|
1326
|
+
classMethod,
|
|
1327
|
+
description,
|
|
1328
|
+
httpMethod,
|
|
1329
|
+
path: pathWithBase,
|
|
1330
|
+
pathParams,
|
|
1331
|
+
bodyParams,
|
|
1332
|
+
responseClass,
|
|
1333
|
+
classGenName,
|
|
1334
|
+
methodParams,
|
|
1335
|
+
methodParamsNoTypes,
|
|
1336
|
+
deprecated,
|
|
1337
|
+
xSecurity: endpoint["x-security"]
|
|
1338
|
+
});
|
|
1339
|
+
tagToSdkClientRecord[tag] = (tagToSdkClientRecord[tag] || "") + generatedMethodString;
|
|
1340
|
+
tagToSdkFunctionNamesRecord[tag] = (tagToSdkFunctionNamesRecord[tag] || "") + classMethod + ",";
|
|
1341
|
+
tagToSdkImportsRecord[tag] = tagToSdkImportsRecord[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...tagToSdkImportsRecord[tag]])] : [...new Set(importStatements)];
|
|
1342
|
+
const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
|
|
1343
|
+
const resultSnippet = templateSdkSnippet({
|
|
1344
|
+
serviceNameTitle,
|
|
1345
|
+
apiName: apiGenName,
|
|
1346
|
+
snippetMethod,
|
|
1347
|
+
snippetApiArgs
|
|
1348
|
+
});
|
|
1349
|
+
const currentSnippetMap = {};
|
|
1350
|
+
snippetMap[pathWithBase][httpMethod] = currentSnippetMap;
|
|
1351
|
+
currentSnippetMap.web = resultSnippet;
|
|
1352
|
+
const generatedDirName = isAdminEndpoint ? "generated-admin" : "generated-public";
|
|
1353
|
+
currentSnippetMap.webGit = GIT_URL + `/sdk-${sdkName}/src/${generatedDirName}/${apiGenName}.ts`;
|
|
1354
|
+
currentSnippetMap.shell = snippetShell;
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
for (const key in result) {
|
|
1358
|
+
result[key].arrayDefinitions = Array.from(new Set(result[key].arrayDefinitions));
|
|
1359
|
+
}
|
|
1360
|
+
return result;
|
|
1361
|
+
};
|
|
1362
|
+
};
|
|
1363
|
+
|
|
1364
|
+
// src/templates/template-api-index.ts
|
|
1365
|
+
var templateApiIndex = (serviceName, serviceNameTitle, apiList) => {
|
|
1366
|
+
let imports = "";
|
|
1367
|
+
let returnStatement = "";
|
|
1368
|
+
for (const cl of apiList) {
|
|
1369
|
+
const dir = cl.toLowerCase().includes("admin") && cl !== "AdminApi" ? "generated-admin" : "generated-public";
|
|
1370
|
+
imports += `
|
|
1371
|
+
import { ${cl} } from './${dir}/${cl}.js'`;
|
|
1372
|
+
returnStatement += `
|
|
1373
|
+
${cl}, `;
|
|
1374
|
+
}
|
|
1375
|
+
return `/**
|
|
1376
|
+
* AUTO GENERATED
|
|
1377
|
+
*/
|
|
1378
|
+
${imports}
|
|
1379
|
+
|
|
1380
|
+
const apis = {
|
|
1381
|
+
${returnStatement}
|
|
1382
|
+
}
|
|
1383
|
+
|
|
1384
|
+
export const ${serviceNameTitle} = apis
|
|
1385
|
+
`;
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
// src/templates/template-zod.ts
|
|
1389
|
+
var TemplateZod = class {
|
|
1390
|
+
duplicates;
|
|
1391
|
+
duplicateFound = false;
|
|
1392
|
+
//
|
|
1393
|
+
importClasses = /* @__PURE__ */ new Set();
|
|
1394
|
+
// --
|
|
1395
|
+
render = (fileName, definition, duplicates) => {
|
|
1396
|
+
this.duplicates = duplicates;
|
|
1397
|
+
const content = this.parseToZodSchema(definition, definition.required || []);
|
|
1398
|
+
const containsRecursiveType = this.importClasses.has(fileName);
|
|
1399
|
+
if (containsRecursiveType) {
|
|
1400
|
+
this.importClasses.delete(fileName);
|
|
1401
|
+
}
|
|
1402
|
+
let imports = "";
|
|
1403
|
+
for (const cl of Array.from(this.importClasses).sort()) {
|
|
1404
|
+
imports += `import { ${cl} } from './${cl}.js'
|
|
1405
|
+
`;
|
|
1406
|
+
}
|
|
1407
|
+
let exportedVariableString;
|
|
1408
|
+
let exportedTypeString;
|
|
1409
|
+
if (containsRecursiveType) {
|
|
1410
|
+
exportedVariableString = `
|
|
1411
|
+
export const ${fileName}: z.ZodType<${fileName}> = z.lazy(() =>
|
|
1412
|
+
${content.schemaString}
|
|
1413
|
+
)
|
|
1414
|
+
`;
|
|
1415
|
+
exportedTypeString = `
|
|
1416
|
+
export interface ${fileName} {
|
|
1417
|
+
${content.typeString}
|
|
1418
|
+
}
|
|
1419
|
+
`;
|
|
1420
|
+
} else {
|
|
1421
|
+
exportedVariableString = `export const ${fileName} = ${content.schemaString}`;
|
|
1422
|
+
exportedTypeString = `export interface ${fileName} extends z.TypeOf<typeof ${fileName}> {}`;
|
|
1423
|
+
}
|
|
1424
|
+
const template = `import { z } from 'zod'
|
|
1425
|
+
${imports}
|
|
1426
|
+
|
|
1427
|
+
${exportedVariableString}
|
|
1428
|
+
|
|
1429
|
+
${exportedTypeString}
|
|
1430
|
+
`;
|
|
1431
|
+
return { buffer: template, duplicateFound: this.duplicateFound };
|
|
1432
|
+
};
|
|
1433
|
+
// --
|
|
1434
|
+
parseToZodSchema = (definition, requiredAttrs) => {
|
|
1435
|
+
if (definition.additionalProperties) {
|
|
1436
|
+
return this.parseToZodAttribute("", definition, []);
|
|
1437
|
+
}
|
|
1438
|
+
let properties;
|
|
1439
|
+
if (definition.properties) {
|
|
1440
|
+
properties = Object.entries(definition.properties);
|
|
1441
|
+
} else if (definition.items?.properties) {
|
|
1442
|
+
properties = Object.entries(definition.items.properties);
|
|
1443
|
+
} else {
|
|
1444
|
+
return {
|
|
1445
|
+
schemaString: "z.any()",
|
|
1446
|
+
typeString: "any"
|
|
1447
|
+
};
|
|
1448
|
+
}
|
|
1449
|
+
const schemaFields = [];
|
|
1450
|
+
const typeFields = [];
|
|
1451
|
+
for (const property of properties) {
|
|
1452
|
+
const [name, definition2] = property;
|
|
1453
|
+
const result = this.parseToZodAttribute(name, definition2, requiredAttrs);
|
|
1454
|
+
schemaFields.push(result.schemaString);
|
|
1455
|
+
typeFields.push(result.typeString);
|
|
1456
|
+
}
|
|
1457
|
+
if (definition?.type === "array") {
|
|
1458
|
+
return {
|
|
1459
|
+
schemaString: `z.array(z.object({${schemaFields.join(",")}}))`,
|
|
1460
|
+
typeString: typeFields.join(";")
|
|
1461
|
+
};
|
|
1462
|
+
}
|
|
1463
|
+
return {
|
|
1464
|
+
schemaString: `z.object({${schemaFields.join(",")}})`,
|
|
1465
|
+
typeString: typeFields.join(";")
|
|
1466
|
+
};
|
|
1467
|
+
};
|
|
1468
|
+
// --
|
|
1469
|
+
parseToZodAttribute = (name, definition, requiredAttrs) => {
|
|
1470
|
+
const isRequired = requiredAttrs.includes(name) || name === "";
|
|
1471
|
+
const schemaRequired = isRequired ? "" : ".nullish()";
|
|
1472
|
+
const typeRequired = isRequired ? "" : "?";
|
|
1473
|
+
const typeNullishability = isRequired ? "" : " | null | undefined";
|
|
1474
|
+
const schemaAttribute = name ? `'${name}':` : "";
|
|
1475
|
+
const typeAttribute = name ? `'${name}'${typeRequired}:` : "";
|
|
1476
|
+
const type = definition?.type;
|
|
1477
|
+
if (definition.properties) {
|
|
1478
|
+
const result = this.parseToZodSchema(definition, requiredAttrs);
|
|
1479
|
+
return {
|
|
1480
|
+
schemaString: `${schemaAttribute} ${result.schemaString}${schemaRequired}`,
|
|
1481
|
+
typeString: `${typeAttribute} ${result.typeString}${typeNullishability}`
|
|
1482
|
+
};
|
|
1483
|
+
} else if (type) {
|
|
1484
|
+
if (type === "object" && definition.additionalProperties) {
|
|
1485
|
+
const zodAttribute = this.parseToZodAttribute("", definition.additionalProperties, [""]);
|
|
1486
|
+
return {
|
|
1487
|
+
schemaString: `${schemaAttribute} z.record(${zodAttribute.schemaString})${schemaRequired}`,
|
|
1488
|
+
typeString: `${typeAttribute} Record<string, ${zodAttribute.typeString}>${typeNullishability}`
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
if (type === "object" && !definition.additionalProperties && !name) {
|
|
1492
|
+
return {
|
|
1493
|
+
schemaString: `z.any()`,
|
|
1494
|
+
typeString: "any"
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
if (type === "object" && !definition.additionalProperties) {
|
|
1498
|
+
return {
|
|
1499
|
+
schemaString: `${schemaAttribute} z.record(z.any())${schemaRequired}`,
|
|
1500
|
+
typeString: `${typeAttribute} Record<string, any>${typeNullishability}`
|
|
1501
|
+
};
|
|
1502
|
+
}
|
|
1503
|
+
if (type === "integer" || type === "number") {
|
|
1504
|
+
const effectiveType = getZodNumberType(type);
|
|
1505
|
+
return {
|
|
1506
|
+
schemaString: `${schemaAttribute} z.${effectiveType.schemaString}()${schemaRequired}`,
|
|
1507
|
+
typeString: `${typeAttribute} ${effectiveType.typeString}${typeNullishability}`
|
|
1508
|
+
};
|
|
1509
|
+
}
|
|
1510
|
+
if (type === "array") {
|
|
1511
|
+
const items = definition.items;
|
|
1512
|
+
const ref2 = items?.$ref;
|
|
1513
|
+
let model2;
|
|
1514
|
+
if (ref2) {
|
|
1515
|
+
const refType = ParserUtils.parseRefType(ref2);
|
|
1516
|
+
this.importClasses.add(refType);
|
|
1517
|
+
model2 = {
|
|
1518
|
+
schemaString: refType,
|
|
1519
|
+
typeString: refType
|
|
1520
|
+
};
|
|
1521
|
+
} else if (items) {
|
|
1522
|
+
if (items.type === "array") {
|
|
1523
|
+
const ref3 = items.items?.$ref;
|
|
1524
|
+
if (ref3) {
|
|
1525
|
+
const refType = ParserUtils.parseRefType(ref3);
|
|
1526
|
+
this.importClasses.add(refType);
|
|
1527
|
+
model2 = {
|
|
1528
|
+
schemaString: refType,
|
|
1529
|
+
typeString: refType
|
|
1530
|
+
};
|
|
1531
|
+
} else if (items.items) {
|
|
1532
|
+
model2 = this.parseEnumItems(items.items);
|
|
1533
|
+
}
|
|
1534
|
+
return {
|
|
1535
|
+
schemaString: `${schemaAttribute} z.array(z.array(${model2.schemaString}))${schemaRequired}`,
|
|
1536
|
+
typeString: `${typeAttribute} ${model2.typeString}[]${typeNullishability}`
|
|
1537
|
+
};
|
|
1538
|
+
} else {
|
|
1539
|
+
model2 = this.parseEnumItems(items);
|
|
1540
|
+
}
|
|
1541
|
+
} else {
|
|
1542
|
+
return {
|
|
1543
|
+
schemaString: `${schemaAttribute} z.array(z.any())${schemaRequired}`,
|
|
1544
|
+
typeString: `${typeAttribute} any[]${typeNullishability}`
|
|
1545
|
+
};
|
|
1546
|
+
}
|
|
1547
|
+
return {
|
|
1548
|
+
schemaString: `${schemaAttribute} z.array(${model2.schemaString})${schemaRequired}`,
|
|
1549
|
+
typeString: `${typeAttribute} ${model2.typeString}[]${typeNullishability}`
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
if (type !== "object") {
|
|
1553
|
+
const result = extractEnumObject(type, isRequired, definition.enum);
|
|
1554
|
+
return {
|
|
1555
|
+
schemaString: `${schemaAttribute} ${result.schemaString}`,
|
|
1556
|
+
typeString: `${typeAttribute} ${result.typeString}`
|
|
1557
|
+
};
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
const ref = definition.$ref;
|
|
1561
|
+
let model = `z.record(z.any())`;
|
|
1562
|
+
if (ref) {
|
|
1563
|
+
model = ParserUtils.parseRefType(ref);
|
|
1564
|
+
const fullModelName = ref.replace("#/definitions/", "");
|
|
1565
|
+
this.duplicateFound = this.duplicates.has(fullModelName);
|
|
1566
|
+
if (this.duplicateFound) {
|
|
1567
|
+
model = this.duplicates.get(fullModelName);
|
|
1568
|
+
}
|
|
1569
|
+
this.importClasses.add(model);
|
|
1570
|
+
model = `${model}`;
|
|
1571
|
+
}
|
|
1572
|
+
return {
|
|
1573
|
+
schemaString: `${schemaAttribute} ${model}${schemaRequired}`,
|
|
1574
|
+
typeString: `${typeAttribute} ${model}${typeNullishability}`
|
|
1575
|
+
};
|
|
1576
|
+
};
|
|
1577
|
+
parseEnumItems = (items) => {
|
|
1578
|
+
if (items.enum) {
|
|
1579
|
+
const enumStr = items.enum.map((e) => {
|
|
1580
|
+
return `"${e}"`;
|
|
1581
|
+
});
|
|
1582
|
+
return {
|
|
1583
|
+
schemaString: `z.enum([${enumStr}])`,
|
|
1584
|
+
typeString: `(${enumStr.join(" | ")})`
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
if (items.type === "object") {
|
|
1588
|
+
return this.parseToZodSchema(items, items.required);
|
|
1589
|
+
}
|
|
1590
|
+
let effectiveType;
|
|
1591
|
+
if (items.type === "integer" || items.type === "number") {
|
|
1592
|
+
effectiveType = getZodNumberType(items.type);
|
|
1593
|
+
} else {
|
|
1594
|
+
effectiveType = { typeString: items.type, schemaString: items.type };
|
|
1595
|
+
}
|
|
1596
|
+
return {
|
|
1597
|
+
schemaString: `z.${effectiveType.schemaString}()`,
|
|
1598
|
+
typeString: effectiveType.typeString
|
|
1599
|
+
};
|
|
1600
|
+
};
|
|
1601
|
+
};
|
|
1602
|
+
var TemplateZodArray = class {
|
|
1603
|
+
//
|
|
1604
|
+
render = (name) => {
|
|
1605
|
+
const cls = name.replace("Array", "");
|
|
1606
|
+
const template = `import { z } from 'zod'
|
|
1607
|
+
import { ${cls} } from './${cls}.js'
|
|
1608
|
+
|
|
1609
|
+
export const ${name} = z.array(${cls})
|
|
1610
|
+
|
|
1611
|
+
export interface ${name} extends z.TypeOf<typeof ${name}> {}
|
|
1612
|
+
`;
|
|
1613
|
+
return template;
|
|
1614
|
+
};
|
|
1615
|
+
};
|
|
1616
|
+
var getZodNumberType = (type) => {
|
|
1617
|
+
if (type === "integer") {
|
|
1618
|
+
return {
|
|
1619
|
+
schemaString: "number().int",
|
|
1620
|
+
typeString: "number"
|
|
1621
|
+
};
|
|
1622
|
+
}
|
|
1623
|
+
return {
|
|
1624
|
+
schemaString: type,
|
|
1625
|
+
typeString: type
|
|
1626
|
+
};
|
|
1627
|
+
};
|
|
1628
|
+
var extractEnumObject = (type, isRequired, enumArr) => {
|
|
1629
|
+
const schemaRequired = isRequired ? "" : ".nullish()";
|
|
1630
|
+
const typeNullishability = isRequired ? "" : " | null | undefined";
|
|
1631
|
+
if (enumArr) {
|
|
1632
|
+
const enumStr = enumArr.map((e) => {
|
|
1633
|
+
return `"${e}"`;
|
|
1634
|
+
});
|
|
1635
|
+
return {
|
|
1636
|
+
schemaString: `z.enum([${enumStr}])${schemaRequired}`,
|
|
1637
|
+
typeString: `(${enumStr.join(" | ")}${typeNullishability})`
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
return {
|
|
1641
|
+
schemaString: `z.${type}()${schemaRequired}`,
|
|
1642
|
+
typeString: `${type}${typeNullishability}`
|
|
1643
|
+
};
|
|
1644
|
+
};
|
|
1645
|
+
|
|
1646
|
+
// src/CodeGenerator.ts
|
|
1647
|
+
var CodeGenerator = class _CodeGenerator {
|
|
1648
|
+
static srcFolder = () => CliParser.getOutputPath();
|
|
1649
|
+
static getGeneratedFolder = (isAdmin) => isAdmin ? `${_CodeGenerator.srcFolder()}/generated-admin` : `${_CodeGenerator.srcFolder()}/generated-public`;
|
|
1650
|
+
static getGeneratedSnippetsFolder = () => `${CliParser.getSnippetOutputPath()}/generated-snippets`;
|
|
1651
|
+
static prepareDirs = (DIST_DEFINITION_DIR, DIST_DIR, DIST_DIR_ENDPOINTS, DIST_DIR_QUERIES) => {
|
|
1652
|
+
ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
|
|
1653
|
+
ParserUtils.mkdirIfNotExist(DIST_DIR(true));
|
|
1654
|
+
ParserUtils.mkdirIfNotExist(DIST_DIR(false));
|
|
1655
|
+
ParserUtils.mkdirIfNotExist(DIST_DIR_ENDPOINTS(true));
|
|
1656
|
+
ParserUtils.mkdirIfNotExist(DIST_DIR_ENDPOINTS(false));
|
|
1657
|
+
ParserUtils.mkdirIfNotExist(DIST_DIR_QUERIES(true));
|
|
1658
|
+
};
|
|
1659
|
+
static main = async (nameArray) => {
|
|
1660
|
+
const serviceName = nameArray[0];
|
|
1661
|
+
const sdkName = nameArray[1];
|
|
1662
|
+
const swaggerFile = nameArray[2];
|
|
1663
|
+
const parser = new SwaggerParser();
|
|
1664
|
+
const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
|
|
1665
|
+
const api = await parser.parse(swaggerFilePath);
|
|
1666
|
+
const serviceNameTitle = ParserUtils.convertDashesToTitleCase(serviceName);
|
|
1667
|
+
const indexImportsSet = /* @__PURE__ */ new Set();
|
|
1668
|
+
const queryImportsSet = /* @__PURE__ */ new Set();
|
|
1669
|
+
const apiInfo = { ...api.info, "x-version": api["x-version"]?.version };
|
|
1670
|
+
console.log("----------\nGenerating API:", { title: apiInfo.title, version: apiInfo.version });
|
|
1671
|
+
ParserUtils.writeXVersion(_CodeGenerator.srcFolder(), api["x-version"], api.info);
|
|
1672
|
+
const parsedInformation = await SwaggerReaderHelpers.parseAllEndpoints({ api, sdkName, serviceName });
|
|
1673
|
+
if (CliParser.getSnippetOutputPath()) {
|
|
1674
|
+
try {
|
|
1675
|
+
ParserUtils.writeSnippetFile(
|
|
1676
|
+
_CodeGenerator.getGeneratedSnippetsFolder(),
|
|
1677
|
+
api.info.title,
|
|
1678
|
+
JSON.stringify(
|
|
1679
|
+
{
|
|
1680
|
+
...parsedInformation.public.snippetMap,
|
|
1681
|
+
...parsedInformation.admin.snippetMap
|
|
1682
|
+
},
|
|
1683
|
+
null,
|
|
1684
|
+
2
|
|
1685
|
+
)
|
|
1686
|
+
);
|
|
1687
|
+
} catch (err) {
|
|
1688
|
+
console.log("Generating snippets", err);
|
|
1689
|
+
}
|
|
1690
|
+
}
|
|
1691
|
+
const DIST_DIR = (isAdmin) => `${_CodeGenerator.getGeneratedFolder(isAdmin)}`;
|
|
1692
|
+
const DIST_DIR_ENDPOINTS = (isAdmin) => path4.join(DIST_DIR(isAdmin), "endpoints");
|
|
1693
|
+
const DIST_DIR_QUERIES = (isAdmin) => path4.join(DIST_DIR(isAdmin), "queries");
|
|
1694
|
+
const DIST_DEFINITION_DIR = path4.join(_CodeGenerator.srcFolder(), "generated-definitions");
|
|
1695
|
+
const targetSrcFolder = `${_CodeGenerator.srcFolder()}/`;
|
|
1696
|
+
_CodeGenerator.prepareDirs(DIST_DEFINITION_DIR, DIST_DIR, DIST_DIR_ENDPOINTS, DIST_DIR_QUERIES);
|
|
1697
|
+
const mainApiList = [];
|
|
1698
|
+
const generatedDefinitions = [];
|
|
1699
|
+
const generatePublicOrAdmin = (isAdmin) => {
|
|
1700
|
+
const parsedInformationByType = isAdmin ? parsedInformation.admin : parsedInformation.public;
|
|
1701
|
+
const {
|
|
1702
|
+
arrayDefinitions,
|
|
1703
|
+
tagToClassImportsRecord,
|
|
1704
|
+
tagToEndpointClassesRecord,
|
|
1705
|
+
tagToSdkClientRecord,
|
|
1706
|
+
tagToSdkFunctionNamesRecord,
|
|
1707
|
+
tagToSdkImportsRecord,
|
|
1708
|
+
tagToEndpointQueryRecord
|
|
1709
|
+
} = parsedInformationByType;
|
|
1710
|
+
const writeApiEndpointFiles = (isAdminEndpoint) => {
|
|
1711
|
+
const apiList = [];
|
|
1712
|
+
for (const tag in tagToEndpointClassesRecord) {
|
|
1713
|
+
const { className, classGenName } = ParserUtils.generateClassName(tag, isAdminEndpoint);
|
|
1714
|
+
const classBuffer = tagToEndpointClassesRecord[tag];
|
|
1715
|
+
const imports = [.../* @__PURE__ */ new Set([...tagToSdkImportsRecord[tag], ...Object.values(tagToClassImportsRecord[className])])];
|
|
1716
|
+
const apiImports = [.../* @__PURE__ */ new Set([...tagToSdkImportsRecord[tag], ...Object.values(tagToClassImportsRecord[className])])];
|
|
1717
|
+
apiImports.push(`import { ${classGenName} } from './endpoints/${classGenName}.js'`);
|
|
1718
|
+
ParserUtils.writeClassFile(DIST_DIR_ENDPOINTS(isAdminEndpoint), classGenName, classBuffer, imports);
|
|
1719
|
+
const { apiGenName } = ParserUtils.generateApiName(tag, isAdminEndpoint);
|
|
1720
|
+
const queryBuffer = tagToEndpointQueryRecord[tag];
|
|
1721
|
+
const queryFileName = !CliParser.skipReactQuery() && ParserUtils.writeQueryFile(
|
|
1722
|
+
DIST_DIR_QUERIES(isAdminEndpoint),
|
|
1723
|
+
apiGenName,
|
|
1724
|
+
queryBuffer,
|
|
1725
|
+
apiImports,
|
|
1726
|
+
serviceNameTitle,
|
|
1727
|
+
tagToSdkFunctionNamesRecord[tag],
|
|
1728
|
+
imports,
|
|
1729
|
+
sdkName
|
|
1730
|
+
);
|
|
1731
|
+
const apiBuffer = tagToSdkClientRecord[tag];
|
|
1732
|
+
ParserUtils.writeApiFile(DIST_DIR(isAdminEndpoint), apiGenName, apiBuffer, imports, tagToSdkFunctionNamesRecord[tag]);
|
|
1733
|
+
apiList.push(apiGenName);
|
|
1734
|
+
indexImportsSet.add(
|
|
1735
|
+
ParserUtils.getRelativePathToWebSdkSrcFolder(path4.join(DIST_DIR_ENDPOINTS(isAdminEndpoint), `${classGenName}`), targetSrcFolder)
|
|
1736
|
+
);
|
|
1737
|
+
indexImportsSet.add(
|
|
1738
|
+
ParserUtils.getRelativePathToWebSdkSrcFolder(path4.join(DIST_DIR(isAdminEndpoint), `${apiGenName}`), targetSrcFolder)
|
|
1739
|
+
);
|
|
1740
|
+
queryFileName && queryImportsSet.add(
|
|
1741
|
+
ParserUtils.getRelativePathToWebSdkSrcFolder(
|
|
1742
|
+
path4.join(DIST_DIR(isAdminEndpoint), "queries", `${queryFileName}`),
|
|
1743
|
+
targetSrcFolder
|
|
1744
|
+
)
|
|
1745
|
+
);
|
|
1746
|
+
}
|
|
1747
|
+
mainApiList.push(...apiList);
|
|
1748
|
+
indexImportsSet.add(
|
|
1749
|
+
ParserUtils.getRelativePathToWebSdkSrcFolder(path4.join(_CodeGenerator.srcFolder(), serviceNameTitle), targetSrcFolder)
|
|
1750
|
+
);
|
|
1751
|
+
};
|
|
1752
|
+
const writeDefinitions = (api2) => {
|
|
1753
|
+
const duplicates = /* @__PURE__ */ new Map();
|
|
1754
|
+
const definitions = api2?.components?.schemas || api2.definitions;
|
|
1755
|
+
for (const ref in definitions) {
|
|
1756
|
+
const definition = definitions[ref];
|
|
1757
|
+
const fileName = ParserUtils.parseRefType(ref);
|
|
1758
|
+
const fileExist = fs4.existsSync(path4.join(DIST_DEFINITION_DIR, `${fileName}.ts`));
|
|
1759
|
+
if (fileExist) {
|
|
1760
|
+
const duplicateName = ParserUtils.toCamelCaseWord(ref).replace(".", "").replace(".", "");
|
|
1761
|
+
duplicates.set(ref, duplicateName);
|
|
1762
|
+
}
|
|
1763
|
+
const { buffer } = new TemplateZod().render(fileName, definition, /* @__PURE__ */ new Map());
|
|
1764
|
+
generatedDefinitions.push(fileName);
|
|
1765
|
+
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, fileName, buffer);
|
|
1766
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path4.join(DIST_DEFINITION_DIR, fileName), targetSrcFolder));
|
|
1767
|
+
}
|
|
1768
|
+
for (const arrayClass of arrayDefinitions) {
|
|
1769
|
+
const buffer = new TemplateZodArray().render(arrayClass);
|
|
1770
|
+
generatedDefinitions.push(arrayClass);
|
|
1771
|
+
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, arrayClass, buffer);
|
|
1772
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path4.join(DIST_DEFINITION_DIR, arrayClass), targetSrcFolder));
|
|
1773
|
+
}
|
|
1774
|
+
};
|
|
1775
|
+
writeApiEndpointFiles(isAdmin);
|
|
1776
|
+
writeDefinitions(api);
|
|
1777
|
+
};
|
|
1778
|
+
generatePublicOrAdmin(true);
|
|
1779
|
+
generatePublicOrAdmin(false);
|
|
1780
|
+
const apiIndexBuff = templateApiIndex(serviceName, serviceNameTitle, mainApiList);
|
|
1781
|
+
ParserUtils.writeApiMainFile(_CodeGenerator.srcFolder(), serviceNameTitle, apiIndexBuff);
|
|
1782
|
+
console.log("\nCOMPLETED\n----------\n\n");
|
|
1783
|
+
return { indexImports: indexImportsSet, queryImports: queryImportsSet };
|
|
1784
|
+
};
|
|
1785
|
+
// end of main
|
|
1786
|
+
};
|
|
1787
|
+
|
|
1788
|
+
// src/SwaggerDownloader.ts
|
|
1789
|
+
import * as https from "https";
|
|
1790
|
+
import * as fs5 from "fs";
|
|
1791
|
+
import * as path5 from "path";
|
|
1792
|
+
var SwaggerDownloader = class _SwaggerDownloader {
|
|
1793
|
+
static getDestFile = (targetFileName) => {
|
|
1794
|
+
const destPath = CliParser.getResolvedSwaggersOutputPath();
|
|
1795
|
+
const destFile = path5.join(destPath, targetFileName);
|
|
1796
|
+
if (fs5.existsSync(destFile)) return destFile;
|
|
1797
|
+
if (!fs5.existsSync(destPath)) fs5.mkdirSync(destPath);
|
|
1798
|
+
fs5.writeFileSync(destFile, "");
|
|
1799
|
+
return destFile;
|
|
1800
|
+
};
|
|
1801
|
+
// session-api.json contains illegal URL encoded character that breaks the codegen
|
|
1802
|
+
// e.g. "$ref": "#/definitions/map%5Bstring%5Dinterface%20%7B%7D"
|
|
1803
|
+
static postSanitizeDownloadedFile = (filePath) => {
|
|
1804
|
+
const searchStr = ["%5B", "%5D", "%20", "%7B", "%7D"];
|
|
1805
|
+
fs5.readFile(filePath, "utf8", (err, data) => {
|
|
1806
|
+
if (err) throw err;
|
|
1807
|
+
let result = data;
|
|
1808
|
+
searchStr.forEach((s) => {
|
|
1809
|
+
result = result.replace(new RegExp(s, "g"), " ");
|
|
1810
|
+
});
|
|
1811
|
+
fs5.writeFile(filePath, result, "utf8", (err2) => {
|
|
1812
|
+
if (err2) throw err2;
|
|
1813
|
+
console.log("File updated successfully.");
|
|
1814
|
+
});
|
|
1815
|
+
});
|
|
1816
|
+
};
|
|
1817
|
+
static downloadFile = async (targetFileName, url) => {
|
|
1818
|
+
const destFile = _SwaggerDownloader.getDestFile(targetFileName);
|
|
1819
|
+
let data = "";
|
|
1820
|
+
return new Promise((resolve2) => {
|
|
1821
|
+
const request = https.get(url, function(response) {
|
|
1822
|
+
response.on("data", (chunk) => {
|
|
1823
|
+
data += chunk;
|
|
1824
|
+
});
|
|
1825
|
+
response.on("end", () => {
|
|
1826
|
+
if (response.statusCode !== 200) {
|
|
1827
|
+
console.log(`SwaggerDownload error with status code: ${response.statusCode}`);
|
|
1828
|
+
} else {
|
|
1829
|
+
fs5.writeFileSync(destFile, JSON.stringify(JSON.parse(data), null, 2), "utf-8");
|
|
1830
|
+
_SwaggerDownloader.postSanitizeDownloadedFile(destFile);
|
|
1831
|
+
console.log(`SwaggerDownload ${url} completed with status code: ${response.statusCode}`);
|
|
1832
|
+
}
|
|
1833
|
+
resolve2(void 0);
|
|
1834
|
+
});
|
|
1835
|
+
});
|
|
1836
|
+
request.on("error", (err) => {
|
|
1837
|
+
console.log(`SwaggerDownloader failed for "${targetFileName}" and "${url}"`, err);
|
|
1838
|
+
});
|
|
1839
|
+
});
|
|
1840
|
+
};
|
|
1841
|
+
static main = async () => {
|
|
1842
|
+
const swaggers = CliParser.getConfigFile();
|
|
1843
|
+
for (const ref in swaggers) {
|
|
1844
|
+
const targetFileName = swaggers[ref][2];
|
|
1845
|
+
const url = swaggers[ref][3];
|
|
1846
|
+
await _SwaggerDownloader.downloadFile(targetFileName, url);
|
|
1847
|
+
}
|
|
1848
|
+
};
|
|
1849
|
+
};
|
|
1850
|
+
|
|
1851
|
+
// src/cli.ts
|
|
1852
|
+
var generateSdk = async () => {
|
|
1853
|
+
const arrayOfSets = await Promise.all(CliParser.getConfigFile().map((config) => CodeGenerator.main(config)));
|
|
1854
|
+
const indexImportsSet = /* @__PURE__ */ new Set();
|
|
1855
|
+
const queryImportsSet = /* @__PURE__ */ new Set();
|
|
1856
|
+
const filenamesSet = /* @__PURE__ */ new Set();
|
|
1857
|
+
for (const set of arrayOfSets) {
|
|
1858
|
+
set.indexImports.forEach((value) => {
|
|
1859
|
+
const fileName = path6.basename(value);
|
|
1860
|
+
if (!filenamesSet.has(fileName)) {
|
|
1861
|
+
indexImportsSet.add(value);
|
|
1862
|
+
filenamesSet.add(fileName);
|
|
1863
|
+
}
|
|
1864
|
+
});
|
|
1865
|
+
set.queryImports.forEach((value) => {
|
|
1866
|
+
const fileName = path6.basename(value);
|
|
1867
|
+
if (!filenamesSet.has(fileName)) {
|
|
1868
|
+
queryImportsSet.add(value);
|
|
1869
|
+
}
|
|
1870
|
+
});
|
|
1871
|
+
}
|
|
1872
|
+
const indexImportsArray = Array.from(indexImportsSet).sort();
|
|
1873
|
+
const queryImportsArray = Array.from(queryImportsSet).sort();
|
|
1874
|
+
const filesToImport = indexImportsArray.map((fileToImport) => {
|
|
1875
|
+
return `export * from '${fileToImport.replace("\\", "/")}.js'`;
|
|
1876
|
+
});
|
|
1877
|
+
const queryFilesToImport = queryImportsArray.map((fileToImport) => {
|
|
1878
|
+
return `export * from '${fileToImport.replace("\\", "/")}.js'`;
|
|
1879
|
+
});
|
|
1880
|
+
ParserUtils.writeAllImportsFile(CliParser.getOutputPath(), filesToImport.join("\n"));
|
|
1881
|
+
ParserUtils.writeAllQueryImportsFile(CliParser.getOutputPath(), queryFilesToImport.join("\n"));
|
|
1882
|
+
};
|
|
1883
|
+
yargs.command("download-swaggers", "Download swaggers JSON files", (yargs2) => {
|
|
1884
|
+
CliParser.createInstance(yargs2);
|
|
1885
|
+
SwaggerDownloader.main();
|
|
1886
|
+
}).command("generate-code", "Generate code based on downloaded swagger files", async (yargs2) => {
|
|
1887
|
+
yargs2.check(({ output }) => {
|
|
1888
|
+
if (!output?.trim()) {
|
|
1889
|
+
throw new Error("output is required for generate-code");
|
|
1890
|
+
}
|
|
1891
|
+
return true;
|
|
1892
|
+
});
|
|
1893
|
+
CliParser.createInstance(yargs2);
|
|
1894
|
+
await generateSdk();
|
|
1895
|
+
}).option("config", {
|
|
1896
|
+
description: "Config file providing backend services URL.",
|
|
1897
|
+
type: "string",
|
|
1898
|
+
demandOption: true
|
|
1899
|
+
}).option("swaggersOutput", {
|
|
1900
|
+
description: "Output path for downloaded swaggers JSON files.",
|
|
1901
|
+
type: "string",
|
|
1902
|
+
demandOption: true
|
|
1903
|
+
}).option("output", {
|
|
1904
|
+
description: "Output path for generated code. Required for generate-code",
|
|
1905
|
+
type: "string"
|
|
1906
|
+
}).option("skipReactQuery", {
|
|
1907
|
+
description: "Skip generating react query",
|
|
1908
|
+
type: "boolean"
|
|
1909
|
+
}).demandCommand(1).help().argv;
|
|
1910
|
+
//# sourceMappingURL=accelbyte-codegen.mjs.map
|