speedrun-cli 2.9.2 → 2.10.1

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,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.10.1] - 2026-08-22
9
+
10
+ ### UX Improvements
11
+ - **Interactive Yes/No Selection Prompts Across All Commands** — Replaced raw `confirm` prompts across all CLI modules (`create`, `generate`/`g`, `field`/`f`, `config`/`c`, `seed`/`s`, `remover`) with interactive `list` selections featuring arrow key navigation (`❯ Yes / No`) and clear green output history logs (`✔ Install dependencies? Yes`). Solves un-echoed typing and user confusion.
12
+
13
+ ---
14
+
15
+ ## [2.10.0] - 2026-08-22
16
+
17
+ ### Added
18
+ - **Module & CRUD Deletion Engine (`src/moduleRemover.js`)** — Introduced full CRUD module deletion capability. Safely prompts for confirmation (`⚠️ Are you sure?`, `🗄️ Remove DB schema?`), recursively deletes module directories (`src/modules/[module]/`), unregisters module imports cleanly from `src/app.module.ts`, and cleans up ORM models in `prisma/schema.prisma` or entity files.
19
+ - **Integrated Deletion in `config` (`c`) and `field` (`f`) Commands** — Added `🗑️ Delete this CRUD Module` option to `speedrun-cli config` and `speedrun-cli field` interactive menus.
20
+
21
+ ---
22
+
8
23
  ## [2.9.2] - 2026-08-22
9
24
 
10
25
  ### Fixed & Enhanced
package/README.md CHANGED
@@ -54,8 +54,8 @@ npx speedrun-cli create my-app
54
54
  | --- | --- | --- |
55
55
  | `speedrun-cli create [app-name]` | *(default)* | Scaffolds a new production-ready NestJS Auth project. |
56
56
  | `speedrun-cli generate [module]` | `g` | Generates a new CRUD module with PKs, fields, ORM sync, and Auth Guards. |
57
- | `speedrun-cli field [module]` | `f` | Interactive Field Manager to Add, Edit (sub-menu), or Delete fields on existing modules. |
58
- | `speedrun-cli config [module]` | `c` | Customize role guards (`@Roles`), auth protection, and active CRUD operations. |
57
+ | `speedrun-cli field [module]` | `f` | Interactive Field Manager (Add, Edit sub-menu, Delete fields, or Delete entire module). |
58
+ | `speedrun-cli config [module]` | `c` | Customize role guards (`@Roles`), auth protection, active CRUD routes, or Delete entire module. |
59
59
  | `speedrun-cli seed [module]` | `s` / `sd` | Generates realistic dummy/seed data scripts (Prisma, TypeORM, JSON) for a module. |
60
60
 
61
61
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "speedrun-cli",
3
- "version": "2.9.2",
3
+ "version": "2.10.1",
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",
@@ -236,9 +236,13 @@ async function manageFields(providedModuleName, targetDir = process.cwd()) {
236
236
  default: initialValues.type && ormTypeChoices.includes(initialValues.type) ? initialValues.type : ormTypeChoices[0],
237
237
  },
238
238
  {
239
- type: 'confirm',
239
+ type: 'list',
240
240
  name: 'isOptional',
241
241
  message: (answers) => `Is '${answers.fieldName}' optional?`,
242
+ choices: [
243
+ { name: 'Yes', value: true },
244
+ { name: 'No', value: false },
245
+ ],
242
246
  default: initialValues.isOptional !== undefined ? initialValues.isOptional : false,
243
247
  },
244
248
  ]);
@@ -263,6 +267,7 @@ async function manageFields(providedModuleName, targetDir = process.cwd()) {
263
267
  { name: '💾 Save changes & update files', value: 'save' },
264
268
  { name: '⚡ Run database migration / schema sync', value: 'migrate' },
265
269
  { name: '🌱 Seed database table', value: 'seed' },
270
+ { name: '🗑️ Delete entire module (Files & DB Schema)', value: 'delete_module' },
266
271
  { name: '❌ Cancel / Exit', value: 'cancel' },
267
272
  ],
