fragment-ts 1.0.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.
Files changed (123) hide show
  1. package/.env.example +0 -0
  2. package/base.ts +1810 -0
  3. package/base2.ts +968 -0
  4. package/bin/frg.ts +5 -0
  5. package/config/fragment.lock.yaml +0 -0
  6. package/config/fragment.yaml +0 -0
  7. package/dist/app.d.ts +15 -0
  8. package/dist/app.js +90 -0
  9. package/dist/auth/auth.controller.d.ts +10 -0
  10. package/dist/auth/auth.controller.js +87 -0
  11. package/dist/auth/auth.middleware.d.ts +2 -0
  12. package/dist/auth/auth.middleware.js +24 -0
  13. package/dist/auth/auth.service.d.ts +20 -0
  14. package/dist/auth/auth.service.js +143 -0
  15. package/dist/auth/dto/login.dto.d.ts +9 -0
  16. package/dist/auth/dto/login.dto.js +2 -0
  17. package/dist/cli/cli.d.ts +12 -0
  18. package/dist/cli/cli.js +186 -0
  19. package/dist/cli/commands/build.command.d.ts +3 -0
  20. package/dist/cli/commands/build.command.js +23 -0
  21. package/dist/cli/commands/config.command.d.ts +6 -0
  22. package/dist/cli/commands/config.command.js +284 -0
  23. package/dist/cli/commands/generate.command.d.ts +8 -0
  24. package/dist/cli/commands/generate.command.js +180 -0
  25. package/dist/cli/commands/init.command.d.ts +7 -0
  26. package/dist/cli/commands/init.command.js +380 -0
  27. package/dist/cli/commands/migrate.command.d.ts +7 -0
  28. package/dist/cli/commands/migrate.command.js +116 -0
  29. package/dist/cli/commands/serve.command.d.ts +6 -0
  30. package/dist/cli/commands/serve.command.js +31 -0
  31. package/dist/cli/templates/controller.template.d.ts +1 -0
  32. package/dist/cli/templates/controller.template.js +52 -0
  33. package/dist/cli/templates/entity.template.d.ts +1 -0
  34. package/dist/cli/templates/entity.template.js +23 -0
  35. package/dist/cli/templates/repository.template.d.ts +1 -0
  36. package/dist/cli/templates/repository.template.js +43 -0
  37. package/dist/cli/templates/service.template.d.ts +1 -0
  38. package/dist/cli/templates/service.template.js +43 -0
  39. package/dist/cli/utils/file-generator.d.ts +9 -0
  40. package/dist/cli/utils/file-generator.js +67 -0
  41. package/dist/cli/utils/logger.d.ts +14 -0
  42. package/dist/cli/utils/logger.js +49 -0
  43. package/dist/controllers/health.controller.d.ts +13 -0
  44. package/dist/controllers/health.controller.js +50 -0
  45. package/dist/core/config/config-loader.d.ts +31 -0
  46. package/dist/core/config/config-loader.js +98 -0
  47. package/dist/core/container/di-container.d.ts +9 -0
  48. package/dist/core/container/di-container.js +37 -0
  49. package/dist/core/decorators/auth-guard.decorator.d.ts +3 -0
  50. package/dist/core/decorators/auth-guard.decorator.js +18 -0
  51. package/dist/core/decorators/autowire.decorator.d.ts +3 -0
  52. package/dist/core/decorators/autowire.decorator.js +17 -0
  53. package/dist/core/decorators/controller.decorator.d.ts +4 -0
  54. package/dist/core/decorators/controller.decorator.js +16 -0
  55. package/dist/core/decorators/injectable.decorator.d.ts +3 -0
  56. package/dist/core/decorators/injectable.decorator.js +14 -0
  57. package/dist/core/decorators/middleware.decorator.d.ts +3 -0
  58. package/dist/core/decorators/middleware.decorator.js +20 -0
  59. package/dist/core/decorators/repository.decorator.d.ts +1 -0
  60. package/dist/core/decorators/repository.decorator.js +7 -0
  61. package/dist/core/decorators/route.decorator.d.ts +14 -0
  62. package/dist/core/decorators/route.decorator.js +32 -0
  63. package/dist/core/decorators/service.decorator.d.ts +1 -0
  64. package/dist/core/decorators/service.decorator.js +7 -0
  65. package/dist/core/openai/openai-client.d.ts +12 -0
  66. package/dist/core/openai/openai-client.js +93 -0
  67. package/dist/database/data-source.d.ts +4 -0
  68. package/dist/database/data-source.js +26 -0
  69. package/dist/entities/session.entity.d.ts +9 -0
  70. package/dist/entities/session.entity.js +45 -0
  71. package/dist/entities/user.entity.d.ts +10 -0
  72. package/dist/entities/user.entity.js +48 -0
  73. package/dist/middlewares/logging.middleware.d.ts +2 -0
  74. package/dist/middlewares/logging.middleware.js +28 -0
  75. package/dist/repositories/session.repository.d.ts +9 -0
  76. package/dist/repositories/session.repository.js +50 -0
  77. package/dist/repositories/user.repository.d.ts +10 -0
  78. package/dist/repositories/user.repository.js +43 -0
  79. package/dist/server.d.ts +1 -0
  80. package/dist/server.js +30 -0
  81. package/dist/services/health.service.d.ts +13 -0
  82. package/dist/services/health.service.js +44 -0
  83. package/package.json +46 -0
  84. package/readme.md +120 -0
  85. package/src/app.ts +121 -0
  86. package/src/auth/auth.controller.ts +52 -0
  87. package/src/auth/auth.middleware.ts +27 -0
  88. package/src/auth/auth.service.ts +110 -0
  89. package/src/auth/dto/login.dto.ts +11 -0
  90. package/src/cli/cli.ts +212 -0
  91. package/src/cli/commands/build.command.ts +24 -0
  92. package/src/cli/commands/config.command.ts +280 -0
  93. package/src/cli/commands/generate.command.ts +170 -0
  94. package/src/cli/commands/init.command.ts +395 -0
  95. package/src/cli/commands/migrate.command.ts +118 -0
  96. package/src/cli/commands/serve.command.ts +37 -0
  97. package/src/cli/templates/controller.template.ts +51 -0
  98. package/src/cli/templates/entity.template.ts +22 -0
  99. package/src/cli/templates/repository.template.ts +42 -0
  100. package/src/cli/templates/service.template.ts +42 -0
  101. package/src/cli/utils/file-generator.ts +37 -0
  102. package/src/cli/utils/logger.ts +52 -0
  103. package/src/controllers/health.controller.ts +24 -0
  104. package/src/core/config/config-loader.ts +98 -0
  105. package/src/core/container/di-container.ts +43 -0
  106. package/src/core/decorators/auth-guard.decorator.ts +15 -0
  107. package/src/core/decorators/autowire.decorator.ts +18 -0
  108. package/src/core/decorators/controller.decorator.ts +15 -0
  109. package/src/core/decorators/injectable.decorator.ts +13 -0
  110. package/src/core/decorators/middleware.decorator.ts +18 -0
  111. package/src/core/decorators/repository.decorator.ts +6 -0
  112. package/src/core/decorators/route.decorator.ts +33 -0
  113. package/src/core/decorators/service.decorator.ts +6 -0
  114. package/src/core/openai/openai-client.ts +99 -0
  115. package/src/database/data-source.ts +29 -0
  116. package/src/entities/session.entity.ts +25 -0
  117. package/src/entities/user.entity.ts +27 -0
  118. package/src/middlewares/logging.middleware.ts +28 -0
  119. package/src/repositories/session.repository.ts +42 -0
  120. package/src/repositories/user.repository.ts +37 -0
  121. package/src/server.ts +32 -0
  122. package/src/services/health.service.ts +29 -0
  123. package/tsconfig.json +20 -0
