speedrun-cli 2.8.0 → 2.9.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/CHANGELOG.md CHANGED
@@ -5,6 +5,28 @@ All notable changes to create-nestjs-auth will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.9.0] - 2026-08-22
9
+
10
+ ### Added
11
+ - **Realistic Seed Generator (`speedrun-cli seed [module]` / alias `s` or `sd`)** — Introduced a new core CLI command and generator module (`src/seedGenerator.js`) to interactively generate realistic dummy data tailored to a module's active fields (emails, titles, prices, dates, UUIDs) targeting Prisma seed scripts (`prisma/seeds/[module].seed.ts` & master `prisma/seed.ts`), TypeORM custom scripts (`src/database/seeds/[module].seed.ts`), or raw JSON mock files (`src/modules/[module]/mock-data.json`).
12
+ - **Interconnected CLI Ecosystem** — Integrated `seed` (`s`) with existing module parser (`parseExistingFields`), ORM detector (`detectOrm`), primary key resolver (`detectModulePrimaryKey`), and package manager runner.
13
+
14
+ ---
15
+
16
+ ## [2.8.2] - 2026-08-22
17
+
18
+ ### Added
19
+ - **Duplicate Module Validation & Overwrite Guard** — When running `speedrun-cli g [module]`, the CLI now checks if the module directory (e.g. `src/modules/orange`) already exists. If detected, it displays a warning with hints to use `speedrun-cli field` (`f`) or `speedrun-cli config` (`c`), and prompts for explicit confirmation before proceeding (`default: false`), preventing accidental overwrites.
20
+
21
+ ---
22
+
23
+ ## [2.8.1] - 2026-08-22
24
+
25
+ ### Fixed
26
+ - **Fixed TS2307: Cannot find module `../../common/guards/jwt-auth.guard`** — Enhanced `ensureBaseArchitecture(targetDir)` in `src/moduleGenerator.js` to automatically verify and scaffold placeholder guards (`src/common/guards/jwt-auth.guard.ts`, `src/common/guards/roles.guard.ts`) and decorators (`src/common/decorators/roles.decorator.ts`) whenever generating (`speedrun-cli g`) or configuring (`speedrun-cli c`) protected CRUD modules.
27
+
28
+ ---
29
+
8
30
  ## [2.8.0] - 2026-08-22
9
31
 
10
32
  ### Added
package/README.md CHANGED
@@ -42,6 +42,7 @@ npx speedrun-cli create my-app
42
42
  * 🔗 **Relationship Builder:** Add `Many-to-One` or `One-to-Many` relationships to other modules directly from the terminal with automatic foreign key wiring.
43
43
  * ✏️ **Sub-Menu Interactive Field Manager (`speedrun-cli field` / `f`):** Modify existing generated modules on the fly. Selectively edit specific field attributes (Name, Type, or Optional status), add new fields, or delete fields with automated DTO and ORM schema re-sync.
44
44
  * ⚙️ **Dynamic Module Configurator (`speedrun-cli config` / `c`):** Customize Auth Guards, change role permissions (`@Roles('ADMIN', 'SUPERADMIN')`), and enable/disable active CRUD endpoints on existing controllers without rewriting code.
45
+ * 🌱 **Realistic Seed Generator (`speedrun-cli seed` / `s` / `sd`):** Interactively generate dummy/seed data tailored to module fields (emails, titles, prices, dates, UUIDs) targeting Prisma seed scripts, TypeORM seed scripts, or raw JSON mock files.
45
46
  * 🏗️ **Automated Base Architecture:** Ensures `src/common/base` (`BaseController`, `BaseService`, and Swagger helpers) exists to eliminate missing import compilation errors (`TS2307`/`TS4112`).
46
47
  * 🔄 **Auto AppModule Registration:** Automatically injects generated modules into `src/app.module.ts`.
47
48
 
@@ -55,6 +56,7 @@ npx speedrun-cli create my-app
55
56
  | `speedrun-cli generate [module]` | `g` | Generates a new CRUD module with PKs, fields, ORM sync, and Auth Guards. |
56
57
  | `speedrun-cli field [module]` | `f` | Interactive Field Manager to Add, Edit (sub-menu), or Delete fields on existing modules. |
57
58
  | `speedrun-cli config [module]` | `c` | Customize role guards (`@Roles`), auth protection, and active CRUD operations. |
59
+ | `speedrun-cli seed [module]` | `s` / `sd` | Generates realistic dummy/seed data scripts (Prisma, TypeORM, JSON) for a module. |
58
60
 
