opticore-feature-component 1.0.4 → 1.0.6

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.
@@ -1,8 +1,8 @@
1
1
  // src/core/core.ts
2
2
  import process3 from "process";
3
3
  import fs5 from "fs";
4
- import path7 from "path";
5
- import { isCancel as isCancel5 } from "@clack/prompts";
4
+ import path9 from "path";
5
+ import { isCancel as isCancel7 } from "@clack/prompts";
6
6
 
7
7
  // src/utils/welcomeMessage.utils.ts
8
8
  import cfonts from "cfonts";
@@ -126,7 +126,9 @@ async function choiceFeatureCleanModule() {
126
126
  ["opticore_principle"],
127
127
  [
128
128
  { label: "OptiCoreJs CLEAN Module", value: ["opticore_clean_module"], hint: "recommended" },
129
- { label: "Custom feature", value: ["custom_feature"] }
129
+ { label: "MVC Architecture", value: ["mvc_architecture"] },
130
+ { label: "Layered Architecture", value: ["layered_architecture"] },
131
+ { label: "Build your own architecture", value: ["custom_feature"] }
130
132
  ]
131
133
  );
132
134
  if (isCancel(featureSelected)) {
@@ -877,19 +879,19 @@ var generateRouterHandlerTemplate = (featureName, controllerMethods) => {
877
879
  const handlerName = `${capitalized}HandlerRouter`;
878
880
  const controllerName = `${capitalized}Controller`;
879
881
  const routesCode = (controllerMethods || []).map((method) => {
880
- const { httpMethod, path: path8 } = resolveRoute(method, featureName);
882
+ const { httpMethod, path: path10 } = resolveRoute(method, featureName);
881
883
  return `{
882
- path: \`${path8}\`,
884
+ path: \`${path10}\`,
883
885
  method: "${httpMethod}",
884
886
  middlewares: [],
885
887
  handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
886
888
  }`;
887
889
  }).join(",\n");
888
- return `import { OpticoreRouting, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
890
+ return `import { OpticoreRoutingFactory, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
889
891
  import { ${controllerName} } from "../adapters/controllers/${featureName}.controller";
890
892
 
891
893
  export const ${handlerName}: () => IMultipleRouteDefinition = () => {
892
- return OpticoreRouting.routes(
894
+ return OpticoreRoutingFactory.routes(
893
895
  ${controllerName},
894
896
  [
895
897
  ${routesCode.replace(/\n/g, "\n ")}
@@ -1397,19 +1399,19 @@ var generateSimpleRouterHandlerTemplate = (featureName, controllerMethods) => {
1397
1399
  const handlerName = `${capitalized}HandlerRouter`;
1398
1400
  const controllerName = `${capitalized}Controller`;
1399
1401
  const routesCode = (controllerMethods || []).map((method) => {
1400
- const { httpMethod, path: path8 } = resolveRoute2(method, featureName);
1402
+ const { httpMethod, path: path10 } = resolveRoute2(method, featureName);
1401
1403
  return `{
1402
- path: \`${path8}\`,
1404
+ path: \`${path10}\`,
1403
1405
  method: "${httpMethod}",
1404
1406
  middlewares: [],
1405
1407
  handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
1406
1408
  }`;
1407
1409
  }).join(",\n");
1408
- return `import { OpticoreRouting, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
1410
+ return `import { OpticoreRoutingFactory, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
1409
1411
  import { ${controllerName} } from "../controllers/${featureName}.controller";
1410
1412
 
1411
1413
  export const ${handlerName}: () => IMultipleRouteDefinition = () => {
1412
- return OpticoreRouting.routes(
1414
+ return OpticoreRoutingFactory.routes(
1413
1415
  ${controllerName},
1414
1416
  [
1415
1417
  ${routesCode.replace(/\n/g, "\n ")}
@@ -1647,7 +1649,7 @@ export class ${controllerName} {}
1647
1649
  */
1648
1650
  static async updateRegisterRouter(featureName) {
1649
1651
  const routerName = `${this.capitalize(featureName)}Router`;
1650
- const routerPath = this.structure === "simple" ? `../../features/${featureName}/routes/${featureName}.router` : this.structure === "custom" ? `../../features/${featureName}/${featureName}.router` : `../../features/${featureName}/infrastructure/routes/${featureName}.router`;
1652
+ const routerPath = this.structure === "simple" || this.structure === "mvc" || this.structure === "layered" ? `../../features/${featureName}/routes/${featureName}.router` : this.structure === "custom" ? `../../features/${featureName}/${featureName}.router` : `../../features/${featureName}/infrastructure/routes/${featureName}.router`;
1651
1653
  const importStatement = `import { ${routerName} } from "${routerPath}"`;
1652
1654
  try {
1653
1655
  if (!fs3.existsSync(this.REGISTER_ROUTER_PATH)) {
@@ -2142,19 +2144,19 @@ var generateCustomRouterHandlerTemplate = (moduleName, controllerMethods) => {
2142
2144
  const handlerName = `${cap}HandlerRouter`;
2143
2145
  const controllerName = `${cap}Controller`;
2144
2146
  const routesCode = (controllerMethods || []).map((method) => {
2145
- const { httpMethod, path: path8 } = CResolveRoute(method, moduleName);
2147
+ const { httpMethod, path: path10 } = CResolveRoute(method, moduleName);
2146
2148
  return `{
2147
- path: \`${path8}\`,
2149
+ path: \`${path10}\`,
2148
2150
  method: "${httpMethod}",
2149
2151
  middlewares: [],
2150
2152
  handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
2151
2153
  }`;
2152
2154
  }).join(",\n");
2153
- return `import { OpticoreRouting, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
2155
+ return `import { OpticoreRoutingFactory, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
2154
2156
  import { ${controllerName} } from "../../app/${moduleName}.controller";
2155
2157
 
2156
2158
  export const ${handlerName}: () => IMultipleRouteDefinition = () => {
2157
- return OpticoreRouting.routes(
2159
+ return OpticoreRoutingFactory.routes(
2158
2160
  ${controllerName},
2159
2161
  [
2160
2162
  ${routesCode ? routesCode.replace(/\n/g, "\n ") : ""}
@@ -2290,6 +2292,668 @@ ${colors9.bgGreen(colors9.white(`
2290
2292
  `))}`);
2291
2293
  };
2292
2294
 
2295
+ // src/templates/mvcModule/mvcModuleScaffold.template.ts
2296
+ import path7 from "path";
2297
+ import colors10 from "ansi-colors";
2298
+ import { isCancel as isCancel5 } from "@clack/prompts";
2299
+
2300
+ // src/templates/mvcModule/mvcModule.template.ts
2301
+ var capitalize19 = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2302
+ var generateMvcModelTemplate = (featureName) => {
2303
+ const capitalized = capitalize19(featureName);
2304
+ const modelName = `${capitalized}Model`;
2305
+ return `/**
2306
+ * ${modelName} \u2014 Model
2307
+ * Owns both the data shape and the data-access logic for "${featureName}".
2308
+ */
2309
+ export class ${modelName} {
2310
+ id: string;
2311
+ createdAt: Date;
2312
+ updatedAt: Date;
2313
+
2314
+ constructor(
2315
+ id: string,
2316
+ // TODO: add your model properties here
2317
+ createdAt?: Date,
2318
+ updatedAt?: Date,
2319
+ ) {
2320
+ this.id = id;
2321
+ this.createdAt = createdAt ?? new Date();
2322
+ this.updatedAt = updatedAt ?? new Date();
2323
+ }
2324
+
2325
+ private static store: Map<string, ${modelName}> = new Map();
2326
+
2327
+ static async findAll(): Promise<${modelName}[]> {
2328
+ // TODO: Replace with your ORM query
2329
+ return Array.from(this.store.values());
2330
+ }
2331
+
2332
+ static async findById(id: string): Promise<${modelName} | null> {
2333
+ // TODO: Replace with your ORM query
2334
+ return this.store.get(id) ?? null;
2335
+ }
2336
+
2337
+ static async create(data: Record<string, unknown>): Promise<${modelName}> {
2338
+ const model = new ${modelName}(String(Date.now()));
2339
+ // TODO: Map data fields onto model
2340
+ this.store.set(model.id, model);
2341
+ return model;
2342
+ }
2343
+
2344
+ static async update(id: string, data: Record<string, unknown>): Promise<${modelName} | null> {
2345
+ const existing = this.store.get(id);
2346
+ if (!existing) return null;
2347
+ // TODO: Apply data fields onto existing model
2348
+ existing.updatedAt = new Date();
2349
+ this.store.set(id, existing);
2350
+ return existing;
2351
+ }
2352
+
2353
+ static async delete(id: string): Promise<boolean> {
2354
+ // TODO: Replace with your ORM delete
2355
+ return this.store.delete(id);
2356
+ }
2357
+ }
2358
+ `;
2359
+ };
2360
+ var generateMvcViewTemplate = (featureName) => {
2361
+ const capitalized = capitalize19(featureName);
2362
+ const modelName = `${capitalized}Model`;
2363
+ const viewName = `${capitalized}View`;
2364
+ return `import { ${modelName} } from "../models/${featureName}.model";
2365
+
2366
+ /**
2367
+ * ${viewName} \u2014 View
2368
+ * Shapes "${featureName}" data before it is sent back as JSON.
2369
+ */
2370
+ export class ${viewName} {
2371
+ static toJSON(model: ${modelName}): Record<string, unknown> {
2372
+ return {
2373
+ id: model.id,
2374
+ createdAt: model.createdAt,
2375
+ updatedAt: model.updatedAt,
2376
+ // TODO: expose the fields API consumers should see (and only those)
2377
+ };
2378
+ }
2379
+
2380
+ static toJSONList(models: ${modelName}[]): Record<string, unknown>[] {
2381
+ return models.map((model: ${modelName}): Record<string, unknown> => this.toJSON(model));
2382
+ }
2383
+ }
2384
+ `;
2385
+ };
2386
+ var generateMvcControllerTemplate = (controllerName, featureName, methods) => {
2387
+ const capitalized = capitalize19(featureName);
2388
+ const modelName = `${capitalized}Model`;
2389
+ const viewName = `${capitalized}View`;
2390
+ const methodsCode = methods.map((method) => generateMethod4(method, capitalized, modelName, viewName)).join("\n");
2391
+ return `import { Request, Response } from "opticore-express";
2392
+ import { ResponseHandler, HttpStatusCode, IResponseHandlerSuccessData } from "opticore-http-response";
2393
+ import { ${modelName} } from "../models/${featureName}.model";
2394
+ import { ${viewName} } from "../views/${featureName}.view";
2395
+
2396
+ export class ${controllerName} {
2397
+ ${methodsCode}
2398
+ private static handleError(error: unknown) {
2399
+ const message = error instanceof Error ? error.message : "Internal server error";
2400
+ return ResponseHandler.error(message, HttpStatusCode.INTERNAL_SERVER_ERROR);
2401
+ }
2402
+ }
2403
+ `;
2404
+ };
2405
+ var generateMethod4 = (method, capitalized, modelName, viewName) => {
2406
+ const lower = method.toLowerCase();
2407
+ if (lower.includes("findall") || lower.includes("getall")) return generateFindAllMethod3(method, capitalized, modelName, viewName);
2408
+ if (lower.includes("findbyid") || lower.includes("getbyid") || lower.includes("getone")) return generateFindByIdMethod3(method, capitalized, modelName, viewName);
2409
+ if (lower.includes("create") || lower.includes("add")) return generateCreateMethod3(method, capitalized, modelName, viewName);
2410
+ if (lower.includes("update") || lower.includes("edit")) return generateUpdateMethod3(method, capitalized, modelName, viewName);
2411
+ if (lower.includes("delete") || lower.includes("remove")) return generateDeleteMethod3(method, capitalized, modelName);
2412
+ return `
2413
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2414
+ try {
2415
+ // TODO: Implement ${method} logic
2416
+ return ResponseHandler.success({}, "success", HttpStatusCode.OK);
2417
+ } catch (error) {
2418
+ return ${capitalized}Controller.handleError(error);
2419
+ }
2420
+ }
2421
+ `;
2422
+ };
2423
+ var generateFindAllMethod3 = (method, capitalized, modelName, viewName) => `
2424
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2425
+ try {
2426
+ const models = await ${modelName}.findAll();
2427
+ return ResponseHandler.success(${viewName}.toJSONList(models), "success", HttpStatusCode.OK);
2428
+ } catch (error) {
2429
+ return ${capitalized}Controller.handleError(error);
2430
+ }
2431
+ }
2432
+ `;
2433
+ var generateFindByIdMethod3 = (method, capitalized, modelName, viewName) => `
2434
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2435
+ try {
2436
+ const { id } = req.params;
2437
+ const model = await ${modelName}.findById(id);
2438
+ if (!model) {
2439
+ return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
2440
+ }
2441
+ return ResponseHandler.success(${viewName}.toJSON(model), "success", HttpStatusCode.OK);
2442
+ } catch (error) {
2443
+ return ${capitalized}Controller.handleError(error);
2444
+ }
2445
+ }
2446
+ `;
2447
+ var generateCreateMethod3 = (method, capitalized, modelName, viewName) => `
2448
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2449
+ try {
2450
+ const model = await ${modelName}.create(req.body);
2451
+ return ResponseHandler.success(${viewName}.toJSON(model), "created", HttpStatusCode.CREATED);
2452
+ } catch (error) {
2453
+ return ${capitalized}Controller.handleError(error);
2454
+ }
2455
+ }
2456
+ `;
2457
+ var generateUpdateMethod3 = (method, capitalized, modelName, viewName) => `
2458
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2459
+ try {
2460
+ const { id } = req.params;
2461
+ const model = await ${modelName}.update(id, req.body);
2462
+ if (!model) {
2463
+ return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
2464
+ }
2465
+ return ResponseHandler.success(${viewName}.toJSON(model), "success", HttpStatusCode.OK);
2466
+ } catch (error) {
2467
+ return ${capitalized}Controller.handleError(error);
2468
+ }
2469
+ }
2470
+ `;
2471
+ var generateDeleteMethod3 = (method, capitalized, modelName) => `
2472
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2473
+ try {
2474
+ const { id } = req.params;
2475
+ const deleted = await ${modelName}.delete(id);
2476
+ if (!deleted) {
2477
+ return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
2478
+ }
2479
+ return ResponseHandler.success(null, "deleted", HttpStatusCode.NO_CONTENT);
2480
+ } catch (error) {
2481
+ return ${capitalized}Controller.handleError(error);
2482
+ }
2483
+ }
2484
+ `;
2485
+ var generateMvcRouterHandlerTemplate = (featureName, controllerMethods) => {
2486
+ const capitalized = capitalize19(featureName);
2487
+ const handlerName = `${capitalized}HandlerRouter`;
2488
+ const controllerName = `${capitalized}Controller`;
2489
+ const routesCode = (controllerMethods || []).map((method) => {
2490
+ const { httpMethod, path: path10 } = resolveRoute3(method, featureName);
2491
+ return `{
2492
+ path: \`${path10}\`,
2493
+ method: "${httpMethod}",
2494
+ middlewares: [],
2495
+ handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
2496
+ }`;
2497
+ }).join(",\n");
2498
+ return `import { OpticoreRoutingFactory, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
2499
+ import { ${controllerName} } from "../controllers/${featureName}.controller";
2500
+
2501
+ export const ${handlerName}: () => IMultipleRouteDefinition = () => {
2502
+ return OpticoreRoutingFactory.routes(
2503
+ ${controllerName},
2504
+ [
2505
+ ${routesCode.replace(/\n/g, "\n ")}
2506
+ ]
2507
+ );
2508
+ };
2509
+ `;
2510
+ };
2511
+ var generateMvcRouterTemplate = (featureName) => {
2512
+ const capitalized = capitalize19(featureName);
2513
+ const handlerName = `${capitalized}HandlerRouter`;
2514
+ const routerName = `${capitalized}Router`;
2515
+ return `import { ${handlerName} } from "./${featureName}.router.handler";
2516
+ import { TFeatureRoutes } from "opticore-router";
2517
+
2518
+ export const ${routerName}: TFeatureRoutes = {
2519
+ routes: [
2520
+ {
2521
+ path: ${handlerName}().path,
2522
+ handler: ${handlerName}().handler
2523
+ }
2524
+ ]
2525
+ };
2526
+ `;
2527
+ };
2528
+ var resolveRoute3 = (methodName, featureName) => {
2529
+ const lower = methodName.toLowerCase();
2530
+ if (lower.includes("findall") || lower.includes("getall")) return { httpMethod: "get", path: `/${featureName}` };
2531
+ if (lower.includes("findbyid") || lower.includes("getbyid") || lower.includes("getone")) return { httpMethod: "get", path: `/${featureName}/:id` };
2532
+ if (lower.includes("create") || lower.includes("add")) return { httpMethod: "post", path: `/${featureName}` };
2533
+ if (lower.includes("update") || lower.includes("edit")) return { httpMethod: "put", path: `/${featureName}/:id` };
2534
+ if (lower.includes("delete") || lower.includes("remove")) return { httpMethod: "delete", path: `/${featureName}/:id` };
2535
+ return { httpMethod: "get", path: `/${featureName}/${lower}` };
2536
+ };
2537
+
2538
+ // src/templates/mvcModule/mvcModuleScaffold.template.ts
2539
+ var capitalize20 = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2540
+ var mvcModuleTemplate = async (featureName) => {
2541
+ FeatureComponentGeneratorUtils.setStructure("mvc");
2542
+ const basePath = path7.join("src", "features", featureName);
2543
+ const paths = {
2544
+ modelsDir: path7.join(basePath, "models"),
2545
+ viewsDir: path7.join(basePath, "views"),
2546
+ controllersDir: path7.join(basePath, "controllers"),
2547
+ routesDir: path7.join(basePath, "routes")
2548
+ };
2549
+ Object.values(paths).forEach((dir) => UFsModule.createDirectoryRecursively(dir));
2550
+ const controllerName = `${capitalize20(featureName)}Controller`;
2551
+ UFsModule.createFile(path7.join(paths.modelsDir, `${featureName}.model.ts`), generateMvcModelTemplate(featureName));
2552
+ console.log(colors10.green(`\u2705 Model created: ${path7.join(paths.modelsDir, `${featureName}.model.ts`)}`));
2553
+ UFsModule.createFile(path7.join(paths.viewsDir, `${featureName}.view.ts`), generateMvcViewTemplate(featureName));
2554
+ console.log(colors10.green(`\u2705 View created: ${path7.join(paths.viewsDir, `${featureName}.view.ts`)}`));
2555
+ const wantsMethods = await UPrompt.confirm("Do you want to add methods to the controller?");
2556
+ let methods = [];
2557
+ let controllerContent;
2558
+ if (wantsMethods && !isCancel5(wantsMethods)) {
2559
+ const methodsText = await UPrompt.text(
2560
+ "Enter the method names (comma separated):",
2561
+ "create, findAll, findById, update, delete",
2562
+ (v) => v ? void 0 : "You must enter at least one method."
2563
+ );
2564
+ methods = methodsText.split(",").map((m) => m.trim()).filter(Boolean);
2565
+ controllerContent = generateMvcControllerTemplate(controllerName, featureName, methods);
2566
+ } else {
2567
+ controllerContent = `import { Request, Response } from "opticore-express";
2568
+
2569
+ export class ${controllerName} {}
2570
+ `;
2571
+ }
2572
+ const controllerPath = path7.join(paths.controllersDir, `${featureName}.controller.ts`);
2573
+ UFsModule.createFile(controllerPath, controllerContent);
2574
+ console.log(colors10.green(`\u2705 Controller created: ${controllerPath}`));
2575
+ UFsModule.createFile(
2576
+ path7.join(paths.routesDir, `${featureName}.router.handler.ts`),
2577
+ generateMvcRouterHandlerTemplate(featureName, methods)
2578
+ );
2579
+ console.log(colors10.green(`\u2705 Router Handler created: ${path7.join(paths.routesDir, `${featureName}.router.handler.ts`)}`));
2580
+ UFsModule.createFile(
2581
+ path7.join(paths.routesDir, `${featureName}.router.ts`),
2582
+ generateMvcRouterTemplate(featureName)
2583
+ );
2584
+ await FeatureComponentGeneratorUtils.registerModuleRouter(featureName);
2585
+ console.log(colors10.green(`\u2705 Router created: ${path7.join(paths.routesDir, `${featureName}.router.ts`)}`));
2586
+ console.log(
2587
+ colors10.bgGreen(
2588
+ colors10.white(`
2589
+ \u{1F389} Feature "${featureName}" scaffolded with MVC architecture!
2590
+ `)
2591
+ )
2592
+ );
2593
+ };
2594
+
2595
+ // src/templates/layeredModule/layeredModuleScaffold.template.ts
2596
+ import path8 from "path";
2597
+ import colors11 from "ansi-colors";
2598
+ import { isCancel as isCancel6 } from "@clack/prompts";
2599
+
2600
+ // src/templates/layeredModule/layeredModule.template.ts
2601
+ var capitalize21 = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2602
+ var generateLayeredEntityTemplate = (featureName) => {
2603
+ const capitalized = capitalize21(featureName);
2604
+ const entityName = `${capitalized}Entity`;
2605
+ return `/**
2606
+ * ${entityName} \u2014 Entity
2607
+ * Plain data structure for the "${featureName}" domain. No data-access logic here.
2608
+ */
2609
+ export class ${entityName} {
2610
+ constructor(
2611
+ public readonly id: string,
2612
+ // TODO: add your entity fields here
2613
+ public readonly createdAt: Date = new Date(),
2614
+ public readonly updatedAt: Date = new Date(),
2615
+ ) {}
2616
+ }
2617
+ `;
2618
+ };
2619
+ var generateLayeredDtoTemplate = (featureName) => {
2620
+ const capitalized = capitalize21(featureName);
2621
+ const entityName = `${capitalized}Entity`;
2622
+ return `import { ${entityName} } from "../entities/${featureName}.entity";
2623
+
2624
+ export interface Create${capitalized}Dto {
2625
+ // TODO: define the fields required to create a ${featureName}
2626
+ }
2627
+
2628
+ export interface Update${capitalized}Dto {
2629
+ // TODO: define the fields that can be updated
2630
+ }
2631
+
2632
+ export interface ${capitalized}ResponseDto {
2633
+ id: string;
2634
+ createdAt: Date;
2635
+ updatedAt: Date;
2636
+ // TODO: define the fields exposed to API consumers
2637
+ }
2638
+
2639
+ export const to${capitalized}ResponseDto = (entity: ${entityName}): ${capitalized}ResponseDto => ({
2640
+ id: entity.id,
2641
+ createdAt: entity.createdAt,
2642
+ updatedAt: entity.updatedAt,
2643
+ });
2644
+ `;
2645
+ };
2646
+ var generateLayeredRepositoryTemplate = (featureName) => {
2647
+ const capitalized = capitalize21(featureName);
2648
+ const entityName = `${capitalized}Entity`;
2649
+ const repoName = `${capitalized}Repository`;
2650
+ return `import { ${entityName} } from "../entities/${featureName}.entity";
2651
+
2652
+ export class ${repoName} {
2653
+ private store: Map<string, ${entityName}> = new Map();
2654
+
2655
+ async findAll(): Promise<${entityName}[]> {
2656
+ // TODO: Replace with your ORM query
2657
+ return Array.from(this.store.values());
2658
+ }
2659
+
2660
+ async findById(id: string): Promise<${entityName} | null> {
2661
+ // TODO: Replace with your ORM query
2662
+ return this.store.get(id) ?? null;
2663
+ }
2664
+
2665
+ async create(entity: ${entityName}): Promise<${entityName}> {
2666
+ // TODO: Replace with your ORM save
2667
+ this.store.set(entity.id, entity);
2668
+ return entity;
2669
+ }
2670
+
2671
+ async update(entity: ${entityName}): Promise<${entityName} | null> {
2672
+ // TODO: Replace with your ORM update
2673
+ if (!this.store.has(entity.id)) return null;
2674
+ this.store.set(entity.id, entity);
2675
+ return entity;
2676
+ }
2677
+
2678
+ async delete(id: string): Promise<boolean> {
2679
+ // TODO: Replace with your ORM delete
2680
+ return this.store.delete(id);
2681
+ }
2682
+ }
2683
+ `;
2684
+ };
2685
+ var generateLayeredServiceTemplate = (featureName) => {
2686
+ const capitalized = capitalize21(featureName);
2687
+ const entityName = `${capitalized}Entity`;
2688
+ const repoName = `${capitalized}Repository`;
2689
+ const serviceName = `${capitalized}Service`;
2690
+ return `import { ${repoName} } from "../repositories/${featureName}.repository";
2691
+ import { ${entityName} } from "../entities/${featureName}.entity";
2692
+ import { Create${capitalized}Dto, Update${capitalized}Dto, ${capitalized}ResponseDto, to${capitalized}ResponseDto } from "../dto/${featureName}.dto";
2693
+
2694
+ export class ${serviceName} {
2695
+ private readonly repository: ${repoName};
2696
+
2697
+ constructor() {
2698
+ this.repository = new ${repoName}();
2699
+ }
2700
+
2701
+ async findAll(): Promise<${capitalized}ResponseDto[]> {
2702
+ const entities = await this.repository.findAll();
2703
+ return entities.map(to${capitalized}ResponseDto);
2704
+ }
2705
+
2706
+ async findById(id: string): Promise<${capitalized}ResponseDto | null> {
2707
+ const entity = await this.repository.findById(id);
2708
+ return entity ? to${capitalized}ResponseDto(entity) : null;
2709
+ }
2710
+
2711
+ async create(data: Create${capitalized}Dto): Promise<${capitalized}ResponseDto> {
2712
+ const entity = new ${entityName}(String(Date.now()));
2713
+ // TODO: Map data fields onto entity
2714
+ const created = await this.repository.create(entity);
2715
+ return to${capitalized}ResponseDto(created);
2716
+ }
2717
+
2718
+ async update(id: string, data: Update${capitalized}Dto): Promise<${capitalized}ResponseDto | null> {
2719
+ const existing = await this.repository.findById(id);
2720
+ if (!existing) {
2721
+ return null;
2722
+ }
2723
+ // TODO: Apply data fields onto existing entity
2724
+ const updated = await this.repository.update(existing);
2725
+ return updated ? to${capitalized}ResponseDto(updated) : null;
2726
+ }
2727
+
2728
+ async delete(id: string): Promise<boolean> {
2729
+ return this.repository.delete(id);
2730
+ }
2731
+ }
2732
+ `;
2733
+ };
2734
+ var generateLayeredControllerTemplate = (controllerName, featureName, methods) => {
2735
+ const capitalized = capitalize21(featureName);
2736
+ const serviceName = `${capitalized}Service`;
2737
+ const methodsCode = methods.map((method) => generateMethod5(method, capitalized, serviceName)).join("\n");
2738
+ return `import { Request, Response } from "opticore-express";
2739
+ import { ResponseHandler, HttpStatusCode, IResponseHandlerSuccessData } from "opticore-http-response";
2740
+ import { ${serviceName} } from "../services/${featureName}.service";
2741
+
2742
+ export class ${controllerName} {
2743
+ private static buildService(): ${serviceName} {
2744
+ return new ${serviceName}();
2745
+ }
2746
+
2747
+ ${methodsCode}
2748
+ private static handleError(error: unknown) {
2749
+ const message = error instanceof Error ? error.message : "Internal server error";
2750
+ return ResponseHandler.error(message, HttpStatusCode.INTERNAL_SERVER_ERROR);
2751
+ }
2752
+ }
2753
+ `;
2754
+ };
2755
+ var generateMethod5 = (method, capitalized, serviceName) => {
2756
+ const lower = method.toLowerCase();
2757
+ if (lower.includes("findall") || lower.includes("getall")) return generateFindAllMethod4(method, capitalized);
2758
+ if (lower.includes("findbyid") || lower.includes("getbyid") || lower.includes("getone")) return generateFindByIdMethod4(method, capitalized);
2759
+ if (lower.includes("create") || lower.includes("add")) return generateCreateMethod4(method, capitalized);
2760
+ if (lower.includes("update") || lower.includes("edit")) return generateUpdateMethod4(method, capitalized);
2761
+ if (lower.includes("delete") || lower.includes("remove")) return generateDeleteMethod4(method, capitalized);
2762
+ return `
2763
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2764
+ try {
2765
+ const service = ${capitalized}Controller.buildService();
2766
+ // TODO: Implement ${method} logic
2767
+ return ResponseHandler.success({}, "success", HttpStatusCode.OK);
2768
+ } catch (error) {
2769
+ return ${capitalized}Controller.handleError(error);
2770
+ }
2771
+ }
2772
+ `;
2773
+ };
2774
+ var generateFindAllMethod4 = (method, capitalized) => `
2775
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2776
+ try {
2777
+ const service = ${capitalized}Controller.buildService();
2778
+ const results = await service.findAll();
2779
+ return ResponseHandler.success(results, "success", HttpStatusCode.OK);
2780
+ } catch (error) {
2781
+ return ${capitalized}Controller.handleError(error);
2782
+ }
2783
+ }
2784
+ `;
2785
+ var generateFindByIdMethod4 = (method, capitalized) => `
2786
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2787
+ try {
2788
+ const { id } = req.params;
2789
+ const service = ${capitalized}Controller.buildService();
2790
+ const result = await service.findById(id);
2791
+ if (!result) {
2792
+ return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
2793
+ }
2794
+ return ResponseHandler.success(result, "success", HttpStatusCode.OK);
2795
+ } catch (error) {
2796
+ return ${capitalized}Controller.handleError(error);
2797
+ }
2798
+ }
2799
+ `;
2800
+ var generateCreateMethod4 = (method, capitalized) => `
2801
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2802
+ try {
2803
+ const service = ${capitalized}Controller.buildService();
2804
+ const result = await service.create(req.body);
2805
+ return ResponseHandler.success(result, "created", HttpStatusCode.CREATED);
2806
+ } catch (error) {
2807
+ return ${capitalized}Controller.handleError(error);
2808
+ }
2809
+ }
2810
+ `;
2811
+ var generateUpdateMethod4 = (method, capitalized) => `
2812
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2813
+ try {
2814
+ const { id } = req.params;
2815
+ const service = ${capitalized}Controller.buildService();
2816
+ const result = await service.update(id, req.body);
2817
+ if (!result) {
2818
+ return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
2819
+ }
2820
+ return ResponseHandler.success(result, "success", HttpStatusCode.OK);
2821
+ } catch (error) {
2822
+ return ${capitalized}Controller.handleError(error);
2823
+ }
2824
+ }
2825
+ `;
2826
+ var generateDeleteMethod4 = (method, capitalized) => `
2827
+ static async ${method}(req: Request, res: Response): Promise<IResponseHandlerSuccessData | ReturnType<typeof ResponseHandler.error>> {
2828
+ try {
2829
+ const { id } = req.params;
2830
+ const service = ${capitalized}Controller.buildService();
2831
+ const deleted = await service.delete(id);
2832
+ if (!deleted) {
2833
+ return ResponseHandler.error(\`Not found: \${id}\`, HttpStatusCode.NOT_FOUND);
2834
+ }
2835
+ return ResponseHandler.success(null, "deleted", HttpStatusCode.NO_CONTENT);
2836
+ } catch (error) {
2837
+ return ${capitalized}Controller.handleError(error);
2838
+ }
2839
+ }
2840
+ `;
2841
+ var generateLayeredRouterHandlerTemplate = (featureName, controllerMethods) => {
2842
+ const capitalized = capitalize21(featureName);
2843
+ const handlerName = `${capitalized}HandlerRouter`;
2844
+ const controllerName = `${capitalized}Controller`;
2845
+ const routesCode = (controllerMethods || []).map((method) => {
2846
+ const { httpMethod, path: path10 } = resolveRoute4(method, featureName);
2847
+ return `{
2848
+ path: \`${path10}\`,
2849
+ method: "${httpMethod}",
2850
+ middlewares: [],
2851
+ handler: async (ctx: ICustomContext) => await ${controllerName}.${method}(ctx.req, ctx.res)
2852
+ }`;
2853
+ }).join(",\n");
2854
+ return `import { OpticoreRoutingFactory, ICustomContext, IMultipleRouteDefinition } from "opticore-router";
2855
+ import { ${controllerName} } from "../controllers/${featureName}.controller";
2856
+
2857
+ export const ${handlerName}: () => IMultipleRouteDefinition = () => {
2858
+ return OpticoreRoutingFactory.routes(
2859
+ ${controllerName},
2860
+ [
2861
+ ${routesCode.replace(/\n/g, "\n ")}
2862
+ ]
2863
+ );
2864
+ };
2865
+ `;
2866
+ };
2867
+ var generateLayeredRouterTemplate = (featureName) => {
2868
+ const capitalized = capitalize21(featureName);
2869
+ const handlerName = `${capitalized}HandlerRouter`;
2870
+ const routerName = `${capitalized}Router`;
2871
+ return `import { ${handlerName} } from "./${featureName}.router.handler";
2872
+ import { TFeatureRoutes } from "opticore-router";
2873
+
2874
+ export const ${routerName}: TFeatureRoutes = {
2875
+ routes: [
2876
+ {
2877
+ path: ${handlerName}().path,
2878
+ handler: ${handlerName}().handler
2879
+ }
2880
+ ]
2881
+ };
2882
+ `;
2883
+ };
2884
+ var resolveRoute4 = (methodName, featureName) => {
2885
+ const lower = methodName.toLowerCase();
2886
+ if (lower.includes("findall") || lower.includes("getall")) return { httpMethod: "get", path: `/${featureName}` };
2887
+ if (lower.includes("findbyid") || lower.includes("getbyid") || lower.includes("getone")) return { httpMethod: "get", path: `/${featureName}/:id` };
2888
+ if (lower.includes("create") || lower.includes("add")) return { httpMethod: "post", path: `/${featureName}` };
2889
+ if (lower.includes("update") || lower.includes("edit")) return { httpMethod: "put", path: `/${featureName}/:id` };
2890
+ if (lower.includes("delete") || lower.includes("remove")) return { httpMethod: "delete", path: `/${featureName}/:id` };
2891
+ return { httpMethod: "get", path: `/${featureName}/${lower}` };
2892
+ };
2893
+
2894
+ // src/templates/layeredModule/layeredModuleScaffold.template.ts
2895
+ var capitalize22 = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2896
+ var layeredModuleTemplate = async (featureName) => {
2897
+ FeatureComponentGeneratorUtils.setStructure("layered");
2898
+ const basePath = path8.join("src", "features", featureName);
2899
+ const paths = {
2900
+ entitiesDir: path8.join(basePath, "entities"),
2901
+ dtoDir: path8.join(basePath, "dto"),
2902
+ repositoriesDir: path8.join(basePath, "repositories"),
2903
+ servicesDir: path8.join(basePath, "services"),
2904
+ controllersDir: path8.join(basePath, "controllers"),
2905
+ routesDir: path8.join(basePath, "routes")
2906
+ };
2907
+ Object.values(paths).forEach((dir) => UFsModule.createDirectoryRecursively(dir));
2908
+ const controllerName = `${capitalize22(featureName)}Controller`;
2909
+ UFsModule.createFile(path8.join(paths.entitiesDir, `${featureName}.entity.ts`), generateLayeredEntityTemplate(featureName));
2910
+ console.log(colors11.green(`\u2705 Entity created: ${path8.join(paths.entitiesDir, `${featureName}.entity.ts`)}`));
2911
+ UFsModule.createFile(path8.join(paths.dtoDir, `${featureName}.dto.ts`), generateLayeredDtoTemplate(featureName));
2912
+ console.log(colors11.green(`\u2705 DTO created: ${path8.join(paths.dtoDir, `${featureName}.dto.ts`)}`));
2913
+ UFsModule.createFile(path8.join(paths.repositoriesDir, `${featureName}.repository.ts`), generateLayeredRepositoryTemplate(featureName));
2914
+ console.log(colors11.green(`\u2705 Repository created: ${path8.join(paths.repositoriesDir, `${featureName}.repository.ts`)}`));
2915
+ UFsModule.createFile(path8.join(paths.servicesDir, `${featureName}.service.ts`), generateLayeredServiceTemplate(featureName));
2916
+ console.log(colors11.green(`\u2705 Service created: ${path8.join(paths.servicesDir, `${featureName}.service.ts`)}`));
2917
+ const wantsMethods = await UPrompt.confirm("Do you want to add methods to the controller?");
2918
+ let methods = [];
2919
+ let controllerContent;
2920
+ if (wantsMethods && !isCancel6(wantsMethods)) {
2921
+ const methodsText = await UPrompt.text(
2922
+ "Enter the method names (comma separated):",
2923
+ "create, findAll, findById, update, delete",
2924
+ (v) => v ? void 0 : "You must enter at least one method."
2925
+ );
2926
+ methods = methodsText.split(",").map((m) => m.trim()).filter(Boolean);
2927
+ controllerContent = generateLayeredControllerTemplate(controllerName, featureName, methods);
2928
+ } else {
2929
+ controllerContent = `import { Request, Response } from "opticore-express";
2930
+
2931
+ export class ${controllerName} {}
2932
+ `;
2933
+ }
2934
+ const controllerPath = path8.join(paths.controllersDir, `${featureName}.controller.ts`);
2935
+ UFsModule.createFile(controllerPath, controllerContent);
2936
+ console.log(colors11.green(`\u2705 Controller created: ${controllerPath}`));
2937
+ UFsModule.createFile(
2938
+ path8.join(paths.routesDir, `${featureName}.router.handler.ts`),
2939
+ generateLayeredRouterHandlerTemplate(featureName, methods)
2940
+ );
2941
+ console.log(colors11.green(`\u2705 Router Handler created: ${path8.join(paths.routesDir, `${featureName}.router.handler.ts`)}`));
2942
+ UFsModule.createFile(
2943
+ path8.join(paths.routesDir, `${featureName}.router.ts`),
2944
+ generateLayeredRouterTemplate(featureName)
2945
+ );
2946
+ await FeatureComponentGeneratorUtils.registerModuleRouter(featureName);
2947
+ console.log(colors11.green(`\u2705 Router created: ${path8.join(paths.routesDir, `${featureName}.router.ts`)}`));
2948
+ console.log(
2949
+ colors11.bgGreen(
2950
+ colors11.white(`
2951
+ \u{1F389} Feature "${featureName}" scaffolded with Layered architecture!
2952
+ `)
2953
+ )
2954
+ );
2955
+ };
2956
+
2293
2957
  // src/core/core.ts
2294
2958
  (async () => {
2295
2959
  UWelcomeMessage();
@@ -2298,18 +2962,40 @@ ${colors9.bgGreen(colors9.white(`
2298
2962
  await customModuleScaffoldTemplate();
2299
2963
  return;
2300
2964
  }
2965
+ if (featureChoice === "mvc_architecture" || featureChoice === "layered_architecture") {
2966
+ const featureName2 = await _featureName();
2967
+ const directory2 = path9.join(process3.cwd(), "src", "features");
2968
+ const featureDirectory2 = path9.join(directory2, featureName2.toString());
2969
+ if (BaseService._isSubdirectoryExists(featureName2)) {
2970
+ BaseService._featureFounded(featureName2);
2971
+ }
2972
+ if (isCancel7(featureName2)) {
2973
+ BaseService._cancelOperation(featureDirectory2);
2974
+ return;
2975
+ }
2976
+ if (!fs5.existsSync(directory2)) {
2977
+ BaseService._checkFeatureDir();
2978
+ return;
2979
+ }
2980
+ if (featureChoice === "mvc_architecture") {
2981
+ await mvcModuleTemplate(featureName2.toString());
2982
+ } else {
2983
+ await layeredModuleTemplate(featureName2.toString());
2984
+ }
2985
+ return;
2986
+ }
2301
2987
  if (!featureChoice || featureChoice !== "opticore_clean_module") {
2302
2988
  process3.exit(0);
2303
2989
  }
2304
2990
  UCustomFeatureInfo(featureChoice);
2305
2991
  const featureName = await _featureName();
2306
- const directory = path7.join(process3.cwd(), "src", "features");
2307
- const featureDirectory = path7.join(directory, featureName.toString());
2992
+ const directory = path9.join(process3.cwd(), "src", "features");
2993
+ const featureDirectory = path9.join(directory, featureName.toString());
2308
2994
  const featureCleanModule = BaseService._isSubdirectoryExists(featureName);
2309
2995
  if (featureCleanModule) {
2310
2996
  BaseService._featureFounded(featureName);
2311
2997
  }
2312
- if (isCancel5(featureName)) {
2998
+ if (isCancel7(featureName)) {
2313
2999
  BaseService._cancelOperation(featureDirectory);
2314
3000
  } else {
2315
3001
  try {