@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,108 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateControllerContent = void 0;
|
|
4
|
+
const generateControllerContent = (camelCaseName, folderName, fields) => {
|
|
5
|
+
// Check if there are any file/image fields
|
|
6
|
+
const hasImageField = fields.some((field) => field.name === "image" || field.name === "images" || field.name === "media" || field.type.toLowerCase() === "image");
|
|
7
|
+
// Generate filterable fields (string and enum types)
|
|
8
|
+
const filterableFields = fields.filter(f => f.type.toLowerCase() === "string" || f.type.toLowerCase() === "enum");
|
|
9
|
+
return `import { Request, Response } from 'express';
|
|
10
|
+
import { ${camelCaseName}Services } from './${folderName}.service';
|
|
11
|
+
import catchAsync from '../../../shared/catchAsync';
|
|
12
|
+
import sendResponse from '../../../shared/sendResponse';
|
|
13
|
+
import { StatusCodes } from 'http-status-codes';
|
|
14
|
+
import pick from '../../../shared/pick';
|
|
15
|
+
import { ${folderName}Filterables } from './${folderName}.constants';
|
|
16
|
+
import { paginationFields } from '../../../interfaces/pagination';
|
|
17
|
+
|
|
18
|
+
const create${camelCaseName} = catchAsync(async (req: Request, res: Response) => {
|
|
19
|
+
${hasImageField
|
|
20
|
+
? `const { images, media, ...${folderName}Data } = req.body;
|
|
21
|
+
|
|
22
|
+
if (images && images.length > 0) {
|
|
23
|
+
${folderName}Data.images = images;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (media && media.length > 0) {
|
|
27
|
+
${folderName}Data.media = media;
|
|
28
|
+
}`
|
|
29
|
+
: `const ${folderName}Data = req.body;`}
|
|
30
|
+
|
|
31
|
+
const result = await ${camelCaseName}Services.create${camelCaseName}(
|
|
32
|
+
req.user!,
|
|
33
|
+
${folderName}Data
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
sendResponse(res, {
|
|
37
|
+
statusCode: StatusCodes.CREATED,
|
|
38
|
+
success: true,
|
|
39
|
+
message: '${camelCaseName} created successfully',
|
|
40
|
+
data: result,
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const update${camelCaseName} = catchAsync(async (req: Request, res: Response) => {
|
|
45
|
+
const { id } = req.params;
|
|
46
|
+
const ${folderName}Data = req.body;
|
|
47
|
+
|
|
48
|
+
const result = await ${camelCaseName}Services.update${camelCaseName}(id, ${folderName}Data);
|
|
49
|
+
|
|
50
|
+
sendResponse(res, {
|
|
51
|
+
statusCode: StatusCodes.OK,
|
|
52
|
+
success: true,
|
|
53
|
+
message: '${camelCaseName} updated successfully',
|
|
54
|
+
data: result,
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const getSingle${camelCaseName} = catchAsync(async (req: Request, res: Response) => {
|
|
59
|
+
const { id } = req.params;
|
|
60
|
+
const result = await ${camelCaseName}Services.getSingle${camelCaseName}(id);
|
|
61
|
+
|
|
62
|
+
sendResponse(res, {
|
|
63
|
+
statusCode: StatusCodes.OK,
|
|
64
|
+
success: true,
|
|
65
|
+
message: '${camelCaseName} retrieved successfully',
|
|
66
|
+
data: result,
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
const getAll${camelCaseName}s = catchAsync(async (req: Request, res: Response) => {
|
|
71
|
+
const filterables = pick(req.query, ${folderName}Filterables);
|
|
72
|
+
const pagination = pick(req.query, paginationFields);
|
|
73
|
+
|
|
74
|
+
const result = await ${camelCaseName}Services.getAll${camelCaseName}s(
|
|
75
|
+
req.user!,
|
|
76
|
+
filterables,
|
|
77
|
+
pagination
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
sendResponse(res, {
|
|
81
|
+
statusCode: StatusCodes.OK,
|
|
82
|
+
success: true,
|
|
83
|
+
message: '${camelCaseName}s retrieved successfully',
|
|
84
|
+
data: result,
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const delete${camelCaseName} = catchAsync(async (req: Request, res: Response) => {
|
|
89
|
+
const { id } = req.params;
|
|
90
|
+
const result = await ${camelCaseName}Services.delete${camelCaseName}(id);
|
|
91
|
+
|
|
92
|
+
sendResponse(res, {
|
|
93
|
+
statusCode: StatusCodes.OK,
|
|
94
|
+
success: true,
|
|
95
|
+
message: '${camelCaseName} deleted successfully',
|
|
96
|
+
data: result,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
export const ${camelCaseName}Controller = {
|
|
101
|
+
create${camelCaseName},
|
|
102
|
+
update${camelCaseName},
|
|
103
|
+
getSingle${camelCaseName},
|
|
104
|
+
getAll${camelCaseName}s,
|
|
105
|
+
delete${camelCaseName},
|
|
106
|
+
};`;
|
|
107
|
+
};
|
|
108
|
+
exports.generateControllerContent = generateControllerContent;
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateRouteContent = void 0;
|
|
4
|
+
const generateRouteContent = (camelCaseName, folderName, fields) => {
|
|
5
|
+
// Check if there are any file/image fields
|
|
6
|
+
const hasImageField = fields.some((field) => field.name === "image" || field.name === "images" || field.name === "media" || field.type.toLowerCase() === "image");
|
|
7
|
+
return `import express from 'express';
|
|
8
|
+
import { ${camelCaseName}Controller } from './${folderName}.controller';
|
|
9
|
+
import { ${camelCaseName}Validations } from './${folderName}.validation';
|
|
10
|
+
import validateRequest from '../../middleware/validateRequest';
|
|
11
|
+
import auth from '../../middleware/auth';
|
|
12
|
+
import { USER_ROLES } from '../../../enum/user';
|
|
13
|
+
${hasImageField ? `import { fileAndBodyProcessorUsingDiskStorage } from '../../middleware/processReqBody';` : ""}
|
|
14
|
+
|
|
15
|
+
const router = express.Router();
|
|
16
|
+
|
|
17
|
+
router.get(
|
|
18
|
+
'/',
|
|
19
|
+
auth(
|
|
20
|
+
USER_ROLES.SUPER_ADMIN,
|
|
21
|
+
USER_ROLES.ADMIN
|
|
22
|
+
),
|
|
23
|
+
${camelCaseName}Controller.getAll${camelCaseName}s
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
router.get(
|
|
27
|
+
'/:id',
|
|
28
|
+
auth(
|
|
29
|
+
USER_ROLES.SUPER_ADMIN,
|
|
30
|
+
USER_ROLES.ADMIN
|
|
31
|
+
),
|
|
32
|
+
${camelCaseName}Controller.getSingle${camelCaseName}
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
router.post(
|
|
36
|
+
'/',
|
|
37
|
+
auth(
|
|
38
|
+
USER_ROLES.SUPER_ADMIN,
|
|
39
|
+
USER_ROLES.ADMIN
|
|
40
|
+
),
|
|
41
|
+
${hasImageField ? `fileAndBodyProcessorUsingDiskStorage(),` : ""}
|
|
42
|
+
validateRequest(${camelCaseName}Validations.create${camelCaseName}ZodSchema),
|
|
43
|
+
${camelCaseName}Controller.create${camelCaseName}
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
router.patch(
|
|
47
|
+
'/:id',
|
|
48
|
+
auth(
|
|
49
|
+
USER_ROLES.SUPER_ADMIN,
|
|
50
|
+
USER_ROLES.ADMIN
|
|
51
|
+
),
|
|
52
|
+
${hasImageField ? `fileAndBodyProcessorUsingDiskStorage(),` : ""}
|
|
53
|
+
validateRequest(${camelCaseName}Validations.update${camelCaseName}ZodSchema),
|
|
54
|
+
${camelCaseName}Controller.update${camelCaseName}
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
router.delete(
|
|
58
|
+
'/:id',
|
|
59
|
+
auth(
|
|
60
|
+
USER_ROLES.SUPER_ADMIN,
|
|
61
|
+
USER_ROLES.ADMIN
|
|
62
|
+
),
|
|
63
|
+
${camelCaseName}Controller.delete${camelCaseName}
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
export const ${camelCaseName}Routes = router;`;
|
|
67
|
+
};
|
|
68
|
+
exports.generateRouteContent = generateRouteContent;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateServiceContent = void 0;
|
|
4
|
+
const generateServiceContent = (camelCaseName, folderName, fields, hasFile = false) => {
|
|
5
|
+
// Check if there are any file/image fields or if hasFile flag is true
|
|
6
|
+
const hasImageField = hasFile || fields.some((field) => field.name === "image" || field.name === "images" || field.name === "media" || field.type.toLowerCase() === "image");
|
|
7
|
+
// Check for reference fields for population
|
|
8
|
+
const referenceFields = fields.filter((field) => {
|
|
9
|
+
var _a;
|
|
10
|
+
return field.type.toLowerCase() === "objectid" ||
|
|
11
|
+
(field.type.toLowerCase() === "array" && ((_a = field.arrayItemType) === null || _a === void 0 ? void 0 : _a.toLowerCase()) === "objectid");
|
|
12
|
+
});
|
|
13
|
+
const populateString = referenceFields.length > 0
|
|
14
|
+
? `.populate('${referenceFields.map(f => f.name).join("').populate('")}')`
|
|
15
|
+
: "";
|
|
16
|
+
// Generate filterable fields (string and enum types)
|
|
17
|
+
const filterableFields = fields.filter(f => f.type.toLowerCase() === "string" || f.type.toLowerCase() === "enum");
|
|
18
|
+
// Generate searchable fields (string types only)
|
|
19
|
+
const searchableFields = fields.filter(f => f.type.toLowerCase() === "string");
|
|
20
|
+
return `import { StatusCodes } from 'http-status-codes';
|
|
21
|
+
import ApiError from '../../../errors/ApiError';
|
|
22
|
+
import { I${camelCaseName}Filterables, I${camelCaseName} } from './${folderName}.interface';
|
|
23
|
+
import { ${camelCaseName} } from './${folderName}.model';
|
|
24
|
+
import { JwtPayload } from 'jsonwebtoken';
|
|
25
|
+
import { IPaginationOptions } from '../../../interfaces/pagination';
|
|
26
|
+
import { paginationHelper } from '../../../helpers/paginationHelper';
|
|
27
|
+
import { ${folderName}SearchableFields } from './${folderName}.constants';
|
|
28
|
+
import { Types } from 'mongoose';
|
|
29
|
+
${hasImageField
|
|
30
|
+
? `import removeFile from '../../../helpers/fileHelper';`
|
|
31
|
+
: ""}
|
|
32
|
+
|
|
33
|
+
const create${camelCaseName} = async (
|
|
34
|
+
user: JwtPayload,
|
|
35
|
+
payload: I${camelCaseName}
|
|
36
|
+
): Promise<I${camelCaseName}> => {
|
|
37
|
+
try {
|
|
38
|
+
const result = await ${camelCaseName}.create(payload);
|
|
39
|
+
if (!result) {
|
|
40
|
+
${hasImageField ? `await removeFile(payload.images || payload.media);` : ""}
|
|
41
|
+
throw new ApiError(
|
|
42
|
+
StatusCodes.BAD_REQUEST,
|
|
43
|
+
'Failed to create ${camelCaseName}, please try again with valid data.'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return result;
|
|
48
|
+
} catch (error: any) {
|
|
49
|
+
${hasImageField ? `if (payload.images || payload.media) await removeFile(payload.images || payload.media);` : ""}
|
|
50
|
+
if (error.code === 11000) {
|
|
51
|
+
throw new ApiError(StatusCodes.CONFLICT, 'Duplicate entry found');
|
|
52
|
+
}
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const getAll${camelCaseName}s = async (
|
|
58
|
+
user: JwtPayload,
|
|
59
|
+
filterables: I${camelCaseName}Filterables,
|
|
60
|
+
pagination: IPaginationOptions
|
|
61
|
+
) => {
|
|
62
|
+
const { searchTerm, ...filterData } = filterables;
|
|
63
|
+
const { page, skip, limit, sortBy, sortOrder } = paginationHelper.calculatePagination(pagination);
|
|
64
|
+
|
|
65
|
+
const andConditions = [];
|
|
66
|
+
|
|
67
|
+
// Search functionality
|
|
68
|
+
if (searchTerm) {
|
|
69
|
+
andConditions.push({
|
|
70
|
+
$or: ${folderName}SearchableFields.map((field) => ({
|
|
71
|
+
[field]: {
|
|
72
|
+
$regex: searchTerm,
|
|
73
|
+
$options: 'i',
|
|
74
|
+
},
|
|
75
|
+
})),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
// Filter functionality
|
|
80
|
+
if (Object.keys(filterData).length) {
|
|
81
|
+
andConditions.push({
|
|
82
|
+
$and: Object.entries(filterData).map(([key, value]) => ({
|
|
83
|
+
[key]: value,
|
|
84
|
+
})),
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const whereConditions = andConditions.length ? { $and: andConditions } : {};
|
|
89
|
+
|
|
90
|
+
const [result, total] = await Promise.all([
|
|
91
|
+
${camelCaseName}
|
|
92
|
+
.find(whereConditions)
|
|
93
|
+
.skip(skip)
|
|
94
|
+
.limit(limit)
|
|
95
|
+
.sort({ [sortBy]: sortOrder })${populateString},
|
|
96
|
+
${camelCaseName}.countDocuments(whereConditions),
|
|
97
|
+
]);
|
|
98
|
+
|
|
99
|
+
return {
|
|
100
|
+
meta: {
|
|
101
|
+
page,
|
|
102
|
+
limit,
|
|
103
|
+
total,
|
|
104
|
+
totalPages: Math.ceil(total / limit),
|
|
105
|
+
},
|
|
106
|
+
data: result,
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const getSingle${camelCaseName} = async (id: string): Promise<I${camelCaseName}> => {
|
|
111
|
+
if (!Types.ObjectId.isValid(id)) {
|
|
112
|
+
throw new ApiError(StatusCodes.BAD_REQUEST, 'Invalid ${camelCaseName} ID');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const result = await ${camelCaseName}.findById(id)${populateString};
|
|
116
|
+
if (!result) {
|
|
117
|
+
throw new ApiError(
|
|
118
|
+
StatusCodes.NOT_FOUND,
|
|
119
|
+
'Requested ${folderName} not found, please try again with valid id'
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return result;
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
const update${camelCaseName} = async (
|
|
127
|
+
id: string,
|
|
128
|
+
payload: Partial<I${camelCaseName}>
|
|
129
|
+
): Promise<I${camelCaseName} | null> => {
|
|
130
|
+
if (!Types.ObjectId.isValid(id)) {
|
|
131
|
+
throw new ApiError(StatusCodes.BAD_REQUEST, 'Invalid ${camelCaseName} ID');
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const result = await ${camelCaseName}.findByIdAndUpdate(
|
|
135
|
+
new Types.ObjectId(id),
|
|
136
|
+
{ $set: payload },
|
|
137
|
+
{
|
|
138
|
+
new: true,
|
|
139
|
+
runValidators: true,
|
|
140
|
+
}
|
|
141
|
+
)${populateString};
|
|
142
|
+
|
|
143
|
+
if (!result) {
|
|
144
|
+
throw new ApiError(
|
|
145
|
+
StatusCodes.NOT_FOUND,
|
|
146
|
+
'Requested ${folderName} not found, please try again with valid id'
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return result;
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const delete${camelCaseName} = async (id: string): Promise<I${camelCaseName}> => {
|
|
154
|
+
if (!Types.ObjectId.isValid(id)) {
|
|
155
|
+
throw new ApiError(StatusCodes.BAD_REQUEST, 'Invalid ${camelCaseName} ID');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
const result = await ${camelCaseName}.findByIdAndDelete(id);
|
|
159
|
+
if (!result) {
|
|
160
|
+
throw new ApiError(
|
|
161
|
+
StatusCodes.NOT_FOUND,
|
|
162
|
+
'Something went wrong while deleting ${folderName}, please try again with valid id.'
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
${hasImageField
|
|
167
|
+
? `// Remove associated files
|
|
168
|
+
if (result.image || result.images || result.media) {
|
|
169
|
+
await removeFile(result.image || result.images || result.media);
|
|
170
|
+
}`
|
|
171
|
+
: ""}
|
|
172
|
+
|
|
173
|
+
return result;
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
export const ${camelCaseName}Services = {
|
|
177
|
+
create${camelCaseName},
|
|
178
|
+
getAll${camelCaseName}s,
|
|
179
|
+
getSingle${camelCaseName},
|
|
180
|
+
update${camelCaseName},
|
|
181
|
+
delete${camelCaseName},
|
|
182
|
+
};`;
|
|
183
|
+
};
|
|
184
|
+
exports.generateServiceContent = generateServiceContent;
|
package/dist/types.js
ADDED