nest-combo 1.2.0 → 1.2.2

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,5 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
4
+
5
+ test-project/
package/README.MD CHANGED
@@ -1,8 +1,8 @@
1
1
  # NestJS Combo CLI
2
2
 
3
- ![npm](https://img.shields.io/npm/v/nest-combo) ![npm](https://img.shields.io/npm/dt/nest-combo)
3
+ ![npm](https://img.shields.io/npm/v/nest-combo) ![npm](https://img.shields.io/npm/dt/nest-combo) [![CI](https://github.com/vinisalves/nest-combo/actions/workflows/ci.yml/badge.svg)](https://github.com/vinisalves/nest-combo/actions/workflows/ci.yml)
4
4
 
5
- A CLI tool to generate NestJS modules, controllers, services, and other components in a single line command.
5
+ A CLI tool to generate NestJS Projects, modules, controllers, services, and other components in a single line command.
6
6
 
7
7
  ---
8
8
 
@@ -29,46 +29,10 @@ If the NestJS CLI is not installed globally, don't worry! **nest-combo** comes b
29
29
 
30
30
  ---
31
31
 
32
- ### Key Features of Nest-Combo
33
-
34
- #### 1. **Importing a YAML File for Project Scaffolding**
35
-
36
- With **nest-combo**, you can define an entire project structure in a `project.yml` file and let **nest-combo** handle the scaffolding process for you. Simply specify your modules, resources, dependencies, and optional flags in the YAML file, and **nest-combo** will generate the entire project automatically.
37
-
38
- This feature encourages thoughtful planning and allows you to automate repetitive tasks, saving you time and effort. Additionally, **nest-combo** supports **recursive logic** for creating nested modules, ensuring that even complex project structures are generated accurately.
39
-
40
- For example, you can define deeply nested modules like this:
41
-
42
- ```yaml
43
- modules:
44
- - name: core
45
- resources:
46
- - module
47
- modules:
48
- - name: user
49
- resources:
50
- - module
51
- - controller
52
- - service
53
- options:
54
- - --no-spec
55
- modules:
56
- - name: subUsers
57
- resources:
58
- - module
59
- - controller
60
- - service
61
- options:
62
- - --no-spec
63
- ```
64
-
65
- This recursive approach ensures that all parent and child modules are created with proper imports and dependencies.
66
-
67
- ---
68
-
69
32
  ## Features
70
33
 
71
34
  - Load a full project from a YAML file.
35
+ - Create a new project and automatically open VsCode
72
36
  - Generate NestJS modules, controllers, services, gateways, middleware, and interceptors with a single-line command.
73
37
  - Support for optional flags like `--no-spec` and `--dry-run`.
74
38
  - Colorful and user-friendly output using `chalk`.
@@ -97,15 +61,21 @@ nest-combo --version
97
61
  Run the CLI tool with the desired module name and options:
98
62
 
99
63
  ```bash
100
- nest-combo <module-name> [options]
64
+ nest-combo <<project|module>-name> [options]
101
65
  ```
102
66
 
103
67
  ### Example Commands
104
68
 
105
- #### Create a Module, Controller, and Service in a Single Line
69
+ #### Create a project
106
70
 
107
71
  ```bash
108
- nest-combo users -m -c -s
72
+ nest-combo my-amazing-project -new # "VSCode will open by default once it's done. If you don't want it just add -no-vscode"
73
+ ```
74
+
75
+ #### Create a Module, Controller, Service, Intercepetor, Gateway and Middleware in a Single Line Command
76
+
77
+ ```bash
78
+ nest-combo users -m -c -s -itc -g -mw # if you don't want spcec files, just add -ns or --no-spec
109
79
  ```
110
80
 
111
81
  #### Create a Full Project from a YAML File
@@ -141,11 +111,11 @@ nest-combo:
141
111
  open-vscode: true # Open VSCode when the process is finished
142
112
  package-manager: npm # npm | yarn | pnpm
143
113
  dependencies:
144
- - "@nestjs/config"
145
- - "@nestjs/bull"
146
- - "class-transformer"
147
- - "class-validator"
148
- - "nestjs-twilio"
114
+ - '@nestjs/config'
115
+ - '@nestjs/bull'
116
+ - 'class-transformer'
117
+ - 'class-validator'
118
+ - 'nestjs-twilio'
149
119
  modules:
150
120
  - name: core
151
121
  resources:
@@ -186,34 +156,6 @@ nest-combo:
186
156
 
187
157
  ---
188
158
 
189
- ## Examples
190
-
191
- ### Create a Full Project from a YAML File
192
-
193
- ```bash
194
- nest-combo -f project.yml
195
- ```
196
-
197
- ### Generate a Module, Controller, and Service
198
-
199
- ```bash
200
- nest-combo users -m -c -s
201
- ```
202
-
203
- ### Generate a Module and Service Without Spec Files
204
-
205
- ```bash
206
- nest-combo auth -m -s --ns
207
- ```
208
-
209
- ### Dry Run: Check What Would Be Generated
210
-
211
- ```bash
212
- nest-combo products -m -c --dr
213
- ```
214
-
215
- ---
216
-
217
159
  ## Contributing
218
160
 
219
161
  We welcome contributions! Here’s how you can help:
package/bin/cli.js CHANGED
@@ -1,218 +1,166 @@
1
1
  #!/usr/bin/env node
2
- import { execSync } from "child_process";
3
- import fs from "fs";
4
- import path from "path";
5
- import chalk from "chalk";
6
- import yaml from "js-yaml";
7
- import {
8
- generateModule,
9
- generateController,
10
- generateService,
11
- generateInterceptor,
12
- generateGateway,
13
- generateMiddlware,
14
- generateProject,
15
- } from "../lib/generate.js";
16
- import { installDependencies } from "../lib/install.js";
17
- import { createRequire } from "module";
18
- import { validateYml } from "../lib/utils.js";
19
- const require = createRequire(import.meta.url);
20
- const { name, version } = require("../package.json");
21
-
2
+ import { execSync } from 'child_process';
3
+ import fs from 'fs';
4
+ import path from 'path';
5
+ import chalk from 'chalk';
6
+ import yaml from 'js-yaml';
7
+ import { generateProject } from '../lib/generate.js';
8
+ import resources from '../lib/resources.js';
9
+ import installDependencies from '../lib/installDependencies.js';
10
+ import { validateResources, validateYml } from '../lib/utils.js';
11
+ import { printBanner, showUsage, showVersion } from '../lib/outputs.js';
22
12
  const args = process.argv.slice(2);
23
- const resources = [
24
- {
25
- name: "module",
26
- flag: "-m",
27
- longFlag: "--module",
28
- generator: generateModule,
29
- },
30
- {
31
- name: "controller",
32
- flag: "-c",
33
- longFlag: "--controller",
34
- generator: generateController,
35
- },
36
- {
37
- name: "service",
38
- flag: "-s",
39
- longFlag: "--service",
40
- generator: generateService,
41
- },
42
- {
43
- name: "gateway",
44
- flag: "-g",
45
- longFlag: "--gateway",
46
- generator: generateGateway,
47
- },
48
- {
49
- name: "middleware",
50
- flag: "-mw",
51
- longFlag: "--middleware",
52
- generator: generateMiddlware,
53
- },
54
- {
55
- name: "interceptor",
56
- flag: "-itc",
57
- longFlag: "--interceptor",
58
- generator: generateInterceptor,
59
- },
60
- ];
61
13
 
62
- function main() {
14
+ export function main() {
63
15
  printBanner();
64
- const {
65
- askForHelp,
66
- askForVersion,
67
- moduleName,
68
- hasDryRun,
69
- hasNoSpec,
70
- hasYmlFile,
71
- } = getArgs();
16
+ const readArgs = getArgs();
72
17
 
73
- switch (true) {
74
- case askForVersion:
75
- showVersion();
76
- process.exit(0);
77
- break;
18
+ if (readArgs.askForVersion) {
19
+ showVersion();
20
+ return;
21
+ }
78
22
 
79
- case askForHelp:
80
- showUsage();
81
- process.exit(0);
82
- break;
23
+ if (readArgs.askForHelp) {
24
+ showUsage();
25
+ return;
26
+ }
83
27
 
84
- case hasYmlFile:
85
- const file = args[1];
86
- loadFromYml(file);
87
- process.exit(0);
88
- break;
28
+ if (readArgs.hasCreateNewProject) {
29
+ const packageManager = readArgs.hasPackageManager ? args[3] : undefined;
30
+ createNewProject(
31
+ readArgs.resourceName,
32
+ packageManager,
33
+ readArgs.doNotOpenVsCode,
34
+ );
35
+ return;
36
+ }
89
37
 
90
- default:
91
- execute(moduleName, hasNoSpec, hasDryRun);
38
+ if (readArgs.hasYmlFile) {
39
+ const file = args[1];
40
+ createFullProjectFromYmlFile(file);
41
+ return;
92
42
  }
93
- }
94
43
 
95
- function execute(moduleName, hasNoSpec, hasDryRun) {
96
- validate(moduleName);
97
- resources.forEach((component) => {
98
- if (args.includes(component.flag) || args.includes(component.longFlag)) {
99
- console.log(
100
- chalk.green(`Generating ${component.name} for module ${moduleName}`)
101
- );
102
- if (component.generator) {
103
- component.generator(moduleName, [
104
- hasNoSpec ? "--no-spec" : null,
105
- hasDryRun ? "--dry-run" : null,
106
- ]);
107
- } else {
108
- console.warn(
109
- chalk.yellow(`Warning:`) +
110
- ` Generator not implemented for ${component.name}`
111
- );
112
- }
113
- console.log(
114
- chalk.green("---------------------------------------------------")
115
- );
116
- }
117
- });
44
+ createResources(
45
+ readArgs.resourceName,
46
+ readArgs.hasNoSpec,
47
+ readArgs.hasDryRun,
48
+ );
118
49
  }
119
50
 
51
+ /**
52
+ * Return arguments from the user input command
53
+ * @returns {object} { resourceName,
54
+ askForVersion,
55
+ askForHelp,
56
+ hasNoSpec,
57
+ hasDryRun,
58
+ hasYmlFile,
59
+ hasCreateNewProject,
60
+ hasPackageManager
61
+ }
62
+ */
120
63
  function getArgs() {
121
- const moduleName = args[0];
122
- const askForVersion = args.includes("-v") || args.includes("--version");
123
- const askForHelp = args.includes("-h") || args.includes("--help");
124
- const hasNoSpec = args.includes("-ns") || args.includes("--no-spec");
125
- const hasDryRun = args.includes("-dr") || args.includes("--dry-run");
126
- const hasYmlFile = args.includes("-f") || args.includes("--file");
64
+ const resourceName = args[0];
65
+ const askForVersion = args.includes('-v') || args.includes('--version');
66
+ const askForHelp = args.includes('-h') || args.includes('--help');
67
+ const hasNoSpec = args.includes('-ns') || args.includes('--no-spec');
68
+ const hasDryRun = args.includes('-dr') || args.includes('--dry-run');
69
+ const hasYmlFile = args.includes('-f') || args.includes('--file');
70
+ const hasCreateNewProject =
71
+ args.includes('-new') || args.includes('--new-project');
72
+ const hasPackageManager =
73
+ args.includes('-p') || args.includes('--package-manager');
74
+ const doNotOpenVsCode = args.includes('-no-vscode');
127
75
 
128
76
  return {
129
- moduleName,
77
+ resourceName,
130
78
  askForVersion,
131
79
  askForHelp,
132
80
  hasNoSpec,
133
81
  hasDryRun,
134
82
  hasYmlFile,
135
- validateYmlFile,
83
+ hasCreateNewProject,
84
+ hasPackageManager,
85
+ doNotOpenVsCode,
136
86
  };
137
87
  }
138
88
 
139
- function showUsage() {
140
- console.log(`
141
- ${chalk.yellow("Usage:")} nest-combo <module-name> [options]
142
-
143
- ${chalk.yellow("Options:")}
144
- ${chalk.cyan("-m, --module")} Generate a Module
145
- ${chalk.cyan("-c, --controller")} Generate a Controller
146
- ${chalk.cyan("-s, --service")} Generate a Service
147
- ${chalk.cyan("-g, --gateway")} Generate a Gateway
148
- ${chalk.cyan("-mw, --middleware")} Generate Middleware
149
- ${chalk.cyan("-itc, --interceptor")} Generate an Interceptor
150
- ${chalk.cyan("-f, --file")} Generate project from yml file
151
-
152
- ${chalk.bgMagenta("Optional:")}
153
- ${chalk.cyan("-ns, --no-spec")} Do not generate spec (test) files
154
- ${chalk.cyan(
155
- "-dr, --dry-run"
156
- )} Report actions that would be taken without writing out results.
157
-
158
- ${chalk.yellow("Example:")}
159
- nest-combo users -m -c -s
160
- nest-combo -f project.yml
161
- `);
162
- }
163
-
164
- function showVersion() {
165
- console.log(chalk.green(`${name} - version: ${version}`));
166
- }
167
-
168
- function validate(moduleName) {
169
- if (!moduleName) {
170
- console.error(chalk.red("Error:") + " Module name is required.");
171
- showUsage();
172
- process.exit(1);
173
- }
174
- const hasComponentFlags = resources.some(
175
- (component) =>
176
- args.includes(component.flag) || args.includes(component.longFlag)
177
- );
178
-
179
- if (!hasComponentFlags) {
180
- console.error(
181
- chalk.red("Error:") +
182
- ` At least one flag (${resources
183
- .map((resource) => resource.flag)
184
- .join(",")}) is required.`
185
- );
186
- showUsage();
89
+ /**
90
+ * Genrate resources like Modules, Controller, Services, etc
91
+ * @param {string} resourceName - Module/Controller/Service/etc name
92
+ * @param {boolean} hasNoSpec - if true do not generate spec files
93
+ * @param {boolean} hasDryRun - if true dry run mode
94
+ * @throws {Error} Throws an error if something goes wrong
95
+ */
96
+ function createResources(resourceName, hasNoSpec, hasDryRun) {
97
+ try {
98
+ validateResources(resourceName, args);
99
+ resources.forEach((component) => {
100
+ if (args.includes(component.flag) || args.includes(component.longFlag)) {
101
+ console.log(
102
+ chalk.green(`Generating ${component.name} for ${resourceName}`),
103
+ );
104
+ if (component.generator) {
105
+ component.generator(resourceName, [
106
+ hasNoSpec ? '--no-spec' : null,
107
+ hasDryRun ? '--dry-run' : null,
108
+ ]);
109
+ } else {
110
+ console.warn(
111
+ chalk.yellow(`Warning:`) +
112
+ ` Generator not implemented for ${component.name}`,
113
+ );
114
+ }
115
+ console.log(
116
+ chalk.green('---------------------------------------------------'),
117
+ );
118
+ }
119
+ });
120
+ } catch (error) {
121
+ console.error(chalk.red(`Error creating resources: ${error.message}`));
187
122
  process.exit(1);
188
123
  }
189
124
  }
190
125
 
191
- function loadFromYml(file) {
126
+ /**
127
+ * Creates a full NestJS project based on the configuration provided in a YAML file.
128
+ *
129
+ * This function performs the following steps:
130
+ * 1. Parses the YAML file to extract project configuration (e.g., project name, dependencies, modules, etc.).
131
+ * 2. Generates the base NestJS project structure using the `nest-cli`.
132
+ * 3. Installs the specified project dependencies.
133
+ * 4. Recursively creates nested modules, controllers, services, and other resources as defined in the YAML file.
134
+ * 5. Opens the generated project in Visual Studio Code once it's done.
135
+ *
136
+ * @param {string} filePath - The absolute or relative path to the YAML configuration file.
137
+ * @throws {Error} Throws an error if the YAML file is invalid, missing required fields, or if any step fails during execution.
138
+ */
139
+ function createFullProjectFromYmlFile(filePath) {
192
140
  try {
193
- const fileContent = fs.readFileSync(file, "utf-8");
141
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
194
142
  const ymlData = yaml.load(fileContent);
195
143
 
196
144
  validateYml(ymlData);
197
145
 
198
- const content = ymlData["nest-combo"];
199
- const projectName = content["project-name"];
200
- const packageManager = content["package-manager"] || "npm";
201
- const dependencies = Array.isArray(content["dependencies"])
202
- ? content["dependencies"]
146
+ const content = ymlData['nest-combo'];
147
+ const projectName = content['project-name'];
148
+ const packageManager = content['package-manager'] || 'npm';
149
+ const dependencies = Array.isArray(content['dependencies'])
150
+ ? content['dependencies']
203
151
  : [];
204
- const modules = Array.isArray(content["modules"]) ? content["modules"] : [];
152
+ const modules = Array.isArray(content['modules']) ? content['modules'] : [];
205
153
 
206
- const openVsCode = content["open-vscode"];
154
+ const openVsCode = content['open-vscode'];
207
155
 
208
156
  console.log(chalk.green(`Generating project: ${projectName}`));
209
157
  generateProject(projectName, [`-p ${packageManager}`]);
210
158
 
211
159
  if (dependencies.length > 0) {
212
- console.log(chalk.cyan("Installing dependencies..."));
160
+ console.log(chalk.cyan('Installing dependencies...'));
213
161
  installDependencies(projectName, dependencies);
214
162
  } else {
215
- console.log(chalk.yellow("No dependencies to install."));
163
+ console.log(chalk.yellow('No dependencies to install.'));
216
164
  }
217
165
 
218
166
  const recursiveAddModule = (parentModule, modules) => {
@@ -231,8 +179,8 @@ function loadFromYml(file) {
231
179
  if (!Array.isArray(moduleResources)) {
232
180
  console.warn(
233
181
  chalk.yellow(
234
- `Invalid resources for module: ${pathModule}. Skipping.`
235
- )
182
+ `Invalid resources for module: ${pathModule}. Skipping.`,
183
+ ),
236
184
  );
237
185
  continue;
238
186
  }
@@ -242,17 +190,17 @@ function loadFromYml(file) {
242
190
 
243
191
  if (!resource) {
244
192
  console.warn(
245
- chalk.yellow(`Unknown resource type: ${resourceName}. Skipping.`)
193
+ chalk.yellow(`Unknown resource type: ${resourceName}. Skipping.`),
246
194
  );
247
195
  return;
248
196
  }
249
197
 
250
198
  console.log(
251
- chalk.magenta(`Generating ${resourceName} for ${pathModule}`)
199
+ chalk.magenta(`Generating ${resourceName} for ${pathModule}`),
252
200
  );
253
201
  resource.generator(pathModule, options, projectName);
254
202
  console.log(
255
- chalk.green("---------------------------------------------------")
203
+ chalk.green('---------------------------------------------------'),
256
204
  );
257
205
  });
258
206
 
@@ -265,15 +213,13 @@ function loadFromYml(file) {
265
213
  recursiveAddModule(null, modules);
266
214
 
267
215
  if (openVsCode) {
268
- const workingDirectory = path.join(process.cwd(), projectName);
269
- const command = "code .";
270
- execSync(command, { cwd: workingDirectory });
216
+ CmdOpenVsCode(projectName);
271
217
  }
272
218
 
273
219
  console.log(
274
220
  chalk.green(
275
- "**************** succefully finished ************************** "
276
- )
221
+ '**************** succefully finished ************************** ',
222
+ ),
277
223
  );
278
224
  showVersion();
279
225
  } catch (error) {
@@ -282,24 +228,33 @@ function loadFromYml(file) {
282
228
  }
283
229
  }
284
230
 
285
- function printBanner() {
286
- console.log(
287
- chalk.magenta(`
288
- ███╗ ██╗███████╗███████╗████████╗ ██████╗ ██████╗ ███╗ ███╗██████╗ ██████╗
289
- ████╗ ██║██╔════╝██╔════╝╚══██╔══╝ ██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔═══██╗
290
- ██╔██╗ ██║█████╗ ███████╗ ██║ █████╗██║ ██║ ██║██╔████╔██║██████╔╝██║ ██║
291
- ██║╚██╗██║██╔══╝ ╚════██║ ██║ ╚════╝██║ ██║ ██║██║╚██╔╝██║██╔══██╗██║ ██║
292
- ██║ ╚████║███████╗███████║ ██║ ╚██████╗╚██████╔╝██║ ╚═╝ ██║██████╔╝╚██████╔╝
293
- ╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝
294
- `)
295
- );
296
- console.log(
297
- chalk.bgWhite(
298
- chalk.bold(
299
- `********************************************************************** version: ${version} `
300
- )
301
- )
302
- );
231
+ /**
232
+ * Creates a NestJS project and Open the generated project in Visual Studio Code once it's done
233
+ *
234
+ * @param {string} projectName - The projectName for the new project.
235
+ * @param {string} packageManagere - The packageManeger such npm, yarn or pnpm, by default it uses npm
236
+ * @throws {Error} Throws an error if something goes wrong.
237
+ *
238
+ */
239
+ function createNewProject(
240
+ projectName,
241
+ packageManager = 'npm',
242
+ doNotOpenVsCode = false,
243
+ ) {
244
+ try {
245
+ generateProject(projectName, [`-p ${packageManager}`]);
246
+ if (doNotOpenVsCode) return;
247
+ CmdOpenVsCode(projectName);
248
+ } catch (error) {
249
+ console.error(chalk.red(`Error: ${error.message}`));
250
+ process.exit(1);
251
+ }
252
+ }
253
+
254
+ function CmdOpenVsCode(directory) {
255
+ const workingDirectory = path.join(process.cwd(), directory);
256
+ const command = 'code .';
257
+ execSync(command, { cwd: workingDirectory });
303
258
  }
304
259
 
305
260
  main();
package/index.html CHANGED
@@ -1,4 +1,4 @@
1
- <!DOCTYPE html>
1
+ <!doctype html>
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />