@forinda/kickjs-cli 0.5.0 → 0.5.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/dist/index.js CHANGED
@@ -57,21 +57,12 @@ __name(pluralizePascal, "pluralizePascal");
57
57
 
58
58
  // src/generators/module.ts
59
59
  import { readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
60
- async function generateModule(options) {
61
- const { name, modulesDir, noEntity, noTests, repo = "inmemory", minimal } = options;
62
- const kebab = toKebabCase(name);
63
- const pascal = toPascalCase(name);
64
- const camel = toCamelCase(name);
65
- const plural = pluralize(kebab);
66
- const pluralPascal = pluralizePascal(pascal);
67
- const moduleDir = join(modulesDir, plural);
68
- const files = [];
69
- const write = /* @__PURE__ */ __name(async (relativePath, content) => {
70
- const fullPath = join(moduleDir, relativePath);
71
- await writeFileSafe(fullPath, content);
72
- files.push(fullPath);
73
- }, "write");
74
- await write("index.ts", `/**
60
+
61
+ // src/generators/templates/module-index.ts
62
+ function generateModuleIndex(pascal, kebab, plural, repo) {
63
+ const repoClass = repo === "inmemory" ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`;
64
+ const repoFile = repo === "inmemory" ? `in-memory-${kebab}` : `drizzle-${kebab}`;
65
+ return `/**
75
66
  * ${pascal} Module
76
67
  *
77
68
  * Self-contained feature module following Domain-Driven Design (DDD).
@@ -86,7 +77,7 @@ async function generateModule(options) {
86
77
  import { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'
87
78
  import { buildRoutes } from '@forinda/kickjs-http'
88
79
  import { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'
89
- import { ${repo === "inmemory" ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`} } from './infrastructure/repositories/${repo === "inmemory" ? `in-memory-${kebab}` : `drizzle-${kebab}`}.repository'
80
+ import { ${repoClass} } from './infrastructure/repositories/${repoFile}.repository'
90
81
  import { ${pascal}Controller } from './presentation/${kebab}.controller'
91
82
 
92
83
  // Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container
@@ -103,7 +94,7 @@ export class ${pascal}Module implements AppModule {
103
94
  */
104
95
  register(container: Container): void {
105
96
  container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>
106
- container.resolve(${repo === "inmemory" ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`}),
97
+ container.resolve(${repoClass}),
107
98
  )
108
99
  }
109
100
 
@@ -120,24 +111,15 @@ export class ${pascal}Module implements AppModule {
120
111
  }
121
112
  }
122
113
  }
123
- `);
124
- await write(`presentation/${kebab}.controller.ts`, `/**
125
- * ${pascal} Controller
126
- *
127
- * Presentation layer \u2014 handles HTTP requests and delegates to use cases.
128
- * Each method receives a RequestContext with typed body, params, and query.
129
- *
130
- * Decorators:
131
- * @Controller(path?) \u2014 registers this class as an HTTP controller
132
- * @Get/@Post/@Put/@Delete(path?, validation?) \u2014 defines routes with optional Zod validation
133
- * @Autowired() \u2014 injects dependencies lazily from the DI container
134
- * @Middleware(...handlers) \u2014 attach middleware at class or method level
135
- *
136
- * Add Swagger decorators (@ApiTags, @ApiOperation, @ApiResponse) from @forinda/kickjs-swagger
137
- * for automatic OpenAPI documentation.
138
- */
139
- import { Controller, Get, Post, Put, Delete, Autowired } from '@forinda/kickjs-core'
140
- import { RequestContext } from '@forinda/kickjs-http'
114
+ `;
115
+ }
116
+ __name(generateModuleIndex, "generateModuleIndex");
117
+
118
+ // src/generators/templates/controller.ts
119
+ function generateController(pascal, kebab, plural, pluralPascal) {
120
+ return `import { Controller, Get, Post, Put, Delete, Autowired, ApiQueryParams } from '@forinda/kickjs-core'
121
+ import type { RequestContext } from '@forinda/kickjs-http'
122
+ import { ApiTags } from '@forinda/kickjs-swagger'
141
123
  import { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'
142
124
  import { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'
143
125
  import { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'
@@ -145,6 +127,7 @@ import { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}
145
127
  import { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'
146
128
  import { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'
147
129
  import { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'
130
+ import { ${pascal.toUpperCase()}_QUERY_CONFIG } from '../constants'
148
131
 
149
132
  @Controller()
150
133
  export class ${pascal}Controller {
@@ -154,39 +137,65 @@ export class ${pascal}Controller {
154
137
  @Autowired() private update${pascal}UseCase!: Update${pascal}UseCase
155
138
  @Autowired() private delete${pascal}UseCase!: Delete${pascal}UseCase
156
139
 
157
- @Post('/', { body: create${pascal}Schema })
158
- async create(ctx: RequestContext) {
159
- const result = await this.create${pascal}UseCase.execute(ctx.body)
160
- ctx.created(result)
161
- }
162
-
163
140
  @Get('/')
141
+ @ApiTags('${pascal}')
142
+ @ApiQueryParams(${pascal.toUpperCase()}_QUERY_CONFIG)
164
143
  async list(ctx: RequestContext) {
165
- const result = await this.list${pluralPascal}UseCase.execute()
166
- ctx.json(result)
144
+ return ctx.paginate(
145
+ (parsed) => this.list${pluralPascal}UseCase.execute(parsed),
146
+ ${pascal.toUpperCase()}_QUERY_CONFIG,
147
+ )
167
148
  }
168
149
 
169
150
  @Get('/:id')
151
+ @ApiTags('${pascal}')
170
152
  async getById(ctx: RequestContext) {
171
153
  const result = await this.get${pascal}UseCase.execute(ctx.params.id)
172
154
  if (!result) return ctx.notFound('${pascal} not found')
173
155
  ctx.json(result)
174
156
  }
175
157
 
176
- @Put('/:id', { body: update${pascal}Schema })
158
+ @Post('/', { body: create${pascal}Schema, name: 'Create${pascal}' })
159
+ @ApiTags('${pascal}')
160
+ async create(ctx: RequestContext) {
161
+ const result = await this.create${pascal}UseCase.execute(ctx.body)
162
+ ctx.created(result)
163
+ }
164
+
165
+ @Put('/:id', { body: update${pascal}Schema, name: 'Update${pascal}' })
166
+ @ApiTags('${pascal}')
177
167
  async update(ctx: RequestContext) {
178
168
  const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)
179
169
  ctx.json(result)
180
170
  }
181
171
 
182
172
  @Delete('/:id')
173
+ @ApiTags('${pascal}')
183
174
  async remove(ctx: RequestContext) {
184
175
  await this.delete${pascal}UseCase.execute(ctx.params.id)
185
176
  ctx.noContent()
186
177
  }
187
178
  }
188
- `);
189
- await write(`application/dtos/create-${kebab}.dto.ts`, `import { z } from 'zod'
179
+ `;
180
+ }
181
+ __name(generateController, "generateController");
182
+
183
+ // src/generators/templates/constants.ts
184
+ function generateConstants(pascal) {
185
+ return `import type { QueryParamsConfig } from '@forinda/kickjs-core'
186
+
187
+ export const ${pascal.toUpperCase()}_QUERY_CONFIG: QueryParamsConfig = {
188
+ filterable: ['name'],
189
+ sortable: ['name', 'createdAt'],
190
+ searchable: ['name'],
191
+ }
192
+ `;
193
+ }
194
+ __name(generateConstants, "generateConstants");
195
+
196
+ // src/generators/templates/dtos.ts
197
+ function generateCreateDTO(pascal, kebab) {
198
+ return `import { z } from 'zod'
190
199
 
191
200
  /**
192
201
  * Create ${pascal} DTO \u2014 Zod schema for validating POST request bodies.
@@ -202,23 +211,34 @@ export const create${pascal}Schema = z.object({
202
211
  })
203
212
 
204
213
  export type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>
205
- `);
206
- await write(`application/dtos/update-${kebab}.dto.ts`, `import { z } from 'zod'
214
+ `;
215
+ }
216
+ __name(generateCreateDTO, "generateCreateDTO");
217
+ function generateUpdateDTO(pascal, kebab) {
218
+ return `import { z } from 'zod'
207
219
 
208
220
  export const update${pascal}Schema = z.object({
209
221
  name: z.string().min(1).max(200).optional(),
210
222
  })
211
223
 
212
224
  export type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>
213
- `);
214
- await write(`application/dtos/${kebab}-response.dto.ts`, `export interface ${pascal}ResponseDTO {
225
+ `;
226
+ }
227
+ __name(generateUpdateDTO, "generateUpdateDTO");
228
+ function generateResponseDTO(pascal, kebab) {
229
+ return `export interface ${pascal}ResponseDTO {
215
230
  id: string
216
231
  name: string
217
232
  createdAt: string
218
233
  updatedAt: string
219
234
  }
220
- `);
221
- const useCases = [
235
+ `;
236
+ }
237
+ __name(generateResponseDTO, "generateResponseDTO");
238
+
239
+ // src/generators/templates/use-cases.ts
240
+ function generateUseCases(pascal, kebab, plural, pluralPascal) {
241
+ return [
222
242
  {
223
243
  file: `create-${kebab}.use-case.ts`,
224
244
  content: `/**
@@ -267,7 +287,7 @@ export class Get${pascal}UseCase {
267
287
  file: `list-${plural}.use-case.ts`,
268
288
  content: `import { Service, Inject } from '@forinda/kickjs-core'
269
289
  import { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'
270
- import type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'
290
+ import type { ParsedQuery } from '@forinda/kickjs-http'
271
291
 
272
292
  @Service()
273
293
  export class List${pluralPascal}UseCase {
@@ -275,8 +295,8 @@ export class List${pluralPascal}UseCase {
275
295
  @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,
276
296
  ) {}
277
297
 
278
- async execute(): Promise<${pascal}ResponseDTO[]> {
279
- return this.repo.findAll()
298
+ async execute(parsed: ParsedQuery) {
299
+ return this.repo.findPaginated(parsed)
280
300
  }
281
301
  }
282
302
  `
@@ -318,10 +338,12 @@ export class Delete${pascal}UseCase {
318
338
  `
319
339
  }
320
340
  ];
321
- for (const uc of useCases) {
322
- await write(`application/use-cases/${uc.file}`, uc.content);
323
- }
324
- await write(`domain/repositories/${kebab}.repository.ts`, `/**
341
+ }
342
+ __name(generateUseCases, "generateUseCases");
343
+
344
+ // src/generators/templates/repository.ts
345
+ function generateRepositoryInterface(pascal, kebab) {
346
+ return `/**
325
347
  * ${pascal} Repository Interface
326
348
  *
327
349
  * Domain layer \u2014 defines the contract for data access.
@@ -334,43 +356,23 @@ export class Delete${pascal}UseCase {
334
356
  import type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'
335
357
  import type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'
336
358
  import type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'
359
+ import type { ParsedQuery } from '@forinda/kickjs-http'
337
360
 
338
361
  export interface I${pascal}Repository {
339
362
  findById(id: string): Promise<${pascal}ResponseDTO | null>
340
363
  findAll(): Promise<${pascal}ResponseDTO[]>
364
+ findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }>
341
365
  create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>
342
366
  update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>
343
367
  delete(id: string): Promise<void>
344
368
  }
345
369
 
346
370
  export const ${pascal.toUpperCase()}_REPOSITORY = Symbol('I${pascal}Repository')
347
- `);
348
- await write(`domain/services/${kebab}-domain.service.ts`, `/**
349
- * ${pascal} Domain Service
350
- *
351
- * Domain layer \u2014 contains business rules that don't belong to a single entity.
352
- * Use this for cross-entity logic, validation rules, and domain invariants.
353
- * Keep it free of HTTP/framework concerns.
354
- */
355
- import { Service, Inject, HttpException } from '@forinda/kickjs-core'
356
- import { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'
357
-
358
- @Service()
359
- export class ${pascal}DomainService {
360
- constructor(
361
- @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,
362
- ) {}
363
-
364
- async ensureExists(id: string): Promise<void> {
365
- const entity = await this.repo.findById(id)
366
- if (!entity) {
367
- throw HttpException.notFound('${pascal} not found')
368
- }
369
- }
371
+ `;
370
372
  }
371
- `);
372
- if (repo === "inmemory") {
373
- await write(`infrastructure/repositories/in-memory-${kebab}.repository.ts`, `/**
373
+ __name(generateRepositoryInterface, "generateRepositoryInterface");
374
+ function generateInMemoryRepository(pascal, kebab) {
375
+ return `/**
374
376
  * In-Memory ${pascal} Repository
375
377
  *
376
378
  * Infrastructure layer \u2014 implements the repository interface using a Map.
@@ -381,6 +383,7 @@ export class ${pascal}DomainService {
381
383
  */
382
384
  import { randomUUID } from 'node:crypto'
383
385
  import { Repository, HttpException } from '@forinda/kickjs-core'
386
+ import type { ParsedQuery } from '@forinda/kickjs-http'
384
387
  import type { I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'
385
388
  import type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'
386
389
  import type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'
@@ -398,6 +401,12 @@ export class InMemory${pascal}Repository implements I${pascal}Repository {
398
401
  return Array.from(this.store.values())
399
402
  }
400
403
 
404
+ async findPaginated(parsed: ParsedQuery): Promise<{ data: ${pascal}ResponseDTO[]; total: number }> {
405
+ const all = Array.from(this.store.values())
406
+ const data = all.slice(parsed.pagination.offset, parsed.pagination.offset + parsed.pagination.limit)
407
+ return { data, total: all.length }
408
+ }
409
+
401
410
  async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {
402
411
  const now = new Date().toISOString()
403
412
  const entity: ${pascal}ResponseDTO = {
@@ -423,10 +432,40 @@ export class InMemory${pascal}Repository implements I${pascal}Repository {
423
432
  this.store.delete(id)
424
433
  }
425
434
  }
426
- `);
435
+ `;
436
+ }
437
+ __name(generateInMemoryRepository, "generateInMemoryRepository");
438
+
439
+ // src/generators/templates/domain.ts
440
+ function generateDomainService(pascal, kebab) {
441
+ return `/**
442
+ * ${pascal} Domain Service
443
+ *
444
+ * Domain layer \u2014 contains business rules that don't belong to a single entity.
445
+ * Use this for cross-entity logic, validation rules, and domain invariants.
446
+ * Keep it free of HTTP/framework concerns.
447
+ */
448
+ import { Service, Inject, HttpException } from '@forinda/kickjs-core'
449
+ import { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'
450
+
451
+ @Service()
452
+ export class ${pascal}DomainService {
453
+ constructor(
454
+ @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,
455
+ ) {}
456
+
457
+ async ensureExists(id: string): Promise<void> {
458
+ const entity = await this.repo.findById(id)
459
+ if (!entity) {
460
+ throw HttpException.notFound('${pascal} not found')
461
+ }
427
462
  }
428
- if (!noEntity && !minimal) {
429
- await write(`domain/entities/${kebab}.entity.ts`, `/**
463
+ }
464
+ `;
465
+ }
466
+ __name(generateDomainService, "generateDomainService");
467
+ function generateEntity(pascal, kebab) {
468
+ return `/**
430
469
  * ${pascal} Entity
431
470
  *
432
471
  * Domain layer \u2014 the core business object.
@@ -495,8 +534,11 @@ export class ${pascal} {
495
534
  }
496
535
  }
497
536
  }
498
- `);
499
- await write(`domain/value-objects/${kebab}-id.vo.ts`, `/**
537
+ `;
538
+ }
539
+ __name(generateEntity, "generateEntity");
540
+ function generateValueObject(pascal, kebab) {
541
+ return `/**
500
542
  * ${pascal} ID Value Object
501
543
  *
502
544
  * Domain layer \u2014 wraps a primitive ID with type safety and validation.
@@ -530,7 +572,171 @@ export class ${pascal}Id {
530
572
  return this.value === other.value
531
573
  }
532
574
  }
533
- `);
575
+ `;
576
+ }
577
+ __name(generateValueObject, "generateValueObject");
578
+
579
+ // src/generators/templates/tests.ts
580
+ function generateControllerTest(pascal, kebab, plural) {
581
+ return `import { describe, it, expect, beforeEach } from 'vitest'
582
+ import { Container } from '@forinda/kickjs-core'
583
+
584
+ describe('${pascal}Controller', () => {
585
+ beforeEach(() => {
586
+ Container.reset()
587
+ })
588
+
589
+ it('should be defined', () => {
590
+ expect(true).toBe(true)
591
+ })
592
+
593
+ describe('POST /${plural}', () => {
594
+ it('should create a new ${kebab}', async () => {
595
+ // TODO: Set up test module, call create endpoint, assert 201
596
+ expect(true).toBe(true)
597
+ })
598
+ })
599
+
600
+ describe('GET /${plural}', () => {
601
+ it('should return paginated ${plural}', async () => {
602
+ // TODO: Set up test module, call list endpoint, assert { data, meta }
603
+ expect(true).toBe(true)
604
+ })
605
+ })
606
+
607
+ describe('GET /${plural}/:id', () => {
608
+ it('should return a ${kebab} by id', async () => {
609
+ // TODO: Create a ${kebab}, then fetch by id, assert match
610
+ expect(true).toBe(true)
611
+ })
612
+
613
+ it('should return 404 for non-existent ${kebab}', async () => {
614
+ // TODO: Fetch non-existent id, assert 404
615
+ expect(true).toBe(true)
616
+ })
617
+ })
618
+
619
+ describe('PUT /${plural}/:id', () => {
620
+ it('should update an existing ${kebab}', async () => {
621
+ // TODO: Create, update, assert changes
622
+ expect(true).toBe(true)
623
+ })
624
+ })
625
+
626
+ describe('DELETE /${plural}/:id', () => {
627
+ it('should delete a ${kebab}', async () => {
628
+ // TODO: Create, delete, assert gone
629
+ expect(true).toBe(true)
630
+ })
631
+ })
632
+ })
633
+ `;
634
+ }
635
+ __name(generateControllerTest, "generateControllerTest");
636
+ function generateRepositoryTest(pascal, kebab, plural) {
637
+ return `import { describe, it, expect, beforeEach } from 'vitest'
638
+ import { InMemory${pascal}Repository } from '../infrastructure/repositories/in-memory-${kebab}.repository'
639
+
640
+ describe('InMemory${pascal}Repository', () => {
641
+ let repo: InMemory${pascal}Repository
642
+
643
+ beforeEach(() => {
644
+ repo = new InMemory${pascal}Repository()
645
+ })
646
+
647
+ it('should create and retrieve a ${kebab}', async () => {
648
+ const created = await repo.create({ name: 'Test ${pascal}' })
649
+ expect(created).toBeDefined()
650
+ expect(created.name).toBe('Test ${pascal}')
651
+ expect(created.id).toBeDefined()
652
+
653
+ const found = await repo.findById(created.id)
654
+ expect(found).toEqual(created)
655
+ })
656
+
657
+ it('should return null for non-existent id', async () => {
658
+ const found = await repo.findById('non-existent')
659
+ expect(found).toBeNull()
660
+ })
661
+
662
+ it('should list all ${plural}', async () => {
663
+ await repo.create({ name: '${pascal} 1' })
664
+ await repo.create({ name: '${pascal} 2' })
665
+
666
+ const all = await repo.findAll()
667
+ expect(all).toHaveLength(2)
668
+ })
669
+
670
+ it('should return paginated results', async () => {
671
+ await repo.create({ name: '${pascal} 1' })
672
+ await repo.create({ name: '${pascal} 2' })
673
+ await repo.create({ name: '${pascal} 3' })
674
+
675
+ const result = await repo.findPaginated({
676
+ filters: [],
677
+ sort: [],
678
+ search: '',
679
+ pagination: { page: 1, limit: 2, offset: 0 },
680
+ })
681
+
682
+ expect(result.data).toHaveLength(2)
683
+ expect(result.total).toBe(3)
684
+ })
685
+
686
+ it('should update a ${kebab}', async () => {
687
+ const created = await repo.create({ name: 'Original' })
688
+ const updated = await repo.update(created.id, { name: 'Updated' })
689
+ expect(updated.name).toBe('Updated')
690
+ })
691
+
692
+ it('should delete a ${kebab}', async () => {
693
+ const created = await repo.create({ name: 'To Delete' })
694
+ await repo.delete(created.id)
695
+ const found = await repo.findById(created.id)
696
+ expect(found).toBeNull()
697
+ })
698
+ })
699
+ `;
700
+ }
701
+ __name(generateRepositoryTest, "generateRepositoryTest");
702
+
703
+ // src/generators/module.ts
704
+ async function generateModule(options) {
705
+ const { name, modulesDir, noEntity, noTests, repo = "inmemory", minimal } = options;
706
+ const kebab = toKebabCase(name);
707
+ const pascal = toPascalCase(name);
708
+ const camel = toCamelCase(name);
709
+ const plural = pluralize(kebab);
710
+ const pluralPascal = pluralizePascal(pascal);
711
+ const moduleDir = join(modulesDir, plural);
712
+ const files = [];
713
+ const write = /* @__PURE__ */ __name(async (relativePath, content) => {
714
+ const fullPath = join(moduleDir, relativePath);
715
+ await writeFileSafe(fullPath, content);
716
+ files.push(fullPath);
717
+ }, "write");
718
+ await write("index.ts", generateModuleIndex(pascal, kebab, plural, repo));
719
+ await write("constants.ts", generateConstants(pascal));
720
+ await write(`presentation/${kebab}.controller.ts`, generateController(pascal, kebab, plural, pluralPascal));
721
+ await write(`application/dtos/create-${kebab}.dto.ts`, generateCreateDTO(pascal, kebab));
722
+ await write(`application/dtos/update-${kebab}.dto.ts`, generateUpdateDTO(pascal, kebab));
723
+ await write(`application/dtos/${kebab}-response.dto.ts`, generateResponseDTO(pascal, kebab));
724
+ const useCases = generateUseCases(pascal, kebab, plural, pluralPascal);
725
+ for (const uc of useCases) {
726
+ await write(`application/use-cases/${uc.file}`, uc.content);
727
+ }
728
+ await write(`domain/repositories/${kebab}.repository.ts`, generateRepositoryInterface(pascal, kebab));
729
+ await write(`domain/services/${kebab}-domain.service.ts`, generateDomainService(pascal, kebab));
730
+ if (repo === "inmemory") {
731
+ await write(`infrastructure/repositories/in-memory-${kebab}.repository.ts`, generateInMemoryRepository(pascal, kebab));
732
+ }
733
+ if (!noEntity && !minimal) {
734
+ await write(`domain/entities/${kebab}.entity.ts`, generateEntity(pascal, kebab));
735
+ await write(`domain/value-objects/${kebab}-id.vo.ts`, generateValueObject(pascal, kebab));
736
+ }
737
+ if (!noTests) {
738
+ await write(`__tests__/${kebab}.controller.test.ts`, generateControllerTest(pascal, kebab, plural));
739
+ await write(`__tests__/${kebab}.repository.test.ts`, generateRepositoryTest(pascal, kebab, plural));
534
740
  }
535
741
  await autoRegisterModule(modulesDir, pascal, plural);
536
742
  return files;
@@ -784,7 +990,7 @@ __name(generateService, "generateService");
784
990
 
785
991
  // src/generators/controller.ts
786
992
  import { join as join6 } from "path";
787
- async function generateController(options) {
993
+ async function generateController2(options) {
788
994
  const { name, outDir } = options;
789
995
  const kebab = toKebabCase(name);
790
996
  const pascal = toPascalCase(name);
@@ -811,7 +1017,7 @@ export class ${pascal}Controller {
811
1017
  files.push(filePath);
812
1018
  return files;
813
1019
  }
814
- __name(generateController, "generateController");
1020
+ __name(generateController2, "generateController");
815
1021
 
816
1022
  // src/generators/dto.ts
817
1023
  import { join as join7 } from "path";
@@ -1116,7 +1322,7 @@ __name(loadKickConfig, "loadKickConfig");
1116
1322
  export {
1117
1323
  defineConfig,
1118
1324
  generateAdapter,
1119
- generateController,
1325
+ generateController2 as generateController,
1120
1326
  generateDto,
1121
1327
  generateGuard,
1122
1328
  generateMiddleware,