@forinda/kickjs-cli 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/cli.js +1264 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +115 -0
- package/dist/index.js +1065 -0
- package/dist/index.js.map +1 -0
- package/package.json +47 -0
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts","../src/commands/init.ts","../src/generators/project.ts","../src/utils/fs.ts","../src/commands/generate.ts","../src/generators/module.ts","../src/utils/naming.ts","../src/generators/adapter.ts","../src/generators/middleware.ts","../src/generators/guard.ts","../src/generators/service.ts","../src/generators/controller.ts","../src/generators/dto.ts","../src/utils/shell.ts","../src/commands/run.ts","../src/commands/info.ts","../src/commands/custom.ts","../src/config.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { registerInitCommand } from './commands/init'\nimport { registerGenerateCommand } from './commands/generate'\nimport { registerRunCommands } from './commands/run'\nimport { registerInfoCommand } from './commands/info'\nimport { registerCustomCommands } from './commands/custom'\nimport { loadKickConfig } from './config'\n\nasync function main() {\n const program = new Command()\n\n program\n .name('kick')\n .description('KickJS — A production-grade, decorator-driven Node.js framework')\n .version('0.1.0')\n\n // Load project-level config for custom commands and generator defaults\n const config = await loadKickConfig(process.cwd())\n\n registerInitCommand(program)\n registerGenerateCommand(program)\n registerRunCommands(program)\n registerInfoCommand(program)\n registerCustomCommands(program, config)\n\n program.showHelpAfterError()\n\n await program.parseAsync(process.argv)\n}\n\nmain().catch((err) => {\n console.error(err instanceof Error ? err.message : err)\n process.exitCode = 1\n})\n","import { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { initProject } from '../generators/project'\n\nexport function registerInitCommand(program: Command): void {\n program\n .command('new <name>')\n .alias('init')\n .description('Create a new KickJS project')\n .option('-d, --directory <dir>', 'Target directory (defaults to project name)')\n .option('--pm <manager>', 'Package manager: pnpm | npm | yarn', 'pnpm')\n .action(async (name: string, opts: any) => {\n const directory = resolve(opts.directory || name)\n await initProject({\n name,\n directory,\n packageManager: opts.pm,\n })\n })\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\n\ninterface InitProjectOptions {\n name: string\n directory: string\n packageManager?: 'pnpm' | 'npm' | 'yarn'\n}\n\n/** Scaffold a new KickJS project */\nexport async function initProject(options: InitProjectOptions): Promise<void> {\n const { name, directory, packageManager = 'pnpm' } = options\n const dir = directory\n\n console.log(`\\n Creating KickJS project: ${name}\\n`)\n\n // ── package.json ────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'package.json'),\n JSON.stringify(\n {\n name,\n version: '0.1.0',\n type: 'module',\n scripts: {\n dev: 'kick dev',\n 'dev:debug': 'kick dev:debug',\n build: 'kick build',\n start: 'kick start',\n test: 'vitest run',\n 'test:watch': 'vitest',\n typecheck: 'tsc --noEmit',\n lint: 'eslint src/',\n format: 'prettier --write src/',\n },\n dependencies: {\n '@forinda/kickjs-core': '^0.1.0',\n '@forinda/kickjs-http': '^0.1.0',\n '@forinda/kickjs-config': '^0.1.0',\n '@forinda/kickjs-swagger': '^0.1.0',\n express: '^5.1.0',\n 'reflect-metadata': '^0.2.2',\n zod: '^4.3.6',\n pino: '^10.3.1',\n 'pino-pretty': '^13.1.3',\n },\n devDependencies: {\n '@forinda/kickjs-cli': '^0.1.0',\n '@swc/core': '^1.7.28',\n '@types/express': '^5.0.6',\n '@types/node': '^24.5.2',\n 'unplugin-swc': '^1.5.9',\n vite: '^7.3.1',\n 'vite-node': '^5.3.0',\n vitest: '^3.2.4',\n typescript: '^5.9.2',\n prettier: '^3.8.1',\n },\n },\n null,\n 2,\n ),\n )\n\n // ── vite.config.ts — enables HMR + SWC for decorators ──────────────\n await writeFileSafe(\n join(dir, 'vite.config.ts'),\n `import { defineConfig } from 'vite'\nimport { resolve } from 'path'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n resolve: {\n alias: {\n '@': resolve(__dirname, 'src'),\n },\n },\n server: {\n watch: { usePolling: false },\n hmr: true,\n },\n build: {\n target: 'node20',\n ssr: true,\n outDir: 'dist',\n sourcemap: true,\n rollupOptions: {\n input: resolve(__dirname, 'src/index.ts'),\n output: { format: 'esm' },\n },\n },\n})\n`,\n )\n\n // ── tsconfig.json ───────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'tsconfig.json'),\n JSON.stringify(\n {\n compilerOptions: {\n target: 'ES2022',\n module: 'ESNext',\n moduleResolution: 'bundler',\n lib: ['ES2022'],\n types: ['node'],\n strict: true,\n esModuleInterop: true,\n skipLibCheck: true,\n sourceMap: true,\n declaration: true,\n experimentalDecorators: true,\n emitDecoratorMetadata: true,\n outDir: 'dist',\n rootDir: 'src',\n paths: { '@/*': ['./src/*'] },\n },\n include: ['src'],\n },\n null,\n 2,\n ),\n )\n\n // ── .prettierrc ─────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.prettierrc'),\n JSON.stringify(\n {\n semi: false,\n singleQuote: true,\n trailingComma: 'all',\n printWidth: 100,\n tabWidth: 2,\n },\n null,\n 2,\n ),\n )\n\n // ── .gitignore ──────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.gitignore'),\n `node_modules/\ndist/\n.env\ncoverage/\n.DS_Store\n*.tsbuildinfo\n`,\n )\n\n // ── .env ────────────────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, '.env'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n await writeFileSafe(\n join(dir, '.env.example'),\n `PORT=3000\nNODE_ENV=development\n`,\n )\n\n // ── src/index.ts — clean entry point with Swagger baked in ────────\n await writeFileSafe(\n join(dir, 'src/index.ts'),\n `import 'reflect-metadata'\nimport { bootstrap } from '@forinda/kickjs-http'\nimport { SwaggerAdapter } from '@forinda/kickjs-swagger'\nimport { modules } from './modules'\n\nbootstrap({\n modules,\n adapters: [\n new SwaggerAdapter({\n info: { title: '${name}', version: '0.1.0' },\n }),\n ],\n})\n`,\n )\n\n // ── src/modules/index.ts ────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'src/modules/index.ts'),\n `import type { AppModuleClass } from '@forinda/kickjs-core'\n\nexport const modules: AppModuleClass[] = []\n`,\n )\n\n // ── vitest.config.ts ────────────────────────────────────────────────\n await writeFileSafe(\n join(dir, 'vitest.config.ts'),\n `import { defineConfig } from 'vitest/config'\nimport swc from 'unplugin-swc'\n\nexport default defineConfig({\n plugins: [swc.vite()],\n test: {\n globals: true,\n environment: 'node',\n include: ['src/**/*.test.ts'],\n },\n})\n`,\n )\n\n console.log(' Project scaffolded successfully!')\n console.log()\n console.log(' Next steps:')\n console.log(` cd ${name}`)\n console.log(` ${packageManager} install`)\n console.log(` kick g module user`)\n console.log(` kick dev`)\n console.log()\n console.log(' Commands:')\n console.log(' kick dev Start dev server with Vite HMR')\n console.log(' kick build Production build via Vite')\n console.log(' kick start Run production build')\n console.log(' kick g module X Generate a DDD module')\n console.log()\n}\n","import { writeFile, mkdir, access, readFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\n\n/** Write a file, creating parent directories if needed */\nexport async function writeFileSafe(filePath: string, content: string): Promise<void> {\n await mkdir(dirname(filePath), { recursive: true })\n await writeFile(filePath, content, 'utf-8')\n}\n\n/** Ensure a directory exists */\nexport async function ensureDirectory(dir: string): Promise<void> {\n await mkdir(dir, { recursive: true })\n}\n\n/** Check if a file exists */\nexport async function fileExists(filePath: string): Promise<boolean> {\n try {\n await access(filePath)\n return true\n } catch {\n return false\n }\n}\n\n/** Read a JSON file */\nexport async function readJsonFile<T = any>(filePath: string): Promise<T> {\n const content = await readFile(filePath, 'utf-8')\n return JSON.parse(content)\n}\n","import { resolve } from 'node:path'\nimport type { Command } from 'commander'\nimport { generateModule } from '../generators/module'\nimport { generateAdapter } from '../generators/adapter'\nimport { generateMiddleware } from '../generators/middleware'\nimport { generateGuard } from '../generators/guard'\nimport { generateService } from '../generators/service'\nimport { generateController } from '../generators/controller'\nimport { generateDto } from '../generators/dto'\n\nfunction printGenerated(files: string[]): void {\n const cwd = process.cwd()\n console.log(`\\n Generated ${files.length} file${files.length === 1 ? '' : 's'}:`)\n for (const f of files) {\n console.log(` ${f.replace(cwd + '/', '')}`)\n }\n console.log()\n}\n\nexport function registerGenerateCommand(program: Command): void {\n const gen = program.command('generate').alias('g').description('Generate code scaffolds')\n\n // ── kick g module <name> ────────────────────────────────────────────\n gen\n .command('module <name>')\n .description('Generate a full DDD module with all layers')\n .option('--no-entity', 'Skip entity and value object generation')\n .option('--no-tests', 'Skip test file generation')\n .option('--repo <type>', 'Repository implementation: inmemory | drizzle', 'inmemory')\n .option('--minimal', 'Only generate index.ts and controller')\n .option('--modules-dir <dir>', 'Modules directory', 'src/modules')\n .action(async (name: string, opts: any) => {\n const files = await generateModule({\n name,\n modulesDir: resolve(opts.modulesDir),\n noEntity: opts.entity === false,\n noTests: opts.tests === false,\n repo: opts.repo,\n minimal: opts.minimal,\n })\n printGenerated(files)\n })\n\n // ── kick g adapter <name> ──────────────────────────────────────────\n gen\n .command('adapter <name>')\n .description('Generate an AppAdapter with lifecycle hooks and middleware support')\n .option('-o, --out <dir>', 'Output directory', 'src/adapters')\n .action(async (name: string, opts: any) => {\n const files = await generateAdapter({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g middleware <name> ────────────────────────────────────────\n gen\n .command('middleware <name>')\n .description('Generate an Express middleware function')\n .option('-o, --out <dir>', 'Output directory', 'src/middleware')\n .action(async (name: string, opts: any) => {\n const files = await generateMiddleware({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g guard <name> ────────────────────────────────────────────\n gen\n .command('guard <name>')\n .description('Generate a route guard (auth, roles, etc.)')\n .option('-o, --out <dir>', 'Output directory', 'src/guards')\n .action(async (name: string, opts: any) => {\n const files = await generateGuard({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g service <name> ──────────────────────────────────────────\n gen\n .command('service <name>')\n .description('Generate a @Service() class')\n .option('-o, --out <dir>', 'Output directory', 'src/services')\n .action(async (name: string, opts: any) => {\n const files = await generateService({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g controller <name> ───────────────────────────────────────\n gen\n .command('controller <name>')\n .description('Generate a @Controller() class with basic routes')\n .option('-o, --out <dir>', 'Output directory', 'src/controllers')\n .action(async (name: string, opts: any) => {\n const files = await generateController({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n\n // ── kick g dto <name> ──────────────────────────────────────────────\n gen\n .command('dto <name>')\n .description('Generate a Zod DTO schema')\n .option('-o, --out <dir>', 'Output directory', 'src/dtos')\n .action(async (name: string, opts: any) => {\n const files = await generateDto({ name, outDir: resolve(opts.out) })\n printGenerated(files)\n })\n}\n","import { join } from 'node:path'\nimport { writeFileSafe, fileExists } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase, pluralize, pluralizePascal } from '../utils/naming'\nimport { readFile, writeFile } from 'node:fs/promises'\n\ninterface GenerateModuleOptions {\n name: string\n modulesDir: string\n noEntity?: boolean\n noTests?: boolean\n repo?: 'drizzle' | 'inmemory'\n minimal?: boolean\n}\n\n/**\n * Generate a full DDD module with all layers:\n * presentation/ — controller\n * application/ — use-cases, DTOs\n * domain/ — entity, value objects, repository interface, domain service\n * infrastructure/ — repository implementation\n */\nexport async function generateModule(options: GenerateModuleOptions): Promise<string[]> {\n const { name, modulesDir, noEntity, noTests, repo = 'inmemory', minimal } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const plural = pluralize(kebab)\n const pluralPascal = pluralizePascal(pascal)\n const moduleDir = join(modulesDir, plural)\n\n const files: string[] = []\n\n const write = async (relativePath: string, content: string) => {\n const fullPath = join(moduleDir, relativePath)\n await writeFileSafe(fullPath, content)\n files.push(fullPath)\n }\n\n // ── Module Index ────────────────────────────────────────────────────\n await write(\n 'index.ts',\n `/**\n * ${pascal} Module\n *\n * Self-contained feature module following Domain-Driven Design (DDD).\n * Registers dependencies in the DI container and declares HTTP routes.\n *\n * Structure:\n * presentation/ — HTTP controllers (entry points)\n * application/ — Use cases (orchestration) and DTOs (validation)\n * domain/ — Entities, value objects, repository interfaces, domain services\n * infrastructure/ — Repository implementations (in-memory, Drizzle, Prisma, etc.)\n */\nimport { Container, type AppModule, type ModuleRoutes } from '@forinda/kickjs-core'\nimport { buildRoutes } from '@forinda/kickjs-http'\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository'\nimport { ${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`} } from './infrastructure/repositories/${repo === 'inmemory' ? `in-memory-${kebab}` : `drizzle-${kebab}`}.repository'\nimport { ${pascal}Controller } from './presentation/${kebab}.controller'\n\n// Eagerly load decorated classes so @Service()/@Repository() decorators register in the DI container\nimport.meta.glob(\n ['./domain/services/**/*.ts', './application/use-cases/**/*.ts', '!./**/*.test.ts'],\n { eager: true },\n)\n\nexport class ${pascal}Module implements AppModule {\n /**\n * Register module dependencies in the DI container.\n * Bind repository interface tokens to their implementations here.\n * To swap implementations (e.g. in-memory -> Drizzle), change the factory target.\n */\n register(container: Container): void {\n container.registerFactory(${pascal.toUpperCase()}_REPOSITORY, () =>\n container.resolve(${repo === 'inmemory' ? `InMemory${pascal}Repository` : `Drizzle${pascal}Repository`}),\n )\n }\n\n /**\n * Declare HTTP routes for this module.\n * The path is prefixed with the global apiPrefix and version (e.g. /api/v1/${plural}).\n * Passing 'controller' enables automatic OpenAPI spec generation via SwaggerAdapter.\n */\n routes(): ModuleRoutes {\n return {\n path: '/${plural}',\n router: buildRoutes(${pascal}Controller),\n controller: ${pascal}Controller,\n }\n }\n}\n`,\n )\n\n // ── Controller ──────────────────────────────────────────────────────\n await write(\n `presentation/${kebab}.controller.ts`,\n `/**\n * ${pascal} Controller\n *\n * Presentation layer — handles HTTP requests and delegates to use cases.\n * Each method receives a RequestContext with typed body, params, and query.\n *\n * Decorators:\n * @Controller(path?) — registers this class as an HTTP controller\n * @Get/@Post/@Put/@Delete(path?, validation?) — defines routes with optional Zod validation\n * @Autowired() — injects dependencies lazily from the DI container\n * @Middleware(...handlers) — attach middleware at class or method level\n *\n * Add Swagger decorators (@ApiTags, @ApiOperation, @ApiResponse) from @forinda/kickjs-swagger\n * for automatic OpenAPI documentation.\n */\nimport { Controller, Get, Post, Put, Delete, Autowired } from '@forinda/kickjs-core'\nimport { RequestContext } from '@forinda/kickjs-http'\nimport { Create${pascal}UseCase } from '../application/use-cases/create-${kebab}.use-case'\nimport { Get${pascal}UseCase } from '../application/use-cases/get-${kebab}.use-case'\nimport { List${pluralPascal}UseCase } from '../application/use-cases/list-${plural}.use-case'\nimport { Update${pascal}UseCase } from '../application/use-cases/update-${kebab}.use-case'\nimport { Delete${pascal}UseCase } from '../application/use-cases/delete-${kebab}.use-case'\nimport { create${pascal}Schema } from '../application/dtos/create-${kebab}.dto'\nimport { update${pascal}Schema } from '../application/dtos/update-${kebab}.dto'\n\n@Controller()\nexport class ${pascal}Controller {\n @Autowired() private create${pascal}UseCase!: Create${pascal}UseCase\n @Autowired() private get${pascal}UseCase!: Get${pascal}UseCase\n @Autowired() private list${pluralPascal}UseCase!: List${pluralPascal}UseCase\n @Autowired() private update${pascal}UseCase!: Update${pascal}UseCase\n @Autowired() private delete${pascal}UseCase!: Delete${pascal}UseCase\n\n @Post('/', { body: create${pascal}Schema })\n async create(ctx: RequestContext) {\n const result = await this.create${pascal}UseCase.execute(ctx.body)\n ctx.created(result)\n }\n\n @Get('/')\n async list(ctx: RequestContext) {\n const result = await this.list${pluralPascal}UseCase.execute()\n ctx.json(result)\n }\n\n @Get('/:id')\n async getById(ctx: RequestContext) {\n const result = await this.get${pascal}UseCase.execute(ctx.params.id)\n if (!result) return ctx.notFound('${pascal} not found')\n ctx.json(result)\n }\n\n @Put('/:id', { body: update${pascal}Schema })\n async update(ctx: RequestContext) {\n const result = await this.update${pascal}UseCase.execute(ctx.params.id, ctx.body)\n ctx.json(result)\n }\n\n @Delete('/:id')\n async remove(ctx: RequestContext) {\n await this.delete${pascal}UseCase.execute(ctx.params.id)\n ctx.noContent()\n }\n}\n`,\n )\n\n // ── DTOs ────────────────────────────────────────────────────────────\n await write(\n `application/dtos/create-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\n/**\n * Create ${pascal} DTO — Zod schema for validating POST request bodies.\n * This schema is passed to @Post('/', { body: create${pascal}Schema }) for automatic validation.\n * It also generates OpenAPI request body docs when SwaggerAdapter is used.\n *\n * Add more fields as needed. Supported Zod types:\n * z.string(), z.number(), z.boolean(), z.enum([...]),\n * z.array(), z.object(), .optional(), .default(), .transform()\n */\nexport const create${pascal}Schema = z.object({\n name: z.string().min(1, 'Name is required').max(200),\n})\n\nexport type Create${pascal}DTO = z.infer<typeof create${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/update-${kebab}.dto.ts`,\n `import { z } from 'zod'\n\nexport const update${pascal}Schema = z.object({\n name: z.string().min(1).max(200).optional(),\n})\n\nexport type Update${pascal}DTO = z.infer<typeof update${pascal}Schema>\n`,\n )\n\n await write(\n `application/dtos/${kebab}-response.dto.ts`,\n `export interface ${pascal}ResponseDTO {\n id: string\n name: string\n createdAt: string\n updatedAt: string\n}\n`,\n )\n\n // ── Use Cases ───────────────────────────────────────────────────────\n const useCases = [\n {\n file: `create-${kebab}.use-case.ts`,\n content: `/**\n * Create ${pascal} Use Case\n *\n * Application layer — orchestrates a single business operation.\n * Use cases are thin: validate input (via DTO), call domain/repo, return response.\n * Keep business rules in the domain service, not here.\n */\nimport { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Create${pascal}DTO } from '../dtos/create-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.create(dto)\n }\n}\n`,\n },\n {\n file: `get-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Get${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.repo.findById(id)\n }\n}\n`,\n },\n {\n file: `list-${plural}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class List${pluralPascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(): Promise<${pascal}ResponseDTO[]> {\n return this.repo.findAll()\n }\n}\n`,\n },\n {\n file: `update-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { Update${pascal}DTO } from '../dtos/update-${kebab}.dto'\nimport type { ${pascal}ResponseDTO } from '../dtos/${kebab}-response.dto'\n\n@Service()\nexport class Update${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n return this.repo.update(id, dto)\n }\n}\n`,\n },\n {\n file: `delete-${kebab}.use-case.ts`,\n content: `import { Service, Inject } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\n\n@Service()\nexport class Delete${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async execute(id: string): Promise<void> {\n await this.repo.delete(id)\n }\n}\n`,\n },\n ]\n\n for (const uc of useCases) {\n await write(`application/use-cases/${uc.file}`, uc.content)\n }\n\n // ── Domain: Repository Interface ────────────────────────────────────\n await write(\n `domain/repositories/${kebab}.repository.ts`,\n `/**\n * ${pascal} Repository Interface\n *\n * Domain layer — defines the contract for data access.\n * The interface lives in the domain layer; implementations live in infrastructure.\n * This inversion of dependencies keeps the domain pure and testable.\n *\n * To swap implementations (e.g. in-memory -> Drizzle -> Prisma),\n * change the factory in the module's register() method.\n */\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\nexport interface I${pascal}Repository {\n findById(id: string): Promise<${pascal}ResponseDTO | null>\n findAll(): Promise<${pascal}ResponseDTO[]>\n create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO>\n update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO>\n delete(id: string): Promise<void>\n}\n\nexport const ${pascal.toUpperCase()}_REPOSITORY = Symbol('I${pascal}Repository')\n`,\n )\n\n // ── Domain: Service ─────────────────────────────────────────────────\n await write(\n `domain/services/${kebab}-domain.service.ts`,\n `/**\n * ${pascal} Domain Service\n *\n * Domain layer — contains business rules that don't belong to a single entity.\n * Use this for cross-entity logic, validation rules, and domain invariants.\n * Keep it free of HTTP/framework concerns.\n */\nimport { Service, Inject, HttpException } from '@forinda/kickjs-core'\nimport { ${pascal.toUpperCase()}_REPOSITORY, type I${pascal}Repository } from '../repositories/${kebab}.repository'\n\n@Service()\nexport class ${pascal}DomainService {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY) private readonly repo: I${pascal}Repository,\n ) {}\n\n async ensureExists(id: string): Promise<void> {\n const entity = await this.repo.findById(id)\n if (!entity) {\n throw HttpException.notFound('${pascal} not found')\n }\n }\n}\n`,\n )\n\n // ── Infrastructure: Repository Implementation ──────────────────────\n if (repo === 'inmemory') {\n await write(\n `infrastructure/repositories/in-memory-${kebab}.repository.ts`,\n `/**\n * In-Memory ${pascal} Repository\n *\n * Infrastructure layer — implements the repository interface using a Map.\n * Useful for prototyping and testing. Replace with a database implementation\n * (Drizzle, Prisma, etc.) for production use.\n *\n * @Repository() registers this class in the DI container as a singleton.\n */\nimport { randomUUID } from 'node:crypto'\nimport { Repository, HttpException } from '@forinda/kickjs-core'\nimport type { I${pascal}Repository } from '../../domain/repositories/${kebab}.repository'\nimport type { ${pascal}ResponseDTO } from '../../application/dtos/${kebab}-response.dto'\nimport type { Create${pascal}DTO } from '../../application/dtos/create-${kebab}.dto'\nimport type { Update${pascal}DTO } from '../../application/dtos/update-${kebab}.dto'\n\n@Repository()\nexport class InMemory${pascal}Repository implements I${pascal}Repository {\n private store = new Map<string, ${pascal}ResponseDTO>()\n\n async findById(id: string): Promise<${pascal}ResponseDTO | null> {\n return this.store.get(id) ?? null\n }\n\n async findAll(): Promise<${pascal}ResponseDTO[]> {\n return Array.from(this.store.values())\n }\n\n async create(dto: Create${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const now = new Date().toISOString()\n const entity: ${pascal}ResponseDTO = {\n id: randomUUID(),\n name: dto.name,\n createdAt: now,\n updatedAt: now,\n }\n this.store.set(entity.id, entity)\n return entity\n }\n\n async update(id: string, dto: Update${pascal}DTO): Promise<${pascal}ResponseDTO> {\n const existing = this.store.get(id)\n if (!existing) throw HttpException.notFound('${pascal} not found')\n const updated = { ...existing, ...dto, updatedAt: new Date().toISOString() }\n this.store.set(id, updated)\n return updated\n }\n\n async delete(id: string): Promise<void> {\n if (!this.store.has(id)) throw HttpException.notFound('${pascal} not found')\n this.store.delete(id)\n }\n}\n`,\n )\n }\n\n // ── Entity & Value Objects ──────────────────────────────────────────\n if (!noEntity && !minimal) {\n await write(\n `domain/entities/${kebab}.entity.ts`,\n `/**\n * ${pascal} Entity\n *\n * Domain layer — the core business object.\n * Uses a private constructor with static factory methods (create, reconstitute)\n * to enforce invariants. Properties are accessed via getters to maintain encapsulation.\n *\n * Patterns used:\n * - Private constructor: prevents direct instantiation\n * - create(): factory for new entities (generates ID, sets timestamps)\n * - reconstitute(): factory for rebuilding from persistence (no side effects)\n * - changeName(): mutation method that enforces business rules\n */\nimport { ${pascal}Id } from '../value-objects/${kebab}-id.vo'\n\ninterface ${pascal}Props {\n id: ${pascal}Id\n name: string\n createdAt: Date\n updatedAt: Date\n}\n\nexport class ${pascal} {\n private constructor(private props: ${pascal}Props) {}\n\n static create(params: { name: string }): ${pascal} {\n const now = new Date()\n return new ${pascal}({\n id: ${pascal}Id.create(),\n name: params.name,\n createdAt: now,\n updatedAt: now,\n })\n }\n\n static reconstitute(props: ${pascal}Props): ${pascal} {\n return new ${pascal}(props)\n }\n\n get id(): ${pascal}Id {\n return this.props.id\n }\n get name(): string {\n return this.props.name\n }\n get createdAt(): Date {\n return this.props.createdAt\n }\n get updatedAt(): Date {\n return this.props.updatedAt\n }\n\n changeName(name: string): void {\n if (!name || name.trim().length === 0) {\n throw new Error('Name cannot be empty')\n }\n this.props.name = name.trim()\n this.props.updatedAt = new Date()\n }\n\n toJSON() {\n return {\n id: this.props.id.toString(),\n name: this.props.name,\n createdAt: this.props.createdAt.toISOString(),\n updatedAt: this.props.updatedAt.toISOString(),\n }\n }\n}\n`,\n )\n\n await write(\n `domain/value-objects/${kebab}-id.vo.ts`,\n `/**\n * ${pascal} ID Value Object\n *\n * Domain layer — wraps a primitive ID with type safety and validation.\n * Value objects are immutable and compared by value, not reference.\n *\n * ${pascal}Id.create() — generate a new UUID\n * ${pascal}Id.from(id) — wrap an existing ID string (validates non-empty)\n * id.equals(other) — compare two IDs by value\n */\nimport { randomUUID } from 'node:crypto'\n\nexport class ${pascal}Id {\n private constructor(private readonly value: string) {}\n\n static create(): ${pascal}Id {\n return new ${pascal}Id(randomUUID())\n }\n\n static from(id: string): ${pascal}Id {\n if (!id || id.trim().length === 0) {\n throw new Error('${pascal}Id cannot be empty')\n }\n return new ${pascal}Id(id)\n }\n\n toString(): string {\n return this.value\n }\n\n equals(other: ${pascal}Id): boolean {\n return this.value === other.value\n }\n}\n`,\n )\n }\n\n // ── Auto-register in modules index ──────────────────────────────────\n await autoRegisterModule(modulesDir, pascal, plural)\n\n return files\n}\n\n/** Add the new module to src/modules/index.ts */\nasync function autoRegisterModule(\n modulesDir: string,\n pascal: string,\n plural: string,\n): Promise<void> {\n const indexPath = join(modulesDir, 'index.ts')\n const exists = await fileExists(indexPath)\n\n if (!exists) {\n await writeFileSafe(\n indexPath,\n `import type { AppModuleClass } from '@forinda/kickjs-core'\nimport { ${pascal}Module } from './${plural}'\n\nexport const modules: AppModuleClass[] = [${pascal}Module]\n`,\n )\n return\n }\n\n let content = await readFile(indexPath, 'utf-8')\n\n // Add import if not present\n const importLine = `import { ${pascal}Module } from './${plural}'`\n if (!content.includes(`${pascal}Module`)) {\n // Insert import after last existing import\n const lastImportIdx = content.lastIndexOf('import ')\n if (lastImportIdx !== -1) {\n const lineEnd = content.indexOf('\\n', lastImportIdx)\n content = content.slice(0, lineEnd + 1) + importLine + '\\n' + content.slice(lineEnd + 1)\n } else {\n content = importLine + '\\n' + content\n }\n\n // Add to modules array — handle both empty and existing entries\n // Match the array assignment: `= [...]` or `= [\\n...\\n]`\n content = content.replace(/(=\\s*\\[)([\\s\\S]*?)(])/, (_match, open, existing, close) => {\n const trimmed = existing.trim()\n if (!trimmed) {\n // Empty array: `= []`\n return `${open}${pascal}Module${close}`\n }\n // Existing entries: append with comma\n const needsComma = trimmed.endsWith(',') ? '' : ','\n return `${open}${existing.trimEnd()}${needsComma} ${pascal}Module${close}`\n })\n }\n\n await writeFile(indexPath, content, 'utf-8')\n}\n","/** Convert a name to PascalCase */\nexport function toPascalCase(name: string): string {\n return name\n .replace(/[-_\\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ''))\n .replace(/^(.)/, (c) => c.toUpperCase())\n}\n\n/** Convert a name to camelCase */\nexport function toCamelCase(name: string): string {\n const pascal = toPascalCase(name)\n return pascal.charAt(0).toLowerCase() + pascal.slice(1)\n}\n\n/** Convert a name to kebab-case */\nexport function toKebabCase(name: string): string {\n return name\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase()\n}\n\n/**\n * Pluralize a kebab-case name for directory/file names.\n * If already plural (ends in 's'), returns as-is.\n */\nexport function pluralize(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n\n/**\n * Pluralize a PascalCase name for class identifiers.\n * If already plural (ends in 's'), returns as-is.\n * Used for `List${pluralPascal}UseCase` to avoid `ListUserssUseCase`.\n */\nexport function pluralizePascal(name: string): string {\n if (name.endsWith('s')) return name\n if (name.endsWith('x') || name.endsWith('z')) return name + 'es'\n if (name.endsWith('sh') || name.endsWith('ch')) return name + 'es'\n if (name.endsWith('y') && !/[aeiou]y$/i.test(name)) return name.slice(0, -1) + 'ies'\n return name + 's'\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateAdapterOptions {\n name: string\n outDir: string\n}\n\nexport async function generateAdapter(options: GenerateAdapterOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.adapter.ts`)\n await writeFileSafe(\n filePath,\n `import type { Express } from 'express'\nimport type { AppAdapter, AdapterMiddleware, Container } from '@forinda/kickjs-core'\n\nexport interface ${pascal}AdapterOptions {\n // Add your adapter configuration here\n}\n\n/**\n * ${pascal} adapter.\n *\n * Hooks into the Application lifecycle to add middleware, routes,\n * or external service connections.\n *\n * Usage:\n * bootstrap({\n * adapters: [new ${pascal}Adapter({ ... })],\n * })\n */\nexport class ${pascal}Adapter implements AppAdapter {\n name = '${pascal}Adapter'\n\n constructor(private options: ${pascal}AdapterOptions = {}) {}\n\n /**\n * Return middleware entries that the Application will mount.\n * Use \\`phase\\` to control where in the pipeline they run:\n * 'beforeGlobal' | 'afterGlobal' | 'beforeRoutes' | 'afterRoutes'\n */\n middleware(): AdapterMiddleware[] {\n return [\n // Example: add a custom header to all responses\n // {\n // phase: 'beforeGlobal',\n // handler: (_req: any, res: any, next: any) => {\n // res.setHeader('X-${pascal}', 'true')\n // next()\n // },\n // },\n // Example: scope middleware to a specific path\n // {\n // phase: 'beforeRoutes',\n // path: '/api/v1/admin',\n // handler: myAdminMiddleware(),\n // },\n ]\n }\n\n /**\n * Called before global middleware.\n * Use this to mount routes that bypass the middleware stack\n * (health checks, docs UI, static assets).\n */\n beforeMount(app: Express, container: Container): void {\n // Example: mount a status route\n // app.get('/${kebab}/status', (_req, res) => {\n // res.json({ status: 'ok' })\n // })\n }\n\n /**\n * Called after modules and routes are registered, before the server starts.\n * Use this for late-stage DI registrations or config validation.\n */\n beforeStart(app: Express, container: Container): void {\n // Example: register a service in the DI container\n // container.registerInstance(MY_TOKEN, new MyService(this.options))\n }\n\n /**\n * Called after the HTTP server is listening.\n * Use this to attach to the raw http.Server (Socket.IO, gRPC, etc).\n */\n afterStart(server: any, container: Container): void {\n // Example: attach Socket.IO\n // const io = new Server(server)\n // container.registerInstance(SOCKET_IO, io)\n }\n\n /**\n * Called on graceful shutdown. Clean up connections.\n */\n async shutdown(): Promise<void> {\n // Example: close a connection pool\n // await this.pool.end()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateMiddlewareOptions {\n name: string\n outDir: string\n}\n\nexport async function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.middleware.ts`)\n await writeFileSafe(\n filePath,\n `import type { Request, Response, NextFunction } from 'express'\n\nexport interface ${toPascalCase(name)}Options {\n // Add configuration options here\n}\n\n/**\n * ${toPascalCase(name)} middleware.\n *\n * Usage in bootstrap:\n * middleware: [${camel}()]\n *\n * Usage with adapter:\n * middleware() { return [{ handler: ${camel}(), phase: 'afterGlobal' }] }\n *\n * Usage with @Middleware decorator:\n * @Middleware(${camel}())\n */\nexport function ${camel}(options: ${toPascalCase(name)}Options = {}) {\n return (req: Request, res: Response, next: NextFunction) => {\n // Implement your middleware logic here\n next()\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateGuardOptions {\n name: string\n outDir: string\n}\n\nexport async function generateGuard(options: GenerateGuardOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const camel = toCamelCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.guard.ts`)\n await writeFileSafe(\n filePath,\n `import { Container, HttpException } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n/**\n * ${pascal} guard.\n *\n * Guards protect routes by checking conditions before the handler runs.\n * Return early with an error response to block access.\n *\n * Usage:\n * @Middleware(${camel}Guard)\n * @Get('/protected')\n * async handler(ctx: RequestContext) { ... }\n */\nexport async function ${camel}Guard(ctx: RequestContext, next: () => void): Promise<void> {\n // Example: check for an authorization header\n const header = ctx.headers.authorization\n if (!header?.startsWith('Bearer ')) {\n ctx.res.status(401).json({ message: 'Missing or invalid authorization header' })\n return\n }\n\n const token = header.slice(7)\n\n try {\n // Verify the token using a service from the DI container\n // const container = Container.getInstance()\n // const authService = container.resolve(AuthService)\n // const payload = authService.verifyToken(token)\n // ctx.set('auth', payload)\n\n next()\n } catch {\n ctx.res.status(401).json({ message: 'Invalid or expired token' })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateServiceOptions {\n name: string\n outDir: string\n}\n\nexport async function generateService(options: GenerateServiceOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.service.ts`)\n await writeFileSafe(\n filePath,\n `import { Service } from '@forinda/kickjs-core'\n\n@Service()\nexport class ${pascal}Service {\n // Inject dependencies via constructor\n // constructor(\n // @Inject(MY_REPO) private readonly repo: IMyRepository,\n // ) {}\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase } from '../utils/naming'\n\ninterface GenerateControllerOptions {\n name: string\n outDir: string\n}\n\nexport async function generateController(options: GenerateControllerOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.controller.ts`)\n await writeFileSafe(\n filePath,\n `import { Controller, Get, Post, Autowired } from '@forinda/kickjs-core'\nimport type { RequestContext } from '@forinda/kickjs-http'\n\n@Controller()\nexport class ${pascal}Controller {\n // @Autowired() private myService!: MyService\n\n @Get('/')\n async list(ctx: RequestContext) {\n ctx.json({ message: '${pascal} list' })\n }\n\n @Post('/')\n async create(ctx: RequestContext) {\n ctx.created({ message: '${pascal} created', data: ctx.body })\n }\n}\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { join } from 'node:path'\nimport { writeFileSafe } from '../utils/fs'\nimport { toPascalCase, toKebabCase, toCamelCase } from '../utils/naming'\n\ninterface GenerateDtoOptions {\n name: string\n outDir: string\n}\n\nexport async function generateDto(options: GenerateDtoOptions): Promise<string[]> {\n const { name, outDir } = options\n const kebab = toKebabCase(name)\n const pascal = toPascalCase(name)\n const camel = toCamelCase(name)\n const files: string[] = []\n\n const filePath = join(outDir, `${kebab}.dto.ts`)\n await writeFileSafe(\n filePath,\n `import { z } from 'zod'\n\nexport const ${camel}Schema = z.object({\n // Define your schema fields here\n name: z.string().min(1).max(200),\n})\n\nexport type ${pascal}DTO = z.infer<typeof ${camel}Schema>\n`,\n )\n files.push(filePath)\n\n return files\n}\n","import { execSync } from 'node:child_process'\n\n/** Run a shell command synchronously, printing output */\nexport function runShellCommand(command: string, cwd?: string): void {\n execSync(command, {\n cwd,\n stdio: 'inherit',\n })\n}\n","import type { Command } from 'commander'\nimport { runShellCommand } from '../utils/shell'\n\nexport function registerRunCommands(program: Command): void {\n program\n .command('dev')\n .description('Start development server with Vite HMR (zero-downtime reload)')\n .option('-e, --entry <file>', 'Entry file', 'src/index.ts')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars: string[] = []\n if (opts.port) envVars.push(`PORT=${opts.port}`)\n\n // vite-node --watch gives true HMR via import.meta.hot.accept()\n // The Application.rebuild() swaps the Express handler on the existing\n // http.Server — DB, Redis, Socket.IO connections survive across reloads\n const cmd = `npx vite-node --watch ${opts.entry}`\n const fullCmd = envVars.length ? `${envVars.join(' ')} ${cmd}` : cmd\n\n console.log(`\\n KickJS dev server starting...`)\n console.log(` Entry: ${opts.entry}`)\n console.log(` HMR: enabled (vite-node)\\n`)\n\n try {\n runShellCommand(fullCmd)\n } catch {\n // Process exits on SIGINT — expected\n }\n })\n\n program\n .command('build')\n .description('Build for production via Vite')\n .action(() => {\n console.log('\\n Building for production...\\n')\n runShellCommand('npx vite build')\n })\n\n program\n .command('start')\n .description('Start production server')\n .option('-e, --entry <file>', 'Entry file', 'dist/index.js')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars: string[] = ['NODE_ENV=production']\n if (opts.port) envVars.push(`PORT=${opts.port}`)\n runShellCommand(`${envVars.join(' ')} node ${opts.entry}`)\n })\n\n program\n .command('dev:debug')\n .description('Start dev server with Node.js inspector')\n .option('-e, --entry <file>', 'Entry file', 'src/index.ts')\n .option('-p, --port <port>', 'Port number')\n .action((opts: any) => {\n const envVars = opts.port ? `PORT=${opts.port} ` : ''\n try {\n runShellCommand(`${envVars}npx vite-node --inspect --watch ${opts.entry}`)\n } catch {\n // SIGINT\n }\n })\n}\n","import { platform, release, arch } from 'node:os'\nimport type { Command } from 'commander'\n\nexport function registerInfoCommand(program: Command): void {\n program\n .command('info')\n .description('Print system and framework info')\n .action(() => {\n console.log(`\n KickJS CLI\n\n System:\n OS: ${platform()} ${release()} (${arch()})\n Node: ${process.version}\n\n Packages:\n @forinda/kickjs-core workspace\n @forinda/kickjs-http workspace\n @forinda/kickjs-config workspace\n @forinda/kickjs-cli workspace\n`)\n })\n}\n","import type { Command } from 'commander'\nimport type { KickConfig, KickCommandDefinition } from '../config'\nimport { runShellCommand } from '../utils/shell'\n\n/**\n * Register custom commands defined in kick.config.ts\n *\n * Developers can extend the CLI with project-specific commands like:\n * kick db:migrate\n * kick db:generate\n * kick seed\n * kick proto:gen\n *\n * @example kick.config.ts\n * ```ts\n * import { defineConfig } from '@forinda/kickjs-cli'\n *\n * export default defineConfig({\n * commands: [\n * {\n * name: 'db:generate',\n * description: 'Generate Drizzle migrations from schema',\n * steps: 'npx drizzle-kit generate',\n * },\n * {\n * name: 'db:migrate',\n * description: 'Run database migrations',\n * steps: 'npx drizzle-kit migrate',\n * },\n * {\n * name: 'db:push',\n * description: 'Push schema directly (dev only)',\n * steps: 'npx drizzle-kit push',\n * },\n * {\n * name: 'db:studio',\n * description: 'Open Drizzle Studio GUI',\n * steps: 'npx drizzle-kit studio',\n * },\n * {\n * name: 'db:seed',\n * description: 'Run seed files',\n * steps: 'npx tsx src/db/seed.ts',\n * },\n * {\n * name: 'proto:gen',\n * description: 'Generate TypeScript from protobuf definitions',\n * steps: [\n * 'npx buf generate',\n * 'echo \"Protobuf types generated\"',\n * ],\n * },\n * ],\n * })\n * ```\n */\nexport function registerCustomCommands(program: Command, config: KickConfig | null): void {\n if (!config?.commands?.length) return\n\n for (const cmd of config.commands) {\n registerSingleCommand(program, cmd)\n }\n}\n\nfunction registerSingleCommand(program: Command, def: KickCommandDefinition): void {\n const command = program.command(def.name).description(def.description)\n\n if (def.aliases) {\n for (const alias of def.aliases) {\n command.alias(alias)\n }\n }\n\n // Accept arbitrary trailing arguments\n command.allowUnknownOption(true)\n command.argument('[args...]', 'Additional arguments passed to the command')\n\n command.action((args: string[]) => {\n const extraArgs = args.join(' ')\n const steps = Array.isArray(def.steps) ? def.steps : [def.steps]\n\n for (const step of steps) {\n // Replace {args} placeholder with CLI arguments\n const finalCmd = extraArgs ? `${step} ${extraArgs}` : step\n console.log(` $ ${finalCmd}`)\n try {\n runShellCommand(finalCmd)\n } catch (err: any) {\n console.error(` Command failed: ${def.name}`)\n process.exitCode = 1\n return\n }\n }\n })\n}\n","import { readFile, access } from 'node:fs/promises'\nimport { join } from 'node:path'\n\n/** A custom command that developers can register via kick.config.ts */\nexport interface KickCommandDefinition {\n /** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */\n name: string\n /** Description shown in --help */\n description: string\n /**\n * Shell command(s) to run. Can be a single string or an array of\n * sequential steps. Use {args} as a placeholder for CLI arguments.\n *\n * @example\n * 'npx drizzle-kit migrate'\n * ['npx drizzle-kit generate', 'npx drizzle-kit migrate']\n */\n steps: string | string[]\n /** Optional aliases (e.g. ['migrate'] for 'db:migrate') */\n aliases?: string[]\n}\n\n/** Configuration for the kick.config.ts file */\nexport interface KickConfig {\n /** Where modules live (default: 'src/modules') */\n modulesDir?: string\n /** Default repository implementation for generators */\n defaultRepo?: 'drizzle' | 'inmemory' | 'prisma'\n /** Drizzle schema output directory */\n schemaDir?: string\n /** Custom commands that extend the CLI */\n commands?: KickCommandDefinition[]\n /** Code style overrides (auto-detected from prettier when possible) */\n style?: {\n semicolons?: boolean\n quotes?: 'single' | 'double'\n trailingComma?: 'all' | 'es5' | 'none'\n indent?: number\n }\n}\n\n/** Helper to define a type-safe kick.config.ts */\nexport function defineConfig(config: KickConfig): KickConfig {\n return config\n}\n\nconst CONFIG_FILES = ['kick.config.ts', 'kick.config.js', 'kick.config.mjs', 'kick.config.json']\n\n/** Load kick.config.* from the project root */\nexport async function loadKickConfig(cwd: string): Promise<KickConfig | null> {\n for (const filename of CONFIG_FILES) {\n const filepath = join(cwd, filename)\n try {\n await access(filepath)\n } catch {\n continue\n }\n\n if (filename.endsWith('.json')) {\n const content = await readFile(filepath, 'utf-8')\n return JSON.parse(content)\n }\n\n // For .ts/.js/.mjs — dynamic import (use file URL for cross-platform compat)\n try {\n const { pathToFileURL } = await import('node:url')\n const mod = await import(pathToFileURL(filepath).href)\n return mod.default ?? mod\n } catch (err) {\n if (filename.endsWith('.ts')) {\n console.warn(\n `Warning: Failed to load ${filename}. TypeScript config files require ` +\n 'a runtime loader (e.g. tsx, ts-node) or use kick.config.js/.mjs instead.',\n )\n }\n continue\n }\n }\n return null\n}\n"],"mappings":"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","names":["Command","resolve","join","writeFile","mkdir","access","readFile","dirname","writeFileSafe","filePath","content","mkdir","dirname","recursive","writeFile","fileExists","filePath","access","initProject","options","name","directory","packageManager","dir","console","log","writeFileSafe","join","JSON","stringify","version","type","scripts","dev","build","start","test","typecheck","lint","format","dependencies","express","zod","pino","devDependencies","vite","vitest","typescript","prettier","compilerOptions","target","module","moduleResolution","lib","types","strict","esModuleInterop","skipLibCheck","sourceMap","declaration","experimentalDecorators","emitDecoratorMetadata","outDir","rootDir","paths","include","semi","singleQuote","trailingComma","printWidth","tabWidth","registerInitCommand","program","command","alias","description","option","action","name","opts","directory","resolve","initProject","packageManager","pm","resolve","join","toPascalCase","name","replace","_","c","toUpperCase","toCamelCase","pascal","charAt","toLowerCase","slice","toKebabCase","pluralize","endsWith","test","pluralizePascal","readFile","writeFile","generateModule","options","name","modulesDir","noEntity","noTests","repo","minimal","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","plural","pluralize","pluralPascal","pluralizePascal","moduleDir","join","files","write","relativePath","content","fullPath","writeFileSafe","push","toUpperCase","useCases","file","uc","autoRegisterModule","indexPath","exists","fileExists","readFile","importLine","includes","lastImportIdx","lastIndexOf","lineEnd","indexOf","slice","replace","_match","open","existing","close","trimmed","trim","needsComma","endsWith","trimEnd","writeFile","join","generateAdapter","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateMiddleware","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","files","filePath","join","writeFileSafe","toPascalCase","push","join","generateGuard","options","name","outDir","kebab","toKebabCase","camel","toCamelCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateService","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateController","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","files","filePath","join","writeFileSafe","push","join","generateDto","options","name","outDir","kebab","toKebabCase","pascal","toPascalCase","camel","toCamelCase","files","filePath","join","writeFileSafe","push","printGenerated","files","cwd","process","console","log","length","f","replace","registerGenerateCommand","program","gen","command","alias","description","option","action","name","opts","generateModule","modulesDir","resolve","noEntity","entity","noTests","tests","repo","minimal","generateAdapter","outDir","out","generateMiddleware","generateGuard","generateService","generateController","generateDto","execSync","runShellCommand","command","cwd","execSync","stdio","registerRunCommands","program","command","description","option","action","opts","envVars","port","push","cmd","entry","fullCmd","length","join","console","log","runShellCommand","platform","release","arch","registerInfoCommand","program","command","description","action","console","log","platform","release","arch","process","version","registerCustomCommands","program","config","commands","length","cmd","registerSingleCommand","def","command","name","description","aliases","alias","allowUnknownOption","argument","action","args","extraArgs","join","steps","Array","isArray","step","finalCmd","console","log","runShellCommand","err","error","process","exitCode","readFile","access","join","CONFIG_FILES","loadKickConfig","cwd","filename","filepath","join","access","endsWith","content","readFile","JSON","parse","pathToFileURL","mod","href","default","err","console","warn","main","program","Command","name","description","version","config","loadKickConfig","process","cwd","registerInitCommand","registerGenerateCommand","registerRunCommands","registerInfoCommand","registerCustomCommands","showHelpAfterError","parseAsync","argv","catch","err","console","error","Error","message","exitCode"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
interface GenerateModuleOptions {
|
|
2
|
+
name: string;
|
|
3
|
+
modulesDir: string;
|
|
4
|
+
noEntity?: boolean;
|
|
5
|
+
noTests?: boolean;
|
|
6
|
+
repo?: 'drizzle' | 'inmemory';
|
|
7
|
+
minimal?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Generate a full DDD module with all layers:
|
|
11
|
+
* presentation/ — controller
|
|
12
|
+
* application/ — use-cases, DTOs
|
|
13
|
+
* domain/ — entity, value objects, repository interface, domain service
|
|
14
|
+
* infrastructure/ — repository implementation
|
|
15
|
+
*/
|
|
16
|
+
declare function generateModule(options: GenerateModuleOptions): Promise<string[]>;
|
|
17
|
+
|
|
18
|
+
interface GenerateAdapterOptions {
|
|
19
|
+
name: string;
|
|
20
|
+
outDir: string;
|
|
21
|
+
}
|
|
22
|
+
declare function generateAdapter(options: GenerateAdapterOptions): Promise<string[]>;
|
|
23
|
+
|
|
24
|
+
interface GenerateMiddlewareOptions {
|
|
25
|
+
name: string;
|
|
26
|
+
outDir: string;
|
|
27
|
+
}
|
|
28
|
+
declare function generateMiddleware(options: GenerateMiddlewareOptions): Promise<string[]>;
|
|
29
|
+
|
|
30
|
+
interface GenerateGuardOptions {
|
|
31
|
+
name: string;
|
|
32
|
+
outDir: string;
|
|
33
|
+
}
|
|
34
|
+
declare function generateGuard(options: GenerateGuardOptions): Promise<string[]>;
|
|
35
|
+
|
|
36
|
+
interface GenerateServiceOptions {
|
|
37
|
+
name: string;
|
|
38
|
+
outDir: string;
|
|
39
|
+
}
|
|
40
|
+
declare function generateService(options: GenerateServiceOptions): Promise<string[]>;
|
|
41
|
+
|
|
42
|
+
interface GenerateControllerOptions {
|
|
43
|
+
name: string;
|
|
44
|
+
outDir: string;
|
|
45
|
+
}
|
|
46
|
+
declare function generateController(options: GenerateControllerOptions): Promise<string[]>;
|
|
47
|
+
|
|
48
|
+
interface GenerateDtoOptions {
|
|
49
|
+
name: string;
|
|
50
|
+
outDir: string;
|
|
51
|
+
}
|
|
52
|
+
declare function generateDto(options: GenerateDtoOptions): Promise<string[]>;
|
|
53
|
+
|
|
54
|
+
interface InitProjectOptions {
|
|
55
|
+
name: string;
|
|
56
|
+
directory: string;
|
|
57
|
+
packageManager?: 'pnpm' | 'npm' | 'yarn';
|
|
58
|
+
}
|
|
59
|
+
/** Scaffold a new KickJS project */
|
|
60
|
+
declare function initProject(options: InitProjectOptions): Promise<void>;
|
|
61
|
+
|
|
62
|
+
/** A custom command that developers can register via kick.config.ts */
|
|
63
|
+
interface KickCommandDefinition {
|
|
64
|
+
/** The command name (e.g. 'db:migrate', 'seed', 'proto:gen') */
|
|
65
|
+
name: string;
|
|
66
|
+
/** Description shown in --help */
|
|
67
|
+
description: string;
|
|
68
|
+
/**
|
|
69
|
+
* Shell command(s) to run. Can be a single string or an array of
|
|
70
|
+
* sequential steps. Use {args} as a placeholder for CLI arguments.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* 'npx drizzle-kit migrate'
|
|
74
|
+
* ['npx drizzle-kit generate', 'npx drizzle-kit migrate']
|
|
75
|
+
*/
|
|
76
|
+
steps: string | string[];
|
|
77
|
+
/** Optional aliases (e.g. ['migrate'] for 'db:migrate') */
|
|
78
|
+
aliases?: string[];
|
|
79
|
+
}
|
|
80
|
+
/** Configuration for the kick.config.ts file */
|
|
81
|
+
interface KickConfig {
|
|
82
|
+
/** Where modules live (default: 'src/modules') */
|
|
83
|
+
modulesDir?: string;
|
|
84
|
+
/** Default repository implementation for generators */
|
|
85
|
+
defaultRepo?: 'drizzle' | 'inmemory' | 'prisma';
|
|
86
|
+
/** Drizzle schema output directory */
|
|
87
|
+
schemaDir?: string;
|
|
88
|
+
/** Custom commands that extend the CLI */
|
|
89
|
+
commands?: KickCommandDefinition[];
|
|
90
|
+
/** Code style overrides (auto-detected from prettier when possible) */
|
|
91
|
+
style?: {
|
|
92
|
+
semicolons?: boolean;
|
|
93
|
+
quotes?: 'single' | 'double';
|
|
94
|
+
trailingComma?: 'all' | 'es5' | 'none';
|
|
95
|
+
indent?: number;
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
/** Helper to define a type-safe kick.config.ts */
|
|
99
|
+
declare function defineConfig(config: KickConfig): KickConfig;
|
|
100
|
+
/** Load kick.config.* from the project root */
|
|
101
|
+
declare function loadKickConfig(cwd: string): Promise<KickConfig | null>;
|
|
102
|
+
|
|
103
|
+
/** Convert a name to PascalCase */
|
|
104
|
+
declare function toPascalCase(name: string): string;
|
|
105
|
+
/** Convert a name to camelCase */
|
|
106
|
+
declare function toCamelCase(name: string): string;
|
|
107
|
+
/** Convert a name to kebab-case */
|
|
108
|
+
declare function toKebabCase(name: string): string;
|
|
109
|
+
/**
|
|
110
|
+
* Pluralize a kebab-case name for directory/file names.
|
|
111
|
+
* If already plural (ends in 's'), returns as-is.
|
|
112
|
+
*/
|
|
113
|
+
declare function pluralize(name: string): string;
|
|
114
|
+
|
|
115
|
+
export { type KickCommandDefinition, type KickConfig, defineConfig, generateAdapter, generateController, generateDto, generateGuard, generateMiddleware, generateModule, generateService, initProject, loadKickConfig, pluralize, toCamelCase, toKebabCase, toPascalCase };
|