@accelbyte/codegen 1.0.0-alpha.3 → 1.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +19 -0
- package/dist/accelbyte-codegen.js +246 -214
- package/dist/accelbyte-codegen.js.map +1 -1
- package/dist/accelbyte-codegen.mjs +212 -170
- package/dist/accelbyte-codegen.mjs.map +1 -1
- package/package.json +3 -3
|
@@ -11,10 +11,7 @@ var _ = require('lodash');
|
|
|
11
11
|
var fastJsonPatch = require('fast-json-patch');
|
|
12
12
|
var https = require('https');
|
|
13
13
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
function _interopNamespace(e) {
|
|
17
|
-
if (e && e.__esModule) return e;
|
|
14
|
+
function _interopNamespaceDefault(e) {
|
|
18
15
|
var n = Object.create(null);
|
|
19
16
|
if (e) {
|
|
20
17
|
Object.keys(e).forEach(function (k) {
|
|
@@ -22,25 +19,18 @@ function _interopNamespace(e) {
|
|
|
22
19
|
var d = Object.getOwnPropertyDescriptor(e, k);
|
|
23
20
|
Object.defineProperty(n, k, d.get ? d : {
|
|
24
21
|
enumerable: true,
|
|
25
|
-
get: function () {
|
|
26
|
-
return e[k];
|
|
27
|
-
}
|
|
22
|
+
get: function () { return e[k]; }
|
|
28
23
|
});
|
|
29
24
|
}
|
|
30
25
|
});
|
|
31
26
|
}
|
|
32
|
-
n
|
|
27
|
+
n.default = e;
|
|
33
28
|
return Object.freeze(n);
|
|
34
29
|
}
|
|
35
30
|
|
|
36
|
-
var
|
|
37
|
-
var
|
|
38
|
-
var
|
|
39
|
-
var path__namespace = /*#__PURE__*/_interopNamespace(path);
|
|
40
|
-
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
|
|
41
|
-
var SwaggerParser__default = /*#__PURE__*/_interopDefaultLegacy(SwaggerParser);
|
|
42
|
-
var ___default = /*#__PURE__*/_interopDefaultLegacy(_);
|
|
43
|
-
var https__namespace = /*#__PURE__*/_interopNamespace(https);
|
|
31
|
+
var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs);
|
|
32
|
+
var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path);
|
|
33
|
+
var https__namespace = /*#__PURE__*/_interopNamespaceDefault(https);
|
|
44
34
|
|
|
45
35
|
const SwaggersConfig = zod.z.array(zod.z.array(zod.z.string()));
|
|
46
36
|
class CliParser {
|
|
@@ -66,7 +56,7 @@ class CliParser {
|
|
|
66
56
|
const configPath = CliParser.getConfigPath();
|
|
67
57
|
if (!configPath)
|
|
68
58
|
throw new Error("Missing config file");
|
|
69
|
-
const config = JSON.parse(
|
|
59
|
+
const config = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
70
60
|
if (!SwaggersConfig.safeParse(config).success) {
|
|
71
61
|
throw new Error("Wrong config file format");
|
|
72
62
|
}
|
|
@@ -86,6 +76,86 @@ class CliParser {
|
|
|
86
76
|
};
|
|
87
77
|
}
|
|
88
78
|
|
|
79
|
+
const Schema = zod.z.object({
|
|
80
|
+
$ref: zod.z.string().nullish(),
|
|
81
|
+
type: zod.z.union([
|
|
82
|
+
zod.z.literal("array"),
|
|
83
|
+
zod.z.literal("object"),
|
|
84
|
+
zod.z.literal("file"),
|
|
85
|
+
zod.z.literal("string"),
|
|
86
|
+
zod.z.literal("boolean")
|
|
87
|
+
]).nullish(),
|
|
88
|
+
items: zod.z.object({
|
|
89
|
+
$ref: zod.z.string().nullish(),
|
|
90
|
+
type: zod.z.string().nullish()
|
|
91
|
+
}).nullish(),
|
|
92
|
+
properties: zod.z.array(zod.z.string()).nullish(),
|
|
93
|
+
description: zod.z.string().nullish(),
|
|
94
|
+
additionalProperties: zod.z.object({
|
|
95
|
+
type: zod.z.string().nullish()
|
|
96
|
+
}).nullish()
|
|
97
|
+
});
|
|
98
|
+
const Definition = zod.z.object({
|
|
99
|
+
required: zod.z.array(zod.z.string()).nullish(),
|
|
100
|
+
properties: zod.z.record(zod.z.object({
|
|
101
|
+
type: zod.z.string()
|
|
102
|
+
})).nullish()
|
|
103
|
+
});
|
|
104
|
+
const Definitions = zod.z.record(Definition);
|
|
105
|
+
const EndpointParametersType = zod.z.enum(["apiKey", "boolean", "int", "integer", "number", "string", "array", "file"]);
|
|
106
|
+
const EndpointParametersIn = zod.z.enum(["body", "formData", "header", "path", "query"]);
|
|
107
|
+
const EndpointParameters = zod.z.object({
|
|
108
|
+
type: EndpointParametersType.nullish(),
|
|
109
|
+
description: zod.z.string().nullish(),
|
|
110
|
+
name: zod.z.string(),
|
|
111
|
+
in: EndpointParametersIn,
|
|
112
|
+
required: zod.z.boolean().nullish(),
|
|
113
|
+
schema: Schema.nullish(),
|
|
114
|
+
default: zod.z.union([zod.z.boolean(), zod.z.string(), zod.z.number()]).nullish(),
|
|
115
|
+
enum: zod.z.array(zod.z.union([zod.z.boolean(), zod.z.string(), zod.z.number()])).nullish(),
|
|
116
|
+
items: zod.z.object({
|
|
117
|
+
type: zod.z.string()
|
|
118
|
+
}).nullish()
|
|
119
|
+
});
|
|
120
|
+
const Endpoint = zod.z.object({
|
|
121
|
+
description: zod.z.string().nullish(),
|
|
122
|
+
consumes: zod.z.array(zod.z.string()).nullish(),
|
|
123
|
+
produces: zod.z.array(zod.z.string()).nullish(),
|
|
124
|
+
tags: zod.z.array(zod.z.string()).nullish(),
|
|
125
|
+
summary: zod.z.string().nullish(),
|
|
126
|
+
operationId: zod.z.string(),
|
|
127
|
+
deprecated: zod.z.boolean().nullish(),
|
|
128
|
+
responses: zod.z.record(zod.z.object({
|
|
129
|
+
description: zod.z.string().nullish(),
|
|
130
|
+
schema: Schema.nullish()
|
|
131
|
+
})),
|
|
132
|
+
parameters: zod.z.array(EndpointParameters).nullish()
|
|
133
|
+
});
|
|
134
|
+
const Operation = zod.z.object({
|
|
135
|
+
get: Endpoint.nullish(),
|
|
136
|
+
post: Endpoint.nullish(),
|
|
137
|
+
patch: Endpoint.nullish(),
|
|
138
|
+
delete: Endpoint.nullish(),
|
|
139
|
+
put: Endpoint.nullish()
|
|
140
|
+
});
|
|
141
|
+
const Paths = zod.z.record(Operation);
|
|
142
|
+
zod.z.object({
|
|
143
|
+
paths: Paths,
|
|
144
|
+
definitions: Definitions,
|
|
145
|
+
basePath: zod.z.string(),
|
|
146
|
+
info: zod.z.object({
|
|
147
|
+
description: zod.z.string(),
|
|
148
|
+
title: zod.z.string(),
|
|
149
|
+
contact: zod.z.object({
|
|
150
|
+
name: zod.z.string(),
|
|
151
|
+
url: zod.z.string(),
|
|
152
|
+
email: zod.z.string()
|
|
153
|
+
}),
|
|
154
|
+
version: zod.z.string()
|
|
155
|
+
}),
|
|
156
|
+
schemes: zod.z.array(zod.z.string()).nullish()
|
|
157
|
+
});
|
|
158
|
+
|
|
89
159
|
const getImportableVarMap = () => ({
|
|
90
160
|
"@accelbyte/sdk": ["CodeGenUtil", "SdkCache", "IResponse", "IResponseWithSync", "Validate"],
|
|
91
161
|
axios: ["AxiosRequestConfig", "AxiosResponse"],
|
|
@@ -131,44 +201,30 @@ ${body}
|
|
|
131
201
|
`.replace(/, \)/g, ")").trim();
|
|
132
202
|
|
|
133
203
|
class ParserUtils {
|
|
134
|
-
static parseQueryParamAttributeDefault = (
|
|
135
|
-
const attrName = name.slice(name.lastIndexOf(".") + 1);
|
|
204
|
+
static parseQueryParamAttributeDefault = (definition) => {
|
|
205
|
+
const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
|
|
136
206
|
const defaultValue = definition.type === "string" ? `'${definition.default}'` : definition.default;
|
|
137
207
|
return `${attrName}: ${defaultValue}`;
|
|
138
208
|
};
|
|
139
|
-
static parseType = (
|
|
140
|
-
if (type === "integer")
|
|
209
|
+
static parseType = (pathParam) => {
|
|
210
|
+
if (pathParam.type === "int" || pathParam.type === "integer")
|
|
141
211
|
return "number";
|
|
142
|
-
if (type === "array")
|
|
143
|
-
return "any[]
|
|
144
|
-
return type;
|
|
212
|
+
if (pathParam.type === "array")
|
|
213
|
+
return `${pathParam.items.type ?? "any"}[]`;
|
|
214
|
+
return pathParam.type;
|
|
145
215
|
};
|
|
146
216
|
static parseQueryParamsType = (queryParams) => {
|
|
147
|
-
return queryParams.map((
|
|
217
|
+
return queryParams.map((queryParam) => ParserUtils.parseAttributeType(queryParam)).join(",");
|
|
148
218
|
};
|
|
149
219
|
static isAnyQueryParamRequired = (queryParams) => {
|
|
150
|
-
queryParams.
|
|
151
|
-
if (p.required) {
|
|
152
|
-
return true;
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
return false;
|
|
220
|
+
return queryParams.some((queryParam) => queryParam.required);
|
|
156
221
|
};
|
|
157
222
|
static parseQueryParamsDefault = (queryParams) => {
|
|
158
|
-
const result = queryParams.filter((
|
|
223
|
+
const result = queryParams.filter((queryParam) => !!queryParam.default && !queryParam.required).map(ParserUtils.parseQueryParamAttributeDefault).join(",");
|
|
159
224
|
return result ? `${result},` : "";
|
|
160
225
|
};
|
|
161
226
|
static parseBodyParamsImports = (bodyParams) => {
|
|
162
|
-
|
|
163
|
-
if (p?.schema?.$ref)
|
|
164
|
-
return ParserUtils.parseRefImport(p.schema.$ref, p);
|
|
165
|
-
if (p?.schema?.items?.$ref)
|
|
166
|
-
return ParserUtils.parseRefImport(p.schema.items.$ref, p);
|
|
167
|
-
if (p?.$ref)
|
|
168
|
-
return ParserUtils.parseRefImport(p.$ref, p);
|
|
169
|
-
return null;
|
|
170
|
-
}).filter((p) => !!p);
|
|
171
|
-
return ret;
|
|
227
|
+
return bodyParams.map(ParserUtils.parseRefImport).filter(Boolean);
|
|
172
228
|
};
|
|
173
229
|
static parseImportDir = ($ref) => {
|
|
174
230
|
let ref = $ref.replace(".", "/");
|
|
@@ -181,7 +237,11 @@ class ParserUtils {
|
|
|
181
237
|
return ref.slice(0, ref.lastIndexOf("/")).replace("#", ".");
|
|
182
238
|
}
|
|
183
239
|
};
|
|
184
|
-
static parseRefImport = (
|
|
240
|
+
static parseRefImport = (bodyParam) => {
|
|
241
|
+
const $ref = bodyParam?.schema?.$ref || bodyParam?.schema?.items?.$ref;
|
|
242
|
+
if (!$ref) {
|
|
243
|
+
return null;
|
|
244
|
+
}
|
|
185
245
|
const type = ParserUtils.parseRefType($ref);
|
|
186
246
|
return `import { ${type} } from './definitions/${type}'`;
|
|
187
247
|
};
|
|
@@ -191,16 +251,16 @@ class ParserUtils {
|
|
|
191
251
|
ref = ref.slice(0, -1);
|
|
192
252
|
}
|
|
193
253
|
const val = ref.slice(ref.lastIndexOf("/") + 1);
|
|
194
|
-
return
|
|
254
|
+
return _.upperFirst(_.camelCase(val)).replace(/( \w)/g, (group) => group.replace(" ", "").toUpperCase());
|
|
195
255
|
};
|
|
196
|
-
static parseAttributeType = (
|
|
256
|
+
static parseAttributeType = (definition) => {
|
|
197
257
|
const required = definition.required ? "" : "?";
|
|
198
|
-
const attrName = name.slice(name.lastIndexOf(".") + 1);
|
|
199
|
-
if (definition.
|
|
200
|
-
const enums = definition.
|
|
258
|
+
const attrName = definition.name.slice(definition.name.lastIndexOf(".") + 1);
|
|
259
|
+
if (definition.enum) {
|
|
260
|
+
const enums = definition.enum.map((enm) => definition.type === "string" ? `'${enm}'` : enm).join(" | ");
|
|
201
261
|
return `${attrName}${required}: ${enums}`;
|
|
202
262
|
}
|
|
203
|
-
if (definition.type && definition
|
|
263
|
+
if (definition.type && ParserUtils.parseType(definition) === "number") {
|
|
204
264
|
return `${attrName}${required}: number`;
|
|
205
265
|
}
|
|
206
266
|
if (definition.type && definition.type === "array") {
|
|
@@ -212,29 +272,29 @@ class ParserUtils {
|
|
|
212
272
|
return `${attrName}${required}: any`;
|
|
213
273
|
};
|
|
214
274
|
static parseBodyParamsType = (bodyParams) => {
|
|
215
|
-
const [
|
|
216
|
-
if (!
|
|
275
|
+
const [bodyParam] = bodyParams;
|
|
276
|
+
if (!bodyParam)
|
|
217
277
|
return null;
|
|
218
|
-
if (bodyParams.length > 0 &&
|
|
219
|
-
let retBodyParams = `{${bodyParams.map((
|
|
278
|
+
if (bodyParams.length > 0 && bodyParam?.name !== "body" && !bodyParam?.schema) {
|
|
279
|
+
let retBodyParams = `{${bodyParams.map((bodyParam2) => ParserUtils.parseAttributeType(bodyParam2)).join(",")}}`;
|
|
220
280
|
retBodyParams = retBodyParams.replace("file?: file", "file?: File");
|
|
221
281
|
return retBodyParams;
|
|
222
282
|
}
|
|
223
|
-
if (
|
|
224
|
-
return `${
|
|
283
|
+
if (bodyParam?.schema?.type === "array" && !bodyParam?.schema?.items?.$ref) {
|
|
284
|
+
return `${bodyParam.schema.items.type ?? "any"}[]`;
|
|
225
285
|
}
|
|
226
|
-
if (
|
|
227
|
-
return `${ParserUtils.parseRefType(
|
|
286
|
+
if (bodyParam?.schema?.type === "array" && bodyParam?.schema?.items?.$ref) {
|
|
287
|
+
return `${ParserUtils.parseRefType(bodyParam.schema.items.$ref)}[]`;
|
|
228
288
|
}
|
|
229
|
-
if (
|
|
230
|
-
return ParserUtils.parseRefType(
|
|
289
|
+
if (bodyParam?.schema.$ref) {
|
|
290
|
+
return ParserUtils.parseRefType(bodyParam.schema.$ref);
|
|
231
291
|
}
|
|
232
|
-
if (
|
|
292
|
+
if (bodyParam?.schema?.additionalProperties?.type === "object") {
|
|
233
293
|
return "any";
|
|
234
294
|
}
|
|
235
295
|
return null;
|
|
236
296
|
};
|
|
237
|
-
static get2xxResponse(methodEntity
|
|
297
|
+
static get2xxResponse(methodEntity) {
|
|
238
298
|
const keys = Object.keys(methodEntity);
|
|
239
299
|
let responseClass = null;
|
|
240
300
|
keys.forEach((key) => {
|
|
@@ -259,31 +319,30 @@ class ParserUtils {
|
|
|
259
319
|
}
|
|
260
320
|
return contentTypes.includes("application/x-www-form-urlencoded");
|
|
261
321
|
}
|
|
262
|
-
static
|
|
263
|
-
if (!
|
|
322
|
+
static filterPathParams(parameters) {
|
|
323
|
+
if (!parameters) {
|
|
264
324
|
return [];
|
|
265
325
|
}
|
|
266
|
-
|
|
267
|
-
for (const p of parametersArray) {
|
|
268
|
-
if (p.in === "path") {
|
|
269
|
-
res.push(p);
|
|
270
|
-
}
|
|
271
|
-
}
|
|
272
|
-
return res;
|
|
326
|
+
return parameters.filter((parameter) => parameter.in === "path");
|
|
273
327
|
}
|
|
274
|
-
static generateClassMethod(
|
|
328
|
+
static generateClassMethod({
|
|
329
|
+
path: path2,
|
|
330
|
+
endpoint,
|
|
331
|
+
httpMethod,
|
|
332
|
+
className
|
|
333
|
+
}) {
|
|
275
334
|
let replacedIdsPath = path2;
|
|
276
|
-
if (
|
|
277
|
-
for (const
|
|
278
|
-
if (
|
|
279
|
-
replacedIdsPath = replacedIdsPath.replace("{" +
|
|
335
|
+
if (endpoint.parameters) {
|
|
336
|
+
for (const parameter of endpoint.parameters) {
|
|
337
|
+
if (parameter.in === "path") {
|
|
338
|
+
replacedIdsPath = replacedIdsPath.replace("{" + parameter.name + "}", "By" + ParserUtils.toTitleCaseWord(parameter.name));
|
|
280
339
|
replacedIdsPath = replacedIdsPath.replace("/iam", "");
|
|
281
340
|
replacedIdsPath = replacedIdsPath.replace("/odin-config", "");
|
|
282
341
|
}
|
|
283
342
|
}
|
|
284
343
|
}
|
|
285
344
|
let classMethod = httpMethod + "/" + replacedIdsPath;
|
|
286
|
-
classMethod =
|
|
345
|
+
classMethod = _.camelCase(classMethod);
|
|
287
346
|
classMethod = classMethod.replace("PublicNamespacesByNamespace", "");
|
|
288
347
|
classMethod = classMethod.replace("AdminNamespacesByNamespace", "Admin");
|
|
289
348
|
const searchWord = "NamespacesByNamespace";
|
|
@@ -294,45 +353,38 @@ class ParserUtils {
|
|
|
294
353
|
}
|
|
295
354
|
return classMethod;
|
|
296
355
|
}
|
|
297
|
-
static
|
|
298
|
-
if (
|
|
299
|
-
return
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
return parametersArray.filter((p) => p.in === "body" || p.in === "formData");
|
|
356
|
+
static filterBodyParams(parameters) {
|
|
357
|
+
if (Array.isArray(parameters) && parameters.length > 0) {
|
|
358
|
+
return parameters.filter((parameter) => parameter.in === "body" || parameter.in === "formData");
|
|
359
|
+
}
|
|
360
|
+
return [];
|
|
303
361
|
}
|
|
304
|
-
static
|
|
305
|
-
if (!
|
|
362
|
+
static filterQueryParameters(parameters) {
|
|
363
|
+
if (!parameters) {
|
|
306
364
|
return [];
|
|
307
365
|
}
|
|
308
|
-
|
|
309
|
-
for (const p of parametersArray) {
|
|
310
|
-
if (p.in === "query") {
|
|
311
|
-
res.push(p);
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return res;
|
|
366
|
+
return parameters.filter((parameter) => parameter.in === "query");
|
|
315
367
|
}
|
|
316
368
|
static mkdirIfNotExist(dirToCreate) {
|
|
317
|
-
if (!
|
|
318
|
-
|
|
369
|
+
if (!fs.existsSync(dirToCreate)) {
|
|
370
|
+
fs.mkdirSync(dirToCreate, { recursive: true });
|
|
319
371
|
}
|
|
320
372
|
}
|
|
321
373
|
static writeClassFile(distDir, apiName, apiBuffer, imports) {
|
|
322
374
|
const fileContent = templateClass(apiName, apiBuffer, imports);
|
|
323
|
-
|
|
375
|
+
fs.writeFileSync(`${distDir}/${apiName}.ts`, ParserUtils.prependCopyrightHeader(fileContent));
|
|
324
376
|
}
|
|
325
377
|
static writeJsdocFile(distDir, nameArray, apiBuffer) {
|
|
326
378
|
const jsdocFile = templateJsdocFile(nameArray[0], apiBuffer);
|
|
327
|
-
|
|
379
|
+
fs.writeFileSync(`${distDir}/docs/${nameArray[0]}.md`, jsdocFile);
|
|
328
380
|
}
|
|
329
381
|
static writeDefinitionFile(distDir, name, buffer) {
|
|
330
382
|
ParserUtils.mkdirIfNotExist(distDir);
|
|
331
|
-
|
|
383
|
+
fs.writeFileSync(path.join(distDir, `${name}.ts`), ParserUtils.prependCopyrightHeader(buffer));
|
|
332
384
|
}
|
|
333
385
|
static writeAllImportsFile(distDir, buffer, isAdminWebSdk) {
|
|
334
386
|
ParserUtils.mkdirIfNotExist(distDir);
|
|
335
|
-
|
|
387
|
+
fs.writeFileSync(path.join(distDir, `all-${isAdminWebSdk ? "admin" : "public"}-imports.ts`), ParserUtils.prependCopyrightHeader(buffer));
|
|
336
388
|
}
|
|
337
389
|
static toCamelCase(str) {
|
|
338
390
|
return str.split("/").map(function(word, index) {
|
|
@@ -358,24 +410,17 @@ class ParserUtils {
|
|
|
358
410
|
});
|
|
359
411
|
}
|
|
360
412
|
static applyPatchIfExists(swaggerFilePath, possibleSwaggerPatchFilePath, swaggerPatchedFilePath, swaggerPatchedDir) {
|
|
361
|
-
if (!
|
|
362
|
-
|
|
413
|
+
if (!fs.existsSync(swaggerPatchedDir)) {
|
|
414
|
+
fs.mkdirSync(swaggerPatchedDir, { recursive: true });
|
|
363
415
|
}
|
|
364
|
-
if (!
|
|
365
|
-
|
|
416
|
+
if (!fs.existsSync(possibleSwaggerPatchFilePath)) {
|
|
417
|
+
fs.copyFileSync(swaggerFilePath, swaggerPatchedFilePath);
|
|
366
418
|
return;
|
|
367
419
|
}
|
|
368
|
-
const swaggerContent = JSON.parse(
|
|
369
|
-
const swaggerPatchFileContent = JSON.parse(
|
|
420
|
+
const swaggerContent = JSON.parse(fs.readFileSync(swaggerFilePath, "utf8"));
|
|
421
|
+
const swaggerPatchFileContent = JSON.parse(fs.readFileSync(possibleSwaggerPatchFilePath, "utf8"));
|
|
370
422
|
const { newDocument } = fastJsonPatch.applyPatch(swaggerContent, swaggerPatchFileContent);
|
|
371
|
-
|
|
372
|
-
}
|
|
373
|
-
static mapKeys(map_) {
|
|
374
|
-
const methods_ = [];
|
|
375
|
-
for (const m in map_) {
|
|
376
|
-
methods_.push(m);
|
|
377
|
-
}
|
|
378
|
-
return methods_;
|
|
423
|
+
fs.writeFileSync(swaggerPatchedFilePath, JSON.stringify(newDocument, null, 2));
|
|
379
424
|
}
|
|
380
425
|
static getRelativePathToWebSdkSrcFolder(srcFolder, targetSrcFolder) {
|
|
381
426
|
const replaced = srcFolder.replace(/\\/g, "/");
|
|
@@ -392,7 +437,7 @@ ${content}`;
|
|
|
392
437
|
};
|
|
393
438
|
}
|
|
394
439
|
|
|
395
|
-
const templateJsdocMethod = (classMethod, httpMethod, path, pathParams, bodyParams, queryParams) => {
|
|
440
|
+
const templateJsdocMethod = ({ classMethod, httpMethod, path, pathParams, bodyParams, queryParams }) => {
|
|
396
441
|
let jsdoc = "";
|
|
397
442
|
let methodSignature = "";
|
|
398
443
|
let newPath = path;
|
|
@@ -429,21 +474,31 @@ const templateJsdocMethod = (classMethod, httpMethod, path, pathParams, bodyPara
|
|
|
429
474
|
`;
|
|
430
475
|
};
|
|
431
476
|
|
|
432
|
-
const templateMethod = (
|
|
477
|
+
const templateMethod = ({
|
|
478
|
+
classMethod,
|
|
479
|
+
description,
|
|
480
|
+
httpMethod,
|
|
481
|
+
path,
|
|
482
|
+
pathParams,
|
|
483
|
+
bodyParams,
|
|
484
|
+
queryParams,
|
|
485
|
+
isFormUrlEncoded,
|
|
486
|
+
responseClass
|
|
487
|
+
}) => {
|
|
433
488
|
let methodSignature = "";
|
|
434
489
|
let newPath = `'${path}'`;
|
|
435
490
|
let dependencies = [];
|
|
436
|
-
for (const
|
|
437
|
-
const type = ParserUtils.parseType(
|
|
438
|
-
if (
|
|
439
|
-
methodSignature +=
|
|
491
|
+
for (const pathParam of pathParams) {
|
|
492
|
+
const type = ParserUtils.parseType(pathParam);
|
|
493
|
+
if (pathParam.name !== "namespace") {
|
|
494
|
+
methodSignature += pathParam.name + `:${type}, `;
|
|
440
495
|
}
|
|
441
|
-
const pName =
|
|
442
|
-
if (path.match(`{${
|
|
496
|
+
const pName = pathParam.name === "namespace" ? "this.namespace" : pathParam.name;
|
|
497
|
+
if (path.match(`{${pathParam.name}}`)) {
|
|
443
498
|
if (type === "string") {
|
|
444
|
-
newPath = `${newPath}.replace('{${
|
|
499
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', ${pName})`;
|
|
445
500
|
} else {
|
|
446
|
-
newPath = `${newPath}.replace('{${
|
|
501
|
+
newPath = `${newPath}.replace('{${pathParam.name}}', String(${pName}))`;
|
|
447
502
|
}
|
|
448
503
|
}
|
|
449
504
|
}
|
|
@@ -453,8 +508,8 @@ const templateMethod = (classMethod, description, httpMethod, path, pathParams,
|
|
|
453
508
|
dependencies = ParserUtils.parseBodyParamsImports(bodyParams);
|
|
454
509
|
methodSignature += dataType ? `data: ${dataType},` : "";
|
|
455
510
|
}
|
|
456
|
-
ParserUtils.isAnyQueryParamRequired(queryParams);
|
|
457
|
-
const queryParamsType = queryParams.length ? `queryParams${"?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
|
|
511
|
+
const isAnyRequired = ParserUtils.isAnyQueryParamRequired(queryParams);
|
|
512
|
+
const queryParamsType = queryParams.length ? `queryParams${isAnyRequired ? "" : "?"}: {${ParserUtils.parseQueryParamsType(queryParams)}}` : "";
|
|
458
513
|
const queryParamsDefault = queryParams.length ? `const params = {${ParserUtils.parseQueryParamsDefault(queryParams)} ...queryParams} as SDKRequestConfig` : "const params = {} as SDKRequestConfig";
|
|
459
514
|
const isPostPutPatch = ["post", "put", "patch"].includes(httpMethod);
|
|
460
515
|
const isDelete = ["delete"].includes(httpMethod);
|
|
@@ -479,74 +534,30 @@ const templateMethod = (classMethod, description, httpMethod, path, pathParams,
|
|
|
479
534
|
const parameters = (queryParamsType ? `${methodSignature} ${queryParamsType}` : methodSignature).replace(/,\s*$/, "");
|
|
480
535
|
let methodImpl = "";
|
|
481
536
|
const isCacheFetch = ["get"].includes(httpMethod) && resolvedResponseClass !== "unknown";
|
|
482
|
-
const isCacheFetchUnknown = ["get"].includes(httpMethod) && resolvedResponseClass === "unknown";
|
|
483
537
|
const cachedFetchMethod = classMethod.replace("get", "fetch");
|
|
484
538
|
const deprecateTag = isCacheFetch ? `/**
|
|
485
539
|
* @deprecated Use "${cachedFetchMethod}()" instead.
|
|
486
540
|
*/` : "";
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
541
|
+
const isGuardInvoked = ["get", "post", "put", "patch", "delete"].includes(httpMethod);
|
|
542
|
+
const methodName = httpMethod === "get" ? cachedFetchMethod : ["post", "put", "patch", "delete"].includes(httpMethod) ? classMethod : "";
|
|
543
|
+
const methodGenerics = resolvedResponseClass !== "unknown" ? `<T = ${resolvedResponseClass}>` : "";
|
|
544
|
+
const responseType = resolvedResponseClass !== "unknown" ? `T` : "unknown";
|
|
545
|
+
const responseSyncType = httpMethod === "get" ? "IResponseWithSync" : ["post", "put", "patch", "delete"].includes(httpMethod) ? "IResponse" : "";
|
|
546
|
+
methodImpl = `${descriptionText}
|
|
547
|
+
${methodName}${methodGenerics}(${parameters}): Promise<${responseSyncType}<${responseType}>> {
|
|
491
548
|
${queryParamsDefault}
|
|
492
549
|
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
493
550
|
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
494
|
-
|
|
495
|
-
const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
|
|
496
551
|
|
|
497
|
-
|
|
498
|
-
return SdkCache.withoutCache(res)
|
|
499
|
-
}
|
|
500
|
-
const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
|
|
501
|
-
return SdkCache.withCache(cacheKey, res)
|
|
502
|
-
}
|
|
503
|
-
`;
|
|
504
|
-
isGuardInvoked = true;
|
|
505
|
-
}
|
|
506
|
-
if (isCacheFetchUnknown) {
|
|
507
|
-
methodImpl = `${descriptionText}
|
|
508
|
-
${cachedFetchMethod}(${parameters}): Promise<IResponseWithSync<unknown>> {
|
|
509
|
-
${queryParamsDefault}
|
|
510
|
-
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
511
|
-
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
512
|
-
|
|
513
|
-
const res = () => Validate.responseType(() => resultPromise, z.unknown())
|
|
552
|
+
${httpMethod === "get" ? `const res = () => Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
|
|
514
553
|
|
|
515
554
|
if (!this.cache) {
|
|
516
555
|
return SdkCache.withoutCache(res)
|
|
517
556
|
}
|
|
518
557
|
const cacheKey = url + CodeGenUtil.hashCode(JSON.stringify({ params }))
|
|
519
|
-
return SdkCache.withCache(cacheKey, res)
|
|
520
|
-
}
|
|
521
|
-
`;
|
|
522
|
-
isGuardInvoked = true;
|
|
523
|
-
}
|
|
524
|
-
const withTypeGuard = ["post", "put", "patch", "delete"].includes(httpMethod) && resolvedResponseClass !== "unknown";
|
|
525
|
-
if (withTypeGuard) {
|
|
526
|
-
methodImpl = `${descriptionText}
|
|
527
|
-
${classMethod}<T = ${resolvedResponseClass}>(${parameters}): Promise<IResponse<T>> {
|
|
528
|
-
${queryParamsDefault}
|
|
529
|
-
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
530
|
-
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
531
|
-
|
|
532
|
-
return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})
|
|
558
|
+
return SdkCache.withCache(cacheKey, res)` : ""}${["post", "put", "patch", "delete"].includes(httpMethod) ? `return Validate.responseType(() => resultPromise, ${resolvedResponseClassValidated})` : ""}
|
|
533
559
|
}
|
|
534
560
|
`;
|
|
535
|
-
isGuardInvoked = true;
|
|
536
|
-
}
|
|
537
|
-
const withTypeGuardUnknown = ["post", "put", "patch", "delete"].includes(httpMethod) && resolvedResponseClass === "unknown";
|
|
538
|
-
if (withTypeGuardUnknown) {
|
|
539
|
-
methodImpl = `${descriptionText}
|
|
540
|
-
${classMethod}(${parameters}): Promise<IResponse<unknown>> {
|
|
541
|
-
${queryParamsDefault}
|
|
542
|
-
const url = ${newPath} ${formPayloadString} ${isFileUpload ? "\n// TODO file upload not implemented" : ""}
|
|
543
|
-
const resultPromise = this.axiosInstance.${httpMethod}(url, ${dataPayload})
|
|
544
|
-
|
|
545
|
-
return Validate.responseType(() => resultPromise, z.unknown())
|
|
546
|
-
}
|
|
547
|
-
`;
|
|
548
|
-
isGuardInvoked = true;
|
|
549
|
-
}
|
|
550
561
|
if (!isGuardInvoked) {
|
|
551
562
|
methodImpl = `${descriptionText}
|
|
552
563
|
${deprecateTag}
|
|
@@ -564,12 +575,12 @@ class TemplateZod {
|
|
|
564
575
|
duplicates;
|
|
565
576
|
duplicateFound = false;
|
|
566
577
|
importClasses = /* @__PURE__ */ new Set();
|
|
567
|
-
render = (
|
|
578
|
+
render = (fileName, definition, duplicates) => {
|
|
568
579
|
this.duplicates = duplicates;
|
|
569
580
|
const content = this.parseToZodSchema(definition, definition.required || []);
|
|
570
|
-
const containsRecursiveType = this.importClasses.has(
|
|
581
|
+
const containsRecursiveType = this.importClasses.has(fileName);
|
|
571
582
|
if (containsRecursiveType) {
|
|
572
|
-
this.importClasses.delete(
|
|
583
|
+
this.importClasses.delete(fileName);
|
|
573
584
|
}
|
|
574
585
|
let imports = "";
|
|
575
586
|
for (const cl of Array.from(this.importClasses).sort()) {
|
|
@@ -580,18 +591,18 @@ class TemplateZod {
|
|
|
580
591
|
let exportedTypeString;
|
|
581
592
|
if (containsRecursiveType) {
|
|
582
593
|
exportedVariableString = `
|
|
583
|
-
export const ${
|
|
594
|
+
export const ${fileName}: z.ZodType<${fileName}> = z.lazy(() =>
|
|
584
595
|
${content.schemaString}
|
|
585
596
|
)
|
|
586
597
|
`;
|
|
587
598
|
exportedTypeString = `
|
|
588
|
-
export type ${
|
|
599
|
+
export type ${fileName} = {
|
|
589
600
|
${content.typeString}
|
|
590
601
|
}
|
|
591
602
|
`;
|
|
592
603
|
} else {
|
|
593
|
-
exportedVariableString = `export const ${
|
|
594
|
-
exportedTypeString = `export type ${
|
|
604
|
+
exportedVariableString = `export const ${fileName} = ${content.schemaString}`;
|
|
605
|
+
exportedTypeString = `export type ${fileName} = z.TypeOf<typeof ${fileName}>`;
|
|
595
606
|
}
|
|
596
607
|
const template = `import { z } from 'zod'
|
|
597
608
|
${imports}
|
|
@@ -780,10 +791,10 @@ const extractEnumObject = (type, isRequired, enumArr) => {
|
|
|
780
791
|
};
|
|
781
792
|
|
|
782
793
|
class CodeGenerator {
|
|
783
|
-
static getPatchedDir = () =>
|
|
794
|
+
static getPatchedDir = () => path.join(CliParser.getSwaggersOutputPath(), "patched");
|
|
784
795
|
static getGeneratedPublicFolder = () => `${CliParser.getOutputPath()}/generated-public`;
|
|
785
796
|
static getGeneratedAdminFolder = () => `${CliParser.getOutputPath()}/generated-admin`;
|
|
786
|
-
static iterateApi = (api) => {
|
|
797
|
+
static iterateApi = async (api) => {
|
|
787
798
|
const apiBufferByTag = {};
|
|
788
799
|
const jsDocApiBufferByTag = {};
|
|
789
800
|
const dependenciesByTag = {};
|
|
@@ -796,15 +807,21 @@ class CodeGenerator {
|
|
|
796
807
|
} else if (!CliParser.isAdmin() && isAdminEndpoint) {
|
|
797
808
|
continue;
|
|
798
809
|
}
|
|
799
|
-
const
|
|
800
|
-
const
|
|
801
|
-
for (const httpMethod of
|
|
802
|
-
const
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
810
|
+
const operation = api.paths[path2];
|
|
811
|
+
const httpMethods = Object.keys(operation);
|
|
812
|
+
for (const httpMethod of httpMethods) {
|
|
813
|
+
const endpoint = await Endpoint.parseAsync(operation[httpMethod]).catch((error) => {
|
|
814
|
+
console.error(JSON.stringify({ path: path2, httpMethod }, null, 2));
|
|
815
|
+
throw error;
|
|
816
|
+
});
|
|
817
|
+
if (!endpoint.tags) {
|
|
818
|
+
continue;
|
|
819
|
+
}
|
|
820
|
+
const [tag] = endpoint.tags;
|
|
821
|
+
const description = endpoint.description;
|
|
822
|
+
const isDeprecated = endpoint.deprecated;
|
|
823
|
+
const responseClass = ParserUtils.get2xxResponse(endpoint.responses);
|
|
824
|
+
const className = _.upperFirst(_.camelCase(tag));
|
|
808
825
|
classImports[className] = classImports[className] ? classImports[className] : {};
|
|
809
826
|
if (!isDeprecated) {
|
|
810
827
|
if (responseClass) {
|
|
@@ -814,15 +831,30 @@ class CodeGenerator {
|
|
|
814
831
|
if (responseClass && responseClass.endsWith("Array")) {
|
|
815
832
|
arrayDefinitions.push(responseClass);
|
|
816
833
|
}
|
|
817
|
-
const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod,
|
|
818
|
-
const queryParams = ParserUtils.
|
|
819
|
-
const pathParams = ParserUtils.
|
|
820
|
-
const bodyParams = ParserUtils.
|
|
821
|
-
const classMethod = ParserUtils.generateClassMethod(
|
|
822
|
-
|
|
823
|
-
|
|
834
|
+
const isFormUrlEncoded = ParserUtils.isFormUrlEncoded(httpMethod, endpoint.consumes);
|
|
835
|
+
const queryParams = ParserUtils.filterQueryParameters(endpoint.parameters);
|
|
836
|
+
const pathParams = ParserUtils.filterPathParams(endpoint.parameters);
|
|
837
|
+
const bodyParams = ParserUtils.filterBodyParams(endpoint.parameters);
|
|
838
|
+
const classMethod = ParserUtils.generateClassMethod({
|
|
839
|
+
path: path2,
|
|
840
|
+
endpoint,
|
|
841
|
+
httpMethod,
|
|
842
|
+
className
|
|
843
|
+
});
|
|
844
|
+
const pathWithBase = `${api.basePath ?? ""}${path2}`;
|
|
845
|
+
const [generatedMethodString, importStatements] = templateMethod({
|
|
846
|
+
classMethod,
|
|
847
|
+
description,
|
|
848
|
+
httpMethod,
|
|
849
|
+
path: pathWithBase,
|
|
850
|
+
pathParams,
|
|
851
|
+
bodyParams,
|
|
852
|
+
queryParams,
|
|
853
|
+
isFormUrlEncoded,
|
|
854
|
+
responseClass
|
|
855
|
+
});
|
|
824
856
|
apiBufferByTag[tag] = (apiBufferByTag[tag] || "") + generatedMethodString;
|
|
825
|
-
jsDocApiBufferByTag[tag] = (jsDocApiBufferByTag[tag] || "") + templateJsdocMethod(classMethod, httpMethod, path2, pathParams, bodyParams, queryParams);
|
|
857
|
+
jsDocApiBufferByTag[tag] = (jsDocApiBufferByTag[tag] || "") + templateJsdocMethod({ classMethod, httpMethod, path: path2, pathParams, bodyParams, queryParams });
|
|
826
858
|
dependenciesByTag[tag] = dependenciesByTag[tag] ? [.../* @__PURE__ */ new Set([...importStatements, ...dependenciesByTag[tag]])] : [...new Set(importStatements)];
|
|
827
859
|
}
|
|
828
860
|
}
|
|
@@ -833,11 +865,11 @@ class CodeGenerator {
|
|
|
833
865
|
static main = async (nameArray) => {
|
|
834
866
|
const serviceName = nameArray[0];
|
|
835
867
|
const swaggerFile = nameArray[2];
|
|
836
|
-
const parser = new
|
|
868
|
+
const parser = new SwaggerParser();
|
|
837
869
|
const generatedFolder = CliParser.isAdmin() ? CodeGenerator.getGeneratedAdminFolder() : CodeGenerator.getGeneratedPublicFolder();
|
|
838
870
|
const DIST_DIR = `${generatedFolder}/${serviceName}`;
|
|
839
|
-
const DIST_DOCS_DIR =
|
|
840
|
-
const DIST_DEFINITION_DIR =
|
|
871
|
+
const DIST_DOCS_DIR = path.join(DIST_DIR, "docs");
|
|
872
|
+
const DIST_DEFINITION_DIR = path.join(DIST_DIR, "definitions");
|
|
841
873
|
const swaggerFilePath = `${CliParser.getSwaggersOutputPath()}/${swaggerFile}`;
|
|
842
874
|
const swaggerPatchedFilePath = `${CodeGenerator.getPatchedDir()}/${swaggerFile}`;
|
|
843
875
|
const swaggerPatchFilePath = `${swaggerFilePath}patch`;
|
|
@@ -848,28 +880,28 @@ class CodeGenerator {
|
|
|
848
880
|
ParserUtils.mkdirIfNotExist(DIST_DIR);
|
|
849
881
|
ParserUtils.mkdirIfNotExist(DIST_DOCS_DIR);
|
|
850
882
|
ParserUtils.mkdirIfNotExist(DIST_DEFINITION_DIR);
|
|
851
|
-
const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions } = CodeGenerator.iterateApi(api);
|
|
883
|
+
const { apiBufferByTag, dependenciesByTag, classImports, arrayDefinitions } = await CodeGenerator.iterateApi(api);
|
|
852
884
|
const targetSrcFolder = `${CliParser.getOutputPath()}/`;
|
|
853
885
|
for (const tag in apiBufferByTag) {
|
|
854
|
-
const className =
|
|
886
|
+
const className = _.upperFirst(_.camelCase(tag));
|
|
855
887
|
const apiBuffer = apiBufferByTag[tag];
|
|
856
888
|
const imports = [.../* @__PURE__ */ new Set([...dependenciesByTag[tag], ...Object.values(classImports[className])])];
|
|
857
889
|
const classGenName = CliParser.isAdmin() ? className + "Admin$" : className + "$";
|
|
858
890
|
ParserUtils.writeClassFile(DIST_DIR, classGenName, apiBuffer, imports);
|
|
859
|
-
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(
|
|
891
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DIR, `${classGenName}`), targetSrcFolder));
|
|
860
892
|
}
|
|
861
893
|
const duplicates = /* @__PURE__ */ new Map();
|
|
862
894
|
for (const ref in api.definitions) {
|
|
863
895
|
const definition = api.definitions[ref];
|
|
864
896
|
let fileName = ParserUtils.parseRefType(ref);
|
|
865
|
-
const fileExist =
|
|
897
|
+
const fileExist = fs.existsSync(path.join(DIST_DEFINITION_DIR, `${fileName}.ts`));
|
|
866
898
|
if (fileExist) {
|
|
867
899
|
fileName = ParserUtils.toCamelCaseWord(ref).replace(".", "").replace(".", "");
|
|
868
900
|
duplicates.set(ref, fileName);
|
|
869
901
|
}
|
|
870
902
|
const { buffer } = new TemplateZod().render(fileName, definition, /* @__PURE__ */ new Map());
|
|
871
903
|
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, fileName, buffer);
|
|
872
|
-
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(
|
|
904
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DEFINITION_DIR, fileName), targetSrcFolder));
|
|
873
905
|
}
|
|
874
906
|
for (const ref in api.definitions) {
|
|
875
907
|
const definition = api.definitions[ref];
|
|
@@ -877,13 +909,13 @@ class CodeGenerator {
|
|
|
877
909
|
const { buffer, duplicateFound } = new TemplateZod().render(fileName, definition, duplicates);
|
|
878
910
|
if (duplicateFound) {
|
|
879
911
|
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, fileName, buffer);
|
|
880
|
-
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(
|
|
912
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DEFINITION_DIR, fileName), targetSrcFolder));
|
|
881
913
|
}
|
|
882
914
|
}
|
|
883
915
|
for (const arrayClass of arrayDefinitions) {
|
|
884
916
|
const buffer = new TemplateZodArray().render(arrayClass);
|
|
885
917
|
ParserUtils.writeDefinitionFile(DIST_DEFINITION_DIR, arrayClass, buffer);
|
|
886
|
-
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(
|
|
918
|
+
indexImportsSet.add(ParserUtils.getRelativePathToWebSdkSrcFolder(path.join(DIST_DEFINITION_DIR, arrayClass), targetSrcFolder));
|
|
887
919
|
}
|
|
888
920
|
console.log("\n----------\nCOMPLETED.\n----------\n\n");
|
|
889
921
|
return indexImportsSet;
|
|
@@ -926,7 +958,7 @@ class SwaggerDownloader {
|
|
|
926
958
|
};
|
|
927
959
|
}
|
|
928
960
|
|
|
929
|
-
|
|
961
|
+
yargs.command("download-swaggers", "Download swaggers JSON files", (yargs2) => {
|
|
930
962
|
CliParser.createInstance(yargs2);
|
|
931
963
|
SwaggerDownloader.main();
|
|
932
964
|
}).command("generate-code", "Generate code based on downloaded swagger files", async (yargs2) => {
|
|
@@ -942,7 +974,7 @@ yargs__default['default'].command("download-swaggers", "Download swaggers JSON f
|
|
|
942
974
|
const filenamesSet = /* @__PURE__ */ new Set();
|
|
943
975
|
for (const set of arrayOfSets) {
|
|
944
976
|
set.forEach((value) => {
|
|
945
|
-
const fileName =
|
|
977
|
+
const fileName = path.basename(value);
|
|
946
978
|
if (!filenamesSet.has(fileName)) {
|
|
947
979
|
indexImportsSet.add(value);
|
|
948
980
|
filenamesSet.add(fileName);
|