speedrun-cli 2.8.1 → 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 +15 -0
- package/README.md +8 -0
- package/bin/cli.js +16 -0
- package/package.json +1 -1
- package/src/fieldManager.js +1 -1
- package/src/index.js +2 -0
- package/src/moduleGenerator.js +33 -2
- package/src/seedGenerator.js +236 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,21 @@ 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
|
+
|
|
8
23
|
## [2.8.1] - 2026-08-22
|
|
9
24
|
|
|
10
25
|
### Fixed
|
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
package/src/fieldManager.js
CHANGED
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
|
};
|
package/src/moduleGenerator.js
CHANGED
|
@@ -202,7 +202,7 @@ function getFieldDetails(fieldType) {
|
|
|
202
202
|
/**
|
|
203
203
|
* Interactive prompt for module options (Name, CRUD Mode, PK, Fields, Relations, Auth Guards)
|
|
204
204
|
*/
|
|
205
|
-
async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma') {
|
|
205
|
+
async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma', targetDir = process.cwd()) {
|
|
206
206
|
let moduleName = providedModuleName;
|
|
207
207
|
|
|
208
208
|
if (!moduleName) {
|
|
@@ -216,6 +216,30 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
|
|
|
216
216
|
}
|
|
217
217
|
|
|
218
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
|
+
|
|
219
243
|
const pascalName = toPascalCase(moduleName);
|
|
220
244
|
const singularPascal = toSingularPascal(pascalName);
|
|
221
245
|
const singularSnake = toSnakeCase(singularPascal);
|
|
@@ -1202,7 +1226,9 @@ async function generateModule(providedModuleName, targetDir = process.cwd(), spe
|
|
|
1202
1226
|
// Detect ORM first so prompt choices match
|
|
1203
1227
|
const orm = specifiedOrm || (await detectOrm(targetDir));
|
|
1204
1228
|
|
|
1205
|
-
const options = await promptForModuleOptions(providedModuleName, orm);
|
|
1229
|
+
const options = await promptForModuleOptions(providedModuleName, orm, targetDir);
|
|
1230
|
+
if (!options) return false;
|
|
1231
|
+
|
|
1206
1232
|
const kebabName = toKebabCase(options.moduleName);
|
|
1207
1233
|
const pascalName = toPascalCase(options.moduleName);
|
|
1208
1234
|
const camelName = toCamelCase(options.moduleName);
|
|
@@ -1576,6 +1602,11 @@ module.exports = {
|
|
|
1576
1602
|
detectModulePrimaryKey,
|
|
1577
1603
|
getOrmFieldChoices,
|
|
1578
1604
|
toKebabCase,
|
|
1605
|
+
toCamelCase,
|
|
1606
|
+
toPascalCase,
|
|
1607
|
+
toSingularPascal,
|
|
1608
|
+
toSingularCamel,
|
|
1609
|
+
toSnakeCase,
|
|
1579
1610
|
registerInAppModule,
|
|
1580
1611
|
ensureBaseArchitecture,
|
|
1581
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 };
|