@bagelink/sdk 0.0.1119 → 0.0.1123
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 +101 -90
- package/dist/index.mjs +101 -90
- package/package.json +1 -1
- package/src/openAPITools/functionGenerator.ts +122 -48
- package/src/openAPITools/typeGenerator.ts +1 -1
- package/src/openAPITools/utils.ts +49 -9
package/dist/index.cjs
CHANGED
|
@@ -14,23 +14,19 @@ function formatType(typeName) {
|
|
|
14
14
|
}
|
|
15
15
|
function resolveReference(ref) {
|
|
16
16
|
const t = ref.split("/").pop();
|
|
17
|
-
if (!t)
|
|
18
|
-
return "any";
|
|
17
|
+
if (!t) return "any";
|
|
19
18
|
return formatType(t);
|
|
20
19
|
}
|
|
21
20
|
function schemaToType(schema) {
|
|
22
|
-
if (!schema)
|
|
23
|
-
return "any";
|
|
21
|
+
if (!schema) return "any";
|
|
24
22
|
if (schema.anyOf) {
|
|
25
23
|
let _t = schema.anyOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" | ");
|
|
26
|
-
if (_t === "" || _t === "null")
|
|
27
|
-
_t = "any";
|
|
24
|
+
if (_t === "" || _t === "null") _t = "any";
|
|
28
25
|
return _t;
|
|
29
26
|
}
|
|
30
27
|
if (schema.allOf)
|
|
31
28
|
return schema.allOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" & ");
|
|
32
|
-
if (schema.$ref)
|
|
33
|
-
return resolveReference(schema.$ref);
|
|
29
|
+
if (schema.$ref) return resolveReference(schema.$ref);
|
|
34
30
|
switch (schema.type) {
|
|
35
31
|
case "object":
|
|
36
32
|
return "{ [key: string]: any }";
|
|
@@ -48,7 +44,7 @@ function schemaToType(schema) {
|
|
|
48
44
|
return "undefined";
|
|
49
45
|
case "null":
|
|
50
46
|
return "null";
|
|
51
|
-
case
|
|
47
|
+
case undefined:
|
|
52
48
|
return "any";
|
|
53
49
|
default:
|
|
54
50
|
console.log("Unknown type", schema.type);
|
|
@@ -60,10 +56,16 @@ function isOptional(schema) {
|
|
|
60
56
|
const splitType = type.split(/\s+\|\s+/);
|
|
61
57
|
const includesNull = splitType.includes("null");
|
|
62
58
|
const includesUndefined = splitType.includes("undefined");
|
|
63
|
-
return includesNull || includesUndefined || schema.default !==
|
|
59
|
+
return includesNull || includesUndefined || schema.default !== undefined;
|
|
64
60
|
}
|
|
65
61
|
const cleanOptionals = (str) => str.split(" | ").filter((t) => t !== "null" && t !== "undefined").join(" | ");
|
|
66
|
-
function formatVarType(
|
|
62
|
+
function formatVarType({
|
|
63
|
+
varName,
|
|
64
|
+
schema,
|
|
65
|
+
required = false,
|
|
66
|
+
defaultValue
|
|
67
|
+
}) {
|
|
68
|
+
if (varName === "personId") console.log({ varName, schema, required, defaultValue });
|
|
67
69
|
let type = schemaToType(schema);
|
|
68
70
|
type = cleanOptionals(type);
|
|
69
71
|
let defaultStr = "";
|
|
@@ -74,9 +76,8 @@ function formatVarType(varName, schema, required = false, defaultValue) {
|
|
|
74
76
|
defaultStr = ` = ${defaultValue}`;
|
|
75
77
|
}
|
|
76
78
|
}
|
|
77
|
-
let optionalStr = required
|
|
78
|
-
if (defaultStr)
|
|
79
|
-
optionalStr = "";
|
|
79
|
+
let optionalStr = !required && isOptional(schema) ? "?" : "";
|
|
80
|
+
if (defaultStr) optionalStr = "";
|
|
80
81
|
return `${varName}${optionalStr}: ${type}${defaultStr}`;
|
|
81
82
|
}
|
|
82
83
|
function cleanPath(path) {
|
|
@@ -84,35 +85,39 @@ function cleanPath(path) {
|
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
const allTypes = [];
|
|
87
|
-
const primitiveTypes = [
|
|
88
|
+
const primitiveTypes = [
|
|
89
|
+
"string",
|
|
90
|
+
"number",
|
|
91
|
+
"boolean",
|
|
92
|
+
"null",
|
|
93
|
+
"void",
|
|
94
|
+
"any",
|
|
95
|
+
"Record<string, any>",
|
|
96
|
+
"undefined",
|
|
97
|
+
"{ [key: string]: any }"
|
|
98
|
+
];
|
|
88
99
|
function collectTypeForImportStatement(typeName) {
|
|
89
100
|
typeName = typeName.trim().replace("[]", "");
|
|
90
101
|
if (typeName.includes("|")) {
|
|
91
|
-
typeName.split("|").forEach(
|
|
92
|
-
(singleType)
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
);
|
|
102
|
+
typeName.split("|").forEach((singleType) => {
|
|
103
|
+
collectTypeForImportStatement(singleType);
|
|
104
|
+
});
|
|
96
105
|
return;
|
|
97
106
|
}
|
|
98
107
|
const isPrimitive = primitiveTypes.includes(typeName);
|
|
99
108
|
typeName = formatType(typeName);
|
|
100
|
-
if (!typeName || isPrimitive)
|
|
101
|
-
|
|
102
|
-
if (!allTypes.includes(typeName))
|
|
103
|
-
allTypes.push(typeName);
|
|
109
|
+
if (!typeName || isPrimitive) return;
|
|
110
|
+
if (!allTypes.includes(typeName)) allTypes.push(typeName);
|
|
104
111
|
}
|
|
105
112
|
function getResponseType(response) {
|
|
106
113
|
const mediaTypeObject = response.content?.["application/json"];
|
|
107
|
-
if (!mediaTypeObject || !mediaTypeObject.schema)
|
|
108
|
-
return;
|
|
114
|
+
if (!mediaTypeObject || !mediaTypeObject.schema) return;
|
|
109
115
|
const responseType = schemaToType(mediaTypeObject.schema);
|
|
110
116
|
collectTypeForImportStatement(responseType);
|
|
111
117
|
return responseType;
|
|
112
118
|
}
|
|
113
119
|
function generateResponseType(responses) {
|
|
114
|
-
if (!responses)
|
|
115
|
-
return "";
|
|
120
|
+
if (!responses) return "";
|
|
116
121
|
const types = [];
|
|
117
122
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
118
123
|
if (statusCode.startsWith("2")) {
|
|
@@ -125,8 +130,7 @@ function generateResponseType(responses) {
|
|
|
125
130
|
return types.join(" | ");
|
|
126
131
|
}
|
|
127
132
|
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
128
|
-
if (allParams === "undefined")
|
|
129
|
-
allParams = "";
|
|
133
|
+
if (allParams === "undefined") allParams = "";
|
|
130
134
|
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
131
135
|
if (requestBodyPayload === "formData") {
|
|
132
136
|
const paramStr = parameters?.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
@@ -175,21 +179,23 @@ function generateRequestBody(requestBody) {
|
|
|
175
179
|
const requestBodyType = schemaToType(bodySchema);
|
|
176
180
|
collectTypeForImportStatement(requestBodyType);
|
|
177
181
|
const requestBodyPayload = toCamelCase(bodySchema.title) || toCamelCase(requestBodyType) || "requestBody";
|
|
178
|
-
const requestBodyParam = formatVarType(
|
|
182
|
+
const requestBodyParam = formatVarType({
|
|
183
|
+
varName: requestBodyPayload,
|
|
184
|
+
schema: bodySchema,
|
|
185
|
+
defaultValue: bodySchema.default
|
|
186
|
+
});
|
|
179
187
|
return { requestBodyParam, requestBodyPayload };
|
|
180
188
|
}
|
|
181
189
|
function combineAllParams(parameters, requestBodyParam) {
|
|
182
190
|
let allParamsArray = [];
|
|
183
191
|
if (parameters && parameters.params)
|
|
184
192
|
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
185
|
-
if (requestBodyParam)
|
|
186
|
-
allParamsArray.push(requestBodyParam.trim());
|
|
193
|
+
if (requestBodyParam) allParamsArray.push(requestBodyParam.trim());
|
|
187
194
|
allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
|
|
188
195
|
return allParamsArray.join(", ");
|
|
189
196
|
}
|
|
190
197
|
function generateFunctionParameters(params, isFileUpload = false) {
|
|
191
|
-
if (!params?.length)
|
|
192
|
-
return {};
|
|
198
|
+
if (!params?.length) return {};
|
|
193
199
|
if (isFileUpload) {
|
|
194
200
|
return {
|
|
195
201
|
config: {
|
|
@@ -207,10 +213,19 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
207
213
|
const paramName = param.name;
|
|
208
214
|
const varName = toCamelCase(param.name);
|
|
209
215
|
if (param.in === "path" || param.in === "query" || param.in === "header") {
|
|
210
|
-
functionParams.push(
|
|
216
|
+
functionParams.push(
|
|
217
|
+
formatVarType({
|
|
218
|
+
varName,
|
|
219
|
+
schema: param.schema,
|
|
220
|
+
required: param.required,
|
|
221
|
+
defaultValue: param.schema.default
|
|
222
|
+
})
|
|
223
|
+
);
|
|
211
224
|
}
|
|
212
225
|
if (param.in === "query" || param.in === "header") {
|
|
213
|
-
paramList.push(
|
|
226
|
+
paramList.push(
|
|
227
|
+
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
228
|
+
);
|
|
214
229
|
}
|
|
215
230
|
}
|
|
216
231
|
return {
|
|
@@ -219,11 +234,15 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
219
234
|
};
|
|
220
235
|
}
|
|
221
236
|
function generateFunctionForOperation(method, path, operation) {
|
|
222
|
-
if (!operation)
|
|
223
|
-
return "";
|
|
237
|
+
if (!operation) return "";
|
|
224
238
|
const isFileUpload = operation.requestBody?.content["multipart/form-data"]?.schema?.$ref?.includes("Body_upload_files");
|
|
225
|
-
const parameters = generateFunctionParameters(
|
|
226
|
-
|
|
239
|
+
const parameters = generateFunctionParameters(
|
|
240
|
+
operation.parameters,
|
|
241
|
+
isFileUpload
|
|
242
|
+
);
|
|
243
|
+
const { requestBodyParam, requestBodyPayload } = generateRequestBody(
|
|
244
|
+
operation.requestBody
|
|
245
|
+
);
|
|
227
246
|
const allParams = isFileUpload ? "file: File, options?: UploadOptions & { dirPath?: string, tags?: string[] }" : combineAllParams(parameters, requestBodyParam);
|
|
228
247
|
const responseType = generateResponseType(operation.responses);
|
|
229
248
|
const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : "";
|
|
@@ -241,13 +260,13 @@ function fileTemplate(tsString, typeForImport, baseURL) {
|
|
|
241
260
|
const templateCode = `import ax from 'axios';
|
|
242
261
|
import type { AxiosResponse } from 'axios';
|
|
243
262
|
import type {${typeForImport.join(", ")}} from './types.d';
|
|
244
|
-
|
|
263
|
+
|
|
245
264
|
interface UploadOptions {
|
|
246
265
|
onUploadProgress?: (progressEvent: any) => void
|
|
247
266
|
dirPath?: string
|
|
248
267
|
tags?: string[]
|
|
249
268
|
}
|
|
250
|
-
|
|
269
|
+
|
|
251
270
|
export const axios = ax.create({baseURL:${baseURL}});
|
|
252
271
|
${tsString}`;
|
|
253
272
|
const doubleQuoteRegex = /"([^"]+)":/g;
|
|
@@ -257,13 +276,19 @@ const functionsInventory = {};
|
|
|
257
276
|
const pathOperations = [];
|
|
258
277
|
function hasConflict(path, method) {
|
|
259
278
|
const cleanPathName = path.split("/").filter((p) => p && !/\{|\}/.test(p)).join("/");
|
|
260
|
-
const matchingPaths = pathOperations.filter(
|
|
279
|
+
const matchingPaths = pathOperations.filter(
|
|
280
|
+
(p) => p.path === cleanPathName && p.method === method
|
|
281
|
+
);
|
|
261
282
|
pathOperations.push({ path: cleanPathName, method });
|
|
262
283
|
return matchingPaths.length > 0;
|
|
263
284
|
}
|
|
264
285
|
function createFunctionPlaceholder(path, method, operation) {
|
|
265
286
|
const funcID = generateRandomString();
|
|
266
|
-
functionsInventory[funcID] = generateFunctionForOperation(
|
|
287
|
+
functionsInventory[funcID] = generateFunctionForOperation(
|
|
288
|
+
method,
|
|
289
|
+
path,
|
|
290
|
+
operation
|
|
291
|
+
);
|
|
267
292
|
return funcID;
|
|
268
293
|
}
|
|
269
294
|
function handlePathSegment(path, operation, existingObj = {}) {
|
|
@@ -275,7 +300,11 @@ function handlePathSegment(path, operation, existingObj = {}) {
|
|
|
275
300
|
const params = getParamsFromPath(path);
|
|
276
301
|
functionName += params ? `By${toPascalCase(params.pop() || "")}` : "All";
|
|
277
302
|
}
|
|
278
|
-
obj[functionName] = createFunctionPlaceholder(
|
|
303
|
+
obj[functionName] = createFunctionPlaceholder(
|
|
304
|
+
path,
|
|
305
|
+
method,
|
|
306
|
+
operation[method]
|
|
307
|
+
);
|
|
279
308
|
}
|
|
280
309
|
return { ...obj, ...existingObj };
|
|
281
310
|
}
|
|
@@ -287,8 +316,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
287
316
|
const splitPath = path.split("/").filter((p) => p && !/\{|\}/.test(p));
|
|
288
317
|
splitPath.reduce((acc, key, index, array) => {
|
|
289
318
|
const objFuncKey = toCamelCase(key);
|
|
290
|
-
if (!objFuncKey)
|
|
291
|
-
return acc;
|
|
319
|
+
if (!objFuncKey) return acc;
|
|
292
320
|
const methods = Object.keys(operation);
|
|
293
321
|
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
|
|
294
322
|
const method = methods[0];
|
|
@@ -303,7 +331,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
303
331
|
}, body);
|
|
304
332
|
}
|
|
305
333
|
for (const [parent, object] of Object.entries(body)) {
|
|
306
|
-
tsString += `export const ${parent} = ${JSON.stringify(object,
|
|
334
|
+
tsString += `export const ${parent} = ${JSON.stringify(object, undefined, 2)};
|
|
307
335
|
`;
|
|
308
336
|
}
|
|
309
337
|
Object.entries(functionsInventory).forEach(([key, value]) => {
|
|
@@ -320,10 +348,9 @@ function generateTypes(schemas) {
|
|
|
320
348
|
return `export type ${typeName} = ${schema.enum.map((item) => `'${item}'`).join(" | ")};
|
|
321
349
|
`;
|
|
322
350
|
}
|
|
323
|
-
if (!schema.properties)
|
|
324
|
-
return "";
|
|
351
|
+
if (!schema.properties) return "";
|
|
325
352
|
const properties = Object.entries(schema.properties).map(([key, value]) => {
|
|
326
|
-
const varType = formatVarType(key, value);
|
|
353
|
+
const varType = formatVarType({ varName: key, schema: value });
|
|
327
354
|
return ` ${varType}`;
|
|
328
355
|
}).join(";\n ");
|
|
329
356
|
return `export type ${typeName} = {
|
|
@@ -338,12 +365,10 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
338
365
|
try {
|
|
339
366
|
const { data: openApi } = await axios__default.get(openApiUrl, { headers: basicAuthHeader });
|
|
340
367
|
const schemas = openApi.components?.schemas;
|
|
341
|
-
if (!schemas)
|
|
342
|
-
throw new Error("No schemas found in OpenAPI document");
|
|
368
|
+
if (!schemas) throw new Error("No schemas found in OpenAPI document");
|
|
343
369
|
const types = generateTypes(schemas);
|
|
344
370
|
const { paths } = openApi;
|
|
345
|
-
if (!paths)
|
|
346
|
-
throw new Error("No paths found in OpenAPI document");
|
|
371
|
+
if (!paths) throw new Error("No paths found in OpenAPI document");
|
|
347
372
|
const code = generateFunctions(paths, baseUrl);
|
|
348
373
|
return { types, code };
|
|
349
374
|
} catch (error) {
|
|
@@ -351,28 +376,21 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
351
376
|
}
|
|
352
377
|
};
|
|
353
378
|
|
|
354
|
-
var __defProp = Object.defineProperty;
|
|
355
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
356
|
-
var __publicField = (obj, key, value) => {
|
|
357
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
358
|
-
return value;
|
|
359
|
-
};
|
|
360
379
|
const axios = axios__default.create({
|
|
361
380
|
withCredentials: true
|
|
362
381
|
});
|
|
363
382
|
class DataRequest {
|
|
383
|
+
data_table;
|
|
384
|
+
bagel;
|
|
385
|
+
itemID;
|
|
386
|
+
_filter = {};
|
|
364
387
|
constructor(table, bagel) {
|
|
365
|
-
__publicField(this, "data_table");
|
|
366
|
-
__publicField(this, "bagel");
|
|
367
|
-
__publicField(this, "itemID");
|
|
368
|
-
__publicField(this, "_filter", {});
|
|
369
388
|
this.data_table = table;
|
|
370
389
|
this.bagel = bagel;
|
|
371
390
|
this.itemID = "";
|
|
372
391
|
}
|
|
373
392
|
async post(item) {
|
|
374
|
-
if (!this.data_table)
|
|
375
|
-
throw new Error("Data table not set");
|
|
393
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
376
394
|
const { data } = await axios.post(`/data/${this.data_table}`, item);
|
|
377
395
|
return data;
|
|
378
396
|
}
|
|
@@ -381,8 +399,7 @@ class DataRequest {
|
|
|
381
399
|
return this;
|
|
382
400
|
}
|
|
383
401
|
async get() {
|
|
384
|
-
if (!this.data_table)
|
|
385
|
-
throw new Error("Data table not set");
|
|
402
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
386
403
|
const filterStr = Object.keys(this._filter).length > 0 ? `?filter={${Object.entries(this._filter).map(([k, v]) => `${k}:${v}`).join(",")}}` : "";
|
|
387
404
|
const url = `/data/${this.data_table}${this.itemID ? `/${this.itemID}` : ""}${filterStr}`;
|
|
388
405
|
try {
|
|
@@ -391,7 +408,7 @@ class DataRequest {
|
|
|
391
408
|
} catch (err) {
|
|
392
409
|
console.log(err);
|
|
393
410
|
this.bagel.onError?.(err);
|
|
394
|
-
return
|
|
411
|
+
return undefined;
|
|
395
412
|
}
|
|
396
413
|
}
|
|
397
414
|
item(id) {
|
|
@@ -399,8 +416,7 @@ class DataRequest {
|
|
|
399
416
|
return this;
|
|
400
417
|
}
|
|
401
418
|
async delete() {
|
|
402
|
-
if (!this.data_table)
|
|
403
|
-
throw new Error("Data table not set");
|
|
419
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
404
420
|
const { data } = await axios.delete(
|
|
405
421
|
`/data/${this.data_table}/${this.itemID}`
|
|
406
422
|
);
|
|
@@ -408,10 +424,8 @@ class DataRequest {
|
|
|
408
424
|
}
|
|
409
425
|
async put(updatedItem) {
|
|
410
426
|
const { data_table, itemID } = this;
|
|
411
|
-
if (!data_table)
|
|
412
|
-
|
|
413
|
-
if (!itemID)
|
|
414
|
-
throw new Error("Item ID not set");
|
|
427
|
+
if (!data_table) throw new Error("Data table not set");
|
|
428
|
+
if (!itemID) throw new Error("Item ID not set");
|
|
415
429
|
const { data } = await axios.put(
|
|
416
430
|
`/data/${data_table}/${itemID}`,
|
|
417
431
|
updatedItem
|
|
@@ -429,9 +443,9 @@ function responses(key) {
|
|
|
429
443
|
class BagelAuth {
|
|
430
444
|
constructor(bagel) {
|
|
431
445
|
this.bagel = bagel;
|
|
432
|
-
__publicField(this, "user");
|
|
433
446
|
this.bagel = bagel;
|
|
434
447
|
}
|
|
448
|
+
user = undefined;
|
|
435
449
|
async validateUser() {
|
|
436
450
|
try {
|
|
437
451
|
const { data: usr } = await axios.get("/users/me", {
|
|
@@ -479,7 +493,7 @@ class BagelAuth {
|
|
|
479
493
|
this.bagel.onError?.(err);
|
|
480
494
|
console.log(err);
|
|
481
495
|
}
|
|
482
|
-
this.user =
|
|
496
|
+
this.user = undefined;
|
|
483
497
|
}
|
|
484
498
|
async acceptInvite(token, user) {
|
|
485
499
|
await axios.post(`/auth/accept-invite/${token}`, user);
|
|
@@ -497,12 +511,10 @@ class BagelAuth {
|
|
|
497
511
|
}
|
|
498
512
|
}
|
|
499
513
|
class Bagel {
|
|
514
|
+
host;
|
|
515
|
+
fileBaseUrl;
|
|
516
|
+
onError;
|
|
500
517
|
constructor({ host, fileBaseUrl, onError }) {
|
|
501
|
-
__publicField(this, "host");
|
|
502
|
-
__publicField(this, "fileBaseUrl");
|
|
503
|
-
__publicField(this, "onError");
|
|
504
|
-
__publicField(this, "read_table");
|
|
505
|
-
__publicField(this, "auth", new BagelAuth(this));
|
|
506
518
|
this.host = host?.replace(/\/$/, "");
|
|
507
519
|
this.fileBaseUrl = fileBaseUrl?.replace(/\/$/, "");
|
|
508
520
|
if (!this.host) {
|
|
@@ -511,9 +523,11 @@ class Bagel {
|
|
|
511
523
|
axios.defaults.baseURL = this.host;
|
|
512
524
|
this.onError = onError;
|
|
513
525
|
}
|
|
526
|
+
read_table = undefined;
|
|
514
527
|
data(table) {
|
|
515
528
|
return new DataRequest(table, this);
|
|
516
529
|
}
|
|
530
|
+
auth = new BagelAuth(this);
|
|
517
531
|
_endpointCleaner(endpoint) {
|
|
518
532
|
const url = `${endpoint.replace(/^\//, "").replaceAll(/\/$/g, "")}`;
|
|
519
533
|
return url;
|
|
@@ -528,12 +542,10 @@ class Bagel {
|
|
|
528
542
|
async get(endpoint, query) {
|
|
529
543
|
this._setAuthorization();
|
|
530
544
|
endpoint = this._endpointCleaner(endpoint);
|
|
531
|
-
if (/undefined|null/.test(endpoint))
|
|
532
|
-
throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
545
|
+
if (/undefined|null/.test(endpoint)) throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
533
546
|
if (query) {
|
|
534
547
|
const queryParams = Object.entries(query).filter(([_, value]) => !!value).map(([key, value]) => `${key}=${value}`).join("&");
|
|
535
|
-
if (queryParams)
|
|
536
|
-
endpoint = `${endpoint}?${queryParams}`;
|
|
548
|
+
if (queryParams) endpoint = `${endpoint}?${queryParams}`;
|
|
537
549
|
}
|
|
538
550
|
const url = `/${endpoint}`;
|
|
539
551
|
return axios.get(url).then(({ data }) => data).catch((err) => {
|
|
@@ -583,8 +595,7 @@ class Bagel {
|
|
|
583
595
|
const formData = new FormData();
|
|
584
596
|
formData.append("file", file);
|
|
585
597
|
let url = "/static_files/upload";
|
|
586
|
-
if (options?.topic)
|
|
587
|
-
url = `/static_files/upload?topic=${options.topic}`;
|
|
598
|
+
if (options?.topic) url = `/static_files/upload?topic=${options.topic}`;
|
|
588
599
|
const { data } = await axios.post(url, formData, {
|
|
589
600
|
headers: {
|
|
590
601
|
"Content-Type": "multipart/form-data"
|
package/dist/index.mjs
CHANGED
|
@@ -8,23 +8,19 @@ function formatType(typeName) {
|
|
|
8
8
|
}
|
|
9
9
|
function resolveReference(ref) {
|
|
10
10
|
const t = ref.split("/").pop();
|
|
11
|
-
if (!t)
|
|
12
|
-
return "any";
|
|
11
|
+
if (!t) return "any";
|
|
13
12
|
return formatType(t);
|
|
14
13
|
}
|
|
15
14
|
function schemaToType(schema) {
|
|
16
|
-
if (!schema)
|
|
17
|
-
return "any";
|
|
15
|
+
if (!schema) return "any";
|
|
18
16
|
if (schema.anyOf) {
|
|
19
17
|
let _t = schema.anyOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" | ");
|
|
20
|
-
if (_t === "" || _t === "null")
|
|
21
|
-
_t = "any";
|
|
18
|
+
if (_t === "" || _t === "null") _t = "any";
|
|
22
19
|
return _t;
|
|
23
20
|
}
|
|
24
21
|
if (schema.allOf)
|
|
25
22
|
return schema.allOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" & ");
|
|
26
|
-
if (schema.$ref)
|
|
27
|
-
return resolveReference(schema.$ref);
|
|
23
|
+
if (schema.$ref) return resolveReference(schema.$ref);
|
|
28
24
|
switch (schema.type) {
|
|
29
25
|
case "object":
|
|
30
26
|
return "{ [key: string]: any }";
|
|
@@ -42,7 +38,7 @@ function schemaToType(schema) {
|
|
|
42
38
|
return "undefined";
|
|
43
39
|
case "null":
|
|
44
40
|
return "null";
|
|
45
|
-
case
|
|
41
|
+
case undefined:
|
|
46
42
|
return "any";
|
|
47
43
|
default:
|
|
48
44
|
console.log("Unknown type", schema.type);
|
|
@@ -54,10 +50,16 @@ function isOptional(schema) {
|
|
|
54
50
|
const splitType = type.split(/\s+\|\s+/);
|
|
55
51
|
const includesNull = splitType.includes("null");
|
|
56
52
|
const includesUndefined = splitType.includes("undefined");
|
|
57
|
-
return includesNull || includesUndefined || schema.default !==
|
|
53
|
+
return includesNull || includesUndefined || schema.default !== undefined;
|
|
58
54
|
}
|
|
59
55
|
const cleanOptionals = (str) => str.split(" | ").filter((t) => t !== "null" && t !== "undefined").join(" | ");
|
|
60
|
-
function formatVarType(
|
|
56
|
+
function formatVarType({
|
|
57
|
+
varName,
|
|
58
|
+
schema,
|
|
59
|
+
required = false,
|
|
60
|
+
defaultValue
|
|
61
|
+
}) {
|
|
62
|
+
if (varName === "personId") console.log({ varName, schema, required, defaultValue });
|
|
61
63
|
let type = schemaToType(schema);
|
|
62
64
|
type = cleanOptionals(type);
|
|
63
65
|
let defaultStr = "";
|
|
@@ -68,9 +70,8 @@ function formatVarType(varName, schema, required = false, defaultValue) {
|
|
|
68
70
|
defaultStr = ` = ${defaultValue}`;
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
|
-
let optionalStr = required
|
|
72
|
-
if (defaultStr)
|
|
73
|
-
optionalStr = "";
|
|
73
|
+
let optionalStr = !required && isOptional(schema) ? "?" : "";
|
|
74
|
+
if (defaultStr) optionalStr = "";
|
|
74
75
|
return `${varName}${optionalStr}: ${type}${defaultStr}`;
|
|
75
76
|
}
|
|
76
77
|
function cleanPath(path) {
|
|
@@ -78,35 +79,39 @@ function cleanPath(path) {
|
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
const allTypes = [];
|
|
81
|
-
const primitiveTypes = [
|
|
82
|
+
const primitiveTypes = [
|
|
83
|
+
"string",
|
|
84
|
+
"number",
|
|
85
|
+
"boolean",
|
|
86
|
+
"null",
|
|
87
|
+
"void",
|
|
88
|
+
"any",
|
|
89
|
+
"Record<string, any>",
|
|
90
|
+
"undefined",
|
|
91
|
+
"{ [key: string]: any }"
|
|
92
|
+
];
|
|
82
93
|
function collectTypeForImportStatement(typeName) {
|
|
83
94
|
typeName = typeName.trim().replace("[]", "");
|
|
84
95
|
if (typeName.includes("|")) {
|
|
85
|
-
typeName.split("|").forEach(
|
|
86
|
-
(singleType)
|
|
87
|
-
|
|
88
|
-
}
|
|
89
|
-
);
|
|
96
|
+
typeName.split("|").forEach((singleType) => {
|
|
97
|
+
collectTypeForImportStatement(singleType);
|
|
98
|
+
});
|
|
90
99
|
return;
|
|
91
100
|
}
|
|
92
101
|
const isPrimitive = primitiveTypes.includes(typeName);
|
|
93
102
|
typeName = formatType(typeName);
|
|
94
|
-
if (!typeName || isPrimitive)
|
|
95
|
-
|
|
96
|
-
if (!allTypes.includes(typeName))
|
|
97
|
-
allTypes.push(typeName);
|
|
103
|
+
if (!typeName || isPrimitive) return;
|
|
104
|
+
if (!allTypes.includes(typeName)) allTypes.push(typeName);
|
|
98
105
|
}
|
|
99
106
|
function getResponseType(response) {
|
|
100
107
|
const mediaTypeObject = response.content?.["application/json"];
|
|
101
|
-
if (!mediaTypeObject || !mediaTypeObject.schema)
|
|
102
|
-
return;
|
|
108
|
+
if (!mediaTypeObject || !mediaTypeObject.schema) return;
|
|
103
109
|
const responseType = schemaToType(mediaTypeObject.schema);
|
|
104
110
|
collectTypeForImportStatement(responseType);
|
|
105
111
|
return responseType;
|
|
106
112
|
}
|
|
107
113
|
function generateResponseType(responses) {
|
|
108
|
-
if (!responses)
|
|
109
|
-
return "";
|
|
114
|
+
if (!responses) return "";
|
|
110
115
|
const types = [];
|
|
111
116
|
for (const [statusCode, response] of Object.entries(responses)) {
|
|
112
117
|
if (statusCode.startsWith("2")) {
|
|
@@ -119,8 +124,7 @@ function generateResponseType(responses) {
|
|
|
119
124
|
return types.join(" | ");
|
|
120
125
|
}
|
|
121
126
|
function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
|
|
122
|
-
if (allParams === "undefined")
|
|
123
|
-
allParams = "";
|
|
127
|
+
if (allParams === "undefined") allParams = "";
|
|
124
128
|
let axiosFunction = `async (${allParams})${responseTypeStr} => {`;
|
|
125
129
|
if (requestBodyPayload === "formData") {
|
|
126
130
|
const paramStr = parameters?.config?.params ? `params: {${parameters.config.params}}` : "";
|
|
@@ -169,21 +173,23 @@ function generateRequestBody(requestBody) {
|
|
|
169
173
|
const requestBodyType = schemaToType(bodySchema);
|
|
170
174
|
collectTypeForImportStatement(requestBodyType);
|
|
171
175
|
const requestBodyPayload = toCamelCase(bodySchema.title) || toCamelCase(requestBodyType) || "requestBody";
|
|
172
|
-
const requestBodyParam = formatVarType(
|
|
176
|
+
const requestBodyParam = formatVarType({
|
|
177
|
+
varName: requestBodyPayload,
|
|
178
|
+
schema: bodySchema,
|
|
179
|
+
defaultValue: bodySchema.default
|
|
180
|
+
});
|
|
173
181
|
return { requestBodyParam, requestBodyPayload };
|
|
174
182
|
}
|
|
175
183
|
function combineAllParams(parameters, requestBodyParam) {
|
|
176
184
|
let allParamsArray = [];
|
|
177
185
|
if (parameters && parameters.params)
|
|
178
186
|
allParamsArray = parameters.params.split(",").map((p) => p.trim());
|
|
179
|
-
if (requestBodyParam)
|
|
180
|
-
allParamsArray.push(requestBodyParam.trim());
|
|
187
|
+
if (requestBodyParam) allParamsArray.push(requestBodyParam.trim());
|
|
181
188
|
allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
|
|
182
189
|
return allParamsArray.join(", ");
|
|
183
190
|
}
|
|
184
191
|
function generateFunctionParameters(params, isFileUpload = false) {
|
|
185
|
-
if (!params?.length)
|
|
186
|
-
return {};
|
|
192
|
+
if (!params?.length) return {};
|
|
187
193
|
if (isFileUpload) {
|
|
188
194
|
return {
|
|
189
195
|
config: {
|
|
@@ -201,10 +207,19 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
201
207
|
const paramName = param.name;
|
|
202
208
|
const varName = toCamelCase(param.name);
|
|
203
209
|
if (param.in === "path" || param.in === "query" || param.in === "header") {
|
|
204
|
-
functionParams.push(
|
|
210
|
+
functionParams.push(
|
|
211
|
+
formatVarType({
|
|
212
|
+
varName,
|
|
213
|
+
schema: param.schema,
|
|
214
|
+
required: param.required,
|
|
215
|
+
defaultValue: param.schema.default
|
|
216
|
+
})
|
|
217
|
+
);
|
|
205
218
|
}
|
|
206
219
|
if (param.in === "query" || param.in === "header") {
|
|
207
|
-
paramList.push(
|
|
220
|
+
paramList.push(
|
|
221
|
+
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
222
|
+
);
|
|
208
223
|
}
|
|
209
224
|
}
|
|
210
225
|
return {
|
|
@@ -213,11 +228,15 @@ function generateFunctionParameters(params, isFileUpload = false) {
|
|
|
213
228
|
};
|
|
214
229
|
}
|
|
215
230
|
function generateFunctionForOperation(method, path, operation) {
|
|
216
|
-
if (!operation)
|
|
217
|
-
return "";
|
|
231
|
+
if (!operation) return "";
|
|
218
232
|
const isFileUpload = operation.requestBody?.content["multipart/form-data"]?.schema?.$ref?.includes("Body_upload_files");
|
|
219
|
-
const parameters = generateFunctionParameters(
|
|
220
|
-
|
|
233
|
+
const parameters = generateFunctionParameters(
|
|
234
|
+
operation.parameters,
|
|
235
|
+
isFileUpload
|
|
236
|
+
);
|
|
237
|
+
const { requestBodyParam, requestBodyPayload } = generateRequestBody(
|
|
238
|
+
operation.requestBody
|
|
239
|
+
);
|
|
221
240
|
const allParams = isFileUpload ? "file: File, options?: UploadOptions & { dirPath?: string, tags?: string[] }" : combineAllParams(parameters, requestBodyParam);
|
|
222
241
|
const responseType = generateResponseType(operation.responses);
|
|
223
242
|
const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : "";
|
|
@@ -235,13 +254,13 @@ function fileTemplate(tsString, typeForImport, baseURL) {
|
|
|
235
254
|
const templateCode = `import ax from 'axios';
|
|
236
255
|
import type { AxiosResponse } from 'axios';
|
|
237
256
|
import type {${typeForImport.join(", ")}} from './types.d';
|
|
238
|
-
|
|
257
|
+
|
|
239
258
|
interface UploadOptions {
|
|
240
259
|
onUploadProgress?: (progressEvent: any) => void
|
|
241
260
|
dirPath?: string
|
|
242
261
|
tags?: string[]
|
|
243
262
|
}
|
|
244
|
-
|
|
263
|
+
|
|
245
264
|
export const axios = ax.create({baseURL:${baseURL}});
|
|
246
265
|
${tsString}`;
|
|
247
266
|
const doubleQuoteRegex = /"([^"]+)":/g;
|
|
@@ -251,13 +270,19 @@ const functionsInventory = {};
|
|
|
251
270
|
const pathOperations = [];
|
|
252
271
|
function hasConflict(path, method) {
|
|
253
272
|
const cleanPathName = path.split("/").filter((p) => p && !/\{|\}/.test(p)).join("/");
|
|
254
|
-
const matchingPaths = pathOperations.filter(
|
|
273
|
+
const matchingPaths = pathOperations.filter(
|
|
274
|
+
(p) => p.path === cleanPathName && p.method === method
|
|
275
|
+
);
|
|
255
276
|
pathOperations.push({ path: cleanPathName, method });
|
|
256
277
|
return matchingPaths.length > 0;
|
|
257
278
|
}
|
|
258
279
|
function createFunctionPlaceholder(path, method, operation) {
|
|
259
280
|
const funcID = generateRandomString();
|
|
260
|
-
functionsInventory[funcID] = generateFunctionForOperation(
|
|
281
|
+
functionsInventory[funcID] = generateFunctionForOperation(
|
|
282
|
+
method,
|
|
283
|
+
path,
|
|
284
|
+
operation
|
|
285
|
+
);
|
|
261
286
|
return funcID;
|
|
262
287
|
}
|
|
263
288
|
function handlePathSegment(path, operation, existingObj = {}) {
|
|
@@ -269,7 +294,11 @@ function handlePathSegment(path, operation, existingObj = {}) {
|
|
|
269
294
|
const params = getParamsFromPath(path);
|
|
270
295
|
functionName += params ? `By${toPascalCase(params.pop() || "")}` : "All";
|
|
271
296
|
}
|
|
272
|
-
obj[functionName] = createFunctionPlaceholder(
|
|
297
|
+
obj[functionName] = createFunctionPlaceholder(
|
|
298
|
+
path,
|
|
299
|
+
method,
|
|
300
|
+
operation[method]
|
|
301
|
+
);
|
|
273
302
|
}
|
|
274
303
|
return { ...obj, ...existingObj };
|
|
275
304
|
}
|
|
@@ -281,8 +310,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
281
310
|
const splitPath = path.split("/").filter((p) => p && !/\{|\}/.test(p));
|
|
282
311
|
splitPath.reduce((acc, key, index, array) => {
|
|
283
312
|
const objFuncKey = toCamelCase(key);
|
|
284
|
-
if (!objFuncKey)
|
|
285
|
-
return acc;
|
|
313
|
+
if (!objFuncKey) return acc;
|
|
286
314
|
const methods = Object.keys(operation);
|
|
287
315
|
if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
|
|
288
316
|
const method = methods[0];
|
|
@@ -297,7 +325,7 @@ function generateFunctions(paths, baseUrl) {
|
|
|
297
325
|
}, body);
|
|
298
326
|
}
|
|
299
327
|
for (const [parent, object] of Object.entries(body)) {
|
|
300
|
-
tsString += `export const ${parent} = ${JSON.stringify(object,
|
|
328
|
+
tsString += `export const ${parent} = ${JSON.stringify(object, undefined, 2)};
|
|
301
329
|
`;
|
|
302
330
|
}
|
|
303
331
|
Object.entries(functionsInventory).forEach(([key, value]) => {
|
|
@@ -314,10 +342,9 @@ function generateTypes(schemas) {
|
|
|
314
342
|
return `export type ${typeName} = ${schema.enum.map((item) => `'${item}'`).join(" | ")};
|
|
315
343
|
`;
|
|
316
344
|
}
|
|
317
|
-
if (!schema.properties)
|
|
318
|
-
return "";
|
|
345
|
+
if (!schema.properties) return "";
|
|
319
346
|
const properties = Object.entries(schema.properties).map(([key, value]) => {
|
|
320
|
-
const varType = formatVarType(key, value);
|
|
347
|
+
const varType = formatVarType({ varName: key, schema: value });
|
|
321
348
|
return ` ${varType}`;
|
|
322
349
|
}).join(";\n ");
|
|
323
350
|
return `export type ${typeName} = {
|
|
@@ -332,12 +359,10 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
332
359
|
try {
|
|
333
360
|
const { data: openApi } = await axios$1.get(openApiUrl, { headers: basicAuthHeader });
|
|
334
361
|
const schemas = openApi.components?.schemas;
|
|
335
|
-
if (!schemas)
|
|
336
|
-
throw new Error("No schemas found in OpenAPI document");
|
|
362
|
+
if (!schemas) throw new Error("No schemas found in OpenAPI document");
|
|
337
363
|
const types = generateTypes(schemas);
|
|
338
364
|
const { paths } = openApi;
|
|
339
|
-
if (!paths)
|
|
340
|
-
throw new Error("No paths found in OpenAPI document");
|
|
365
|
+
if (!paths) throw new Error("No paths found in OpenAPI document");
|
|
341
366
|
const code = generateFunctions(paths, baseUrl);
|
|
342
367
|
return { types, code };
|
|
343
368
|
} catch (error) {
|
|
@@ -345,28 +370,21 @@ const index = async (openApiUrl, baseUrl) => {
|
|
|
345
370
|
}
|
|
346
371
|
};
|
|
347
372
|
|
|
348
|
-
var __defProp = Object.defineProperty;
|
|
349
|
-
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
350
|
-
var __publicField = (obj, key, value) => {
|
|
351
|
-
__defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
|
|
352
|
-
return value;
|
|
353
|
-
};
|
|
354
373
|
const axios = axios$1.create({
|
|
355
374
|
withCredentials: true
|
|
356
375
|
});
|
|
357
376
|
class DataRequest {
|
|
377
|
+
data_table;
|
|
378
|
+
bagel;
|
|
379
|
+
itemID;
|
|
380
|
+
_filter = {};
|
|
358
381
|
constructor(table, bagel) {
|
|
359
|
-
__publicField(this, "data_table");
|
|
360
|
-
__publicField(this, "bagel");
|
|
361
|
-
__publicField(this, "itemID");
|
|
362
|
-
__publicField(this, "_filter", {});
|
|
363
382
|
this.data_table = table;
|
|
364
383
|
this.bagel = bagel;
|
|
365
384
|
this.itemID = "";
|
|
366
385
|
}
|
|
367
386
|
async post(item) {
|
|
368
|
-
if (!this.data_table)
|
|
369
|
-
throw new Error("Data table not set");
|
|
387
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
370
388
|
const { data } = await axios.post(`/data/${this.data_table}`, item);
|
|
371
389
|
return data;
|
|
372
390
|
}
|
|
@@ -375,8 +393,7 @@ class DataRequest {
|
|
|
375
393
|
return this;
|
|
376
394
|
}
|
|
377
395
|
async get() {
|
|
378
|
-
if (!this.data_table)
|
|
379
|
-
throw new Error("Data table not set");
|
|
396
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
380
397
|
const filterStr = Object.keys(this._filter).length > 0 ? `?filter={${Object.entries(this._filter).map(([k, v]) => `${k}:${v}`).join(",")}}` : "";
|
|
381
398
|
const url = `/data/${this.data_table}${this.itemID ? `/${this.itemID}` : ""}${filterStr}`;
|
|
382
399
|
try {
|
|
@@ -385,7 +402,7 @@ class DataRequest {
|
|
|
385
402
|
} catch (err) {
|
|
386
403
|
console.log(err);
|
|
387
404
|
this.bagel.onError?.(err);
|
|
388
|
-
return
|
|
405
|
+
return undefined;
|
|
389
406
|
}
|
|
390
407
|
}
|
|
391
408
|
item(id) {
|
|
@@ -393,8 +410,7 @@ class DataRequest {
|
|
|
393
410
|
return this;
|
|
394
411
|
}
|
|
395
412
|
async delete() {
|
|
396
|
-
if (!this.data_table)
|
|
397
|
-
throw new Error("Data table not set");
|
|
413
|
+
if (!this.data_table) throw new Error("Data table not set");
|
|
398
414
|
const { data } = await axios.delete(
|
|
399
415
|
`/data/${this.data_table}/${this.itemID}`
|
|
400
416
|
);
|
|
@@ -402,10 +418,8 @@ class DataRequest {
|
|
|
402
418
|
}
|
|
403
419
|
async put(updatedItem) {
|
|
404
420
|
const { data_table, itemID } = this;
|
|
405
|
-
if (!data_table)
|
|
406
|
-
|
|
407
|
-
if (!itemID)
|
|
408
|
-
throw new Error("Item ID not set");
|
|
421
|
+
if (!data_table) throw new Error("Data table not set");
|
|
422
|
+
if (!itemID) throw new Error("Item ID not set");
|
|
409
423
|
const { data } = await axios.put(
|
|
410
424
|
`/data/${data_table}/${itemID}`,
|
|
411
425
|
updatedItem
|
|
@@ -423,9 +437,9 @@ function responses(key) {
|
|
|
423
437
|
class BagelAuth {
|
|
424
438
|
constructor(bagel) {
|
|
425
439
|
this.bagel = bagel;
|
|
426
|
-
__publicField(this, "user");
|
|
427
440
|
this.bagel = bagel;
|
|
428
441
|
}
|
|
442
|
+
user = undefined;
|
|
429
443
|
async validateUser() {
|
|
430
444
|
try {
|
|
431
445
|
const { data: usr } = await axios.get("/users/me", {
|
|
@@ -473,7 +487,7 @@ class BagelAuth {
|
|
|
473
487
|
this.bagel.onError?.(err);
|
|
474
488
|
console.log(err);
|
|
475
489
|
}
|
|
476
|
-
this.user =
|
|
490
|
+
this.user = undefined;
|
|
477
491
|
}
|
|
478
492
|
async acceptInvite(token, user) {
|
|
479
493
|
await axios.post(`/auth/accept-invite/${token}`, user);
|
|
@@ -491,12 +505,10 @@ class BagelAuth {
|
|
|
491
505
|
}
|
|
492
506
|
}
|
|
493
507
|
class Bagel {
|
|
508
|
+
host;
|
|
509
|
+
fileBaseUrl;
|
|
510
|
+
onError;
|
|
494
511
|
constructor({ host, fileBaseUrl, onError }) {
|
|
495
|
-
__publicField(this, "host");
|
|
496
|
-
__publicField(this, "fileBaseUrl");
|
|
497
|
-
__publicField(this, "onError");
|
|
498
|
-
__publicField(this, "read_table");
|
|
499
|
-
__publicField(this, "auth", new BagelAuth(this));
|
|
500
512
|
this.host = host?.replace(/\/$/, "");
|
|
501
513
|
this.fileBaseUrl = fileBaseUrl?.replace(/\/$/, "");
|
|
502
514
|
if (!this.host) {
|
|
@@ -505,9 +517,11 @@ class Bagel {
|
|
|
505
517
|
axios.defaults.baseURL = this.host;
|
|
506
518
|
this.onError = onError;
|
|
507
519
|
}
|
|
520
|
+
read_table = undefined;
|
|
508
521
|
data(table) {
|
|
509
522
|
return new DataRequest(table, this);
|
|
510
523
|
}
|
|
524
|
+
auth = new BagelAuth(this);
|
|
511
525
|
_endpointCleaner(endpoint) {
|
|
512
526
|
const url = `${endpoint.replace(/^\//, "").replaceAll(/\/$/g, "")}`;
|
|
513
527
|
return url;
|
|
@@ -522,12 +536,10 @@ class Bagel {
|
|
|
522
536
|
async get(endpoint, query) {
|
|
523
537
|
this._setAuthorization();
|
|
524
538
|
endpoint = this._endpointCleaner(endpoint);
|
|
525
|
-
if (/undefined|null/.test(endpoint))
|
|
526
|
-
throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
539
|
+
if (/undefined|null/.test(endpoint)) throw new Error(`Invalid endpoint: ${endpoint}`);
|
|
527
540
|
if (query) {
|
|
528
541
|
const queryParams = Object.entries(query).filter(([_, value]) => !!value).map(([key, value]) => `${key}=${value}`).join("&");
|
|
529
|
-
if (queryParams)
|
|
530
|
-
endpoint = `${endpoint}?${queryParams}`;
|
|
542
|
+
if (queryParams) endpoint = `${endpoint}?${queryParams}`;
|
|
531
543
|
}
|
|
532
544
|
const url = `/${endpoint}`;
|
|
533
545
|
return axios.get(url).then(({ data }) => data).catch((err) => {
|
|
@@ -577,8 +589,7 @@ class Bagel {
|
|
|
577
589
|
const formData = new FormData();
|
|
578
590
|
formData.append("file", file);
|
|
579
591
|
let url = "/static_files/upload";
|
|
580
|
-
if (options?.topic)
|
|
581
|
-
url = `/static_files/upload?topic=${options.topic}`;
|
|
592
|
+
if (options?.topic) url = `/static_files/upload?topic=${options.topic}`;
|
|
582
593
|
const { data } = await axios.post(url, formData, {
|
|
583
594
|
headers: {
|
|
584
595
|
"Content-Type": "multipart/form-data"
|
package/package.json
CHANGED
|
@@ -18,14 +18,24 @@ import {
|
|
|
18
18
|
|
|
19
19
|
const allTypes: string[] = []
|
|
20
20
|
|
|
21
|
-
const primitiveTypes = [
|
|
21
|
+
const primitiveTypes = [
|
|
22
|
+
'string',
|
|
23
|
+
'number',
|
|
24
|
+
'boolean',
|
|
25
|
+
'null',
|
|
26
|
+
'void',
|
|
27
|
+
'any',
|
|
28
|
+
'Record<string, any>',
|
|
29
|
+
'undefined',
|
|
30
|
+
'{ [key: string]: any }',
|
|
31
|
+
]
|
|
22
32
|
|
|
23
33
|
function collectTypeForImportStatement(typeName: string) {
|
|
24
34
|
typeName = typeName.trim().replace('[]', '')
|
|
25
35
|
if (typeName.includes('|')) {
|
|
26
|
-
typeName.split('|').forEach(
|
|
27
|
-
|
|
28
|
-
)
|
|
36
|
+
typeName.split('|').forEach(singleType => {
|
|
37
|
+
collectTypeForImportStatement(singleType)
|
|
38
|
+
})
|
|
29
39
|
return
|
|
30
40
|
}
|
|
31
41
|
const isPrimitive = primitiveTypes.includes(typeName)
|
|
@@ -73,7 +83,7 @@ function generateAxiosFunction(
|
|
|
73
83
|
allParams: string,
|
|
74
84
|
responseTypeStr: string,
|
|
75
85
|
parameters: any,
|
|
76
|
-
requestBodyPayload: string
|
|
86
|
+
requestBodyPayload: string
|
|
77
87
|
): string {
|
|
78
88
|
if (allParams === 'undefined') allParams = ''
|
|
79
89
|
|
|
@@ -92,7 +102,9 @@ function generateAxiosFunction(
|
|
|
92
102
|
onUploadProgress: options?.onUploadProgress${paramStr ? `,\n ${paramStr}` : ''}
|
|
93
103
|
})`
|
|
94
104
|
} else {
|
|
95
|
-
const paramStr = parameters?.config?.params
|
|
105
|
+
const paramStr = parameters?.config?.params
|
|
106
|
+
? `, { params: {${parameters.config.params}} }`
|
|
107
|
+
: ''
|
|
96
108
|
const bodyVar = requestBodyPayload ? `${requestBodyPayload}` : '{}'
|
|
97
109
|
axiosFunction += `return axios.${method}(${formattedPath}${['get', 'delete'].includes(method) ? paramStr : `, ${bodyVar}${paramStr}`})`
|
|
98
110
|
}
|
|
@@ -110,19 +122,25 @@ function getParamsFromPath(path: string) {
|
|
|
110
122
|
|
|
111
123
|
function formatPathWithParams(path: string) {
|
|
112
124
|
const params = getParamsFromPath(path)
|
|
113
|
-
const formattedPath = params
|
|
125
|
+
const formattedPath = params
|
|
126
|
+
? `\`${path.replace(pathParamRegex, v => `$${toCamelCase(v)}`)}\``
|
|
127
|
+
: `'${path}'`
|
|
114
128
|
return formattedPath
|
|
115
129
|
}
|
|
116
130
|
|
|
117
|
-
function generateRequestBody(requestBody?: RequestBodyObject): {
|
|
118
|
-
|
|
131
|
+
function generateRequestBody(requestBody?: RequestBodyObject): {
|
|
132
|
+
[key: string]: string
|
|
133
|
+
} {
|
|
134
|
+
if (!requestBody?.content)
|
|
135
|
+
return { requestBodyParam: '', requestBodyPayload: '' }
|
|
119
136
|
|
|
120
137
|
const { content } = requestBody
|
|
121
138
|
const multipartFormData = content['multipart/form-data'] || {}
|
|
122
139
|
if (multipartFormData.schema?.$ref?.includes('Body_upload_files')) {
|
|
123
140
|
return {
|
|
124
|
-
requestBodyParam:
|
|
125
|
-
|
|
141
|
+
requestBodyParam:
|
|
142
|
+
'file: File, options?: UploadOptions & { dirPath?: string, tags?: string[] }',
|
|
143
|
+
requestBodyPayload: 'formData',
|
|
126
144
|
}
|
|
127
145
|
}
|
|
128
146
|
|
|
@@ -135,8 +153,16 @@ function generateRequestBody(requestBody?: RequestBodyObject): { [key: string]:
|
|
|
135
153
|
const bodySchema = jsonContent.schema
|
|
136
154
|
const requestBodyType = schemaToType(bodySchema)
|
|
137
155
|
collectTypeForImportStatement(requestBodyType)
|
|
138
|
-
const requestBodyPayload =
|
|
139
|
-
|
|
156
|
+
const requestBodyPayload =
|
|
157
|
+
toCamelCase(bodySchema.title) ||
|
|
158
|
+
toCamelCase(requestBodyType) ||
|
|
159
|
+
'requestBody'
|
|
160
|
+
|
|
161
|
+
const requestBodyParam = formatVarType({
|
|
162
|
+
varName: requestBodyPayload,
|
|
163
|
+
schema: bodySchema,
|
|
164
|
+
defaultValue: bodySchema.default,
|
|
165
|
+
})
|
|
140
166
|
return { requestBodyParam, requestBodyPayload }
|
|
141
167
|
}
|
|
142
168
|
|
|
@@ -146,9 +172,13 @@ function generateRequestBody(requestBody?: RequestBodyObject): { [key: string]:
|
|
|
146
172
|
* @param requestBodyParam - The parameter representing the request body.
|
|
147
173
|
* @returns A string representing all combined parameters.
|
|
148
174
|
*/
|
|
149
|
-
function combineAllParams(
|
|
175
|
+
function combineAllParams(
|
|
176
|
+
parameters: { params?: string },
|
|
177
|
+
requestBodyParam: string
|
|
178
|
+
): string {
|
|
150
179
|
let allParamsArray: string[] = []
|
|
151
|
-
if (parameters && parameters.params)
|
|
180
|
+
if (parameters && parameters.params)
|
|
181
|
+
allParamsArray = parameters.params.split(',').map(p => p.trim())
|
|
152
182
|
if (requestBodyParam) allParamsArray.push(requestBodyParam.trim())
|
|
153
183
|
|
|
154
184
|
allParamsArray = allParamsArray
|
|
@@ -158,7 +188,10 @@ function combineAllParams(parameters: { params?: string }, requestBodyParam: str
|
|
|
158
188
|
return allParamsArray.join(', ')
|
|
159
189
|
}
|
|
160
190
|
|
|
161
|
-
function generateFunctionParameters(
|
|
191
|
+
function generateFunctionParameters(
|
|
192
|
+
params?: ParameterObject[],
|
|
193
|
+
isFileUpload = false
|
|
194
|
+
) {
|
|
162
195
|
if (!params?.length) return {}
|
|
163
196
|
|
|
164
197
|
// For file uploads, we want to handle query parameters differently
|
|
@@ -166,9 +199,9 @@ function generateFunctionParameters(params?: ParameterObject[], isFileUpload = f
|
|
|
166
199
|
// Don't include these as function parameters, they'll be part of options
|
|
167
200
|
return {
|
|
168
201
|
config: {
|
|
169
|
-
params: 'dir_path: options?.dirPath, tags: options?.tags'
|
|
202
|
+
params: 'dir_path: options?.dirPath, tags: options?.tags',
|
|
170
203
|
},
|
|
171
|
-
params: '' // Empty string to ensure file is the first parameter
|
|
204
|
+
params: '', // Empty string to ensure file is the first parameter
|
|
172
205
|
}
|
|
173
206
|
}
|
|
174
207
|
|
|
@@ -182,27 +215,48 @@ function generateFunctionParameters(params?: ParameterObject[], isFileUpload = f
|
|
|
182
215
|
const varName = toCamelCase(param.name)
|
|
183
216
|
|
|
184
217
|
if (param.in === 'path' || param.in === 'query' || param.in === 'header') {
|
|
185
|
-
functionParams.push(
|
|
218
|
+
functionParams.push(
|
|
219
|
+
formatVarType({
|
|
220
|
+
varName,
|
|
221
|
+
schema: param.schema,
|
|
222
|
+
required: param.required,
|
|
223
|
+
defaultValue: param.schema.default,
|
|
224
|
+
})
|
|
225
|
+
)
|
|
186
226
|
}
|
|
187
227
|
|
|
188
228
|
if (param.in === 'query' || param.in === 'header') {
|
|
189
|
-
paramList.push(
|
|
229
|
+
paramList.push(
|
|
230
|
+
paramName === varName ? paramName : `'${paramName}': ${varName}`
|
|
231
|
+
)
|
|
190
232
|
}
|
|
191
233
|
}
|
|
192
234
|
|
|
193
235
|
return {
|
|
194
236
|
params: functionParams.join(', '),
|
|
195
|
-
config: paramList.length ? { params: paramList.join(', ') } : {}
|
|
237
|
+
config: paramList.length ? { params: paramList.join(', ') } : {},
|
|
196
238
|
}
|
|
197
239
|
}
|
|
198
240
|
|
|
199
|
-
function generateFunctionForOperation(
|
|
241
|
+
function generateFunctionForOperation(
|
|
242
|
+
method: string,
|
|
243
|
+
path: string,
|
|
244
|
+
operation: OperationObject
|
|
245
|
+
): string {
|
|
200
246
|
if (!operation) return ''
|
|
201
247
|
|
|
202
248
|
// Check if this is a file upload operation by looking at the schema reference
|
|
203
|
-
const isFileUpload =
|
|
204
|
-
|
|
205
|
-
|
|
249
|
+
const isFileUpload =
|
|
250
|
+
operation.requestBody?.content[
|
|
251
|
+
'multipart/form-data'
|
|
252
|
+
]?.schema?.$ref?.includes('Body_upload_files')
|
|
253
|
+
const parameters = generateFunctionParameters(
|
|
254
|
+
operation.parameters,
|
|
255
|
+
isFileUpload
|
|
256
|
+
)
|
|
257
|
+
const { requestBodyParam, requestBodyPayload } = generateRequestBody(
|
|
258
|
+
operation.requestBody
|
|
259
|
+
)
|
|
206
260
|
|
|
207
261
|
// For file uploads, ignore the regular parameter generation
|
|
208
262
|
const allParams = isFileUpload
|
|
@@ -210,7 +264,9 @@ function generateFunctionForOperation(method: string, path: string, operation: O
|
|
|
210
264
|
: combineAllParams(parameters, requestBodyParam)
|
|
211
265
|
|
|
212
266
|
const responseType = generateResponseType(operation.responses)
|
|
213
|
-
const responseTypeStr = responseType
|
|
267
|
+
const responseTypeStr = responseType
|
|
268
|
+
? `: Promise<AxiosResponse<${responseType}>>`
|
|
269
|
+
: ''
|
|
214
270
|
|
|
215
271
|
return generateAxiosFunction(
|
|
216
272
|
method,
|
|
@@ -224,21 +280,23 @@ function generateFunctionForOperation(method: string, path: string, operation: O
|
|
|
224
280
|
|
|
225
281
|
const generateRandomString = () => Math.random().toString(36).slice(7)
|
|
226
282
|
|
|
227
|
-
function fileTemplate(
|
|
228
|
-
|
|
229
|
-
|
|
283
|
+
function fileTemplate(
|
|
284
|
+
tsString: string,
|
|
285
|
+
typeForImport: string[],
|
|
286
|
+
baseURL: string
|
|
287
|
+
) {
|
|
288
|
+
const templateCode = `import ax from 'axios';
|
|
230
289
|
import type { AxiosResponse } from 'axios';
|
|
231
290
|
import type {${typeForImport.join(', ')}} from './types.d';
|
|
232
|
-
|
|
291
|
+
|
|
233
292
|
interface UploadOptions {
|
|
234
293
|
onUploadProgress?: (progressEvent: any) => void
|
|
235
294
|
dirPath?: string
|
|
236
295
|
tags?: string[]
|
|
237
296
|
}
|
|
238
|
-
|
|
297
|
+
|
|
239
298
|
export const axios = ax.create({baseURL:${baseURL}});
|
|
240
299
|
${tsString}`
|
|
241
|
-
)
|
|
242
300
|
const doubleQuoteRegex = /"([^"]+)":/g
|
|
243
301
|
return templateCode.replace(doubleQuoteRegex, '$1:')
|
|
244
302
|
}
|
|
@@ -252,23 +310,36 @@ const functionsInventory: Record<string, string> = {}
|
|
|
252
310
|
const pathOperations: PathOperation[] = []
|
|
253
311
|
|
|
254
312
|
function hasConflict(path: string, method: string) {
|
|
255
|
-
const cleanPathName = path
|
|
256
|
-
|
|
313
|
+
const cleanPathName = path
|
|
314
|
+
.split('/')
|
|
315
|
+
.filter(p => p && !/\{|\}/.test(p))
|
|
316
|
+
.join('/')
|
|
317
|
+
const matchingPaths = pathOperations.filter(
|
|
318
|
+
p => p.path === cleanPathName && p.method === method
|
|
319
|
+
)
|
|
257
320
|
pathOperations.push({ path: cleanPathName, method })
|
|
258
321
|
return matchingPaths.length > 0
|
|
259
322
|
}
|
|
260
323
|
|
|
261
324
|
// Creates a placeholder for a function and stores its body in the inventory
|
|
262
|
-
function createFunctionPlaceholder(
|
|
325
|
+
function createFunctionPlaceholder(
|
|
326
|
+
path: string,
|
|
327
|
+
method: string,
|
|
328
|
+
operation: any
|
|
329
|
+
) {
|
|
263
330
|
const funcID = generateRandomString()
|
|
264
|
-
functionsInventory[funcID] = generateFunctionForOperation(
|
|
331
|
+
functionsInventory[funcID] = generateFunctionForOperation(
|
|
332
|
+
method,
|
|
333
|
+
path,
|
|
334
|
+
operation
|
|
335
|
+
)
|
|
265
336
|
return funcID
|
|
266
337
|
}
|
|
267
338
|
|
|
268
339
|
function handlePathSegment(
|
|
269
340
|
path: string,
|
|
270
341
|
operation: any,
|
|
271
|
-
existingObj: { [key: string]: any } = {}
|
|
342
|
+
existingObj: { [key: string]: any } = {}
|
|
272
343
|
) {
|
|
273
344
|
const methods = Object.keys(operation)
|
|
274
345
|
const obj: { [key: string]: any } = {}
|
|
@@ -276,9 +347,13 @@ function handlePathSegment(
|
|
|
276
347
|
let functionName = method.toLowerCase()
|
|
277
348
|
if (hasConflict(path, method)) {
|
|
278
349
|
const params: string[] | undefined = getParamsFromPath(path)
|
|
279
|
-
functionName +=
|
|
350
|
+
functionName += params ? `By${toPascalCase(params.pop() || '')}` : 'All'
|
|
280
351
|
}
|
|
281
|
-
obj[functionName] = createFunctionPlaceholder(
|
|
352
|
+
obj[functionName] = createFunctionPlaceholder(
|
|
353
|
+
path,
|
|
354
|
+
method,
|
|
355
|
+
operation[method]
|
|
356
|
+
)
|
|
282
357
|
}
|
|
283
358
|
return { ...obj, ...existingObj }
|
|
284
359
|
}
|
|
@@ -288,24 +363,23 @@ export function generateFunctions(paths: PathsObject, baseUrl: string) {
|
|
|
288
363
|
const body: { [key: string]: any } = {}
|
|
289
364
|
const allPathsClean = Object.keys(paths).map(cleanPath)
|
|
290
365
|
for (const [path, operation] of Object.entries(paths)) {
|
|
291
|
-
const splitPath = path.split('/').filter(p => p &&
|
|
366
|
+
const splitPath = path.split('/').filter(p => p && !/\{|\}/.test(p))
|
|
292
367
|
splitPath.reduce((acc, key: string, index: number, array: string[]) => {
|
|
293
368
|
const objFuncKey = toCamelCase(key)
|
|
294
369
|
if (!objFuncKey) return acc
|
|
295
370
|
const methods = Object.keys(operation)
|
|
296
371
|
if (
|
|
297
|
-
index === array.length - 1
|
|
298
|
-
|
|
299
|
-
|
|
372
|
+
index === array.length - 1 &&
|
|
373
|
+
methods.length === 1 &&
|
|
374
|
+
allPathsClean.filter(p => p === cleanPath(path)).length === 1
|
|
300
375
|
) {
|
|
301
376
|
const method: string = methods[0]
|
|
302
377
|
const opp: any = { ...operation }[method]
|
|
303
378
|
acc[objFuncKey] = createFunctionPlaceholder(path, methods[0], opp)
|
|
304
|
-
} else if (
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== 'object') { acc[objFuncKey] = {}
|
|
379
|
+
} else if (index === array.length - 1) {
|
|
380
|
+
acc[objFuncKey] = handlePathSegment(path, operation, acc[objFuncKey])
|
|
381
|
+
} else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== 'object') {
|
|
382
|
+
acc[objFuncKey] = {}
|
|
309
383
|
}
|
|
310
384
|
return acc[objFuncKey]
|
|
311
385
|
}, body)
|
|
@@ -11,7 +11,7 @@ export function generateTypes(schemas: SchemasObject): string {
|
|
|
11
11
|
if (!schema.properties) return ''
|
|
12
12
|
|
|
13
13
|
const properties = Object.entries(schema.properties).map(([key, value]) => {
|
|
14
|
-
const varType = formatVarType(key, value)
|
|
14
|
+
const varType = formatVarType({ varName: key, schema: value })
|
|
15
15
|
|
|
16
16
|
return `\t\t${varType}`
|
|
17
17
|
}).join(';\n ')
|
|
@@ -1,11 +1,24 @@
|
|
|
1
1
|
import type { SchemaObject } from './openApiTypes'
|
|
2
2
|
|
|
3
|
-
export const toCamelCase = (str?: string) =>
|
|
4
|
-
|
|
3
|
+
export const toCamelCase = (str?: string) =>
|
|
4
|
+
str
|
|
5
|
+
?.replaceAll(/[-._\s]+(.)?/g, (_, c) => c?.toUpperCase() || '')
|
|
6
|
+
.replace(/^./, str => str.toLowerCase()) ||
|
|
7
|
+
str ||
|
|
8
|
+
''
|
|
9
|
+
export const toPascalCase = (str?: string) =>
|
|
10
|
+
str
|
|
11
|
+
?.replaceAll(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || '')
|
|
12
|
+
.replace(/^./, str => str.toUpperCase()) ||
|
|
13
|
+
str ||
|
|
14
|
+
''
|
|
5
15
|
|
|
6
16
|
export function formatType(typeName: string): string {
|
|
7
17
|
// eslint-disable-next-line regexp/no-unused-capturing-group
|
|
8
|
-
typeName = typeName
|
|
18
|
+
typeName = typeName
|
|
19
|
+
.replaceAll('-', '')
|
|
20
|
+
.replaceAll(/(post|put)$/gi, '')
|
|
21
|
+
.replaceAll(/^body_/gi, '')
|
|
9
22
|
return toPascalCase(typeName)!
|
|
10
23
|
}
|
|
11
24
|
|
|
@@ -18,11 +31,18 @@ function resolveReference(ref: string): string {
|
|
|
18
31
|
export function schemaToType(schema?: SchemaObject): string {
|
|
19
32
|
if (!schema) return 'any'
|
|
20
33
|
if (schema.anyOf) {
|
|
21
|
-
let _t = schema.anyOf
|
|
34
|
+
let _t = schema.anyOf
|
|
35
|
+
.map(s => schemaToType(s))
|
|
36
|
+
.filter(p => p !== 'any')
|
|
37
|
+
.join(' | ')
|
|
22
38
|
if (_t === '' || _t === 'null') _t = 'any'
|
|
23
39
|
return _t
|
|
24
40
|
}
|
|
25
|
-
if (schema.allOf)
|
|
41
|
+
if (schema.allOf)
|
|
42
|
+
return schema.allOf
|
|
43
|
+
.map(s => schemaToType(s))
|
|
44
|
+
.filter(p => p !== 'any')
|
|
45
|
+
.join(' & ')
|
|
26
46
|
if (schema.$ref) return resolveReference(schema.$ref)
|
|
27
47
|
switch (schema.type) {
|
|
28
48
|
case 'object':
|
|
@@ -59,9 +79,25 @@ export function isOptional(schema: SchemaObject) {
|
|
|
59
79
|
return includesNull || includesUndefined || schema.default !== undefined
|
|
60
80
|
}
|
|
61
81
|
|
|
62
|
-
export const cleanOptionals = (str: string) =>
|
|
82
|
+
export const cleanOptionals = (str: string) =>
|
|
83
|
+
str
|
|
84
|
+
.split(' | ')
|
|
85
|
+
.filter(t => t !== 'null' && t !== 'undefined')
|
|
86
|
+
.join(' | ')
|
|
87
|
+
|
|
88
|
+
export function formatVarType({
|
|
89
|
+
varName,
|
|
90
|
+
schema,
|
|
91
|
+
required = false,
|
|
92
|
+
defaultValue,
|
|
93
|
+
}: {
|
|
94
|
+
varName: string
|
|
95
|
+
schema: SchemaObject
|
|
96
|
+
required?: boolean
|
|
97
|
+
defaultValue?: unknown
|
|
98
|
+
}) {
|
|
99
|
+
if (varName === 'personId') console.log({ varName, schema, required, defaultValue });
|
|
63
100
|
|
|
64
|
-
export function formatVarType(varName: string, schema: any, required = false, defaultValue?: unknown) {
|
|
65
101
|
let type = schemaToType(schema)
|
|
66
102
|
type = cleanOptionals(type)
|
|
67
103
|
|
|
@@ -74,12 +110,16 @@ export function formatVarType(varName: string, schema: any, required = false, de
|
|
|
74
110
|
}
|
|
75
111
|
}
|
|
76
112
|
|
|
77
|
-
let optionalStr = required
|
|
113
|
+
let optionalStr = (!required && isOptional(schema)) ? '?' : ''
|
|
114
|
+
|
|
78
115
|
if (defaultStr) optionalStr = ''
|
|
79
116
|
|
|
80
117
|
return `${varName}${optionalStr}: ${type}${defaultStr}`
|
|
81
118
|
}
|
|
82
119
|
|
|
83
120
|
export function cleanPath(path: string) {
|
|
84
|
-
return path
|
|
121
|
+
return path
|
|
122
|
+
.split('/')
|
|
123
|
+
.filter(p => p && !/\{|\}/.test(p))
|
|
124
|
+
.join('/')
|
|
85
125
|
}
|