@bagelink/sdk 0.0.1129 → 0.0.1131
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 +55 -74
- package/dist/index.mjs +55 -74
- package/package.json +1 -1
- package/src/openAPITools/functionGenerator.ts +11 -4
- package/src/openAPITools/typeGenerator.ts +30 -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,15 @@ 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) {
|
|
366
|
+
console.log("No properties found for schema:", typeName);
|
|
367
|
+
console.log(JSON.stringify({ typeName, schema }, null, 2));
|
|
372
368
|
return "";
|
|
369
|
+
}
|
|
373
370
|
const properties = Object.entries(schema.properties).map(([key, value]) => {
|
|
374
371
|
const varType = formatVarType({ varName: key, schema: value });
|
|
375
372
|
return ` ${varType}`;
|
|
@@ -386,12 +383,10 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
386
383
|
try {
|
|
387
384
|
const { data: openApi } = await axios__default.get(openApiUrl, { headers: basicAuthHeader });
|
|
388
385
|
const schemas = openApi.components?.schemas;
|
|
389
|
-
if (!schemas)
|
|
390
|
-
throw new Error("No schemas found in OpenAPI document");
|
|
386
|
+
if (!schemas) throw new Error("No schemas found in OpenAPI document");
|
|
391
387
|
const types = generateTypes(schemas);
|
|
392
388
|
const { paths } = openApi;
|
|
393
|
-
if (!paths)
|
|
394
|
-
throw new Error("No paths found in OpenAPI document");
|
|
389
|
+
if (!paths) throw new Error("No paths found in OpenAPI document");
|
|
395
390
|
const code = generateFunctions(paths, baseUrl);
|
|
396
391
|
return { types, code };
|
|
397
392
|
} catch (error) {
|
|
@@ -399,28 +394,21 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
399
394
|
}
|
|
400
395
|
};
|
|
401
396
|
|
|
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
397
|
const axios = axios__default.create({
|
|
409
398
|
withCredentials: true
|
|
410
399
|
});
|
|
411
400
|
class DataRequest {
|
|
401
|
+
data_table;
|
|
402
|
+
bagel;
|
|
403
|
+
itemID;
|
|
404
|
+
_filter = {};
|
|
412
405
|
constructor(table, bagel) {
|
|
413
|
-
__publicField(this, "data_table");
|
|
414
|
-
__publicField(this, "bagel");
|
|
415
|
-
__publicField(this, "itemID");
|
|
416
|
-
__publicField(this, "_filter", {});
|
|
417
406
|
this.data_table = table;
|
|
418
407
|
this.bagel = bagel;
|
|
419
408
|
this.itemID = "";
|
|
420
409
|
}
|
|
421
410
|
async post(item) {
|
|
422
|
-
if (!this.data_table)
|
|
423
|
-
throw new Error("Data table not set");
|
|
411
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
424
412
|
const { data } = await axios.post(`/data/${this.data_table}`, item);
|
|
425
413
|
return data;
|
|
426
414
|
}
|
|
@@ -429,8 +417,7 @@ class DataRequest {
|
|
|
429
417
|
return this;
|
|
430
418
|
}
|
|
431
419
|
async get() {
|
|
432
|
-
if (!this.data_table)
|
|
433
|
-
throw new Error("Data table not set");
|
|
420
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
434
421
|
const filterStr = Object.keys(this._filter).length > 0 ? `?filter={${Object.entries(this._filter).map(([k, v]) => `${k}:${v}`).join(",")}}` : "";
|
|
435
422
|
const url = `/data/${this.data_table}${this.itemID ? `/${this.itemID}` : ""}${filterStr}`;
|
|
436
423
|
try {
|
|
@@ -439,7 +426,7 @@ class DataRequest {
|
|
|
439
426
|
} catch (err) {
|
|
440
427
|
console.log(err);
|
|
441
428
|
this.bagel.onError?.(err);
|
|
442
|
-
return
|
|
429
|
+
return undefined;
|
|
443
430
|
}
|
|
444
431
|
}
|
|
445
432
|
item(id) {
|
|
@@ -447,8 +434,7 @@ class DataRequest {
|
|
|
447
434
|
return this;
|
|
448
435
|
}
|
|
449
436
|
async delete() {
|
|
450
|
-
if (!this.data_table)
|
|
451
|
-
throw new Error("Data table not set");
|
|
437
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
452
438
|
const { data } = await axios.delete(
|
|
453
439
|
`/data/${this.data_table}/${this.itemID}`
|
|
454
440
|
);
|
|
@@ -456,10 +442,8 @@ class DataRequest {
|
|
|
456
442
|
}
|
|
457
443
|
async put(updatedItem) {
|
|
458
444
|
const { data_table, itemID } = this;
|
|
459
|
-
if (!data_table)
|
|
460
|
-
|
|
461
|
-
if (!itemID)
|
|
462
|
-
throw new Error("Item ID not set");
|
|
445
|
+
if (!data_table) throw new Error("Data table not set");
|
|
446
|
+
if (!itemID) throw new Error("Item ID not set");
|
|
463
447
|
const { data } = await axios.put(
|
|
464
448
|
`/data/${data_table}/${itemID}`,
|
|
465
449
|
updatedItem
|
|
@@ -477,9 +461,9 @@ function responses(key) {
|
|
|
477
461
|
class BagelAuth {
|
|
478
462
|
constructor(bagel) {
|
|
479
463
|
this.bagel = bagel;
|
|
480
|
-
__publicField(this, "user");
|
|
481
464
|
this.bagel = bagel;
|
|
482
465
|
}
|
|
466
|
+
user = undefined;
|
|
483
467
|
async validateUser() {
|
|
484
468
|
try {
|
|
485
469
|
const { data: usr } = await axios.get("/users/me", {
|
|
@@ -527,7 +511,7 @@ class BagelAuth {
|
|
|
527
511
|
this.bagel.onError?.(err);
|
|
528
512
|
console.log(err);
|
|
529
513
|
}
|
|
530
|
-
this.user =
|
|
514
|
+
this.user = undefined;
|
|
531
515
|
}
|
|
532
516
|
async acceptInvite(token, user) {
|
|
533
517
|
await axios.post(`/auth/accept-invite/${token}`, user);
|
|
@@ -545,12 +529,10 @@ class BagelAuth {
|
|
|
545
529
|
}
|
|
546
530
|
}
|
|
547
531
|
class Bagel {
|
|
532
|
+
host;
|
|
533
|
+
fileBaseUrl;
|
|
534
|
+
onError;
|
|
548
535
|
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
536
|
this.host = host?.replace(/\/$/, "");
|
|
555
537
|
this.fileBaseUrl = fileBaseUrl?.replace(/\/$/, "");
|
|
556
538
|
if (!this.host) {
|
|
@@ -559,9 +541,11 @@ class Bagel {
|
|
|
559
541
|
axios.defaults.baseURL = this.host;
|
|
560
542
|
this.onError = onError;
|
|
561
543
|
}
|
|
544
|
+
read_table = undefined;
|
|
562
545
|
data(table) {
|
|
563
546
|
return new DataRequest(table, this);
|
|
564
547
|
}
|
|
548
|
+
auth = new BagelAuth(this);
|
|
565
549
|
_endpointCleaner(endpoint) {
|
|
566
550
|
const url = `${endpoint.replace(/^\//, "").replaceAll(/\/$/g, "")}`;
|
|
567
551
|
return url;
|
|
@@ -576,12 +560,10 @@ class Bagel {
|
|
|
576
560
|
async get(endpoint, query) {
|
|
577
561
|
this._setAuthorization();
|
|
578
562
|
endpoint = this._endpointCleaner(endpoint);
|
|
579
|
-
if (/undefined|null/.test(endpoint))
|
|
580
|
-
throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
563
|
+
if (/undefined|null/.test(endpoint)) throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
581
564
|
if (query) {
|
|
582
565
|
const queryParams = Object.entries(query).filter(([_, value]) => !!value).map(([key, value]) => `${key}=${value}`).join("&");
|
|
583
|
-
if (queryParams)
|
|
584
|
-
endpoint = `${endpoint}?${queryParams}`;
|
|
566
|
+
if (queryParams) endpoint = `${endpoint}?${queryParams}`;
|
|
585
567
|
}
|
|
586
568
|
const url = `/${endpoint}`;
|
|
587
569
|
return axios.get(url).then(({ data }) => data).catch((err) => {
|
|
@@ -631,8 +613,7 @@ class Bagel {
|
|
|
631
613
|
const formData = new FormData();
|
|
632
614
|
formData.append("file", file);
|
|
633
615
|
let url = "/static_files/upload";
|
|
634
|
-
if (options?.topic)
|
|
635
|
-
url = `/static_files/upload?topic=${options.topic}`;
|
|
616
|
+
if (options?.topic) url = `/static_files/upload?topic=${options.topic}`;
|
|
636
617
|
const { data } = await axios.post(url, formData, {
|
|
637
618
|
headers: {
|
|
638
619
|
"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,15 @@ 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) {
|
|
360
|
+
console.log("No properties found for schema:", typeName);
|
|
361
|
+
console.log(JSON.stringify({ typeName, schema }, null, 2));
|
|
366
362
|
return "";
|
|
363
|
+
}
|
|
367
364
|
const properties = Object.entries(schema.properties).map(([key, value]) => {
|
|
368
365
|
const varType = formatVarType({ varName: key, schema: value });
|
|
369
366
|
return ` ${varType}`;
|
|
@@ -380,12 +377,10 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
380
377
|
try {
|
|
381
378
|
const { data: openApi } = await axios$1.get(openApiUrl, { headers: basicAuthHeader });
|
|
382
379
|
const schemas = openApi.components?.schemas;
|
|
383
|
-
if (!schemas)
|
|
384
|
-
throw new Error("No schemas found in OpenAPI document");
|
|
380
|
+
if (!schemas) throw new Error("No schemas found in OpenAPI document");
|
|
385
381
|
const types = generateTypes(schemas);
|
|
386
382
|
const { paths } = openApi;
|
|
387
|
-
if (!paths)
|
|
388
|
-
throw new Error("No paths found in OpenAPI document");
|
|
383
|
+
if (!paths) throw new Error("No paths found in OpenAPI document");
|
|
389
384
|
const code = generateFunctions(paths, baseUrl);
|
|
390
385
|
return { types, code };
|
|
391
386
|
} catch (error) {
|
|
@@ -393,28 +388,21 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
393
388
|
}
|
|
394
389
|
};
|
|
395
390
|
|
|
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
391
|
const axios = axios$1.create({
|
|
403
392
|
withCredentials: true
|
|
404
393
|
});
|
|
405
394
|
class DataRequest {
|
|
395
|
+
data_table;
|
|
396
|
+
bagel;
|
|
397
|
+
itemID;
|
|
398
|
+
_filter = {};
|
|
406
399
|
constructor(table, bagel) {
|
|
407
|
-
__publicField(this, "data_table");
|
|
408
|
-
__publicField(this, "bagel");
|
|
409
|
-
__publicField(this, "itemID");
|
|
410
|
-
__publicField(this, "_filter", {});
|
|
411
400
|
this.data_table = table;
|
|
412
401
|
this.bagel = bagel;
|
|
413
402
|
this.itemID = "";
|
|
414
403
|
}
|
|
415
404
|
async post(item) {
|
|
416
|
-
if (!this.data_table)
|
|
417
|
-
throw new Error("Data table not set");
|
|
405
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
418
406
|
const { data } = await axios.post(`/data/${this.data_table}`, item);
|
|
419
407
|
return data;
|
|
420
408
|
}
|
|
@@ -423,8 +411,7 @@ class DataRequest {
|
|
|
423
411
|
return this;
|
|
424
412
|
}
|
|
425
413
|
async get() {
|
|
426
|
-
if (!this.data_table)
|
|
427
|
-
throw new Error("Data table not set");
|
|
414
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
428
415
|
const filterStr = Object.keys(this._filter).length > 0 ? `?filter={${Object.entries(this._filter).map(([k, v]) => `${k}:${v}`).join(",")}}` : "";
|
|
429
416
|
const url = `/data/${this.data_table}${this.itemID ? `/${this.itemID}` : ""}${filterStr}`;
|
|
430
417
|
try {
|
|
@@ -433,7 +420,7 @@ class DataRequest {
|
|
|
433
420
|
} catch (err) {
|
|
434
421
|
console.log(err);
|
|
435
422
|
this.bagel.onError?.(err);
|
|
436
|
-
return
|
|
423
|
+
return undefined;
|
|
437
424
|
}
|
|
438
425
|
}
|
|
439
426
|
item(id) {
|
|
@@ -441,8 +428,7 @@ class DataRequest {
|
|
|
441
428
|
return this;
|
|
442
429
|
}
|
|
443
430
|
async delete() {
|
|
444
|
-
if (!this.data_table)
|
|
445
|
-
throw new Error("Data table not set");
|
|
431
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
446
432
|
const { data } = await axios.delete(
|
|
447
433
|
`/data/${this.data_table}/${this.itemID}`
|
|
448
434
|
);
|
|
@@ -450,10 +436,8 @@ class DataRequest {
|
|
|
450
436
|
}
|
|
451
437
|
async put(updatedItem) {
|
|
452
438
|
const { data_table, itemID } = this;
|
|
453
|
-
if (!data_table)
|
|
454
|
-
|
|
455
|
-
if (!itemID)
|
|
456
|
-
throw new Error("Item ID not set");
|
|
439
|
+
if (!data_table) throw new Error("Data table not set");
|
|
440
|
+
if (!itemID) throw new Error("Item ID not set");
|
|
457
441
|
const { data } = await axios.put(
|
|
458
442
|
`/data/${data_table}/${itemID}`,
|
|
459
443
|
updatedItem
|
|
@@ -471,9 +455,9 @@ function responses(key) {
|
|
|
471
455
|
class BagelAuth {
|
|
472
456
|
constructor(bagel) {
|
|
473
457
|
this.bagel = bagel;
|
|
474
|
-
__publicField(this, "user");
|
|
475
458
|
this.bagel = bagel;
|
|
476
459
|
}
|
|
460
|
+
user = undefined;
|
|
477
461
|
async validateUser() {
|
|
478
462
|
try {
|
|
479
463
|
const { data: usr } = await axios.get("/users/me", {
|
|
@@ -521,7 +505,7 @@ class BagelAuth {
|
|
|
521
505
|
this.bagel.onError?.(err);
|
|
522
506
|
console.log(err);
|
|
523
507
|
}
|
|
524
|
-
this.user =
|
|
508
|
+
this.user = undefined;
|
|
525
509
|
}
|
|
526
510
|
async acceptInvite(token, user) {
|
|
527
511
|
await axios.post(`/auth/accept-invite/${token}`, user);
|
|
@@ -539,12 +523,10 @@ class BagelAuth {
|
|
|
539
523
|
}
|
|
540
524
|
}
|
|
541
525
|
class Bagel {
|
|
526
|
+
host;
|
|
527
|
+
fileBaseUrl;
|
|
528
|
+
onError;
|
|
542
529
|
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
530
|
this.host = host?.replace(/\/$/, "");
|
|
549
531
|
this.fileBaseUrl = fileBaseUrl?.replace(/\/$/, "");
|
|
550
532
|
if (!this.host) {
|
|
@@ -553,9 +535,11 @@ class Bagel {
|
|
|
553
535
|
axios.defaults.baseURL = this.host;
|
|
554
536
|
this.onError = onError;
|
|
555
537
|
}
|
|
538
|
+
read_table = undefined;
|
|
556
539
|
data(table) {
|
|
557
540
|
return new DataRequest(table, this);
|
|
558
541
|
}
|
|
542
|
+
auth = new BagelAuth(this);
|
|
559
543
|
_endpointCleaner(endpoint) {
|
|
560
544
|
const url = `${endpoint.replace(/^\//, "").replaceAll(/\/$/g, "")}`;
|
|
561
545
|
return url;
|
|
@@ -570,12 +554,10 @@ class Bagel {
|
|
|
570
554
|
async get(endpoint, query) {
|
|
571
555
|
this._setAuthorization();
|
|
572
556
|
endpoint = this._endpointCleaner(endpoint);
|
|
573
|
-
if (/undefined|null/.test(endpoint))
|
|
574
|
-
throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
557
|
+
if (/undefined|null/.test(endpoint)) throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
575
558
|
if (query) {
|
|
576
559
|
const queryParams = Object.entries(query).filter(([_, value]) => !!value).map(([key, value]) => `${key}=${value}`).join("&");
|
|
577
|
-
if (queryParams)
|
|
578
|
-
endpoint = `${endpoint}?${queryParams}`;
|
|
560
|
+
if (queryParams) endpoint = `${endpoint}?${queryParams}`;
|
|
579
561
|
}
|
|
580
562
|
const url = `/${endpoint}`;
|
|
581
563
|
return axios.get(url).then(({ data }) => data).catch((err) => {
|
|
@@ -625,8 +607,7 @@ class Bagel {
|
|
|
625
607
|
const formData = new FormData();
|
|
626
608
|
formData.append("file", file);
|
|
627
609
|
let url = "/static_files/upload";
|
|
628
|
-
if (options?.topic)
|
|
629
|
-
url = `/static_files/upload?topic=${options.topic}`;
|
|
610
|
+
if (options?.topic) url = `/static_files/upload?topic=${options.topic}`;
|
|
630
611
|
const { data } = await axios.post(url, formData, {
|
|
631
612
|
headers: {
|
|
632
613
|
"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,38 @@
|
|
|
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 (!schema.properties) {
|
|
18
|
+
// #region Debug
|
|
19
|
+
console.log('No properties found for schema:', typeName)
|
|
18
20
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
+
console.log(JSON.stringify({ typeName, schema }, null, 2))
|
|
22
|
+
// #endregion Debug
|
|
23
|
+
|
|
24
|
+
return ''
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const properties = Object.entries(schema.properties)
|
|
28
|
+
.map(([key, value]) => {
|
|
29
|
+
const varType = formatVarType({ varName: key, schema: value })
|
|
30
|
+
|
|
31
|
+
return `\t\t${varType}`
|
|
32
|
+
})
|
|
33
|
+
.join(';\n ')
|
|
34
|
+
|
|
35
|
+
return `export type ${typeName} = {\n ${properties};\n };\n`
|
|
36
|
+
})
|
|
37
|
+
.join('\n')
|
|
21
38
|
}
|