nest-combo 1.1.1 → 1.2.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.
@@ -0,0 +1,5 @@
1
+ node_modules/
2
+ dist/
3
+ coverage/
4
+
5
+ test-project/
package/README.MD CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![npm](https://img.shields.io/npm/v/nest-combo) ![npm](https://img.shields.io/npm/dt/nest-combo)
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
 
@@ -19,20 +19,21 @@ A CLI tool to generate NestJS modules, controllers, services, and other componen
19
19
 
20
20
  ---
21
21
 
22
- ## How it works
22
+ ## How It Works
23
23
 
24
- How Nest-Combo Works with NestJS CLI
24
+ ### How Nest-Combo Works with NestJS CLI
25
25
 
26
- If you have the NestJS CLI installed globally , nest-combo will automatically detect and use it to execute commands. This ensures compatibility with your existing global setup.
26
+ If you have the **NestJS CLI** installed globally, **nest-combo** will automatically detect and use it to execute commands. This ensures compatibility with your existing global setup.
27
27
 
28
- If the NestJS CLI is not installed globally, don't worry! nest-combo comes bundled with its own local version of the NestJS CLI. It will seamlessly fall back to this cached version to ensure smooth operation without requiring any additional setup from you.
29
- WIth Nest-Combo you will be able to speed you development process with single line commands.
28
+ If the NestJS CLI is not installed globally, don't worry! **nest-combo** comes bundled with its own local version of the NestJS CLI. It will seamlessly fall back to this cached version to ensure smooth operation without requiring any additional setup from you.
30
29
 
31
30
  ---
32
31
 
33
32
  ## Features
34
33
 
35
- - Generate NestJS modules, controllers, services, gateways, middleware, and interceptors with single line command.
34
+ - Load a full project from a YAML file.
35
+ - Create a new project and automatically open VsCode
36
+ - Generate NestJS modules, controllers, services, gateways, middleware, and interceptors with a single-line command.
36
37
  - Support for optional flags like `--no-spec` and `--dry-run`.
37
38
  - Colorful and user-friendly output using `chalk`.
38
39
  - Easy-to-use command-line interface.
@@ -60,15 +61,27 @@ nest-combo --version
60
61
  Run the CLI tool with the desired module name and options:
61
62
 
62
63
  ```bash
63
- nest-combo <module-name> [options]
64
+ nest-combo <<project|module>-name> [options]
64
65
  ```
65
66
 
66
- ### Example:
67
+ ### Example Commands
67
68
 
68
- To create a module, controller and a service in a single line command:
69
+ #### Create a project
69
70
 
70
71
  ```bash
71
- 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
79
+ ```
80
+
81
+ #### Create a Full Project from a YAML File
82
+
83
+ ```bash
84
+ nest-combo -f project.yml
72
85
  ```
73
86
 
74
87
  ---
@@ -85,27 +98,60 @@ nest-combo users -m -c -s
85
98
  | `-itc, --interceptor` | Generate an interceptor |
86
99
  | `-ns, --no-spec` | Do not generate `.spec.ts` test files |
87
100
  | `-dr, --dry-run` | Report actions that would be taken without writing out results |
101
+ | `-f, --file` | Create a project from a YAML file |
88
102
 
89
103
  ---
90
104
 
91
- ## Examples
92
-
93
- ### Generate a Module, Controller, and Service
94
-
95
- ```bash
96
- nest-combo users -m -c -s
97
- ```
98
-
99
- ### Generate a Module and Service Without Spec Files
100
-
101
- ```bash
102
- nest-combo auth -m -s --no-spec
103
- ```
104
-
105
- ### Dry Run: Check What Would Be Generated
106
-
107
- ```bash
108
- nest-combo products -m -c --dry-run
105
+ ### YAML Example for Loading a Full Project from Scratch
106
+
107
+ ```yaml
108
+ # YML example for loading a full project from scratch
109
+ nest-combo:
110
+ project-name: my-new-project
111
+ open-vscode: true # Open VSCode when the process is finished
112
+ package-manager: npm # npm | yarn | pnpm
113
+ dependencies:
114
+ - '@nestjs/config'
115
+ - '@nestjs/bull'
116
+ - 'class-transformer'
117
+ - 'class-validator'
118
+ - 'nestjs-twilio'
119
+ modules:
120
+ - name: core
121
+ resources:
122
+ - module
123
+ modules:
124
+ - name: user
125
+ resources:
126
+ - module
127
+ - controller
128
+ - service
129
+ options:
130
+ - --no-spec
131
+ modules:
132
+ - name: subUsers
133
+ resources:
134
+ - module
135
+ - controller
136
+ - service
137
+ options:
138
+ - --no-spec
139
+ - name: auth
140
+ resources:
141
+ - module
142
+ - controller
143
+ - service
144
+ - interceptor
145
+ - name: product
146
+ resources:
147
+ - module
148
+ - controller
149
+ - service
150
+ - name: payment
151
+ resources:
152
+ - module
153
+ - controller
154
+ - service
109
155
  ```
110
156
 
111
157
  ---
package/bin/cli.js CHANGED
@@ -1,221 +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");
127
- const validateYmlFile =
128
- args.includes("-vf") || args.includes("--validate-yml");
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');
129
75
 
130
76
  return {
131
- moduleName,
77
+ resourceName,
132
78
  askForVersion,
133
79
  askForHelp,
134
80
  hasNoSpec,
135
81
  hasDryRun,
136
82
  hasYmlFile,
137
- validateYmlFile,
83
+ hasCreateNewProject,
84
+ hasPackageManager,
85
+ doNotOpenVsCode,
138
86
  };
139
87
  }
140
88
 
141
- function showUsage() {
142
- console.log(`
143
- ${chalk.yellow("Usage:")} nest-combo <module-name> [options]
144
-
145
- ${chalk.yellow("Options:")}
146
- ${chalk.cyan("-m, --module")} Generate a Module
147
- ${chalk.cyan("-c, --controller")} Generate a Controller
148
- ${chalk.cyan("-s, --service")} Generate a Service
149
- ${chalk.cyan("-g, --gateway")} Generate a Gateway
150
- ${chalk.cyan("-mw, --middleware")} Generate Middleware
151
- ${chalk.cyan("-itc, --interceptor")} Generate an Interceptor
152
- ${chalk.cyan("-f, --file")} Generate project from yml file
153
- ${chalk.cyan("-vf, --validate-yml")} Validate Yml File
154
-
155
- ${chalk.bgMagenta("Optional:")}
156
- ${chalk.cyan("-ns, --no-spec")} Do not generate spec (test) files
157
- ${chalk.cyan(
158
- "-dr, --dry-run"
159
- )} Report actions that would be taken without writing out results.
160
-
161
- ${chalk.yellow("Example:")}
162
- nest-combo users -m -c -s
163
- nest-combo -f project.yml
164
- `);
165
- }
166
-
167
- function showVersion() {
168
- console.log(chalk.green(`${name} - version: ${version}`));
169
- }
170
-
171
- function validate(moduleName) {
172
- if (!moduleName) {
173
- console.error(chalk.red("Error:") + " Module name is required.");
174
- showUsage();
175
- process.exit(1);
176
- }
177
- const hasComponentFlags = resources.some(
178
- (component) =>
179
- args.includes(component.flag) || args.includes(component.longFlag)
180
- );
181
-
182
- if (!hasComponentFlags) {
183
- console.error(
184
- chalk.red("Error:") +
185
- ` At least one flag (${resources
186
- .map((resource) => resource.flag)
187
- .join(",")}) is required.`
188
- );
189
- 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}`));
190
122
  process.exit(1);