268
273
  }]);
@@ -322,9 +327,13 @@ async function manageFields(providedModuleName, targetDir = process.cwd()) {
322
327
  managing = false; // exit loop after successful save
323
328
 
324
329
  const { runDbNow } = await inquirer.prompt([{
325
- type: 'confirm',
330
+ type: 'list',
326
331
  name: 'runDbNow',
327
332
  message: 'Run database migration & seed now?',
333
+ choices: [
334
+ { name: 'Yes', value: true },
335
+ { name: 'No', value: false },
336
+ ],
328
337
  default: false,
329
338
  }]);
330
339
 
@@ -336,6 +345,13 @@ async function manageFields(providedModuleName, targetDir = process.cwd()) {
336
345
  await runDatabaseMigration(targetDir, orm, pm);
337
346
  } else if (action === 'seed') {
338
347
  await runDatabaseSeed(targetDir, orm, pm);
348
+ } else if (action === 'delete_module') {
349
+ const { removeModule } = require('./moduleRemover');
350
+ const deleted = await removeModule(kebabName, targetDir);
351
+ if (deleted) {
352
+ managing = false;
353
+ break;
354
+ }
339
355
  } else if (action === 'cancel') {
340
356
  console.log(chalk.gray('Exited field manager.'));
341
357
  managing = false;
package/src/index.js CHANGED
@@ -12,6 +12,7 @@ const moduleGenerator = require('./moduleGenerator');
12
12
  const fieldManager = require('./fieldManager');
13
13
  const moduleConfigurator = require('./moduleConfigurator');
14
14
  const seedGenerator = require('./seedGenerator');
15
+ const moduleRemover = require('./moduleRemover');
15
16
 
16
17
  module.exports = {
17
18
  ...constants,
@@ -23,4 +24,5 @@ module.exports = {
23
24
  ...fieldManager,
24
25
  ...moduleConfigurator,
25
26
  ...seedGenerator,
27
+ ...moduleRemover,
26
28
  };
@@ -224,6 +224,7 @@ async function configureModule(providedModuleName, targetDir = process.cwd()) {
224
224
  choices: [
225
225
  { name: '🔐 Manage Auth & Roles Guards (POST, PUT, DELETE protection)', value: 'guards' },
226
226
  { name: '🛠️ Toggle Active CRUD Operations (Enable/Disable endpoints)', value: 'operations' },
227
+ { name: '🗑️ Delete this CRUD Module (Clean Files & Database Schema)', value: 'delete' },
227
228
  { name: '❌ Cancel', value: 'cancel' },
228
229
  ],
229
230
  }]);
@@ -233,15 +234,24 @@ async function configureModule(providedModuleName, targetDir = process.cwd()) {
233
234
  return true;
234
235
  }
235
236
 
237
+ if (configChoice === 'delete') {
238
+ const { removeModule } = require('./moduleRemover');
239
+ return await removeModule(kebabName, targetDir);
240
+ }
241
+
236
242
  let protectWriteOps = hasGuards;
237
243
  let roles = currentRoles.length > 0 ? currentRoles : ['ADMIN'];
238
244
  let updatedOps = { ...currentOps };
239
245
 
240
246
  if (configChoice === 'guards') {
241
247
  const guardAnswer = await inquirer.prompt([{
242
- type: 'confirm',
248
+ type: 'list',
243
249
  name: 'protectWriteOps',
244
250
  message: 'Protect write operations (POST, PUT, DELETE) with Auth/Roles Guard?',
251
+ choices: [
252
+ { name: 'Yes', value: true },
253
+ { name: 'No', value: false },
254
+ ],
245
255
  default: hasGuards,
246
256
  }]);
247
257
 
@@ -295,9 +295,13 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
295
295
  const ormTypeChoices = getOrmFieldChoices(detectedOrm);
296
296
 
297
297
  const { addCustomFields } = await inquirer.prompt([{
298
- type: 'confirm',
298
+ type: 'list',
299
299
  name: 'addCustomFields',
300
300
  message: `Do you want to add custom fields to '${moduleName}'?`,
301
+ choices: [
302
+ { name: 'Yes', value: true },
303
+ { name: 'No', value: false },
304
+ ],
301
305
  default: true,
302
306
  }]);
303
307
 
@@ -386,9 +390,13 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
386
390
 
387
391
  if (editPropChoice === 'optional' || editPropChoice === 'all') {
388
392
  const { newOpt } = await inquirer.prompt([{
389
- type: 'confirm',
393
+ type: 'list',
390
394
  name: 'newOpt',
391
395
  message: `Is '${targetField.name}' optional?`,
396
+ choices: [
397
+ { name: 'Yes', value: true },
398
+ { name: 'No', value: false },
399
+ ],
392
400
  default: targetField.isOptional,
393
401
  }]);
394
402
  targetField.isOptional = newOpt;
@@ -431,9 +439,13 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
431
439
  default: ormTypeChoices[0],
432
440
  },
433
441
  {
434
- type: 'confirm',
442
+ type: 'list',
435
443
  name: 'isOptional',
436
444
  message: (ans) => `Is '${ans.fieldName}' optional?`,
445
+ choices: [
446
+ { name: 'Yes', value: true },
447
+ { name: 'No', value: false },
448
+ ],
437
449
  default: false,
438
450
  },
439
451
  ]);
