@bagelink/sdk 0.0.216 → 0.0.221

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 CHANGED
@@ -1,10 +1,287 @@
1
1
  'use strict';
2
2
 
3
- const ax = require('axios');
3
+ const axios$1 = require('axios');
4
4
 
5
5
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e.default : e; }
6
6
 
7
- const ax__default = /*#__PURE__*/_interopDefaultCompat(ax);
7
+ const axios__default = /*#__PURE__*/_interopDefaultCompat(axios$1);
8
+
9
+ const resolveReference = (ref) => {
10
+ const t = ref.split("/").pop() || "any";
11
+ return t;
12
+ };
13
+ const schemaToType = (schema) => {
14
+ if (!schema)
15
+ return "any";
16
+ if (schema.anyOf)
17
+ return schema.anyOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" | ");
18
+ if (schema.allOf)
19
+ return schema.allOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" & ");
20
+ if (schema.$ref)
21
+ return resolveReference(schema.$ref);
22
+ switch (schema.type) {
23
+ case "object":
24
+ return "Record<string, any>";
25
+ case "string":
26
+ return "string";
27
+ case "integer":
28
+ return "number";
29
+ case "number":
30
+ return "number";
31
+ case "boolean":
32
+ return "boolean";
33
+ case "array":
34
+ return `${schemaToType(schema.items)}[]`;
35
+ case "null":
36
+ return "null";
37
+ default:
38
+ return "any";
39
+ }
40
+ };
41
+ const toCamelCase = (str) => str?.replace(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || "").replace(/^./, (str2) => str2.toLowerCase()) || str;
42
+ const toPascalCase = (str) => str?.replace(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || "").replace(/^./, (str2) => str2.toUpperCase()) || str;
43
+ const isOptional = (schema) => {
44
+ const type = schemaToType(schema);
45
+ return type?.split(/\s+\|\s+/).includes("null");
46
+ };
47
+ const cleanNulls = (str) => str.split(" | ").filter((t) => t !== "null").join(" | ");
48
+ function formatVarType(varName, schema, required = false, defaultValue = null) {
49
+ let type = schemaToType(schema);
50
+ const optionalStr = required || isOptional(schema) ? "?" : "";
51
+ type = cleanNulls(type);
52
+ let defaultStr = defaultValue ? ` = ${defaultValue}` : "";
53
+ if (defaultStr && type === "string")
54
+ defaultStr = ` = '${defaultValue}'`;
55
+ else if (defaultValue && (typeof defaultValue === "object" || defaultValue === "{}"))
56
+ defaultStr = " = {}";
57
+ return `${varName}${optionalStr}: ${type}${defaultStr}`;
58
+ }
59
+ function cleanPath(path) {
60
+ return path.split("/").filter((p) => p && !p.match(/\{|\}/)).join("/");
61
+ }
62
+
63
+ const generateTypes = (schemas) => Object.entries(schemas).map(([typeName, schema]) => {
64
+ if (schema?.enum) {
65
+ return `export type ${typeName} = ${schema.enum.map((item) => `'${item}'`).join(" | ")};
66
+ `;
67
+ }
68
+ if (!schema?.properties)
69
+ return "";
70
+ const properties = Object.entries(schema.properties).map(([key, value]) => {
71
+ const varType = formatVarType(key, value);
72
+ return ` ${varType}`;
73
+ }).join(";\n ");
74
+ return `export type ${typeName} = {
75
+ ${properties};
76
+ };
77
+ `;
78
+ }).join("\n");
79
+
80
+ const allTypes = [];
81
+ function collectTypeForImportStatement(typeName) {
82
+ typeName = typeName.trim().replace("[]", "");
83
+ if (typeName.includes("|")) {
84
+ typeName.split("|").forEach(
85
+ (singleType) => collectTypeForImportStatement(singleType)
86
+ );
87
+ return;
88
+ }
89
+ const primitiveTypes = ["string", "number", "boolean", "null", "void", "any", "Record<string, any>"];
90
+ const isPrimitive = primitiveTypes.includes(typeName);
91
+ if (!typeName || isPrimitive)
92
+ return;
93
+ if (!allTypes.includes(typeName))
94
+ allTypes.push(typeName);
95
+ }
96
+ function getResponseType(response) {
97
+ const mediaTypeObject = response.content?.["application/json"];
98
+ if (!mediaTypeObject || !mediaTypeObject.schema)
99
+ return null;
100
+ const responseType = schemaToType(mediaTypeObject.schema);
101
+ collectTypeForImportStatement(responseType);
102
+ return responseType;
103
+ }
104
+ function generateResponseType(responses) {
105
+ if (!responses)
106
+ return "";
107
+ const types = [];
108
+ for (const [statusCode, response] of Object.entries(responses)) {
109
+ if (statusCode.startsWith("2")) {
110
+ const responseType = getResponseType(response);
111
+ if (responseType && responseType !== "any") {
112
+ types.push(responseType);
113
+ }
114
+ }
115
+ }
116
+ return types?.join(" | ");
117
+ }
118
+ function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
119
+ let axiosFunction = `async (${allParams})${responseTypeStr} => axios.${method}(`;
120
+ const paramStr = parameters?.config?.params ? `, { params: {${parameters.config.params}} }` : "";
121
+ if (["get", "delete"].includes(method)) {
122
+ axiosFunction += `${formattedPath}${paramStr}`;
123
+ } else if (["post", "put", "patch"].includes(method)) {
124
+ const bodyVar = requestBodyPayload ? `, ${requestBodyPayload}` : "";
125
+ axiosFunction += `${formattedPath}${bodyVar}${paramStr}`;
126
+ }
127
+ axiosFunction += ")";
128
+ return axiosFunction;
129
+ }
130
+ const pathParamRegex = /\{([^}]+)\}/g;
131
+ const getParamsFromPath = (path) => {
132
+ const params = path.match(pathParamRegex)?.map((p) => p.slice(1, -1));
133
+ return params;
134
+ };
135
+ function formatPathWithParams(path) {
136
+ const params = getParamsFromPath(path);
137
+ const formattedPath = params ? `\`${path.replace(pathParamRegex, (v) => `$${toCamelCase(v)}`)}\`` : `'${path}'`;
138
+ return formattedPath;
139
+ }
140
+ function generateRequestBody(requestBody) {
141
+ const bodySchema = requestBody?.content?.["application/json"]?.schema;
142
+ if (!bodySchema)
143
+ return { requestBodyParam: "", requestBodyPayload: "" };
144
+ const requestBodyType = schemaToType(bodySchema);
145
+ collectTypeForImportStatement(requestBodyType);
146
+ const requestBodyPayload = toCamelCase(bodySchema?.title) || toCamelCase(requestBodyType) || "requestBody";
147
+ const defaultValue = requestBody?.content?.["application/json"]?.schema?.default;
148
+ const requestBodyParam = formatVarType(requestBodyPayload, bodySchema, defaultValue);
149
+ return { requestBodyParam, requestBodyPayload };
150
+ }
151
+ function combineAllParams(parameters, requestBodyParam) {
152
+ let allParamsArray = [];
153
+ if (parameters && parameters.params)
154
+ allParamsArray = parameters.params.split(",").map((p) => p.trim());
155
+ if (requestBodyParam)
156
+ allParamsArray.push(requestBodyParam.trim());
157
+ allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
158
+ return allParamsArray.join(", ");
159
+ }
160
+ function generateFunctionParameters(params) {
161
+ if (!params || params.length === 0)
162
+ return {};
163
+ const functionParams = [];
164
+ const paramList = [];
165
+ for (const param of params) {
166
+ const paramType = schemaToType(param.schema);
167
+ collectTypeForImportStatement(paramType);
168
+ const paramName = param.name;
169
+ const varName = toCamelCase(param.name) || "param";
170
+ if (param.in === "path" || param.in === "query" || param.in === "header") {
171
+ const defaultValue = param?.schema?.default;
172
+ const varType = formatVarType(varName, param.schema, param.required, defaultValue);
173
+ functionParams.push(varType);
174
+ }
175
+ if (param.in === "query" || param.in === "header") {
176
+ if (paramName === varName)
177
+ paramList.push(paramName);
178
+ else
179
+ paramList.push(`'${paramName}': ${varName}`);
180
+ }
181
+ }
182
+ const paramsString = functionParams.join(", ");
183
+ const config = {};
184
+ if (paramList.length > 0)
185
+ config.params = paramList.join(", ");
186
+ return { params: paramsString, config };
187
+ }
188
+ function generateFunctionForOperation(method, path, operation) {
189
+ if (!operation)
190
+ return "";
191
+ const parameters = generateFunctionParameters(operation.parameters);
192
+ const responseType = generateResponseType(operation.responses);
193
+ const formattedPath = formatPathWithParams(path);
194
+ const { requestBodyParam, requestBodyPayload } = generateRequestBody(operation.requestBody);
195
+ const allParams = combineAllParams(parameters, requestBodyParam);
196
+ const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : "";
197
+ return generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload);
198
+ }
199
+ const generateRandomString = () => Math.random().toString(36).substring(7);
200
+ function fileTemplate(tsString, typeForImport, baseURL) {
201
+ const templateCode = `import axios, { type AxiosResponse } from 'axios';
202
+ import type {${typeForImport.join(", ")}} from './types.d';
203
+
204
+ axios.defaults.baseURL = ${baseURL};
205
+
206
+ ${tsString}`;
207
+ const doubleQuoteRegex = /"([^"]+)":/g;
208
+ return templateCode.replace(doubleQuoteRegex, "$1:");
209
+ }
210
+ const functionsInventory = {};
211
+ const pathOperations = [];
212
+ const hasConflict = (path, method) => {
213
+ const cleanPathName = path.split("/").filter((p) => p && !p.match(/\{|\}/)).join("/");
214
+ const matchingPaths = pathOperations.filter((p) => p.path === cleanPathName && p.method === method);
215
+ pathOperations.push({ path: cleanPathName, method });
216
+ return matchingPaths.length > 0;
217
+ };
218
+ const createFunctionPlaceholder = (path, method, operation) => {
219
+ const funcID = generateRandomString();
220
+ functionsInventory[funcID] = generateFunctionForOperation(method, path, operation);
221
+ return funcID;
222
+ };
223
+ function handlePathSegment(path, operation, existingObj = null) {
224
+ const methods = Object.keys(operation);
225
+ const obj = {};
226
+ for (const method of methods) {
227
+ let functionName = method.toLowerCase();
228
+ if (hasConflict(path, method)) {
229
+ const params = getParamsFromPath(path);
230
+ functionName += params ? `By${toPascalCase(params?.pop() || "")}` : "All";
231
+ }
232
+ obj[functionName] = createFunctionPlaceholder(path, method, operation[method]);
233
+ }
234
+ return { ...obj, ...existingObj };
235
+ }
236
+ function generateFunctions(paths, baseURL) {
237
+ let tsString = "";
238
+ const body = {};
239
+ const allPathsClean = Object.keys(paths).map(cleanPath);
240
+ for (const [path, operation] of Object.entries(paths)) {
241
+ const splitPath = path.split("/").filter((p) => p && !p.match(/\{|\}/));
242
+ splitPath.reduce((acc, key, index, array) => {
243
+ const objFuncKey = toCamelCase(key);
244
+ if (!objFuncKey)
245
+ return acc;
246
+ const methods = Object.keys(operation);
247
+ if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
248
+ const method = methods[0];
249
+ const opp = { ...operation }[method];
250
+ acc[objFuncKey] = createFunctionPlaceholder(path, methods[0], opp);
251
+ } else if (index === array.length - 1)
252
+ acc[objFuncKey] = handlePathSegment(path, operation, acc[objFuncKey]);
253
+ else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== "object")
254
+ acc[objFuncKey] = {};
255
+ return acc[objFuncKey];
256
+ }, body);
257
+ }
258
+ for (const [parent, object] of Object.entries(body)) {
259
+ tsString += `export const ${parent} = ${JSON.stringify(object, null, 2)};
260
+ `;
261
+ }
262
+ Object.entries(functionsInventory).forEach(([key, value]) => {
263
+ tsString = tsString.replace(`"${key}"`, value);
264
+ });
265
+ tsString = fileTemplate(tsString, allTypes, baseURL);
266
+ return tsString;
267
+ }
268
+
269
+ const index = async (openApiUrl, baseURL) => {
270
+ try {
271
+ const { data: openApi } = await axios__default.get(openApiUrl);
272
+ const schemas = openApi.components?.schemas;
273
+ if (!schemas)
274
+ throw new Error("No schemas found in OpenAPI document");
275
+ const types = generateTypes(schemas);
276
+ const { paths } = openApi;
277
+ if (!paths)
278
+ throw new Error("No paths found in OpenAPI document");
279
+ const code = generateFunctions(paths, baseURL);
280
+ return { types, code };
281
+ } catch (error) {
282
+ throw new Error(error);
283
+ }
284
+ };
8
285
 
