opticore-feature-component 1.0.0 → 1.0.2
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/README.md +214 -173
- package/dist/{core-ED52ORJA.js → core-GNR24GXE.js} +614 -238
- package/dist/index.cjs +647 -252
- package/dist/index.js +1 -1
- package/package.json +42 -40
package/dist/index.cjs
CHANGED
|
@@ -35,16 +35,35 @@ var init_cjs_shims = __esm({
|
|
|
35
35
|
|
|
36
36
|
// src/utils/welcomeMessage.utils.ts
|
|
37
37
|
function UWelcomeMessage() {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
import_cfonts.default.say("OpticoreJS", {
|
|
39
|
+
font: "block",
|
|
40
|
+
align: "left",
|
|
41
|
+
colors: ["yellow", "#FF6B35"],
|
|
42
|
+
background: "transparent",
|
|
43
|
+
letterSpacing: 1,
|
|
44
|
+
lineHeight: 1,
|
|
45
|
+
space: true,
|
|
46
|
+
maxLength: "0"
|
|
47
|
+
});
|
|
48
|
+
const blue = import_chalk.default.bold.hex("#00D4FF");
|
|
49
|
+
const orange = import_chalk.default.bold.hex("#FF6B35");
|
|
50
|
+
const dim = import_chalk.default.bold.yellow;
|
|
51
|
+
const subTitle = ` ${blue("")} ${orange(" OPTICORE F E A T U R E M O D U L E")}
|
|
52
|
+
${blue("")} ${dim(" Create \xB7 Structure \xB7 Scaffold \xB7 Generate \xB7 Organize ")} ${blue("")}
|
|
53
|
+
${blue("")}`;
|
|
54
|
+
const FOOTER = `
|
|
55
|
+
${import_chalk.default.bold.dim("Documentation")} ${import_chalk.default.underline.cyan("https://github.com/guyzoum77/opticore-feature-cli")}
|
|
56
|
+
`;
|
|
57
|
+
console.log(subTitle);
|
|
58
|
+
console.log(FOOTER);
|
|
41
59
|
}
|
|
42
|
-
var
|
|
60
|
+
var import_cfonts, import_chalk;
|
|
43
61
|
var init_welcomeMessage_utils = __esm({
|
|
44
62
|
"src/utils/welcomeMessage.utils.ts"() {
|
|
45
63
|
"use strict";
|
|
46
64
|
init_cjs_shims();
|
|
47
|
-
|
|
65
|
+
import_cfonts = __toESM(require("cfonts"), 1);
|
|
66
|
+
import_chalk = __toESM(require("chalk"), 1);
|
|
48
67
|
}
|
|
49
68
|
});
|
|
50
69
|
|
|
@@ -173,44 +192,44 @@ var init_choiceFeatureCleanModule = __esm({
|
|
|
173
192
|
}
|
|
174
193
|
});
|
|
175
194
|
|
|
176
|
-
// src/utils/constants/customFeatureInfoMessage.constant.ts
|
|
177
|
-
function customFeatureInfo() {
|
|
178
|
-
console.log(`${import_ansi_colors3.default.bgCyan(`${import_ansi_colors3.default.white("\nYou will have to create and configure your created modules manually.")}`)}`);
|
|
179
|
-
import_process.default.exit(0);
|
|
180
|
-
}
|
|
181
|
-
var import_ansi_colors3, import_process;
|
|
182
|
-
var init_customFeatureInfoMessage_constant = __esm({
|
|
183
|
-
"src/utils/constants/customFeatureInfoMessage.constant.ts"() {
|
|
184
|
-
"use strict";
|
|
185
|
-
init_cjs_shims();
|
|
186
|
-
import_ansi_colors3 = __toESM(require("ansi-colors"), 1);
|
|
187
|
-
import_process = __toESM(require("process"), 1);
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
195
|
// src/utils/customFeatureInfo.utils.ts
|
|
192
196
|
function UCustomFeatureInfo(choice) {
|
|
193
|
-
console.log(
|
|
194
|
-
`
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
`)
|
|
206
|
-
|
|
197
|
+
console.log(
|
|
198
|
+
`
|
|
199
|
+
You have chosen : ${choice === "opticore_clean_module" ? import_ansi_colors3.default.cyan("OptiCoreJs CLEAN Module") : import_ansi_colors3.default.cyan("Custom feature")}
|
|
200
|
+
`
|
|
201
|
+
);
|
|
202
|
+
const I = (s) => import_ansi_colors3.default.yellow(s);
|
|
203
|
+
const A = (s) => import_ansi_colors3.default.cyan(s);
|
|
204
|
+
const D = (s) => import_ansi_colors3.default.yellowBright(s);
|
|
205
|
+
const E = (s) => import_ansi_colors3.default.white(s);
|
|
206
|
+
const st = (s) => import_ansi_colors3.default.gray(s);
|
|
207
|
+
const diagram = [
|
|
208
|
+
` ` + I(`INFRASTRUCTURE`),
|
|
209
|
+
` ` + I(`controllers \xB7 repositories \xB7 routes`),
|
|
210
|
+
` ` + I(`presenters \xB7 routes`),
|
|
211
|
+
``,
|
|
212
|
+
` ` + A(`APPLICATION`),
|
|
213
|
+
` ` + A(`ports \xB7 interfaces \xB7 dtos \xB7 use-cases`),
|
|
214
|
+
``,
|
|
215
|
+
` ` + D(`DOMAIN`),
|
|
216
|
+
` ` + D(`events \xB7 exceptions`),
|
|
217
|
+
``,
|
|
218
|
+
` ` + E(`ENTITIES`),
|
|
219
|
+
` ` + E(`core \xB7 no external deps`),
|
|
220
|
+
``,
|
|
221
|
+
` ` + import_ansi_colors3.default.dim(`Dependency direction : outer layers depend on inner layers`),
|
|
222
|
+
``
|
|
223
|
+
];
|
|
224
|
+
console.log(diagram.join(`
|
|
225
|
+
`));
|
|
207
226
|
}
|
|
208
|
-
var
|
|
227
|
+
var import_ansi_colors3;
|
|
209
228
|
var init_customFeatureInfo_utils = __esm({
|
|
210
229
|
"src/utils/customFeatureInfo.utils.ts"() {
|
|
211
230
|
"use strict";
|
|
212
231
|
init_cjs_shims();
|
|
213
|
-
|
|
232
|
+
import_ansi_colors3 = __toESM(require("ansi-colors"), 1);
|
|
214
233
|
}
|
|
215
234
|
});
|
|
216
235
|
|
|
@@ -240,20 +259,20 @@ var init_featureName_service = __esm({
|
|
|
240
259
|
});
|
|
241
260
|
|
|
242
261
|
// src/services/base.service.ts
|
|
243
|
-
var import_path, import_node_fs,
|
|
262
|
+
var import_path, import_node_fs, import_ansi_colors4, import_process, BaseService;
|
|
244
263
|
var init_base_service = __esm({
|
|
245
264
|
"src/services/base.service.ts"() {
|
|
246
265
|
"use strict";
|
|
247
266
|
init_cjs_shims();
|
|
248
267
|
import_path = __toESM(require("path"), 1);
|
|
249
268
|
import_node_fs = __toESM(require("fs"), 1);
|
|
250
|
-
|
|
251
|
-
|
|
269
|
+
import_ansi_colors4 = __toESM(require("ansi-colors"), 1);
|
|
270
|
+
import_process = __toESM(require("process"), 1);
|
|
252
271
|
init_fsModule_utils();
|
|
253
272
|
BaseService = class {
|
|
254
273
|
static _isSubdirectoryExists(subdirectory) {
|
|
255
274
|
const subdirectoryString = typeof subdirectory === "symbol" ? subdirectory.toString() : String(subdirectory);
|
|
256
|
-
const subdirectoryPath = import_path.default.join(
|
|
275
|
+
const subdirectoryPath = import_path.default.join(import_process.default.cwd(), "src", "features", subdirectoryString);
|
|
257
276
|
try {
|
|
258
277
|
const stats = import_node_fs.default.statSync(subdirectoryPath);
|
|
259
278
|
return stats.isDirectory();
|
|
@@ -262,27 +281,27 @@ var init_base_service = __esm({
|
|
|
262
281
|
}
|
|
263
282
|
}
|
|
264
283
|
static _featureFounded(feature) {
|
|
265
|
-
console.log(`${
|
|
266
|
-
|
|
284
|
+
console.log(`${import_ansi_colors4.default.bgCyan(`${import_ansi_colors4.default.white(`${import_ansi_colors4.default.bold(`feature ${feature} is already exists.`)}`)}`)}`);
|
|
285
|
+
import_process.default.exit(0);
|
|
267
286
|
}
|
|
268
287
|
static _checkFeatureDir() {
|
|
269
|
-
console.error(`${
|
|
270
|
-
|
|
288
|
+
console.error(`${import_ansi_colors4.default.bgRed(`${import_ansi_colors4.default.white("Check if directory src/features exists, and try again.")}`)}`);
|
|
289
|
+
import_process.default.exit();
|
|
271
290
|
}
|
|
272
291
|
static _dirFounded(feature) {
|
|
273
|
-
console.error(`${
|
|
274
|
-
|
|
292
|
+
console.error(`${import_ansi_colors4.default.bgRed(`${import_ansi_colors4.default.white(`The ${import_ansi_colors4.default.bgCyan(`${import_ansi_colors4.default.bold(`feature ${feature} is already exists.`)}`)}`)}`)}`);
|
|
293
|
+
import_process.default.exit();
|
|
275
294
|
}
|
|
276
295
|
static _cancelOperation(controllerPath) {
|
|
277
|
-
console.log(`${
|
|
296
|
+
console.log(`${import_ansi_colors4.default.bgRed(`${import_ansi_colors4.default.white("Operation cancelled.")}`)}`);
|
|
278
297
|
UFsModule.removeDir(controllerPath, true, true);
|
|
279
|
-
|
|
298
|
+
import_process.default.exit(0);
|
|
280
299
|
}
|
|
281
300
|
static async _createFeatureModuleDir(featureDir, feature) {
|
|
282
301
|
let ora = (await import("ora")).default;
|
|
283
302
|
const spinner = ora("Feature's name creation...").start();
|
|
284
303
|
UFsModule.createDirectoryRecursively(featureDir);
|
|
285
|
-
spinner.succeed(`Your feature"s name ${
|
|
304
|
+
spinner.succeed(`Your feature"s name ${import_ansi_colors4.default.bgCyan(import_ansi_colors4.default.white(`${feature}`))} has been created successfully.
|
|
286
305
|
`);
|
|
287
306
|
return { featureDir, feature };
|
|
288
307
|
}
|
|
@@ -364,13 +383,6 @@ import { ${capitalized}Repository } from "../repositories/${featureName}.reposit
|
|
|
364
383
|
|
|
365
384
|
/**
|
|
366
385
|
* ${controllerName} \u2014 HTTP Controller (Infrastructure Layer)
|
|
367
|
-
*
|
|
368
|
-
* Handles Express Request/Response only.
|
|
369
|
-
* Delegates all business logic to the use case.
|
|
370
|
-
* Uses the presenter to format the output.
|
|
371
|
-
*
|
|
372
|
-
* Wiring: Controller \u2192 UseCase \u2192 Repository (all injected here manually).
|
|
373
|
-
* For larger projects, replace manual wiring with a DI container (e.g., tsyringe, awilix).
|
|
374
386
|
*/
|
|
375
387
|
export class ${controllerName} {
|
|
376
388
|
private static buildUseCase(): ${useCaseName} {
|
|
@@ -498,7 +510,9 @@ ${errorHandler}
|
|
|
498
510
|
`;
|
|
499
511
|
errorHandlerAppend = (capitalized) => `
|
|
500
512
|
private static handleError(error: unknown) {
|
|
501
|
-
const message = error instanceof Error
|
|
513
|
+
const message = error instanceof Error
|
|
514
|
+
? error.message
|
|
515
|
+
: "Internal server error";
|
|
502
516
|
return ResponseHandler.error(message, HttpStatusCode.INTERNAL_SERVER_ERROR);
|
|
503
517
|
}
|
|
504
518
|
`;
|
|
@@ -537,10 +551,6 @@ export class ${entityName} {
|
|
|
537
551
|
this.validate();
|
|
538
552
|
}
|
|
539
553
|
|
|
540
|
-
// -------------------------------------------------------------------------
|
|
541
|
-
// Getters
|
|
542
|
-
// -------------------------------------------------------------------------
|
|
543
|
-
|
|
544
554
|
get id(): string {
|
|
545
555
|
return this._id;
|
|
546
556
|
}
|
|
@@ -553,10 +563,6 @@ export class ${entityName} {
|
|
|
553
563
|
return this._updatedAt;
|
|
554
564
|
}
|
|
555
565
|
|
|
556
|
-
// -------------------------------------------------------------------------
|
|
557
|
-
// Business methods (behavior belongs to the entity)
|
|
558
|
-
// -------------------------------------------------------------------------
|
|
559
|
-
|
|
560
566
|
/**
|
|
561
567
|
* Marks the entity as updated.
|
|
562
568
|
* Call this whenever a business mutation occurs.
|
|
@@ -577,10 +583,6 @@ export class ${entityName} {
|
|
|
577
583
|
};
|
|
578
584
|
}
|
|
579
585
|
|
|
580
|
-
// -------------------------------------------------------------------------
|
|
581
|
-
// Invariant validation (domain rules enforced at construction)
|
|
582
|
-
// -------------------------------------------------------------------------
|
|
583
|
-
|
|
584
586
|
private validate(): void {
|
|
585
587
|
if (!this._id || this._id.trim().length === 0) {
|
|
586
588
|
throw new Error(\`[${entityName}] id must not be empty.\`);
|
|
@@ -674,16 +676,14 @@ export class ${implName} implements ${interfaceName} {
|
|
|
674
676
|
|
|
675
677
|
/**
|
|
676
678
|
* TODO: Inject your database client / ORM model here via the constructor.
|
|
677
|
-
* Example with TypeORM:
|
|
678
|
-
* constructor(private readonly repo: Repository<${capitalized}Model>) {}
|
|
679
|
+
* Example with TypeORM: constructor(private readonly repo: Repository<${capitalized}Model>) {}
|
|
679
680
|
*
|
|
680
|
-
* Example with Prisma:
|
|
681
|
-
* constructor(private readonly prisma: PrismaClient) {}
|
|
681
|
+
* Example with Prisma: constructor(private readonly prisma: PrismaClient) {}
|
|
682
682
|
*/
|
|
683
683
|
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
684
|
+
/**
|
|
685
|
+
* In-memory store (replace with real persistence)
|
|
686
|
+
*/
|
|
687
687
|
private store: Map<string, ${entityName}> = new Map();
|
|
688
688
|
|
|
689
689
|
async findAll(): Promise<${entityName}[]> {
|
|
@@ -726,9 +726,6 @@ export class ${implName} implements ${interfaceName} {
|
|
|
726
726
|
return this.store.delete(id);
|
|
727
727
|
}
|
|
728
728
|
|
|
729
|
-
// -------------------------------------------------------------------------
|
|
730
|
-
// Private mappers (ORM model \u2194 Domain entity)
|
|
731
|
-
// -------------------------------------------------------------------------
|
|
732
729
|
|
|
733
730
|
/**
|
|
734
731
|
* Maps an ORM/DB row to a domain entity.
|
|
@@ -790,13 +787,7 @@ import {
|
|
|
790
787
|
*/
|
|
791
788
|
export class ${useCaseName} {
|
|
792
789
|
|
|
793
|
-
constructor(
|
|
794
|
-
private readonly repository: ${interfaceName},
|
|
795
|
-
) {}
|
|
796
|
-
|
|
797
|
-
// -------------------------------------------------------------------------
|
|
798
|
-
// Query methods (read)
|
|
799
|
-
// -------------------------------------------------------------------------
|
|
790
|
+
constructor(private readonly repository: ${interfaceName}) {}
|
|
800
791
|
|
|
801
792
|
async findAll(): Promise<${capitalized}ResponseDto[]> {
|
|
802
793
|
const entities = await this.repository.findAll();
|
|
@@ -805,14 +796,12 @@ export class ${useCaseName} {
|
|
|
805
796
|
|
|
806
797
|
async findById(id: string): Promise<${capitalized}ResponseDto | null> {
|
|
807
798
|
const entity = await this.repository.findById(id);
|
|
808
|
-
if (!entity)
|
|
799
|
+
if (!entity) {
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
809
802
|
return ${capitalized}DtoMapper.toResponse(entity);
|
|
810
803
|
}
|
|
811
804
|
|
|
812
|
-
// -------------------------------------------------------------------------
|
|
813
|
-
// Command methods (write)
|
|
814
|
-
// -------------------------------------------------------------------------
|
|
815
|
-
|
|
816
805
|
async create(dto: Create${capitalized}Dto): Promise<${capitalized}ResponseDto> {
|
|
817
806
|
// TODO: Map DTO to domain entity. Generate id using your preferred strategy (uuid, etc.)
|
|
818
807
|
const id = crypto.randomUUID();
|
|
@@ -827,14 +816,18 @@ export class ${useCaseName} {
|
|
|
827
816
|
|
|
828
817
|
async update(dto: Update${capitalized}Dto): Promise<${capitalized}ResponseDto | null> {
|
|
829
818
|
const existing = await this.repository.findById(dto.id);
|
|
830
|
-
if (!existing)
|
|
819
|
+
if (!existing) {
|
|
820
|
+
return null;
|
|
821
|
+
}
|
|
831
822
|
|
|
832
823
|
// TODO: Apply the update to the domain entity
|
|
833
824
|
// existing.updateName(dto.name);
|
|
834
825
|
existing.touch();
|
|
835
826
|
|
|
836
827
|
const updated = await this.repository.update(existing);
|
|
837
|
-
if (!updated)
|
|
828
|
+
if (!updated) {
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
838
831
|
return ${capitalized}DtoMapper.toResponse(updated);
|
|
839
832
|
}
|
|
840
833
|
|
|
@@ -864,9 +857,6 @@ var init_dto_template = __esm({
|
|
|
864
857
|
* Validation is handled at the infrastructure layer (e.g., in the controller).
|
|
865
858
|
*/
|
|
866
859
|
|
|
867
|
-
// -------------------------------------------------------------------------
|
|
868
|
-
// Input DTOs (data coming IN to use cases)
|
|
869
|
-
// -------------------------------------------------------------------------
|
|
870
860
|
|
|
871
861
|
export interface Create${capitalized}Dto {
|
|
872
862
|
// TODO: Define the fields required to create a ${featureName}
|
|
@@ -877,28 +867,17 @@ export interface Create${capitalized}Dto {
|
|
|
877
867
|
|
|
878
868
|
export interface Update${capitalized}Dto {
|
|
879
869
|
id: string;
|
|
880
|
-
// TODO: Define the fields allowed to be updated
|
|
881
|
-
//
|
|
882
|
-
// Example:
|
|
883
|
-
// name?: string;
|
|
870
|
+
// TODO: Define the fields allowed to be updated. All fields should be optional (partial update pattern)
|
|
871
|
+
// Example: name?: string;
|
|
884
872
|
}
|
|
885
873
|
|
|
886
|
-
// -------------------------------------------------------------------------
|
|
887
|
-
// Output DTOs (data going OUT from use cases to the controller/presenter)
|
|
888
|
-
// -------------------------------------------------------------------------
|
|
889
|
-
|
|
890
874
|
export interface ${capitalized}ResponseDto {
|
|
891
875
|
id: string;
|
|
892
876
|
createdAt: Date;
|
|
893
877
|
updatedAt: Date;
|
|
894
|
-
// TODO: Mirror the fields you expose to clients
|
|
895
|
-
// Avoid leaking internal domain model details (e.g., private fields, passwords)
|
|
878
|
+
// TODO: Mirror the fields you expose to clients. Avoid leaking internal domain model details (e.g., private fields, passwords)
|
|
896
879
|
}
|
|
897
880
|
|
|
898
|
-
// -------------------------------------------------------------------------
|
|
899
|
-
// Mapper helper (Domain Entity \u2192 Response DTO)
|
|
900
|
-
// -------------------------------------------------------------------------
|
|
901
|
-
|
|
902
881
|
import { ${capitalized}Entity } from "../../domain/entities/${featureName}.entity";
|
|
903
882
|
|
|
904
883
|
export class ${capitalized}DtoMapper {
|
|
@@ -1031,9 +1010,9 @@ var init_router_template = __esm({
|
|
|
1031
1010
|
const handlerName = `${capitalized}HandlerRouter`;
|
|
1032
1011
|
const controllerName = `${capitalized}Controller`;
|
|
1033
1012
|
const routesCode = (controllerMethods || []).map((method) => {
|
|
1034
|
-
const { httpMethod, path:
|
|
1013
|
+
const { httpMethod, path: path8 } = resolveRoute(method, featureName);
|
|
1035
1014
|
return `{
|
|
1036
|
-
path: \`${
|
|
1015
|
+
path: \`${path8}\`,
|
|
1037
1016
|
method: "${httpMethod}",
|
|
1038
1017
|
middlewares: [],
|
|
1039
1018
|
handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
|
|
@@ -1093,24 +1072,22 @@ var init_event_template = __esm({
|
|
|
1093
1072
|
* - Feed an event bus / message broker (RabbitMQ, Kafka, etc.)
|
|
1094
1073
|
* - Build an audit log or event sourcing stream
|
|
1095
1074
|
*/
|
|
1075
|
+
|
|
1096
1076
|
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1077
|
+
/**
|
|
1078
|
+
* Unique event identifier (uuid)
|
|
1079
|
+
* When the event occurred
|
|
1080
|
+
* The aggregate that emitted this event
|
|
1081
|
+
*/
|
|
1101
1082
|
export interface IDomainEvent {
|
|
1102
|
-
/** Unique event identifier (uuid) */
|
|
1103
1083
|
readonly eventId: string;
|
|
1104
|
-
/** When the event occurred */
|
|
1105
1084
|
readonly occurredAt: Date;
|
|
1106
|
-
/** The aggregate that emitted this event */
|
|
1107
1085
|
readonly aggregateId: string;
|
|
1108
1086
|
}
|
|
1109
1087
|
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1088
|
+
/**
|
|
1089
|
+
* Concrete events for the "${featureName}" feature
|
|
1090
|
+
*/
|
|
1114
1091
|
export class ${capitalized}CreatedEvent implements IDomainEvent {
|
|
1115
1092
|
readonly eventId: string;
|
|
1116
1093
|
readonly occurredAt: Date;
|
|
@@ -1176,10 +1153,6 @@ var init_exception_template = __esm({
|
|
|
1176
1153
|
* Rule: never import HTTP status codes or Express here \u2014 this is pure domain logic.
|
|
1177
1154
|
*/
|
|
1178
1155
|
|
|
1179
|
-
// -------------------------------------------------------------------------
|
|
1180
|
-
// Base domain exception
|
|
1181
|
-
// -------------------------------------------------------------------------
|
|
1182
|
-
|
|
1183
1156
|
export class ${capitalized}DomainException extends Error {
|
|
1184
1157
|
/** Machine-readable error code for programmatic handling */
|
|
1185
1158
|
readonly code: string;
|
|
@@ -1194,9 +1167,6 @@ export class ${capitalized}DomainException extends Error {
|
|
|
1194
1167
|
}
|
|
1195
1168
|
}
|
|
1196
1169
|
|
|
1197
|
-
// -------------------------------------------------------------------------
|
|
1198
|
-
// Specific domain exceptions
|
|
1199
|
-
// -------------------------------------------------------------------------
|
|
1200
1170
|
|
|
1201
1171
|
/**
|
|
1202
1172
|
* Thrown when a ${featureName} cannot be found by its identifier.
|
|
@@ -1240,10 +1210,6 @@ export class ${capitalized}InvalidDataException extends ${capitalized}DomainExce
|
|
|
1240
1210
|
}
|
|
1241
1211
|
}
|
|
1242
1212
|
|
|
1243
|
-
// -------------------------------------------------------------------------
|
|
1244
|
-
// Exception guard helper
|
|
1245
|
-
// -------------------------------------------------------------------------
|
|
1246
|
-
|
|
1247
1213
|
/**
|
|
1248
1214
|
* Type guard to check if an unknown error is a ${capitalized}DomainException.
|
|
1249
1215
|
* Use this in your controller's catch block to map domain errors to HTTP responses.
|
|
@@ -1456,7 +1422,9 @@ export class ${serviceName} {
|
|
|
1456
1422
|
|
|
1457
1423
|
async update(id: string, data: Record<string, unknown>): Promise<${modelName} | null> {
|
|
1458
1424
|
const existing = await this.repository.findById(id);
|
|
1459
|
-
if (!existing)
|
|
1425
|
+
if (!existing) {
|
|
1426
|
+
return null;
|
|
1427
|
+
}
|
|
1460
1428
|
// TODO: Apply data fields onto existing model
|
|
1461
1429
|
return this.repository.update(existing);
|
|
1462
1430
|
}
|
|
@@ -1500,11 +1468,21 @@ ${methodsCode}
|
|
|
1500
1468
|
};
|
|
1501
1469
|
generateMethod2 = (method, capitalized, serviceName) => {
|
|
1502
1470
|
const lower = method.toLowerCase();
|
|
1503
|
-
if (lower.includes("findall") || lower.includes("getall"))
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
if (lower.includes("
|
|
1507
|
-
|
|
1471
|
+
if (lower.includes("findall") || lower.includes("getall")) {
|
|
1472
|
+
return generateFindAllMethod2(method, capitalized);
|
|
1473
|
+
}
|
|
1474
|
+
if (lower.includes("findbyid") || lower.includes("getbyid") || lower.includes("getone")) {
|
|
1475
|
+
return generateFindByIdMethod2(method, capitalized);
|
|
1476
|
+
}
|
|
1477
|
+
if (lower.includes("create") || lower.includes("add")) {
|
|
1478
|
+
return generateCreateMethod2(method, capitalized);
|
|
1479
|
+
}
|
|
1480
|
+
if (lower.includes("update") || lower.includes("edit")) {
|
|
1481
|
+
return generateUpdateMethod2(method, capitalized);
|
|
1482
|
+
}
|
|
1483
|
+
if (lower.includes("delete") || lower.includes("remove")) {
|
|
1484
|
+
return generateDeleteMethod2(method, capitalized);
|
|
1485
|
+
}
|
|
1508
1486
|
return `
|
|
1509
1487
|
static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
|
|
1510
1488
|
try {
|
|
@@ -1608,9 +1586,9 @@ var init_simpleRouter_template = __esm({
|
|
|
1608
1586
|
const handlerName = `${capitalized}HandlerRouter`;
|
|
1609
1587
|
const controllerName = `${capitalized}Controller`;
|
|
1610
1588
|
const routesCode = (controllerMethods || []).map((method) => {
|
|
1611
|
-
const { httpMethod, path:
|
|
1589
|
+
const { httpMethod, path: path8 } = resolveRoute2(method, featureName);
|
|
1612
1590
|
return `{
|
|
1613
|
-
path: \`${
|
|
1591
|
+
path: \`${path8}\`,
|
|
1614
1592
|
method: "${httpMethod}",
|
|
1615
1593
|
middlewares: [],
|
|
1616
1594
|
handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
|
|
@@ -1651,13 +1629,13 @@ export const ${routerName}: TFeatureRoutes = {
|
|
|
1651
1629
|
});
|
|
1652
1630
|
|
|
1653
1631
|
// src/utils/featureComponentGenerator.utils.ts
|
|
1654
|
-
var import_path2,
|
|
1632
|
+
var import_path2, import_ansi_colors5, import_fs2, import_opticore_logger2, FeatureComponentGeneratorUtils;
|
|
1655
1633
|
var init_featureComponentGenerator_utils = __esm({
|
|
1656
1634
|
"src/utils/featureComponentGenerator.utils.ts"() {
|
|
1657
1635
|
"use strict";
|
|
1658
1636
|
init_cjs_shims();
|
|
1659
1637
|
import_path2 = __toESM(require("path"), 1);
|
|
1660
|
-
|
|
1638
|
+
import_ansi_colors5 = __toESM(require("ansi-colors"), 1);
|
|
1661
1639
|
import_fs2 = __toESM(require("fs"), 1);
|
|
1662
1640
|
init_prompt_utils();
|
|
1663
1641
|
init_fsModule_utils();
|
|
@@ -1685,107 +1663,101 @@ var init_featureComponentGenerator_utils = __esm({
|
|
|
1685
1663
|
static setStructure(s) {
|
|
1686
1664
|
this.structure = s;
|
|
1687
1665
|
}
|
|
1666
|
+
/**
|
|
1667
|
+
* Registers a custom module router in register.router.ts.
|
|
1668
|
+
* Must be preceded by setStructure("custom").
|
|
1669
|
+
*/
|
|
1670
|
+
static async registerModuleRouter(moduleName) {
|
|
1671
|
+
await this.updateRegisterRouter(moduleName);
|
|
1672
|
+
this.structure = "clean";
|
|
1673
|
+
}
|
|
1688
1674
|
/**
|
|
1689
1675
|
* Creates the domain entity file.
|
|
1690
|
-
* File: domain/entities/<featureName>.entity.ts
|
|
1691
1676
|
*/
|
|
1692
1677
|
static async createEntity(featureName, entityDir) {
|
|
1693
1678
|
const entityName = `${this.capitalize(featureName)}Entity`;
|
|
1694
1679
|
const filePath = import_path2.default.join(entityDir, `${featureName}.entity.ts`);
|
|
1695
1680
|
UFsModule.createFile(filePath, generateEntityTemplate(entityName, featureName));
|
|
1696
|
-
console.log(
|
|
1681
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Entity created: ${filePath}`));
|
|
1697
1682
|
}
|
|
1698
1683
|
/**
|
|
1699
1684
|
* Creates the domain event file.
|
|
1700
|
-
* File: domain/events/<featureName>.event.ts
|
|
1701
1685
|
*/
|
|
1702
1686
|
static async createEvent(featureName, eventDir) {
|
|
1703
1687
|
const filePath = import_path2.default.join(eventDir, `${featureName}.event.ts`);
|
|
1704
1688
|
UFsModule.createFile(filePath, generateEventTemplate(featureName));
|
|
1705
|
-
console.log(
|
|
1689
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Event created: ${filePath}`));
|
|
1706
1690
|
}
|
|
1707
1691
|
/**
|
|
1708
1692
|
* Creates the domain exception file.
|
|
1709
|
-
* File: domain/exceptions/<featureName>.exception.ts
|
|
1710
1693
|
*/
|
|
1711
1694
|
static async createException(featureName, exceptionDir) {
|
|
1712
1695
|
const filePath = import_path2.default.join(exceptionDir, `${featureName}.exception.ts`);
|
|
1713
1696
|
UFsModule.createFile(filePath, generateExceptionTemplate(featureName));
|
|
1714
|
-
console.log(
|
|
1697
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Exception created: ${filePath}`));
|
|
1715
1698
|
}
|
|
1716
1699
|
/**
|
|
1717
1700
|
* Creates the repository port interface.
|
|
1718
|
-
* File: application/ports/repositories/<featureName>.repository.interface.ts
|
|
1719
1701
|
*/
|
|
1720
1702
|
static async createRepositoryInterface(featureName, interfaceDir) {
|
|
1721
1703
|
const interfaceName = `I${this.capitalize(featureName)}Repository`;
|
|
1722
1704
|
const filePath = import_path2.default.join(interfaceDir, `${featureName}.repository.interface.ts`);
|
|
1723
1705
|
UFsModule.createFile(filePath, generateRepositoryInterfaceTemplate(interfaceName, featureName));
|
|
1724
|
-
console.log(
|
|
1706
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Repository interface created: ${filePath}`));
|
|
1725
1707
|
}
|
|
1726
1708
|
/**
|
|
1727
1709
|
* Creates the presenter port interface.
|
|
1728
|
-
* File: application/ports/presenters/<featureName>.presenter.interface.ts
|
|
1729
1710
|
*/
|
|
1730
1711
|
static async createPresenterInterface(featureName, presenterInterfaceDir) {
|
|
1731
1712
|
const filePath = import_path2.default.join(presenterInterfaceDir, `${featureName}.presenter.interface.ts`);
|
|
1732
1713
|
UFsModule.createFile(filePath, generatePresenterInterfaceTemplate(featureName));
|
|
1733
|
-
console.log(
|
|
1714
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Presenter interface created: ${filePath}`));
|
|
1734
1715
|
}
|
|
1735
1716
|
/**
|
|
1736
1717
|
* Creates the application service port interface.
|
|
1737
|
-
* File: application/ports/services/<featureName>.service.ts
|
|
1738
1718
|
*/
|
|
1739
1719
|
static async createService(featureName, serviceDir) {
|
|
1740
1720
|
const filePath = import_path2.default.join(serviceDir, `${featureName}.service.ts`);
|
|
1741
1721
|
UFsModule.createFile(filePath, generateServiceTemplate(featureName));
|
|
1742
|
-
console.log(
|
|
1722
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Service interface created: ${filePath}`));
|
|
1743
1723
|
}
|
|
1744
1724
|
/**
|
|
1745
1725
|
* Creates the DTO file (input + output shapes + mapper).
|
|
1746
|
-
* File: application/dtos/<featureName>.dto.ts
|
|
1747
1726
|
*/
|
|
1748
1727
|
static async createDto(featureName, dtoDir) {
|
|
1749
1728
|
const filePath = import_path2.default.join(dtoDir, `${featureName}.dto.ts`);
|
|
1750
1729
|
UFsModule.createFile(filePath, generateDtoTemplate(featureName));
|
|
1751
|
-
console.log(
|
|
1730
|
+
console.log(import_ansi_colors5.default.green(`\u2705 DTO created: ${filePath}`));
|
|
1752
1731
|
}
|
|
1753
1732
|
/**
|
|
1754
1733
|
* Creates the use case file.
|
|
1755
|
-
* File: application/use-cases/<featureName>.usecase.ts
|
|
1756
1734
|
*/
|
|
1757
1735
|
static async createUseCase(featureName, useCaseDir) {
|
|
1758
1736
|
const useCaseName = `${this.capitalize(featureName)}UseCase`;
|
|
1759
1737
|
const filePath = import_path2.default.join(useCaseDir, `${featureName}.usecase.ts`);
|
|
1760
1738
|
UFsModule.createFile(filePath, generateUseCaseTemplate(useCaseName, featureName));
|
|
1761
|
-
console.log(
|
|
1739
|
+
console.log(import_ansi_colors5.default.green(`\u2705 UseCase created: ${filePath}`));
|
|
1762
1740
|
}
|
|
1763
|
-
// =========================================================================
|
|
1764
|
-
// INFRASTRUCTURE LAYER
|
|
1765
|
-
// =========================================================================
|
|
1766
1741
|
/**
|
|
1767
1742
|
* Creates the concrete repository implementation.
|
|
1768
|
-
* File: infrastructure/adapters/repositories/<featureName>.repository.ts
|
|
1769
1743
|
*/
|
|
1770
1744
|
static async createRepositoryImpl(featureName, repositoryImplDir) {
|
|
1771
1745
|
const interfaceImportPath = `../../../application/ports/repositories/${featureName}.repository.interface`;
|
|
1772
1746
|
const filePath = import_path2.default.join(repositoryImplDir, `${featureName}.repository.ts`);
|
|
1773
1747
|
UFsModule.createFile(filePath, generateRepositoryImplTemplate(featureName, interfaceImportPath));
|
|
1774
|
-
console.log(
|
|
1748
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Repository implementation created: ${filePath}`));
|
|
1775
1749
|
}
|
|
1776
1750
|
/**
|
|
1777
1751
|
* Creates the concrete presenter implementation.
|
|
1778
|
-
* File: infrastructure/adapters/presenters/<featureName>.presenter.ts
|
|
1779
1752
|
*/
|
|
1780
1753
|
static async createPresenterImpl(featureName, presenterImplDir) {
|
|
1781
1754
|
const filePath = import_path2.default.join(presenterImplDir, `${featureName}.presenter.ts`);
|
|
1782
1755
|
UFsModule.createFile(filePath, generatePresenterImplTemplate(featureName));
|
|
1783
|
-
console.log(
|
|
1756
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Presenter implementation created: ${filePath}`));
|
|
1784
1757
|
}
|
|
1785
1758
|
/**
|
|
1786
1759
|
* Creates the HTTP controller.
|
|
1787
1760
|
* Prompts the user for method names, then generates the file.
|
|
1788
|
-
* File: infrastructure/adapters/controllers/<featureName>.controller.ts
|
|
1789
1761
|
*
|
|
1790
1762
|
* @returns The controller class name and the list of chosen methods.
|
|
1791
1763
|
*/
|
|
@@ -1810,39 +1782,35 @@ export class ${controllerName} {}
|
|
|
1810
1782
|
`;
|
|
1811
1783
|
}
|
|
1812
1784
|
UFsModule.createFile(filePath, content);
|
|
1813
|
-
console.log(
|
|
1785
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Controller created: ${filePath}`));
|
|
1814
1786
|
return { controllerName, methods };
|
|
1815
1787
|
}
|
|
1816
1788
|
/**
|
|
1817
1789
|
* Creates the data model file (simple component).
|
|
1818
|
-
* File: models/<featureName>.model.ts
|
|
1819
1790
|
*/
|
|
1820
1791
|
static async createModel(featureName, modelDir) {
|
|
1821
1792
|
const filePath = import_path2.default.join(modelDir, `${featureName}.model.ts`);
|
|
1822
1793
|
UFsModule.createFile(filePath, generateModelTemplate(featureName));
|
|
1823
|
-
console.log(
|
|
1794
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Model created: ${filePath}`));
|
|
1824
1795
|
}
|
|
1825
1796
|
/**
|
|
1826
1797
|
* Creates the simple repository (no interface, uses the model directly).
|
|
1827
|
-
* File: repositories/<featureName>.repository.ts
|
|
1828
1798
|
*/
|
|
1829
1799
|
static async createSimpleRepository(featureName, repositoryDir) {
|
|
1830
1800
|
const filePath = import_path2.default.join(repositoryDir, `${featureName}.repository.ts`);
|
|
1831
1801
|
UFsModule.createFile(filePath, generateSimpleRepositoryTemplate(featureName));
|
|
1832
|
-
console.log(
|
|
1802
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Repository created: ${filePath}`));
|
|
1833
1803
|
}
|
|
1834
1804
|
/**
|
|
1835
1805
|
* Creates the simple concrete service (no interface, wires the repository).
|
|
1836
|
-
* File: services/<featureName>.service.ts
|
|
1837
1806
|
*/
|
|
1838
1807
|
static async createSimpleService(featureName, serviceDir) {
|
|
1839
1808
|
const filePath = import_path2.default.join(serviceDir, `${featureName}.service.ts`);
|
|
1840
1809
|
UFsModule.createFile(filePath, generateSimpleServiceTemplate(featureName));
|
|
1841
|
-
console.log(
|
|
1810
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Service created: ${filePath}`));
|
|
1842
1811
|
}
|
|
1843
1812
|
/**
|
|
1844
1813
|
* Creates the simple controller (delegates to service, no use-case/presenter).
|
|
1845
|
-
* File: controllers/<featureName>.controller.ts
|
|
1846
1814
|
*/
|
|
1847
1815
|
static async createSimpleController(featureName, controllerDir) {
|
|
1848
1816
|
const controllerName = `${this.capitalize(featureName)}Controller`;
|
|
@@ -1865,31 +1833,29 @@ export class ${controllerName} {}
|
|
|
1865
1833
|
`;
|
|
1866
1834
|
}
|
|
1867
1835
|
UFsModule.createFile(filePath, content);
|
|
1868
|
-
console.log(
|
|
1836
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Controller created: ${filePath}`));
|
|
1869
1837
|
return { controllerName, methods };
|
|
1870
1838
|
}
|
|
1871
1839
|
/**
|
|
1872
1840
|
* Creates the route handler (HTTP verb + path → controller method bindings).
|
|
1873
|
-
*
|
|
1874
|
-
* routes/<featureName>.router.handler.ts (simple)
|
|
1841
|
+
*
|
|
1875
1842
|
*/
|
|
1876
1843
|
static async createRouterHandler(featureName, routerHandlerDir, controllerMethods) {
|
|
1877
1844
|
const filePath = import_path2.default.join(routerHandlerDir, `${featureName}.router.handler.ts`);
|
|
1878
1845
|
const content = this.structure === "simple" ? generateSimpleRouterHandlerTemplate(featureName, controllerMethods) : generateRouterHandlerTemplate(featureName, controllerMethods);
|
|
1879
1846
|
UFsModule.createFile(filePath, content);
|
|
1880
|
-
console.log(
|
|
1847
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Router Handler created: ${filePath}`));
|
|
1881
1848
|
}
|
|
1882
1849
|
/**
|
|
1883
1850
|
* Creates the feature router and registers it in register.router.ts.
|
|
1884
|
-
*
|
|
1885
|
-
* routes/<featureName>.router.ts (simple)
|
|
1851
|
+
*
|
|
1886
1852
|
*/
|
|
1887
1853
|
static async createRouter(featureName, routerDir) {
|
|
1888
1854
|
const filePath = import_path2.default.join(routerDir, `${featureName}.router.ts`);
|
|
1889
1855
|
const content = this.structure === "simple" ? generateSimpleRouterTemplate(featureName) : generateRouterTemplate(featureName);
|
|
1890
1856
|
UFsModule.createFile(filePath, content);
|
|
1891
1857
|
await this.updateRegisterRouter(featureName);
|
|
1892
|
-
console.log(
|
|
1858
|
+
console.log(import_ansi_colors5.default.green(`\u2705 Router created: ${filePath}`));
|
|
1893
1859
|
}
|
|
1894
1860
|
static capitalize(str) {
|
|
1895
1861
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
@@ -1899,18 +1865,18 @@ export class ${controllerName} {}
|
|
|
1899
1865
|
*/
|
|
1900
1866
|
static async updateRegisterRouter(featureName) {
|
|
1901
1867
|
const routerName = `${this.capitalize(featureName)}Router`;
|
|
1902
|
-
const routerPath = this.structure === "simple" ? `../../features/${featureName}/routes/${featureName}.router` : `../../features/${featureName}/infrastructure/routes/${featureName}.router`;
|
|
1868
|
+
const routerPath = this.structure === "simple" ? `../../features/${featureName}/routes/${featureName}.router` : this.structure === "custom" ? `../../features/${featureName}/${featureName}.router` : `../../features/${featureName}/infrastructure/routes/${featureName}.router`;
|
|
1903
1869
|
const importStatement = `import { ${routerName} } from "${routerPath}"`;
|
|
1904
1870
|
try {
|
|
1905
1871
|
if (!import_fs2.default.existsSync(this.REGISTER_ROUTER_PATH)) {
|
|
1906
1872
|
console.log(
|
|
1907
|
-
|
|
1873
|
+
import_ansi_colors5.default.yellow(`\u26A0\uFE0F register.router.ts not found at ${this.REGISTER_ROUTER_PATH}, skipping auto-registration.`)
|
|
1908
1874
|
);
|
|
1909
1875
|
return;
|
|
1910
1876
|
}
|
|
1911
1877
|
let content = import_fs2.default.readFileSync(this.REGISTER_ROUTER_PATH, "utf-8");
|
|
1912
1878
|
if (content.includes(`import { ${routerName} } from`)) {
|
|
1913
|
-
console.log(
|
|
1879
|
+
console.log(import_ansi_colors5.default.cyan(`\u2139\uFE0F ${routerName} is already registered.`));
|
|
1914
1880
|
return;
|
|
1915
1881
|
}
|
|
1916
1882
|
const lines = content.split("\n");
|
|
@@ -1928,12 +1894,12 @@ export class ${controllerName} {}
|
|
|
1928
1894
|
const ARRAY_CLOSE = "]);";
|
|
1929
1895
|
const startIdx = content.indexOf(ARRAY_OPEN);
|
|
1930
1896
|
if (startIdx === -1) {
|
|
1931
|
-
console.log(
|
|
1897
|
+
console.log(import_ansi_colors5.default.yellow(`\u26A0\uFE0F Could not find 'registered([' in register.router.ts.`));
|
|
1932
1898
|
return;
|
|
1933
1899
|
}
|
|
1934
1900
|
const endIdx = content.indexOf(ARRAY_CLOSE, startIdx + ARRAY_OPEN.length);
|
|
1935
1901
|
if (endIdx === -1) {
|
|
1936
|
-
console.log(
|
|
1902
|
+
console.log(import_ansi_colors5.default.yellow(`\u26A0\uFE0F Could not find matching ']);' in register.router.ts.`));
|
|
1937
1903
|
return;
|
|
1938
1904
|
}
|
|
1939
1905
|
const arrayContent = content.substring(startIdx + ARRAY_OPEN.length, endIdx);
|
|
@@ -1946,9 +1912,9 @@ export class ${controllerName} {}
|
|
|
1946
1912
|
${indentedRoutes}
|
|
1947
1913
|
` + content.substring(endIdx);
|
|
1948
1914
|
import_fs2.default.writeFileSync(this.REGISTER_ROUTER_PATH, newContent, "utf-8");
|
|
1949
|
-
console.log(
|
|
1915
|
+
console.log(import_ansi_colors5.default.green(`\u2705 register.router.ts updated with ${routerName}.`));
|
|
1950
1916
|
} catch (error) {
|
|
1951
|
-
console.error(
|
|
1917
|
+
console.error(import_ansi_colors5.default.red(`\u274C Failed to update register.router.ts: ${error.message}`));
|
|
1952
1918
|
}
|
|
1953
1919
|
}
|
|
1954
1920
|
};
|
|
@@ -1956,13 +1922,13 @@ ${indentedRoutes}
|
|
|
1956
1922
|
});
|
|
1957
1923
|
|
|
1958
1924
|
// src/templates/simpleComponent/simpleComponent.template.ts
|
|
1959
|
-
var import_path3,
|
|
1925
|
+
var import_path3, import_ansi_colors6, simpleComponentTemplate;
|
|
1960
1926
|
var init_simpleComponent_template = __esm({
|
|
1961
1927
|
"src/templates/simpleComponent/simpleComponent.template.ts"() {
|
|
1962
1928
|
"use strict";
|
|
1963
1929
|
init_cjs_shims();
|
|
1964
1930
|
import_path3 = __toESM(require("path"), 1);
|
|
1965
|
-
|
|
1931
|
+
import_ansi_colors6 = __toESM(require("ansi-colors"), 1);
|
|
1966
1932
|
init_fsModule_utils();
|
|
1967
1933
|
init_featureComponentGenerator_utils();
|
|
1968
1934
|
simpleComponentTemplate = async (featureName) => {
|
|
@@ -1993,8 +1959,8 @@ var init_simpleComponent_template = __esm({
|
|
|
1993
1959
|
await FeatureComponentGeneratorUtils.createRouterHandler(featureName, paths.routesDir, controller.methods);
|
|
1994
1960
|
await FeatureComponentGeneratorUtils.createRouter(featureName, paths.routesDir);
|
|
1995
1961
|
console.log(
|
|
1996
|
-
|
|
1997
|
-
|
|
1962
|
+
import_ansi_colors6.default.bgGreen(
|
|
1963
|
+
import_ansi_colors6.default.white(`
|
|
1998
1964
|
\u{1F389} Feature "${featureName}" scaffolded with Simple Component!
|
|
1999
1965
|
`)
|
|
2000
1966
|
)
|
|
@@ -2004,29 +1970,26 @@ var init_simpleComponent_template = __esm({
|
|
|
2004
1970
|
});
|
|
2005
1971
|
|
|
2006
1972
|
// src/templates/fullCleanComponent/fullCleanComponent.template.ts
|
|
2007
|
-
var import_path4,
|
|
1973
|
+
var import_path4, import_ansi_colors7, fullCleanComponentTemplate;
|
|
2008
1974
|
var init_fullCleanComponent_template = __esm({
|
|
2009
1975
|
"src/templates/fullCleanComponent/fullCleanComponent.template.ts"() {
|
|
2010
1976
|
"use strict";
|
|
2011
1977
|
init_cjs_shims();
|
|
2012
1978
|
import_path4 = __toESM(require("path"), 1);
|
|
2013
|
-
|
|
1979
|
+
import_ansi_colors7 = __toESM(require("ansi-colors"), 1);
|
|
2014
1980
|
init_fsModule_utils();
|
|
2015
1981
|
init_featureComponentGenerator_utils();
|
|
2016
1982
|
fullCleanComponentTemplate = async (featureName) => {
|
|
2017
1983
|
const basePath = import_path4.default.join("src", "features", featureName);
|
|
2018
1984
|
const dirs = [
|
|
2019
|
-
// Domain
|
|
2020
1985
|
import_path4.default.join(basePath, "domain", "entities"),
|
|
2021
1986
|
import_path4.default.join(basePath, "domain", "events"),
|
|
2022
1987
|
import_path4.default.join(basePath, "domain", "exceptions"),
|
|
2023
|
-
// Application
|
|
2024
1988
|
import_path4.default.join(basePath, "application", "use-cases"),
|
|
2025
1989
|
import_path4.default.join(basePath, "application", "dtos"),
|
|
2026
1990
|
import_path4.default.join(basePath, "application", "ports", "repositories"),
|
|
2027
1991
|
import_path4.default.join(basePath, "application", "ports", "presenters"),
|
|
2028
1992
|
import_path4.default.join(basePath, "application", "ports", "services"),
|
|
2029
|
-
// Infrastructure
|
|
2030
1993
|
import_path4.default.join(basePath, "infrastructure", "adapters", "controllers"),
|
|
2031
1994
|
import_path4.default.join(basePath, "infrastructure", "adapters", "repositories"),
|
|
2032
1995
|
import_path4.default.join(basePath, "infrastructure", "adapters", "presenters"),
|
|
@@ -2034,17 +1997,14 @@ var init_fullCleanComponent_template = __esm({
|
|
|
2034
1997
|
];
|
|
2035
1998
|
dirs.forEach((dir) => UFsModule.createDirectoryRecursively(dir));
|
|
2036
1999
|
const paths = {
|
|
2037
|
-
// Domain
|
|
2038
2000
|
entityDir: import_path4.default.join(basePath, "domain", "entities"),
|
|
2039
2001
|
eventDir: import_path4.default.join(basePath, "domain", "events"),
|
|
2040
2002
|
exceptionDir: import_path4.default.join(basePath, "domain", "exceptions"),
|
|
2041
|
-
// Application
|
|
2042
2003
|
repositoryInterfaceDir: import_path4.default.join(basePath, "application", "ports", "repositories"),
|
|
2043
2004
|
presenterInterfaceDir: import_path4.default.join(basePath, "application", "ports", "presenters"),
|
|
2044
2005
|
serviceDir: import_path4.default.join(basePath, "application", "ports", "services"),
|
|
2045
2006
|
dtoDir: import_path4.default.join(basePath, "application", "dtos"),
|
|
2046
2007
|
useCaseDir: import_path4.default.join(basePath, "application", "use-cases"),
|
|
2047
|
-
// Infrastructure
|
|
2048
2008
|
repositoryImplDir: import_path4.default.join(basePath, "infrastructure", "adapters", "repositories"),
|
|
2049
2009
|
presenterImplDir: import_path4.default.join(basePath, "infrastructure", "adapters", "presenters"),
|
|
2050
2010
|
controllerDir: import_path4.default.join(basePath, "infrastructure", "adapters", "controllers"),
|
|
@@ -2067,8 +2027,8 @@ var init_fullCleanComponent_template = __esm({
|
|
|
2067
2027
|
await FeatureComponentGeneratorUtils.createRouterHandler(featureName, paths.routerDir, controller.methods);
|
|
2068
2028
|
await FeatureComponentGeneratorUtils.createRouter(featureName, paths.routerDir);
|
|
2069
2029
|
console.log(
|
|
2070
|
-
|
|
2071
|
-
|
|
2030
|
+
import_ansi_colors7.default.bgGreen(
|
|
2031
|
+
import_ansi_colors7.default.white(`
|
|
2072
2032
|
\u{1F389} Feature "${featureName}" scaffolded with Clean Architecture!
|
|
2073
2033
|
`)
|
|
2074
2034
|
)
|
|
@@ -2078,19 +2038,21 @@ var init_fullCleanComponent_template = __esm({
|
|
|
2078
2038
|
});
|
|
2079
2039
|
|
|
2080
2040
|
// src/templates/cleanComponentByStep/cleanComponentByStep.template.ts
|
|
2081
|
-
var import_path5,
|
|
2041
|
+
var import_path5, import_ansi_colors8, import_prompts3, cleanComponentByStepTemplate;
|
|
2082
2042
|
var init_cleanComponentByStep_template = __esm({
|
|
2083
2043
|
"src/templates/cleanComponentByStep/cleanComponentByStep.template.ts"() {
|
|
2084
2044
|
"use strict";
|
|
2085
2045
|
init_cjs_shims();
|
|
2086
2046
|
import_path5 = __toESM(require("path"), 1);
|
|
2087
|
-
|
|
2047
|
+
import_ansi_colors8 = __toESM(require("ansi-colors"), 1);
|
|
2088
2048
|
import_prompts3 = require("@clack/prompts");
|
|
2089
2049
|
init_fsModule_utils();
|
|
2090
2050
|
init_prompt_utils();
|
|
2051
|
+
init_featureComponentGenerator_utils();
|
|
2091
2052
|
cleanComponentByStepTemplate = async (featureName) => {
|
|
2092
2053
|
const base = import_path5.default.join("src", "features", featureName);
|
|
2093
2054
|
let created = 0;
|
|
2055
|
+
let controller = { controllerName: "", methods: [] };
|
|
2094
2056
|
const ask = async (label) => {
|
|
2095
2057
|
const answer = await UPrompt.confirm(label, false);
|
|
2096
2058
|
if ((0, import_prompts3.isCancel)(answer)) {
|
|
@@ -2099,48 +2061,74 @@ var init_cleanComponentByStep_template = __esm({
|
|
|
2099
2061
|
}
|
|
2100
2062
|
return answer;
|
|
2101
2063
|
};
|
|
2102
|
-
const
|
|
2103
|
-
UFsModule.createDirectoryRecursively(dir);
|
|
2104
|
-
const filePath = import_path5.default.join(dir, filename);
|
|
2105
|
-
UFsModule.createFile(filePath, "");
|
|
2106
|
-
console.log(import_ansi_colors9.default.green(`\u2705 Created: ${filePath}`));
|
|
2064
|
+
const track = () => {
|
|
2107
2065
|
created++;
|
|
2108
2066
|
};
|
|
2109
|
-
console.log(
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
if (await ask(`
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2067
|
+
console.log(import_ansi_colors8.default.bold(import_ansi_colors8.default.cyan("\n\u2500\u2500 Domain \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")));
|
|
2068
|
+
const mkDir = (dir) => {
|
|
2069
|
+
UFsModule.createDirectoryRecursively(dir);
|
|
2070
|
+
return dir;
|
|
2071
|
+
};
|
|
2072
|
+
if (await ask(`Entity - ${featureName}.entity.ts`)) {
|
|
2073
|
+
await FeatureComponentGeneratorUtils.createEntity(featureName, mkDir(import_path5.default.join(base, "domain", "entities")));
|
|
2074
|
+
track();
|
|
2075
|
+
}
|
|
2076
|
+
if (await ask(`Event - ${featureName}.event.ts`)) {
|
|
2077
|
+
await FeatureComponentGeneratorUtils.createEvent(featureName, mkDir(import_path5.default.join(base, "domain", "events")));
|
|
2078
|
+
track();
|
|
2079
|
+
}
|
|
2080
|
+
if (await ask(`Exception - ${featureName}.exception.ts`)) {
|
|
2081
|
+
await FeatureComponentGeneratorUtils.createException(featureName, mkDir(import_path5.default.join(base, "domain", "exceptions")));
|
|
2082
|
+
track();
|
|
2083
|
+
}
|
|
2084
|
+
console.log(import_ansi_colors8.default.bold(import_ansi_colors8.default.cyan("\n\u2500\u2500 Application \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")));
|
|
2085
|
+
if (await ask(`Repo Interface - ${featureName}.repository.interface.ts`)) {
|
|
2086
|
+
await FeatureComponentGeneratorUtils.createRepositoryInterface(featureName, mkDir(import_path5.default.join(base, "application", "ports", "repositories")));
|
|
2087
|
+
track();
|
|
2088
|
+
}
|
|
2089
|
+
if (await ask(`Presenter Port - ${featureName}.presenter.interface.ts`)) {
|
|
2090
|
+
await FeatureComponentGeneratorUtils.createPresenterInterface(featureName, mkDir(import_path5.default.join(base, "application", "ports", "presenters")));
|
|
2091
|
+
track();
|
|
2092
|
+
}
|
|
2093
|
+
if (await ask(`Service Port - ${featureName}.service.ts`)) {
|
|
2094
|
+
await FeatureComponentGeneratorUtils.createService(featureName, mkDir(import_path5.default.join(base, "application", "ports", "services")));
|
|
2095
|
+
track();
|
|
2096
|
+
}
|
|
2097
|
+
if (await ask(`DTO - ${featureName}.dto.ts`)) {
|
|
2098
|
+
await FeatureComponentGeneratorUtils.createDto(featureName, mkDir(import_path5.default.join(base, "application", "dtos")));
|
|
2099
|
+
track();
|
|
2100
|
+
}
|
|
2101
|
+
if (await ask(`Use Case - ${featureName}.usecase.ts`)) {
|
|
2102
|
+
await FeatureComponentGeneratorUtils.createUseCase(featureName, mkDir(import_path5.default.join(base, "application", "use-cases")));
|
|
2103
|
+
track();
|
|
2104
|
+
}
|
|
2105
|
+
console.log(import_ansi_colors8.default.bold(import_ansi_colors8.default.cyan("\n\u2500\u2500 Infrastructure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500")));
|
|
2106
|
+
if (await ask(`Repo Impl - ${featureName}.repository.ts`)) {
|
|
2107
|
+
await FeatureComponentGeneratorUtils.createRepositoryImpl(featureName, mkDir(import_path5.default.join(base, "infrastructure", "adapters", "repositories")));
|
|
2108
|
+
track();
|
|
2109
|
+
}
|
|
2110
|
+
if (await ask(`Presenter Impl - ${featureName}.presenter.ts`)) {
|
|
2111
|
+
await FeatureComponentGeneratorUtils.createPresenterImpl(featureName, mkDir(import_path5.default.join(base, "infrastructure", "adapters", "presenters")));
|
|
2112
|
+
track();
|
|
2113
|
+
}
|
|
2114
|
+
if (await ask(`Controller - ${featureName}.controller.ts`)) {
|
|
2115
|
+
controller = await FeatureComponentGeneratorUtils.createController(featureName, mkDir(import_path5.default.join(base, "infrastructure", "adapters", "controllers")));
|
|
2116
|
+
track();
|
|
2117
|
+
}
|
|
2118
|
+
if (await ask(`Router Handler - ${featureName}.router.handler.ts`)) {
|
|
2119
|
+
await FeatureComponentGeneratorUtils.createRouterHandler(featureName, mkDir(import_path5.default.join(base, "infrastructure", "routes")), controller.methods);
|
|
2120
|
+
track();
|
|
2121
|
+
}
|
|
2122
|
+
if (await ask(`Router - ${featureName}.router.ts`)) {
|
|
2123
|
+
await FeatureComponentGeneratorUtils.createRouter(featureName, mkDir(import_path5.default.join(base, "infrastructure", "routes")));
|
|
2124
|
+
track();
|
|
2125
|
+
}
|
|
2138
2126
|
if (created === 0) {
|
|
2139
|
-
console.log(
|
|
2127
|
+
console.log(import_ansi_colors8.default.yellow(`
|
|
2140
2128
|
\u26A0\uFE0F No files were created for feature "${featureName}".`));
|
|
2141
2129
|
} else {
|
|
2142
2130
|
console.log(
|
|
2143
|
-
|
|
2131
|
+
import_ansi_colors8.default.bgGreen(import_ansi_colors8.default.white(`
|
|
2144
2132
|
\u{1F389} Feature "${featureName}" \u2014 ${created} file(s) created step by step.
|
|
2145
2133
|
`))
|
|
2146
2134
|
);
|
|
@@ -2191,36 +2179,443 @@ var init_createController_application = __esm({
|
|
|
2191
2179
|
}
|
|
2192
2180
|
});
|
|
2193
2181
|
|
|
2182
|
+
// src/core/domains/constants/resolveRoute.constant.ts
|
|
2183
|
+
var CResolveRoute;
|
|
2184
|
+
var init_resolveRoute_constant = __esm({
|
|
2185
|
+
"src/core/domains/constants/resolveRoute.constant.ts"() {
|
|
2186
|
+
"use strict";
|
|
2187
|
+
init_cjs_shims();
|
|
2188
|
+
CResolveRoute = (methodName, moduleName) => {
|
|
2189
|
+
const lower = methodName.toLowerCase();
|
|
2190
|
+
if (lower.includes("findall") || lower.includes("getall")) return { httpMethod: "get", path: `/${moduleName}` };
|
|
2191
|
+
if (lower.includes("findbyid") || lower.includes("getbyid") || lower.includes("getone")) return { httpMethod: "get", path: `/${moduleName}/:id` };
|
|
2192
|
+
if (lower.includes("create") || lower.includes("add")) return { httpMethod: "post", path: `/${moduleName}` };
|
|
2193
|
+
if (lower.includes("update") || lower.includes("edit")) return { httpMethod: "put", path: `/${moduleName}/:id` };
|
|
2194
|
+
if (lower.includes("delete") || lower.includes("remove")) return { httpMethod: "delete", path: `/${moduleName}/:id` };
|
|
2195
|
+
return { httpMethod: "get", path: `/${moduleName}/${lower}` };
|
|
2196
|
+
};
|
|
2197
|
+
}
|
|
2198
|
+
});
|
|
2199
|
+
|
|
2200
|
+
// src/templates/customModule/customModule.template.ts
|
|
2201
|
+
var capitalize17, generateCustomControllerTemplate, generateMethod3, methodFindAll, methodFindById, methodCreate, methodUpdate, methodDelete, generateCustomServiceTemplate, generateCustomRepositoryTemplate, generateCustomModelTemplate, generateCustomTypesTemplate, generateCustomMiddlewareTemplate, generateCustomUtilsTemplate, generateCustomErrorsTemplate, generateCustomConstantsTemplate, generateCustomRouterHandlerTemplate, generateCustomRouterTemplate;
|
|
2202
|
+
var init_customModule_template = __esm({
|
|
2203
|
+
"src/templates/customModule/customModule.template.ts"() {
|
|
2204
|
+
"use strict";
|
|
2205
|
+
init_cjs_shims();
|
|
2206
|
+
init_resolveRoute_constant();
|
|
2207
|
+
capitalize17 = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
2208
|
+
generateCustomControllerTemplate = (controllerName, moduleName, methods) => {
|
|
2209
|
+
const cap = capitalize17(moduleName);
|
|
2210
|
+
const serviceName = `${cap}Service`;
|
|
2211
|
+
const body = methods.length === 0 ? ` // TODO: add your handler methods here` : methods.map((m) => generateMethod3(m, cap, serviceName)).join("\n");
|
|
2212
|
+
const serviceImport = methods.length === 0 ? `` : `import { ${serviceName} } from "./${moduleName}.service";
|
|
2213
|
+
`;
|
|
2214
|
+
return `import { Request, Response } from "opticore-express";
|
|
2215
|
+
import { ResponseHandler, HttpStatusCode, IResponseHandlerSuccessData } from "opticore-http-response";
|
|
2216
|
+
${serviceImport}
|
|
2217
|
+
export class ${controllerName} {${methods.length > 0 ? `
|
|
2218
|
+
private static buildService(): ${serviceName} {
|
|
2219
|
+
return new ${serviceName}();
|
|
2220
|
+
}
|
|
2221
|
+
` : ""}
|
|
2222
|
+
${body}
|
|
2223
|
+
private static handleError(error: unknown) {
|
|
2224
|
+
const message = error instanceof Error ? error.message : "Internal server error";
|
|
2225
|
+
return ResponseHandler.error(message, HttpStatusCode.INTERNAL_SERVER_ERROR);
|
|
2226
|
+
}
|
|
2227
|
+
}`.trimEnd();
|
|
2228
|
+
};
|
|
2229
|
+
generateMethod3 = (method, cap, serviceName) => {
|
|
2230
|
+
const lower = method.toLowerCase();
|
|
2231
|
+
if (lower.includes("findall") || lower.includes("getall")) return methodFindAll(method, cap);
|
|
2232
|
+
if (lower.includes("findbyid") || lower.includes("getbyid") || lower.includes("getone")) return methodFindById(method, cap);
|
|
2233
|
+
if (lower.includes("create") || lower.includes("add")) return methodCreate(method, cap);
|
|
2234
|
+
if (lower.includes("update") || lower.includes("edit")) return methodUpdate(method, cap);
|
|
2235
|
+
if (lower.includes("delete") || lower.includes("remove")) return methodDelete(method, cap);
|
|
2236
|
+
return `
|
|
2237
|
+
static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
|
|
2238
|
+
try {
|
|
2239
|
+
const service = ${cap}Controller.buildService();
|
|
2240
|
+
// TODO: implement ${method}
|
|
2241
|
+
return ResponseHandler.success({}, "success", HttpStatusCode.OK);
|
|
2242
|
+
} catch (error) {
|
|
2243
|
+
return ${cap}Controller.handleError(error);
|
|
2244
|
+
}
|
|
2245
|
+
}`;
|
|
2246
|
+
};
|
|
2247
|
+
methodFindAll = (m, cap) => `
|
|
2248
|
+
static async ${m}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
|
|
2249
|
+
try {
|
|
2250
|
+
const service = ${cap}Controller.buildService();
|
|
2251
|
+
const results = await service.findAll();
|
|
2252
|
+
return ResponseHandler.success(results, "success", HttpStatusCode.OK);
|
|
2253
|
+
} catch (error) {
|
|
2254
|
+
return ${cap}Controller.handleError(error);
|
|
2255
|
+
}
|
|
2256
|
+
}`;
|
|
2257
|
+
methodFindById = (m, cap) => `
|
|
2258
|
+
static async ${m}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
|
|
2259
|
+
try {
|
|
2260
|
+
const { id } = req.params;
|
|
2261
|
+
const service = ${cap}Controller.buildService();
|
|
2262
|
+
const result = await service.findById(id);
|
|
2263
|
+
if (!result) return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
|
|
2264
|
+
return ResponseHandler.success(result, "success", HttpStatusCode.OK);
|
|
2265
|
+
} catch (error) {
|
|
2266
|
+
return ${cap}Controller.handleError(error);
|
|
2267
|
+
}
|
|
2268
|
+
}`;
|
|
2269
|
+
methodCreate = (m, cap) => `
|
|
2270
|
+
static async ${m}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
|
|
2271
|
+
try {
|
|
2272
|
+
const service = ${cap}Controller.buildService();
|
|
2273
|
+
const result = await service.create(req.body);
|
|
2274
|
+
return ResponseHandler.success(result, "created", HttpStatusCode.CREATED);
|
|
2275
|
+
} catch (error) {
|
|
2276
|
+
return ${cap}Controller.handleError(error);
|
|
2277
|
+
}
|
|
2278
|
+
}`;
|
|
2279
|
+
methodUpdate = (m, cap) => `
|
|
2280
|
+
static async ${m}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
|
|
2281
|
+
try {
|
|
2282
|
+
const { id } = req.params;
|
|
2283
|
+
const service = ${cap}Controller.buildService();
|
|
2284
|
+
const result = await service.update(id, req.body);
|
|
2285
|
+
if (!result) return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
|
|
2286
|
+
return ResponseHandler.success(result, "success", HttpStatusCode.OK);
|
|
2287
|
+
} catch (error) {
|
|
2288
|
+
return ${cap}Controller.handleError(error);
|
|
2289
|
+
}
|
|
2290
|
+
}`;
|
|
2291
|
+
methodDelete = (m, cap) => `
|
|
2292
|
+
static async ${m}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
|
|
2293
|
+
try {
|
|
2294
|
+
const { id } = req.params;
|
|
2295
|
+
const service = ${cap}Controller.buildService();
|
|
2296
|
+
const deleted = await service.delete(id);
|
|
2297
|
+
if (!deleted) return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
|
|
2298
|
+
return ResponseHandler.success(null, "deleted", HttpStatusCode.NO_CONTENT);
|
|
2299
|
+
} catch (error) {
|
|
2300
|
+
return ${cap}Controller.handleError(error);
|
|
2301
|
+
}
|
|
2302
|
+
}`;
|
|
2303
|
+
generateCustomServiceTemplate = (moduleName) => {
|
|
2304
|
+
const cap = capitalize17(moduleName);
|
|
2305
|
+
return `export class ${cap}Service {
|
|
2306
|
+
async findAll(): Promise<unknown[]> {
|
|
2307
|
+
// TODO: implement
|
|
2308
|
+
return [];
|
|
2309
|
+
}
|
|
2310
|
+
async findById(id: string): Promise<unknown | null> {
|
|
2311
|
+
// TODO: implement
|
|
2312
|
+
return null;
|
|
2313
|
+
}
|
|
2314
|
+
async create(data: Record<string, unknown>): Promise<unknown> {
|
|
2315
|
+
// TODO: implement
|
|
2316
|
+
return data;
|
|
2317
|
+
}
|
|
2318
|
+
async update(id: string, data: Record<string, unknown>): Promise<unknown | null> {
|
|
2319
|
+
// TODO: implement
|
|
2320
|
+
return null;
|
|
2321
|
+
}
|
|
2322
|
+
async delete(id: string): Promise<boolean> {
|
|
2323
|
+
// TODO: implement
|
|
2324
|
+
return false;
|
|
2325
|
+
}
|
|
2326
|
+
}`.trimEnd();
|
|
2327
|
+
};
|
|
2328
|
+
generateCustomRepositoryTemplate = (moduleName) => {
|
|
2329
|
+
const cap = capitalize17(moduleName);
|
|
2330
|
+
const name = moduleName.toLowerCase();
|
|
2331
|
+
const isAuthRelated = name.includes("auth") || name.includes("authenticate") || name.includes("authentication") || name.includes("login") || name.includes("security") || name.includes("session") || name.includes("connect") || name.includes("connexion") || name.includes("connection");
|
|
2332
|
+
if (isAuthRelated) {
|
|
2333
|
+
return `export class ${cap}Repository {
|
|
2334
|
+
// TODO: inject your data source (ORM, DB client, etc.)
|
|
2335
|
+
|
|
2336
|
+
async findByEmail(email: string): Promise<User | null> {
|
|
2337
|
+
throw new Error("Not implemented");
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
async findByUsernameOrEmail(identity: string): Promise<User | null> {
|
|
2341
|
+
throw new Error("Not implemented");
|
|
2342
|
+
}
|
|
2343
|
+
|
|
2344
|
+
async updateLastLogin(userId: string, date: Date): Promise<void> {
|
|
2345
|
+
throw new Error("Not implemented");
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
async incrementLoginAttempts(userId: string): Promise<number> {
|
|
2349
|
+
throw new Error("Not implemented");
|
|
2350
|
+
}
|
|
2351
|
+
|
|
2352
|
+
async resetLoginAttempts(userId: string): Promise<void> {
|
|
2353
|
+
throw new Error("Not implemented");
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
async saveToken(userId: string, token: string): Promise<void> {
|
|
2357
|
+
throw new Error("Not implemented");
|
|
2358
|
+
}
|
|
2359
|
+
}`.trimEnd();
|
|
2360
|
+
}
|
|
2361
|
+
return `export class ${cap}Repository {
|
|
2362
|
+
// TODO: inject your data source (ORM, DB client, etc.)
|
|
2363
|
+
async findAll(): Promise<unknown[]> { throw new Error("Not implemented"); }
|
|
2364
|
+
async findById(id: string): Promise<unknown | null> { throw new Error("Not implemented"); }
|
|
2365
|
+
async create(data: Record<string, unknown>): Promise<unknown> { throw new Error("Not implemented"); }
|
|
2366
|
+
async update(id: string, data: Record<string, unknown>): Promise<unknown | null> { throw new Error("Not implemented"); }
|
|
2367
|
+
async delete(id: string): Promise<boolean> { throw new Error("Not implemented"); }
|
|
2368
|
+
}`.trimEnd();
|
|
2369
|
+
};
|
|
2370
|
+
generateCustomModelTemplate = (moduleName) => {
|
|
2371
|
+
const cap = capitalize17(moduleName);
|
|
2372
|
+
return `export class ${cap}Model {
|
|
2373
|
+
constructor(
|
|
2374
|
+
public readonly id: string,
|
|
2375
|
+
// TODO: add your fields here
|
|
2376
|
+
) {}
|
|
2377
|
+
}`.trimEnd();
|
|
2378
|
+
};
|
|
2379
|
+
generateCustomTypesTemplate = (moduleName) => `// ${moduleName} types
|
|
2380
|
+
export type ${capitalize17(moduleName)}Id = string;
|
|
2381
|
+
// TODO: add your domain types here`.trimEnd();
|
|
2382
|
+
generateCustomMiddlewareTemplate = (moduleName) => {
|
|
2383
|
+
const cap = capitalize17(moduleName);
|
|
2384
|
+
return `import { Request, Response, NextFunction } from "opticore-express";
|
|
2385
|
+
|
|
2386
|
+
export function ${moduleName}Middleware(req: Request, res: Response, next: NextFunction): void {
|
|
2387
|
+
// TODO: implement ${cap} middleware logic
|
|
2388
|
+
next();
|
|
2389
|
+
}`.trimEnd();
|
|
2390
|
+
};
|
|
2391
|
+
generateCustomUtilsTemplate = (moduleName) => `// ${moduleName} utilities
|
|
2392
|
+
// TODO: add helper functions here`.trimEnd();
|
|
2393
|
+
generateCustomErrorsTemplate = (moduleName) => {
|
|
2394
|
+
const cap = capitalize17(moduleName);
|
|
2395
|
+
return `export class ${cap}NotFoundError extends Error {
|
|
2396
|
+
constructor(id: string) {
|
|
2397
|
+
super(\`${cap} not found: \${id}\`);
|
|
2398
|
+
this.name = "${cap}NotFoundError";
|
|
2399
|
+
}
|
|
2400
|
+
}
|
|
2401
|
+
export class ${cap}ValidationError extends Error {
|
|
2402
|
+
constructor(message: string) {
|
|
2403
|
+
super(message);
|
|
2404
|
+
this.name = "${cap}ValidationError";
|
|
2405
|
+
}
|
|
2406
|
+
}`.trimEnd();
|
|
2407
|
+
};
|
|
2408
|
+
generateCustomConstantsTemplate = (moduleName) => `// ${moduleName} constants
|
|
2409
|
+
export const ${moduleName.toUpperCase()}_PREFIX = "/${moduleName}";
|
|
2410
|
+
// TODO: add your constants here`.trimEnd();
|
|
2411
|
+
generateCustomRouterHandlerTemplate = (moduleName, controllerMethods) => {
|
|
2412
|
+
const cap = capitalize17(moduleName);
|
|
2413
|
+
const handlerName = `${cap}HandlerRouter`;
|
|
2414
|
+
const controllerName = `${cap}Controller`;
|
|
2415
|
+
const routesCode = (controllerMethods || []).map((method) => {
|
|
2416
|
+
const { httpMethod, path: path8 } = CResolveRoute(method, moduleName);
|
|
2417
|
+
return `{
|
|
2418
|
+
path: \`${path8}\`,
|
|
2419
|
+
method: "${httpMethod}",
|
|
2420
|
+
middlewares: [],
|
|
2421
|
+
handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
|
|
2422
|
+
}`;
|
|
2423
|
+
}).join(",\n");
|
|
2424
|
+
return `import { OpticoreRouting, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
|
|
2425
|
+
import { ${controllerName} } from "../../app/${moduleName}.controller";
|
|
2426
|
+
|
|
2427
|
+
export const ${handlerName}: () => IMultipleRouteDefinition = () => {
|
|
2428
|
+
return OpticoreRouting.routes(
|
|
2429
|
+
${controllerName},
|
|
2430
|
+
[
|
|
2431
|
+
${routesCode ? routesCode.replace(/\n/g, "\n ") : ""}
|
|
2432
|
+
]
|
|
2433
|
+
);
|
|
2434
|
+
};`.trimEnd();
|
|
2435
|
+
};
|
|
2436
|
+
generateCustomRouterTemplate = (moduleName) => {
|
|
2437
|
+
const cap = capitalize17(moduleName);
|
|
2438
|
+
const handlerName = `${cap}HandlerRouter`;
|
|
2439
|
+
const routerName = `${cap}Router`;
|
|
2440
|
+
return `import { ${handlerName} } from "./core/handler/${moduleName}.router.handler";
|
|
2441
|
+
import { TFeatureRoutes } from "opticore-router";
|
|
2442
|
+
|
|
2443
|
+
export const ${routerName}: TFeatureRoutes = {
|
|
2444
|
+
routes: [
|
|
2445
|
+
{
|
|
2446
|
+
path: ${handlerName}().path,
|
|
2447
|
+
handler: ${handlerName}().handler
|
|
2448
|
+
}
|
|
2449
|
+
]
|
|
2450
|
+
};`.trimEnd();
|
|
2451
|
+
};
|
|
2452
|
+
}
|
|
2453
|
+
});
|
|
2454
|
+
|
|
2455
|
+
// src/templates/customModule/customModuleScaffold.template.ts
|
|
2456
|
+
async function askFile(label) {
|
|
2457
|
+
const answer = await UPrompt.confirm(`Create ${label}?`, false);
|
|
2458
|
+
return answer === true;
|
|
2459
|
+
}
|
|
2460
|
+
async function askMethods() {
|
|
2461
|
+
const wantsMethods = await UPrompt.confirm("Do you want to add methods to the controller?");
|
|
2462
|
+
if (!wantsMethods) return [];
|
|
2463
|
+
const raw = await UPrompt.text(
|
|
2464
|
+
"Enter the method names (comma separated):",
|
|
2465
|
+
"create, findAll, findById, update, delete",
|
|
2466
|
+
(v) => v ? void 0 : "Enter at least one method name."
|
|
2467
|
+
);
|
|
2468
|
+
if ((0, import_prompts5.isCancel)(raw)) return [];
|
|
2469
|
+
return raw.split(",").map((m) => m.trim()).filter(Boolean);
|
|
2470
|
+
}
|
|
2471
|
+
var import_path6, import_fs3, import_ansi_colors9, import_prompts5, ok, tip, capitalize18, customModuleScaffoldTemplate;
|
|
2472
|
+
var init_customModuleScaffold_template = __esm({
|
|
2473
|
+
"src/templates/customModule/customModuleScaffold.template.ts"() {
|
|
2474
|
+
"use strict";
|
|
2475
|
+
init_cjs_shims();
|
|
2476
|
+
import_path6 = __toESM(require("path"), 1);
|
|
2477
|
+
import_fs3 = __toESM(require("fs"), 1);
|
|
2478
|
+
import_ansi_colors9 = __toESM(require("ansi-colors"), 1);
|
|
2479
|
+
import_prompts5 = require("@clack/prompts");
|
|
2480
|
+
init_fsModule_utils();
|
|
2481
|
+
init_prompt_utils();
|
|
2482
|
+
init_featureName_service();
|
|
2483
|
+
init_customModule_template();
|
|
2484
|
+
init_featureComponentGenerator_utils();
|
|
2485
|
+
ok = (msg) => {
|
|
2486
|
+
console.log(import_ansi_colors9.default.green(`\u2705 ${msg}`));
|
|
2487
|
+
};
|
|
2488
|
+
tip = (msg) => {
|
|
2489
|
+
console.log(import_ansi_colors9.default.yellow(` ${msg}`));
|
|
2490
|
+
};
|
|
2491
|
+
capitalize18 = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
2492
|
+
customModuleScaffoldTemplate = async () => {
|
|
2493
|
+
const rawName = await _featureName();
|
|
2494
|
+
if ((0, import_prompts5.isCancel)(rawName)) {
|
|
2495
|
+
console.log(import_ansi_colors9.default.bgRed(import_ansi_colors9.default.white("Operation cancelled.")));
|
|
2496
|
+
process.exit(0);
|
|
2497
|
+
}
|
|
2498
|
+
const moduleName = rawName.toString();
|
|
2499
|
+
const moduleDir = import_path6.default.join(process.cwd(), "src", "features", moduleName);
|
|
2500
|
+
if (import_fs3.default.existsSync(moduleDir)) {
|
|
2501
|
+
console.log(import_ansi_colors9.default.bgCyan(import_ansi_colors9.default.white(`Module "${moduleName}" already exists.`)));
|
|
2502
|
+
process.exit(0);
|
|
2503
|
+
}
|
|
2504
|
+
const appDir = import_path6.default.join(moduleDir, "app");
|
|
2505
|
+
const coreMiddlewaresDir = import_path6.default.join(moduleDir, "core", "middlewares");
|
|
2506
|
+
const coreHandlerDir = import_path6.default.join(moduleDir, "core", "handler");
|
|
2507
|
+
const sharedUtilsDir = import_path6.default.join(moduleDir, "shared", "utils");
|
|
2508
|
+
const sharedErrorsDir = import_path6.default.join(moduleDir, "shared", "errors");
|
|
2509
|
+
const sharedConstantsDir = import_path6.default.join(moduleDir, "shared", "constants");
|
|
2510
|
+
UFsModule.createDirectoryRecursively(appDir);
|
|
2511
|
+
UFsModule.createDirectoryRecursively(coreHandlerDir);
|
|
2512
|
+
UFsModule.createDirectoryRecursively(sharedUtilsDir);
|
|
2513
|
+
UFsModule.createDirectoryRecursively(sharedErrorsDir);
|
|
2514
|
+
UFsModule.createDirectoryRecursively(sharedConstantsDir);
|
|
2515
|
+
let controllerMethods = [];
|
|
2516
|
+
if (await askFile(`${moduleName}.controller.ts`)) {
|
|
2517
|
+
controllerMethods = await askMethods();
|
|
2518
|
+
UFsModule.createFile(
|
|
2519
|
+
import_path6.default.join(appDir, `${moduleName}.controller.ts`),
|
|
2520
|
+
generateCustomControllerTemplate(`${capitalize18(moduleName)}Controller`, moduleName, controllerMethods)
|
|
2521
|
+
);
|
|
2522
|
+
ok(`app/${moduleName}.controller.ts`);
|
|
2523
|
+
}
|
|
2524
|
+
if (await askFile(`${moduleName}.service.ts`)) {
|
|
2525
|
+
UFsModule.createFile(import_path6.default.join(appDir, `${moduleName}.service.ts`), generateCustomServiceTemplate(moduleName));
|
|
2526
|
+
ok(`app/${moduleName}.service.ts`);
|
|
2527
|
+
}
|
|
2528
|
+
if (await askFile(`${moduleName}.repository.ts`)) {
|
|
2529
|
+
UFsModule.createFile(import_path6.default.join(appDir, `${moduleName}.repository.ts`), generateCustomRepositoryTemplate(moduleName));
|
|
2530
|
+
ok(`app/${moduleName}.repository.ts`);
|
|
2531
|
+
}
|
|
2532
|
+
if (await askFile(`${moduleName}.model.ts`)) {
|
|
2533
|
+
UFsModule.createFile(import_path6.default.join(appDir, `${moduleName}.model.ts`), generateCustomModelTemplate(moduleName));
|
|
2534
|
+
ok(`app/${moduleName}.model.ts`);
|
|
2535
|
+
}
|
|
2536
|
+
if (await askFile(`${moduleName}.types.ts`)) {
|
|
2537
|
+
UFsModule.createFile(import_path6.default.join(appDir, `${moduleName}.types.ts`), generateCustomTypesTemplate(moduleName));
|
|
2538
|
+
ok(`app/${moduleName}.types.ts`);
|
|
2539
|
+
}
|
|
2540
|
+
const wantsMiddleware = await UPrompt.confirm("Does your module need a middleware?", false);
|
|
2541
|
+
if (wantsMiddleware === true) {
|
|
2542
|
+
UFsModule.createDirectoryRecursively(coreMiddlewaresDir);
|
|
2543
|
+
UFsModule.createFile(
|
|
2544
|
+
import_path6.default.join(coreMiddlewaresDir, `${moduleName}.middleware.ts`),
|
|
2545
|
+
generateCustomMiddlewareTemplate(moduleName)
|
|
2546
|
+
);
|
|
2547
|
+
ok(`core/middlewares/${moduleName}.middleware.ts`);
|
|
2548
|
+
}
|
|
2549
|
+
UFsModule.createFile(
|
|
2550
|
+
import_path6.default.join(coreHandlerDir, `${moduleName}.router.handler.ts`),
|
|
2551
|
+
generateCustomRouterHandlerTemplate(moduleName, controllerMethods)
|
|
2552
|
+
);
|
|
2553
|
+
ok(`core/handler/${moduleName}.router.handler.ts`);
|
|
2554
|
+
UFsModule.createFile(import_path6.default.join(sharedUtilsDir, `${moduleName}.utils.ts`), generateCustomUtilsTemplate(moduleName));
|
|
2555
|
+
UFsModule.createFile(import_path6.default.join(sharedErrorsDir, `${moduleName}.errors.ts`), generateCustomErrorsTemplate(moduleName));
|
|
2556
|
+
UFsModule.createFile(import_path6.default.join(sharedConstantsDir, `${moduleName}.constants.ts`), generateCustomConstantsTemplate(moduleName));
|
|
2557
|
+
ok(`shared/utils/${moduleName}.utils.ts`);
|
|
2558
|
+
ok(`shared/errors/${moduleName}.errors.ts`);
|
|
2559
|
+
ok(`shared/constants/${moduleName}.constants.ts`);
|
|
2560
|
+
UFsModule.createFile(import_path6.default.join(moduleDir, `${moduleName}.router.ts`), generateCustomRouterTemplate(moduleName));
|
|
2561
|
+
ok(`${moduleName}.router.ts`);
|
|
2562
|
+
FeatureComponentGeneratorUtils.setStructure("custom");
|
|
2563
|
+
await FeatureComponentGeneratorUtils.registerModuleRouter(moduleName);
|
|
2564
|
+
tip(`src/features/${moduleName}/`);
|
|
2565
|
+
tip(`\u251C\u2500\u2500 app/`);
|
|
2566
|
+
tip(`\u251C\u2500\u2500 core/`);
|
|
2567
|
+
tip(`\u2502 \u251C\u2500\u2500 middlewares/`);
|
|
2568
|
+
tip(`\u2502 \u2514\u2500\u2500 handler/`);
|
|
2569
|
+
tip(`\u251C\u2500\u2500 shared/`);
|
|
2570
|
+
tip(`\u2502 \u251C\u2500\u2500 utils/`);
|
|
2571
|
+
tip(`\u2502 \u251C\u2500\u2500 errors/`);
|
|
2572
|
+
tip(`\u2502 \u2514\u2500\u2500 constants/`);
|
|
2573
|
+
tip(`\u2514\u2500\u2500 ${moduleName}.router.ts`);
|
|
2574
|
+
console.log(`
|
|
2575
|
+
${import_ansi_colors9.default.bgGreen(import_ansi_colors9.default.white(`
|
|
2576
|
+
\u{1F389} Custom module "${moduleName}" scaffolded successfully!
|
|
2577
|
+
`))}`);
|
|
2578
|
+
};
|
|
2579
|
+
}
|
|
2580
|
+
});
|
|
2581
|
+
|
|
2194
2582
|
// src/core/core.ts
|
|
2195
2583
|
var core_exports = {};
|
|
2196
|
-
var
|
|
2584
|
+
var import_process2, import_node_fs2, import_path7, import_prompts6;
|
|
2197
2585
|
var init_core = __esm({
|
|
2198
2586
|
"src/core/core.ts"() {
|
|
2199
2587
|
"use strict";
|
|
2200
2588
|
init_cjs_shims();
|
|
2201
|
-
|
|
2589
|
+
import_process2 = __toESM(require("process"), 1);
|
|
2202
2590
|
import_node_fs2 = __toESM(require("fs"), 1);
|
|
2203
|
-
|
|
2204
|
-
|
|
2591
|
+
import_path7 = __toESM(require("path"), 1);
|
|
2592
|
+
import_prompts6 = require("@clack/prompts");
|
|
2205
2593
|
init_welcomeMessage_utils();
|
|
2206
2594
|
init_choiceFeatureCleanModule();
|
|
2207
|
-
init_customFeatureInfoMessage_constant();
|
|
2208
2595
|
init_customFeatureInfo_utils();
|
|
2209
2596
|
init_featureName_service();
|
|
2210
2597
|
init_base_service();
|
|
2211
2598
|
init_createController_application();
|
|
2599
|
+
init_customModuleScaffold_template();
|
|
2212
2600
|
(async () => {
|
|
2213
2601
|
UWelcomeMessage();
|
|
2214
2602
|
const featureChoice = await choiceFeatureCleanModule();
|
|
2215
|
-
featureChoice
|
|
2603
|
+
if (featureChoice === "custom_feature") {
|
|
2604
|
+
await customModuleScaffoldTemplate();
|
|
2605
|
+
return;
|
|
2606
|
+
}
|
|
2607
|
+
if (!featureChoice || featureChoice !== "opticore_clean_module") {
|
|
2608
|
+
import_process2.default.exit(0);
|
|
2609
|
+
}
|
|
2610
|
+
UCustomFeatureInfo(featureChoice);
|
|
2216
2611
|
const featureName = await _featureName();
|
|
2217
|
-
const directory =
|
|
2218
|
-
const featureDirectory =
|
|
2612
|
+
const directory = import_path7.default.join(import_process2.default.cwd(), "src", "features");
|
|
2613
|
+
const featureDirectory = import_path7.default.join(directory, featureName.toString());
|
|
2219
2614
|
const featureCleanModule = BaseService._isSubdirectoryExists(featureName);
|
|
2220
2615
|
if (featureCleanModule) {
|
|
2221
2616
|
BaseService._featureFounded(featureName);
|
|
2222
2617
|
}
|
|
2223
|
-
if ((0,
|
|
2618
|
+
if ((0, import_prompts6.isCancel)(featureName)) {
|
|
2224
2619
|
BaseService._cancelOperation(featureDirectory);
|
|
2225
2620
|
} else {
|
|
2226
2621
|
try {
|
|
@@ -2231,7 +2626,7 @@ var init_core = __esm({
|
|
|
2231
2626
|
}
|
|
2232
2627
|
} catch (err) {
|
|
2233
2628
|
console.error(err.message);
|
|
2234
|
-
|
|
2629
|
+
import_process2.default.exit();
|
|
2235
2630
|
}
|
|
2236
2631
|
}
|
|
2237
2632
|
})();
|