@gyxer-studio/generator 0.1.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/README.md +63 -0
- package/dist/generators/app.generator.d.ts +19 -0
- package/dist/generators/app.generator.d.ts.map +1 -0
- package/dist/generators/app.generator.js +237 -0
- package/dist/generators/app.generator.js.map +1 -0
- package/dist/generators/controller.generator.d.ts +10 -0
- package/dist/generators/controller.generator.d.ts.map +1 -0
- package/dist/generators/controller.generator.js +88 -0
- package/dist/generators/controller.generator.js.map +1 -0
- package/dist/generators/docker.generator.d.ts +15 -0
- package/dist/generators/docker.generator.d.ts.map +1 -0
- package/dist/generators/docker.generator.js +82 -0
- package/dist/generators/docker.generator.js.map +1 -0
- package/dist/generators/dto.generator.d.ts +23 -0
- package/dist/generators/dto.generator.d.ts.map +1 -0
- package/dist/generators/dto.generator.js +271 -0
- package/dist/generators/dto.generator.js.map +1 -0
- package/dist/generators/module.generator.d.ts +6 -0
- package/dist/generators/module.generator.d.ts.map +1 -0
- package/dist/generators/module.generator.js +20 -0
- package/dist/generators/module.generator.js.map +1 -0
- package/dist/generators/prisma.generator.d.ts +6 -0
- package/dist/generators/prisma.generator.d.ts.map +1 -0
- package/dist/generators/prisma.generator.js +243 -0
- package/dist/generators/prisma.generator.js.map +1 -0
- package/dist/generators/service.generator.d.ts +6 -0
- package/dist/generators/service.generator.d.ts.map +1 -0
- package/dist/generators/service.generator.js +97 -0
- package/dist/generators/service.generator.js.map +1 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/auth-jwt.generator.d.ts +20 -0
- package/dist/modules/auth-jwt.generator.d.ts.map +1 -0
- package/dist/modules/auth-jwt.generator.js +431 -0
- package/dist/modules/auth-jwt.generator.js.map +1 -0
- package/dist/project-generator.d.ts +16 -0
- package/dist/project-generator.d.ts.map +1 -0
- package/dist/project-generator.js +199 -0
- package/dist/project-generator.js.map +1 -0
- package/dist/security/report.d.ts +24 -0
- package/dist/security/report.d.ts.map +1 -0
- package/dist/security/report.js +108 -0
- package/dist/security/report.js.map +1 -0
- package/dist/utils.d.ts +16 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +44 -0
- package/dist/utils.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# @gyxer-studio/generator
|
|
2
|
+
|
|
3
|
+
NestJS project code generator. Takes a Gyxer schema and generates a complete, production-ready NestJS application with Prisma ORM.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @gyxer-studio/generator
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { generateProject } from '@gyxer-studio/generator';
|
|
15
|
+
import type { GyxerProject } from '@gyxer-studio/schema';
|
|
16
|
+
|
|
17
|
+
const project: GyxerProject = {
|
|
18
|
+
name: 'my-app',
|
|
19
|
+
version: '0.1.0',
|
|
20
|
+
entities: [/* ... */],
|
|
21
|
+
modules: [],
|
|
22
|
+
settings: {
|
|
23
|
+
port: 3000,
|
|
24
|
+
database: 'postgresql',
|
|
25
|
+
// ...
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
const files = generateProject(project);
|
|
30
|
+
// files is a Map<string, string> of filepath → content
|
|
31
|
+
|
|
32
|
+
for (const [path, content] of files) {
|
|
33
|
+
// write files to disk
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## What Gets Generated
|
|
38
|
+
|
|
39
|
+
- **Prisma schema** with models, relations, and enums
|
|
40
|
+
- **NestJS modules** with controllers, services, and DTOs
|
|
41
|
+
- **CRUD endpoints** with Swagger decorators and validation
|
|
42
|
+
- **JWT auth** (when `auth-jwt` module is enabled)
|
|
43
|
+
- **Docker** files (Dockerfile + docker-compose.yml)
|
|
44
|
+
- **Security report** with best practices assessment
|
|
45
|
+
|
|
46
|
+
## Individual Generators
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import {
|
|
50
|
+
generatePrismaSchema,
|
|
51
|
+
generateCreateDto,
|
|
52
|
+
generateUpdateDto,
|
|
53
|
+
generateController,
|
|
54
|
+
generateService,
|
|
55
|
+
generateModule,
|
|
56
|
+
generateDockerfile,
|
|
57
|
+
generateDockerCompose,
|
|
58
|
+
} from '@gyxer-studio/generator';
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Part of [Gyxer Studio](https://github.com/Gyxer513/gyxer-studio)
|
|
62
|
+
|
|
63
|
+
MIT License
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { GyxerProject } from '@gyxer-studio/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Generate main.ts bootstrap file.
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateMain(project: GyxerProject): string;
|
|
6
|
+
/**
|
|
7
|
+
* Generate app.module.ts with all entity modules imported.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateAppModule(project: GyxerProject): string;
|
|
10
|
+
/**
|
|
11
|
+
* Generate PrismaService and PrismaModule.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generatePrismaService(): string;
|
|
14
|
+
export declare function generatePrismaModule(): string;
|
|
15
|
+
/**
|
|
16
|
+
* Generate Prisma exception filter that converts Prisma errors to proper HTTP responses.
|
|
17
|
+
*/
|
|
18
|
+
export declare function generatePrismaExceptionFilter(): string;
|
|
19
|
+
//# sourceMappingURL=app.generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.generator.d.ts","sourceRoot":"","sources":["../../src/generators/app.generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGzD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAgF1D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CA+E/D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAe9C;AAED,wBAAgB,oBAAoB,IAAI,MAAM,CAW7C;AAED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CA6DtD"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { toKebabCase } from '../utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate main.ts bootstrap file.
|
|
4
|
+
*/
|
|
5
|
+
export function generateMain(project) {
|
|
6
|
+
const lines = [];
|
|
7
|
+
lines.push(`import { NestFactory } from '@nestjs/core';`);
|
|
8
|
+
lines.push(`import { ValidationPipe } from '@nestjs/common';`);
|
|
9
|
+
if (project.settings.enableSwagger) {
|
|
10
|
+
lines.push(`import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';`);
|
|
11
|
+
}
|
|
12
|
+
if (project.settings.enableHelmet) {
|
|
13
|
+
lines.push(`import helmet from 'helmet';`);
|
|
14
|
+
}
|
|
15
|
+
lines.push(`import { AppModule } from './app.module';`);
|
|
16
|
+
lines.push(`import { PrismaExceptionFilter } from './prisma/prisma-exception.filter';`);
|
|
17
|
+
lines.push('');
|
|
18
|
+
lines.push('async function bootstrap() {');
|
|
19
|
+
lines.push(' const app = await NestFactory.create(AppModule);');
|
|
20
|
+
lines.push('');
|
|
21
|
+
// Helmet
|
|
22
|
+
if (project.settings.enableHelmet) {
|
|
23
|
+
lines.push(' // Security headers');
|
|
24
|
+
lines.push(' app.use(helmet());');
|
|
25
|
+
lines.push('');
|
|
26
|
+
}
|
|
27
|
+
// CORS
|
|
28
|
+
if (project.settings.enableCors) {
|
|
29
|
+
lines.push(' // CORS');
|
|
30
|
+
lines.push(' app.enableCors();');
|
|
31
|
+
lines.push('');
|
|
32
|
+
}
|
|
33
|
+
// Validation
|
|
34
|
+
lines.push(' // Global validation pipe');
|
|
35
|
+
lines.push(' app.useGlobalPipes(');
|
|
36
|
+
lines.push(' new ValidationPipe({');
|
|
37
|
+
lines.push(' whitelist: true,');
|
|
38
|
+
lines.push(' forbidNonWhitelisted: true,');
|
|
39
|
+
lines.push(' transform: true,');
|
|
40
|
+
lines.push(' }),');
|
|
41
|
+
lines.push(' );');
|
|
42
|
+
lines.push('');
|
|
43
|
+
lines.push(' // Prisma exception filter — converts DB errors to proper HTTP responses');
|
|
44
|
+
lines.push(' app.useGlobalFilters(new PrismaExceptionFilter());');
|
|
45
|
+
lines.push('');
|
|
46
|
+
// Swagger
|
|
47
|
+
if (project.settings.enableSwagger) {
|
|
48
|
+
lines.push(' // Swagger API documentation');
|
|
49
|
+
const hasAuthJwt = project.modules?.some((m) => m.name === 'auth-jwt' && m.enabled !== false) ?? false;
|
|
50
|
+
lines.push(' const config = new DocumentBuilder()');
|
|
51
|
+
lines.push(` .setTitle('${project.name}')`);
|
|
52
|
+
lines.push(` .setDescription('${project.description || 'API documentation'}')`);
|
|
53
|
+
lines.push(` .setVersion('${project.version}')`);
|
|
54
|
+
if (hasAuthJwt) {
|
|
55
|
+
lines.push(" .addBearerAuth()");
|
|
56
|
+
}
|
|
57
|
+
lines.push(' .build();');
|
|
58
|
+
lines.push(' const document = SwaggerModule.createDocument(app, config);');
|
|
59
|
+
lines.push(" SwaggerModule.setup('api/docs', app, document);");
|
|
60
|
+
lines.push('');
|
|
61
|
+
}
|
|
62
|
+
lines.push(` await app.listen(process.env.PORT ?? ${project.settings.port});`);
|
|
63
|
+
lines.push(` console.log(\`Application is running on: \${await app.getUrl()}\`);`);
|
|
64
|
+
if (project.settings.enableSwagger) {
|
|
65
|
+
lines.push(` console.log(\`Swagger docs: \${await app.getUrl()}/api/docs\`);`);
|
|
66
|
+
}
|
|
67
|
+
lines.push('}');
|
|
68
|
+
lines.push('bootstrap();');
|
|
69
|
+
return lines.join('\n') + '\n';
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Generate app.module.ts with all entity modules imported.
|
|
73
|
+
*/
|
|
74
|
+
export function generateAppModule(project) {
|
|
75
|
+
const hasAuthJwt = project.modules?.some((m) => m.name === 'auth-jwt' && m.enabled !== false) ?? false;
|
|
76
|
+
const needsAppGuard = project.settings.enableRateLimit || hasAuthJwt;
|
|
77
|
+
const imports = [];
|
|
78
|
+
const moduleNames = [];
|
|
79
|
+
// Prisma module
|
|
80
|
+
imports.push(`import { PrismaModule } from './prisma/prisma.module';`);
|
|
81
|
+
moduleNames.push('PrismaModule');
|
|
82
|
+
// Rate limiting
|
|
83
|
+
if (project.settings.enableRateLimit) {
|
|
84
|
+
imports.push(`import { ThrottlerModule, ThrottlerGuard } from '@nestjs/throttler';`);
|
|
85
|
+
}
|
|
86
|
+
// Auth JWT
|
|
87
|
+
if (hasAuthJwt) {
|
|
88
|
+
imports.push(`import { AuthModule } from './auth/auth.module';`);
|
|
89
|
+
imports.push(`import { JwtAuthGuard } from './auth/guards/jwt-auth.guard';`);
|
|
90
|
+
moduleNames.push('AuthModule');
|
|
91
|
+
}
|
|
92
|
+
if (needsAppGuard) {
|
|
93
|
+
imports.push(`import { APP_GUARD } from '@nestjs/core';`);
|
|
94
|
+
}
|
|
95
|
+
// Entity modules
|
|
96
|
+
for (const entity of project.entities) {
|
|
97
|
+
const kebab = toKebabCase(entity.name);
|
|
98
|
+
imports.push(`import { ${entity.name}Module } from './${kebab}/${kebab}.module';`);
|
|
99
|
+
moduleNames.push(`${entity.name}Module`);
|
|
100
|
+
}
|
|
101
|
+
const lines = [];
|
|
102
|
+
lines.push(`import { Module } from '@nestjs/common';`);
|
|
103
|
+
for (const imp of imports) {
|
|
104
|
+
lines.push(imp);
|
|
105
|
+
}
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push('@Module({');
|
|
108
|
+
lines.push(' imports: [');
|
|
109
|
+
if (project.settings.enableRateLimit) {
|
|
110
|
+
lines.push(' ThrottlerModule.forRoot([{');
|
|
111
|
+
lines.push(` ttl: ${(project.settings.rateLimitTtl ?? 60) * 1000},`);
|
|
112
|
+
lines.push(` limit: ${project.settings.rateLimitMax ?? 100},`);
|
|
113
|
+
lines.push(' }]),');
|
|
114
|
+
}
|
|
115
|
+
for (const mod of moduleNames) {
|
|
116
|
+
lines.push(` ${mod},`);
|
|
117
|
+
}
|
|
118
|
+
lines.push(' ],');
|
|
119
|
+
if (needsAppGuard) {
|
|
120
|
+
lines.push(' providers: [');
|
|
121
|
+
if (project.settings.enableRateLimit) {
|
|
122
|
+
lines.push(' {');
|
|
123
|
+
lines.push(' provide: APP_GUARD,');
|
|
124
|
+
lines.push(' useClass: ThrottlerGuard,');
|
|
125
|
+
lines.push(' },');
|
|
126
|
+
}
|
|
127
|
+
if (hasAuthJwt) {
|
|
128
|
+
lines.push(' // Global JWT guard — all routes protected by default');
|
|
129
|
+
lines.push(' // Use @Public() decorator to make specific routes public');
|
|
130
|
+
lines.push(' {');
|
|
131
|
+
lines.push(' provide: APP_GUARD,');
|
|
132
|
+
lines.push(' useClass: JwtAuthGuard,');
|
|
133
|
+
lines.push(' },');
|
|
134
|
+
}
|
|
135
|
+
lines.push(' ],');
|
|
136
|
+
}
|
|
137
|
+
lines.push('})');
|
|
138
|
+
lines.push('export class AppModule {}');
|
|
139
|
+
return lines.join('\n') + '\n';
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Generate PrismaService and PrismaModule.
|
|
143
|
+
*/
|
|
144
|
+
export function generatePrismaService() {
|
|
145
|
+
return `import { Injectable, OnModuleInit, OnModuleDestroy } from '@nestjs/common';
|
|
146
|
+
import { PrismaClient } from '@prisma/client';
|
|
147
|
+
|
|
148
|
+
@Injectable()
|
|
149
|
+
export class PrismaService extends PrismaClient implements OnModuleInit, OnModuleDestroy {
|
|
150
|
+
async onModuleInit() {
|
|
151
|
+
await this.$connect();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
async onModuleDestroy() {
|
|
155
|
+
await this.$disconnect();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
`;
|
|
159
|
+
}
|
|
160
|
+
export function generatePrismaModule() {
|
|
161
|
+
return `import { Global, Module } from '@nestjs/common';
|
|
162
|
+
import { PrismaService } from './prisma.service';
|
|
163
|
+
|
|
164
|
+
@Global()
|
|
165
|
+
@Module({
|
|
166
|
+
providers: [PrismaService],
|
|
167
|
+
exports: [PrismaService],
|
|
168
|
+
})
|
|
169
|
+
export class PrismaModule {}
|
|
170
|
+
`;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Generate Prisma exception filter that converts Prisma errors to proper HTTP responses.
|
|
174
|
+
*/
|
|
175
|
+
export function generatePrismaExceptionFilter() {
|
|
176
|
+
return `import { ArgumentsHost, Catch, ExceptionFilter, HttpStatus } from '@nestjs/common';
|
|
177
|
+
import { Prisma } from '@prisma/client';
|
|
178
|
+
import { Response } from 'express';
|
|
179
|
+
|
|
180
|
+
@Catch(Prisma.PrismaClientKnownRequestError)
|
|
181
|
+
export class PrismaExceptionFilter implements ExceptionFilter {
|
|
182
|
+
catch(exception: Prisma.PrismaClientKnownRequestError, host: ArgumentsHost) {
|
|
183
|
+
const ctx = host.switchToHttp();
|
|
184
|
+
const response = ctx.getResponse<Response>();
|
|
185
|
+
|
|
186
|
+
switch (exception.code) {
|
|
187
|
+
case 'P2002': {
|
|
188
|
+
// Unique constraint violation
|
|
189
|
+
const fields = (exception.meta?.target as string[]) || [];
|
|
190
|
+
response.status(HttpStatus.CONFLICT).json({
|
|
191
|
+
statusCode: HttpStatus.CONFLICT,
|
|
192
|
+
message: \`Unique constraint violation on: \${fields.join(', ')}\`,
|
|
193
|
+
error: 'Conflict',
|
|
194
|
+
});
|
|
195
|
+
break;
|
|
196
|
+
}
|
|
197
|
+
case 'P2003': {
|
|
198
|
+
// Foreign key constraint violation
|
|
199
|
+
const field = (exception.meta?.field_name as string) || 'unknown';
|
|
200
|
+
response.status(HttpStatus.BAD_REQUEST).json({
|
|
201
|
+
statusCode: HttpStatus.BAD_REQUEST,
|
|
202
|
+
message: \`Foreign key constraint violated on: \${field}\`,
|
|
203
|
+
error: 'Bad Request',
|
|
204
|
+
});
|
|
205
|
+
break;
|
|
206
|
+
}
|
|
207
|
+
case 'P2025': {
|
|
208
|
+
// Record not found
|
|
209
|
+
response.status(HttpStatus.NOT_FOUND).json({
|
|
210
|
+
statusCode: HttpStatus.NOT_FOUND,
|
|
211
|
+
message: (exception.meta?.cause as string) || 'Record not found',
|
|
212
|
+
error: 'Not Found',
|
|
213
|
+
});
|
|
214
|
+
break;
|
|
215
|
+
}
|
|
216
|
+
case 'P2014': {
|
|
217
|
+
// Required relation violation
|
|
218
|
+
response.status(HttpStatus.BAD_REQUEST).json({
|
|
219
|
+
statusCode: HttpStatus.BAD_REQUEST,
|
|
220
|
+
message: 'Required relation violation',
|
|
221
|
+
error: 'Bad Request',
|
|
222
|
+
});
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
default: {
|
|
226
|
+
response.status(HttpStatus.INTERNAL_SERVER_ERROR).json({
|
|
227
|
+
statusCode: HttpStatus.INTERNAL_SERVER_ERROR,
|
|
228
|
+
message: \`Database error: \${exception.code}\`,
|
|
229
|
+
error: 'Internal Server Error',
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
`;
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=app.generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app.generator.js","sourceRoot":"","sources":["../../src/generators/app.generator.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Entity, GyxerProject } from '@gyxer-studio/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a NestJS controller for an entity with full CRUD + Swagger.
|
|
4
|
+
* When auth-jwt is enabled:
|
|
5
|
+
* - GET endpoints are @Public() (no auth required)
|
|
6
|
+
* - POST/PATCH/DELETE require JWT (global guard)
|
|
7
|
+
* - @ApiBearerAuth() on protected endpoints for Swagger UI
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateController(entity: Entity, project: GyxerProject): string;
|
|
10
|
+
//# sourceMappingURL=controller.generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.generator.d.ts","sourceRoot":"","sources":["../../src/generators/controller.generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGjE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAsFhF"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { toCamelCase, toKebabCase, pluralize } from '../utils.js';
|
|
2
|
+
/**
|
|
3
|
+
* Generate a NestJS controller for an entity with full CRUD + Swagger.
|
|
4
|
+
* When auth-jwt is enabled:
|
|
5
|
+
* - GET endpoints are @Public() (no auth required)
|
|
6
|
+
* - POST/PATCH/DELETE require JWT (global guard)
|
|
7
|
+
* - @ApiBearerAuth() on protected endpoints for Swagger UI
|
|
8
|
+
*/
|
|
9
|
+
export function generateController(entity, project) {
|
|
10
|
+
const name = entity.name;
|
|
11
|
+
const camel = toCamelCase(name);
|
|
12
|
+
const kebab = toKebabCase(name);
|
|
13
|
+
const route = pluralize(kebab);
|
|
14
|
+
const serviceName = `${camel}Service`;
|
|
15
|
+
const className = `${name}Controller`;
|
|
16
|
+
const hasAuthJwt = project.modules?.some((m) => m.name === 'auth-jwt' && m.enabled !== false) ?? false;
|
|
17
|
+
const importLines = [
|
|
18
|
+
'import {',
|
|
19
|
+
' Controller,',
|
|
20
|
+
' Get,',
|
|
21
|
+
' Post,',
|
|
22
|
+
' Body,',
|
|
23
|
+
' Patch,',
|
|
24
|
+
' Param,',
|
|
25
|
+
' Delete,',
|
|
26
|
+
' ParseIntPipe,',
|
|
27
|
+
"} from '@nestjs/common';",
|
|
28
|
+
];
|
|
29
|
+
const swaggerImports = hasAuthJwt
|
|
30
|
+
? "import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';"
|
|
31
|
+
: "import { ApiTags, ApiOperation, ApiResponse } from '@nestjs/swagger';";
|
|
32
|
+
importLines.push(swaggerImports);
|
|
33
|
+
if (hasAuthJwt) {
|
|
34
|
+
importLines.push("import { Public } from '../auth/decorators/public.decorator';");
|
|
35
|
+
}
|
|
36
|
+
importLines.push(`import { ${name}Service } from './${kebab}.service';`);
|
|
37
|
+
importLines.push(`import { Create${name}Dto } from './dto/create-${kebab}.dto';`);
|
|
38
|
+
importLines.push(`import { Update${name}Dto } from './dto/update-${kebab}.dto';`);
|
|
39
|
+
const protectedDecorator = hasAuthJwt ? '\n @ApiBearerAuth()' : '';
|
|
40
|
+
const publicDecorator = hasAuthJwt ? '\n @Public()' : '';
|
|
41
|
+
return `${importLines.join('\n')}
|
|
42
|
+
|
|
43
|
+
@ApiTags('${route}')
|
|
44
|
+
@Controller('${route}')
|
|
45
|
+
export class ${className} {
|
|
46
|
+
constructor(private readonly ${serviceName}: ${name}Service) {}
|
|
47
|
+
|
|
48
|
+
@Post()${protectedDecorator}
|
|
49
|
+
@ApiOperation({ summary: 'Create a new ${camel}' })
|
|
50
|
+
@ApiResponse({ status: 201, description: '${name} created successfully' })
|
|
51
|
+
create(@Body() dto: Create${name}Dto) {
|
|
52
|
+
return this.${serviceName}.create(dto);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
@Get()${publicDecorator}
|
|
56
|
+
@ApiOperation({ summary: 'Get all ${pluralize(camel)}' })
|
|
57
|
+
@ApiResponse({ status: 200, description: 'List of ${pluralize(camel)}' })
|
|
58
|
+
findAll() {
|
|
59
|
+
return this.${serviceName}.findAll();
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
@Get(':id')${publicDecorator}
|
|
63
|
+
@ApiOperation({ summary: 'Get a ${camel} by id' })
|
|
64
|
+
@ApiResponse({ status: 200, description: '${name} found' })
|
|
65
|
+
@ApiResponse({ status: 404, description: '${name} not found' })
|
|
66
|
+
findOne(@Param('id', ParseIntPipe) id: number) {
|
|
67
|
+
return this.${serviceName}.findOne(id);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
@Patch(':id')${protectedDecorator}
|
|
71
|
+
@ApiOperation({ summary: 'Update a ${camel}' })
|
|
72
|
+
@ApiResponse({ status: 200, description: '${name} updated successfully' })
|
|
73
|
+
@ApiResponse({ status: 404, description: '${name} not found' })
|
|
74
|
+
update(@Param('id', ParseIntPipe) id: number, @Body() dto: Update${name}Dto) {
|
|
75
|
+
return this.${serviceName}.update(id, dto);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@Delete(':id')${protectedDecorator}
|
|
79
|
+
@ApiOperation({ summary: 'Delete a ${camel}' })
|
|
80
|
+
@ApiResponse({ status: 200, description: '${name} deleted successfully' })
|
|
81
|
+
@ApiResponse({ status: 404, description: '${name} not found' })
|
|
82
|
+
remove(@Param('id', ParseIntPipe) id: number) {
|
|
83
|
+
return this.${serviceName}.remove(id);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
`;
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=controller.generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.generator.js","sourceRoot":"","sources":["../../src/generators/controller.generator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAElE;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,OAAqB;IACtE,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;IACzB,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;IAC/B,MAAM,WAAW,GAAG,GAAG,KAAK,SAAS,CAAC;IACtC,MAAM,SAAS,GAAG,GAAG,IAAI,YAAY,CAAC;IAEtC,MAAM,UAAU,GACd,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,IAAI,KAAK,CAAC;IAEtF,MAAM,WAAW,GAAG;QAClB,UAAU;QACV,eAAe;QACf,QAAQ;QACR,SAAS;QACT,SAAS;QACT,UAAU;QACV,UAAU;QACV,WAAW;QACX,iBAAiB;QACjB,0BAA0B;KAC3B,CAAC;IAEF,MAAM,cAAc,GAAG,UAAU;QAC/B,CAAC,CAAC,sFAAsF;QACxF,CAAC,CAAC,uEAAuE,CAAC;IAC5E,WAAW,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAEjC,IAAI,UAAU,EAAE,CAAC;QACf,WAAW,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;IACpF,CAAC;IAED,WAAW,CAAC,IAAI,CAAC,YAAY,IAAI,qBAAqB,KAAK,YAAY,CAAC,CAAC;IACzE,WAAW,CAAC,IAAI,CAAC,kBAAkB,IAAI,4BAA4B,KAAK,QAAQ,CAAC,CAAC;IAClF,WAAW,CAAC,IAAI,CAAC,kBAAkB,IAAI,4BAA4B,KAAK,QAAQ,CAAC,CAAC;IAElF,MAAM,kBAAkB,GAAG,UAAU,CAAC,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,EAAE,CAAC;IACpE,MAAM,eAAe,GAAG,UAAU,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,EAAE,CAAC;IAE1D,OAAO,GAAG,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC;;YAEtB,KAAK;eACF,KAAK;eACL,SAAS;iCACS,WAAW,KAAK,IAAI;;WAE1C,kBAAkB;2CACc,KAAK;8CACF,IAAI;8BACpB,IAAI;kBAChB,WAAW;;;UAGnB,eAAe;sCACa,SAAS,CAAC,KAAK,CAAC;sDACA,SAAS,CAAC,KAAK,CAAC;;kBAEpD,WAAW;;;eAGd,eAAe;oCACM,KAAK;8CACK,IAAI;8CACJ,IAAI;;kBAEhC,WAAW;;;iBAGZ,kBAAkB;uCACI,KAAK;8CACE,IAAI;8CACJ,IAAI;qEACmB,IAAI;kBACvD,WAAW;;;kBAGX,kBAAkB;uCACG,KAAK;8CACE,IAAI;8CACJ,IAAI;;kBAEhC,WAAW;;;CAG5B,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { GyxerProject } from '@gyxer-studio/schema';
|
|
2
|
+
/**
|
|
3
|
+
* Generate Dockerfile for the NestJS app.
|
|
4
|
+
*/
|
|
5
|
+
export declare function generateDockerfile(): string;
|
|
6
|
+
/**
|
|
7
|
+
* Generate docker-compose.yml with app + PostgreSQL.
|
|
8
|
+
*/
|
|
9
|
+
export declare function generateDockerCompose(project: GyxerProject): string;
|
|
10
|
+
/**
|
|
11
|
+
* Generate .env and .env.example files.
|
|
12
|
+
*/
|
|
13
|
+
export declare function generateEnvFile(project: GyxerProject): string;
|
|
14
|
+
export declare function generateEnvExample(project: GyxerProject): string;
|
|
15
|
+
//# sourceMappingURL=docker.generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.generator.d.ts","sourceRoot":"","sources":["../../src/generators/docker.generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAkB3C;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAsCnE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAO7D;AAED,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,MAAM,CAMhE"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate Dockerfile for the NestJS app.
|
|
3
|
+
*/
|
|
4
|
+
export function generateDockerfile() {
|
|
5
|
+
return `FROM node:20-alpine AS builder
|
|
6
|
+
WORKDIR /app
|
|
7
|
+
COPY package*.json ./
|
|
8
|
+
RUN npm install
|
|
9
|
+
COPY . .
|
|
10
|
+
RUN npx prisma generate
|
|
11
|
+
RUN npm run build
|
|
12
|
+
|
|
13
|
+
FROM node:20-alpine AS runner
|
|
14
|
+
WORKDIR /app
|
|
15
|
+
COPY --from=builder /app/dist ./dist
|
|
16
|
+
COPY --from=builder /app/node_modules ./node_modules
|
|
17
|
+
COPY --from=builder /app/package*.json ./
|
|
18
|
+
COPY --from=builder /app/prisma ./prisma
|
|
19
|
+
EXPOSE 3000
|
|
20
|
+
CMD ["sh", "-c", "npx prisma db push --skip-generate && node dist/main.js"]
|
|
21
|
+
`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Generate docker-compose.yml with app + PostgreSQL.
|
|
25
|
+
*/
|
|
26
|
+
export function generateDockerCompose(project) {
|
|
27
|
+
const dbName = project.name.replace(/-/g, '_');
|
|
28
|
+
return `version: '3.8'
|
|
29
|
+
|
|
30
|
+
services:
|
|
31
|
+
app:
|
|
32
|
+
build: .
|
|
33
|
+
ports:
|
|
34
|
+
- "\${PORT:-${project.settings.port}}:${project.settings.port}"
|
|
35
|
+
environment:
|
|
36
|
+
- DATABASE_URL=postgresql://postgres:\${DB_PASSWORD:-postgres}@db:5432/${dbName}
|
|
37
|
+
- PORT=${project.settings.port}
|
|
38
|
+
depends_on:
|
|
39
|
+
db:
|
|
40
|
+
condition: service_healthy
|
|
41
|
+
restart: unless-stopped
|
|
42
|
+
|
|
43
|
+
db:
|
|
44
|
+
image: postgres:16-alpine
|
|
45
|
+
environment:
|
|
46
|
+
POSTGRES_DB: ${dbName}
|
|
47
|
+
POSTGRES_USER: postgres
|
|
48
|
+
POSTGRES_PASSWORD: \${DB_PASSWORD:-postgres}
|
|
49
|
+
ports:
|
|
50
|
+
- "\${DB_PORT:-5432}:5432"
|
|
51
|
+
volumes:
|
|
52
|
+
- pgdata:/var/lib/postgresql/data
|
|
53
|
+
healthcheck:
|
|
54
|
+
test: ["CMD-SHELL", "pg_isready -U postgres"]
|
|
55
|
+
interval: 5s
|
|
56
|
+
timeout: 5s
|
|
57
|
+
retries: 5
|
|
58
|
+
restart: unless-stopped
|
|
59
|
+
|
|
60
|
+
volumes:
|
|
61
|
+
pgdata:
|
|
62
|
+
`;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Generate .env and .env.example files.
|
|
66
|
+
*/
|
|
67
|
+
export function generateEnvFile(project) {
|
|
68
|
+
const dbName = project.name.replace(/-/g, '_');
|
|
69
|
+
return `DATABASE_URL=postgresql://postgres:postgres@localhost:5432/${dbName}
|
|
70
|
+
PORT=${project.settings.port}
|
|
71
|
+
DB_PASSWORD=postgres
|
|
72
|
+
DB_PORT=5432
|
|
73
|
+
`;
|
|
74
|
+
}
|
|
75
|
+
export function generateEnvExample(project) {
|
|
76
|
+
return `DATABASE_URL=postgresql://postgres:YOUR_PASSWORD@localhost:5432/YOUR_DB_NAME
|
|
77
|
+
PORT=${project.settings.port}
|
|
78
|
+
DB_PASSWORD=YOUR_PASSWORD
|
|
79
|
+
DB_PORT=5432
|
|
80
|
+
`;
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=docker.generator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"docker.generator.js","sourceRoot":"","sources":["../../src/generators/docker.generator.ts"],"names":[],"mappings":"AAEA;;GAEG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO;;;;;;;;;;;;;;;;CAgBR,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAqB;IACzD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAE/C,OAAO;;;;;;oBAMW,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,CAAC,IAAI;;+EAEY,MAAM;eACtE,OAAO,CAAC,QAAQ,CAAC,IAAI;;;;;;;;;qBASf,MAAM;;;;;;;;;;;;;;;;CAgB1B,CAAC;AACF,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,OAAqB;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC/C,OAAO,8DAA8D,MAAM;OACtE,OAAO,CAAC,QAAQ,CAAC,IAAI;;;CAG3B,CAAC;AACF,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,OAAqB;IACtD,OAAO;OACF,OAAO,CAAC,QAAQ,CAAC,IAAI;;;CAG3B,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Entity, GyxerProject } from '@gyxer-studio/schema';
|
|
2
|
+
/** FK field descriptor for DTO generation. */
|
|
3
|
+
interface FkFieldInfo {
|
|
4
|
+
name: string;
|
|
5
|
+
targetEntity: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Collect all foreign key fields that this entity needs in its DTO.
|
|
9
|
+
* Sources:
|
|
10
|
+
* 1. Entity's own relations that define a foreignKey (explicit FK).
|
|
11
|
+
* 2. Inverse relations from other entities that create FK on this entity.
|
|
12
|
+
*/
|
|
13
|
+
export declare function collectFkFields(entity: Entity, project: GyxerProject): FkFieldInfo[];
|
|
14
|
+
/**
|
|
15
|
+
* Generate Create DTO for an entity.
|
|
16
|
+
*/
|
|
17
|
+
export declare function generateCreateDto(entity: Entity, project: GyxerProject): string;
|
|
18
|
+
/**
|
|
19
|
+
* Generate Update DTO for an entity (all fields optional).
|
|
20
|
+
*/
|
|
21
|
+
export declare function generateUpdateDto(entity: Entity, project: GyxerProject): string;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=dto.generator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dto.generator.d.ts","sourceRoot":"","sources":["../../src/generators/dto.generator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAS,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGxE,8CAA8C;AAC9C,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;CACtB;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,WAAW,EAAE,CAgDpF;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAkD/E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,YAAY,GAAG,MAAM,CAgC/E"}
|