191
123
  }
192
124
  }
193
125
 
194
- 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) {
195
140
  try {
196
- const fileContent = fs.readFileSync(file, "utf-8");
141
+ const fileContent = fs.readFileSync(filePath, 'utf-8');
197
142
  const ymlData = yaml.load(fileContent);
198
143
 
199
144
  validateYml(ymlData);
200
145
 
201
- const content = ymlData["nest-combo"];
202
- const projectName = content["project-name"];
203
- const packageManager = content["package-manager"] || "npm";
204
- const dependencies = Array.isArray(content["dependencies"])
205
- ? 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']
206
151
  : [];
207
- const modules = Array.isArray(content["modules"]) ? content["modules"] : [];
152
+ const modules = Array.isArray(content['modules']) ? content['modules'] : [];
208
153
 
209
- const openVsCode = content["open-vscode"];
154
+ const openVsCode = content['open-vscode'];
210
155
 
211
156
  console.log(chalk.green(`Generating project: ${projectName}`));
212
157
  generateProject(projectName, [`-p ${packageManager}`]);
213
158
 
214
159
  if (dependencies.length > 0) {
215
- console.log(chalk.blue("Installing dependencies..."));
160
+ console.log(chalk.cyan('Installing dependencies...'));
216
161
  installDependencies(projectName, dependencies);
217
162
  } else {
218
- console.log(chalk.yellow("No dependencies to install."));
163
+ console.log(chalk.yellow('No dependencies to install.'));
219
164
  }
220
165
 
221
166
  const recursiveAddModule = (parentModule, modules) => {
@@ -234,8 +179,8 @@ function loadFromYml(file) {
234
179
  if (!Array.isArray(moduleResources)) {
235
180
  console.warn(
236
181
  chalk.yellow(
237
- `Invalid resources for module: ${pathModule}. Skipping.`
238
- )
182
+ `Invalid resources for module: ${pathModule}. Skipping.`,
183
+ ),
239
184
  );
240
185
  continue;
241
186
  }
@@ -245,17 +190,17 @@ function loadFromYml(file) {
245
190
 
246
191
  if (!resource) {
247
192
  console.warn(
248
- chalk.yellow(`Unknown resource type: ${resourceName}. Skipping.`)
193
+ chalk.yellow(`Unknown resource type: ${resourceName}. Skipping.`),
249
194
  );
250
195
  return;
251
196
  }
252
197
 
253
198
  console.log(
254
- chalk.magenta(`Generating ${resourceName} for ${pathModule}`)
199
+ chalk.magenta(`Generating ${resourceName} for ${pathModule}`),
255
200
  );
256
201
  resource.generator(pathModule, options, projectName);
257
202
  console.log(
258
- chalk.green("---------------------------------------------------")
203
+ chalk.green('---------------------------------------------------'),
259
204
  );
260
205
  });
261
206
 
@@ -268,15 +213,13 @@ function loadFromYml(file) {
268
213
  recursiveAddModule(null, modules);
269
214
 
270
215
  if (openVsCode) {
271
- const workingDirectory = path.join(process.cwd(), projectName);
272
- const command = "code .";
273
- execSync(command, { cwd: workingDirectory });
216
+ CmdOpenVsCode(projectName);
274
217
  }
275
218
 
276
219
  console.log(
277
220
  chalk.green(
278
- "**************** succefully finished ************************** "
279
- )
221
+ '**************** succefully finished ************************** ',
222
+ ),
280
223
  );
281
224
  showVersion();
282
225
  } catch (error) {
@@ -285,24 +228,33 @@ function loadFromYml(file) {
285
228
  }
286
229
  }
287
230
 
288
- function printBanner() {
289
- console.log(
290
- chalk.magenta(`
291
- ███╗ ██╗███████╗███████╗████████╗ ██████╗ ██████╗ ███╗ ███╗██████╗ ██████╗
292
- ████╗ ██║██╔════╝██╔════╝╚══██╔══╝ ██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔═══██╗
293
- ██╔██╗ ██║█████╗ ███████╗ ██║ █████╗██║ ██║ ██║██╔████╔██║██████╔╝██║ ██║
294
- ██║╚██╗██║██╔══╝ ╚════██║ ██║ ╚════╝██║ ██║ ██║██║╚██╔╝██║██╔══██╗██║ ██║
295
- ██║ ╚████║███████╗███████║ ██║ ╚██████╗╚██████╔╝██║ ╚═╝ ██║██████╔╝╚██████╔╝
296
- ╚═╝ ╚═══╝╚══════╝╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═════╝ ╚═════╝
297
- `)
298
- );
299
- console.log(
300
- chalk.bgWhite(
301
- chalk.bold(
302
- `********************************************************************** version: ${version} `
303
- )
304
- )
305
- );
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 });
306
258
  }
307
259
 
308
260
  main();
package/demo.mp4 ADDED
Binary file
package/index.html ADDED
@@ -0,0 +1,27 @@
1
+ <!doctype html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
+ <title>Video Demo</title>
7
+ <style>
8
+ body {
9
+ font-family: Arial, sans-serif;
10
+ text-align: center;
11
+ margin-top: 50px;
12
+ }
13
+ video {
14
+ max-width: 100%;
15
+ height: auto;
16
+ }
17
+ </style>
18
+ </head>
19
+ <body>
20
+ <h1>Video Demo</h1>
21
+ <video controls>
22
+ <source src="./demo.mp4" type="video/mp4" />
23
+ Your browser does not support the video tag.
24
+ </video>
25
+ <p>Watch the demo video above.</p>
26
+ </body>
27
+ </html>