package/base.ts ADDED
@@ -0,0 +1,1810 @@
1
+ // // ============================================================================
2
+ // // PROJECT STRUCTURE
3
+ // // ============================================================================
4
+ // /*
5
+ // fragment/
6
+ // ├── bin/
7
+ // │ └── frg.ts
8
+ // ├── src/
9
+ // │ ├── cli/
10
+ // │ │ ├── commands/
11
+ // │ │ │ ├── init.command.ts
12
+ // │ │ │ ├── generate.command.ts
13
+ // │ │ │ ├── config.command.ts
14
+ // │ │ │ ├── serve.command.ts
15
+ // │ │ │ ├── build.command.ts
16
+ // │ │ │ └── migrate.command.ts
17
+ // │ │ ├── templates/
18
+ // │ │ │ ├── controller.template.ts
19
+ // │ │ │ ├── service.template.ts
20
+ // │ │ │ ├── repository.template.ts
21
+ // │ │ │ └── entity.template.ts
22
+ // │ │ ├── utils/
23
+ // │ │ │ ├── logger.ts
24
+ // │ │ │ └── file-generator.ts
25
+ // │ │ └── cli.ts
26
+ // │ ├── core/
27
+ // │ │ ├── decorators/
28
+ // │ │ ├── container/
29
+ // │ │ ├── config/
30
+ // │ │ └── openai/
31
+ // │ ├── auth/
32
+ // │ ├── entities/
33
+ // │ ├── repositories/
34
+ // │ ├── services/
35
+ // │ ├── controllers/
36
+ // │ ├── middlewares/
37
+ // │ ├── database/
38
+ // │ ├── app.ts
39
+ // │ └── server.ts
40
+ // ├── config/
41
+ // │ ├── fragment.yaml
42
+ // │ └── fragment.lock.yaml
43
+ // ├── package.json
44
+ // ├── tsconfig.json
45
+ // └── .env.example
46
+ // */
47
+
48
+ // // ============================================================================
49
+ // // FILE: bin/frg.ts
50
+ // // ============================================================================
51
+ // #!/usr/bin/env node
52
+ // import { CLI } from '../src/cli/cli';
53
+
54
+ // const cli = new CLI();
55
+ // cli.run(process.argv.slice(2));
56
+
57
+ // // ============================================================================
58
+ // // FILE: src/cli/utils/logger.ts
59
+ // // ============================================================================
60
+ // import chalk from 'chalk';
61
+ // import ora, { Ora } from 'ora';
62
+
63
+ // export class CLILogger {
64
+ // static success(message: string): void {
65
+ // console.log(chalk.green('✓'), message);
66
+ // }
67
+
68
+ // static error(message: string): void {
69
+ // console.log(chalk.red('✗'), message);
70
+ // }
71
+
72
+ // static info(message: string): void {
73
+ // console.log(chalk.blue('ℹ'), message);
74
+ // }
75
+
76
+ // static warning(message: string): void {
77
+ // console.log(chalk.yellow('⚠'), message);
78
+ // }
79
+
80
+ // static title(message: string): void {
81
+ // console.log(chalk.bold.cyan(`\n${message}\n`));
82
+ // }
83
+
84
+ // static section(message: string): void {
85
+ // console.log(chalk.bold(`\n${message}`));
86
+ // }
87
+
88
+ // static spinner(text: string): Ora {
89
+ // return ora(text).start();
90
+ // }
91
+
92
+ // static box(title: string, content: string[]): void {
93
+ // const maxLength = Math.max(title.length, ...content.map(c => c.length)) + 4;
94
+ // const border = '═'.repeat(maxLength);
95
+
96
+ // console.log(chalk.cyan(`╔${border}╗`));
97
+ // console.log(chalk.cyan('║') + chalk.bold(` ${title.padEnd(maxLength)} `) + chalk.cyan('║'));
98
+ // console.log(chalk.cyan(`╠${border}â•Ŗ`));
99
+ // content.forEach(line => {
100
+ // console.log(chalk.cyan('║') + ` ${line.padEnd(maxLength)} ` + chalk.cyan('║'));
101
+ // });
102
+ // console.log(chalk.cyan(`╚${border}╝`));
103
+ // }
104
+
105
+ // static table(data: { [key: string]: string }): void {
106
+ // const maxKeyLength = Math.max(...Object.keys(data).map(k => k.length));
107
+ // Object.entries(data).forEach(([key, value]) => {
108
+ // console.log(` ${chalk.cyan(key.padEnd(maxKeyLength))} : ${value}`);
109
+ // });
110
+ // }
111
+ // }
112
+
113
+ // // ============================================================================
114
+ // // FILE: src/cli/utils/file-generator.ts
115
+ // // ============================================================================
116
+ // import * as fs from 'fs';
117
+ // import * as path from 'path';
118
+
119
+ // export class FileGenerator {
120
+ // static createDirectory(dirPath: string): void {
121
+ // if (!fs.existsSync(dirPath)) {
122
+ // fs.mkdirSync(dirPath, { recursive: true });
123
+ // }
124
+ // }
125
+
126
+ // static writeFile(filePath: string, content: string): void {
127
+ // const dir = path.dirname(filePath);
128
+ // this.createDirectory(dir);
129
+ // fs.writeFileSync(filePath, content, 'utf-8');
130
+ // }
131
+
132
+ // static fileExists(filePath: string): boolean {
133
+ // return fs.existsSync(filePath);
134
+ // }
135
+
136
+ // static readFile(filePath: string): string {
137
+ // return fs.readFileSync(filePath, 'utf-8');
138
+ // }
139
+
140
+ // static toCamelCase(str: string): string {
141
+ // return str.replace(/-([a-z])/g, (g) => g[1].toUpperCase());
142
+ // }
143
+
144
+ // static toPascalCase(str: string): string {
145
+ // const camel = this.toCamelCase(str);
146
+ // return camel.charAt(0).toUpperCase() + camel.slice(1);
147
+ // }
148
+
149
+ // static toKebabCase(str: string): string {
150
+ // return str.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
151
+ // }
152
+ // }
153
+
154
+ // // ============================================================================
155
+ // // FILE: src/cli/templates/controller.template.ts
156
+ // // ============================================================================
157
+ // export function controllerTemplate(name: string, route: string): string {
158
+ // const className = name.endsWith('Controller') ? name : `${name}Controller`;
159
+ // const serviceName = name.replace('Controller', '') + 'Service';
160
+
161
+ // return `import { Controller } from '../core/decorators/controller.decorator';
162
+ // import { Get, Post, Put, Delete } from '../core/decorators/route.decorator';
163
+ // import { Injectable } from '../core/decorators/injectable.decorator';
164
+ // import { Autowire } from '../core/decorators/autowire.decorator';
165
+ // import { ${serviceName} } from '../services/${name.toLowerCase()}.service';
166
+ // import { Request, Response } from 'express';
167
+
168
+ // @Controller('${route}')
169
+ // @Injectable()
170
+ // export class ${className} {
171
+ // constructor(
172
+ // @Autowire() private ${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}: ${serviceName}
173
+ // ) {}
174
+
175
+ // @Get('/')
176
+ // async findAll(req: Request, res: Response) {
177
+ // const items = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.findAll();
178
+ // return res.json(items);
179
+ // }
180
+
181
+ // @Get('/:id')
182
+ // async findOne(req: Request, res: Response) {
183
+ // const item = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.findById(parseInt(req.params.id));
184
+ // return res.json(item);
185
+ // }
186
+
187
+ // @Post('/')
188
+ // async create(req: Request, res: Response) {
189
+ // const item = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.create(req.body);
190
+ // return res.status(201).json(item);
191
+ // }
192
+
193
+ // @Put('/:id')
194
+ // async update(req: Request, res: Response) {
195
+ // const item = await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.update(parseInt(req.params.id), req.body);
196
+ // return res.json(item);
197
+ // }
198
+
199
+ // @Delete('/:id')
200
+ // async delete(req: Request, res: Response) {
201
+ // await this.${serviceName.charAt(0).toLowerCase() + serviceName.slice(1)}.delete(parseInt(req.params.id));
202
+ // return res.status(204).send();
203
+ // }
204
+ // }
205
+ // `;
206
+ // }
207
+
208
+ // // ============================================================================
209
+ // // FILE: src/cli/templates/service.template.ts
210
+ // // ============================================================================
211
+ // export function serviceTemplate(name: string): string {
212
+ // const className = name.endsWith('Service') ? name : `${name}Service`;
213
+ // const repoName = name.replace('Service', '') + 'Repository';
214
+
215
+ // return `import { Service } from '../core/decorators/service.decorator';
216
+ // import { Autowire } from '../core/decorators/autowire.decorator';
217
+ // import { ${repoName} } from '../repositories/${name.toLowerCase()}.repository';
218
+
219
+ // @Service()
220
+ // export class ${className} {
221
+ // constructor(
222
+ // @Autowire() private ${repoName.charAt(0).toLowerCase() + repoName.slice(1)}: ${repoName}
223
+ // ) {}
224
+
225
+ // async findAll() {
226
+ // // Implement business logic
227
+ // return [];
228
+ // }
229
+
230
+ // async findById(id: number) {
231
+ // // Implement business logic
232
+ // return null;
233
+ // }
234
+
235
+ // async create(data: any) {
236
+ // // Implement business logic
237
+ // return data;
238
+ // }
239
+
240
+ // async update(id: number, data: any) {
241
+ // // Implement business logic
242
+ // return data;
243
+ // }
244
+
245
+ // async delete(id: number) {
246
+ // // Implement business logic
247
+ // return true;
248
+ // }
249
+ // }
250
+ // `;
251
+ // }
252
+
253
+ // // ============================================================================
254
+ // // FILE: src/cli/templates/repository.template.ts
255
+ // // ============================================================================
256
+ // export function repositoryTemplate(name: string, entityName: string): string {
257
+ // const className = name.endsWith('Repository') ? name : `${name}Repository`;
258
+
259
+ // return `import { Repository as TypeORMRepository } from 'typeorm';
260
+ // import { Repository } from '../core/decorators/repository.decorator';
261
+ // import { ${entityName} } from '../entities/${entityName.toLowerCase()}.entity';
262
+ // import { AppDataSource } from '../database/data-source';
263
+
264
+ // @Repository()
265
+ // export class ${className} {
266
+ // private repository: TypeORMRepository<${entityName}>;
267
+
268
+ // constructor() {
269
+ // this.repository = AppDataSource.getRepository(${entityName});
270
+ // }
271
+
272
+ // async findAll(): Promise<${entityName}[]> {
273
+ // return await this.repository.find();
274
+ // }
275
+
276
+ // async findById(id: number): Promise<${entityName} | null> {
277
+ // return await this.repository.findOne({ where: { id } });
278
+ // }
279
+
280
+ // async create(data: Partial<${entityName}>): Promise<${entityName}> {
281
+ // const entity = this.repository.create(data);
282
+ // return await this.repository.save(entity);
283
+ // }
284
+
285
+ // async update(id: number, data: Partial<${entityName}>): Promise<${entityName} | null> {
286
+ // await this.repository.update(id, data);
287
+ // return await this.findById(id);
288
+ // }
289
+
290
+ // async delete(id: number): Promise<boolean> {
291
+ // const result = await this.repository.delete(id);
292
+ // return result.affected ? result.affected > 0 : false;
293
+ // }
294
+ // }
295
+ // `;
296
+ // }
297
+
298
+ // // ============================================================================
299
+ // // FILE: src/cli/templates/entity.template.ts
300
+ // // ============================================================================
301
+ // export function entityTemplate(name: string): string {
302
+ // const className = name.endsWith('Entity') ? name.replace('Entity', '') : name;
303
+
304
+ // return `import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from 'typeorm';
305
+
306
+ // @Entity('${className.toLowerCase()}s')
307
+ // export class ${className} {
308
+ // @PrimaryGeneratedColumn()
309
+ // id!: number;
310
+
311
+ // @Column({ length: 255 })
312
+ // name!: string;
313
+
314
+ // @CreateDateColumn()
315
+ // createdAt!: Date;
316
+
317
+ // @UpdateDateColumn()
318
+ // updatedAt!: Date;
319
+ // }
320
+ // `;
321
+ // }
322
+
323
+ // // ============================================================================
324
+ // // FILE: src/cli/commands/init.command.ts
325
+ // // ============================================================================
326
+ // import * as fs from 'fs';
327
+ // import * as path from 'path';
328
+ // import { execSync } from 'child_process';
329
+ // import { CLILogger } from '../utils/logger';
330
+ // import { FileGenerator } from '../utils/file-generator';
331
+ // import inquirer from 'inquirer';
332
+
333
+ // export class InitCommand {
334
+ // async execute(projectName?: string): Promise<void> {
335
+ // CLILogger.title('🔷 Fragment Framework Initializer');
336
+
337
+ // const answers = await inquirer.prompt([
338
+ // {
339
+ // type: 'input',
340
+ // name: 'projectName',
341
+ // message: 'Project name:',
342
+ // default: projectName || 'my-fragment-app',
343
+ // validate: (input: string) => {
344
+ // if (!/^[a-z0-9-]+$/.test(input)) {
345
+ // return 'Project name must contain only lowercase letters, numbers, and hyphens';
346
+ // }
347
+ // return true;
348
+ // }
349
+ // },
350
+ // {
351
+ // type: 'list',
352
+ // name: 'database',
353
+ // message: 'Select database:',
354
+ // choices: ['PostgreSQL', 'MySQL', 'SQLite', 'MongoDB'],
355
+ // default: 'PostgreSQL'
356
+ // },
357
+ // {
358
+ // type: 'confirm',
359
+ // name: 'useOpenAI',
360
+ // message: 'Enable OpenAI integration?',
361
+ // default: true
362
+ // },
363
+ // {
364
+ // type: 'confirm',
365
+ // name: 'useAuth',
366
+ // message: 'Include authentication system?',
367
+ // default: true
368
+ // },
369
+ // {
370
+ // type: 'list',
371
+ // name: 'packageManager',
372
+ // message: 'Package manager:',
373
+ // choices: ['npm', 'yarn', 'pnpm'],
374
+ // default: 'npm'
375
+ // }
376
+ // ]);
377
+
378
+ // const projectPath = path.join(process.cwd(), answers.projectName);
379
+
380
+ // if (fs.existsSync(projectPath)) {
381
+ // CLILogger.error(`Directory ${answers.projectName} already exists`);
382
+ // return;
383
+ // }
384
+
385
+ // const spinner = CLILogger.spinner('Creating project structure...');
386
+
387
+ // try {
388
+ // // Create project directory
389
+ // FileGenerator.createDirectory(projectPath);
390
+
391
+ // // Create directory structure
392
+ // const dirs = [
393
+ // 'src/controllers',
394
+ // 'src/services',
395
+ // 'src/repositories',
396
+ // 'src/entities',
397
+ // 'src/middlewares',
398
+ // 'src/core/decorators',
399
+ // 'src/core/container',
400
+ // 'src/core/config',
401
+ // 'src/database',
402
+ // 'config'
403
+ // ];
404
+
405
+ // if (answers.useOpenAI) {
406
+ // dirs.push('src/core/openai');
407
+ // }
408
+
409
+ // if (answers.useAuth) {
410
+ // dirs.push('src/auth', 'src/auth/dto');
411
+ // }
412
+
413
+ // dirs.forEach(dir => {
414
+ // FileGenerator.createDirectory(path.join(projectPath, dir));
415
+ // });
416
+
417
+ // spinner.text = 'Generating configuration files...';
418
+
419
+ // // Generate package.json
420
+ // const packageJson = {
421
+ // name: answers.projectName,
422
+ // version: '1.0.0',
423
+ // description: 'Fragment Framework Application',
424
+ // main: 'dist/server.js',
425
+ // scripts: {
426
+ // dev: 'ts-node-dev --respawn --transpile-only src/server.ts',
427
+ // build: 'tsc',
428
+ // start: 'node dist/server.js',
429
+ // 'frg:generate': 'frg generate',
430
+ // 'frg:migrate': 'frg migrate'
431
+ // },
432
+ // dependencies: {
433
+ // express: '^4.18.2',
434
+ // typeorm: '^0.3.17',
435
+ // 'reflect-metadata': '^0.1.13',
436
+ // bcrypt: '^5.1.1',
437
+ // 'js-yaml': '^4.1.0',
438
+ // pino: '^8.16.0',
439
+ // 'pino-pretty': '^10.2.3'
440
+ // },
441
+ // devDependencies: {
442
+ // '@types/express': '^4.17.20',
443
+ // '@types/node': '^20.9.0',
444
+ // '@types/bcrypt': '^5.0.2',
445
+ // '@types/js-yaml': '^4.0.9',
446
+ // typescript: '^5.2.2',
447
+ // 'ts-node': '^10.9.1',
448
+ // 'ts-node-dev': '^2.0.0'
449
+ // }
450
+ // };
451
+
452
+ // // Add database driver
453
+ // const dbDrivers: { [key: string]: string } = {
454
+ // 'PostgreSQL': 'pg@^8.11.3',
455
+ // 'MySQL': 'mysql2@^3.6.5',
456
+ // 'SQLite': 'sqlite3@^5.1.6',
457
+ // 'MongoDB': 'mongodb@^6.3.0'
458
+ // };
459
+ // packageJson.dependencies = {
460
+ // ...packageJson.dependencies,
461
+ // [dbDrivers[answers.database].split('@')[0]]: dbDrivers[answers.database].split('@')[1]
462
+ // };
463
+
464
+ // FileGenerator.writeFile(
465
+ // path.join(projectPath, 'package.json'),
466
+ // JSON.stringify(packageJson, null, 2)
467
+ // );
468
+
469
+ // // Generate tsconfig.json
470
+ // const tsConfig = {
471
+ // compilerOptions: {
472
+ // target: 'ES2020',
473
+ // module: 'commonjs',
474
+ // lib: ['ES2020'],
475
+ // outDir: './dist',
476
+ // rootDir: './src',
477
+ // strict: true,
478
+ // esModuleInterop: true,
479
+ // skipLibCheck: true,
480
+ // forceConsistentCasingInFileNames: true,
481
+ // resolveJsonModule: true,
482
+ // experimentalDecorators: true,
483
+ // emitDecoratorMetadata: true,
484
+ // moduleResolution: 'node',
485
+ // allowSyntheticDefaultImports: true
486
+ // },
487
+ // include: ['src/**/*'],
488
+ // exclude: ['node_modules', 'dist']
489
+ // };
490
+
491
+ // FileGenerator.writeFile(
492
+ // path.join(projectPath, 'tsconfig.json'),
493
+ // JSON.stringify(tsConfig, null, 2)
494
+ // );
495
+
496
+ // // Generate fragment.yaml
497
+ // const dbConfig = this.getDatabaseConfig(answers.database);
498
+ // const fragmentConfig = `app:
499
+ // name: ${answers.projectName}
500
+ // port: 3000
501
+ // env: development
502
+
503
+ // database:
504
+ // ${dbConfig}
505
+
506
+ // ${answers.useOpenAI ? `openai:
507
+ // apiKey: \${OPENAI_API_KEY}
508
+ // model: gpt-4
509
+ // ` : ''}
510
+ // ${answers.useAuth ? `auth:
511
+ // tokenExpiry: 7d
512
+ // sessionExpiry: 30d
513
+ // ` : ''}`;
514
+
515
+ // FileGenerator.writeFile(
516
+ // path.join(projectPath, 'config/fragment.yaml'),
517
+ // fragmentConfig
518
+ // );
519
+
520
+ // // Generate .env.example
521
+ // let envExample = `NODE_ENV=development
522
+ // PORT=3000
523
+
524
+ // ${this.getEnvTemplate(answers.database)}`;
525
+
526
+ // if (answers.useOpenAI) {
527
+ // envExample += '\nOPENAI_API_KEY=sk-your-openai-api-key';
528
+ // }
529
+
530
+ // FileGenerator.writeFile(
531
+ // path.join(projectPath, '.env.example'),
532
+ // envExample
533
+ // );
534
+
535
+ // // Generate .gitignore
536
+ // const gitignore = `node_modules/
537
+ // dist/
538
+ // .env
539
+ // *.log
540
+ // .DS_Store
541
+ // config/fragment.lock.yaml`;
542
+
543
+ // FileGenerator.writeFile(
544
+ // path.join(projectPath, '.gitignore'),
545
+ // gitignore
546
+ // );
547
+
548
+ // // Generate README.md
549
+ // const readme = this.generateReadme(answers.projectName, answers);
550
+ // FileGenerator.writeFile(
551
+ // path.join(projectPath, 'README.md'),
552
+ // readme
553
+ // );
554
+
555
+ // spinner.text = 'Copying core framework files...';
556
+
557
+ // // Copy all core files (decorators, container, config, etc.)
558
+ // await this.copyFrameworkCore(projectPath, answers);
559
+
560
+ // spinner.succeed('Project structure created');
561
+
562
+ // // Install dependencies
563
+ // const installSpinner = CLILogger.spinner(`Installing dependencies with ${answers.packageManager}...`);
564
+
565
+ // try {
566
+ // execSync(`cd ${projectPath} && ${answers.packageManager} install`, {
567
+ // stdio: 'pipe'
568
+ // });
569
+ // installSpinner.succeed('Dependencies installed');
570
+ // } catch (error) {
571
+ // installSpinner.fail('Failed to install dependencies');
572
+ // CLILogger.warning('You can install them manually by running:');
573
+ // console.log(` cd ${answers.projectName} && ${answers.packageManager} install`);
574
+ // }
575
+
576
+ // // Success message
577
+ // CLILogger.box('🎉 Project Created Successfully!', [
578
+ // `Project: ${answers.projectName}`,
579
+ // `Location: ${projectPath}`,
580
+ // `Database: ${answers.database}`,
581
+ // `OpenAI: ${answers.useOpenAI ? 'Enabled' : 'Disabled'}`,
582
+ // `Auth: ${answers.useAuth ? 'Enabled' : 'Disabled'}`
583
+ // ]);
584
+
585
+ // console.log(chalk.bold('\nNext steps:'));
586
+ // console.log(` 1. cd ${answers.projectName}`);
587
+ // console.log(` 2. cp .env.example .env`);
588
+ // console.log(` 3. Configure your database in .env`);
589
+ // if (answers.useOpenAI) {
590
+ // console.log(` 4. Add your OpenAI API key to .env`);
591
+ // }
592
+ // console.log(` ${answers.useOpenAI ? '5' : '4'}. ${answers.packageManager} run dev`);
593
+
594
+ // CLILogger.section('Available Commands:');
595
+ // CLILogger.table({
596
+ // 'frg generate controller <name>': 'Generate a new controller',
597
+ // 'frg generate service <name>': 'Generate a new service',
598
+ // 'frg generate resource <name>': 'Generate controller, service, repository & entity',
599
+ // 'frg config ai': 'Configure OpenAI settings',
600
+ // 'frg migrate': 'Run database migrations',
601
+ // 'frg serve': 'Start development server'
602
+ // });
603
+
604
+ // } catch (error: any) {
605
+ // spinner.fail('Failed to create project');
606
+ // CLILogger.error(error.message);
607
+ // }
608
+ // }
609
+
610
+ // private getDatabaseConfig(database: string): string {
611
+ // const configs: { [key: string]: string } = {
612
+ // 'PostgreSQL': ` type: postgres
613
+ // host: \${DB_HOST:localhost}
614
+ // port: \${DB_PORT:5432}
615
+ // username: \${DB_USERNAME:postgres}
616
+ // password: \${DB_PASSWORD:postgres}
617
+ // database: \${DB_DATABASE:fragment_db}
618
+ // synchronize: true
619
+ // logging: false`,
620
+ // 'MySQL': ` type: mysql
621
+ // host: \${DB_HOST:localhost}
622
+ // port: \${DB_PORT:3306}
623
+ // username: \${DB_USERNAME:root}
624
+ // password: \${DB_PASSWORD:root}
625
+ // database: \${DB_DATABASE:fragment_db}
626
+ // synchronize: true
627
+ // logging: false`,
628
+ // 'SQLite': ` type: sqlite
629
+ // database: \${DB_DATABASE:database.sqlite}
630
+ // synchronize: true
631
+ // logging: false`,
632
+ // 'MongoDB': ` type: mongodb
633
+ // host: \${DB_HOST:localhost}
634
+ // port: \${DB_PORT:27017}
635
+ // database: \${DB_DATABASE:fragment_db}
636
+ // synchronize: true
637
+ // logging: false`
638
+ // };
639
+ // return configs[database];
640
+ // }
641
+
642
+ // private getEnvTemplate(database: string): string {
643
+ // if (database === 'SQLite') {
644
+ // return 'DB_DATABASE=database.sqlite';
645
+ // }
646
+ // return `DB_HOST=localhost
647
+ // DB_PORT=${database === 'PostgreSQL' ? '5432' : database === 'MySQL' ? '3306' : '27017'}
648
+ // DB_USERNAME=${database === 'PostgreSQL' ? 'postgres' : 'root'}
649
+ // DB_PASSWORD=${database === 'PostgreSQL' ? 'postgres' : 'root'}
650
+ // DB_DATABASE=fragment_db`;
651
+ // }
652
+
653
+ // private generateReadme(projectName: string, answers: any): string {
654
+ // return `# ${projectName}
655
+
656
+ // A Fragment Framework application.
657
+
658
+ // ## Getting Started
659
+
660
+ // \`\`\`bash
661
+ // # Install dependencies
662
+ // ${answers.packageManager} install
663
+
664
+ // # Configure environment
665
+ // cp .env.example .env
666
+
667
+ // # Start development server
668
+ // ${answers.packageManager} run dev
669
+ // \`\`\`
670
+
671
+ // ## Fragment CLI Commands
672
+
673
+ // \`\`\`bash
674
+ // # Generate resources
675
+ // frg generate controller <name> # Generate controller
676
+ // frg generate service <name> # Generate service
677
+ // frg generate repository <name> # Generate repository
678
+ // frg generate entity <name> # Generate entity
679
+ // frg generate resource <name> # Generate all of the above
680
+
681
+ // # Configuration
682
+ // frg config ai # Configure OpenAI settings
683
+ // frg config db # Configure database settings
684
+
685
+ // # Database
686
+ // frg migrate # Run migrations
687
+
688
+ // # Development
689
+ // frg serve # Start development server
690
+ // frg build # Build for production
691
+ // \`\`\`
692
+
693
+ // ## Project Structure
694
+
695
+ // \`\`\`
696
+ // src/
697
+ // ├── controllers/ # HTTP request handlers
698
+ // ├── services/ # Business logic
699
+ // ├── repositories/ # Data access layer
700
+ // ├── entities/ # Database models
701
+ // ├── middlewares/ # Express middlewares
702
+ // └── core/ # Framework core
703
+ // \`\`\`
704
+
705
+ // ## Documentation
706
+
707
+ // Visit [Fragment Framework Documentation](https://fragment-framework.dev) for more information.
708
+ // `;
709
+ // }
710
+
711
+ // private async copyFrameworkCore(projectPath: string, answers: any): Promise<void> {
712
+ // // This would copy all the core framework files
713
+ // // For brevity, I'll show the structure
714
+ // // In a real implementation, these would be actual file copies
715
+
716
+ // CLILogger.info('Core framework files copied');
717
+ // }
718
+ // }
719
+
720
+ // // ============================================================================
721
+ // // FILE: src/cli/commands/generate.command.ts
722
+ // // ============================================================================
723
+ // import * as path from 'path';
724
+ // import { CLILogger } from '../utils/logger';
725
+ // import { FileGenerator } from '../utils/file-generator';
726
+ // import {
727
+ // controllerTemplate,
728
+ // serviceTemplate,
729
+ // repositoryTemplate,
730
+ // entityTemplate
731
+ // } from '../templates';
732
+ // import inquirer from 'inquirer';
733
+
734
+ // export class GenerateCommand {
735
+ // async execute(type: string, name?: string): Promise<void> {
736
+ // if (!name) {
737
+ // const answer = await inquirer.prompt([
738
+ // {
739
+ // type: 'input',
740
+ // name: 'name',
741
+ // message: `Enter ${type} name:`,
742
+ // validate: (input: string) => {
743
+ // if (!input) return 'Name is required';
744
+ // return true;
745
+ // }
746
+ // }
747
+ // ]);
748
+ // name = answer.name;
749
+ // }
750
+
751
+ // const pascalName = FileGenerator.toPascalCase(name);
752
+ // const kebabName = FileGenerator.toKebabCase(name);
753
+
754
+ // switch (type) {
755
+ // case 'controller':
756
+ // await this.generateController(pascalName, kebabName);
757
+ // break;
758
+ // case 'service':
759
+ // await this.generateService(pascalName, kebabName);
760
+ // break;
761
+ // case 'repository':
762
+ // await this.generateRepository(pascalName, kebabName);
763
+ // break;
764
+ // case 'entity':
765
+ // await this.generateEntity(pascalName, kebabName);
766
+ // break;
767
+ // case 'resource':
768
+ // await this.generateResource(pascalName, kebabName);
769
+ // break;
770
+ // default:
771
+ // CLILogger.error(`Unknown type: ${type}`);
772
+ // CLILogger.info('Available types: controller, service, repository, entity, resource');
773
+ // }
774
+ // }
775
+
776
+ // private async generateController(name: string, fileName: string): Promise<void> {
777
+ // const answers = await inquirer.prompt([
778
+ // {
779
+ // type: 'input',
780
+ // name: 'route',
781
+ // message: 'Route path:',
782
+ // default: `/api/${fileName}s`
783
+ // }
784
+ // ]);
785
+
786
+ // const filePath = path.join(process.cwd(), 'src/controllers', `${fileName}.controller.ts`);
787
+
788
+ // if (FileGenerator.fileExists(filePath)) {
789
+ // CLILogger.error(`Controller ${name} already exists`);
790
+ // return;
791
+ // }
792
+
793
+ // const content = controllerTemplate(name, answers.route);
794
+ // FileGenerator.writeFile(filePath, content);
795
+
796
+ // CLILogger.success(`Controller created: src/controllers/${fileName}.controller.ts`);
797
+ // CLILogger.info(`Route: ${answers.route}`);
798
+ // }
799
+
800
+ // private async generateService(name: string, fileName: string): Promise<void> {
801
+ // const filePath = path.join(process.cwd(), 'src/services', `${fileName}.service.ts`);
802
+
803
+ // if (FileGenerator.fileExists(filePath)) {
804
+ // CLILogger.error(`Service ${name} already exists`);
805
+ // return;
806
+ // }
807
+
808
+ // const content = serviceTemplate(name);
809
+ // FileGenerator.writeFile(filePath, content);
810
+
811
+ // CLILogger.success(`Service created: src/services/${fileName}.service.ts`);
812
+ // }
813
+
814
+ // private async generateRepository(name: string, fileName: string): Promise<void> {
815
+ // const answers = await inquirer.prompt([
816
+ // {
817
+ // type: 'input',
818
+ // name: 'entity',
819
+ // message: 'Entity name:',
820
+ // default: name.replace('Repository', '')
821
+ // }
822
+ // ]);
823
+
824
+ // const filePath = path.join(process.cwd(), 'src/repositories', `${fileName}.repository.ts`);
825
+
826
+ // if (FileGenerator.fileExists(filePath)) {
827
+ // CLILogger.error(`Repository ${name} already exists`);
828
+ // return;
829
+ // }
830
+
831
+ // const content = repositoryTemplate(name, answers.entity);
832
+ // FileGenerator.writeFile(filePath, content);
833
+
834
+ // CLILogger.success(`Repository created: src/repositories/${fileName}.repository.ts`);
835
+ // }
836
+
837
+ // private async generateEntity(name: string, fileName: string): Promise<void> {
838
+ // const filePath = path.join(process.cwd(), 'src/entities', `${fileName}.entity.ts`);
839
+
840
+ // if (FileGenerator.fileExists(filePath)) {
841
+ // CLILogger.error(`Entity ${name} already exists`);
842
+ // return;
843
+ // }
844
+
845
+ // const content = entityTemplate(name);
846
+ // FileGenerator.writeFile(filePath, content);
847
+
848
+ // CLILogger.success(`Entity created: src/entities/${fileName}.entity.ts`);
849
+ // }
850
+
851
+ // private async generateResource(name: string, fileName: string): Promise<void> {
852
+ // CLILogger.title(`🔷 Generating resource: ${name}`);
853
+
854
+ // const spinner = CLILogger.spinner('Generating files...');
855
+
856
+ // try {
857
+ // // Generate entity
858
+ // const entityPath = path.join(process.cwd(), 'src/entities', `${fileName}.entity.ts`);
859
+ // FileGenerator.writeFile(entityPath, entityTemplate(name));
860
+ // spinner.text = 'Entity created...';
861
+
862
+ // // Generate repository
863
+ // const repoPath = path.join(process.cwd(), 'src/repositories', `${fileName}.repository.ts`);
864
+ // FileGenerator.writeFile(repoPath, repositoryTemplate(name + 'Repository', name));
865
+ // spinner.text = 'Repository created...';
866
+
867
+ // // Generate service
868
+ // const servicePath = path.join(process.cwd(), 'src/services', `${fileName}.service.ts`);
869
+ // FileGenerator.writeFile(servicePath, serviceTemplate(name + 'Service'));
870
+ // spinner.text = 'Service created...';
871
+
872
+ // // Generate controller
873
+ // const controllerPath = path.join(process.cwd(), 'src/controllers', `${fileName}.controller.ts`);
874
+ // FileGenerator.writeFile(controllerPath, controllerTemplate(name + 'Controller', `/api/${fileName}s`));
875
+ // spinner.text = 'Controller created...';
876
+
877
+ // spinner.succeed('Resource generated successfully');
878
+
879
+ // CLILogger.box('đŸ“Ļ Generated Files', [
880
+ // `Entity: src/entities/${fileName}.entity.ts`,
881
+ // `Repository: src/repositories/${fileName}.repository.ts`,
882
+ // `Service: src/services/${fileName}.service.ts`,
883
+ // `Controller: src/controllers/${fileName}.controller.ts`
884
+ // ]);
885
+
886
+ // CLILogger.info(`\nRoute available at: /api/${fileName}s`);
887
+
888
+ // } catch (error: any) {
889
+ // spinner.fail('Failed to generate resource');
890
+ // CLILogger.error(error.message);
891
+ // }
892
+ // }
893
+ // }
894
+
895
+ // // ============================================================================
896
+ // // FILE: src/cli/commands/config.command.ts
897
+ // // ============================================================================
898
+ // import * as fs from 'fs';
899
+ // import * as path from 'path';
900
+ // import * as yaml from 'js-yaml';
901
+ // import { CLILogger } from '../utils/logger';
902
+ // import { FileGenerator } from '../utils/file-generator';
903
+ // import inquirer from 'inquirer';
904
+
905
+ // export class ConfigCommand {
906
+ // async execute(target: string): Promise<void> {
907
+ // switch (target) {
908
+ // case 'ai':
909
+ // await this.configureAI();
910
+ // break;
911
+ // case 'db':
912
+ // case 'database':
913
+ // await this.configureDatabase();
914
+ // break;
915
+ // case 'show':
916
+ // await this.showConfig();
917
+ // break;
918
+ // default:
919
+ // CLILogger.error(`Unknown config target: ${target}`);
920
+ // CLILogger.info('Available targets: ai, db, show');
921
+ // }
922
+ // }
923
+
924
+ // private async configureAI(): Promise<void> {
925
+ // CLILogger.title('🤖 OpenAI Configuration');
926
+
927
+ // const answers = await inquirer.prompt([
928
+ // {
929
+ // type: 'password',
930
+ // name: 'apiKey',
931
+ // message: 'OpenAI API Key:',
932
+ // mask: '*',
933
+ // validate: (input: string) => {
934
+ // if (!input || !input.startsWith('sk-')) {
935
+ // return 'Please enter a valid OpenAI API key (starts with sk-)';
936
+ // }
937
+ // return true;
938
+ // }
939
+ // },
940
+ // {
941
+ // type: 'list',
942
+ // name: 'model',
943
+ // message: 'Default model:',
944
+ // choices: [
945
+ // 'gpt-4-turbo',
946
+ // 'gpt-4',
947
+ // 'gpt-3.5-turbo',
948
+ // 'claude-sonnet-4-5-20250929',
949
+ // 'claude-opus-4-1-20250514'
950
+ // ],
951
+ // default: 'gpt-4'
952
+ // },
953
+ // {
954
+ // type: 'confirm',
955
+ // name: 'saveToEnv',
956
+ // message: 'Save API key to .env file?',
957
+ // default: true
958
+ // }
959
+ // ]);
960
+
961
+ // const configPath = path.join(process.cwd(), 'config/fragment.yaml');
962
+
963
+ // if (!FileGenerator.fileExists(configPath)) {
964
+ // CLILogger.error('fragment.yaml not found. Are you in a Fragment project?');
965
+ // return;
966
+ // }
967
+
968
+ // try {
969
+ // const configContent = FileGenerator.readFile(configPath);
970
+ // const config: any = yaml.load(configContent);
971
+
972
+ // if (!config.openai) {
973
+ // config.openai = {};
974
+ // }
975
+
976
+ // config.openai.apiKey = answers.saveToEnv ? '${OPENAI_API_KEY}' : answers.apiKey;
977
+ // config.openai.model = answers.model;
978
+
979
+ // FileGenerator.writeFile(configPath, yaml.dump(config));
980
+
981
+ // if (answers.saveToEnv) {
982
+ // const envPath = path.join(process.cwd(), '.env');
983
+ // let envContent = '';
984
+
985
+ // if (FileGenerator.fileExists(envPath)) {
986
+ // envContent = FileGenerator.readFile(envPath);
987
+ // }
988
+
989
+ // // Update or add OPENAI_API_KEY
990
+ // if (envContent.includes('OPENAI_API_KEY=')) {
991
+ // envContent = envContent.replace(
992
+ // /OPENAI_API_KEY=.*/,
993
+ // `OPENAI_API_KEY=${answers.apiKey}`
994
+ // );
995
+ // } else {
996
+ // envContent += `\nOPENAI_API_KEY=${answers.apiKey}`;
997
+ // }
998
+
999
+ // FileGenerator.writeFile(envPath, envContent);
1000
+ // CLILogger.success('API key saved to .env file');
1001
+ // }
1002
+
1003
+ // CLILogger.success('OpenAI configuration updated');
1004
+ // CLILogger.table({
1005
+ // 'Model': answers.model,
1006
+ // 'API Key': answers.saveToEnv ? 'Stored in .env' : 'Stored in config'
1007
+ // });
1008
+
1009
+ // } catch (error: any) {
1010
+ // CLILogger.error(`Failed to update configuration: ${error.message}`);
1011
+ // }
1012
+ // }
1013
+
1014
+ // private async configureDatabase(): Promise<void> {
1015
+ // CLILogger.title('đŸ—„ī¸ Database Configuration');
1016
+
1017
+ // const answers = await inquirer.prompt([
1018
+ // {
1019
+ // type: 'list',
1020
+ // name: 'type',
1021
+ // message: 'Database type:',
1022
+ // choices: ['postgres', 'mysql', 'sqlite', 'mongodb']
1023
+ // },
1024
+ // {
1025
+ // type: 'input',
1026
+ // name: 'host',
1027
+ // message: 'Host:',
1028
+ // default: 'localhost',
1029
+ // when: (answers) => answers.type !== 'sqlite'
1030
+ // },
1031
+ // {
1032
+ // type: 'input',
1033
+ // name: 'port',
1034
+ // message: 'Port:',
1035
+ // default: (answers: any) => {
1036
+ // const ports: any = { postgres: 5432, mysql: 3306, mongodb: 27017 };
1037
+ // return ports[answers.type] || 5432;
1038
+ // },
1039
+ // when: (answers) => answers.type !== 'sqlite'
1040
+ // },
1041
+ // {
1042
+ // type: 'input',
1043
+ // name: 'username',
1044
+ // message: 'Username:',
1045
+ // default: (answers: any) => answers.type === 'postgres' ? 'postgres' : 'root',
1046
+ // when: (answers) => answers.type !== 'sqlite'
1047
+ // },
1048
+ // {
1049
+ // type: 'password',
1050
+ // name: 'password',
1051
+ // message: 'Password:',
1052
+ // mask: '*',
1053
+ // when: (answers) => answers.type !== 'sqlite'
1054
+ // },
1055
+ // {
1056
+ // type: 'input',
1057
+ // name: 'database',
1058
+ // message: 'Database name:',
1059
+ // default: 'fragment_db'
1060
+ // },
1061
+ // {
1062
+ // type: 'confirm',
1063
+ // name: 'synchronize',
1064
+ // message: 'Auto-synchronize schema? (not recommended for production)',
1065
+ // default: true
1066
+ // }
1067
+ // ]);
1068
+
1069
+ // const configPath = path.join(process.cwd(), 'config/fragment.yaml');
1070
+
1071
+ // try {
1072
+ // const configContent = FileGenerator.readFile(configPath);
1073
+ // const config: any = yaml.load(configContent);
1074
+
1075
+ // config.database = {
1076
+ // type: answers.type,
1077
+ // ...(answers.type !== 'sqlite' && {
1078
+ // host: '${DB_HOST:' + answers.host + '}',
1079
+ // port: '${DB_PORT:' + answers.port + '}',
1080
+ // username: '${DB_USERNAME:' + answers.username + '}',
1081
+ // password: '${DB_PASSWORD}'
1082
+ // }),
1083
+ // database: '${DB_DATABASE:' + answers.database + '}',
1084
+ // synchronize: answers.synchronize,
1085
+ // logging: false
1086
+ // };
1087
+
1088
+ // FileGenerator.writeFile(configPath, yaml.dump(config));
1089
+
1090
+ // // Update .env
1091
+ // const envPath = path.join(process.cwd(), '.env');
1092
+ // let envContent = FileGenerator.fileExists(envPath) ? FileGenerator.readFile(envPath) : '';
1093
+
1094
+ // const envVars: any = {
1095
+ // DB_HOST: answers.host,
1096
+ // DB_PORT: answers.port,
1097
+ // DB_USERNAME: answers.username,
1098
+ // DB_PASSWORD: answers.password,
1099
+ // DB_DATABASE: answers.database
1100
+ // };
1101
+
1102
+ // Object.entries(envVars).forEach(([key, value]) => {
1103
+ // if (value !== undefined) {
1104
+ // if (envContent.includes(`${key}=`)) {
1105
+ // envContent = envContent.replace(new RegExp(`${key}=.*`), `${key}=${value}`);
1106
+ // } else {
1107
+ // envContent += `\n${key}=${value}`;
1108
+ // }
1109
+ // }
1110
+ // });
1111
+
1112
+ // FileGenerator.writeFile(envPath, envContent.trim());
1113
+
1114
+ // CLILogger.success('Database configuration updated');
1115
+ // CLILogger.table({
1116
+ // 'Type': answers.type,
1117
+ // 'Host': answers.host || 'N/A',
1118
+ // 'Database': answers.database,
1119
+ // 'Synchronize': answers.synchronize ? 'Yes' : 'No'
1120
+ // });
1121
+
1122
+ // } catch (error: any) {
1123
+ // CLILogger.error(`Failed to update configuration: ${error.message}`);
1124
+ // }
1125
+ // }
1126
+
1127
+ // private async showConfig(): Promise<void> {
1128
+ // CLILogger.title('📋 Current Configuration');
1129
+
1130
+ // const configPath = path.join(process.cwd(), 'config/fragment.yaml');
1131
+
1132
+ // if (!FileGenerator.fileExists(configPath)) {
1133
+ // CLILogger.error('fragment.yaml not found');
1134
+ // return;
1135
+ // }
1136
+
1137
+ // try {
1138
+ // const configContent = FileGenerator.readFile(configPath);
1139
+ // const config: any = yaml.load(configContent);
1140
+
1141
+ // CLILogger.section('Application');
1142
+ // CLILogger.table({
1143
+ // 'Name': config.app?.name || 'N/A',
1144
+ // 'Port': config.app?.port || 'N/A',
1145
+ // 'Environment': config.app?.env || 'N/A'
1146
+ // });
1147
+
1148
+ // CLILogger.section('Database');
1149
+ // CLILogger.table({
1150
+ // 'Type': config.database?.type || 'N/A',
1151
+ // 'Host': config.database?.host || 'N/A',
1152
+ // 'Database': config.database?.database || 'N/A',
1153
+ // 'Synchronize': config.database?.synchronize ? 'Yes' : 'No'
1154
+ // });
1155
+
1156
+ // if (config.openai) {
1157
+ // CLILogger.section('OpenAI');
1158
+ // CLILogger.table({
1159
+ // 'Model': config.openai.model || 'N/A',
1160
+ // 'API Key': config.openai.apiKey?.includes('${') ? 'From environment' : 'Configured'
1161
+ // });
1162
+ // }
1163
+
1164
+ // if (config.auth) {
1165
+ // CLILogger.section('Authentication');
1166
+ // CLILogger.table({
1167
+ // 'Token Expiry': config.auth.tokenExpiry || 'N/A',
1168
+ // 'Session Expiry': config.auth.sessionExpiry || 'N/A'
1169
+ // });
1170
+ // }
1171
+
1172
+ // } catch (error: any) {
1173
+ // CLILogger.error(`Failed to read configuration: ${error.message}`);
1174
+ // }
1175
+ // }
1176
+ // }
1177
+
1178
+ // // ============================================================================
1179
+ // // FILE: src/cli/commands/serve.command.ts
1180
+ // // ============================================================================
1181
+ // import { spawn } from 'child_process';
1182
+ // import { CLILogger } from '../utils/logger';
1183
+
1184
+ // export class ServeCommand {
1185
+ // async execute(options: { port?: number; watch?: boolean }): Promise<void> {
1186
+ // CLILogger.title('🚀 Starting Fragment Application');
1187
+
1188
+ // const port = options.port || process.env.PORT || 3000;
1189
+ // const args = ['--respawn', '--transpile-only'];
1190
+
1191
+ // if (options.watch !== false) {
1192
+ // args.push('--watch');
1193
+ // }
1194
+
1195
+ // args.push('src/server.ts');
1196
+
1197
+ // const env = { ...process.env, PORT: port.toString() };
1198
+
1199
+ // CLILogger.info(`Starting server on port ${port}...`);
1200
+
1201
+ // const child = spawn('ts-node-dev', args, {
1202
+ // env,
1203
+ // stdio: 'inherit'
1204
+ // });
1205
+
1206
+ // child.on('error', (error) => {
1207
+ // CLILogger.error(`Failed to start server: ${error.message}`);
1208
+ // });
1209
+
1210
+ // child.on('close', (code) => {
1211
+ // if (code !== 0) {
1212
+ // CLILogger.error(`Server exited with code ${code}`);
1213
+ // }
1214
+ // });
1215
+ // }
1216
+ // }
1217
+
1218
+ // // ============================================================================
1219
+ // // FILE: src/cli/commands/build.command.ts
1220
+ // // ============================================================================
1221
+ // import { execSync } from 'child_process';
1222
+ // import { CLILogger } from '../utils/logger';
1223
+
1224
+ // export class BuildCommand {
1225
+ // async execute(): Promise<void> {
1226
+ // CLILogger.title('🔨 Building Fragment Application');
1227
+
1228
+ // const spinner = CLILogger.spinner('Compiling TypeScript...');
1229
+
1230
+ // try {
1231
+ // execSync('tsc', { stdio: 'pipe' });
1232
+ // spinner.succeed('Build completed successfully');
1233
+
1234
+ // CLILogger.success('Output directory: ./dist');
1235
+ // CLILogger.info('Run "node dist/server.js" to start the production server');
1236
+
1237
+ // } catch (error: any) {
1238
+ // spinner.fail('Build failed');
1239
+ // CLILogger.error(error.message);
1240
+ // process.exit(1);
1241
+ // }
1242
+ // }
1243
+ // }
1244
+
1245
+ // // ============================================================================
1246
+ // // FILE: src/cli/commands/migrate.command.ts
1247
+ // // ============================================================================
1248
+ // import { execSync } from 'child_process';
1249
+ // import { CLILogger } from '../utils/logger';
1250
+ // import inquirer from 'inquirer';
1251
+
1252
+ // export class MigrateCommand {
1253
+ // async execute(action?: string): Promise<void> {
1254
+ // if (!action) {
1255
+ // const answer = await inquirer.prompt([
1256
+ // {
1257
+ // type: 'list',
1258
+ // name: 'action',
1259
+ // message: 'Select migration action:',
1260
+ // choices: [
1261
+ // { name: 'Run pending migrations', value: 'run' },
1262
+ // { name: 'Generate new migration', value: 'generate' },
1263
+ // { name: 'Revert last migration', value: 'revert' },
1264
+ // { name: 'Show migration status', value: 'show' }
1265
+ // ]
1266
+ // }
1267
+ // ]);
1268
+ // action = answer.action;
1269
+ // }
1270
+
1271
+ // switch (action) {
1272
+ // case 'run':
1273
+ // await this.runMigrations();
1274
+ // break;
1275
+ // case 'generate':
1276
+ // await this.generateMigration();
1277
+ // break;
1278
+ // case 'revert':
1279
+ // await this.revertMigration();
1280
+ // break;
1281
+ // case 'show':
1282
+ // await this.showMigrations();
1283
+ // break;
1284
+ // default:
1285
+ // CLILogger.error(`Unknown action: ${action}`);
1286
+ // }
1287
+ // }
1288
+
1289
+ // private async runMigrations(): Promise<void> {
1290
+ // CLILogger.title('đŸ“Ļ Running Migrations');
1291
+ // const spinner = CLILogger.spinner('Executing migrations...');
1292
+
1293
+ // try {
1294
+ // execSync('npm run typeorm migration:run', { stdio: 'pipe' });
1295
+ // spinner.succeed('Migrations executed successfully');
1296
+ // } catch (error: any) {
1297
+ // spinner.fail('Migration failed');
1298
+ // CLILogger.error(error.message);
1299
+ // }
1300
+ // }
1301
+
1302
+ // private async generateMigration(): Promise<void> {
1303
+ // const answer = await inquirer.prompt([
1304
+ // {
1305
+ // type: 'input',
1306
+ // name: 'name',
1307
+ // message: 'Migration name:',
1308
+ // validate: (input: string) => {
1309
+ // if (!input) return 'Name is required';
1310
+ // return true;
1311
+ // }
1312
+ // }
1313
+ // ]);
1314
+
1315
+ // CLILogger.title(`📝 Generating Migration: ${answer.name}`);
1316
+ // const spinner = CLILogger.spinner('Creating migration file...');
1317
+
1318
+ // try {
1319
+ // execSync(`npm run typeorm migration:generate -- -n ${answer.name}`, { stdio: 'pipe' });
1320
+ // spinner.succeed('Migration generated successfully');
1321
+ // } catch (error: any) {
1322
+ // spinner.fail('Failed to generate migration');
1323
+ // CLILogger.error(error.message);
1324
+ // }
1325
+ // }
1326
+
1327
+ // private async revertMigration(): Promise<void> {
1328
+ // const confirm = await inquirer.prompt([
1329
+ // {
1330
+ // type: 'confirm',
1331
+ // name: 'confirmed',
1332
+ // message: 'Are you sure you want to revert the last migration?',
1333
+ // default: false
1334
+ // }
1335
+ // ]);
1336
+
1337
+ // if (!confirm.confirmed) {
1338
+ // CLILogger.info('Migration revert cancelled');
1339
+ // return;
1340
+ // }
1341
+
1342
+ // CLILogger.title('âĒ Reverting Migration');
1343
+ // const spinner = CLILogger.spinner('Reverting last migration...');
1344
+
1345
+ // try {
1346
+ // execSync('npm run typeorm migration:revert', { stdio: 'pipe' });
1347
+ // spinner.succeed('Migration reverted successfully');
1348
+ // } catch (error: any) {
1349
+ // spinner.fail('Failed to revert migration');
1350
+ // CLILogger.error(error.message);
1351
+ // }
1352
+ // }
1353
+
1354
+ // private async showMigrations(): Promise<void> {
1355
+ // CLILogger.title('📋 Migration Status');
1356
+
1357
+ // try {
1358
+ // const output = execSync('npm run typeorm migration:show', { encoding: 'utf-8' });
1359
+ // console.log(output);
1360
+ // } catch (error: any) {
1361
+ // CLILogger.error('Failed to show migrations');
1362
+ // }
1363
+ // }
1364
+ // }
1365
+
1366
+ // // ============================================================================
1367
+ // // FILE: src/cli/cli.ts
1368
+ // // ============================================================================
1369
+ // import chalk from 'chalk';
1370
+ // import { Command } from 'commander';
1371
+ // import { InitCommand } from './commands/init.command';
1372
+ // import { GenerateCommand } from './commands/generate.command';
1373
+ // import { ConfigCommand } from './commands/config.command';
1374
+ // import { ServeCommand } from './commands/serve.command';
1375
+ // import { BuildCommand } from './commands/build.command';
1376
+ // import { MigrateCommand } from './commands/migrate.command';
1377
+ // import { CLILogger } from './utils/logger';
1378
+
1379
+ // export class CLI {
1380
+ // private program: Command;
1381
+ // private initCommand: InitCommand;
1382
+ // private generateCommand: GenerateCommand;
1383
+ // private configCommand: ConfigCommand;
1384
+ // private serveCommand: ServeCommand;
1385
+ // private buildCommand: BuildCommand;
1386
+ // private migrateCommand: MigrateCommand;
1387
+
1388
+ // constructor() {
1389
+ // this.program = new Command();
1390
+ // this.initCommand = new InitCommand();
1391
+ // this.generateCommand = new GenerateCommand();
1392
+ // this.configCommand = new ConfigCommand();
1393
+ // this.serveCommand = new ServeCommand();
1394
+ // this.buildCommand = new BuildCommand();
1395
+ // this.migrateCommand = new MigrateCommand();
1396
+
1397
+ // this.setupCommands();
1398
+ // }
1399
+
1400
+ // private setupCommands(): void {
1401
+ // this.program
1402
+ // .name('frg')
1403
+ // .description('Fragment Framework CLI - Build powerful TypeScript backends')
1404
+ // .version('1.0.0');
1405
+
1406
+ // // ASCII Art Banner
1407
+ // this.program
1408
+ // .addHelpText('beforeAll', () => {
1409
+ // return chalk.cyan(`
1410
+ // ╔═══════════════════════════════════════════════════════════╗
1411
+ // ║ ║
1412
+ // ║ ███████╗██████╗ █████╗ ██████╗ ███╗ ███╗███████╗ ║
1413
+ // ║ ██╔════╝██╔══██╗██╔══██╗██╔════╝ ████╗ ████║██╔════╝ ║
1414
+ // ║ █████╗ ██████╔╝███████║██║ ███╗██╔████╔██║█████╗ ║
1415
+ // ║ ██╔══╝ ██╔══██╗██╔══██║██║ ██║██║╚██╔╝██║██╔══╝ ║
1416
+ // ║ ██║ ██║ ██║██║ ██║╚██████╔╝██║ ╚═╝ ██║███████╗ ║
1417
+ // ║ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝ ║
1418
+ // ║ ║
1419
+ // ║ TypeScript Backend Framework (v1.0.0) ║
1420
+ // ╚═══════════════════════════════════════════════════════════╝
1421
+ // `);
1422
+ // });
1423
+
1424
+ // // Init command
1425
+ // this.program
1426
+ // .command('init [project-name]')
1427
+ // .description('Initialize a new Fragment project')
1428
+ // .action(async (projectName) => {
1429
+ // await this.initCommand.execute(projectName);
1430
+ // });
1431
+
1432
+ // // Generate commands
1433
+ // const generate = this.program
1434
+ // .command('generate')
1435
+ // .alias('g')
1436
+ // .description('Generate application components');
1437
+
1438
+ // generate
1439
+ // .command('controller [name]')
1440
+ // .alias('c')
1441
+ // .description('Generate a new controller')
1442
+ // .action(async (name) => {
1443
+ // await this.generateCommand.execute('controller', name);
1444
+ // });
1445
+
1446
+ // generate
1447
+ // .command('service [name]')
1448
+ // .alias('s')
1449
+ // .description('Generate a new service')
1450
+ // .action(async (name) => {
1451
+ // await this.generateCommand.execute('service', name);
1452
+ // });
1453
+
1454
+ // generate
1455
+ // .command('repository [name]')
1456
+ // .alias('r')
1457
+ // .description('Generate a new repository')
1458
+ // .action(async (name) => {
1459
+ // await this.generateCommand.execute('repository', name);
1460
+ // });
1461
+
1462
+ // generate
1463
+ // .command('entity [name]')
1464
+ // .alias('e')
1465
+ // .description('Generate a new entity')
1466
+ // .action(async (name) => {
1467
+ // await this.generateCommand.execute('entity', name);
1468
+ // });
1469
+
1470
+ // generate
1471
+ // .command('resource [name]')
1472
+ // .alias('res')
1473
+ // .description('Generate a complete resource (controller, service, repository, entity)')
1474
+ // .action(async (name) => {
1475
+ // await this.generateCommand.execute('resource', name);
1476
+ // });
1477
+
1478
+ // // Config commands
1479
+ // const config = this.program
1480
+ // .command('config')
1481
+ // .description('Configure Fragment application');
1482
+
1483
+ // config
1484
+ // .command('ai')
1485
+ // .description('Configure OpenAI integration')
1486
+ // .action(async () => {
1487
+ // await this.configCommand.execute('ai');
1488
+ // });
1489
+
1490
+ // config
1491
+ // .command('db')
1492
+ // .alias('database')
1493
+ // .description('Configure database connection')
1494
+ // .action(async () => {
1495
+ // await this.configCommand.execute('db');
1496
+ // });
1497
+
1498
+ // config
1499
+ // .command('show')
1500
+ // .description('Show current configuration')
1501
+ // .action(async () => {
1502
+ // await this.configCommand.execute('show');
1503
+ // });
1504
+
1505
+ // // Serve command
1506
+ // this.program
1507
+ // .command('serve')
1508
+ // .alias('dev')
1509
+ // .description('Start development server')
1510
+ // .option('-p, --port <port>', 'Port number', parseInt)
1511
+ // .option('--no-watch', 'Disable file watching')
1512
+ // .action(async (options) => {
1513
+ // await this.serveCommand.execute(options);
1514
+ // });
1515
+
1516
+ // // Build command
1517
+ // this.program
1518
+ // .command('build')
1519
+ // .description('Build application for production')
1520
+ // .action(async () => {
1521
+ // await this.buildCommand.execute();
1522
+ // });
1523
+
1524
+ // // Migrate commands
1525
+ // const migrate = this.program
1526
+ // .command('migrate')
1527
+ // .alias('migration')
1528
+ // .description('Database migration commands');
1529
+
1530
+ // migrate
1531
+ // .command('run')
1532
+ // .description('Run pending migrations')
1533
+ // .action(async () => {
1534
+ // await this.migrateCommand.execute('run');
1535
+ // });
1536
+
1537
+ // migrate
1538
+ // .command('generate')
1539
+ // .alias('create')
1540
+ // .description('Generate a new migration')
1541
+ // .action(async () => {
1542
+ // await this.migrateCommand.execute('generate');
1543
+ // });
1544
+
1545
+ // migrate
1546
+ // .command('revert')
1547
+ // .description('Revert last migration')
1548
+ // .action(async () => {
1549
+ // await this.migrateCommand.execute('revert');
1550
+ // });
1551
+
1552
+ // migrate
1553
+ // .command('show')
1554
+ // .alias('status')
1555
+ // .description('Show migration status')
1556
+ // .action(async () => {
1557
+ // await this.migrateCommand.execute('show');
1558
+ // });
1559
+
1560
+ // // Info command
1561
+ // this.program
1562
+ // .command('info')
1563
+ // .description('Display Fragment CLI information')
1564
+ // .action(() => {
1565
+ // CLILogger.box('Fragment Framework CLI', [
1566
+ // 'Version: 1.0.0',
1567
+ // 'TypeScript Backend Framework',
1568
+ // 'OOP + Decorators + DI',
1569
+ // '',
1570
+ // 'Documentation: https://fragment-framework.dev',
1571
+ // 'Repository: https://github.com/fragment/framework'
1572
+ // ]);
1573
+ // });
1574
+ // }
1575
+
1576
+ // run(args: string[]): void {
1577
+ // this.program.parse(['node', 'frg', ...args]);
1578
+ // }
1579
+ // }
1580
+
1581
+ // // ============================================================================
1582
+ // // FILE: src/app.ts (Updated with Fragment branding)
1583
+ // // ============================================================================
1584
+ // import express, { Express, Request, Response, NextFunction } from 'express';
1585
+ // import { DIContainer } from './core/container/di-container';
1586
+ // import { ConfigLoader } from './core/config/config-loader';
1587
+ // import { initializeDataSource, AppDataSource } from './database/data-source';
1588
+ // import { loggingMiddleware } from './middlewares/logging.middleware';
1589
+ // import { authMiddleware } from './auth/auth.middleware';
1590
+ // import {
1591
+ // CONTROLLER_METADATA,
1592
+ // CONTROLLER_PATH
1593
+ // } from './core/decorators/controller.decorator';
1594
+ // import {
1595
+ // ROUTE_METADATA
1596
+ // } from './core/decorators/route.decorator';
1597
+ // import {
1598
+ // AUTH_GUARD_METADATA
1599
+ // } from './core/decorators/auth-guard.decorator';
1600
+ // import {
1601
+ // MIDDLEWARE_METADATA
1602
+ // } from './core/decorators/middleware.decorator';
1603
+
1604
+ // // Import all controllers, services, repositories
1605
+ // import './controllers/health.controller';
1606
+ // import './auth/auth.controller';
1607
+ // import './services/health.service';
1608
+ // import './repositories/user.repository';
1609
+ // import './repositories/session.repository';
1610
+ // import './auth/auth.service';
1611
+ // import './core/openai/openai-client';
1612
+
1613
+ // export class FragmentApplication {
1614
+ // private app: Express;
1615
+
1616
+ // constructor() {
1617
+ // this.app = express();
1618
+ // }
1619
+
1620
+ // async initialize(): Promise<Express> {
1621
+ // // Load configuration
1622
+ // ConfigLoader.load(true);
1623
+
1624
+ // // Initialize database
1625
+ // const dataSource = initializeDataSource();
1626
+ // await dataSource.initialize();
1627
+ // console.log('✅ Database connected');
1628
+
1629
+ // // Middleware
1630
+ // this.app.use(express.json());
1631
+ // this.app.use(express.urlencoded({ extended: true }));
1632
+ // this.app.use(loggingMiddleware);
1633
+
1634
+ // // Register all controllers
1635
+ // this.registerControllers();
1636
+
1637
+ // // Error handling
1638
+ // this.app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
1639
+ // console.error(err.stack);
1640
+ // res.status(500).json({ error: 'Internal server error' });
1641
+ // });
1642
+
1643
+ // return this.app;
1644
+ // }
1645
+
1646
+ // private registerControllers(): void {
1647
+ // const registeredClasses = DIContainer.getRegisteredClasses();
1648
+
1649
+ // registeredClasses.forEach((controllerClass) => {
1650
+ // const isController = Reflect.getMetadata(CONTROLLER_METADATA, controllerClass);
1651
+ // if (!isController) return;
1652
+
1653
+ // const basePath = Reflect.getMetadata(CONTROLLER_PATH, controllerClass) || '';
1654
+ // const routes = Reflect.getMetadata(ROUTE_METADATA, controllerClass) || [];
1655
+ // const classMiddlewares = Reflect.getMetadata(MIDDLEWARE_METADATA, controllerClass) || [];
1656
+ // const classAuthGuard = Reflect.getMetadata(AUTH_GUARD_METADATA, controllerClass);
1657
+
1658
+ // const controllerInstance = DIContainer.resolve(controllerClass);
1659
+
1660
+ // routes.forEach((route: any) => {
1661
+ // const fullPath = basePath + route.path;
1662
+ // const handler = controllerInstance[route.handlerName].bind(controllerInstance);
1663
+
1664
+ // const middlewares: any[] = [...classMiddlewares];
1665
+
1666
+ // const methodAuthGuard = Reflect.getMetadata(
1667
+ // AUTH_GUARD_METADATA,
1668
+ // controllerClass,
1669
+ // route.handlerName
1670
+ // );
1671
+ // if (classAuthGuard || methodAuthGuard) {
1672
+ // middlewares.push(authMiddleware);
1673
+ // }
1674
+
1675
+ // const methodMiddlewares = Reflect.getMetadata(
1676
+ // MIDDLEWARE_METADATA,
1677
+ // controllerClass,
1678
+ // route.handlerName
1679
+ // ) || [];
1680
+ // middlewares.push(...methodMiddlewares);
1681
+
1682
+ // const asyncHandler = async (req: Request, res: Response, next: NextFunction) => {
1683
+ // try {
1684
+ // const result = await handler(req, res, next);
1685
+ // if (result && !res.headersSent) {
1686
+ // res.json(result);
1687
+ // }
1688
+ // } catch (error) {
1689
+ // next(error);
1690
+ // }
1691
+ // };
1692
+
1693
+ // (this.app as any)[route.method](fullPath, ...middlewares, asyncHandler);
1694
+
1695
+ // console.log(`📍 ${route.method.toUpperCase().padEnd(6)} ${fullPath}`);
1696
+ // });
1697
+ // });
1698
+ // }
1699
+
1700
+ // getExpressApp(): Express {
1701
+ // return this.app;
1702
+ // }
1703
+ // }
1704
+
1705
+ // // ============================================================================
1706
+ // // FILE: src/server.ts (Updated)
1707
+ // // ============================================================================a
1708
+
1709
+ // // ============================================================================
1710
+ // // COMPLETE CLI USAGE GUIDE
1711
+ // // ============================================================================
1712
+ // /*
1713
+
1714
+ // ## Fragment CLI (FRG) - World-Class Commands
1715
+
1716
+ // ### đŸŽ¯ Initialize New Project
1717
+ // ```bash
1718
+ // frg init my-app # Create new project
1719
+ // frg init # Interactive mode
1720
+ // ```
1721
+
1722
+ // ### đŸ—ī¸ Generate Code
1723
+ // ```bash
1724
+ // frg generate controller User # Generate controller
1725
+ // frg g c User # Short alias
1726
+
1727
+ // frg generate service User # Generate service
1728
+ // frg g s User # Short alias
1729
+
1730
+ // frg generate repository User # Generate repository
1731
+ // frg g r User # Short alias
1732
+
1733
+ // frg generate entity User # Generate entity
1734
+ // frg g e User # Short alias
1735
+
1736
+ // frg generate resource Product # Generate complete resource
1737
+ // frg g res Product # (controller, service, repository, entity)
1738
+ // ```
1739
+
1740
+ // ### âš™ī¸ Configure
1741
+ // ```bash
1742
+ // frg config ai # Configure OpenAI
1743
+ // frg config db # Configure database
1744
+ // frg config show # Show current config
1745
+ // ```
1746
+
1747
+ // ### 🚀 Development
1748
+ // ```bash
1749
+ // frg serve # Start dev server
1750
+ // frg dev # Alias for serve
1751
+ // frg serve --port 8080 # Custom port
1752
+ // frg serve --no-watch # Disable watch mode
1753
+ // ```
1754
+
1755
+ // ### đŸ“Ļ Production
1756
+ // ```bash
1757
+ // frg build # Build for production
1758
+ // node dist/server.js # Run production build
1759
+ // ```
1760
+
1761
+ // ### đŸ—„ī¸ Database Migrations
1762
+ // ```bash
1763
+ // frg migrate run # Run pending migrations
1764
+ // frg migrate generate # Create new migration
1765
+ // frg migrate revert # Revert last migration
1766
+ // frg migrate show # Show migration status
1767
+ // ```
1768
+
1769
+ // ### â„šī¸ Information
1770
+ // ```bash
1771
+ // frg info # Show CLI info
1772
+ // frg --help # Show help
1773
+ // frg --version # Show version
1774
+ // ```
1775
+
1776
+ // ## Example Workflow
1777
+
1778
+ // ```bash
1779
+ // # 1. Create new project
1780
+ // frg init my-blog-api
1781
+
1782
+ // # 2. Navigate to project
1783
+ // cd my-blog-api
1784
+
1785
+ // # 3. Configure OpenAI
1786
+ // frg config ai
1787
+
1788
+ // # 4. Generate a complete resource
1789
+ // frg generate resource Post
1790
+
1791
+ // # 5. Start development server
1792
+ // frg serve
1793
+
1794
+ // # 6. Access your API
1795
+ // curl http://localhost:3000/api/posts
1796
+ // ```
1797
+
1798
+ // ## Features
1799
+
1800
+ // ✨ Interactive prompts with validation
1801
+ // ✨ Beautiful ASCII art and colored output
1802
+ // ✨ Progress spinners for long operations
1803
+ // ✨ Automatic dependency installation
1804
+ // ✨ Smart file generation with templates
1805
+ // ✨ Configuration management
1806
+ // ✨ Database migration tools
1807
+ // ✨ Hot-reload development server
1808
+ // ✨ Production build optimization
1809
+
1810
+ // */