create-backend-templates 1.0.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/Readme.md +129 -0
- package/bin/index.js +17 -0
- package/create-backend-cli-1.1.0.tgz +0 -0
- package/package.json +36 -0
- package/scripts/verify-templates.js +51 -0
- package/src/cli.js +166 -0
- package/src/config/repoMap.js +12 -0
- package/src/update.js +15 -0
- package/src/utils/env.js +45 -0
- package/src/utils/git.js +61 -0
- package/src/utils/installer.js +74 -0
- package/src/utils/scaffold.js +163 -0
- package/src/utils/templates.js +0 -0
- package/templates/express-ts-prisma-mysql/.env.example +2 -0
- package/templates/express-ts-prisma-mysql/README.md +21 -0
- package/templates/express-ts-prisma-mysql/package.json +47 -0
- package/templates/express-ts-prisma-mysql/src/index.ts +32 -0
- package/templates/express-ts-prisma-mysql/src/prisma/schema.prisma +16 -0
- package/templates/express-ts-prisma-mysql/tsconfig.json +19 -0
- package/templates/express-ts-prisma-postgres/.env.example +2 -0
- package/templates/express-ts-prisma-postgres/README.md +21 -0
- package/templates/express-ts-prisma-postgres/package.json +47 -0
- package/templates/express-ts-prisma-postgres/src/index.ts +32 -0
- package/templates/express-ts-prisma-postgres/src/prisma/schema.prisma +16 -0
- package/templates/express-ts-prisma-postgres/tsconfig.json +19 -0
- package/templates/nest-ts-prisma-mysql/.env.example +1 -0
- package/templates/nest-ts-prisma-mysql/README.md +21 -0
- package/templates/nest-ts-prisma-mysql/nest-cli.json +8 -0
- package/templates/nest-ts-prisma-mysql/package.json +71 -0
- package/templates/nest-ts-prisma-mysql/src/app.controller.ts +12 -0
- package/templates/nest-ts-prisma-mysql/src/app.module.ts +11 -0
- package/templates/nest-ts-prisma-mysql/src/app.service.ts +8 -0
- package/templates/nest-ts-prisma-mysql/src/main.ts +8 -0
- package/templates/nest-ts-prisma-mysql/src/prisma/prisma.module.ts +9 -0
- package/templates/nest-ts-prisma-mysql/src/prisma/prisma.service.ts +9 -0
- package/templates/nest-ts-prisma-mysql/src/prisma/schema.prisma +14 -0
- package/templates/nest-ts-prisma-mysql/tsconfig.json +21 -0
- package/templates/nest-ts-prisma-postgres/.env.example +1 -0
- package/templates/nest-ts-prisma-postgres/README.md +21 -0
- package/templates/nest-ts-prisma-postgres/nest-cli.json +8 -0
- package/templates/nest-ts-prisma-postgres/package.json +71 -0
- package/templates/nest-ts-prisma-postgres/src/app.controller.ts +12 -0
- package/templates/nest-ts-prisma-postgres/src/app.module.ts +11 -0
- package/templates/nest-ts-prisma-postgres/src/app.service.ts +8 -0
- package/templates/nest-ts-prisma-postgres/src/main.ts +8 -0
- package/templates/nest-ts-prisma-postgres/src/prisma/prisma.module.ts +9 -0
- package/templates/nest-ts-prisma-postgres/src/prisma/prisma.service.ts +9 -0
- package/templates/nest-ts-prisma-postgres/src/prisma/schema.prisma +14 -0
- package/templates/nest-ts-prisma-postgres/tsconfig.json +21 -0
- package/test.js +34 -0
package/Readme.md
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Backend Project Generator CLI
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/create-backend)
|
|
4
|
+
[](https://github.com/dee-raj/create-backend/blob/main/LICENSE)
|
|
5
|
+
[](https://nodejs.org/)
|
|
6
|
+
|
|
7
|
+
> ⚡ A fast, interactive CLI to scaffold modern backend projects with **Express** or **NestJS**, MongoDB/MySQL/Postgres, Prisma support, and optional features like Auth, Swagger, Docker, and ESLint.
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Scaffold backend projects with **Express.js** or **NestJS**
|
|
14
|
+
- Choose **TypeScript** or **JavaScript**
|
|
15
|
+
- Database support:
|
|
16
|
+
- MongoDB (Mongoose)
|
|
17
|
+
- MySQL (Prisma)
|
|
18
|
+
- PostgreSQL (Prisma)
|
|
19
|
+
- Optional extra features:
|
|
20
|
+
- JWT Authentication
|
|
21
|
+
- Swagger API Docs
|
|
22
|
+
- Docker support
|
|
23
|
+
- ESLint + Prettier setup
|
|
24
|
+
- Git initialized with first commit
|
|
25
|
+
- Interactive CLI with colorized UI and progress bars
|
|
26
|
+
- **Offline ready**: Bundled templates for instant scaffolding without git cloning
|
|
27
|
+
- Works on Windows, macOS, and Linux
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm install -g create-backend
|
|
35
|
+
````
|
|
36
|
+
|
|
37
|
+
or via **yarn**
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
yarn global add create-backend
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Usage
|
|
46
|
+
|
|
47
|
+
### List Available Templates
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
create-backend --list
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Output:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
• Express + TypeScript (Mongo) → express-ts-mongo
|
|
57
|
+
• NestJS + TypeScript (Mongo) → nest-ts-mongo
|
|
58
|
+
• Express + JavaScript (Mongo) → express-js-mongo
|
|
59
|
+
• Express + TS + Prisma (MySQL) → express-ts-prisma-mysql
|
|
60
|
+
• Express + TS + Prisma (Postgres) → express-ts-prisma-postgres
|
|
61
|
+
• Nest + TS + Prisma (MySQL) → nest-ts-prisma-mysql
|
|
62
|
+
• Nest + TS + Prisma (Postgres) → nest-ts-prisma-postgres
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
### Generate a New Project
|
|
68
|
+
|
|
69
|
+
Run the CLI:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
create-backend
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
Follow the prompts to:
|
|
76
|
+
|
|
77
|
+
1. Select **Framework** (Express / NestJS)
|
|
78
|
+
2. Choose **Language** (TypeScript / JavaScript)
|
|
79
|
+
3. Pick **Database** (MongoDB / MySQL / PostgreSQL)
|
|
80
|
+
4. Enable optional **features** (Auth, Swagger, Docker, ESLint)
|
|
81
|
+
5. Specify **Project Name**
|
|
82
|
+
|
|
83
|
+
The CLI will:
|
|
84
|
+
|
|
85
|
+
* Clone the selected template
|
|
86
|
+
* Generate `.env` for your database
|
|
87
|
+
* Install dependencies with progress bar
|
|
88
|
+
* Initialize git and create initial commit
|
|
89
|
+
* Optional features scaffolding
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### Example
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
? Choose Framework: Express
|
|
97
|
+
? Language: JavaScript
|
|
98
|
+
? Database: MongoDB
|
|
99
|
+
? Add Features: Auth, Swagger, Docker, ESLint
|
|
100
|
+
? Project Name: my-backend
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
After completion:
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
cd my-backend
|
|
107
|
+
npm run dev
|
|
108
|
+
# or
|
|
109
|
+
npm start
|
|
110
|
+
code .
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
---
|
|
114
|
+
|
|
115
|
+
## Contributing
|
|
116
|
+
|
|
117
|
+
Contributions are welcome! Please follow these steps:
|
|
118
|
+
|
|
119
|
+
1. Fork the repository
|
|
120
|
+
2. Create a feature branch: `git checkout -b feature/my-feature`
|
|
121
|
+
3. Commit your changes: `git commit -m 'Add my feature'`
|
|
122
|
+
4. Push to the branch: `git push origin feature/my-feature`
|
|
123
|
+
5. Open a Pull Request
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT © 2025 [Dhurbaraj N Joshi](https://github.com/dee-raj)
|
package/bin/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { runCLI, listTemplates } from "../src/cli.js";
|
|
3
|
+
import updateProject from "../src/update.js";
|
|
4
|
+
|
|
5
|
+
const args = process.argv.slice(2);
|
|
6
|
+
|
|
7
|
+
if (args.includes("--list")) {
|
|
8
|
+
listTemplates();
|
|
9
|
+
process.exit(0);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
if (args[0] === "update") {
|
|
13
|
+
updateProject(args[1]);
|
|
14
|
+
process.exit(0);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
runCLI();
|
|
Binary file
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-backend-templates",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "This is node backend creation with multiples templates and features like jwt & etc.",
|
|
5
|
+
"bin": {
|
|
6
|
+
"create-backend": "./bin/index.js"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"backend",
|
|
10
|
+
"templates",
|
|
11
|
+
"nodejs",
|
|
12
|
+
"express",
|
|
13
|
+
"jwt",
|
|
14
|
+
"nest",
|
|
15
|
+
"mongodb",
|
|
16
|
+
"mongoose",
|
|
17
|
+
"prisma",
|
|
18
|
+
"sql"
|
|
19
|
+
],
|
|
20
|
+
"license": "ISC",
|
|
21
|
+
"author": "Dhurbaraj N Joshi",
|
|
22
|
+
"type": "module",
|
|
23
|
+
"main": "bin/index.js",
|
|
24
|
+
"scripts": {
|
|
25
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"chalk": "^5.6.2",
|
|
29
|
+
"cli-progress": "^3.12.0",
|
|
30
|
+
"commander": "^14.0.2",
|
|
31
|
+
"execa": "^9.6.1",
|
|
32
|
+
"fs-extra": "^11.3.3",
|
|
33
|
+
"inquirer": "^13.1.0",
|
|
34
|
+
"ora": "^9.0.0"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import chalk from 'chalk';
|
|
4
|
+
import { fileURLToPath } from 'url';
|
|
5
|
+
|
|
6
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
7
|
+
const __dirname = path.dirname(__filename);
|
|
8
|
+
|
|
9
|
+
const templatesDir = path.join(__dirname, '../templates');
|
|
10
|
+
const requiredFiles = ['package.json', 'README.md', 'src/prisma/schema.prisma'];
|
|
11
|
+
|
|
12
|
+
const templates = [
|
|
13
|
+
'express-ts-prisma-mysql',
|
|
14
|
+
'express-ts-prisma-postgres',
|
|
15
|
+
'nest-ts-prisma-mysql',
|
|
16
|
+
'nest-ts-prisma-postgres'
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
console.log(chalk.blue('Verifying templates...\n'));
|
|
20
|
+
|
|
21
|
+
let hasErrors = false;
|
|
22
|
+
|
|
23
|
+
templates.forEach(template => {
|
|
24
|
+
const templatePath = path.join(templatesDir, template);
|
|
25
|
+
|
|
26
|
+
if (!fs.existsSync(templatePath)) {
|
|
27
|
+
console.log(chalk.red(`✖ Template missing: ${template}`));
|
|
28
|
+
hasErrors = true;
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
console.log(chalk.cyan(`Checking ${template}...`));
|
|
33
|
+
|
|
34
|
+
requiredFiles.forEach(file => {
|
|
35
|
+
const filePath = path.join(templatePath, file);
|
|
36
|
+
if (!fs.existsSync(filePath)) {
|
|
37
|
+
console.log(chalk.red(` ✖ Missing file: ${file}`));
|
|
38
|
+
hasErrors = true;
|
|
39
|
+
} else {
|
|
40
|
+
console.log(chalk.green(` ✔ ${file} exists`));
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
console.log('');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
if (hasErrors) {
|
|
47
|
+
console.log(chalk.red('Verification failed with errors.'));
|
|
48
|
+
process.exit(1);
|
|
49
|
+
} else {
|
|
50
|
+
console.log(chalk.green('All templates verified successfully!'));
|
|
51
|
+
}
|
package/src/cli.js
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import inquirer from "inquirer";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import scaffold from "./utils/scaffold.js";
|
|
4
|
+
import { ensureGitInstalled } from "./utils/git.js";
|
|
5
|
+
|
|
6
|
+
const headline = text => console.log(chalk.bold.bgBlue.white(`\n ${text} \n`));
|
|
7
|
+
|
|
8
|
+
const section = text => console.log(chalk.bold.cyan(`\n› ${text}`));
|
|
9
|
+
|
|
10
|
+
const success = text => console.log(chalk.green(`✔ ${text}`));
|
|
11
|
+
|
|
12
|
+
const warn = text => console.log(chalk.yellow(`⚠ ${text}`));
|
|
13
|
+
|
|
14
|
+
const error = text => console.log(chalk.bold.redBright(`\n✖ ${text}\n`));
|
|
15
|
+
|
|
16
|
+
export function listTemplates() {
|
|
17
|
+
headline("Available Templates");
|
|
18
|
+
|
|
19
|
+
const list = [
|
|
20
|
+
["Express + TypeScript (Mongo)", "express-ts-mongo"],
|
|
21
|
+
["NestJS + TypeScript (Mongo)", "nest-ts-mongo"],
|
|
22
|
+
["Express + JavaScript (Mongo)", "express-js-mongo"],
|
|
23
|
+
["Express + TS + Prisma (MySQL)", "express-ts-prisma-mysql"],
|
|
24
|
+
["Express + TS + Prisma (Postgres)", "express-ts-prisma-postgres"],
|
|
25
|
+
["Nest + TS + Prisma (MySQL)", "nest-ts-prisma-mysql"],
|
|
26
|
+
["Nest + TS + Prisma (Postgres)", "nest-ts-prisma-postgres"],
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
list.forEach(([label, key]) =>
|
|
30
|
+
console.log(`${chalk.white("•")} ${chalk.green(label)} ${chalk.gray(`→ ${key}`)}`)
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
console.log(chalk.dim("\nUsage: create-backend --list\n"));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
const delay = (ms) => new Promise(res => setTimeout(res, ms));
|
|
38
|
+
|
|
39
|
+
async function typeLine(text, speed = 40) {
|
|
40
|
+
for (let char of text) {
|
|
41
|
+
process.stdout.write(char);
|
|
42
|
+
await delay(speed);
|
|
43
|
+
}
|
|
44
|
+
process.stdout.write("\n");
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const banner = async () => {
|
|
48
|
+
console.log(
|
|
49
|
+
chalk.blueBright("\n╔══════════════════════════════════════╗") +
|
|
50
|
+
chalk.blueBright("\n║") + chalk.white.bold(" BACKEND PROJECT GENERATOR CLI ") + chalk.blueBright("║") +
|
|
51
|
+
chalk.blueBright("\n╚══════════════════════════════════════╝\n")
|
|
52
|
+
);
|
|
53
|
+
const lines = [
|
|
54
|
+
chalk.green("\n[~] Initializing Backend Generator..."),
|
|
55
|
+
chalk.green("[|] Loading Modules..."),
|
|
56
|
+
chalk.green("[/] Ready")
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
for (const line of lines) {
|
|
61
|
+
await typeLine(line, 10);
|
|
62
|
+
await delay(300);
|
|
63
|
+
}
|
|
64
|
+
console.log();
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
export async function runCLI() {
|
|
69
|
+
try {
|
|
70
|
+
await banner();
|
|
71
|
+
await ensureGitInstalled();
|
|
72
|
+
section("Select technologies\n");
|
|
73
|
+
|
|
74
|
+
const answers = await inquirer.prompt([
|
|
75
|
+
{
|
|
76
|
+
type: "rawlist",
|
|
77
|
+
name: "framework",
|
|
78
|
+
message: chalk.bold.white("Choose Framework"),
|
|
79
|
+
choices: [
|
|
80
|
+
{ name: chalk.cyan("Express"), value: "express" },
|
|
81
|
+
{ name: chalk.magenta("NestJS"), value: "nest" }
|
|
82
|
+
],
|
|
83
|
+
theme: {
|
|
84
|
+
style: {
|
|
85
|
+
highlight: (text) => chalk.underline(text)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
type: "rawlist",
|
|
91
|
+
name: "language",
|
|
92
|
+
message: chalk.bold.white("Language"),
|
|
93
|
+
choices: [
|
|
94
|
+
{ name: chalk.blueBright("TypeScript"), value: "ts" },
|
|
95
|
+
{ name: chalk.yellowBright("JavaScript"), value: "js" }
|
|
96
|
+
],
|
|
97
|
+
theme: {
|
|
98
|
+
style: {
|
|
99
|
+
highlight: (text) => chalk.underline(text)
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
type: "rawlist",
|
|
105
|
+
name: "database",
|
|
106
|
+
message: chalk.bold.white("Database"),
|
|
107
|
+
choices: [
|
|
108
|
+
{ name: chalk.green("MongoDB"), value: "mongo" },
|
|
109
|
+
{ name: chalk.blue("MySQL"), value: "mysql" },
|
|
110
|
+
{ name: chalk.blueBright("PostgreSQL"), value: "postgres" }
|
|
111
|
+
],
|
|
112
|
+
theme: {
|
|
113
|
+
style: {
|
|
114
|
+
highlight: (text) => chalk.underline(text)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
type: "checkbox",
|
|
120
|
+
name: "features",
|
|
121
|
+
message: chalk.bold.white("Add Features"),
|
|
122
|
+
choices: [
|
|
123
|
+
{ name: chalk.green("Auth (JWT)"), value: "auth" },
|
|
124
|
+
{ name: chalk.cyan("Swagger Docs"), value: "swagger" },
|
|
125
|
+
{ name: chalk.yellow("Docker Support"), value: "docker" },
|
|
126
|
+
{ name: chalk.magenta("ESLint Rules"), value: "eslint" }
|
|
127
|
+
],
|
|
128
|
+
theme: {
|
|
129
|
+
style: {
|
|
130
|
+
highlight: (text) => chalk.underline(text)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
type: "input",
|
|
136
|
+
name: "folder",
|
|
137
|
+
message: chalk.bold.white("Project Name"),
|
|
138
|
+
default: "backend-service"
|
|
139
|
+
}
|
|
140
|
+
]);
|
|
141
|
+
|
|
142
|
+
const { framework, language, database, features, folder } = answers;
|
|
143
|
+
|
|
144
|
+
let key = `${framework}-${language}-${database}`;
|
|
145
|
+
if (database !== "mongo") key = `${framework}-${language}-prisma-${database}`;
|
|
146
|
+
|
|
147
|
+
section("Template Selected");
|
|
148
|
+
console.log(chalk.green(`→ ${key}`));
|
|
149
|
+
|
|
150
|
+
section("Generating Project...");
|
|
151
|
+
await scaffold(key, folder, database, features);
|
|
152
|
+
|
|
153
|
+
success("Project created successfully.");
|
|
154
|
+
console.log(
|
|
155
|
+
chalk.white("\nNext steps") +
|
|
156
|
+
chalk.gray(" (copy & run):") +
|
|
157
|
+
"\n" +
|
|
158
|
+
chalk.green(` cd ${folder}\n npm run dev `) +
|
|
159
|
+
chalk.gray("// or npm start") +
|
|
160
|
+
"\n code .\n"
|
|
161
|
+
);
|
|
162
|
+
} catch (err) {
|
|
163
|
+
error(`Something went wrong: ${err.message}`);
|
|
164
|
+
process.exit(1);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export const repoMap = {
|
|
2
|
+
// available at this version
|
|
3
|
+
"express-ts-mongo": "https://github.com/dee-raj/backend-ts.git",
|
|
4
|
+
"nest-ts-mongo": "https://github.com/dee-raj/nest.git",
|
|
5
|
+
"express-js-mongo": "https://github.com/dee-raj/backend.git|devlopment",
|
|
6
|
+
|
|
7
|
+
// not available at this version
|
|
8
|
+
"express-ts-prisma-mysql": "templates/express-ts-prisma-mysql",
|
|
9
|
+
"express-ts-prisma-postgres": "templates/express-ts-prisma-postgres",
|
|
10
|
+
"nest-ts-prisma-mysql": "templates/nest-ts-prisma-mysql",
|
|
11
|
+
"nest-ts-prisma-postgres": "templates/nest-ts-prisma-postgres"
|
|
12
|
+
};
|
package/src/update.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import { execa } from "execa";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
|
|
5
|
+
export default async function updateProject(folder) {
|
|
6
|
+
const spinner = ora("Updating project...").start();
|
|
7
|
+
|
|
8
|
+
try {
|
|
9
|
+
if (fs.existsSync(`${folder}/.git`)) await execa("git", ["pull"], { cwd: folder });
|
|
10
|
+
await execa("npm", ["install"], { cwd: folder });
|
|
11
|
+
spinner.succeed("✔ Project updated");
|
|
12
|
+
} catch (e) {
|
|
13
|
+
spinner.fail("Update failed");
|
|
14
|
+
}
|
|
15
|
+
}
|
package/src/utils/env.js
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import readline from "readline";
|
|
4
|
+
|
|
5
|
+
async function ask(question) {
|
|
6
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
7
|
+
return new Promise(resolve => rl.question(question, ans => {
|
|
8
|
+
rl.close();
|
|
9
|
+
resolve(ans.trim().toLowerCase());
|
|
10
|
+
}));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function generateEnv(db, folder, projectName = "myapp") {
|
|
14
|
+
// DB template map
|
|
15
|
+
const envTemplates = {
|
|
16
|
+
mongo: `MONGODB_URI="mongodb://localhost:27017/${projectName}"\nPORT=5000`,
|
|
17
|
+
mysql: `DATABASE_URL="mysql://root:password@localhost:3306/${projectName}"\nPORT=5000`,
|
|
18
|
+
postgres: `DATABASE_URL="postgresql://user:password@localhost:5432/${projectName}?schema=public"\nPORT=5000`,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
if (!envTemplates[db]) {
|
|
22
|
+
console.log(chalk.red(`✘ Unknown database type: ${db}`));
|
|
23
|
+
console.log(chalk.yellow("Supported: mongo | mysql | postgres"));
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
fs.ensureDirSync(folder); // auto-create target folder if missing
|
|
28
|
+
const envPath = `${folder}/.env`;
|
|
29
|
+
|
|
30
|
+
// If .env already exists, confirm overwrite
|
|
31
|
+
if (fs.existsSync(envPath)) {
|
|
32
|
+
const confirm = await ask(chalk.yellow(".env already exists. Overwrite? (y/n): "));
|
|
33
|
+
if (confirm !== "y") return console.log(chalk.red("✘ Cancelled"));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fs.writeFileSync(envPath, envTemplates[db]);
|
|
37
|
+
|
|
38
|
+
// styled success output with typing animation
|
|
39
|
+
const message = "✔ .env file generated successfully";
|
|
40
|
+
for (let char of message) {
|
|
41
|
+
process.stdout.write(chalk.green(char));
|
|
42
|
+
await new Promise(res => setTimeout(res, 12));
|
|
43
|
+
}
|
|
44
|
+
console.log("\n");
|
|
45
|
+
};
|
package/src/utils/git.js
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import fs from "fs-extra";
|
|
4
|
+
import path from "path";
|
|
5
|
+
|
|
6
|
+
// small typing output utility
|
|
7
|
+
async function typeLog(text, color = chalk.white, speed = 10) {
|
|
8
|
+
for (let char of text) {
|
|
9
|
+
process.stdout.write(color(char));
|
|
10
|
+
await new Promise(res => setTimeout(res, speed));
|
|
11
|
+
}
|
|
12
|
+
process.stdout.write("\n");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export async function ensureGitInstalled() {
|
|
16
|
+
try {
|
|
17
|
+
const gv = await execa("git", ["--version"]);
|
|
18
|
+
console.log(chalk.green("✔ Found git is already installed and its version: ", gv.stdout));
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.log(chalk.red("\n✘ Git is not installed on this system."));
|
|
21
|
+
console.log(chalk.yellow("Install Git: https://git-scm.com/downloads\n"));
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export async function initGit(folder) {
|
|
27
|
+
try {
|
|
28
|
+
// check if .git already exists
|
|
29
|
+
if (fs.existsSync(path.join(folder, ".git"))) {
|
|
30
|
+
console.log(chalk.yellow("⚠ Git repository already initialized. Skipping init.\n"));
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// initialize repository
|
|
35
|
+
await typeLog("→ Initializing Git repository...", chalk.cyanBright);
|
|
36
|
+
|
|
37
|
+
await execa("git", ["init"], { cwd: folder });
|
|
38
|
+
await execa("git", ["add", "."], { cwd: folder });
|
|
39
|
+
await execa("git", ["commit", "-m", "Initial commit"], { cwd: folder });
|
|
40
|
+
|
|
41
|
+
// generate .gitignore if not exist
|
|
42
|
+
const gitignorePath = path.join(folder, ".gitignore");
|
|
43
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
44
|
+
fs.writeFileSync(gitignorePath, `
|
|
45
|
+
node_modules
|
|
46
|
+
.env
|
|
47
|
+
dist
|
|
48
|
+
build
|
|
49
|
+
coverage
|
|
50
|
+
*.log
|
|
51
|
+
`);
|
|
52
|
+
await typeLog("✔ .gitignore created", chalk.green);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
await typeLog("✔ Git initialized successfully and first commit created.", chalk.green);
|
|
56
|
+
|
|
57
|
+
} catch (err) {
|
|
58
|
+
console.log(chalk.red("\n✘ Git initialization failed."));
|
|
59
|
+
console.log(chalk.gray(err.message), "\n");
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { execa } from "execa";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import cliProgress from "cli-progress";
|
|
4
|
+
import ora from "ora";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
|
|
7
|
+
/* Detect available package manager */
|
|
8
|
+
async function detectPkgManager() {
|
|
9
|
+
const managers = ["pnpm", "yarn", "bun", "npm"];
|
|
10
|
+
for (const m of managers) {
|
|
11
|
+
try { await execa(m, ["-v"]); return m; }
|
|
12
|
+
catch { }
|
|
13
|
+
}
|
|
14
|
+
return "npm";
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export async function installDependencies(folder) {
|
|
18
|
+
console.log(chalk.cyan("\nInstalling dependencies...\n"));
|
|
19
|
+
|
|
20
|
+
const pkgManager = await detectPkgManager();
|
|
21
|
+
const spinner = ora(`Using ${pkgManager}...`).start();
|
|
22
|
+
|
|
23
|
+
await new Promise(res => setTimeout(res, 800));
|
|
24
|
+
spinner.succeed(chalk.green(`Detected package manager: ${pkgManager}`));
|
|
25
|
+
|
|
26
|
+
const bar = new cliProgress.SingleBar({
|
|
27
|
+
format: chalk.magenta("Progress") + " |" + chalk.cyan("{bar}") + "| {percentage}%"
|
|
28
|
+
}, cliProgress.Presets.shades_classic);
|
|
29
|
+
|
|
30
|
+
bar.start(100, 0);
|
|
31
|
+
|
|
32
|
+
let percent = 0;
|
|
33
|
+
const interval = setInterval(() => {
|
|
34
|
+
percent = Math.min(percent + 2, 95);
|
|
35
|
+
bar.update(percent);
|
|
36
|
+
}, 250);
|
|
37
|
+
|
|
38
|
+
const startTime = Date.now();
|
|
39
|
+
|
|
40
|
+
try {
|
|
41
|
+
const runner = execa(pkgManager, ["install"], { cwd: folder });
|
|
42
|
+
|
|
43
|
+
runner.stdout?.on("data", d => process.stdout.write(chalk.gray(d.toString())));
|
|
44
|
+
runner.stderr?.on("data", d => process.stdout.write(chalk.red(d.toString())));
|
|
45
|
+
|
|
46
|
+
await runner;
|
|
47
|
+
|
|
48
|
+
clearInterval(interval);
|
|
49
|
+
bar.update(100);
|
|
50
|
+
bar.stop();
|
|
51
|
+
|
|
52
|
+
const time = ((Date.now() - startTime) / 1000).toFixed(1);
|
|
53
|
+
console.log(chalk.green(`\n✔ Dependencies installed successfully in ${time}s\n`));
|
|
54
|
+
return true;
|
|
55
|
+
|
|
56
|
+
} catch (err) {
|
|
57
|
+
clearInterval(interval);
|
|
58
|
+
bar.stop();
|
|
59
|
+
console.log(chalk.red("\n✖ Dependency installation failed"));
|
|
60
|
+
console.log(chalk.red("Error:"), err.message);
|
|
61
|
+
|
|
62
|
+
const { retry } = await inquirer.prompt([
|
|
63
|
+
{
|
|
64
|
+
type: "confirm",
|
|
65
|
+
name: "retry",
|
|
66
|
+
message: "Retry installation?",
|
|
67
|
+
default: true
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
if (retry) return await installDependencies(folder);
|
|
72
|
+
else return false;
|
|
73
|
+
}
|
|
74
|
+
}
|