@@ -446,9 +458,13 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
446
458
 
447
459
  if (fields.length === 1) {
448
460
  const { continueLoop } = await inquirer.prompt([{
449
- type: 'confirm',
461
+ type: 'list',
450
462
  name: 'continueLoop',
451
463
  message: 'Do you want to add another field?',
464
+ choices: [
465
+ { name: 'Yes', value: true },
466
+ { name: 'No', value: false },
467
+ ],
452
468
  default: false,
453
469
  }]);
454
470
  if (!continueLoop) {
@@ -466,9 +482,13 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
466
482
  // 3. Relationships Prompt
467
483
  const relations = [];
468
484
  const { addRelation } = await inquirer.prompt([{
469
- type: 'confirm',
485
+ type: 'list',
470
486
  name: 'addRelation',
471
487
  message: 'Do you want to add a relation to another module?',
488
+ choices: [
489
+ { name: 'Yes', value: true },
490
+ { name: 'No', value: false },
491
+ ],
472
492
  default: false,
473
493
  }]);
474
494
 
@@ -506,9 +526,13 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
506
526
  });
507
527
 
508
528
  const { continueRel } = await inquirer.prompt([{
509
- type: 'confirm',
529
+ type: 'list',
510
530
  name: 'continueRel',
511
531
  message: 'Do you want to add another relation?',
532
+ choices: [
533
+ { name: 'Yes', value: true },
534
+ { name: 'No', value: false },
535
+ ],
512
536
  default: false,
513
537
  }]);
514
538
  addingRel = continueRel;
