@bagelink/sdk 0.0.1129 → 0.0.1133
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/dist/index.cjs +53 -74
- package/dist/index.mjs +53 -74
- package/package.json +1 -1
- package/src/openAPITools/functionGenerator.ts +11 -4
- package/src/openAPITools/typeGenerator.ts +34 -13
package/dist/index.cjs
CHANGED
|
@@ -18,24 +18,20 @@ function formatType(typeName) {
|
|
|
18
18
|
}
|
|
19
19
|
function resolveReference(ref) {
|
|
20
20
|
const t = ref.split("/").pop();
|
|
21
|
-
if (!t)
|
|
22
|
-
return "any";
|
|
21
|
+
if (!t) return "any";
|
|
23
22
|
return formatType(t);
|
|
24
23
|
}
|
|
25
24
|
function schemaToType(schema) {
|
|
26
|
-
if (!schema)
|
|
27
|
-
return "any";
|
|
25
|
+
if (!schema) return "any";
|
|
28
26
|
if (schema.anyOf) {
|
|
29
27
|
let _t = schema.anyOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" | ");
|
|
30
|
-
if (_t === "" || _t === "null")
|
|
31
|
-
_t = "any";
|
|
28
|
+
if (_t === "" || _t === "null") _t = "any";
|
|
32
29
|
return _t;
|
|
33
30
|
}
|
|
34
31
|
if (schema.allOf) {
|
|
35
32
|
return schema.allOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" & ");
|
|
36
33
|
}
|
|
37
|
-
if (schema.$ref)
|
|
38
|
-
return resolveReference(schema.$ref);
|
|
34
|
+
if (schema.$ref) return resolveReference(schema.$ref);
|
|
39
35
|
switch (schema.type) {
|
|
40
36
|
case "object":
|
|
41
37
|
return "{ [key: string]: any }";
|
|
@@ -53,7 +49,7 @@ function schemaToType(schema) {
|
|
|
53
49
|
return "undefined";
|
|
54
50
|
case "null":
|
|
55
51
|
return "null";
|
|
56
|
-
case
|
|
52
|
+
case undefined:
|
|
57
53
|
return "any";
|
|
58
54
|
default:
|
|
59
55
|
console.log("Unknown type", schema.type);
|
|
@@ -65,7 +61,7 @@ function isOptional(schema) {
|
|
|
65
61
|
const splitType = type.split(/\s+\|\s+/);
|
|
66
62
|
const includesNull = splitType.includes("null");
|
|
67
63
|
const includesUndefined = splitType.includes("undefined");
|
|
68
|
-
return includesNull || includesUndefined || schema.default !==
|
|
64
|
+
return includesNull || includesUndefined || schema.default !== undefined;
|
|
69
65
|
}
|
|
70
66
|
function cleanOptionals(str) {
|
|
71
67
|
return str.split(" | ").filter((t) => t !== "null" && t !== "undefined").join(" | ");
|
|
@@ -87,8 +83,7 @@ function formatVarType({
|
|
|
87
83
|
}
|
|
88
84
|
}
|
|
89
85
|
let optionalStr = !required && isOptional(schema) ? "?" : "";
|
|
90
|
-
if (defaultStr)
|
|
91
|
-
optionalStr = "";
|
|
86
|
+
if (defaultStr) optionalStr = "";
|
|
92
87
|
return `${varName}${optionalStr}: ${type}${defaultStr}`;
|
|
93
88
|
}
|
|
94
89
|
function cleanPath(path) {
|
|
@@ -117,22 +112,22 @@ function collectTypeForImportStatement(typeName) {
|
|
|
117
112
|
}
|
|
118
113
|
const isPrimitive = primitiveTypes.includes(typeName);
|
|
119
114
|
typeName = formatType(typeName);
|
|
120
|
-
if (!typeName || isPrimitive)
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
if (!typeName || isPrimitive) return;
|
|
116
|
+
if (!allTypes.includes(typeName)) allTypes.push(typeName);
|
|
117
|
+
}
|
|
118
|
+
function schemaToTypeWithCollection(schema) {
|
|
119
|
+
const type = schemaToType(schema);
|
|
120
|
+
collectTypeForImportStatement(type);
|
|
121
|
+
return type;
|
|
124
122
|
}
|
|
125
123
|
function getResponseType(response) {
|
|
126
124
|
const mediaTypeObject = response.content?.["application/json"];
|
|
127
|
-
if (!mediaTypeObject || !mediaTypeObject.schema)
|
|
128
|
-
|
|
129
|
-
const responseType = schemaToType(mediaTypeObject.schema);
|
|
130
|
-
collectTypeForImportStatement(responseType);
|
|
125
|
+
if (!mediaTypeObject || !mediaTypeObject.schema) return;
|
|
126
|
+
const responseType = schemaToTypeWithCollection(mediaTypeObject.schema);
|
|
131
127
|
return responseType;
|
|
132
128
|
}
|
|
133
129
|
function generateResponseType(responses) {
|
|
134
|
-
if (!responses)
|
|
135
|
-
return "";
|
|
130
|
+
if (!responses) return "";
|
|
136
131
|
const types = [];
|
|
137
132
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
138
133
|
if (statusCode.startsWith("2")) {
|
|
@@ -145,8 +140,7 @@ function generateResponseType(responses) {
|
|
|
145
140
|
return types.join(" | ");
|
|
146
141
|
}
|
|
147
142
|
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
148
|
-
if (allParams === "undefined")
|
|
149
|
-
allParams = "";
|
|
143
|
+
if (allParams === "undefined") allParams = "";
|
|
150
144
|
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
151
145
|
if (requestBodyPayload === "formData") {
|
|
152
146
|
const paramStr = parameters?.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
@@ -206,14 +200,12 @@ function combineAllParams(parameters, requestBodyParam) {
|
|
|
206
200
|
let allParamsArray = [];
|
|
207
201
|
if (parameters && parameters.params)
|
|
208
202
|
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
209
|
-
if (requestBodyParam)
|
|
210
|
-
allParamsArray.push(requestBodyParam.trim());
|
|
203
|
+
if (requestBodyParam) allParamsArray.push(requestBodyParam.trim());
|
|
211
204
|
allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
|
|
212
205
|
return allParamsArray.join(", ");
|
|
213
206
|
}
|
|
214
207
|
function generateFunctionParameters(params, isFileUpload = false) {
|
|
215
|
-
if (!params?.length)
|
|
216
|
-
return {};
|
|
208
|
+
if (!params?.length) return {};
|
|
217
209
|
if (isFileUpload) {
|
|
218
210
|
return {
|
|
219
211
|
config: {
|
|
@@ -252,8 +244,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
252
244
|
};
|
|
253
245
|
}
|
|
254
246
|
function generateFunctionForOperation(method, path, operation) {
|
|
255
|
-
if (!operation)
|
|
256
|
-
return "";
|
|
247
|
+
if (!operation) return "";
|
|
257
248
|
const isFileUpload = operation.requestBody?.content["multipart/form-data"]?.schema?.$ref?.includes("Body_upload_files");
|
|
258
249
|
const parameters = generateFunctionParameters(
|
|
259
250
|
operation.parameters,
|
|
@@ -275,6 +266,7 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
275
266
|
);
|
|
276
267
|
}
|
|
277
268
|
const generateRandomString = () => Math.random().toString(36).slice(7);
|
|
269
|
+
const DOUBLE_QUOTE_REGEX = /"([^"]+)":/g;
|
|
278
270
|
function fileTemplate(tsString, typeForImport, baseURL) {
|
|
279
271
|
const templateCode = `import ax from 'axios';
|
|
280
272
|
import type { AxiosResponse } from 'axios';
|
|
@@ -288,8 +280,7 @@ function fileTemplate(tsString, typeForImport, baseURL) {
|
|
|
288
280
|
|
|
289
281
|
export const axios = ax.create({baseURL:${baseURL}});
|
|
290
282
|
${tsString}`;
|
|
291
|
-
|
|
292
|
-
return templateCode.replace(doubleQuoteRegex, "$1:");
|
|
283
|
+
return templateCode.replace(DOUBLE_QUOTE_REGEX, "$1:");
|
|
293
284
|
}
|
|
294
285
|
const functionsInventory = {};
|
|
295
286
|
const pathOperations = [];
|
|
@@ -335,8 +326,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
335
326
|
const splitPath = path.split("/").filter((p) => p && !/\{|\}/.test(p));
|
|
336
327
|
splitPath.reduce((acc, key, index, array) => {
|
|
337
328
|
const objFuncKey = toCamelCase(key);
|
|
338
|
-
if (!objFuncKey)
|
|
339
|
-
return acc;
|
|
329
|
+
if (!objFuncKey) return acc;
|
|
340
330
|
const methods = Object.keys(operation);
|
|
341
331
|
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
|
|
342
332
|
const method = methods[0];
|
|
@@ -351,7 +341,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
351
341
|
}, body);
|
|
352
342
|
}
|
|
353
343
|
for (const [parent, object] of Object.entries(body)) {
|
|
354
|
-
tsString += `export const ${parent} = ${JSON.stringify(object,
|
|
344
|
+
tsString += `export const ${parent} = ${JSON.stringify(object, undefined, 2)};
|
|
355
345
|
`;
|
|
356
346
|
}
|
|
357
347
|
Object.entries(functionsInventory).forEach(([key, value]) => {
|
|
@@ -368,8 +358,13 @@ function generateTypes(schemas) {
|
|
|
368
358
|
return `export type ${typeName} = ${schema.enum.map((item) => `'${item}'`).join(" | ")};
|
|
369
359
|
`;
|
|
370
360
|
}
|
|
371
|
-
if (
|
|
361
|
+
if (schema.type === "array" && schema.items) {
|
|
362
|
+
return `export type ${typeName} = ${schemaToType(schema.items)}[];
|
|
363
|
+
`;
|
|
364
|
+
}
|
|
365
|
+
if (!schema.properties) {
|
|
372
366
|
return "";
|
|
367
|
+
}
|
|
373
368
|
const properties = Object.entries(schema.properties).map(([key, value]) => {
|
|
374
369
|
const varType = formatVarType({ varName: key, schema: value });
|
|
375
370
|
return ` ${varType}`;
|
|
@@ -386,12 +381,10 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
386
381
|
try {
|
|
387
382
|
const { data: openApi } = await axios__default.get(openApiUrl, { headers: basicAuthHeader });
|
|
388
383
|
const schemas = openApi.components?.schemas;
|
|
389
|
-
if (!schemas)
|
|
390
|
-
throw new Error("No schemas found in OpenAPI document");
|
|
384
|
+
if (!schemas) throw new Error("No schemas found in OpenAPI document");
|
|
391
385
|
const types = generateTypes(schemas);
|
|
392
386
|
const { paths } = openApi;
|
|
393
|
-
if (!paths)
|
|
394
|
-
throw new Error("No paths found in OpenAPI document");
|
|
387
|
+
if (!paths) throw new Error("No paths found in OpenAPI document");
|
|
395
388
|
const code = generateFunctions(paths, baseUrl);
|
|
396
389
|
return { types, code };
|
|
397
390
|
} catch (error) {
|
|
@@ -399,28 +392,21 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
399
392
|
}
|
|
400
393
|
};
|
|
401
394
|
|
|
402
|
-
var __defProp = Object.defineProperty;
|
|
403
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
404
|
-
var __publicField = (obj, key, value) => {
|
|
405
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
406
|
-
return value;
|
|
407
|
-
};
|
|
408
395
|
const axios = axios__default.create({
|
|
409
396
|
withCredentials: true
|
|
410
397
|
});
|
|
411
398
|
class DataRequest {
|
|
399
|
+
data_table;
|
|
400
|
+
bagel;
|
|
401
|
+
itemID;
|
|
402
|
+
_filter = {};
|
|
412
403
|
constructor(table, bagel) {
|
|
413
|
-
__publicField(this, "data_table");
|
|
414
|
-
__publicField(this, "bagel");
|
|
415
|
-
__publicField(this, "itemID");
|
|
416
|
-
__publicField(this, "_filter", {});
|
|
417
404
|
this.data_table = table;
|
|
418
405
|
this.bagel = bagel;
|
|
419
406
|
this.itemID = "";
|
|
420
407
|
}
|
|
421
408
|
async post(item) {
|
|
422
|
-
if (!this.data_table)
|
|
423
|
-
throw new Error("Data table not set");
|
|
409
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
424
410
|
const { data } = await axios.post(`/data/${this.data_table}`, item);
|
|
425
411
|
return data;
|
|
426
412
|
}
|
|
@@ -429,8 +415,7 @@ class DataRequest {
|
|
|
429
415
|
return this;
|
|
430
416
|
}
|
|
431
417
|
async get() {
|
|
432
|
-
if (!this.data_table)
|
|
433
|
-
throw new Error("Data table not set");
|
|
418
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
434
419
|
const filterStr = Object.keys(this._filter).length > 0 ? `?filter={${Object.entries(this._filter).map(([k, v]) => `${k}:${v}`).join(",")}}` : "";
|
|
435
420
|
const url = `/data/${this.data_table}${this.itemID ? `/${this.itemID}` : ""}${filterStr}`;
|
|
436
421
|
try {
|
|
@@ -439,7 +424,7 @@ class DataRequest {
|
|
|
439
424
|
} catch (err) {
|
|
440
425
|
console.log(err);
|
|
441
426
|
this.bagel.onError?.(err);
|
|
442
|
-
return
|
|
427
|
+
return undefined;
|
|
443
428
|
}
|
|
444
429
|
}
|
|
445
430
|
item(id) {
|
|
@@ -447,8 +432,7 @@ class DataRequest {
|
|
|
447
432
|
return this;
|
|
448
433
|
}
|
|
449
434
|
async delete() {
|
|
450
|
-
if (!this.data_table)
|
|
451
|
-
throw new Error("Data table not set");
|
|
435
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
452
436
|
const { data } = await axios.delete(
|
|
453
437
|
`/data/${this.data_table}/${this.itemID}`
|
|
454
438
|
);
|
|
@@ -456,10 +440,8 @@ class DataRequest {
|
|
|
456
440
|
}
|
|
457
441
|
async put(updatedItem) {
|
|
458
442
|
const { data_table, itemID } = this;
|
|
459
|
-
if (!data_table)
|
|
460
|
-
|
|
461
|
-
if (!itemID)
|
|
462
|
-
throw new Error("Item ID not set");
|
|
443
|
+
if (!data_table) throw new Error("Data table not set");
|
|
444
|
+
if (!itemID) throw new Error("Item ID not set");
|
|
463
445
|
const { data } = await axios.put(
|
|
464
446
|
`/data/${data_table}/${itemID}`,
|
|
465
447
|
updatedItem
|
|
@@ -477,9 +459,9 @@ function responses(key) {
|
|
|
477
459
|
class BagelAuth {
|
|
478
460
|
constructor(bagel) {
|
|
479
461
|
this.bagel = bagel;
|
|
480
|
-
__publicField(this, "user");
|
|
481
462
|
this.bagel = bagel;
|
|
482
463
|
}
|
|
464
|
+
user = undefined;
|
|
483
465
|
async validateUser() {
|
|
484
466
|
try {
|
|
485
467
|
const { data: usr } = await axios.get("/users/me", {
|
|
@@ -527,7 +509,7 @@ class BagelAuth {
|
|
|
527
509
|
this.bagel.onError?.(err);
|
|
528
510
|
console.log(err);
|
|
529
511
|
}
|
|
530
|
-
this.user =
|
|
512
|
+
this.user = undefined;
|
|
531
513
|
}
|
|
532
514
|
async acceptInvite(token, user) {
|
|
533
515
|
await axios.post(`/auth/accept-invite/${token}`, user);
|
|
@@ -545,12 +527,10 @@ class BagelAuth {
|
|
|
545
527
|
}
|
|
546
528
|
}
|
|
547
529
|
class Bagel {
|
|
530
|
+
host;
|
|
531
|
+
fileBaseUrl;
|
|
532
|
+
onError;
|
|
548
533
|
constructor({ host, fileBaseUrl, onError }) {
|
|
549
|
-
__publicField(this, "host");
|
|
550
|
-
__publicField(this, "fileBaseUrl");
|
|
551
|
-
__publicField(this, "onError");
|
|
552
|
-
__publicField(this, "read_table");
|
|
553
|
-
__publicField(this, "auth", new BagelAuth(this));
|
|
554
534
|
this.host = host?.replace(/\/$/, "");
|
|
555
535
|
this.fileBaseUrl = fileBaseUrl?.replace(/\/$/, "");
|
|
556
536
|
if (!this.host) {
|
|
@@ -559,9 +539,11 @@ class Bagel {
|
|
|
559
539
|
axios.defaults.baseURL = this.host;
|
|
560
540
|
this.onError = onError;
|
|
561
541
|
}
|
|
542
|
+
read_table = undefined;
|
|
562
543
|
data(table) {
|
|
563
544
|
return new DataRequest(table, this);
|
|
564
545
|
}
|
|
546
|
+
auth = new BagelAuth(this);
|
|
565
547
|
_endpointCleaner(endpoint) {
|
|
566
548
|
const url = `${endpoint.replace(/^\//, "").replaceAll(/\/$/g, "")}`;
|
|
567
549
|
return url;
|
|
@@ -576,12 +558,10 @@ class Bagel {
|
|
|
576
558
|
async get(endpoint, query) {
|
|
577
559
|
this._setAuthorization();
|
|
578
560
|
endpoint = this._endpointCleaner(endpoint);
|
|
579
|
-
if (/undefined|null/.test(endpoint))
|
|
580
|
-
throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
561
|
+
if (/undefined|null/.test(endpoint)) throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
581
562
|
if (query) {
|
|
582
563
|
const queryParams = Object.entries(query).filter(([_, value]) => !!value).map(([key, value]) => `${key}=${value}`).join("&");
|
|
583
|
-
if (queryParams)
|
|
584
|
-
endpoint = `${endpoint}?${queryParams}`;
|
|
564
|
+
if (queryParams) endpoint = `${endpoint}?${queryParams}`;
|
|
585
565
|
}
|
|
586
566
|
const url = `/${endpoint}`;
|
|
587
567
|
return axios.get(url).then(({ data }) => data).catch((err) => {
|
|
@@ -631,8 +611,7 @@ class Bagel {
|
|
|
631
611
|
const formData = new FormData();
|
|
632
612
|
formData.append("file", file);
|
|
633
613
|
let url = "/static_files/upload";
|
|
634
|
-
if (options?.topic)
|
|
635
|
-
url = `/static_files/upload?topic=${options.topic}`;
|
|
614
|
+
if (options?.topic) url = `/static_files/upload?topic=${options.topic}`;
|
|
636
615
|
const { data } = await axios.post(url, formData, {
|
|
637
616
|
headers: {
|
|
638
617
|
"Content-Type": "multipart/form-data"
|
package/dist/index.mjs
CHANGED
|
@@ -12,24 +12,20 @@ function formatType(typeName) {
|
|
|
12
12
|
}
|
|
13
13
|
function resolveReference(ref) {
|
|
14
14
|
const t = ref.split("/").pop();
|
|
15
|
-
if (!t)
|
|
16
|
-
return "any";
|
|
15
|
+
if (!t) return "any";
|
|
17
16
|
return formatType(t);
|
|
18
17
|
}
|
|
19
18
|
function schemaToType(schema) {
|
|
20
|
-
if (!schema)
|
|
21
|
-
return "any";
|
|
19
|
+
if (!schema) return "any";
|
|
22
20
|
if (schema.anyOf) {
|
|
23
21
|
let _t = schema.anyOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" | ");
|
|
24
|
-
if (_t === "" || _t === "null")
|
|
25
|
-
_t = "any";
|
|
22
|
+
if (_t === "" || _t === "null") _t = "any";
|
|
26
23
|
return _t;
|
|
27
24
|
}
|
|
28
25
|
if (schema.allOf) {
|
|
29
26
|
return schema.allOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" & ");
|
|
30
27
|
}
|
|
31
|
-
if (schema.$ref)
|
|
32
|
-
return resolveReference(schema.$ref);
|
|
28
|
+
if (schema.$ref) return resolveReference(schema.$ref);
|
|
33
29
|
switch (schema.type) {
|
|
34
30
|
case "object":
|
|
35
31
|
return "{ [key: string]: any }";
|
|
@@ -47,7 +43,7 @@ function schemaToType(schema) {
|
|
|
47
43
|
return "undefined";
|
|
48
44
|
case "null":
|
|
49
45
|
return "null";
|
|
50
|
-
case
|
|
46
|
+
case undefined:
|
|
51
47
|
return "any";
|
|
52
48
|
default:
|
|
53
49
|
console.log("Unknown type", schema.type);
|
|
@@ -59,7 +55,7 @@ function isOptional(schema) {
|
|
|
59
55
|
const splitType = type.split(/\s+\|\s+/);
|
|
60
56
|
const includesNull = splitType.includes("null");
|
|
61
57
|
const includesUndefined = splitType.includes("undefined");
|
|
62
|
-
return includesNull || includesUndefined || schema.default !==
|
|
58
|
+
return includesNull || includesUndefined || schema.default !== undefined;
|
|
63
59
|
}
|
|
64
60
|
function cleanOptionals(str) {
|
|
65
61
|
return str.split(" | ").filter((t) => t !== "null" && t !== "undefined").join(" | ");
|
|
@@ -81,8 +77,7 @@ function formatVarType({
|
|
|
81
77
|
}
|
|
82
78
|
}
|
|
83
79
|
let optionalStr = !required && isOptional(schema) ? "?" : "";
|
|
84
|
-
if (defaultStr)
|
|
85
|
-
optionalStr = "";
|
|
80
|
+
if (defaultStr) optionalStr = "";
|
|
86
81
|
return `${varName}${optionalStr}: ${type}${defaultStr}`;
|
|
87
82
|
}
|
|
88
83
|
function cleanPath(path) {
|
|
@@ -111,22 +106,22 @@ function collectTypeForImportStatement(typeName) {
|
|
|
111
106
|
}
|
|
112
107
|
const isPrimitive = primitiveTypes.includes(typeName);
|
|
113
108
|
typeName = formatType(typeName);
|
|
114
|
-
if (!typeName || isPrimitive)
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
109
|
+
if (!typeName || isPrimitive) return;
|
|
110
|
+
if (!allTypes.includes(typeName)) allTypes.push(typeName);
|
|
111
|
+
}
|
|
112
|
+
function schemaToTypeWithCollection(schema) {
|
|
113
|
+
const type = schemaToType(schema);
|
|
114
|
+
collectTypeForImportStatement(type);
|
|
115
|
+
return type;
|
|
118
116
|
}
|
|
119
117
|
function getResponseType(response) {
|
|
120
118
|
const mediaTypeObject = response.content?.["application/json"];
|
|
121
|
-
if (!mediaTypeObject || !mediaTypeObject.schema)
|
|
122
|
-
|
|
123
|
-
const responseType = schemaToType(mediaTypeObject.schema);
|
|
124
|
-
collectTypeForImportStatement(responseType);
|
|
119
|
+
if (!mediaTypeObject || !mediaTypeObject.schema) return;
|
|
120
|
+
const responseType = schemaToTypeWithCollection(mediaTypeObject.schema);
|
|
125
121
|
return responseType;
|
|
126
122
|
}
|
|
127
123
|
function generateResponseType(responses) {
|
|
128
|
-
if (!responses)
|
|
129
|
-
return "";
|
|
124
|
+
if (!responses) return "";
|
|
130
125
|
const types = [];
|
|
131
126
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
132
127
|
if (statusCode.startsWith("2")) {
|
|
@@ -139,8 +134,7 @@ function generateResponseType(responses) {
|
|
|
139
134
|
return types.join(" | ");
|
|
140
135
|
}
|
|
141
136
|
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
142
|
-
if (allParams === "undefined")
|
|
143
|
-
allParams = "";
|
|
137
|
+
if (allParams === "undefined") allParams = "";
|
|
144
138
|
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
145
139
|
if (requestBodyPayload === "formData") {
|
|
146
140
|
const paramStr = parameters?.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
@@ -200,14 +194,12 @@ function combineAllParams(parameters, requestBodyParam) {
|
|
|
200
194
|
let allParamsArray = [];
|
|
201
195
|
if (parameters && parameters.params)
|
|
202
196
|
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
203
|
-
if (requestBodyParam)
|
|
204
|
-
allParamsArray.push(requestBodyParam.trim());
|
|
197
|
+
if (requestBodyParam) allParamsArray.push(requestBodyParam.trim());
|
|
205
198
|
allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
|
|
206
199
|
return allParamsArray.join(", ");
|
|
207
200
|
}
|
|
208
201
|
function generateFunctionParameters(params, isFileUpload = false) {
|
|
209
|
-
if (!params?.length)
|
|
210
|
-
return {};
|
|
202
|
+
if (!params?.length) return {};
|
|
211
203
|
if (isFileUpload) {
|
|
212
204
|
return {
|
|
213
205
|
config: {
|
|
@@ -246,8 +238,7 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
246
238
|
};
|
|
247
239
|
}
|
|
248
240
|
function generateFunctionForOperation(method, path, operation) {
|
|
249
|
-
if (!operation)
|
|
250
|
-
return "";
|
|
241
|
+
if (!operation) return "";
|
|
251
242
|
const isFileUpload = operation.requestBody?.content["multipart/form-data"]?.schema?.$ref?.includes("Body_upload_files");
|
|
252
243
|
const parameters = generateFunctionParameters(
|
|
253
244
|
operation.parameters,
|
|
@@ -269,6 +260,7 @@ function generateFunctionForOperation(method, path, operation) {
|
|
|
269
260
|
);
|
|
270
261
|
}
|
|
271
262
|
const generateRandomString = () => Math.random().toString(36).slice(7);
|
|
263
|
+
const DOUBLE_QUOTE_REGEX = /"([^"]+)":/g;
|
|
272
264
|
function fileTemplate(tsString, typeForImport, baseURL) {
|
|
273
265
|
const templateCode = `import ax from 'axios';
|
|
274
266
|
import type { AxiosResponse } from 'axios';
|
|
@@ -282,8 +274,7 @@ function fileTemplate(tsString, typeForImport, baseURL) {
|
|
|
282
274
|
|
|
283
275
|
export const axios = ax.create({baseURL:${baseURL}});
|
|
284
276
|
${tsString}`;
|
|
285
|
-
|
|
286
|
-
return templateCode.replace(doubleQuoteRegex, "$1:");
|
|
277
|
+
return templateCode.replace(DOUBLE_QUOTE_REGEX, "$1:");
|
|
287
278
|
}
|
|
288
279
|
const functionsInventory = {};
|
|
289
280
|
const pathOperations = [];
|
|
@@ -329,8 +320,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
329
320
|
const splitPath = path.split("/").filter((p) => p && !/\{|\}/.test(p));
|
|
330
321
|
splitPath.reduce((acc, key, index, array) => {
|
|
331
322
|
const objFuncKey = toCamelCase(key);
|
|
332
|
-
if (!objFuncKey)
|
|
333
|
-
return acc;
|
|
323
|
+
if (!objFuncKey) return acc;
|
|
334
324
|
const methods = Object.keys(operation);
|
|
335
325
|
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
|
|
336
326
|
const method = methods[0];
|
|
@@ -345,7 +335,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
345
335
|
}, body);
|
|
346
336
|
}
|
|
347
337
|
for (const [parent, object] of Object.entries(body)) {
|
|
348
|
-
tsString += `export const ${parent} = ${JSON.stringify(object,
|
|
338
|
+
tsString += `export const ${parent} = ${JSON.stringify(object, undefined, 2)};
|
|
349
339
|
`;
|
|
350
340
|
}
|
|
351
341
|
Object.entries(functionsInventory).forEach(([key, value]) => {
|
|
@@ -362,8 +352,13 @@ function generateTypes(schemas) {
|
|
|
362
352
|
return `export type ${typeName} = ${schema.enum.map((item) => `'${item}'`).join(" | ")};
|
|
363
353
|
`;
|
|
364
354
|
}
|
|
365
|
-
if (
|
|
355
|
+
if (schema.type === "array" && schema.items) {
|
|
356
|
+
return `export type ${typeName} = ${schemaToType(schema.items)}[];
|
|
357
|
+
`;
|
|
358
|
+
}
|
|
359
|
+
if (!schema.properties) {
|
|
366
360
|
return "";
|
|
361
|
+
}
|
|
367
362
|
const properties = Object.entries(schema.properties).map(([key, value]) => {
|
|
368
363
|
const varType = formatVarType({ varName: key, schema: value });
|
|
369
364
|
return ` ${varType}`;
|
|
@@ -380,12 +375,10 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
380
375
|
try {
|
|
381
376
|
const { data: openApi } = await axios$1.get(openApiUrl, { headers: basicAuthHeader });
|
|
382
377
|
const schemas = openApi.components?.schemas;
|
|
383
|
-
if (!schemas)
|
|
384
|
-
throw new Error("No schemas found in OpenAPI document");
|
|
378
|
+
if (!schemas) throw new Error("No schemas found in OpenAPI document");
|
|
385
379
|
const types = generateTypes(schemas);
|
|
386
380
|
const { paths } = openApi;
|
|
387
|
-
if (!paths)
|
|
388
|
-
throw new Error("No paths found in OpenAPI document");
|
|
381
|
+
if (!paths) throw new Error("No paths found in OpenAPI document");
|
|
389
382
|
const code = generateFunctions(paths, baseUrl);
|
|
390
383
|
return { types, code };
|
|
391
384
|
} catch (error) {
|
|
@@ -393,28 +386,21 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
393
386
|
}
|
|
394
387
|
};
|
|
395
388
|
|
|
396
|
-
var __defProp = Object.defineProperty;
|
|
397
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
398
|
-
var __publicField = (obj, key, value) => {
|
|
399
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
400
|
-
return value;
|
|
401
|
-
};
|
|
402
389
|
const axios = axios$1.create({
|
|
403
390
|
withCredentials: true
|
|
404
391
|
});
|
|
405
392
|
class DataRequest {
|
|
393
|
+
data_table;
|
|
394
|
+
bagel;
|
|
395
|
+
itemID;
|
|
396
|
+
_filter = {};
|
|
406
397
|
constructor(table, bagel) {
|
|
407
|
-
__publicField(this, "data_table");
|
|
408
|
-
__publicField(this, "bagel");
|
|
409
|
-
__publicField(this, "itemID");
|
|
410
|
-
__publicField(this, "_filter", {});
|
|
411
398
|
this.data_table = table;
|
|
412
399
|
this.bagel = bagel;
|
|
413
400
|
this.itemID = "";
|
|
414
401
|
}
|
|
415
402
|
async post(item) {
|
|
416
|
-
if (!this.data_table)
|
|
417
|
-
throw new Error("Data table not set");
|
|
403
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
418
404
|
const { data } = await axios.post(`/data/${this.data_table}`, item);
|
|
419
405
|
return data;
|
|
420
406
|
}
|
|
@@ -423,8 +409,7 @@ class DataRequest {
|
|
|
423
409
|
return this;
|
|
424
410
|
}
|
|
425
411
|
async get() {
|
|
426
|
-
if (!this.data_table)
|
|
427
|
-
throw new Error("Data table not set");
|
|
412
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
428
413
|
const filterStr = Object.keys(this._filter).length > 0 ? `?filter={${Object.entries(this._filter).map(([k, v]) => `${k}:${v}`).join(",")}}` : "";
|
|
429
414
|
const url = `/data/${this.data_table}${this.itemID ? `/${this.itemID}` : ""}${filterStr}`;
|
|
430
415
|
try {
|
|
@@ -433,7 +418,7 @@ class DataRequest {
|
|
|
433
418
|
} catch (err) {
|
|
434
419
|
console.log(err);
|
|
435
420
|
this.bagel.onError?.(err);
|
|
436
|
-
return
|
|
421
|
+
return undefined;
|
|
437
422
|
}
|
|
438
423
|
}
|
|
439
424
|
item(id) {
|
|
@@ -441,8 +426,7 @@ class DataRequest {
|
|
|
441
426
|
return this;
|
|
442
427
|
}
|
|
443
428
|
async delete() {
|
|
444
|
-
if (!this.data_table)
|
|
445
|
-
throw new Error("Data table not set");
|
|
429
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
446
430
|
const { data } = await axios.delete(
|
|
447
431
|
`/data/${this.data_table}/${this.itemID}`
|
|
448
432
|
);
|
|
@@ -450,10 +434,8 @@ class DataRequest {
|
|
|
450
434
|
}
|
|
451
435
|
async put(updatedItem) {
|
|
452
436
|
const { data_table, itemID } = this;
|
|
453
|
-
if (!data_table)
|
|
454
|
-
|
|
455
|
-
if (!itemID)
|
|
456
|
-
throw new Error("Item ID not set");
|
|
437
|
+
if (!data_table) throw new Error("Data table not set");
|
|
438
|
+
if (!itemID) throw new Error("Item ID not set");
|
|
457
439
|
const { data } = await axios.put(
|
|
458
440
|
`/data/${data_table}/${itemID}`,
|
|
459
441
|
updatedItem
|
|
@@ -471,9 +453,9 @@ function responses(key) {
|
|
|
471
453
|
class BagelAuth {
|
|
472
454
|
constructor(bagel) {
|
|
473
455
|
this.bagel = bagel;
|
|
474
|
-
__publicField(this, "user");
|
|
475
456
|
this.bagel = bagel;
|
|
476
457
|
}
|
|
458
|
+
user = undefined;
|
|
477
459
|
async validateUser() {
|
|
478
460
|
try {
|
|
479
461
|
const { data: usr } = await axios.get("/users/me", {
|
|
@@ -521,7 +503,7 @@ class BagelAuth {
|
|
|
521
503
|
this.bagel.onError?.(err);
|
|
522
504
|
console.log(err);
|
|
523
505
|
}
|
|
524
|
-
this.user =
|
|
506
|
+
this.user = undefined;
|
|
525
507
|
}
|
|
526
508
|
async acceptInvite(token, user) {
|
|
527
509
|
await axios.post(`/auth/accept-invite/${token}`, user);
|
|
@@ -539,12 +521,10 @@ class BagelAuth {
|
|
|
539
521
|
}
|
|
540
522
|
}
|
|
541
523
|
class Bagel {
|
|
524
|
+
host;
|
|
525
|
+
fileBaseUrl;
|
|
526
|
+
onError;
|
|
542
527
|
constructor({ host, fileBaseUrl, onError }) {
|
|
543
|
-
__publicField(this, "host");
|
|
544
|
-
__publicField(this, "fileBaseUrl");
|
|
545
|
-
__publicField(this, "onError");
|
|
546
|
-
__publicField(this, "read_table");
|
|
547
|
-
__publicField(this, "auth", new BagelAuth(this));
|
|
548
528
|
this.host = host?.replace(/\/$/, "");
|
|
549
529
|
this.fileBaseUrl = fileBaseUrl?.replace(/\/$/, "");
|
|
550
530
|
if (!this.host) {
|
|
@@ -553,9 +533,11 @@ class Bagel {
|
|
|
553
533
|
axios.defaults.baseURL = this.host;
|
|
554
534
|
this.onError = onError;
|
|
555
535
|
}
|
|
536
|
+
read_table = undefined;
|
|
556
537
|
data(table) {
|
|
557
538
|
return new DataRequest(table, this);
|
|
558
539
|
}
|
|
540
|
+
auth = new BagelAuth(this);
|
|
559
541
|
_endpointCleaner(endpoint) {
|
|
560
542
|
const url = `${endpoint.replace(/^\//, "").replaceAll(/\/$/g, "")}`;
|
|
561
543
|
return url;
|
|
@@ -570,12 +552,10 @@ class Bagel {
|
|
|
570
552
|
async get(endpoint, query) {
|
|
571
553
|
this._setAuthorization();
|
|
572
554
|
endpoint = this._endpointCleaner(endpoint);
|
|
573
|
-
if (/undefined|null/.test(endpoint))
|
|
574
|
-
throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
555
|
+
if (/undefined|null/.test(endpoint)) throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
575
556
|
if (query) {
|
|
576
557
|
const queryParams = Object.entries(query).filter(([_, value]) => !!value).map(([key, value]) => `${key}=${value}`).join("&");
|
|
577
|
-
if (queryParams)
|
|
578
|
-
endpoint = `${endpoint}?${queryParams}`;
|
|
558
|
+
if (queryParams) endpoint = `${endpoint}?${queryParams}`;
|
|
579
559
|
}
|
|
580
560
|
const url = `/${endpoint}`;
|
|
581
561
|
return axios.get(url).then(({ data }) => data).catch((err) => {
|
|
@@ -625,8 +605,7 @@ class Bagel {
|
|
|
625
605
|
const formData = new FormData();
|
|
626
606
|
formData.append("file", file);
|
|
627
607
|
let url = "/static_files/upload";
|
|
628
|
-
if (options?.topic)
|
|
629
|
-
url = `/static_files/upload?topic=${options.topic}`;
|
|
608
|
+
if (options?.topic) url = `/static_files/upload?topic=${options.topic}`;
|
|
630
609
|
const { data } = await axios.post(url, formData, {
|
|
631
610
|
headers: {
|
|
632
611
|
"Content-Type": "multipart/form-data"
|
package/package.json
CHANGED
|
@@ -5,6 +5,7 @@ import type {
|
|
|
5
5
|
RequestBodyObject,
|
|
6
6
|
ResponseObject,
|
|
7
7
|
ResponsesObject,
|
|
8
|
+
SchemaObject,
|
|
8
9
|
} from './openApiTypes'
|
|
9
10
|
|
|
10
11
|
import {
|
|
@@ -44,11 +45,16 @@ function collectTypeForImportStatement(typeName: string) {
|
|
|
44
45
|
if (!allTypes.includes(typeName)) allTypes.push(typeName)
|
|
45
46
|
}
|
|
46
47
|
|
|
48
|
+
function schemaToTypeWithCollection(schema?: SchemaObject): string {
|
|
49
|
+
const type = schemaToType(schema)
|
|
50
|
+
collectTypeForImportStatement(type)
|
|
51
|
+
return type
|
|
52
|
+
}
|
|
53
|
+
|
|
47
54
|
function getResponseType(response: ResponseObject): string | undefined {
|
|
48
55
|
const mediaTypeObject = response.content?.['application/json']
|
|
49
56
|
if (!mediaTypeObject || !mediaTypeObject.schema) return
|
|
50
|
-
const responseType =
|
|
51
|
-
collectTypeForImportStatement(responseType)
|
|
57
|
+
const responseType = schemaToTypeWithCollection(mediaTypeObject.schema)
|
|
52
58
|
return responseType
|
|
53
59
|
}
|
|
54
60
|
|
|
@@ -280,6 +286,8 @@ function generateFunctionForOperation(
|
|
|
280
286
|
|
|
281
287
|
const generateRandomString = () => Math.random().toString(36).slice(7)
|
|
282
288
|
|
|
289
|
+
const DOUBLE_QUOTE_REGEX = /"([^"]+)":/g // ! TODO: @nevehallon believes this may not be necessary
|
|
290
|
+
|
|
283
291
|
function fileTemplate(
|
|
284
292
|
tsString: string,
|
|
285
293
|
typeForImport: string[],
|
|
@@ -297,8 +305,7 @@ function fileTemplate(
|
|
|
297
305
|
|
|
298
306
|
export const axios = ax.create({baseURL:${baseURL}});
|
|
299
307
|
${tsString}`
|
|
300
|
-
|
|
301
|
-
return templateCode.replace(doubleQuoteRegex, '$1:')
|
|
308
|
+
return templateCode.replace(DOUBLE_QUOTE_REGEX, '$1:')
|
|
302
309
|
}
|
|
303
310
|
|
|
304
311
|
interface PathOperation {
|
|
@@ -1,21 +1,42 @@
|
|
|
1
1
|
import type { SchemasObject } from './openApiTypes'
|
|
2
|
-
import { formatType, formatVarType } from './utils'
|
|
2
|
+
import { formatType, formatVarType, schemaToType } from './utils'
|
|
3
3
|
|
|
4
4
|
export function generateTypes(schemas: SchemasObject): string {
|
|
5
|
-
return Object.entries(schemas)
|
|
6
|
-
typeName
|
|
5
|
+
return Object.entries(schemas)
|
|
6
|
+
.map(([typeName, schema]) => {
|
|
7
|
+
typeName = formatType(typeName)
|
|
7
8
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (!schema.properties) return ''
|
|
9
|
+
if (schema.enum) {
|
|
10
|
+
return `export type ${typeName} = ${schema.enum.map((item: string) => `'${item}'`).join(' | ')};\n`
|
|
11
|
+
}
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
if (schema.type === 'array' && schema.items) {
|
|
14
|
+
return `export type ${typeName} = ${schemaToType(schema.items)}[];\n`
|
|
15
|
+
}
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
// if (typeName === 'LocalizedJsonInt') {
|
|
18
|
+
// console.log(JSON.stringify({ typeName, schema }, null, 2))
|
|
19
|
+
// }
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
if (!schema.properties) {
|
|
22
|
+
// #region Debug
|
|
23
|
+
// console.log('No properties found for schema:', typeName)
|
|
24
|
+
|
|
25
|
+
// console.log(JSON.stringify({ typeName, schema }, null, 2))
|
|
26
|
+
// #endregion Debug
|
|
27
|
+
|
|
28
|
+
return ''
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const properties = Object.entries(schema.properties)
|
|
32
|
+
.map(([key, value]) => {
|
|
33
|
+
const varType = formatVarType({ varName: key, schema: value })
|
|
34
|
+
|
|
35
|
+
return `\t\t${varType}`
|
|
36
|
+
})
|
|
37
|
+
.join(';\n ')
|
|
38
|
+
|
|
39
|
+
return `export type ${typeName} = {\n ${properties};\n };\n`
|
|
40
|
+
})
|
|
41
|
+
.join('\n')
|
|
21
42
|
}
|