59
61
  ---
60
62
 
@@ -89,6 +91,12 @@ npx speedrun-cli f orders
89
91
  npx speedrun-cli c orders
90
92
  ```
91
93
 
94
+ ### 5. Generate Seed & Dummy Data
95
+ ```bash
96
+ # Generate realistic seed data for Prisma, TypeORM, or raw JSON mock files
97
+ npx speedrun-cli s orders
98
+ ```
99
+
92
100
  ---
93
101
 
94
102
  ## 💡 Why This Exists
package/bin/cli.js CHANGED
@@ -30,6 +30,7 @@ const {
30
30
  generateModule,
31
31
  manageFields,
32
32
  configureModule,
33
+ generateSeed,
33
34
  } = require(path.join(packageRoot, 'src'));
34
35
 
35
36
  program
@@ -81,6 +82,21 @@ program
81
82
  }
82
83
  });
83
84
 
85
+ // ==================== SEED GENERATOR COMMAND ====================
86
+ program
87
+ .command('seed [module-name]')
88
+ .alias('s')
89
+ .alias('sd')
90
+ .description('Generate realistic seed/dummy data for a module')
91
+ .action(async (moduleName) => {
92
+ try {
93
+ console.log(chalk.cyan(`\n😱🤯🤯 speedrun-cli v${CLI_VERSION} seed generator 🤧🥶🥶🥶 (real)\n`));
94
+ await generateSeed(moduleName, process.cwd());
95
+ } catch (error) {
96
+ console.error(chalk.red('\n❌ Seed generation failed:'), error);
97
+ }
98
+ });
99
+
84
100
  // ==================== MAIN SCAFFOLD COMMAND (DEFAULT) ====================
85
101
  program
86
102
  .command('create [app-name]', { isDefault: true })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speedrun-cli",
3
- "version": "2.8.0",
3
+ "version": "2.9.0",
4
4
  "description": "CLI tool to scaffold a production-ready NestJS authentication system with JWT, refresh tokens, and RBAC",
5
5
  "keywords": [
6
6
  "nestjs",
@@ -336,4 +336,4 @@ async function manageFields(providedModuleName, targetDir = process.cwd()) {
336
336
  }
337
337
  }
338
338
 
339
- module.exports = { manageFields };
339
+ module.exports = { manageFields, parseExistingFields };
package/src/index.js CHANGED
@@ -11,6 +11,7 @@ const postSetup = require('./postSetup');
11
11
  const moduleGenerator = require('./moduleGenerator');
12
12
  const fieldManager = require('./fieldManager');
13
13
  const moduleConfigurator = require('./moduleConfigurator');
14
+ const seedGenerator = require('./seedGenerator');
14
15
 
15
16
  module.exports = {
16
17
  ...constants,
@@ -21,4 +22,5 @@ module.exports = {
21
22
  ...moduleGenerator,
22
23
  ...fieldManager,
23
24
  ...moduleConfigurator,
25
+ ...seedGenerator,
24
26
  };
@@ -176,6 +176,9 @@ ${ops.create ? `
176
176
  */