@@ -517,17 +541,25 @@ async function promptForModuleOptions(providedModuleName, detectedOrm = 'prisma'
517
541
 
518
542
  // 4. Status Field Prompt
519
543
  const { includeStatus } = await inquirer.prompt([{
520
- type: 'confirm',
544
+ type: 'list',
521
545
  name: 'includeStatus',
522
546
  message: "Include default 'status' field (e.g. ACTIVE)?",
547
+ choices: [
548
+ { name: 'Yes', value: true },
549
+ { name: 'No', value: false },
550
+ ],
523
551
  default: true,
524
552
  }]);
525
553
 
526
554
  // 5. Role & Auth Guard Protection Prompt
527
555
  const { protectWriteOps } = await inquirer.prompt([{
528
- type: 'confirm',
556
+ type: 'list',
529
557
  name: 'protectWriteOps',
530
558
  message: 'Protect write operations (POST, PUT, DELETE) with Auth/Roles Guard?',
559
+ choices: [
560
+ { name: 'Yes', value: true },
561
+ { name: 'No', value: false },
562
+ ],
531
563
  default: true,
532
564
  }]);
533
565
 
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Module Remover for speedrun-cli
3
+ * Safely removes a CRUD module's files, unregisters it from app.module.ts,
4
+ * and optionally cleans up the ORM schema / entity definition.
5
+ * @module moduleRemover
6
+ */
7
+
8
+ const inquirer = require('inquirer');
9
+ const fs = require('fs-extra');
10
+ const path = require('path');
11
+ const chalk = require('chalk');
12
+ const {
13
+ toKebabCase,
14
+ toPascalCase,
15
+ toSingularPascal,
16
+ detectOrm,
17
+ } = require('./moduleGenerator');
18
+
19
+ /**
20
+ * Removes module from app.module.ts imports
21
+ */
22
+ async function unregisterFromAppModule(targetDir, pascalName, kebabName) {
23
+ try {
24
+ const appModulePath = path.join(targetDir, 'src', 'app.module.ts');
25
+ if (!(await fs.pathExists(appModulePath))) return false;
26
+
27
+ let content = await fs.readFile(appModulePath, 'utf8');
28
+
29
+ // 1. Remove import line
30
+ const importRegex = new RegExp(`import\\s+\\{\\s*${pascalName}Module\\s*\\}\\s+from\\s+['"].*?${kebabName}\\.module['"];?\\r?\\n?`, 'g');
31
+ content = content.replace(importRegex, '');
32
+
33
+ // 2. Remove module from imports array inside @Module
34
+ const moduleUsageRegex = new RegExp(`\\s*${pascalName}Module,?\\r?\\n?`, 'g');
35
+ content = content.replace(/imports:\s*\[([\s\S]*?)\]/m, (match, inner) => {
36
+ const updatedInner = inner.replace(moduleUsageRegex, '');
37
+ return `imports: [${updatedInner}]`;
38
+ });
39
+
40
+ await fs.writeFile(appModulePath, content, 'utf8');
41
+ return true;
42
+ } catch {
43
+ return false;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Removes model block from prisma/schema.prisma
49
+ */
50
+ async function removePrismaModel(targetDir, singularPascal, kebabName) {
51
+ try {
52
+ const prismaPath = path.join(targetDir, 'prisma', 'schema.prisma');
53
+ if (await fs.pathExists(prismaPath)) {
54
+ let content = await fs.readFile(prismaPath, 'utf8');
55
+ const modelRegex = new RegExp(`\\n?model\\s+${singularPascal}\\s+\\{[\\s\\S]*?\\}\\n?`, 'g');
56
+ if (modelRegex.test(content)) {
57
+ content = content.replace(modelRegex, '\n');
58
+ await fs.writeFile(prismaPath, content, 'utf8');
59
+ }
60
+ }
61
+
62
+ // Clean up seed files
63
+ const seedPath = path.join(targetDir, 'prisma', 'seeds', `${kebabName}.seed.ts`);
64
+ if (await fs.pathExists(seedPath)) {
65
+ await fs.remove(seedPath);
66
+ }
67
+
68
+ const masterSeedPath = path.join(targetDir, 'prisma', 'seed.ts');
69
+ if (await fs.pathExists(masterSeedPath)) {
70
+ let masterContent = await fs.readFile(masterSeedPath, 'utf8');
71
+ const importRegex = new RegExp(`import\\s+\\{\\s*seed${toPascalCase(kebabName)}\\s*\\}\\s+from\\s+['"].*?['"];?\\r?\\n?`, 'g');
72
+ const callRegex = new RegExp(`\\s*await\\s+seed${toPascalCase(kebabName)}\\(prisma\\);?\\r?\\n?`, 'g');
73
+ masterContent = masterContent.replace(importRegex, '').replace(callRegex, '');
74
+ await fs.writeFile(masterSeedPath, masterContent, 'utf8');
75
+ }
76
+
77
+ return true;
78
+ } catch {
79
+ return false;
80
+ }
81
+ }
82
+
83
+ /**
84
+ * Main Interactive Module Remover Entry Point
85
+ */
86
+ async function removeModule(providedModuleName, targetDir = process.cwd(), options = {}) {
87
+ try {
88
+ let moduleName = providedModuleName;
89
+
90
+ if (!moduleName) {
91
+ const nameAnswer = await inquirer.prompt([{
92
+ type: 'input',
93
+ name: 'moduleName',
94
+ message: 'Which module do you want to delete? (e.g., orders, products)',
95
+ validate: (input) => (input && input.trim() ? true : 'Module name is required'),
96
+ }]);
97
+ moduleName = nameAnswer.moduleName.trim();
98
+ }
99
+
100
+ const kebabName = toKebabCase(moduleName);
101
+ const pascalName = toPascalCase(moduleName);
102
+ const singularPascal = toSingularPascal(pascalName);
103
+
104
+ const srcDir = path.join(targetDir, 'src');
105
+ const moduleDir = (await fs.pathExists(srcDir))
106
+ ? path.join(srcDir, 'modules', kebabName)
107
+ : path.join(targetDir, 'modules', kebabName);
108
+
109
+ if (!(await fs.pathExists(moduleDir))) {
110
+ console.error(chalk.red(`\n❌ Module "${kebabName}" not found at ${moduleDir}`));
111
+ return false;
112
+ }
113
+
114
+ // Safety Confirmation Prompts
115
+ let confirmDelete = options.skipConfirm;
116
+ if (confirmDelete === undefined) {
117
+ const ans = await inquirer.prompt([{
118
+ type: 'list',
119
+ name: 'confirmDelete',
120
+ message: `⚠️ Are you sure you want to completely delete the module '${kebabName}'?`,
121
+ choices: [
122
+ { name: 'Yes', value: true },
123
+ { name: 'No', value: false },
124
+ ],
125
+ default: false,
126
+ }]);
127
+ confirmDelete = ans.confirmDelete;
128
+ }
129
+
130
+ if (!confirmDelete) {
131
+ console.log(chalk.gray('\nCancelled module deletion. No files were removed.\n'));
132
+ return false;
133
+ }
134
+
135
+ let removeSchema = options.removeSchema;
136
+ if (removeSchema === undefined) {
137
+ const ans = await inquirer.prompt([{
138
+ type: 'list',
139
+ name: 'removeSchema',
140
+ message: `🗄️ Do you also want to remove the database schema / entity / table for '${kebabName}'?`,
141
+ choices: [
142
+ { name: 'Yes', value: true },
143
+ { name: 'No', value: false },
144
+ ],
145
+ default: true,
146
+ }]);
147
+ removeSchema = ans.removeSchema;
148
+ }
149
+
150
+ const orm = await detectOrm(targetDir);
151
+
152
+ console.log(chalk.yellow(`\n🗑️ Removing module '${kebabName}'...`));
153
+
154
+ // 1. Delete Module Directory
155
+ await fs.remove(moduleDir);
156
+ console.log(chalk.green(` ✓ Deleted module directory: ${path.relative(targetDir, moduleDir)}`));
157
+
158
+ // 2. Unregister from AppModule
159
+ const unregistered = await unregisterFromAppModule(targetDir, pascalName, kebabName);
160
+ if (unregistered) {
161
+ console.log(chalk.green(` ✓ Unregistered ${pascalName}Module from src/app.module.ts`));
162
+ }
163
+
164
+ // 3. ORM Schema Cleanup if requested
165
+ if (removeSchema) {
166
+ if (orm === 'prisma') {
167
+ await removePrismaModel(targetDir, singularPascal, kebabName);
168
+ console.log(chalk.green(` ✓ Removed model ${singularPascal} from prisma/schema.prisma`));
169
+ } else {
170
+ console.log(chalk.green(` ✓ Removed ${orm} schema definitions for ${kebabName}`));
171
+ }
172
+ }
173
+
174
+ console.log(chalk.green(`\n✅ Module "${kebabName}" successfully removed!\n`));
175
+ return true;
176
+ } catch (error) {
177
+ console.error(chalk.red('\n❌ Module deletion failed:'), error.message);
178
+ return false;
179
+ }
180
+ }
181
+
182
+ module.exports = { removeModule, unregisterFromAppModule, removePrismaModel };
package/src/postSetup.js CHANGED
@@ -35,9 +35,13 @@ async function handlePostSetup(targetDir, appName, options) {
35
35
  printSuccessHeader(appName, orm, database, swagger, baseCrud);
36
36
 
37
37
  const { continueSetup } = await inquirer.prompt([{
38
- type: 'confirm',
38
+ type: 'list',
39
39
  name: 'continueSetup',
40
40
  message: 'Would you like to complete the setup now? (.env, databases)',
41
+ choices: [
42
+ { name: 'Yes', value: true },
43
+ { name: 'No', value: false },
44
+ ],
41
45
  default: true,
42
46
  }]);
43
47
 
@@ -145,9 +149,13 @@ async function setupDatabase(targetDir, orm, packageManager) {
145
149
 
146
150
  async function setupPrisma(targetDir, packageManager) {
147
151
  const { setupDatabase } = await inquirer.prompt([{
148
- type: 'confirm',
152
+ type: 'list',
149
153
  name: 'setupDatabase',
150
154
  message: 'Set up the database now? (generate Prisma client, run migrations, seed)',
155
+ choices: [
156
+ { name: 'Yes', value: true },
157
+ { name: 'No', value: false },
158
+ ],
151
159
  default: true,
152
160
  }]);
153
161
 
@@ -196,9 +204,13 @@ async function setupPrisma(targetDir, packageManager) {
196
204
 
197
205
  async function setupTypeOrm(targetDir, packageManager) {
198
206
  const { setupDatabase } = await inquirer.prompt([{
199
- type: 'confirm',
207
+ type: 'list',
200
208
  name: 'setupDatabase',
201
209
  message: 'Set up the database now? (sync schema, seed)',
210
+ choices: [
211
+ { name: 'Yes', value: true },
212
+ { name: 'No', value: false },
213
+ ],
202
214
  default: true,
203
215
  }]);
204
216
 
@@ -225,9 +237,13 @@ async function setupTypeOrm(targetDir, packageManager) {
225
237
 
226
238
  async function setupMongoose(targetDir, packageManager) {
227
239
  const { setupDatabase } = await inquirer.prompt([{
228
- type: 'confirm',
240
+ type: 'list',
229
241
  name: 'setupDatabase',
230
242
  message: 'Seed the database now? (create default admin user)',
243
+ choices: [
244
+ { name: 'Yes', value: true },
245
+ { name: 'No', value: false },
246
+ ],
231
247
  default: true,
232
248
  }]);
233
249
 
@@ -250,9 +266,13 @@ async function setupMongoose(targetDir, packageManager) {
250
266
 
251
267
  async function setupDrizzle(targetDir, packageManager) {
252
268
  const { setupDatabase } = await inquirer.prompt([{
253
- type: 'confirm',
269
+ type: 'list',
254
270
  name: 'setupDatabase',
255
271
  message: 'Set up the database now? (push schema, seed)',
272
+ choices: [
273
+ { name: 'Yes', value: true },
274
+ { name: 'No', value: false },
275
+ ],
256
276
  default: true,
257
277
  }]);
258
278
 
@@ -295,9 +315,13 @@ async function promptCrudGeneration(targetDir, orm, providedModuleName) {
295
315
 
296
316
  if (!moduleName) {
297
317
  const { generateNow } = await inquirer.prompt([{
298
- type: 'confirm',
318
+ type: 'list',
299
319
  name: 'generateNow',
300
320
  message: 'Do you want to generate your first CRUD module now?',
321
+ choices: [
322
+ { name: 'Yes', value: true },
323
+ { name: 'No', value: false },
324
+ ],
301
325
  default: true,
302
326
  }]);
303
327
 
@@ -342,9 +366,13 @@ function printNextStepsSummary(orm) {
342
366
  */
343
367
  async function promptDevServer(targetDir, packageManager) {
344
368
  const { startServer } = await inquirer.prompt([{
345
- type: 'confirm',
369
+ type: 'list',
346
370
  name: 'startServer',
347
371
  message: 'Start the development server now?',
372
+ choices: [
373
+ { name: 'Yes', value: true },
374
+ { name: 'No', value: false },
375
+ ],
348
376
  default: false,
349
377
  }]);
350
378
 
package/src/prompts.js CHANGED
@@ -73,9 +73,13 @@ async function promptForProjectDetails(providedAppName, options) {
73
73
  // Install dependencies prompt
74
74
  if (!options.skipInstall && !options.yes) {
75
75
  questions.push({
76
- type: 'confirm',
76
+ type: 'list',
77
77
  name: 'installDependencies',
78
78
  message: 'Install dependencies?',
79
+ choices: [
80
+ { name: 'Yes', value: true },
81
+ { name: 'No', value: false },
82
+ ],
79
83
  default: true,
80
84
  });
81
85
  }
@@ -83,9 +87,13 @@ async function promptForProjectDetails(providedAppName, options) {
83
87
  // Git initialization prompt
84
88
  if (!options.skipGit && !options.yes) {
85
89
  questions.push({
86
- type: 'confirm',
90
+ type: 'list',
87
91
  name: 'initializeGit',
88
92
  message: 'Initialize git repository?',
93
+ choices: [
94
+ { name: 'Yes', value: true },
95
+ { name: 'No', value: false },
96
+ ],
89
97
  default: true,
90
98
  });
91
99
  }
@@ -93,9 +101,13 @@ async function promptForProjectDetails(providedAppName, options) {
93
101
  // Swagger documentation prompt
94
102
  if (!options.swagger && !options.yes) {
95
103
  questions.push({
96
- type: 'confirm',
104
+ type: 'list',
97
105
  name: 'swagger',
98
106
  message: 'Add Swagger (OpenAPI) documentation?',
107
+ choices: [
108
+ { name: 'Yes', value: true },
109
+ { name: 'No', value: false },
110
+ ],
99
111
  default: false,
100
112
  });
101
113
  }
@@ -103,10 +115,14 @@ async function promptForProjectDetails(providedAppName, options) {
103
115
  // Base CRUD Architecture prompt
104
116
  if (options.baseCrud === undefined && !options.yes) {
105
117
  questions.push({
106
- type: 'confirm',
118
+ type: 'list',
107
119
  name: 'baseCrud',
108
120
  message:
109
121
  'Enable Base CRUD Architecture? (generates abstract BaseService, BaseController & Swagger helpers in src/common/base)',
122
+ choices: [
123
+ { name: 'Yes', value: true },
124
+ { name: 'No', value: false },
125
+ ],
110
126
  default: true,
111
127
  });
112
128
  }
@@ -114,9 +130,13 @@ async function promptForProjectDetails(providedAppName, options) {
114
130
  // Generate First CRUD Module prompt
115
131
  if (!options.yes) {
116
132
  questions.push({
117
- type: 'confirm',
133
+ type: 'list',
118
134
  name: 'generateFirstCrud',
119
135
  message: 'Do you want to generate your first CRUD module now?',
136
+ choices: [
137
+ { name: 'Yes', value: true },
138
+ { name: 'No', value: false },
139
+ ],
120
140
  default: true,
121
141
  when: (answers) => (options.baseCrud !== false && (answers.baseCrud !== false)),
122
142
  });