9
286
  var __defProp = Object.defineProperty;
10
287
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -12,7 +289,7 @@ var __publicField = (obj, key, value) => {
12
289
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
290
  return value;
14
291
  };
15
- const axios = ax__default.create({
292
+ const axios = axios__default.create({
16
293
  // withCredentials to true to send cookies with requests
17
294
  withCredentials: true
18
295
  });
@@ -234,3 +511,4 @@ class Bagel {
234
511
  }
235
512
 
236
513
  exports.Bagel = Bagel;
514
+ exports.openAPI = index;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,12 @@
1
+ type OpenAPIResponse = {
2
+ types: string;
3
+ code: string;
4
+ };
5
+ declare const _default: (openApiUrl: string, baseURL: string) => Promise<OpenAPIResponse>;
6
+
1
7
  type Tables = '';
2
8
  type TableToTypeMapping = Record<Tables, any>;
9
+
3
10
  interface User {
4
11
  id: string;
5
12
  first_name?: string;
@@ -58,4 +65,4 @@ declare class Bagel {
58
65
  uploadFile(file: File, options?: UploadOptions): Promise<any>;
59
66
  }
60
67
 
61
- export { Bagel, type TableToTypeMapping, type Tables, type User };
68
+ export { Bagel, type TableToTypeMapping, type Tables, type User, _default as openAPI };
package/dist/index.d.mts CHANGED
@@ -1,5 +1,12 @@
1
+ type OpenAPIResponse = {
2
+ types: string;
3
+ code: string;
4
+ };
5
+ declare const _default: (openApiUrl: string, baseURL: string) => Promise<OpenAPIResponse>;
6
+
1
7
  type Tables = '';
2
8
  type TableToTypeMapping = Record<Tables, any>;
9
+
3
10
  interface User {
4
11
  id: string;
5
12
  first_name?: string;
@@ -58,4 +65,4 @@ declare class Bagel {
58
65
  uploadFile(file: File, options?: UploadOptions): Promise<any>;
59
66
  }
60
67
 
61
- export { Bagel, type TableToTypeMapping, type Tables, type User };
68
+ export { Bagel, type TableToTypeMapping, type Tables, type User, _default as openAPI };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,12 @@
1
+ type OpenAPIResponse = {
2
+ types: string;
3
+ code: string;
4
+ };
5
+ declare const _default: (openApiUrl: string, baseURL: string) => Promise<OpenAPIResponse>;
6
+
1
7
  type Tables = '';
2
8
  type TableToTypeMapping = Record<Tables, any>;
9
+
3
10
  interface User {
4
11
  id: string;
5
12
  first_name?: string;
@@ -58,4 +65,4 @@ declare class Bagel {
58
65
  uploadFile(file: File, options?: UploadOptions): Promise<any>;
59
66
  }
60
67
 
61
- export { Bagel, type TableToTypeMapping, type Tables, type User };
68
+ export { Bagel, type TableToTypeMapping, type Tables, type User, _default as openAPI };
package/dist/index.mjs CHANGED
@@ -1,4 +1,281 @@
1
- import ax from 'axios';
1
+ import axios$1 from 'axios';
2
+
3
+ const resolveReference = (ref) => {
4
+ const t = ref.split("/").pop() || "any";
5
+ return t;
6
+ };
7
+ const schemaToType = (schema) => {
8
+ if (!schema)
9
+ return "any";
10
+ if (schema.anyOf)
11
+ return schema.anyOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" | ");
12
+ if (schema.allOf)
13
+ return schema.allOf.map((s) => schemaToType(s)).filter((p) => p !== "any").join(" & ");
14
+ if (schema.$ref)
15
+ return resolveReference(schema.$ref);
16
+ switch (schema.type) {
17
+ case "object":
18
+ return "Record<string, any>";
19
+ case "string":
20
+ return "string";
21
+ case "integer":
22
+ return "number";
23
+ case "number":
24
+ return "number";
25
+ case "boolean":
26
+ return "boolean";
27
+ case "array":
28
+ return `${schemaToType(schema.items)}[]`;
29
+ case "null":
30
+ return "null";
31
+ default:
32
+ return "any";
33
+ }
34
+ };
35
+ const toCamelCase = (str) => str?.replace(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || "").replace(/^./, (str2) => str2.toLowerCase()) || str;
36
+ const toPascalCase = (str) => str?.replace(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || "").replace(/^./, (str2) => str2.toUpperCase()) || str;
37
+ const isOptional = (schema) => {
38
+ const type = schemaToType(schema);
39
+ return type?.split(/\s+\|\s+/).includes("null");
40
+ };
41
+ const cleanNulls = (str) => str.split(" | ").filter((t) => t !== "null").join(" | ");
42
+ function formatVarType(varName, schema, required = false, defaultValue = null) {
43
+ let type = schemaToType(schema);
44
+ const optionalStr = required || isOptional(schema) ? "?" : "";
45
+ type = cleanNulls(type);
46
+ let defaultStr = defaultValue ? ` = ${defaultValue}` : "";
47
+ if (defaultStr && type === "string")
48
+ defaultStr = ` = '${defaultValue}'`;
49
+ else if (defaultValue && (typeof defaultValue === "object" || defaultValue === "{}"))
50
+ defaultStr = " = {}";
51
+ return `${varName}${optionalStr}: ${type}${defaultStr}`;
52
+ }
53
+ function cleanPath(path) {
54
+ return path.split("/").filter((p) => p && !p.match(/\{|\}/)).join("/");
55
+ }
56
+
57
+ const generateTypes = (schemas) => Object.entries(schemas).map(([typeName, schema]) => {
58
+ if (schema?.enum) {
59
+ return `export type ${typeName} = ${schema.enum.map((item) => `'${item}'`).join(" | ")};
60
+ `;
61
+ }
62
+ if (!schema?.properties)
63
+ return "";
64
+ const properties = Object.entries(schema.properties).map(([key, value]) => {
65
+ const varType = formatVarType(key, value);
66
+ return ` ${varType}`;
67
+ }).join(";\n ");
68
+ return `export type ${typeName} = {
69
+ ${properties};
70
+ };
71
+ `;
72
+ }).join("\n");
73
+
74
+ const allTypes = [];
75
+ function collectTypeForImportStatement(typeName) {
76
+ typeName = typeName.trim().replace("[]", "");
77
+ if (typeName.includes("|")) {
78
+ typeName.split("|").forEach(
79
+ (singleType) => collectTypeForImportStatement(singleType)
80
+ );
81
+ return;
82
+ }
83
+ const primitiveTypes = ["string", "number", "boolean", "null", "void", "any", "Record<string, any>"];
84
+ const isPrimitive = primitiveTypes.includes(typeName);
85
+ if (!typeName || isPrimitive)
86
+ return;
87
+ if (!allTypes.includes(typeName))
88
+ allTypes.push(typeName);
89
+ }
90
+ function getResponseType(response) {
91
+ const mediaTypeObject = response.content?.["application/json"];
92
+ if (!mediaTypeObject || !mediaTypeObject.schema)
93
+ return null;
94
+ const responseType = schemaToType(mediaTypeObject.schema);
95
+ collectTypeForImportStatement(responseType);
96
+ return responseType;
97
+ }
98
+ function generateResponseType(responses) {
99
+ if (!responses)
100
+ return "";
101
+ const types = [];
102
+ for (const [statusCode, response] of Object.entries(responses)) {
103
+ if (statusCode.startsWith("2")) {
104
+ const responseType = getResponseType(response);
105
+ if (responseType && responseType !== "any") {
106
+ types.push(responseType);
107
+ }
108
+ }
109
+ }
110
+ return types?.join(" | ");
111
+ }
112
+ function generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload) {
113
+ let axiosFunction = `async (${allParams})${responseTypeStr} => axios.${method}(`;
114
+ const paramStr = parameters?.config?.params ? `, { params: {${parameters.config.params}} }` : "";
115
+ if (["get", "delete"].includes(method)) {
116
+ axiosFunction += `${formattedPath}${paramStr}`;
117
+ } else if (["post", "put", "patch"].includes(method)) {
118
+ const bodyVar = requestBodyPayload ? `, ${requestBodyPayload}` : "";
119
+ axiosFunction += `${formattedPath}${bodyVar}${paramStr}`;
120
+ }
121
+ axiosFunction += ")";
122
+ return axiosFunction;
123
+ }
124
+ const pathParamRegex = /\{([^}]+)\}/g;
125
+ const getParamsFromPath = (path) => {
126
+ const params = path.match(pathParamRegex)?.map((p) => p.slice(1, -1));
127
+ return params;
128
+ };
129
+ function formatPathWithParams(path) {
130
+ const params = getParamsFromPath(path);
131
+ const formattedPath = params ? `\`${path.replace(pathParamRegex, (v) => `$${toCamelCase(v)}`)}\`` : `'${path}'`;
132
+ return formattedPath;
133
+ }
134
+ function generateRequestBody(requestBody) {
135
+ const bodySchema = requestBody?.content?.["application/json"]?.schema;
136
+ if (!bodySchema)
137
+ return { requestBodyParam: "", requestBodyPayload: "" };
138
+ const requestBodyType = schemaToType(bodySchema);
139
+ collectTypeForImportStatement(requestBodyType);
140
+ const requestBodyPayload = toCamelCase(bodySchema?.title) || toCamelCase(requestBodyType) || "requestBody";
141
+ const defaultValue = requestBody?.content?.["application/json"]?.schema?.default;
142
+ const requestBodyParam = formatVarType(requestBodyPayload, bodySchema, defaultValue);
143
+ return { requestBodyParam, requestBodyPayload };
144
+ }
145
+ function combineAllParams(parameters, requestBodyParam) {
146
+ let allParamsArray = [];
147
+ if (parameters && parameters.params)
148
+ allParamsArray = parameters.params.split(",").map((p) => p.trim());
149
+ if (requestBodyParam)
150
+ allParamsArray.push(requestBodyParam.trim());
151
+ allParamsArray = allParamsArray.filter((p) => p).sort((a, b) => (a.includes("?") ? 1 : -1) - (b.includes("?") ? 1 : -1));
152
+ return allParamsArray.join(", ");
153
+ }
154
+ function generateFunctionParameters(params) {
155
+ if (!params || params.length === 0)
156
+ return {};
157
+ const functionParams = [];
158
+ const paramList = [];
159
+ for (const param of params) {
160
+ const paramType = schemaToType(param.schema);
161
+ collectTypeForImportStatement(paramType);
162
+ const paramName = param.name;
163
+ const varName = toCamelCase(param.name) || "param";
164
+ if (param.in === "path" || param.in === "query" || param.in === "header") {
165
+ const defaultValue = param?.schema?.default;
166
+ const varType = formatVarType(varName, param.schema, param.required, defaultValue);
167
+ functionParams.push(varType);
168
+ }
169
+ if (param.in === "query" || param.in === "header") {
170
+ if (paramName === varName)
171
+ paramList.push(paramName);
172
+ else
173
+ paramList.push(`'${paramName}': ${varName}`);
174
+ }
175
+ }
176
+ const paramsString = functionParams.join(", ");
177
+ const config = {};
178
+ if (paramList.length > 0)
179
+ config.params = paramList.join(", ");
180
+ return { params: paramsString, config };
181
+ }
182
+ function generateFunctionForOperation(method, path, operation) {
183
+ if (!operation)
184
+ return "";
185
+ const parameters = generateFunctionParameters(operation.parameters);
186
+ const responseType = generateResponseType(operation.responses);
187
+ const formattedPath = formatPathWithParams(path);
188
+ const { requestBodyParam, requestBodyPayload } = generateRequestBody(operation.requestBody);
189
+ const allParams = combineAllParams(parameters, requestBodyParam);
190
+ const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : "";
191
+ return generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload);
192
+ }
193
+ const generateRandomString = () => Math.random().toString(36).substring(7);
194
+ function fileTemplate(tsString, typeForImport, baseURL) {
195
+ const templateCode = `import axios, { type AxiosResponse } from 'axios';
196
+ import type {${typeForImport.join(", ")}} from './types.d';
197
+
198
+ axios.defaults.baseURL = ${baseURL};
199
+
200
+ ${tsString}`;
201
+ const doubleQuoteRegex = /"([^"]+)":/g;
202
+ return templateCode.replace(doubleQuoteRegex, "$1:");
203
+ }
204
+ const functionsInventory = {};
205
+ const pathOperations = [];
206
+ const hasConflict = (path, method) => {
207
+ const cleanPathName = path.split("/").filter((p) => p && !p.match(/\{|\}/)).join("/");
208
+ const matchingPaths = pathOperations.filter((p) => p.path === cleanPathName && p.method === method);
209
+ pathOperations.push({ path: cleanPathName, method });
210
+ return matchingPaths.length > 0;
211
+ };
212
+ const createFunctionPlaceholder = (path, method, operation) => {
213
+ const funcID = generateRandomString();
214
+ functionsInventory[funcID] = generateFunctionForOperation(method, path, operation);
215
+ return funcID;
216
+ };
217
+ function handlePathSegment(path, operation, existingObj = null) {
218
+ const methods = Object.keys(operation);
219
+ const obj = {};
220
+ for (const method of methods) {
221
+ let functionName = method.toLowerCase();
222
+ if (hasConflict(path, method)) {
223
+ const params = getParamsFromPath(path);
224
+ functionName += params ? `By${toPascalCase(params?.pop() || "")}` : "All";
225
+ }
226
+ obj[functionName] = createFunctionPlaceholder(path, method, operation[method]);
227
+ }
228
+ return { ...obj, ...existingObj };
229
+ }
230
+ function generateFunctions(paths, baseURL) {
231
+ let tsString = "";
232
+ const body = {};
233
+ const allPathsClean = Object.keys(paths).map(cleanPath);
234
+ for (const [path, operation] of Object.entries(paths)) {
235
+ const splitPath = path.split("/").filter((p) => p && !p.match(/\{|\}/));
236
+ splitPath.reduce((acc, key, index, array) => {
237
+ const objFuncKey = toCamelCase(key);
238
+ if (!objFuncKey)
239
+ return acc;
240
+ const methods = Object.keys(operation);
241
+ if (index === array.length - 1 && methods.length === 1 && allPathsClean.filter((p) => p === cleanPath(path)).length === 1) {
242
+ const method = methods[0];
243
+ const opp = { ...operation }[method];
244
+ acc[objFuncKey] = createFunctionPlaceholder(path, methods[0], opp);
245
+ } else if (index === array.length - 1)
246
+ acc[objFuncKey] = handlePathSegment(path, operation, acc[objFuncKey]);
247
+ else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== "object")
248
+ acc[objFuncKey] = {};
249
+ return acc[objFuncKey];
250
+ }, body);
251
+ }
252
+ for (const [parent, object] of Object.entries(body)) {
253
+ tsString += `export const ${parent} = ${JSON.stringify(object, null, 2)};
254
+ `;
255
+ }
256
+ Object.entries(functionsInventory).forEach(([key, value]) => {
257
+ tsString = tsString.replace(`"${key}"`, value);
258
+ });
259
+ tsString = fileTemplate(tsString, allTypes, baseURL);
260
+ return tsString;
261
+ }
262
+
263
+ const index = async (openApiUrl, baseURL) => {
264
+ try {
265
+ const { data: openApi } = await axios$1.get(openApiUrl);
266
+ const schemas = openApi.components?.schemas;
267
+ if (!schemas)
268
+ throw new Error("No schemas found in OpenAPI document");
269
+ const types = generateTypes(schemas);
270
+ const { paths } = openApi;
271
+ if (!paths)
272
+ throw new Error("No paths found in OpenAPI document");
273
+ const code = generateFunctions(paths, baseURL);
274
+ return { types, code };
275
+ } catch (error) {
276
+ throw new Error(error);
277
+ }
278
+ };
2
279
 