177
177
  async function configureModule(providedModuleName, targetDir = process.cwd()) {
178
178
  try {
179
+ const { ensureBaseArchitecture } = require('./moduleGenerator');
180
+ await ensureBaseArchitecture(targetDir);
181
+
179
182
  let moduleName = providedModuleName;
180
183
 
181
184
  if (!moduleName) {
@@ -80,11 +80,13 @@ async function detectOrm(targetDir) {
80
80
  }
81
81
 
82
82
  /**
83
- * Ensures src/common/base exists with required abstract classes & DTOs
83
+ * Ensures src/common/base, src/common/guards, and src/common/decorators exist with required abstract classes, DTOs, guards & decorators
84
84
  */
85
85
  async function ensureBaseArchitecture(targetDir) {
86
86
  try {
87
87
  const commonBaseDir = path.join(targetDir, 'src', 'common', 'base');
88
+ const commonGuardsDir = path.join(targetDir, 'src', 'common', 'guards');
89
+ const commonDecoratorsDir = path.join(targetDir, 'src', 'common', 'decorators');
88
90
 
89
91
  if (!(await fs.pathExists(commonBaseDir))) {
90
92
  const templateBaseDir = path.join(__dirname, '..', 'templates', 'base-crud', 'src', 'common', 'base');
@@ -93,6 +95,54 @@ async function ensureBaseArchitecture(targetDir) {
93
95
  console.log(chalk.green(' ✓ Scaffolded Base CRUD architecture at src/common/base'));
94
96
  }
95
97
  }
98
+
99
+ // Scaffold Guards if missing
100
+ await fs.ensureDir(commonGuardsDir);
101
+ const jwtGuardPath = path.join(commonGuardsDir, 'jwt-auth.guard.ts');
102
+ const authGuardPath = path.join(commonGuardsDir, 'auth.guard.ts');
103
+ const rolesGuardPath = path.join(commonGuardsDir, 'roles.guard.ts');
104
+
105
+ if (!(await fs.pathExists(jwtGuardPath)) && !(await fs.pathExists(authGuardPath))) {
106
+ const jwtGuardContent = `import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
107
+
108
+ @Injectable()
109
+ export class JwtAuthGuard implements CanActivate {
110
+ canActivate(context: ExecutionContext): boolean {
111
+ return true;
112
+ }
113
+ }
114
+ `;
115
+ await fs.writeFile(jwtGuardPath, jwtGuardContent, 'utf8');
116
+ console.log(chalk.green(' ✓ Scaffolded JwtAuthGuard at src/common/guards/jwt-auth.guard.ts'));
117
+ }
118
+
119
+ if (!(await fs.pathExists(rolesGuardPath))) {
120
+ const rolesGuardContent = `import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
121
+
122
+ @Injectable()
123
+ export class RolesGuard implements CanActivate {
124
+ canActivate(context: ExecutionContext): boolean {
125
+ return true;
126
+ }
127
+ }
128
+ `;
129
+ await fs.writeFile(rolesGuardPath, rolesGuardContent, 'utf8');
130
+ console.log(chalk.green(' ✓ Scaffolded RolesGuard at src/common/guards/roles.guard.ts'));
131
+ }
132
+
133
+ // Scaffold Decorators if missing
134
+ await fs.ensureDir(commonDecoratorsDir);
135
+ const rolesDecoratorPath = path.join(commonDecoratorsDir, 'roles.decorator.ts');
136
+
137
+ if (!(await fs.pathExists(rolesDecoratorPath))) {
138
+ const rolesDecoratorContent = `import { SetMetadata } from '@nestjs/common';
139
+
140
+ export const ROLES_KEY = 'roles';
141
+ export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
142
+ `;
143
+ await fs.writeFile(rolesDecoratorPath, rolesDecoratorContent, 'utf8');
144
+ console.log(chalk.green(' ✓ Scaffolded Roles decorator at src/common/decorators/roles.decorator.ts'));
145
+ }
96
146
  } catch (error) {
97
147
  console.warn(chalk.yellow(` ⚠️ Could not scaffold Base CRUD architecture: ${error.message}`));
98
148
  }
@@ -152,7 +202,7 @@ function getFieldDetails(fieldType) {
152
202
  /**
153
203
  * Interactive prompt for module options (Name, CRUD Mode, PK, Fields, Relations, Auth Guards)
154
204
  */
155
- async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma') {
205
+ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma', targetDir = process.cwd()) {
156
206
  let moduleName = providedModuleName;
157
207
 
158
208
  if (!moduleName) {
@@ -166,6 +216,30 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
166
216
  }
167
217
 
168
218
  const kebabName = toKebabCase(moduleName);
219
+ const srcDir = path.join(targetDir, 'src');
220
+ const moduleDir = (await fs.pathExists(srcDir))
221
+ ? path.join(srcDir, 'modules', kebabName)
222
+ : path.join(targetDir, 'modules', kebabName);
223
+
224
+ if (await fs.pathExists(moduleDir)) {
225
+ const relPath = path.relative(targetDir, moduleDir);
226
+ console.log(chalk.yellow(`\n⚠️ Module "${kebabName}" already exists at ${relPath}`));
227
+ console.log(chalk.gray(` - Use "speedrun-cli field ${kebabName}" (alias: f) to add or edit fields.`));
228
+ console.log(chalk.gray(` - Use "speedrun-cli config ${kebabName}" (alias: c) to configure guards & routes.\n`));
229
+
230
+ const { overwrite } = await inquirer.prompt([{
231
+ type: 'confirm',
232
+ name: 'overwrite',
233
+ message: `Do you still want to overwrite existing module "${kebabName}"?`,
234
+ default: false,
235
+ }]);
236
+
237
+ if (!overwrite) {
238
+ console.log(chalk.gray('Cancelled module generation. Existing module files preserved.\n'));
239
+ return null;
240
+ }
241
+ }
242
+
169
243
  const pascalName = toPascalCase(moduleName);
170
244
  const singularPascal = toSingularPascal(pascalName);
171
245
  const singularSnake = toSnakeCase(singularPascal);
@@ -1152,7 +1226,9 @@ async function generateModule(providedModuleName, targetDir = process.cwd(), spe
1152
1226
  // Detect ORM first so prompt choices match
1153
1227
  const orm = specifiedOrm || (await detectOrm(targetDir));
1154
1228
 
1155
- const options = await promptForModuleOptions(providedModuleName, orm);
1229
+ const options = await promptForModuleOptions(providedModuleName, orm, targetDir);
1230
+ if (!options) return false;
1231
+
1156
1232
  const kebabName = toKebabCase(options.moduleName);
1157
1233
  const pascalName = toPascalCase(options.moduleName);
1158
1234
  const camelName = toCamelCase(options.moduleName);
@@ -1526,6 +1602,11 @@ module.exports = {
1526
1602
  detectModulePrimaryKey,
1527
1603
  getOrmFieldChoices,
1528
1604
  toKebabCase,
1605
+ toCamelCase,
1606
+ toPascalCase,
1607
+ toSingularPascal,
1608
+ toSingularCamel,
1609
+ toSnakeCase,
1529
1610
  registerInAppModule,
1530
1611
  ensureBaseArchitecture,
1531
1612
  regenerateModuleComponents,
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Seed Generator for speedrun-cli
3
+ * Generates realistic dummy/seed data for a target CRUD module based on its DTOs / ORM Schema.
4
+ * @module seedGenerator
5
+ */
6
+
7
+ const inquirer = require('inquirer');
8
+ const fs = require('fs-extra');
9
+ const path = require('path');
10
+ const chalk = require('chalk');
11
+ const crypto = require('crypto');
12
+ const {
13
+ detectOrm,
14
+ detectModulePrimaryKey,
15
+ toKebabCase,
16
+ toPascalCase,
17
+ toSingularPascal,
18
+ toSingularCamel,
19
+ } = require('./moduleGenerator');
20
+ const { parseExistingFields } = require('./fieldManager');
21
+ const { detectPackageManager, getRunPrefix } = require('./utils');
22
+
23
+ /**
24
+ * Generates realistic mock values based on field name and field type.
25
+ */
26
+ function generateMockValue(fieldName, fieldType, index = 1) {
27
+ const lowerName = fieldName.toLowerCase();
28
+
29
+ if (lowerName.includes('email')) {
30
+ return `user${index}@example.com`;
31
+ }
32
+ if (lowerName.includes('phone') || lowerName.includes('mobile')) {
33
+ return `+1555010${(index % 100).toString().padStart(4, '0')}`;
34
+ }
35
+ if (lowerName.includes('name') || lowerName.includes('title')) {
36
+ return `Sample ${fieldName} ${index}`;
37
+ }
38
+ if (lowerName.includes('price') || lowerName.includes('amount') || lowerName.includes('cost') || lowerName.includes('total')) {
39
+ return Number((10 + index * 5.5).toFixed(2));
40
+ }
41
+ if (lowerName.includes('count') || lowerName.includes('quantity') || lowerName.includes('stock')) {
42
+ return 10 * index;
43
+ }
44
+ if (lowerName.includes('url') || lowerName.includes('image') || lowerName.includes('avatar')) {
45
+ return `https://example.com/assets/${lowerName}-${index}.jpg`;
46
+ }
47
+ if (lowerName.includes('description') || lowerName.includes('note') || lowerName.includes('remark') || lowerName.includes('comment')) {
48
+ return `This is a sample ${fieldName} content for item #${index}.`;
49
+ }
50
+
51
+ // Type fallbacks
52
+ const ft = (fieldType || '').toLowerCase();
53
+ if (['int', 'integer', 'number'].includes(ft)) {
54
+ return index * 10;
55
+ }
56
+ if (['float', 'decimal', 'numeric'].includes(ft)) {
57
+ return Number((9.99 + index).toFixed(2));
58
+ }
59
+ if (['boolean'].includes(ft)) {
60
+ return index % 2 === 0;
61
+ }
62
+ if (['datetime', 'date', 'timestamp'].includes(ft)) {
63
+ return new Date(Date.now() - index * 86400000).toISOString();
64
+ }
65
+ if (['json', 'object'].includes(ft)) {
66
+ return { key: `value_${index}` };
67
+ }
68
+ if (ft === 'array') {
69
+ return [`item_${index}_a`, `item_${index}_b`];
70
+ }
71
+
72
+ return `Sample ${fieldName} ${index}`;
73
+ }
74
+
75
+ /**
76
+ * Main Interactive Seed Generator Entry Point
77
+ */
78
+ async function generateSeed(providedModuleName, targetDir = process.cwd()) {
79
+ try {
80
+ let moduleName = providedModuleName;
81
+
82
+ if (!moduleName) {
83
+ const nameAnswer = await inquirer.prompt([{
84
+ type: 'input',
85
+ name: 'moduleName',
86
+ message: 'Which module do you want to generate seed data for? (e.g., orders, products)',
87
+ validate: (input) => (input && input.trim() ? true : 'Module name is required'),
88
+ }]);
89
+ moduleName = nameAnswer.moduleName.trim();
90
+ }
91
+
92
+ const kebabName = toKebabCase(moduleName);
93
+ const pascalName = toPascalCase(moduleName);
94
+ const singularPascal = toSingularPascal(pascalName);
95
+ const singularCamel = toSingularCamel(kebabName);
96
+
97
+ const srcDir = path.join(targetDir, 'src');
98
+ const moduleDir = (await fs.pathExists(srcDir))
99
+ ? path.join(srcDir, 'modules', kebabName)
100
+ : path.join(targetDir, 'modules', kebabName);
101
+
102
+ if (!(await fs.pathExists(moduleDir))) {
103
+ console.error(chalk.red(`\n❌ Module "${kebabName}" not found at ${moduleDir}`));
104
+ return false;
105
+ }
106
+
107
+ const orm = await detectOrm(targetDir);
108
+ const primaryKey = await detectModulePrimaryKey(moduleDir, kebabName);
109
+ const fields = await parseExistingFields(moduleDir, kebabName, orm);
110
+ const pm = detectPackageManager();
111
+ const runPrefix = getRunPrefix(pm);
112
+
113
+ console.log(chalk.cyan(`\n🌱 Generating seed data for module: ${chalk.bold(kebabName)} (Detected ORM: ${orm})`));
114
+
115
+ // 1. Prompt for count
116
+ const { countStr } = await inquirer.prompt([{
117
+ type: 'input',
118
+ name: 'countStr',
119
+ message: 'How many seed records do you want to generate?',
120
+ default: '10',
121
+ validate: (input) => {
122
+ const num = parseInt(input, 10);
123
+ return !isNaN(num) && num > 0 ? true : 'Please enter a positive integer';
124
+ },
125
+ }]);
126
+ const count = parseInt(countStr, 10);
127
+
128
+ // 2. Prompt for seed strategy
129
+ const { seedStrategy } = await inquirer.prompt([{
130
+ type: 'list',
131
+ name: 'seedStrategy',
132
+ message: 'Select target output format / seeding strategy:',
133
+ choices: [
134
+ { name: 'Prisma Seed Script (prisma/seeds/[module].seed.ts integration)', value: 'prisma' },
135
+ { name: 'TypeORM / Custom Script (src/database/seeds/[module].seed.ts)', value: 'typeorm' },
136
+ { name: 'Raw JSON Mock File (src/modules/[module]/mock-data.json)', value: 'json' },
137
+ ],
138
+ default: orm === 'prisma' ? 'prisma' : 'typeorm',
139
+ }]);
140
+
141
+ // 3. Generate Records
142
+ const records = [];
143
+ for (let i = 1; i <= count; i++) {
144
+ const uuidVal = crypto.randomUUID ? crypto.randomUUID() : `123e4567-e89b-12d3-a456-${(100000000000 + i).toString()}`;
145
+ const rec = {
146
+ [primaryKey]: uuidVal,
147
+ };
148
+
149
+ fields.forEach((f) => {
150
+ rec[f.name] = generateMockValue(f.name, f.type, i);
151
+ });
152
+
153
+ rec['status'] = 'ACTIVE';
154
+ records.push(rec);
155
+ }
156
+
157
+ // 4. Output according to selected strategy
158
+ if (seedStrategy === 'prisma') {
159
+ const prismaSeedsDir = path.join(targetDir, 'prisma', 'seeds');
160
+ await fs.ensureDir(prismaSeedsDir);
161
+ const moduleSeedPath = path.join(prismaSeedsDir, `${kebabName}.seed.ts`);
162
+
163
+ const seedScriptContent = `import { PrismaClient } from '@prisma/client';
164
+
165
+ export const ${singularCamel}SeedData = ${JSON.stringify(records, null, 2)};
166
+
167
+ export async function seed${pascalName}(prisma: PrismaClient) {
168
+ console.log('🌱 Seeding ${kebabName}...');
169
+ for (const item of ${singularCamel}SeedData) {
170
+ await (prisma as any).${singularCamel}.upsert({
171
+ where: { ${primaryKey}: item.${primaryKey} },
172
+ update: {},
173
+ create: item,
174
+ });
175
+ }
176
+ console.log(' ✓ Seeded ${count} ${kebabName} records');
177
+ }
178
+ `;
179
+ await fs.writeFile(moduleSeedPath, seedScriptContent, 'utf8');
180
+ console.log(chalk.green(`\n⚡ Generated Prisma seed script at: ${path.relative(targetDir, moduleSeedPath)}`));
181
+
182
+ // Check master prisma/seed.ts
183
+ const masterSeedPath = path.join(targetDir, 'prisma', 'seed.ts');
184
+ if (await fs.pathExists(masterSeedPath)) {
185
+ let masterContent = await fs.readFile(masterSeedPath, 'utf8');
186
+ const importLine = `import { seed${pascalName} } from './seeds/${kebabName}.seed';`;
187
+ const callLine = `await seed${pascalName}(prisma);`;
188
+
189
+ if (!masterContent.includes(importLine)) {
190
+ masterContent = `${importLine}\n` + masterContent;
191
+ }
192
+
193
+ if (!masterContent.includes(callLine)) {
194
+ masterContent = masterContent.replace(/async function main\(\) \{/, `async function main() {\n ${callLine}`);
195
+ }
196
+
197
+ await fs.writeFile(masterSeedPath, masterContent, 'utf8');
198
+ console.log(chalk.green(`✨ Integrated seed${pascalName} into prisma/seed.ts`));
199
+ }
200
+
201
+ console.log(chalk.cyan(`\n💡 To execute this seed script, run:`));
202
+ console.log(chalk.bold(` ${runPrefix} prisma:seed (or npx prisma db seed)\n`));
203
+ } else if (seedStrategy === 'typeorm') {
204
+ const seedsDir = path.join(targetDir, 'src', 'database', 'seeds');
205
+ await fs.ensureDir(seedsDir);
206
+ const customSeedPath = path.join(seedsDir, `${kebabName}.seed.ts`);
207
+
208
+ const customSeedContent = `/**
209
+ * Seed data for module "${kebabName}"
210
+ */
211
+ export const ${singularCamel}SeedData = ${JSON.stringify(records, null, 2)};
212
+
213
+ export async function seed${pascalName}() {
214
+ console.log('🌱 Seeding ${kebabName} with ${count} records...');
215
+ return ${singularCamel}SeedData;
216
+ }
217
+ `;
218
+ await fs.writeFile(customSeedPath, customSeedContent, 'utf8');
219
+ console.log(chalk.green(`\n⚡ Generated seed script at: ${path.relative(targetDir, customSeedPath)}`));
220
+ console.log(chalk.cyan(`\n💡 To execute custom seeds, run:`));
221
+ console.log(chalk.bold(` ${runPrefix} db:seed (or ${runPrefix} seed)\n`));
222
+ } else if (seedStrategy === 'json') {
223
+ const jsonMockPath = path.join(moduleDir, 'mock-data.json');
224
+ await fs.writeFile(jsonMockPath, JSON.stringify(records, null, 2), 'utf8');
225
+ console.log(chalk.green(`\n⚡ Generated raw JSON mock data file at: ${path.relative(targetDir, jsonMockPath)}`));
226
+ console.log(chalk.gray(` Contains ${count} mock records.\n`));
227
+ }
228
+
229
+ return true;
230
+ } catch (error) {
231
+ console.error(chalk.red('\n❌ Seed generation failed:'), error.message);
232
+ return false;
233
+ }
234
+ }
235
+
236
+ module.exports = { generateSeed, generateMockValue };
@@ -18,3 +18,4 @@ export {
18
18
  PaginatedResponseDto,
19
19
  PaginatedResponseSchema,
20
20
  } from './swagger/paginated.dto';
21
+