@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.
Files changed (38) hide show
  1. package/CHANGELOG.md +194 -0
  2. package/COMMAND_REFERENCE.md +412 -0
  3. package/README.md +486 -0
  4. package/dist/app/modules/imagemodule/imagemodule.constants.js +18 -0
  5. package/dist/app/modules/imagemodule/imagemodule.controller.js +98 -0
  6. package/dist/app/modules/imagemodule/imagemodule.interface.js +2 -0
  7. package/dist/app/modules/imagemodule/imagemodule.model.js +10 -0
  8. package/dist/app/modules/imagemodule/imagemodule.route.js +20 -0
  9. package/dist/app/modules/imagemodule/imagemodule.service.js +137 -0
  10. package/dist/app/modules/imagemodule/imagemodule.validation.js +12 -0
  11. package/dist/app/modules/skiptest/skiptest.controller.js +81 -0
  12. package/dist/app/modules/skiptest/skiptest.route.js +19 -0
  13. package/dist/app/modules/skiptest/skiptest.service.js +129 -0
  14. package/dist/app/modules/skiptest/skiptest.validation.js +12 -0
  15. package/dist/app/modules/testmodule/testmodule.constants.js +18 -0
  16. package/dist/app/modules/testmodule/testmodule.controller.js +81 -0
  17. package/dist/app/modules/testmodule/testmodule.interface.js +2 -0
  18. package/dist/app/modules/testmodule/testmodule.model.js +11 -0
  19. package/dist/app/modules/testmodule/testmodule.route.js +19 -0
  20. package/dist/app/modules/testmodule/testmodule.service.js +129 -0
  21. package/dist/app/modules/testmodule/testmodule.validation.js +14 -0
  22. package/dist/helpers/fileHelper.js +44 -0
  23. package/dist/index.js +586 -0
  24. package/dist/templates/constants.template.js +24 -0
  25. package/dist/templates/controller.template.js +108 -0
  26. package/dist/templates/route.template.js +68 -0
  27. package/dist/templates/service.template.js +184 -0
  28. package/dist/types.js +2 -0
  29. package/dist/utils/documentationUpdater.js +430 -0
  30. package/dist/utils/fieldParser.js +163 -0
  31. package/dist/utils/helperGenerator.js +87 -0
  32. package/dist/utils/interfaceGenerator.js +158 -0
  33. package/dist/utils/modelGenerator.js +140 -0
  34. package/dist/utils/postmanApi.js +113 -0
  35. package/dist/utils/postmanGenerator.js +283 -0
  36. package/dist/utils/swaggerGenerator.js +444 -0
  37. package/dist/utils/validationGenerator.js +170 -0
  38. 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
+ }