3
280
  var __defProp = Object.defineProperty;
4
281
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -6,7 +283,7 @@ var __publicField = (obj, key, value) => {
6
283
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
7
284
  return value;
8
285
  };
9
- const axios = ax.create({
286
+ const axios = axios$1.create({
10
287
  // withCredentials to true to send cookies with requests
11
288
  withCredentials: true
12
289
  });
@@ -227,4 +504,4 @@ class Bagel {
227
504
  }
228
505
  }
229
506
 
230
- export { Bagel };
507
+ export { Bagel, index as openAPI };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bagelink/sdk",
3
3
  "type": "module",
4
- "version": "0.0.216",
4
+ "version": "0.0.221",
5
5
  "description": "Bagel core sdk packages",
6
6
  "author": {
7
7
  "name": "Neveh Allon",
package/src/index.ts CHANGED
@@ -1,8 +1,11 @@
1
1
  import ax from 'axios';
2
2
 
3
+ import openAPI from './openAPITools';
4
+
3
5
  export type Tables = '';
4
6
  export type TableToTypeMapping = Record<Tables, any>;
5
7
 
8
+ export { openAPI };
6
9
  export interface User {
7
10
  id: string
8
11
  first_name?: string
@@ -0,0 +1,245 @@
1
+ import type {
2
+ OperationObject, ParameterObject, PathsObject, RequestBodyObject, ResponseObject, ResponsesObject,
3
+ } from './openApiTypes';
4
+ import {
5
+ cleanPath,
6
+ formatVarType, schemaToType, toCamelCase, toPascalCase,
7
+ } from './utils';
8
+
9
+ const allTypes: string[] = [];
10
+
11
+ function collectTypeForImportStatement(typeName: string) {
12
+ typeName = typeName.trim().replace('[]', '');
13
+ if (typeName.includes('|')) {
14
+ typeName
15
+ .split('|')
16
+ .forEach(
17
+ (singleType) => collectTypeForImportStatement(singleType),
18
+ );
19
+ return;
20
+ }
21
+ const primitiveTypes = ['string', 'number', 'boolean', 'null', 'void', 'any', 'Record<string, any>'];
22
+ const isPrimitive = primitiveTypes.includes(typeName);
23
+ if (!typeName || isPrimitive) return;
24
+ if (!allTypes.includes(typeName)) allTypes.push(typeName);
25
+ }
26
+
27
+ function getResponseType(response: ResponseObject): string | null {
28
+ const mediaTypeObject = response.content?.['application/json'];
29
+ if (!mediaTypeObject || !mediaTypeObject.schema) return null;
30
+ const responseType = schemaToType(mediaTypeObject.schema);
31
+ collectTypeForImportStatement(responseType);
32
+ return responseType;
33
+ }
34
+
35
+ function generateResponseType(responses?: ResponsesObject): string {
36
+ if (!responses) return '';
37
+ const types: string[] = [];
38
+
39
+ for (const [statusCode, response] of Object.entries(responses)) {
40
+ if (statusCode.startsWith('2')) {
41
+ const responseType = getResponseType(response);
42
+ if (responseType && responseType !== 'any') {
43
+ types.push(responseType);
44
+ }
45
+ }
46
+ }
47
+ return types?.join(' | ');
48
+ }
49
+
50
+ /**
51
+ * Generates the string representation of an Axios function call.
52
+ * @param method - The HTTP method (get, post, etc.).
53
+ * @param formattedPath - The API endpoint path, formatted with template literals for parameters.
54
+ * @param allParams - All parameters required for the function, formatted as a string.
55
+ * @param responseTypeStr - The expected response type for the function.
56
+ * @param parameters - Additional configuration parameters, if any.
57
+ * @returns A string representing the Axios function.
58
+ */
59
+ function generateAxiosFunction(
60
+ method: string,
61
+ formattedPath: string,
62
+ allParams: string,
63
+ responseTypeStr: string,
64
+ parameters: any,
65
+ requestBodyPayload: string,
66
+ ): string {
67
+ let axiosFunction = `async (${allParams})${responseTypeStr} => axios.${method}(`;
68
+ // Different handling based on the HTTP method
69
+ const paramStr = parameters?.config?.params ? `, { params: {${parameters.config.params}} }` : '';
70
+ if (['get', 'delete'].includes(method)) {
71
+ axiosFunction += `${formattedPath}${paramStr}`;
72
+ } else if (['post', 'put', 'patch'].includes(method)) {
73
+ const bodyVar = requestBodyPayload ? `, ${requestBodyPayload}` : '';
74
+
75
+ axiosFunction += `${formattedPath}${bodyVar}${paramStr}`;
76
+ }
77
+ axiosFunction += ')';
78
+ return axiosFunction;
79
+ }
80
+
81
+ const pathParamRegex = /\{([^}]+)\}/g;
82
+ const getParamsFromPath = (path: string) => {
83
+ const params = path.match(pathParamRegex)?.map((p) => p.slice(1, -1));
84
+ return params;
85
+ };
86
+
87
+ function formatPathWithParams(path: string) {
88
+ const params = getParamsFromPath(path);
89
+ const formattedPath = params ? `\`${path.replace(pathParamRegex, (v) => `$${toCamelCase(v)}`)}\`` : `'${path}'`;
90
+ return formattedPath;
91
+ }
92
+
93
+ function generateRequestBody(requestBody?: RequestBodyObject): Record<string, string> {
94
+ const bodySchema = requestBody?.content?.['application/json']?.schema;
95
+ if (!bodySchema) return { requestBodyParam: '', requestBodyPayload: '' };
96
+ const requestBodyType = schemaToType(bodySchema);
97
+ collectTypeForImportStatement(requestBodyType);
98
+ const requestBodyPayload = toCamelCase(bodySchema?.title) || toCamelCase(requestBodyType) || 'requestBody';
99
+ const defaultValue = requestBody?.content?.['application/json']?.schema?.default;
100
+ const requestBodyParam = formatVarType(requestBodyPayload, bodySchema, defaultValue);
101
+ return { requestBodyParam, requestBodyPayload };
102
+ }
103
+
104
+ /**
105
+ * Combines and formats function parameters and request body parameters into a single parameter string.
106
+ * @param parameters - The parameters derived from the OpenAPI specification.
107
+ * @param requestBodyParam - The parameter representing the request body.
108
+ * @returns A string representing all combined parameters.
109
+ */
110
+ function combineAllParams(parameters: { params?: string }, requestBodyParam: string): string {
111
+ let allParamsArray: string[] = [];
112
+ if (parameters && parameters.params) allParamsArray = parameters.params.split(',').map((p) => p.trim());
113
+ if (requestBodyParam) allParamsArray.push(requestBodyParam.trim());
114
+
115
+ allParamsArray = allParamsArray
116
+ .filter((p) => p).sort((a, b) => (a.includes('?') ? 1 : -1) - (b.includes('?') ? 1 : -1));
117
+
118
+ return allParamsArray.join(', ');
119
+ }
120
+
121
+ function generateFunctionParameters(params?: ParameterObject[]) {
122
+ if (!params || params.length === 0) return {};
123
+
124
+ const functionParams: string[] = [];
125
+ const paramList: string[] = [];
126
+
127
+ for (const param of params) {
128
+ const paramType = schemaToType(param.schema);
129
+ collectTypeForImportStatement(paramType);
130
+ const paramName = param.name;
131
+ const varName = toCamelCase(param.name) || 'param';
132
+ if (param.in === 'path' || param.in === 'query' || param.in === 'header') {
133
+ const defaultValue = param?.schema?.default;
134
+ const varType = formatVarType(varName, param.schema, param.required, defaultValue);
135
+ functionParams.push(varType);
136
+ }
137
+ if (param.in === 'query' || param.in === 'header') {
138
+ if (paramName === varName) paramList.push(paramName);
139
+ else paramList.push(`'${paramName}': ${varName}`);
140
+ }
141
+ }
142
+
143
+ const paramsString = functionParams.join(', ');
144
+ const config: { params?: string } = {};
145
+
146
+ if (paramList.length > 0) config.params = paramList.join(', ');
147
+ return { params: paramsString, config };
148
+ }
149
+
150
+ function generateFunctionForOperation(method: string, path: string, operation: OperationObject): string {
151
+ if (!operation) return '';
152
+ const parameters = generateFunctionParameters(operation.parameters);
153
+ const responseType = generateResponseType(operation.responses);
154
+ const formattedPath = formatPathWithParams(path);
155
+ const { requestBodyParam, requestBodyPayload } = generateRequestBody(operation.requestBody);
156
+ const allParams = combineAllParams(parameters, requestBodyParam);
157
+ const responseTypeStr = responseType ? `: Promise<AxiosResponse<${responseType}>>` : '';
158
+ return generateAxiosFunction(method, formattedPath, allParams, responseTypeStr, parameters, requestBodyPayload);
159
+ }
160
+
161
+ const generateRandomString = () => Math.random().toString(36).substring(7);
162
+
163
+ function fileTemplate(tsString: string, typeForImport: string[], baseURL: string) {
164
+ const templateCode = (
165
+ `import axios, { type AxiosResponse } from 'axios';
166
+ import type {${typeForImport.join(', ')}} from './types.d';
167
+
168
+ axios.defaults.baseURL = ${baseURL};
169
+
170
+ ${tsString}`
171
+ );
172
+ const doubleQuoteRegex = /"([^"]+)":/g;
173
+ return templateCode.replace(doubleQuoteRegex, '$1:');
174
+ }
175
+
176
+ const functionsInventory: Record<string, any> = {};
177
+ const pathOperations: any[] = [];
178
+
179
+ const hasConflict = (path: string, method: string) => {
180
+ const cleanPathName = path.split('/').filter((p) => p && !p.match(/\{|\}/)).join('/');
181
+ const matchingPaths = pathOperations.filter((p) => p.path === cleanPathName && p.method === method);
182
+ pathOperations.push({ path: cleanPathName, method });
183
+ return matchingPaths.length > 0;
184
+ };
185
+
186
+ // Creates a placeholder for a function and stores its body in the inventory
187
+ const createFunctionPlaceholder = (path: string, method: string, operation: any) => {
188
+ const funcID = generateRandomString();
189
+ functionsInventory[funcID] = generateFunctionForOperation(method, path, operation);
190
+ return funcID;
191
+ };
192
+
193
+ function handlePathSegment(
194
+ path: string,
195
+ operation: any,
196
+ existingObj: Record<string, any> | null = null,
197
+ ) {
198
+ const methods = Object.keys(operation);
199
+ const obj: Record<string, any> = {};
200
+ for (const method of methods) {
201
+ let functionName = method.toLowerCase();
202
+ if (hasConflict(path, method)) {
203
+ const params: string[] | undefined = getParamsFromPath(path);
204
+ functionName += (params ? `By${toPascalCase(params?.pop() || '')}` : 'All');
205
+ }
206
+ obj[functionName] = createFunctionPlaceholder(path, method, operation[method]);
207
+ }
208
+
209
+ return { ...obj, ...existingObj };
210
+ }
211
+
212
+ export function generateFunctions(paths: PathsObject, baseURL: string) {
213
+ let tsString = '';
214
+ const body: Record<string, any> = {};
215
+ const allPathsClean = Object.keys(paths).map(cleanPath);
216
+ for (const [path, operation] of Object.entries(paths)) {
217
+ const splitPath = path.split('/').filter((p) => p && !p.match(/\{|\}/));
218
+ splitPath.reduce((acc, key: string, index: number, array: string[]) => {
219
+ const objFuncKey = toCamelCase(key);
220
+ if (!objFuncKey) return acc;
221
+ const methods = Object.keys(operation);
222
+ if (
223
+ index === array.length - 1 &&
224
+ methods.length === 1 &&
225
+ allPathsClean.filter((p) => p === cleanPath(path)).length === 1
226
+ ) {
227
+ const method: string = methods[0];
228
+ const opp:any = { ...operation }[method];
229
+ acc[objFuncKey] = createFunctionPlaceholder(path, methods[0], opp);
230
+ } else if (
231
+ index === array.length - 1
232
+ ) acc[objFuncKey] = handlePathSegment(path, operation, acc[objFuncKey]);
233
+ else if (!acc[objFuncKey] || typeof acc[objFuncKey] !== 'object') acc[objFuncKey] = {};
234
+ return acc[objFuncKey];
235
+ }, body);
236
+ }
237
+ for (const [parent, object] of Object.entries(body)) {
238
+ tsString += `export const ${parent} = ${JSON.stringify(object, null, 2)};\n`;
239
+ }
240
+ Object.entries(functionsInventory).forEach(([key, value]) => {
241
+ tsString = tsString.replace(`"${key}"`, value);
242
+ });
243
+ tsString = fileTemplate(tsString, allTypes, baseURL);
244
+ return tsString;
245
+ }
@@ -0,0 +1,25 @@
1
+ import axios from 'axios';
2
+ import type { OpenAPIDocument } from './openApiTypes';
3
+ import { generateTypes } from './typeGenerator';
4
+ import { generateFunctions } from './functionGenerator';
5
+
6
+ type OpenAPIResponse = {
7
+ types: string;
8
+ code: string;
9
+ }
10
+
11
+ export default async (openApiUrl: string, baseURL: string): Promise<OpenAPIResponse> => {
12
+ try {
13
+ const { data: openApi } = await axios.get<OpenAPIDocument>(openApiUrl);
14
+ const schemas = openApi.components?.schemas;
15
+ if (!schemas) throw new Error('No schemas found in OpenAPI document');
16
+ const types = generateTypes(schemas);
17
+ // Generate Functions
18
+ const { paths } = openApi;
19
+ if (!paths) throw new Error('No paths found in OpenAPI document');
20
+ const code = generateFunctions(paths, baseURL);
21
+ return { types, code };
22
+ } catch (error: any) {
23
+ throw new Error(error);
24
+ }
25
+ };
@@ -0,0 +1,70 @@
1
+ export interface OpenAPIDocument {
2
+ openapi: string;
3
+ info: InfoObject;
4
+ paths: PathsObject,
5
+ components?: ComponentsObject;
6
+ }
7
+
8
+ export type PathsObject = { [path: string]: PathItemObject };
9
+
10
+ export interface InfoObject {
11
+ title: string;
12
+ version: string;
13
+ }
14
+
15
+ export interface PathItemObject {
16
+ get?: OperationObject;
17
+ put?: OperationObject;
18
+ post?: OperationObject;
19
+ delete?: OperationObject;
20
+ }
21
+
22
+ export type SchemasObject = { [schema: string]: SchemaObject };
23
+
24
+ export interface ComponentsObject {
25
+ schemas?: SchemasObject
26
+ }
27
+
28
+ export interface OperationObject {
29
+ summary?: string;
30
+ operationId?: string;
31
+ parameters?: ParameterObject[];
32
+ requestBody?: RequestBodyObject;
33
+ responses: ResponsesObject;
34
+ }
35
+
36
+ export type ResponsesObject = { [statusCode: string]: ResponseObject };
37
+
38
+ export interface SchemaObject {
39
+ type?: string;
40
+ properties?: { [property: string]: SchemaObject };
41
+ items?: SchemaObject;
42
+ $ref?: string;
43
+ enum: string[];
44
+ anyOf?: SchemaObject[];
45
+ allOf?: SchemaObject[];
46
+ title?: string;
47
+ description?: string;
48
+ default: any
49
+ }
50
+
51
+ export interface ParameterObject {
52
+ name: string;
53
+ in: string;
54
+ schema: SchemaObject;
55
+ required?: boolean;
56
+ }
57
+
58
+ export interface RequestBodyObject {
59
+ description?: string;
60
+ content: { [mediaType: string]: MediaTypeObject };
61
+ }
62
+
63
+ export interface ResponseObject {
64
+ description: string;
65
+ content?: { [mediaType: string]: MediaTypeObject };
66
+ }
67
+
68
+ export interface MediaTypeObject {
69
+ schema?: SchemaObject;
70
+ }
@@ -0,0 +1,16 @@
1
+ import { formatVarType } from './utils';
2
+ import type { SchemasObject } from './openApiTypes';
3
+
4
+ export const generateTypes = (schemas: SchemasObject): string => Object.entries(schemas).map(([typeName, schema]) => {
5
+ if (schema?.enum) {
6
+ return `export type ${typeName} = ${schema.enum.map((item: string) => `'${item}'`).join(' | ')};\n`;
7
+ }
8
+ if (!schema?.properties) return '';
9
+
10
+ const properties = Object.entries(schema.properties).map(([key, value]) => {
11
+ const varType = formatVarType(key, value);
12
+ return `\t\t${varType}`;
13
+ }).join(';\n ');
14
+
15
+ return `export type ${typeName} = {\n ${properties};\n };\n`;
16
+ }).join('\n');
@@ -0,0 +1,56 @@
1
+ import type { SchemaObject } from './openApiTypes';
2
+
3
+ const resolveReference = (ref: string): string => {
4
+ const t = ref.split('/').pop() || 'any';
5
+ return t;
6
+ };
7
+
8
+ export const schemaToType = (schema?: SchemaObject): string => {
9
+ if (!schema) return 'any';
10
+ if (schema.anyOf) return schema.anyOf.map((s) => schemaToType(s)).filter((p) => p !== 'any').join(' | ');
11
+ if (schema.allOf) return schema.allOf.map((s) => schemaToType(s)).filter((p) => p !== 'any').join(' & ');
12
+ if (schema.$ref) return resolveReference(schema.$ref);
13
+ switch (schema.type) {
14
+ case 'object':
15
+ return 'Record<string, any>';
16
+ case 'string':
17
+ return 'string';
18
+ case 'integer':
19
+ return 'number';
20
+ case 'number':
21
+ return 'number';
22
+ case 'boolean':
23
+ return 'boolean';
24
+ case 'array':
25
+ return `${schemaToType(schema.items)}[]`;
26
+ case 'null':
27
+ return 'null';
28
+ default:
29
+ return 'any';
30
+ }
31
+ };
32
+
33
+ export const toCamelCase = (str?: string) => str?.replace(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || '').replace(/^./, (str) => str.toLowerCase()) || str;
34
+ export const toPascalCase = (str?: string) => str?.replace(/[-_\s]+(.)?/g, (_, c) => c?.toUpperCase() || '').replace(/^./, (str) => str.toUpperCase()) || str;
35
+
36
+ export const isOptional = (schema: SchemaObject) => {
37
+ /// / !schema?.required?.includes(schema.title || '')
38
+ const type = schemaToType(schema);
39
+ return type?.split(/\s+\|\s+/).includes('null');
40
+ };
41
+
42
+ export const cleanNulls = (str: string) => str.split(' | ').filter((t) => t !== 'null').join(' | ');
43
+
44
+ export function formatVarType(varName: string, schema: any, required = false, defaultValue: any = null) {
45
+ let type = schemaToType(schema);
46
+ const optionalStr = required || isOptional(schema) ? '?' : '';
47
+ type = cleanNulls(type);
48
+ let defaultStr = defaultValue ? ` = ${defaultValue}` : '';
49
+ if (defaultStr && type === 'string') defaultStr = ` = '${defaultValue}'`;
50
+ else if (defaultValue && (typeof defaultValue === 'object' || defaultValue === '{}')) defaultStr = ' = {}';
51
+ return `${varName}${optionalStr}: ${type}${defaultStr}`;
52
+ }
53
+
54
+ export function cleanPath(path: string) {
55
+ return path.split('/').filter((p) => p && !p.match(/\{|\}/)).join('/');
56
+ }