@manulz/nest-tools 1.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.
@@ -0,0 +1,546 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli/index.ts
4
+ import { Command } from "commander";
5
+
6
+ // src/core/runner/command-runner.ts
7
+ import { exec } from "child_process";
8
+ import { promisify } from "util";
9
+
10
+ // src/utils/logger.ts
11
+ import pc from "picocolors";
12
+ var logger = {
13
+ info: (msg) => console.log(pc.cyan("\u2139 ") + msg),
14
+ success: (msg) => console.log(pc.green("\u2714 ") + pc.bold(msg)),
15
+ warn: (msg) => console.log(pc.yellow("\u26A0 ") + msg),
16
+ error: (msg) => console.error(pc.red("\u2716 ") + pc.bold(msg)),
17
+ step: (step, detail) => {
18
+ console.log(pc.blue("\u25B6 ") + pc.bold(step) + (detail ? pc.dim(` (${detail})`) : ""));
19
+ }
20
+ };
21
+
22
+ // src/core/runner/command-runner.ts
23
+ var execAsync = promisify(exec);
24
+ async function runCommand(command, options = {}) {
25
+ const { cwd = process.cwd(), dryRun = false, silent = false } = options;
26
+ if (dryRun) {
27
+ logger.info(`[dry-run] Would execute: ${command}`);
28
+ return { stdout: "", stderr: "" };
29
+ }
30
+ if (!silent) {
31
+ logger.step(command);
32
+ }
33
+ try {
34
+ const result = await execAsync(command, { cwd });
35
+ return result;
36
+ } catch (error) {
37
+ const message = error.stderr || error.message || "Command failed";
38
+ throw new Error(`Failed to execute: "${command}"
39
+ ${message}`);
40
+ }
41
+ }
42
+
43
+ // src/core/config/index.ts
44
+ import fs from "fs/promises";
45
+ import path from "path";
46
+ var DEFAULT_CONFIG = {
47
+ spec: false,
48
+ flat: false,
49
+ architecture: "standard",
50
+ packageManager: "npm"
51
+ };
52
+ var CONFIG_FILENAMES = ["nest-tools.json", ".nesttoolsrc", ".nesttoolsrc.json"];
53
+ async function loadConfig(cwd = process.cwd()) {
54
+ for (const filename of CONFIG_FILENAMES) {
55
+ const configPath = path.join(cwd, filename);
56
+ try {
57
+ const data = await fs.readFile(configPath, "utf-8");
58
+ const parsed = JSON.parse(data);
59
+ return { ...DEFAULT_CONFIG, ...parsed };
60
+ } catch {
61
+ }
62
+ }
63
+ return DEFAULT_CONFIG;
64
+ }
65
+ async function createDefaultConfig(cwd = process.cwd()) {
66
+ const targetPath = path.join(cwd, "nest-tools.json");
67
+ const content = JSON.stringify(DEFAULT_CONFIG, null, 2) + "\n";
68
+ await fs.writeFile(targetPath, content, "utf-8");
69
+ return targetPath;
70
+ }
71
+
72
+ // src/utils/strings.ts
73
+ function toKebabCase(str) {
74
+ return str.replace(/([a-z])([A-Z])/g, "$1-$2").replace(/[\s_]+/g, "-").toLowerCase();
75
+ }
76
+ function toPascalCase(str) {
77
+ return toKebabCase(str).split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join("");
78
+ }
79
+ function toCamelCase(str) {
80
+ const pascal = toPascalCase(str);
81
+ return pascal.charAt(0).toLowerCase() + pascal.slice(1);
82
+ }
83
+
84
+ // src/core/generator/generate-resource.ts
85
+ async function generateResource(options) {
86
+ const config = await loadConfig(options.cwd);
87
+ const rawName = options.name.trim();
88
+ const name = toKebabCase(rawName);
89
+ const spec = options.spec ?? config.spec ?? false;
90
+ const flat = options.flat ?? config.flat ?? false;
91
+ const dryRun = options.dryRun ?? false;
92
+ const cwd = options.cwd ?? process.cwd();
93
+ const specFlag = spec ? "" : "--no-spec";
94
+ const flatFlag = flat ? "--flat" : "";
95
+ const commands = [
96
+ `nest g mo ${name} ${flatFlag}`.trim(),
97
+ `nest g co ${name} ${specFlag} ${flatFlag}`.trim(),
98
+ `nest g s ${name} ${specFlag} ${flatFlag}`.trim()
99
+ ];
100
+ logger.info(`Generating resource "${name}" (spec: ${spec ? "yes" : "no"}, flat: ${flat ? "yes" : "no"})...`);
101
+ for (const cmd of commands) {
102
+ await runCommand(cmd, { cwd, dryRun });
103
+ }
104
+ logger.success(`Resource "${name}" generated successfully.`);
105
+ }
106
+
107
+ // src/core/generator/generate-clean-architecture.ts
108
+ import fs2 from "fs/promises";
109
+ import path2 from "path";
110
+ async function generateCleanArchitecture(options) {
111
+ const { dryRun = false, cwd = process.cwd() } = options;
112
+ const rawName = options.name.trim();
113
+ const kebab = toKebabCase(rawName);
114
+ const pascal = toPascalCase(rawName);
115
+ const camel = toCamelCase(rawName);
116
+ const baseDir = path2.join(cwd, "src", kebab);
117
+ const files = [
118
+ // 1. Domain Entity
119
+ {
120
+ filePath: path2.join(baseDir, "domain", "entities", `${kebab}.entity.ts`),
121
+ content: `export class ${pascal}Entity {
122
+ id!: string;
123
+ name!: string;
124
+ createdAt!: Date;
125
+ updatedAt!: Date;
126
+
127
+ constructor(partial: Partial<${pascal}Entity>) {
128
+ Object.assign(this, partial);
129
+ }
130
+ }
131
+ `
132
+ },
133
+ // 2. Domain Repository Interface & Token
134
+ {
135
+ filePath: path2.join(baseDir, "domain", "repositories", `${kebab}.repository.interface.ts`),
136
+ content: `import { ${pascal}Entity } from '../entities/${kebab}.entity';
137
+
138
+ export const ${pascal.toUpperCase()}_REPOSITORY = Symbol('${pascal.toUpperCase()}_REPOSITORY');
139
+
140
+ export interface ${pascal}Repository {
141
+ findById(id: string): Promise<${pascal}Entity | null>;
142
+ findAll(): Promise<${pascal}Entity[]>;
143
+ create(data: Partial<${pascal}Entity>): Promise<${pascal}Entity>;
144
+ delete(id: string): Promise<void>;
145
+ }
146
+ `
147
+ },
148
+ // 3. Application DTOs
149
+ {
150
+ filePath: path2.join(baseDir, "application", "dtos", `create-${kebab}.dto.ts`),
151
+ content: `export class Create${pascal}Dto {
152
+ name!: string;
153
+ }
154
+ `
155
+ },
156
+ {
157
+ filePath: path2.join(baseDir, "application", "dtos", `update-${kebab}.dto.ts`),
158
+ content: `export class Update${pascal}Dto {
159
+ name?: string;
160
+ }
161
+ `
162
+ },
163
+ // 4. Application Use Cases
164
+ {
165
+ filePath: path2.join(baseDir, "application", "use-cases", `create-${kebab}.use-case.ts`),
166
+ content: `import { Inject, Injectable } from '@nestjs/common';
167
+ import {
168
+ ${pascal}Repository,
169
+ ${pascal.toUpperCase()}_REPOSITORY,
170
+ } from '../../domain/repositories/${kebab}.repository.interface';
171
+ import { ${pascal}Entity } from '../../domain/entities/${kebab}.entity';
172
+ import { Create${pascal}Dto } from '../dtos/create-${kebab}.dto';
173
+
174
+ @Injectable()
175
+ export class Create${pascal}UseCase {
176
+ constructor(
177
+ @Inject(${pascal.toUpperCase()}_REPOSITORY)
178
+ private readonly repository: ${pascal}Repository
179
+ ) {}
180
+
181
+ async execute(dto: Create${pascal}Dto): Promise<${pascal}Entity> {
182
+ return this.repository.create({
183
+ name: dto.name,
184
+ createdAt: new Date(),
185
+ updatedAt: new Date(),
186
+ });
187
+ }
188
+ }
189
+ `
190
+ },
191
+ {
192
+ filePath: path2.join(baseDir, "application", "use-cases", `find-${kebab}.use-case.ts`),
193
+ content: `import { Inject, Injectable, NotFoundException } from '@nestjs/common';
194
+ import {
195
+ ${pascal}Repository,
196
+ ${pascal.toUpperCase()}_REPOSITORY,
197
+ } from '../../domain/repositories/${kebab}.repository.interface';
198
+ import { ${pascal}Entity } from '../../domain/entities/${kebab}.entity';
199
+
200
+ @Injectable()
201
+ export class Find${pascal}UseCase {
202
+ constructor(
203
+ @Inject(${pascal.toUpperCase()}_REPOSITORY)
204
+ private readonly repository: ${pascal}Repository
205
+ ) {}
206
+
207
+ async execute(id: string): Promise<${pascal}Entity> {
208
+ const item = await this.repository.findById(id);
209
+ if (!item) {
210
+ throw new NotFoundException(\`${pascal} with id "\${id}" not found\`);
211
+ }
212
+ return item;
213
+ }
214
+ }
215
+ `
216
+ },
217
+ // 5. Infrastructure In-Memory Repository
218
+ {
219
+ filePath: path2.join(
220
+ baseDir,
221
+ "infrastructure",
222
+ "repositories",
223
+ `in-memory-${kebab}.repository.ts`
224
+ ),
225
+ content: `import { Injectable } from '@nestjs/common';
226
+ import {
227
+ ${pascal}Repository,
228
+ } from '../../domain/repositories/${kebab}.repository.interface';
229
+ import { ${pascal}Entity } from '../../domain/entities/${kebab}.entity';
230
+
231
+ @Injectable()
232
+ export class InMemory${pascal}Repository implements ${pascal}Repository {
233
+ private readonly items: Map<string, ${pascal}Entity> = new Map();
234
+
235
+ async findById(id: string): Promise<${pascal}Entity | null> {
236
+ return this.items.get(id) || null;
237
+ }
238
+
239
+ async findAll(): Promise<${pascal}Entity[]> {
240
+ return Array.from(this.items.values());
241
+ }
242
+
243
+ async create(data: Partial<${pascal}Entity>): Promise<${pascal}Entity> {
244
+ const id = (this.items.size + 1).toString();
245
+ const entity = new ${pascal}Entity({
246
+ id,
247
+ name: data.name ?? 'Untitled',
248
+ createdAt: data.createdAt ?? new Date(),
249
+ updatedAt: data.updatedAt ?? new Date(),
250
+ });
251
+ this.items.set(id, entity);
252
+ return entity;
253
+ }
254
+
255
+ async delete(id: string): Promise<void> {
256
+ this.items.delete(id);
257
+ }
258
+ }
259
+ `
260
+ },
261
+ // 6. Infrastructure Controller
262
+ {
263
+ filePath: path2.join(baseDir, "infrastructure", "controllers", `${kebab}.controller.ts`),
264
+ content: `import { Body, Controller, Get, Param, Post } from '@nestjs/common';
265
+ import { Create${pascal}UseCase } from '../../application/use-cases/create-${kebab}.use-case';
266
+ import { Find${pascal}UseCase } from '../../application/use-cases/find-${kebab}.use-case';
267
+ import { Create${pascal}Dto } from '../../application/dtos/create-${kebab}.dto';
268
+
269
+ @Controller('${kebab}')
270
+ export class ${pascal}Controller {
271
+ constructor(
272
+ private readonly createUseCase: Create${pascal}UseCase,
273
+ private readonly findUseCase: Find${pascal}UseCase
274
+ ) {}
275
+
276
+ @Post()
277
+ create(@Body() dto: Create${pascal}Dto) {
278
+ return this.createUseCase.execute(dto);
279
+ }
280
+
281
+ @Get(':id')
282
+ findOne(@Param('id') id: string) {
283
+ return this.findUseCase.execute(id);
284
+ }
285
+ }
286
+ `
287
+ },
288
+ // 7. NestJS Module
289
+ {
290
+ filePath: path2.join(baseDir, `${kebab}.module.ts`),
291
+ content: `import { Module } from '@nestjs/common';
292
+ import { ${pascal}Controller } from './infrastructure/controllers/${kebab}.controller';
293
+ import { Create${pascal}UseCase } from './application/use-cases/create-${kebab}.use-case';
294
+ import { Find${pascal}UseCase } from './application/use-cases/find-${kebab}.use-case';
295
+ import { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository.interface';
296
+ import { InMemory${pascal}Repository } from './infrastructure/repositories/in-memory-${kebab}.repository';
297
+
298
+ @Module({
299
+ controllers: [${pascal}Controller],
300
+ providers: [
301
+ Create${pascal}UseCase,
302
+ Find${pascal}UseCase,
303
+ {
304
+ provide: ${pascal.toUpperCase()}_REPOSITORY,
305
+ useClass: InMemory${pascal}Repository,
306
+ },
307
+ ],
308
+ exports: [Create${pascal}UseCase, Find${pascal}UseCase, ${pascal.toUpperCase()}_REPOSITORY],
309
+ })
310
+ export class ${pascal}Module {}
311
+ `
312
+ }
313
+ ];
314
+ logger.info(`Generating Clean Architecture module for "${kebab}" at ${baseDir}...`);
315
+ for (const file of files) {
316
+ if (dryRun) {
317
+ logger.info(`[dry-run] Would create: ${path2.relative(cwd, file.filePath)}`);
318
+ } else {
319
+ await fs2.mkdir(path2.dirname(file.filePath), { recursive: true });
320
+ await fs2.writeFile(file.filePath, file.content, "utf-8");
321
+ logger.step(`Created ${path2.relative(cwd, file.filePath)}`);
322
+ }
323
+ }
324
+ logger.success(`Clean Architecture structure for "${pascal}Module" generated!`);
325
+ logger.info(`Remember to import ${pascal}Module in your AppModule.`);
326
+ }
327
+
328
+ // src/core/diagnostics/doctor.ts
329
+ import fs3 from "fs/promises";
330
+ import path3 from "path";
331
+ import pc2 from "picocolors";
332
+ async function runDoctor(cwd = process.cwd()) {
333
+ const report = {
334
+ isNestProject: false,
335
+ issues: [],
336
+ recommendations: []
337
+ };
338
+ logger.info("Running nest-tools doctor diagnostics...\n");
339
+ const pkgPath = path3.join(cwd, "package.json");
340
+ let pkg = null;
341
+ try {
342
+ const pkgRaw = await fs3.readFile(pkgPath, "utf-8");
343
+ pkg = JSON.parse(pkgRaw);
344
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
345
+ if (deps["@nestjs/core"] || deps["@nestjs/common"]) {
346
+ report.isNestProject = true;
347
+ console.log(pc2.green("\u2714") + " NestJS dependencies detected in package.json");
348
+ } else {
349
+ report.issues.push("Could not find @nestjs/core or @nestjs/common in package.json.");
350
+ }
351
+ } catch {
352
+ report.issues.push("No package.json found in current working directory.");
353
+ }
354
+ try {
355
+ await fs3.access(path3.join(cwd, "nest-cli.json"));
356
+ console.log(pc2.green("\u2714") + " nest-cli.json configuration found");
357
+ } catch {
358
+ report.recommendations.push('nest-cli.json is missing. Consider generating one with "nest new".');
359
+ }
360
+ try {
361
+ await fs3.access(path3.join(cwd, "tsconfig.json"));
362
+ console.log(pc2.green("\u2714") + " tsconfig.json found");
363
+ } catch {
364
+ report.issues.push("tsconfig.json is missing in project root.");
365
+ }
366
+ try {
367
+ await fs3.access(path3.join(cwd, ".env"));
368
+ try {
369
+ await fs3.access(path3.join(cwd, ".env.example"));
370
+ console.log(pc2.green("\u2714") + " .env and .env.example are present");
371
+ } catch {
372
+ report.recommendations.push(
373
+ ".env exists but .env.example is missing. It is recommended to commit an example file."
374
+ );
375
+ }
376
+ } catch {
377
+ }
378
+ try {
379
+ const appModulePath = path3.join(cwd, "src", "app.module.ts");
380
+ const appModuleContent = await fs3.readFile(appModulePath, "utf-8");
381
+ const srcDir = path3.join(cwd, "src");
382
+ const entries = await fs3.readdir(srcDir, { withFileTypes: true });
383
+ for (const entry of entries) {
384
+ if (entry.isDirectory()) {
385
+ const potentialModule = `${entry.name}.module.ts`;
386
+ const moduleFilePath = path3.join(srcDir, entry.name, potentialModule);
387
+ try {
388
+ await fs3.access(moduleFilePath);
389
+ if (!appModuleContent.includes(potentialModule.replace(".ts", "")) && !appModuleContent.includes(entry.name)) {
390
+ report.recommendations.push(
391
+ `Module "${entry.name}" was found at src/${entry.name}/${potentialModule}, but might not be imported in app.module.ts.`
392
+ );
393
+ }
394
+ } catch {
395
+ }
396
+ }
397
+ }
398
+ } catch {
399
+ }
400
+ console.log("");
401
+ if (report.issues.length > 0) {
402
+ logger.error(`Found ${report.issues.length} issue(s):`);
403
+ for (const issue of report.issues) {
404
+ console.log(pc2.red(" \u2716 ") + issue);
405
+ }
406
+ } else {
407
+ logger.success("No critical issues found!");
408
+ }
409
+ if (report.recommendations.length > 0) {
410
+ logger.warn(`Found ${report.recommendations.length} recommendation(s):`);
411
+ for (const rec of report.recommendations) {
412
+ console.log(pc2.yellow(" \u279C ") + rec);
413
+ }
414
+ }
415
+ return report;
416
+ }
417
+
418
+ // src/cli/prompts.ts
419
+ import * as p from "@clack/prompts";
420
+ import pc3 from "picocolors";
421
+ async function runInteractive() {
422
+ p.intro(pc3.bgCyan(pc3.black(" @manulz/nest-tools ")));
423
+ const action = await p.select({
424
+ message: "What would you like to do?",
425
+ options: [
426
+ { value: "resource", label: "Generate Standard Resource (Module + Controller + Service)" },
427
+ { value: "clean", label: "Generate Clean Architecture / Hexagonal Module" },
428
+ { value: "init", label: "Initialize nest-tools.json config file" },
429
+ { value: "doctor", label: "Run project diagnostics (Doctor)" }
430
+ ]
431
+ });
432
+ if (p.isCancel(action)) {
433
+ p.cancel("Operation cancelled.");
434
+ process.exit(0);
435
+ }
436
+ if (action === "doctor") {
437
+ await runDoctor();
438
+ p.outro(pc3.green("Diagnostics completed!"));
439
+ return;
440
+ }
441
+ if (action === "init") {
442
+ const configPath = await createDefaultConfig();
443
+ p.outro(pc3.green(`Created config at: ${configPath}`));
444
+ return;
445
+ }
446
+ const name = await p.text({
447
+ message: "What is the name of the resource/module?",
448
+ placeholder: "e.g. users, products, auth",
449
+ validate: (value) => {
450
+ if (!value || value.trim().length === 0) {
451
+ return "Please enter a valid name";
452
+ }
453
+ }
454
+ });
455
+ if (p.isCancel(name)) {
456
+ p.cancel("Operation cancelled.");
457
+ process.exit(0);
458
+ }
459
+ if (action === "resource") {
460
+ const spec = await p.confirm({
461
+ message: "Do you want to generate spec/test files?",
462
+ initialValue: false
463
+ });
464
+ if (p.isCancel(spec)) {
465
+ p.cancel("Operation cancelled.");
466
+ process.exit(0);
467
+ }
468
+ const s = p.spinner();
469
+ s.start(`Generating resource "${name}"...`);
470
+ try {
471
+ await generateResource({ name, spec: Boolean(spec) });
472
+ s.stop(`Resource "${name}" generated!`);
473
+ p.outro(pc3.green("Done!"));
474
+ } catch (err) {
475
+ s.stop(pc3.red("Generation failed."));
476
+ p.cancel(err.message);
477
+ process.exit(1);
478
+ }
479
+ } else if (action === "clean") {
480
+ const s = p.spinner();
481
+ s.start(`Generating Clean Architecture module "${name}"...`);
482
+ try {
483
+ await generateCleanArchitecture({ name });
484
+ s.stop(`Clean Architecture module "${name}" generated!`);
485
+ p.outro(pc3.green("Done!"));
486
+ } catch (err) {
487
+ s.stop(pc3.red("Generation failed."));
488
+ p.cancel(err.message);
489
+ process.exit(1);
490
+ }
491
+ }
492
+ }
493
+
494
+ // src/cli/index.ts
495
+ var program = new Command();
496
+ program.name("nest-tools").description("Developer utilities, clean architecture generator, and runtime helpers for NestJS").version("1.1.0");
497
+ program.command("generate <name>").alias("g").description("Generate Module, Controller, and Service for a resource").option("--spec", "Include unit test files (.spec.ts)").option("--no-spec", "Exclude unit test files (.spec.ts)").option("--flat", "Generate elements without creating a subfolder").option("--dry-run", "Preview the commands without executing them").action(async (name, options) => {
498
+ try {
499
+ await generateResource({
500
+ name,
501
+ spec: options.spec,
502
+ flat: options.flat,
503
+ dryRun: options.dryRun
504
+ });
505
+ } catch (error) {
506
+ logger.error(error.message);
507
+ process.exit(1);
508
+ }
509
+ });
510
+ program.command("hex <name>").alias("clean").description("Generate a Clean Architecture / Hexagonal module structure").option("--dry-run", "Preview the files to create without writing them").action(async (name, options) => {
511
+ try {
512
+ await generateCleanArchitecture({
513
+ name,
514
+ dryRun: options.dryRun
515
+ });
516
+ } catch (error) {
517
+ logger.error(error.message);
518
+ process.exit(1);
519
+ }
520
+ });
521
+ program.command("doctor").description("Inspect current NestJS project health and check for common issues").action(async () => {
522
+ try {
523
+ await runDoctor();
524
+ } catch (error) {
525
+ logger.error(error.message);
526
+ process.exit(1);
527
+ }
528
+ });
529
+ program.command("init").description("Create default nest-tools.json configuration file").action(async () => {
530
+ try {
531
+ const configPath = await createDefaultConfig();
532
+ logger.success(`Configuration file created at: ${configPath}`);
533
+ } catch (error) {
534
+ logger.error(error.message);
535
+ process.exit(1);
536
+ }
537
+ });
538
+ if (process.argv.slice(2).length === 0) {
539
+ runInteractive().catch((error) => {
540
+ logger.error(error.message);
541
+ process.exit(1);
542
+ });
543
+ } else {
544
+ program.parse(process.argv);
545
+ }
546
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/cli/index.ts","../../src/core/runner/command-runner.ts","../../src/utils/logger.ts","../../src/core/config/index.ts","../../src/utils/strings.ts","../../src/core/generator/generate-resource.ts","../../src/core/generator/generate-clean-architecture.ts","../../src/core/diagnostics/doctor.ts","../../src/cli/prompts.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { Command } from 'commander';\nimport { generateResource } from '../core/generator/generate-resource';\nimport { generateCleanArchitecture } from '../core/generator/generate-clean-architecture';\nimport { runDoctor } from '../core/diagnostics/doctor';\nimport { createDefaultConfig } from '../core/config';\nimport { runInteractive } from './prompts';\nimport { logger } from '../utils/logger';\n\nconst program = new Command();\n\nprogram\n .name('nest-tools')\n .description('Developer utilities, clean architecture generator, and runtime helpers for NestJS')\n .version('1.1.0');\n\n// Subcommand: generate (g)\nprogram\n .command('generate <name>')\n .alias('g')\n .description('Generate Module, Controller, and Service for a resource')\n .option('--spec', 'Include unit test files (.spec.ts)')\n .option('--no-spec', 'Exclude unit test files (.spec.ts)')\n .option('--flat', 'Generate elements without creating a subfolder')\n .option('--dry-run', 'Preview the commands without executing them')\n .action(async (name: string, options: { spec?: boolean; flat?: boolean; dryRun?: boolean }) => {\n try {\n await generateResource({\n name,\n spec: options.spec,\n flat: options.flat,\n dryRun: options.dryRun,\n });\n } catch (error: any) {\n logger.error(error.message);\n process.exit(1);\n }\n });\n\n// Subcommand: hex / clean\nprogram\n .command('hex <name>')\n .alias('clean')\n .description('Generate a Clean Architecture / Hexagonal module structure')\n .option('--dry-run', 'Preview the files to create without writing them')\n .action(async (name: string, options: { dryRun?: boolean }) => {\n try {\n await generateCleanArchitecture({\n name,\n dryRun: options.dryRun,\n });\n } catch (error: any) {\n logger.error(error.message);\n process.exit(1);\n }\n });\n\n// Subcommand: doctor\nprogram\n .command('doctor')\n .description('Inspect current NestJS project health and check for common issues')\n .action(async () => {\n try {\n await runDoctor();\n } catch (error: any) {\n logger.error(error.message);\n process.exit(1);\n }\n });\n\n// Subcommand: init\nprogram\n .command('init')\n .description('Create default nest-tools.json configuration file')\n .action(async () => {\n try {\n const configPath = await createDefaultConfig();\n logger.success(`Configuration file created at: ${configPath}`);\n } catch (error: any) {\n logger.error(error.message);\n process.exit(1);\n }\n });\n\n// If no arguments provided, launch interactive prompt\nif (process.argv.slice(2).length === 0) {\n runInteractive().catch((error) => {\n logger.error(error.message);\n process.exit(1);\n });\n} else {\n program.parse(process.argv);\n}\n","import { exec } from 'node:child_process';\nimport { promisify } from 'node:util';\nimport { logger } from '../../utils/logger';\n\nconst execAsync = promisify(exec);\n\nexport interface RunCommandOptions {\n cwd?: string;\n dryRun?: boolean;\n silent?: boolean;\n}\n\nexport async function runCommand(\n command: string,\n options: RunCommandOptions = {}\n): Promise<{ stdout: string; stderr: string }> {\n const { cwd = process.cwd(), dryRun = false, silent = false } = options;\n\n if (dryRun) {\n logger.info(`[dry-run] Would execute: ${command}`);\n return { stdout: '', stderr: '' };\n }\n\n if (!silent) {\n logger.step(command);\n }\n\n try {\n const result = await execAsync(command, { cwd });\n return result;\n } catch (error: any) {\n const message = error.stderr || error.message || 'Command failed';\n throw new Error(`Failed to execute: \"${command}\"\\n${message}`);\n }\n}\n","import pc from 'picocolors';\n\nexport const logger = {\n info: (msg: string) => console.log(pc.cyan('ℹ ') + msg),\n success: (msg: string) => console.log(pc.green('✔ ') + pc.bold(msg)),\n warn: (msg: string) => console.log(pc.yellow('⚠ ') + msg),\n error: (msg: string) => console.error(pc.red('✖ ') + pc.bold(msg)),\n step: (step: string, detail?: string) => {\n console.log(pc.blue('▶ ') + pc.bold(step) + (detail ? pc.dim(` (${detail})`) : ''));\n },\n};\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\n\nexport interface NestToolsConfig {\n spec?: boolean;\n flat?: boolean;\n architecture?: 'standard' | 'clean';\n packageManager?: 'npm' | 'yarn' | 'pnpm';\n}\n\nexport const DEFAULT_CONFIG: NestToolsConfig = {\n spec: false,\n flat: false,\n architecture: 'standard',\n packageManager: 'npm',\n};\n\nconst CONFIG_FILENAMES = ['nest-tools.json', '.nesttoolsrc', '.nesttoolsrc.json'];\n\nexport async function loadConfig(cwd = process.cwd()): Promise<NestToolsConfig> {\n for (const filename of CONFIG_FILENAMES) {\n const configPath = path.join(cwd, filename);\n try {\n const data = await fs.readFile(configPath, 'utf-8');\n const parsed = JSON.parse(data);\n return { ...DEFAULT_CONFIG, ...parsed };\n } catch {\n // Continue searching\n }\n }\n\n return DEFAULT_CONFIG;\n}\n\nexport async function createDefaultConfig(cwd = process.cwd()): Promise<string> {\n const targetPath = path.join(cwd, 'nest-tools.json');\n const content = JSON.stringify(DEFAULT_CONFIG, null, 2) + '\\n';\n await fs.writeFile(targetPath, content, 'utf-8');\n return targetPath;\n}\n","export function toKebabCase(str: string): string {\n return str\n .replace(/([a-z])([A-Z])/g, '$1-$2')\n .replace(/[\\s_]+/g, '-')\n .toLowerCase();\n}\n\nexport function toPascalCase(str: string): string {\n return toKebabCase(str)\n .split('-')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join('');\n}\n\nexport function toCamelCase(str: string): string {\n const pascal = toPascalCase(str);\n return pascal.charAt(0).toLowerCase() + pascal.slice(1);\n}\n","import { runCommand } from '../runner/command-runner';\nimport { loadConfig } from '../config';\nimport { logger } from '../../utils/logger';\nimport { toKebabCase } from '../../utils/strings';\n\nexport interface GenerateResourceOptions {\n name: string;\n spec?: boolean;\n flat?: boolean;\n dryRun?: boolean;\n cwd?: string;\n}\n\nexport async function generateResource(options: GenerateResourceOptions): Promise<void> {\n const config = await loadConfig(options.cwd);\n const rawName = options.name.trim();\n const name = toKebabCase(rawName);\n\n const spec = options.spec ?? config.spec ?? false;\n const flat = options.flat ?? config.flat ?? false;\n const dryRun = options.dryRun ?? false;\n const cwd = options.cwd ?? process.cwd();\n\n const specFlag = spec ? '' : '--no-spec';\n const flatFlag = flat ? '--flat' : '';\n\n const commands = [\n `nest g mo ${name} ${flatFlag}`.trim(),\n `nest g co ${name} ${specFlag} ${flatFlag}`.trim(),\n `nest g s ${name} ${specFlag} ${flatFlag}`.trim(),\n ];\n\n logger.info(`Generating resource \"${name}\" (spec: ${spec ? 'yes' : 'no'}, flat: ${flat ? 'yes' : 'no'})...`);\n\n for (const cmd of commands) {\n await runCommand(cmd, { cwd, dryRun });\n }\n\n logger.success(`Resource \"${name}\" generated successfully.`);\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport { logger } from '../../utils/logger';\nimport { toCamelCase, toKebabCase, toPascalCase } from '../../utils/strings';\n\nexport interface GenerateCleanArchitectureOptions {\n name: string;\n dryRun?: boolean;\n cwd?: string;\n}\n\nexport async function generateCleanArchitecture(\n options: GenerateCleanArchitectureOptions\n): Promise<void> {\n const { dryRun = false, cwd = process.cwd() } = options;\n const rawName = options.name.trim();\n const kebab = toKebabCase(rawName);\n const pascal = toPascalCase(rawName);\n const camel = toCamelCase(rawName);\n\n const baseDir = path.join(cwd, 'src', kebab);\n\n const files: { filePath: string; content: string }[] = [\n // 1. Domain Entity\n {\n filePath: path.join(baseDir, 'domain', 'entities', `${kebab}.entity.ts`),\n content: `export class ${pascal}Entity {\n id!: string;\n name!: string;\n createdAt!: Date;\n updatedAt!: Date;\n\n constructor(partial: Partial<${pascal}Entity>) {\n Object.assign(this, partial);\n }\n}\n`,\n },\n // 2. Domain Repository Interface & Token\n {\n filePath: path.join(baseDir, 'domain', 'repositories', `${kebab}.repository.interface.ts`),\n content: `import { ${pascal}Entity } from '../entities/${kebab}.entity';\n\nexport const ${pascal.toUpperCase()}_REPOSITORY = Symbol('${pascal.toUpperCase()}_REPOSITORY');\n\nexport interface ${pascal}Repository {\n findById(id: string): Promise<${pascal}Entity | null>;\n findAll(): Promise<${pascal}Entity[]>;\n create(data: Partial<${pascal}Entity>): Promise<${pascal}Entity>;\n delete(id: string): Promise<void>;\n}\n`,\n },\n // 3. Application DTOs\n {\n filePath: path.join(baseDir, 'application', 'dtos', `create-${kebab}.dto.ts`),\n content: `export class Create${pascal}Dto {\n name!: string;\n}\n`,\n },\n {\n filePath: path.join(baseDir, 'application', 'dtos', `update-${kebab}.dto.ts`),\n content: `export class Update${pascal}Dto {\n name?: string;\n}\n`,\n },\n // 4. Application Use Cases\n {\n filePath: path.join(baseDir, 'application', 'use-cases', `create-${kebab}.use-case.ts`),\n content: `import { Inject, Injectable } from '@nestjs/common';\nimport {\n ${pascal}Repository,\n ${pascal.toUpperCase()}_REPOSITORY,\n} from '../../domain/repositories/${kebab}.repository.interface';\nimport { ${pascal}Entity } from '../../domain/entities/${kebab}.entity';\nimport { Create${pascal}Dto } from '../dtos/create-${kebab}.dto';\n\n@Injectable()\nexport class Create${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY)\n private readonly repository: ${pascal}Repository\n ) {}\n\n async execute(dto: Create${pascal}Dto): Promise<${pascal}Entity> {\n return this.repository.create({\n name: dto.name,\n createdAt: new Date(),\n updatedAt: new Date(),\n });\n }\n}\n`,\n },\n {\n filePath: path.join(baseDir, 'application', 'use-cases', `find-${kebab}.use-case.ts`),\n content: `import { Inject, Injectable, NotFoundException } from '@nestjs/common';\nimport {\n ${pascal}Repository,\n ${pascal.toUpperCase()}_REPOSITORY,\n} from '../../domain/repositories/${kebab}.repository.interface';\nimport { ${pascal}Entity } from '../../domain/entities/${kebab}.entity';\n\n@Injectable()\nexport class Find${pascal}UseCase {\n constructor(\n @Inject(${pascal.toUpperCase()}_REPOSITORY)\n private readonly repository: ${pascal}Repository\n ) {}\n\n async execute(id: string): Promise<${pascal}Entity> {\n const item = await this.repository.findById(id);\n if (!item) {\n throw new NotFoundException(\\`${pascal} with id \"\\${id}\" not found\\`);\n }\n return item;\n }\n}\n`,\n },\n // 5. Infrastructure In-Memory Repository\n {\n filePath: path.join(\n baseDir,\n 'infrastructure',\n 'repositories',\n `in-memory-${kebab}.repository.ts`\n ),\n content: `import { Injectable } from '@nestjs/common';\nimport {\n ${pascal}Repository,\n} from '../../domain/repositories/${kebab}.repository.interface';\nimport { ${pascal}Entity } from '../../domain/entities/${kebab}.entity';\n\n@Injectable()\nexport class InMemory${pascal}Repository implements ${pascal}Repository {\n private readonly items: Map<string, ${pascal}Entity> = new Map();\n\n async findById(id: string): Promise<${pascal}Entity | null> {\n return this.items.get(id) || null;\n }\n\n async findAll(): Promise<${pascal}Entity[]> {\n return Array.from(this.items.values());\n }\n\n async create(data: Partial<${pascal}Entity>): Promise<${pascal}Entity> {\n const id = (this.items.size + 1).toString();\n const entity = new ${pascal}Entity({\n id,\n name: data.name ?? 'Untitled',\n createdAt: data.createdAt ?? new Date(),\n updatedAt: data.updatedAt ?? new Date(),\n });\n this.items.set(id, entity);\n return entity;\n }\n\n async delete(id: string): Promise<void> {\n this.items.delete(id);\n }\n}\n`,\n },\n // 6. Infrastructure Controller\n {\n filePath: path.join(baseDir, 'infrastructure', 'controllers', `${kebab}.controller.ts`),\n content: `import { Body, Controller, Get, Param, Post } from '@nestjs/common';\nimport { Create${pascal}UseCase } from '../../application/use-cases/create-${kebab}.use-case';\nimport { Find${pascal}UseCase } from '../../application/use-cases/find-${kebab}.use-case';\nimport { Create${pascal}Dto } from '../../application/dtos/create-${kebab}.dto';\n\n@Controller('${kebab}')\nexport class ${pascal}Controller {\n constructor(\n private readonly createUseCase: Create${pascal}UseCase,\n private readonly findUseCase: Find${pascal}UseCase\n ) {}\n\n @Post()\n create(@Body() dto: Create${pascal}Dto) {\n return this.createUseCase.execute(dto);\n }\n\n @Get(':id')\n findOne(@Param('id') id: string) {\n return this.findUseCase.execute(id);\n }\n}\n`,\n },\n // 7. NestJS Module\n {\n filePath: path.join(baseDir, `${kebab}.module.ts`),\n content: `import { Module } from '@nestjs/common';\nimport { ${pascal}Controller } from './infrastructure/controllers/${kebab}.controller';\nimport { Create${pascal}UseCase } from './application/use-cases/create-${kebab}.use-case';\nimport { Find${pascal}UseCase } from './application/use-cases/find-${kebab}.use-case';\nimport { ${pascal.toUpperCase()}_REPOSITORY } from './domain/repositories/${kebab}.repository.interface';\nimport { InMemory${pascal}Repository } from './infrastructure/repositories/in-memory-${kebab}.repository';\n\n@Module({\n controllers: [${pascal}Controller],\n providers: [\n Create${pascal}UseCase,\n Find${pascal}UseCase,\n {\n provide: ${pascal.toUpperCase()}_REPOSITORY,\n useClass: InMemory${pascal}Repository,\n },\n ],\n exports: [Create${pascal}UseCase, Find${pascal}UseCase, ${pascal.toUpperCase()}_REPOSITORY],\n})\nexport class ${pascal}Module {}\n`,\n },\n ];\n\n logger.info(`Generating Clean Architecture module for \"${kebab}\" at ${baseDir}...`);\n\n for (const file of files) {\n if (dryRun) {\n logger.info(`[dry-run] Would create: ${path.relative(cwd, file.filePath)}`);\n } else {\n await fs.mkdir(path.dirname(file.filePath), { recursive: true });\n await fs.writeFile(file.filePath, file.content, 'utf-8');\n logger.step(`Created ${path.relative(cwd, file.filePath)}`);\n }\n }\n\n logger.success(`Clean Architecture structure for \"${pascal}Module\" generated!`);\n logger.info(`Remember to import ${pascal}Module in your AppModule.`);\n}\n","import fs from 'node:fs/promises';\nimport path from 'node:path';\nimport pc from 'picocolors';\nimport { logger } from '../../utils/logger';\n\nexport interface DoctorReport {\n isNestProject: boolean;\n issues: string[];\n recommendations: string[];\n}\n\nexport async function runDoctor(cwd = process.cwd()): Promise<DoctorReport> {\n const report: DoctorReport = {\n isNestProject: false,\n issues: [],\n recommendations: [],\n };\n\n logger.info('Running nest-tools doctor diagnostics...\\n');\n\n // 1. Check package.json\n const pkgPath = path.join(cwd, 'package.json');\n let pkg: any = null;\n try {\n const pkgRaw = await fs.readFile(pkgPath, 'utf-8');\n pkg = JSON.parse(pkgRaw);\n const deps = { ...pkg.dependencies, ...pkg.devDependencies };\n if (deps['@nestjs/core'] || deps['@nestjs/common']) {\n report.isNestProject = true;\n console.log(pc.green('✔') + ' NestJS dependencies detected in package.json');\n } else {\n report.issues.push('Could not find @nestjs/core or @nestjs/common in package.json.');\n }\n } catch {\n report.issues.push('No package.json found in current working directory.');\n }\n\n // 2. Check nest-cli.json\n try {\n await fs.access(path.join(cwd, 'nest-cli.json'));\n console.log(pc.green('✔') + ' nest-cli.json configuration found');\n } catch {\n report.recommendations.push('nest-cli.json is missing. Consider generating one with \"nest new\".');\n }\n\n // 3. Check tsconfig.json\n try {\n await fs.access(path.join(cwd, 'tsconfig.json'));\n console.log(pc.green('✔') + ' tsconfig.json found');\n } catch {\n report.issues.push('tsconfig.json is missing in project root.');\n }\n\n // 4. Check .env and .env.example\n try {\n await fs.access(path.join(cwd, '.env'));\n try {\n await fs.access(path.join(cwd, '.env.example'));\n console.log(pc.green('✔') + ' .env and .env.example are present');\n } catch {\n report.recommendations.push(\n '.env exists but .env.example is missing. It is recommended to commit an example file.'\n );\n }\n } catch {\n // No .env, ignore\n }\n\n // 5. Module check (look for orphan modules)\n try {\n const appModulePath = path.join(cwd, 'src', 'app.module.ts');\n const appModuleContent = await fs.readFile(appModulePath, 'utf-8');\n\n const srcDir = path.join(cwd, 'src');\n const entries = await fs.readdir(srcDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (entry.isDirectory()) {\n const potentialModule = `${entry.name}.module.ts`;\n const moduleFilePath = path.join(srcDir, entry.name, potentialModule);\n try {\n await fs.access(moduleFilePath);\n if (!appModuleContent.includes(potentialModule.replace('.ts', '')) &&\n !appModuleContent.includes(entry.name)) {\n report.recommendations.push(\n `Module \"${entry.name}\" was found at src/${entry.name}/${potentialModule}, but might not be imported in app.module.ts.`\n );\n }\n } catch {\n // not a module dir\n }\n }\n }\n } catch {\n // app.module.ts doesn't exist or isn't accessible\n }\n\n console.log('');\n if (report.issues.length > 0) {\n logger.error(`Found ${report.issues.length} issue(s):`);\n for (const issue of report.issues) {\n console.log(pc.red(' ✖ ') + issue);\n }\n } else {\n logger.success('No critical issues found!');\n }\n\n if (report.recommendations.length > 0) {\n logger.warn(`Found ${report.recommendations.length} recommendation(s):`);\n for (const rec of report.recommendations) {\n console.log(pc.yellow(' ➜ ') + rec);\n }\n }\n\n return report;\n}\n","import * as p from '@clack/prompts';\nimport pc from 'picocolors';\nimport { generateResource } from '../core/generator/generate-resource';\nimport { generateCleanArchitecture } from '../core/generator/generate-clean-architecture';\nimport { runDoctor } from '../core/diagnostics/doctor';\nimport { createDefaultConfig } from '../core/config';\n\nexport async function runInteractive(): Promise<void> {\n p.intro(pc.bgCyan(pc.black(' @manulz/nest-tools ')));\n\n const action = await p.select({\n message: 'What would you like to do?',\n options: [\n { value: 'resource', label: 'Generate Standard Resource (Module + Controller + Service)' },\n { value: 'clean', label: 'Generate Clean Architecture / Hexagonal Module' },\n { value: 'init', label: 'Initialize nest-tools.json config file' },\n { value: 'doctor', label: 'Run project diagnostics (Doctor)' },\n ],\n });\n\n if (p.isCancel(action)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n if (action === 'doctor') {\n await runDoctor();\n p.outro(pc.green('Diagnostics completed!'));\n return;\n }\n\n if (action === 'init') {\n const configPath = await createDefaultConfig();\n p.outro(pc.green(`Created config at: ${configPath}`));\n return;\n }\n\n const name = await p.text({\n message: 'What is the name of the resource/module?',\n placeholder: 'e.g. users, products, auth',\n validate: (value) => {\n if (!value || value.trim().length === 0) {\n return 'Please enter a valid name';\n }\n },\n });\n\n if (p.isCancel(name)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n if (action === 'resource') {\n const spec = await p.confirm({\n message: 'Do you want to generate spec/test files?',\n initialValue: false,\n });\n\n if (p.isCancel(spec)) {\n p.cancel('Operation cancelled.');\n process.exit(0);\n }\n\n const s = p.spinner();\n s.start(`Generating resource \"${name}\"...`);\n try {\n await generateResource({ name: name as string, spec: Boolean(spec) });\n s.stop(`Resource \"${name}\" generated!`);\n p.outro(pc.green('Done!'));\n } catch (err: any) {\n s.stop(pc.red('Generation failed.'));\n p.cancel(err.message);\n process.exit(1);\n }\n } else if (action === 'clean') {\n const s = p.spinner();\n s.start(`Generating Clean Architecture module \"${name}\"...`);\n try {\n await generateCleanArchitecture({ name: name as string });\n s.stop(`Clean Architecture module \"${name}\" generated!`);\n p.outro(pc.green('Done!'));\n } catch (err: any) {\n s.stop(pc.red('Generation failed.'));\n p.cancel(err.message);\n process.exit(1);\n }\n }\n}\n"],"mappings":"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","names":["fs","path","path","fs","fs","path","pc","path","fs","pc","pc","pc"]}