create-flex-stack 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.
@@ -0,0 +1,654 @@
1
+ function toPackageName(name) {
2
+ const normalized = name
3
+ .toLowerCase()
4
+ .replace(/[^a-z0-9._-]+/g, '-')
5
+ .replace(/^[._-]+/, '')
6
+ .replace(/[._-]+$/, '');
7
+ return normalized || 'app';
8
+ }
9
+ export function getTsConfig(options) {
10
+ const decorators = options.orm === 'typeorm'
11
+ ? `,\n "experimentalDecorators": true,\n "emitDecoratorMetadata": true,\n "strictPropertyInitialization": false`
12
+ : '';
13
+ return `{
14
+ "compilerOptions": {
15
+ "target": "es2022",
16
+ "module": "NodeNext",
17
+ "moduleResolution": "NodeNext",
18
+ "outDir": "./dist",
19
+ "rootDir": "./src",
20
+ "strict": true,
21
+ "isolatedModules": true,
22
+ "esModuleInterop": true,
23
+ "skipLibCheck": true,
24
+ "forceConsistentCasingInFileNames": true,
25
+ "resolveJsonModule": true${decorators}
26
+ },
27
+ "include": ["src/**/*"]
28
+ }`;
29
+ }
30
+ export function getGitIgnore() {
31
+ return `# Logs
32
+ logs
33
+ *.log
34
+ npm-debug.log*
35
+ yarn-debug.log*
36
+ yarn-error.log*
37
+ lerna-debug.log*
38
+
39
+ # Diagnostic reports
40
+ report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
41
+
42
+ # Dependency directories
43
+ node_modules/
44
+ jspm_packages/
45
+
46
+ # Dist / Build
47
+ dist/
48
+ build/
49
+ .tsbuildinfo
50
+
51
+ # Environment variables
52
+ .env
53
+ .env.local
54
+ .env.development.local
55
+ .env.test.local
56
+ .env.production.local
57
+
58
+ # IDEs and editors
59
+ .idea/
60
+ .vscode/
61
+ *.suo
62
+ *.ntvs*
63
+ *.njsproj
64
+ *.sln
65
+ *.sw?
66
+
67
+ # OS files
68
+ .DS_Store
69
+ Thumbs.db
70
+
71
+ # Uploads
72
+ uploads/
73
+ `;
74
+ }
75
+ export function getDockerFiles(options) {
76
+ const isPrisma = options.orm === 'prisma';
77
+ const composeDatabaseUrl = options.database === 'postgres'
78
+ ? 'postgresql://postgres:password@db:5432/${PROJECT_NAME}?schema=public'
79
+ : options.database === 'mysql'
80
+ ? 'mysql://user:password@db:3306/${PROJECT_NAME}'
81
+ : options.database === 'mongodb'
82
+ ? 'mongodb://db:27017/${PROJECT_NAME}'
83
+ : '${DATABASE_URL}';
84
+ const dbService = options.database === 'postgres'
85
+ ? ` db:
86
+ image: postgres:15-alpine
87
+ container_name: \${PROJECT_NAME}-db
88
+ restart: always
89
+ environment:
90
+ POSTGRES_USER: postgres
91
+ POSTGRES_PASSWORD: password
92
+ POSTGRES_DB: \${PROJECT_NAME}
93
+ ports:
94
+ - "5432:5432"
95
+ volumes:
96
+ - pgdata:/var/lib/postgresql/data`
97
+ : options.database === 'mysql'
98
+ ? ` db:
99
+ image: mysql:8
100
+ container_name: \${PROJECT_NAME}-db
101
+ restart: always
102
+ environment:
103
+ MYSQL_ROOT_PASSWORD: password
104
+ MYSQL_DATABASE: \${PROJECT_NAME}
105
+ MYSQL_USER: user
106
+ MYSQL_PASSWORD: password
107
+ ports:
108
+ - "3306:3306"
109
+ volumes:
110
+ - mysqldata:/var/lib/mysql`
111
+ : options.database === 'mongodb'
112
+ ? ` db:
113
+ image: mongo:6
114
+ container_name: \${PROJECT_NAME}-db
115
+ restart: always
116
+ ports:
117
+ - "27017:27017"
118
+ volumes:
119
+ - mongodata:/data/db`
120
+ : ''; // No SQLite service needed in docker-compose
121
+ const redisService = options.caching
122
+ ? `\n redis:
123
+ image: redis:7-alpine
124
+ container_name: \${PROJECT_NAME}-redis
125
+ restart: always
126
+ ports:
127
+ - "6379:6379"`
128
+ : '';
129
+ let volumes = '';
130
+ if (options.database === 'postgres') {
131
+ volumes = `volumes:\n pgdata:`;
132
+ }
133
+ else if (options.database === 'mysql') {
134
+ volumes = `volumes:\n mysqldata:`;
135
+ }
136
+ else if (options.database === 'mongodb') {
137
+ volumes = `volumes:\n mongodata:`;
138
+ }
139
+ const dockerfile = isPrisma
140
+ ? `FROM node:20-slim AS builder
141
+ WORKDIR /usr/src/app
142
+
143
+ RUN apt-get update -y && apt-get install -y openssl ca-certificates && rm -rf /var/lib/apt/lists/*
144
+
145
+ COPY package*.json ./
146
+ RUN npm ci
147
+ COPY . .
148
+ RUN npx prisma generate
149
+ RUN npm run build
150
+
151
+ FROM node:20-slim
152
+ WORKDIR /usr/src/app
153
+
154
+ RUN apt-get update -y && apt-get install -y openssl ca-certificates && rm -rf /var/lib/apt/lists/*
155
+
156
+ COPY package*.json ./
157
+ RUN npm ci --omit=dev
158
+ COPY --from=builder /usr/src/app/dist ./dist
159
+ COPY --from=builder /usr/src/app/prisma ./prisma
160
+ COPY --from=builder /usr/src/app/node_modules/.prisma ./node_modules/.prisma
161
+
162
+ EXPOSE 3000
163
+ CMD ["node", "dist/server.js"]
164
+ `
165
+ : `FROM node:20-slim AS builder
166
+ WORKDIR /usr/src/app
167
+
168
+ COPY package*.json ./
169
+ RUN npm ci
170
+ COPY . .
171
+ RUN npm run build
172
+
173
+ FROM node:20-slim
174
+ WORKDIR /usr/src/app
175
+
176
+ COPY package*.json ./
177
+ RUN npm ci --omit=dev
178
+ COPY --from=builder /usr/src/app/dist ./dist
179
+
180
+ EXPOSE 3000
181
+ CMD ["node", "dist/server.js"]
182
+ `;
183
+ const dockerCompose = `version: '3.8'
184
+
185
+ services:
186
+ app:
187
+ build: .
188
+ container_name: \${PROJECT_NAME}-app
189
+ ports:
190
+ - "\${PORT:-3000}:\${PORT:-3000}"
191
+ env_file:
192
+ - .env
193
+ environment:
194
+ - NODE_ENV=production
195
+ - PORT=\${PORT:-3000}
196
+ - DATABASE_URL=${composeDatabaseUrl}
197
+ ${options.auth ? `- JWT_SECRET=\${JWT_SECRET}
198
+ - JWT_REFRESH_SECRET=\${JWT_REFRESH_SECRET}` : ''}
199
+ ${options.caching ? '- REDIS_URL=redis://redis:6379' : ''}
200
+ depends_on:
201
+ ${dbService ? '- db' : ''}
202
+ ${options.caching ? '- redis' : ''}
203
+
204
+ ${dbService}${redisService}
205
+
206
+ ${volumes}
207
+ `;
208
+ return { dockerfile, dockerCompose };
209
+ }
210
+ export function getDotEnv(options) {
211
+ let dbUrl = '';
212
+ if (options.database === 'postgres') {
213
+ dbUrl = 'postgresql://postgres:password@localhost:5432/' + options.projectName + '?schema=public';
214
+ }
215
+ else if (options.database === 'mysql') {
216
+ dbUrl = 'mysql://user:password@localhost:3306/' + options.projectName;
217
+ }
218
+ else if (options.database === 'sqlite') {
219
+ dbUrl = 'file:./dev.db';
220
+ }
221
+ else if (options.database === 'mongodb') {
222
+ dbUrl = 'mongodb://localhost:27017/' + options.projectName;
223
+ }
224
+ let env = `PROJECT_NAME="${toPackageName(options.projectName)}"
225
+ PORT=3000
226
+ NODE_ENV=development
227
+ DATABASE_URL="${dbUrl}"
228
+ `;
229
+ if (options.auth) {
230
+ env += `JWT_SECRET="super-secret-key-change-me-in-production"
231
+ JWT_REFRESH_SECRET="super-secret-refresh-key-change-me-in-production"
232
+ JWT_EXPIRES_IN="15m"
233
+ JWT_REFRESH_EXPIRES_IN="7d"
234
+ `;
235
+ }
236
+ if (options.caching) {
237
+ env += `REDIS_URL="redis://localhost:6379"
238
+ `;
239
+ }
240
+ return env;
241
+ }
242
+ export function getReadme(options) {
243
+ const architectureName = options.architecture === 'clean'
244
+ ? 'Clean Architecture'
245
+ : options.architecture === 'hexagonal'
246
+ ? 'Hexagonal Architecture (Ports & Adapters)'
247
+ : options.architecture === 'modular'
248
+ ? 'Modular Feature-based Architecture'
249
+ : options.architecture === 'vmc'
250
+ ? 'VMC Architecture (View, Model, Controller)'
251
+ : 'Layered Architecture (MVC)';
252
+ const prismaSection = options.orm === 'prisma'
253
+ ? `## Prisma
254
+
255
+ Prisma needs a generated client before the app can import \`@prisma/client\`.
256
+
257
+ Development:
258
+ \`\`\`bash
259
+ npm run db:generate
260
+ npm run db:push
261
+ \`\`\`
262
+
263
+ Production or Docker release flow:
264
+ \`\`\`bash
265
+ npm run db:generate
266
+ npm run db:migrate:deploy
267
+ \`\`\`
268
+
269
+ Equivalent direct Prisma commands:
270
+ \`\`\`bash
271
+ npx prisma generate
272
+ npx prisma migrate deploy
273
+ \`\`\`
274
+
275
+ Useful local tools:
276
+ \`\`\`bash
277
+ npx prisma studio
278
+ \`\`\`
279
+ `
280
+ : '';
281
+ const dockerSection = options.docker
282
+ ? `## Docker
283
+
284
+ The generated \`Dockerfile\` uses \`node:20-slim\` and installs \`openssl\` plus CA certificates so Prisma engines work reliably in containers.
285
+
286
+ \`\`\`bash
287
+ docker compose up --build
288
+ \`\`\`
289
+
290
+ Make sure \`.env\` contains \`PROJECT_NAME\`, \`PORT\`, and \`DATABASE_URL\`. The compose file reads \`.env\` via \`env_file\`.
291
+ `
292
+ : '';
293
+ const swaggerSection = options.swagger
294
+ ? `## API Documentation
295
+
296
+ Swagger UI is mounted at:
297
+
298
+ \`\`\`text
299
+ http://localhost:3000/docs
300
+ \`\`\`
301
+
302
+ The OpenAPI document includes the user endpoints generated for this project.
303
+ `
304
+ : '';
305
+ const testingSection = options.testing
306
+ ? `## Tests
307
+
308
+ Tests live in \`tests/\`.
309
+
310
+ \`\`\`bash
311
+ npm test
312
+ \`\`\`
313
+ `
314
+ : '';
315
+ return `# ${options.projectName}
316
+
317
+ Created with create-flex-stack. This project uses **${architectureName}** built with **ExpressJS + TypeScript**${options.frontend ? ' and a React frontend client' : ''}.
318
+
319
+ ## Technologies
320
+ - **Backend Framework**: ExpressJS
321
+ - **Database**: ${options.database}
322
+ - **ORM / ODM**: ${options.orm}
323
+ - **Validation**: ${options.validation}
324
+ ${options.auth ? '- **Auth**: JWT Authentication & Refresh Tokens' : ''}
325
+ ${options.fileUpload ? '- **File Upload**: Configured with Multer' : ''}
326
+ ${options.docker ? '- **Docker**: Dockerfile & docker-compose configuration' : ''}
327
+ ${options.rateLimiting ? '- **Rate Limiting**: express-rate-limit' : ''}
328
+ ${options.swagger ? '- **Swagger**: API Documentation' : ''}
329
+ ${options.caching ? '- **Caching**: Redis Cache Layer' : ''}
330
+ ${options.rbac ? '- **RBAC**: Role-Based Access Control' : ''}
331
+ ${options.testing ? '- **Testing**: Jest unit & integration testing' : ''}
332
+
333
+ ## Project Structure
334
+
335
+ ${options.frontend ? `- \`backend/\`: Express API
336
+ - \`frontend/\`: React client
337
+ - \`docker-compose.yml\`: local container orchestration` : `- \`src/\`: application source code
338
+ - \`prisma/\`: Prisma schema and migrations when Prisma is selected
339
+ - \`tests/\`: Jest tests when testing is enabled`}
340
+
341
+ ## Getting Started
342
+
343
+ ### Installation
344
+ Install dependencies:
345
+ \`\`\`bash
346
+ npm install
347
+ \`\`\`
348
+
349
+ Configure environment variables in \`.env\`.
350
+
351
+ ${options.orm !== 'prisma' ? 'Ensure your selected database is running before starting the API.' : ''}
352
+
353
+ ### Development
354
+ \`\`\`bash
355
+ npm run dev
356
+ \`\`\`
357
+
358
+ ### Build
359
+ \`\`\`bash
360
+ npm run build
361
+ \`\`\`
362
+
363
+ ### Production Start
364
+ \`\`\`bash
365
+ npm start
366
+ \`\`\`
367
+
368
+ ${prismaSection}
369
+ ${dockerSection}
370
+ ${swaggerSection}
371
+ ${testingSection}
372
+ `;
373
+ }
374
+ export function getRootPackageJson(projectName) {
375
+ const packageName = toPackageName(projectName);
376
+ const pkg = {
377
+ name: packageName,
378
+ version: "1.0.0",
379
+ private: true,
380
+ workspaces: [
381
+ "backend",
382
+ "frontend"
383
+ ],
384
+ scripts: {
385
+ "dev": "concurrently \"npm run dev --workspace=backend\" \"npm run dev --workspace=frontend\"",
386
+ "build": "npm run build --workspace=backend && npm run build --workspace=frontend",
387
+ "start": "npm start --workspace=backend",
388
+ "test": "npm test --workspace=backend"
389
+ },
390
+ dependencies: {
391
+ "concurrently": "^8.2.2"
392
+ }
393
+ };
394
+ return JSON.stringify(pkg, null, 2);
395
+ }
396
+ export function getPackageJson(options) {
397
+ const packageName = toPackageName(options.projectName);
398
+ const dependencies = {
399
+ "express": "^4.19.2",
400
+ "cors": "^2.8.5",
401
+ "dotenv": "^16.4.5",
402
+ "helmet": "^7.1.0"
403
+ };
404
+ const devDependencies = {
405
+ "typescript": "^5.4.5",
406
+ "@types/node": "^20.12.7",
407
+ "@types/express": "^4.17.21",
408
+ "@types/cors": "^2.8.17",
409
+ "tsx": "^4.7.2",
410
+ "nodemon": "^3.1.0"
411
+ };
412
+ // ORM Specifics
413
+ if (options.orm === 'prisma') {
414
+ dependencies["@prisma/client"] = "^5.12.1";
415
+ devDependencies["prisma"] = "^5.12.1";
416
+ }
417
+ else if (options.orm === 'mongoose') {
418
+ dependencies["mongoose"] = "^8.3.1";
419
+ }
420
+ else if (options.orm === 'typeorm') {
421
+ dependencies["typeorm"] = "^0.3.20";
422
+ dependencies["reflect-metadata"] = "^0.2.2";
423
+ if (options.database === 'postgres') {
424
+ dependencies["pg"] = "^8.11.5";
425
+ devDependencies["@types/pg"] = "^8.11.5";
426
+ }
427
+ else if (options.database === 'mysql') {
428
+ dependencies["mysql2"] = "^3.9.7";
429
+ }
430
+ else if (options.database === 'sqlite') {
431
+ dependencies["sqlite3"] = "^5.1.7";
432
+ }
433
+ }
434
+ // Auth Specifics
435
+ if (options.auth) {
436
+ dependencies["jsonwebtoken"] = "^9.0.2";
437
+ dependencies["bcryptjs"] = "^2.4.3";
438
+ devDependencies["@types/jsonwebtoken"] = "^9.0.6";
439
+ devDependencies["@types/bcryptjs"] = "^2.4.6";
440
+ }
441
+ // Validation
442
+ if (options.validation === 'zod') {
443
+ dependencies["zod"] = "^3.22.4";
444
+ }
445
+ else if (options.validation === 'joi') {
446
+ dependencies["joi"] = "^17.12.3";
447
+ devDependencies["@types/joi"] = "^17.2.3";
448
+ }
449
+ // Optional modules
450
+ if (options.rateLimiting) {
451
+ dependencies["express-rate-limit"] = "^7.2.0";
452
+ }
453
+ if (options.swagger) {
454
+ dependencies["swagger-ui-express"] = "^5.0.0";
455
+ devDependencies["@types/swagger-ui-express"] = "^4.1.6";
456
+ }
457
+ if (options.caching) {
458
+ dependencies["redis"] = "^4.6.13";
459
+ }
460
+ if (options.fileUpload) {
461
+ dependencies["multer"] = "^2.2.0";
462
+ devDependencies["@types/multer"] = "^1.4.11";
463
+ }
464
+ // Testing setup (Jest)
465
+ if (options.testing) {
466
+ devDependencies["jest"] = "^29.7.0";
467
+ devDependencies["ts-jest"] = "^29.1.2";
468
+ devDependencies["supertest"] = "^6.3.4";
469
+ devDependencies["@types/jest"] = "^29.5.12";
470
+ devDependencies["@types/supertest"] = "^6.0.2";
471
+ }
472
+ const packageJson = {
473
+ name: `${packageName}-backend`,
474
+ version: "1.0.0",
475
+ description: `Express backend built with ${options.architecture} architecture`,
476
+ main: "dist/server.js",
477
+ type: "module",
478
+ scripts: {
479
+ "build": "tsc",
480
+ "start": "node dist/server.js",
481
+ "dev": "nodemon --watch src --ext ts --exec tsx src/server.ts",
482
+ "db:generate": options.orm === 'prisma' ? "npx prisma generate" : "echo 'No db:generate script needed'",
483
+ "db:push": options.orm === 'prisma' ? "npx prisma db push" : "echo 'No db:push script needed'",
484
+ "db:migrate:deploy": options.orm === 'prisma' ? "npx prisma migrate deploy" : "echo 'No db:migrate:deploy script needed'",
485
+ "test": options.testing ? "node --experimental-vm-modules node_modules/jest/bin/jest.js --passWithNoTests" : "echo 'No tests configured'"
486
+ },
487
+ dependencies,
488
+ devDependencies
489
+ };
490
+ return JSON.stringify(packageJson, null, 2);
491
+ }
492
+ export function getPrismaSchema(options) {
493
+ let provider = 'postgresql';
494
+ if (options.database === 'mysql')
495
+ provider = 'mysql';
496
+ if (options.database === 'sqlite')
497
+ provider = 'sqlite';
498
+ if (options.database === 'mongodb')
499
+ provider = 'mongodb';
500
+ let schema = `datasource db {
501
+ provider = "${provider}"
502
+ url = env("DATABASE_URL")
503
+ }
504
+
505
+ generator client {
506
+ provider = "prisma-client-js"
507
+ }
508
+ `;
509
+ schema += `\nmodel User {
510
+ id String @id @default(${provider === 'mongodb' ? 'auto()' : 'uuid()'}) ${provider === 'mongodb' ? '@map("_id") @db.ObjectId' : ''}
511
+ email String @unique
512
+ name String?
513
+ ${options.auth ? ` password String
514
+ role String @default("user")` : ` role String?`}
515
+ createdAt DateTime @default(now())
516
+ updatedAt DateTime @updatedAt
517
+ ${options.auth ? ` refreshToken String?` : ''}
518
+ }
519
+ `;
520
+ return schema;
521
+ }
522
+ export function getAuthenticatedPrismaUserModel(options) {
523
+ let provider = 'postgresql';
524
+ if (options.database === 'mysql')
525
+ provider = 'mysql';
526
+ if (options.database === 'sqlite')
527
+ provider = 'sqlite';
528
+ if (options.database === 'mongodb')
529
+ provider = 'mongodb';
530
+ return `model User {
531
+ id String @id @default(${provider === 'mongodb' ? 'auto()' : 'uuid()'}) ${provider === 'mongodb' ? '@map("_id") @db.ObjectId' : ''}
532
+ email String @unique
533
+ name String?
534
+ password String
535
+ role String @default("user")
536
+ createdAt DateTime @default(now())
537
+ updatedAt DateTime @updatedAt
538
+ refreshToken String?
539
+ }
540
+ `;
541
+ }
542
+ export function getMulterMiddleware() {
543
+ return `import multer from 'multer';
544
+ import path from 'path';
545
+ import fs from 'fs';
546
+ import { AppError } from './errorHandler.js'; // Fallback path
547
+
548
+ const uploadDir = path.resolve(process.cwd(), 'uploads');
549
+ if (!fs.existsSync(uploadDir)) {
550
+ fs.mkdirSync(uploadDir, { recursive: true });
551
+ }
552
+
553
+ const storage = multer.diskStorage({
554
+ destination: (req, file, cb) => {
555
+ cb(null, uploadDir);
556
+ },
557
+ filename: (req, file, cb) => {
558
+ const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
559
+ cb(null, file.fieldname + '-' + uniqueSuffix + path.extname(file.originalname));
560
+ }
561
+ });
562
+
563
+ const fileFilter = (req: any, file: any, cb: any) => {
564
+ // Allow images and documents
565
+ const allowedTypes = ['.png', '.jpg', '.jpeg', '.pdf', '.docx', '.txt'];
566
+ const ext = path.extname(file.originalname).toLowerCase();
567
+ if (allowedTypes.includes(ext)) {
568
+ cb(null, true);
569
+ } else {
570
+ cb(new AppError(400, 'Invalid file type. Only PNG, JPG, PDF, DOCX, TXT allowed.'));
571
+ }
572
+ };
573
+
574
+ export const upload = multer({
575
+ storage,
576
+ fileFilter,
577
+ limits: {
578
+ fileSize: 5 * 1024 * 1024 // 5 MB limit
579
+ }
580
+ });
581
+ `;
582
+ }
583
+ export function getTypeOrmConfig(options) {
584
+ let type = 'postgres';
585
+ if (options.database === 'mysql')
586
+ type = 'mysql';
587
+ if (options.database === 'sqlite')
588
+ type = 'sqlite';
589
+ const databaseLine = type === 'sqlite' ? ' database: "dev.db",' : ' url: process.env.DATABASE_URL,';
590
+ return `import "reflect-metadata";
591
+ import { DataSource } from "typeorm";
592
+ import { UserEntity } from "../entities/user.entity.js"; // Fallback path
593
+
594
+ export const AppDataSource = new DataSource({
595
+ type: "${type}",
596
+ ${databaseLine}
597
+ synchronize: true, // Auto-create tables in development
598
+ logging: false,
599
+ entities: [UserEntity],
600
+ migrations: [],
601
+ subscribers: [],
602
+ });
603
+ `;
604
+ }
605
+ export function getTypeOrmEntity() {
606
+ return `import { Entity, PrimaryGeneratedColumn, Column, CreateDateColumn, UpdateDateColumn } from "typeorm";
607
+
608
+ @Entity({ name: "users" })
609
+ export class UserEntity {
610
+ @PrimaryGeneratedColumn("uuid")
611
+ id!: string;
612
+
613
+ @Column({ unique: true })
614
+ email!: string;
615
+
616
+ @Column({ nullable: true })
617
+ name?: string;
618
+
619
+ @Column()
620
+ password!: string;
621
+
622
+ @Column({ default: "user" })
623
+ role!: string;
624
+
625
+ @Column({ nullable: true })
626
+ refreshToken?: string;
627
+
628
+ @CreateDateColumn()
629
+ createdAt!: Date;
630
+
631
+ @UpdateDateColumn()
632
+ updatedAt!: Date;
633
+ }
634
+ `;
635
+ }
636
+ export function getJestConfig() {
637
+ return `{
638
+ "preset": "ts-jest",
639
+ "testEnvironment": "node",
640
+ "testPathIgnorePatterns": ["/node_modules/", "/dist/"],
641
+ "extensionsToTreatAsEsm": [".ts"],
642
+ "moduleNameMapper": {
643
+ "^(\\\\.{1,2}/.*)\\\\.js$": "$1"
644
+ },
645
+ "transform": {
646
+ "^.+\\\\.tsx?$": [
647
+ "ts-jest",
648
+ {
649
+ "useESM": true
650
+ }
651
+ ]
652
+ }
653
+ }`;
654
+ }
@@ -0,0 +1,26 @@
1
+ import { getLayeredFiles } from './layeredTemplate.js';
2
+ export function getVmcFiles(options) {
3
+ const layeredFiles = getLayeredFiles(options);
4
+ const files = {};
5
+ for (const [filePath, originalContent] of Object.entries(layeredFiles)) {
6
+ let targetPath = filePath
7
+ .replace('src/schemas/user.schema.ts', 'src/view/user.view.ts')
8
+ .replace('src/repositories/user.repository.ts', 'src/model/user.repository.ts')
9
+ .replace('src/models/user.model.ts', 'src/model/user.model.ts')
10
+ .replace('src/services/user.service.ts', 'src/model/user.model-service.ts')
11
+ .replace('src/controllers/user.controller.ts', 'src/controller/user.controller.ts');
12
+ let content = originalContent
13
+ .replaceAll('../repositories/user.repository.js', '../model/user.repository.js')
14
+ .replaceAll('../models/user.model.js', './user.model.js')
15
+ .replaceAll('../services/user.service.js', '../model/user.model-service.js')
16
+ .replaceAll('../controllers/user.controller.js', '../controller/user.controller.js')
17
+ .replaceAll('../schemas/user.schema.js', '../view/user.view.js')
18
+ .replaceAll('Traditional Layered', 'VMC')
19
+ .replaceAll('Layered Architecture', 'VMC Architecture');
20
+ if (targetPath === 'src/model/user.repository.ts') {
21
+ content = content.replaceAll('../models/user.model.js', './user.model.js');
22
+ }
23
+ files[targetPath] = content;
24
+ }
25
+ return files;
26
+ }
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};