@asad_dev/leo-generator 1.6.0
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/CHANGELOG.md +194 -0
- package/COMMAND_REFERENCE.md +412 -0
- package/README.md +486 -0
- package/dist/app/modules/imagemodule/imagemodule.constants.js +18 -0
- package/dist/app/modules/imagemodule/imagemodule.controller.js +98 -0
- package/dist/app/modules/imagemodule/imagemodule.interface.js +2 -0
- package/dist/app/modules/imagemodule/imagemodule.model.js +10 -0
- package/dist/app/modules/imagemodule/imagemodule.route.js +20 -0
- package/dist/app/modules/imagemodule/imagemodule.service.js +137 -0
- package/dist/app/modules/imagemodule/imagemodule.validation.js +12 -0
- package/dist/app/modules/skiptest/skiptest.controller.js +81 -0
- package/dist/app/modules/skiptest/skiptest.route.js +19 -0
- package/dist/app/modules/skiptest/skiptest.service.js +129 -0
- package/dist/app/modules/skiptest/skiptest.validation.js +12 -0
- package/dist/app/modules/testmodule/testmodule.constants.js +18 -0
- package/dist/app/modules/testmodule/testmodule.controller.js +81 -0
- package/dist/app/modules/testmodule/testmodule.interface.js +2 -0
- package/dist/app/modules/testmodule/testmodule.model.js +11 -0
- package/dist/app/modules/testmodule/testmodule.route.js +19 -0
- package/dist/app/modules/testmodule/testmodule.service.js +129 -0
- package/dist/app/modules/testmodule/testmodule.validation.js +14 -0
- package/dist/helpers/fileHelper.js +44 -0
- package/dist/index.js +586 -0
- package/dist/templates/constants.template.js +24 -0
- package/dist/templates/controller.template.js +108 -0
- package/dist/templates/route.template.js +68 -0
- package/dist/templates/service.template.js +184 -0
- package/dist/types.js +2 -0
- package/dist/utils/documentationUpdater.js +430 -0
- package/dist/utils/fieldParser.js +163 -0
- package/dist/utils/helperGenerator.js +87 -0
- package/dist/utils/interfaceGenerator.js +158 -0
- package/dist/utils/modelGenerator.js +140 -0
- package/dist/utils/postmanApi.js +113 -0
- package/dist/utils/postmanGenerator.js +283 -0
- package/dist/utils/swaggerGenerator.js +444 -0
- package/dist/utils/validationGenerator.js +170 -0
- package/package.json +58 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.updateAllDocumentation = updateAllDocumentation;
|
|
46
|
+
exports.updateExistingModulesDocumentation = updateExistingModulesDocumentation;
|
|
47
|
+
const postmanGenerator_1 = require("./postmanGenerator");
|
|
48
|
+
const postmanApi_1 = require("./postmanApi");
|
|
49
|
+
const swaggerGenerator_1 = require("./swaggerGenerator");
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const path = __importStar(require("path"));
|
|
52
|
+
function updateAllDocumentation(moduleName_1, fields_1) {
|
|
53
|
+
return __awaiter(this, arguments, void 0, function* (moduleName, fields, options = {}) {
|
|
54
|
+
const { postmanDir = "postman", swaggerFile = "swagger.json", updatePostman = true, updateSwagger = true } = options;
|
|
55
|
+
console.log(`đ Updating documentation for ${moduleName}...`);
|
|
56
|
+
if (updatePostman) {
|
|
57
|
+
try {
|
|
58
|
+
const postmanCollection = (0, postmanGenerator_1.generatePostmanCollection)(moduleName, fields);
|
|
59
|
+
// Save locally (always happens)
|
|
60
|
+
(0, postmanGenerator_1.savePostmanCollection)(moduleName, postmanCollection, postmanDir);
|
|
61
|
+
// Save to Postman API if config is provided
|
|
62
|
+
if (options.postmanApiKey && options.postmanCollectionId) {
|
|
63
|
+
console.log(`âī¸ Syncing ${moduleName} API to Postman Cloud...`);
|
|
64
|
+
// Await the API call to ensure sequential processing
|
|
65
|
+
yield (0, postmanApi_1.updatePostmanCollectionViaApi)(moduleName, postmanCollection, {
|
|
66
|
+
apiKey: options.postmanApiKey,
|
|
67
|
+
collectionId: options.postmanCollectionId
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
console.error("â Error updating Postman collection:", error);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
if (updateSwagger) {
|
|
76
|
+
try {
|
|
77
|
+
(0, swaggerGenerator_1.updateSwaggerFile)(moduleName, fields, swaggerFile);
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
console.error("â Error updating Swagger documentation:", error);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
console.log("â
Documentation update completed!");
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function updateExistingModulesDocumentation() {
|
|
87
|
+
return __awaiter(this, arguments, void 0, function* (modulesDir = "src/app/modules", options = {}) {
|
|
88
|
+
const fullModulesPath = path.join(process.cwd(), modulesDir);
|
|
89
|
+
if (!fs.existsSync(fullModulesPath)) {
|
|
90
|
+
console.error(`â Modules directory not found: ${fullModulesPath}`);
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
console.log("đ Scanning existing modules for documentation updates...");
|
|
94
|
+
const moduleDirectories = fs.readdirSync(fullModulesPath, { withFileTypes: true })
|
|
95
|
+
.filter(dirent => dirent.isDirectory())
|
|
96
|
+
.map(dirent => dirent.name);
|
|
97
|
+
let updatedCount = 0;
|
|
98
|
+
// Process modules sequentially to avoid race conditions with Postman API
|
|
99
|
+
for (const moduleDir of moduleDirectories) {
|
|
100
|
+
try {
|
|
101
|
+
const modulePath = path.join(fullModulesPath, moduleDir);
|
|
102
|
+
const interfaceFile = path.join(modulePath, `${moduleDir}.interface.ts`);
|
|
103
|
+
const modelFile = path.join(modulePath, `${moduleDir}.model.ts`);
|
|
104
|
+
if (fs.existsSync(interfaceFile)) {
|
|
105
|
+
console.log(`đ Processing module: ${moduleDir}`);
|
|
106
|
+
// Check if model file exists for better parsing
|
|
107
|
+
if (fs.existsSync(modelFile)) {
|
|
108
|
+
console.log(` đ Found interface and model files`);
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
console.log(` đ Found interface file (model file missing)`);
|
|
112
|
+
}
|
|
113
|
+
// Extract fields from interface and model files
|
|
114
|
+
const fields = extractFieldsFromInterface(interfaceFile);
|
|
115
|
+
if (fields.length > 0) {
|
|
116
|
+
console.log(` đ Extracted ${fields.length} fields: ${fields.map(f => f.name).join(', ')}`);
|
|
117
|
+
const camelCaseName = toCamelCase(moduleDir);
|
|
118
|
+
// Await to ensure sequential processing (prevents Postman API conflicts)
|
|
119
|
+
yield updateAllDocumentation(camelCaseName, fields, options);
|
|
120
|
+
updatedCount++;
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
console.warn(` â ī¸ No fields found in ${moduleDir} interface`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
else {
|
|
127
|
+
console.warn(`â ī¸ Interface file not found for module: ${moduleDir}`);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
console.error(`â Error processing module ${moduleDir}:`, error);
|
|
132
|
+
console.error(` Details: ${error instanceof Error ? error.message : String(error)}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
console.log(`â
Updated documentation for ${updatedCount} modules`);
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
// Enhanced field extraction from both interface and model files
|
|
139
|
+
function extractFieldsFromInterface(interfaceFilePath) {
|
|
140
|
+
try {
|
|
141
|
+
const moduleDir = path.dirname(interfaceFilePath);
|
|
142
|
+
const moduleName = path.basename(interfaceFilePath, '.interface.ts');
|
|
143
|
+
const modelFilePath = path.join(moduleDir, `${moduleName}.model.ts`);
|
|
144
|
+
// Read both interface and model files
|
|
145
|
+
const interfaceContent = fs.readFileSync(interfaceFilePath, "utf-8");
|
|
146
|
+
let modelContent = "";
|
|
147
|
+
if (fs.existsSync(modelFilePath)) {
|
|
148
|
+
modelContent = fs.readFileSync(modelFilePath, "utf-8");
|
|
149
|
+
}
|
|
150
|
+
const fields = [];
|
|
151
|
+
// Extract nested interface definitions first
|
|
152
|
+
const nestedInterfaces = extractNestedInterfaces(interfaceContent);
|
|
153
|
+
// Extract enum definitions from the interface file
|
|
154
|
+
const enumDefinitions = extractEnumDefinitions(interfaceContent);
|
|
155
|
+
// Find the main interface definition (starts with 'I' and is the main entity interface)
|
|
156
|
+
// Use a more robust approach to find the correct interface
|
|
157
|
+
let mainInterfaceBody = "";
|
|
158
|
+
// Split content by interface definitions and find the main one
|
|
159
|
+
const interfaceRegex = /export interface (I\w+)\s*\{([\s\S]*?)\}/g;
|
|
160
|
+
let match;
|
|
161
|
+
while ((match = interfaceRegex.exec(interfaceContent)) !== null) {
|
|
162
|
+
const [, interfaceName, body] = match;
|
|
163
|
+
// The main interface usually has _id field and more content
|
|
164
|
+
if (body.includes('_id') && body.includes('Types.ObjectId')) {
|
|
165
|
+
mainInterfaceBody = body;
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (!mainInterfaceBody) {
|
|
170
|
+
// Fallback: find any interface starting with 'I'
|
|
171
|
+
const fallbackMatch = interfaceContent.match(/export interface I\w+\s*\{([\s\S]*?)\}/);
|
|
172
|
+
if (fallbackMatch) {
|
|
173
|
+
mainInterfaceBody = fallbackMatch[1];
|
|
174
|
+
}
|
|
175
|
+
else {
|
|
176
|
+
return fields;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const lines = mainInterfaceBody.split('\n');
|
|
180
|
+
for (const line of lines) {
|
|
181
|
+
const trimmedLine = line.trim();
|
|
182
|
+
if (!trimmedLine || trimmedLine.startsWith('//') || trimmedLine.startsWith('_id') || trimmedLine.includes('createdAt') || trimmedLine.includes('updatedAt')) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
// Enhanced field parsing: fieldName?: Type;
|
|
186
|
+
const fieldMatch = trimmedLine.match(/(\w+)(\?)?:\s*([^;]+);?/);
|
|
187
|
+
if (fieldMatch) {
|
|
188
|
+
const [, name, optional, typeStr] = fieldMatch;
|
|
189
|
+
const isOptional = !!optional;
|
|
190
|
+
// Get additional info from model file
|
|
191
|
+
const modelFieldInfo = extractFieldInfoFromModel(name, modelContent);
|
|
192
|
+
// Enhanced type mapping with enum support
|
|
193
|
+
const fieldDef = mapTypeScriptTypeToFieldDefinition(name, typeStr, isOptional, modelFieldInfo, nestedInterfaces, enumDefinitions);
|
|
194
|
+
if (fieldDef) {
|
|
195
|
+
fields.push(fieldDef);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return fields;
|
|
200
|
+
}
|
|
201
|
+
catch (error) {
|
|
202
|
+
console.error("Error extracting fields from interface:", error);
|
|
203
|
+
return [];
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
// Extract enum definitions from interface file
|
|
207
|
+
function extractEnumDefinitions(content) {
|
|
208
|
+
const enumMap = new Map();
|
|
209
|
+
// Match TypeScript enum definitions: export enum EnumName { VALUE1 = 'value1', VALUE2 = 'value2' }
|
|
210
|
+
const enumRegex = /export enum (\w+)\s*\{([\s\S]*?)\}/g;
|
|
211
|
+
let match;
|
|
212
|
+
while ((match = enumRegex.exec(content)) !== null) {
|
|
213
|
+
const [, enumName, enumBody] = match;
|
|
214
|
+
const values = [];
|
|
215
|
+
// Extract enum values - handle both 'KEY = "value"' and 'KEY = value' formats
|
|
216
|
+
const valueRegex = /\w+\s*=\s*['"]([^'"]+)['"]/g;
|
|
217
|
+
let valueMatch;
|
|
218
|
+
while ((valueMatch = valueRegex.exec(enumBody)) !== null) {
|
|
219
|
+
values.push(valueMatch[1]);
|
|
220
|
+
}
|
|
221
|
+
if (values.length > 0) {
|
|
222
|
+
enumMap.set(enumName, values);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return enumMap;
|
|
226
|
+
}
|
|
227
|
+
// Extract nested interface definitions
|
|
228
|
+
function extractNestedInterfaces(content) {
|
|
229
|
+
const nestedInterfaces = new Map();
|
|
230
|
+
// Find all interface definitions using a more robust approach
|
|
231
|
+
const interfaceRegex = /export interface (\w+)\s*\{([\s\S]*?)\}/g;
|
|
232
|
+
let match;
|
|
233
|
+
while ((match = interfaceRegex.exec(content)) !== null) {
|
|
234
|
+
const [, interfaceName, interfaceBody] = match;
|
|
235
|
+
// Skip the main interface (starts with 'I' and has more than 1 character after 'I')
|
|
236
|
+
if (interfaceName.startsWith('I') && interfaceName.length > 1 && interfaceName !== 'ItemsItem') {
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
// Skip type definitions
|
|
240
|
+
if (interfaceName.includes('Model') || interfaceName.includes('Type')) {
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
const fields = [];
|
|
244
|
+
const lines = interfaceBody.split('\n');
|
|
245
|
+
for (const line of lines) {
|
|
246
|
+
const trimmedLine = line.trim();
|
|
247
|
+
if (!trimmedLine || trimmedLine.startsWith('//'))
|
|
248
|
+
continue;
|
|
249
|
+
const fieldMatch = trimmedLine.match(/(\w+)(\?)?:\s*([^;]+);?/);
|
|
250
|
+
if (fieldMatch) {
|
|
251
|
+
const [, name, optional, typeStr] = fieldMatch;
|
|
252
|
+
const isOptional = !!optional;
|
|
253
|
+
fields.push({
|
|
254
|
+
name,
|
|
255
|
+
type: mapSimpleType(typeStr),
|
|
256
|
+
isOptional,
|
|
257
|
+
isRequired: !isOptional
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (fields.length > 0) {
|
|
262
|
+
nestedInterfaces.set(interfaceName, fields);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return nestedInterfaces;
|
|
266
|
+
}
|
|
267
|
+
// Extract field information from model file
|
|
268
|
+
function extractFieldInfoFromModel(fieldName, modelContent) {
|
|
269
|
+
if (!modelContent)
|
|
270
|
+
return null;
|
|
271
|
+
try {
|
|
272
|
+
// Look for field definition in schema - handle multiline definitions
|
|
273
|
+
const fieldRegex = new RegExp(`${fieldName}:\\s*\\{([^}]+)\\}`, 'i');
|
|
274
|
+
const match = modelContent.match(fieldRegex);
|
|
275
|
+
if (match) {
|
|
276
|
+
const fieldDef = match[1].trim();
|
|
277
|
+
// Extract enum values if present
|
|
278
|
+
const enumMatch = fieldDef.match(/enum:\s*\[([^\]]+)\]/);
|
|
279
|
+
if (enumMatch) {
|
|
280
|
+
const enumValues = enumMatch[1].split(',').map(v => v.trim().replace(/['"]/g, ''));
|
|
281
|
+
return { enumValues, isEnum: true };
|
|
282
|
+
}
|
|
283
|
+
// Extract reference information
|
|
284
|
+
const refMatch = fieldDef.match(/ref:\s*['"]([^'"]+)['"]/);
|
|
285
|
+
if (refMatch) {
|
|
286
|
+
return { ref: refMatch[1], isReference: true };
|
|
287
|
+
}
|
|
288
|
+
// Check if it's an array
|
|
289
|
+
if (fieldDef.includes('[') && fieldDef.includes(']')) {
|
|
290
|
+
return { isArray: true };
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
// Fallback: look for simpler field definitions
|
|
294
|
+
const simpleFieldRegex = new RegExp(`${fieldName}:\\s*([^,}]+)`, 'i');
|
|
295
|
+
const simpleMatch = modelContent.match(simpleFieldRegex);
|
|
296
|
+
if (simpleMatch) {
|
|
297
|
+
const fieldDef = simpleMatch[1].trim();
|
|
298
|
+
// Extract enum values from simple definitions
|
|
299
|
+
const enumMatch = fieldDef.match(/enum:\s*\[([^\]]+)\]/);
|
|
300
|
+
if (enumMatch) {
|
|
301
|
+
const enumValues = enumMatch[1].split(',').map(v => v.trim().replace(/['"]/g, ''));
|
|
302
|
+
return { enumValues, isEnum: true };
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
return null;
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
return null;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
// Enhanced type mapping function
|
|
312
|
+
function mapTypeScriptTypeToFieldDefinition(name, typeStr, isOptional, modelInfo, nestedInterfaces, enumDefinitions) {
|
|
313
|
+
// Check if typeStr is an enum type reference (e.g., "TypeEnum")
|
|
314
|
+
if (enumDefinitions && enumDefinitions.has(typeStr.trim())) {
|
|
315
|
+
const enumValues = enumDefinitions.get(typeStr.trim());
|
|
316
|
+
return {
|
|
317
|
+
name,
|
|
318
|
+
type: "enum",
|
|
319
|
+
enumValues: enumValues || [],
|
|
320
|
+
isOptional,
|
|
321
|
+
isRequired: !isOptional
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
// Handle enum types from model or interface
|
|
325
|
+
if ((modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.isEnum) && modelInfo.enumValues) {
|
|
326
|
+
return {
|
|
327
|
+
name,
|
|
328
|
+
type: "enum",
|
|
329
|
+
enumValues: modelInfo.enumValues,
|
|
330
|
+
isOptional,
|
|
331
|
+
isRequired: !isOptional
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
// Check if it's a union type enum in the interface (e.g., 'active' | 'inactive')
|
|
335
|
+
if (typeStr.includes('|')) {
|
|
336
|
+
const enumValues = typeStr.split('|').map(v => v.trim().replace(/['"]/g, ''));
|
|
337
|
+
return {
|
|
338
|
+
name,
|
|
339
|
+
type: "enum",
|
|
340
|
+
enumValues,
|
|
341
|
+
isOptional,
|
|
342
|
+
isRequired: !isOptional
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
// Handle ObjectId references
|
|
346
|
+
if (typeStr.includes("Types.ObjectId") || typeStr.includes("ObjectId")) {
|
|
347
|
+
if (typeStr.includes("[]")) {
|
|
348
|
+
// Array of ObjectIds
|
|
349
|
+
return {
|
|
350
|
+
name,
|
|
351
|
+
type: "array",
|
|
352
|
+
arrayItemType: "objectid",
|
|
353
|
+
ref: (modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.ref) || "Document",
|
|
354
|
+
isOptional,
|
|
355
|
+
isRequired: !isOptional
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
// Single ObjectId
|
|
360
|
+
return {
|
|
361
|
+
name,
|
|
362
|
+
type: "objectid",
|
|
363
|
+
ref: (modelInfo === null || modelInfo === void 0 ? void 0 : modelInfo.ref) || "Document",
|
|
364
|
+
isOptional,
|
|
365
|
+
isRequired: !isOptional
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
// Handle arrays
|
|
370
|
+
if (typeStr.includes("[]")) {
|
|
371
|
+
const baseType = typeStr.replace("[]", "").trim();
|
|
372
|
+
// Check if it's an array of nested interface objects
|
|
373
|
+
if (nestedInterfaces.has(baseType)) {
|
|
374
|
+
const objectProperties = nestedInterfaces.get(baseType) || [];
|
|
375
|
+
return {
|
|
376
|
+
name,
|
|
377
|
+
type: "array",
|
|
378
|
+
ref: "object",
|
|
379
|
+
objectProperties,
|
|
380
|
+
isOptional,
|
|
381
|
+
isRequired: !isOptional
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
// Handle basic array types with proper arrayItemType
|
|
385
|
+
const arrayItemType = mapSimpleType(baseType);
|
|
386
|
+
return {
|
|
387
|
+
name,
|
|
388
|
+
type: "array",
|
|
389
|
+
arrayItemType,
|
|
390
|
+
isOptional,
|
|
391
|
+
isRequired: !isOptional
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
// Handle nested objects
|
|
395
|
+
if (nestedInterfaces.has(typeStr)) {
|
|
396
|
+
const objectProperties = nestedInterfaces.get(typeStr) || [];
|
|
397
|
+
return {
|
|
398
|
+
name,
|
|
399
|
+
type: "object",
|
|
400
|
+
objectProperties,
|
|
401
|
+
isOptional,
|
|
402
|
+
isRequired: !isOptional
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
// Handle basic types
|
|
406
|
+
return {
|
|
407
|
+
name,
|
|
408
|
+
type: mapSimpleType(typeStr),
|
|
409
|
+
isOptional,
|
|
410
|
+
isRequired: !isOptional
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
// Simple type mapping helper
|
|
414
|
+
function mapSimpleType(typeStr) {
|
|
415
|
+
const cleanType = typeStr.toLowerCase().trim();
|
|
416
|
+
if (cleanType.includes("string"))
|
|
417
|
+
return "string";
|
|
418
|
+
if (cleanType.includes("number"))
|
|
419
|
+
return "number";
|
|
420
|
+
if (cleanType.includes("boolean"))
|
|
421
|
+
return "boolean";
|
|
422
|
+
if (cleanType.includes("date"))
|
|
423
|
+
return "date";
|
|
424
|
+
if (cleanType.includes("objectid"))
|
|
425
|
+
return "objectid";
|
|
426
|
+
return "string"; // Default fallback
|
|
427
|
+
}
|
|
428
|
+
function toCamelCase(str) {
|
|
429
|
+
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
430
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseFieldDefinitions = parseFieldDefinitions;
|
|
4
|
+
function parseFieldDefinitions(args) {
|
|
5
|
+
const fields = [];
|
|
6
|
+
const skipFiles = [];
|
|
7
|
+
let skipMode = false;
|
|
8
|
+
let hasFile = false;
|
|
9
|
+
for (let i = 0; i < args.length; i++) {
|
|
10
|
+
const arg = args[i];
|
|
11
|
+
if (arg === "--skip") {
|
|
12
|
+
skipMode = true;
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (arg === "--file:true" || arg === "file:true") {
|
|
16
|
+
hasFile = true;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (skipMode) {
|
|
20
|
+
skipFiles.push(arg);
|
|
21
|
+
}
|
|
22
|
+
else {
|
|
23
|
+
try {
|
|
24
|
+
// Check if the argument contains enum values
|
|
25
|
+
const enumMatch = arg.match(/^([a-zA-Z0-9_]+(?:\?|!)?)\[([^\]]+)\]$/);
|
|
26
|
+
if (enumMatch) {
|
|
27
|
+
// This is an enum field with values in square brackets
|
|
28
|
+
let [, name, enumValues] = enumMatch;
|
|
29
|
+
const enumOptions = enumValues.split(",").map((v) => v.trim());
|
|
30
|
+
// Check for optional marker (?)
|
|
31
|
+
const isOptional = name.endsWith("?");
|
|
32
|
+
if (isOptional) {
|
|
33
|
+
name = name.slice(0, -1);
|
|
34
|
+
}
|
|
35
|
+
// Check for required marker (!)
|
|
36
|
+
const isRequired = name.endsWith("!");
|
|
37
|
+
if (isRequired) {
|
|
38
|
+
name = name.slice(0, -1);
|
|
39
|
+
}
|
|
40
|
+
fields.push({
|
|
41
|
+
name,
|
|
42
|
+
type: "enum",
|
|
43
|
+
enumValues: enumOptions,
|
|
44
|
+
isRequired,
|
|
45
|
+
isOptional,
|
|
46
|
+
});
|
|
47
|
+
console.log(`Added enum field: ${name} with values [${enumOptions.join(", ")}]`);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
// Process as field definition
|
|
51
|
+
const parts = arg.split(":");
|
|
52
|
+
if (parts.length >= 2) {
|
|
53
|
+
let name = parts[0].trim();
|
|
54
|
+
const typeRaw = parts[1].trim(); // Don't lowercase yet to preserve enum values if any
|
|
55
|
+
let type = typeRaw.toLowerCase();
|
|
56
|
+
// Check if type follows enum[a,b] pattern
|
|
57
|
+
const typeEnumMatch = typeRaw.match(/^enum\[([^\]]+)\]$/i);
|
|
58
|
+
if (typeEnumMatch) {
|
|
59
|
+
const enumValues = typeEnumMatch[1].split(",").map((v) => v.trim());
|
|
60
|
+
// Check for optional marker (?)
|
|
61
|
+
const isOptional = name.endsWith("?");
|
|
62
|
+
if (isOptional) {
|
|
63
|
+
name = name.slice(0, -1);
|
|
64
|
+
}
|
|
65
|
+
// Check for required marker (!)
|
|
66
|
+
const isRequired = name.endsWith("!");
|
|
67
|
+
if (isRequired) {
|
|
68
|
+
name = name.slice(0, -1);
|
|
69
|
+
}
|
|
70
|
+
fields.push({
|
|
71
|
+
name,
|
|
72
|
+
type: "enum",
|
|
73
|
+
enumValues,
|
|
74
|
+
isRequired,
|
|
75
|
+
isOptional,
|
|
76
|
+
});
|
|
77
|
+
console.log(`Added enum field: ${name} with values [${enumValues.join(", ")}]`);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
// Skip _id field as it's automatically handled by MongoDB
|
|
81
|
+
if (name.toLowerCase() === "_id") {
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
// Check for optional marker (?)
|
|
85
|
+
const isOptional = name.endsWith("?");
|
|
86
|
+
if (isOptional) {
|
|
87
|
+
name = name.slice(0, -1);
|
|
88
|
+
}
|
|
89
|
+
// Check for required marker (!)
|
|
90
|
+
const isRequired = name.endsWith("!");
|
|
91
|
+
if (isRequired) {
|
|
92
|
+
name = name.slice(0, -1);
|
|
93
|
+
}
|
|
94
|
+
// Handle array of objects with properties
|
|
95
|
+
if (type === "array" &&
|
|
96
|
+
parts.length > 2 &&
|
|
97
|
+
parts[2].toLowerCase() === "object") {
|
|
98
|
+
console.log(`Processing array of objects field: ${name}`);
|
|
99
|
+
const objectProperties = [];
|
|
100
|
+
for (let j = 3; j < parts.length; j += 2) {
|
|
101
|
+
if (j + 1 < parts.length) {
|
|
102
|
+
let propName = parts[j];
|
|
103
|
+
const propType = parts[j + 1];
|
|
104
|
+
console.log(` Property: ${propName}:${propType}`);
|
|
105
|
+
const propIsOptional = propName.endsWith("?");
|
|
106
|
+
const propIsRequired = propName.endsWith("!");
|
|
107
|
+
if (propIsOptional) {
|
|
108
|
+
propName = propName.slice(0, -1);
|
|
109
|
+
}
|
|
110
|
+
if (propIsRequired) {
|
|
111
|
+
propName = propName.slice(0, -1);
|
|
112
|
+
}
|
|
113
|
+
objectProperties.push({
|
|
114
|
+
name: propName,
|
|
115
|
+
type: propType,
|
|
116
|
+
isOptional: propIsOptional,
|
|
117
|
+
isRequired: propIsRequired,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
fields.push({
|
|
122
|
+
name,
|
|
123
|
+
type,
|
|
124
|
+
ref: "object",
|
|
125
|
+
isRequired,
|
|
126
|
+
isOptional,
|
|
127
|
+
objectProperties,
|
|
128
|
+
});
|
|
129
|
+
console.log(`Added field with ${objectProperties.length} properties`);
|
|
130
|
+
}
|
|
131
|
+
else if (type === "array" && parts.length > 2) {
|
|
132
|
+
// Handle array of references (e.g., products:array:objectid:Product)
|
|
133
|
+
const arrayItemType = parts[2].toLowerCase();
|
|
134
|
+
let ref = parts.length > 3 ? parts[3].trim() : undefined;
|
|
135
|
+
fields.push({
|
|
136
|
+
name,
|
|
137
|
+
type,
|
|
138
|
+
arrayItemType,
|
|
139
|
+
ref,
|
|
140
|
+
isRequired,
|
|
141
|
+
isOptional,
|
|
142
|
+
});
|
|
143
|
+
console.log(`Added array field: ${name}:${type}:${arrayItemType}${ref ? `:${ref}` : ""}`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Regular field
|
|
147
|
+
const ref = parts.length > 2 ? parts[2].trim() : undefined;
|
|
148
|
+
fields.push({ name, type, ref, isRequired, isOptional });
|
|
149
|
+
console.log(`Added regular field: ${name}:${type}${ref ? `:${ref}` : ""}`);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
console.error(`Error parsing field definition: ${arg}`, error);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
console.log("Parsed fields:", JSON.stringify(fields, null, 2));
|
|
160
|
+
if (hasFile)
|
|
161
|
+
console.log("đ File upload support enabled");
|
|
162
|
+
return { fields, skipFiles, hasFile };
|
|
163
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.generateFileHelper = generateFileHelper;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
function generateFileHelper(baseDir = 'src') {
|
|
40
|
+
const helpersDir = path.join(process.cwd(), baseDir, 'helpers');
|
|
41
|
+
const filePath = path.join(helpersDir, 'fileHelper.ts');
|
|
42
|
+
// Create helpers directory if it doesn't exist
|
|
43
|
+
if (!fs.existsSync(helpersDir)) {
|
|
44
|
+
fs.mkdirSync(helpersDir, { recursive: true });
|
|
45
|
+
console.log(`â
Created directory: ${helpersDir}`);
|
|
46
|
+
}
|
|
47
|
+
// Define the content for the file helper
|
|
48
|
+
const content = `import fs from 'fs/promises';
|
|
49
|
+
import path from 'path';
|
|
50
|
+
|
|
51
|
+
async function removeFile(filenames: string | string[]) {
|
|
52
|
+
if (!filenames || (Array.isArray(filenames) && filenames.length === 0)) return;
|
|
53
|
+
|
|
54
|
+
// Normalize to array for consistent handling
|
|
55
|
+
const files = Array.isArray(filenames) ? filenames : [filenames];
|
|
56
|
+
|
|
57
|
+
for (const filename of files) {
|
|
58
|
+
if (!filename) continue;
|
|
59
|
+
|
|
60
|
+
// Remove leading '/images/' if included
|
|
61
|
+
const cleanedName = filename.replace(/^\/?images\//, '');
|
|
62
|
+
const filePath = path.join(process.cwd(), 'uploads', 'images', cleanedName);
|
|
63
|
+
|
|
64
|
+
try {
|
|
65
|
+
await fs.unlink(filePath);
|
|
66
|
+
console.log(\`Deleted image: \${cleanedName}\`);
|
|
67
|
+
} catch (err) {
|
|
68
|
+
if ((err as NodeJS.ErrnoException).code === 'ENOENT') {
|
|
69
|
+
console.warn(\`File not found: \${cleanedName}\`);
|
|
70
|
+
} else {
|
|
71
|
+
console.error(\`Error deleting file \${cleanedName}:\`, err);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export default removeFile;
|
|
78
|
+
`;
|
|
79
|
+
// Write file if it doesn't exist
|
|
80
|
+
if (!fs.existsSync(filePath)) {
|
|
81
|
+
fs.writeFileSync(filePath, content);
|
|
82
|
+
console.log(`â
Created file: ${filePath}`);
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
console.log(`âšī¸ File already exists: ${filePath}`);
|
|
86
|
+
}
|
|
87
|
+
}
|