create-express-mongo-ts 1.0.0 → 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.
- package/README.md +3 -3
- package/bin/cli.js +185 -130
- package/package.json +6 -2
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
# create-express-mongo
|
|
1
|
+
# create-express-mongo-ts
|
|
2
2
|
|
|
3
3
|
Create Express + MongoDB applications with TypeScript, authentication, and best practices out of the box.
|
|
4
4
|
|
|
5
|
-
[](https://www.npmjs.com/package/create-express-mongo)
|
|
5
|
+
[](https://www.npmjs.com/package/create-express-mongo-ts)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
7
|
|
|
8
8
|
## Quick Start
|
|
9
9
|
|
|
10
10
|
```bash
|
|
11
|
-
npx create-express-mongo my-app
|
|
11
|
+
npx create-express-mongo-ts my-app
|
|
12
12
|
cd my-app
|
|
13
13
|
npm install
|
|
14
14
|
cp .env.example .env
|
package/bin/cli.js
CHANGED
|
@@ -1,104 +1,128 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
// Colors for console output
|
|
8
|
-
const colors = {
|
|
9
|
-
reset: '\x1b[0m',
|
|
10
|
-
bright: '\x1b[1m',
|
|
11
|
-
green: '\x1b[32m',
|
|
12
|
-
cyan: '\x1b[36m',
|
|
13
|
-
yellow: '\x1b[33m',
|
|
14
|
-
red: '\x1b[31m',
|
|
15
|
-
};
|
|
1
|
+
import inquirer from 'inquirer';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import { execSync } from 'child_process';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
16
7
|
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
success: (msg) => console.log(`${colors.green}✔${colors.reset} ${msg}`),
|
|
20
|
-
warn: (msg) => console.log(`${colors.yellow}⚠${colors.reset} ${msg}`),
|
|
21
|
-
error: (msg) => console.log(`${colors.red}✖${colors.reset} ${msg}`),
|
|
22
|
-
};
|
|
8
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
9
|
+
const __dirname = path.dirname(__filename);
|
|
23
10
|
|
|
24
|
-
|
|
25
|
-
const
|
|
11
|
+
const GITLAB_CI_FILE = '.gitlab-ci.yml';
|
|
12
|
+
const GITHUB_CI_FOLDER = '.github';
|
|
13
|
+
const PACKAGE_JSON = 'package.json';
|
|
26
14
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
)
|
|
32
|
-
|
|
33
|
-
|
|
15
|
+
const styles = {
|
|
16
|
+
command: (cmd) => chalk.cyan.bold(cmd),
|
|
17
|
+
path: (p) => chalk.gray(p),
|
|
18
|
+
success: (msg) => chalk.green(msg),
|
|
19
|
+
warning: (msg) => chalk.yellow(msg),
|
|
20
|
+
error: (msg) => chalk.red(msg),
|
|
21
|
+
heading: (msg) => chalk.bold(msg),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
async function createExpressMongo() {
|
|
34
25
|
console.log(
|
|
35
|
-
|
|
26
|
+
chalk.cyan.bold('\n🚀 Create Express MongoDB TypeScript App\n'),
|
|
36
27
|
);
|
|
37
|
-
process.exit(1);
|
|
38
|
-
}
|
|
39
28
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const templatePath = path.join(__dirname, '..', 'template');
|
|
29
|
+
// Get project name from command line or prompt
|
|
30
|
+
let projectName = process.argv[2];
|
|
43
31
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
32
|
+
const answers = await inquirer.prompt([
|
|
33
|
+
{
|
|
34
|
+
type: 'input',
|
|
35
|
+
name: 'appName',
|
|
36
|
+
message: 'What is your app name?',
|
|
37
|
+
default: projectName || 'my-express-mongo-app',
|
|
38
|
+
validate(input) {
|
|
39
|
+
if (!input.trim()) return 'App name cannot be empty';
|
|
40
|
+
if (!/^[a-z0-9-_]+$/i.test(input))
|
|
41
|
+
return 'App name can only contain letters, numbers, hyphens and underscores';
|
|
42
|
+
return true;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: 'list',
|
|
47
|
+
name: 'gitProvider',
|
|
48
|
+
message: 'Which Git provider do you want to use?',
|
|
49
|
+
choices: [
|
|
50
|
+
{ name: 'GitHub', value: 'github' },
|
|
51
|
+
{ name: 'GitLab', value: 'gitlab' },
|
|
52
|
+
{ name: 'None', value: 'none' },
|
|
53
|
+
],
|
|
54
|
+
default: 'github',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'confirm',
|
|
58
|
+
name: 'initGit',
|
|
59
|
+
message: 'Initialize a git repository?',
|
|
60
|
+
default: true,
|
|
61
|
+
},
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
createApp(answers);
|
|
53
65
|
}
|
|
54
66
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
);
|
|
59
|
-
console.log();
|
|
67
|
+
function createApp({ appName, gitProvider, initGit }) {
|
|
68
|
+
const targetDir = path.join(process.cwd(), appName);
|
|
69
|
+
const templateDir = path.join(__dirname, '../template');
|
|
60
70
|
|
|
61
|
-
//
|
|
62
|
-
fs.
|
|
71
|
+
// Check if directory exists
|
|
72
|
+
if (fs.existsSync(targetDir)) {
|
|
73
|
+
console.log(styles.error(`\n✖ Folder "${appName}" already exists.`));
|
|
74
|
+
process.exit(1);
|
|
75
|
+
}
|
|
63
76
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
console.log(
|
|
78
|
+
styles.heading(
|
|
79
|
+
`\nCreating a new Express + MongoDB app in ${styles.path(
|
|
80
|
+
targetDir,
|
|
81
|
+
)}\n`,
|
|
82
|
+
),
|
|
83
|
+
);
|
|
68
84
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
// Copy template files
|
|
86
|
+
console.log(chalk.cyan('ℹ') + ' Copying template files...');
|
|
87
|
+
copyDir(templateDir, targetDir);
|
|
88
|
+
console.log(styles.success('✔ Template files copied successfully.'));
|
|
72
89
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
90
|
+
// Handle git provider - remove unused CI files
|
|
91
|
+
if (gitProvider === 'github') {
|
|
92
|
+
const gitlabPath = path.join(targetDir, GITLAB_CI_FILE);
|
|
93
|
+
if (fs.existsSync(gitlabPath)) {
|
|
94
|
+
fs.rmSync(gitlabPath, { recursive: true, force: true });
|
|
95
|
+
}
|
|
96
|
+
} else if (gitProvider === 'gitlab') {
|
|
97
|
+
const githubPath = path.join(targetDir, GITHUB_CI_FOLDER);
|
|
98
|
+
if (fs.existsSync(githubPath)) {
|
|
99
|
+
fs.rmSync(githubPath, { recursive: true, force: true });
|
|
77
100
|
}
|
|
101
|
+
} else {
|
|
102
|
+
// Remove both if none selected
|
|
103
|
+
const gitlabPath = path.join(targetDir, GITLAB_CI_FILE);
|
|
104
|
+
const githubPath = path.join(targetDir, GITHUB_CI_FOLDER);
|
|
105
|
+
if (fs.existsSync(gitlabPath))
|
|
106
|
+
fs.rmSync(gitlabPath, { recursive: true, force: true });
|
|
107
|
+
if (fs.existsSync(githubPath))
|
|
108
|
+
fs.rmSync(githubPath, { recursive: true, force: true });
|
|
78
109
|
}
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
try {
|
|
82
|
-
// Copy template files
|
|
83
|
-
log.info('Copying template files...');
|
|
84
|
-
copyDir(templatePath, projectPath);
|
|
85
|
-
log.success('Template files copied successfully.');
|
|
86
110
|
|
|
87
111
|
// Update package.json with project name
|
|
88
|
-
const
|
|
89
|
-
if (fs.existsSync(
|
|
90
|
-
const
|
|
91
|
-
|
|
112
|
+
const pkgPath = path.join(targetDir, PACKAGE_JSON);
|
|
113
|
+
if (fs.existsSync(pkgPath)) {
|
|
114
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf-8'));
|
|
115
|
+
pkg.name = appName;
|
|
116
|
+
pkg.version = '1.0.0';
|
|
117
|
+
pkg.description = `${appName} - Express + MongoDB TypeScript application`;
|
|
118
|
+
fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
|
|
119
|
+
console.log(
|
|
120
|
+
styles.success('✔ Updated package.json with project name.'),
|
|
92
121
|
);
|
|
93
|
-
packageJson.name = projectName;
|
|
94
|
-
packageJson.version = '1.0.0';
|
|
95
|
-
packageJson.description = `${projectName} - Express + MongoDB application`;
|
|
96
|
-
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
97
|
-
log.success('Updated package.json with project name.');
|
|
98
122
|
}
|
|
99
123
|
|
|
100
124
|
// Create .env.example file
|
|
101
|
-
const envExamplePath = path.join(
|
|
125
|
+
const envExamplePath = path.join(targetDir, '.env.example');
|
|
102
126
|
if (!fs.existsSync(envExamplePath)) {
|
|
103
127
|
const envContent = `# Server Configuration
|
|
104
128
|
PORT=3000
|
|
@@ -107,35 +131,38 @@ NODE_ENV=development
|
|
|
107
131
|
# Database Configuration
|
|
108
132
|
DB_HOST=localhost
|
|
109
133
|
DB_PORT=27017
|
|
110
|
-
DB_NAME=${
|
|
134
|
+
DB_NAME=${appName}
|
|
111
135
|
DB_USER=
|
|
112
|
-
|
|
136
|
+
DB_USER_PASSWORD=
|
|
113
137
|
DB_MIN_POOL_SIZE=2
|
|
114
138
|
DB_MAX_POOL_SIZE=5
|
|
115
139
|
|
|
116
140
|
# JWT Configuration
|
|
117
141
|
ACCESS_TOKEN_VALIDITY_SEC=3600
|
|
118
142
|
REFRESH_TOKEN_VALIDITY_SEC=86400
|
|
143
|
+
TOKEN_ISSUER=${appName}
|
|
144
|
+
TOKEN_AUDIENCE=${appName}
|
|
119
145
|
|
|
120
146
|
# CORS Configuration
|
|
121
|
-
|
|
147
|
+
ORIGIN_URL=*
|
|
122
148
|
|
|
123
149
|
# Logging
|
|
124
|
-
|
|
150
|
+
LOG_DIRECTORY=logs
|
|
125
151
|
`;
|
|
126
152
|
fs.writeFileSync(envExamplePath, envContent);
|
|
127
|
-
log.success('Created .env.example file.');
|
|
153
|
+
console.log(styles.success('✔ Created .env.example file.'));
|
|
128
154
|
}
|
|
129
155
|
|
|
130
156
|
// Initialize git repository
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
157
|
+
if (initGit) {
|
|
158
|
+
console.log(chalk.cyan('ℹ') + ' Initializing git repository...');
|
|
159
|
+
try {
|
|
160
|
+
execSync('git init', { cwd: targetDir, stdio: 'ignore' });
|
|
161
|
+
|
|
162
|
+
// Create .gitignore if it doesn't exist
|
|
163
|
+
const gitignorePath = path.join(targetDir, '.gitignore');
|
|
164
|
+
if (!fs.existsSync(gitignorePath)) {
|
|
165
|
+
const gitignoreContent = `# Dependencies
|
|
139
166
|
node_modules/
|
|
140
167
|
|
|
141
168
|
# Build output
|
|
@@ -169,49 +196,77 @@ keys/*.key
|
|
|
169
196
|
# TypeScript cache
|
|
170
197
|
*.tsbuildinfo
|
|
171
198
|
`;
|
|
172
|
-
|
|
199
|
+
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
200
|
+
}
|
|
201
|
+
console.log(styles.success('✔ Initialized git repository.'));
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.log(
|
|
204
|
+
styles.warning('⚠ Could not initialize git repository.'),
|
|
205
|
+
);
|
|
173
206
|
}
|
|
174
|
-
log.success('Initialized git repository.');
|
|
175
|
-
} catch (error) {
|
|
176
|
-
log.warn(
|
|
177
|
-
'Could not initialize git repository. Please initialize it manually.',
|
|
178
|
-
);
|
|
179
207
|
}
|
|
180
208
|
|
|
181
209
|
// Success message
|
|
182
|
-
console.log();
|
|
183
210
|
console.log(
|
|
184
|
-
|
|
211
|
+
styles.success(`\n✨ Success! Created ${appName} at ${targetDir}\n`),
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
console.log(styles.heading('Next Steps:\n'));
|
|
215
|
+
console.log(
|
|
216
|
+
` 👉 Go to project directory: ${styles.command(`cd ${appName}`)}`,
|
|
217
|
+
);
|
|
218
|
+
console.log(
|
|
219
|
+
` 👉 Install dependencies: ${styles.command('npm install')}`,
|
|
220
|
+
);
|
|
221
|
+
console.log(
|
|
222
|
+
` 👉 Set up environment: ${styles.command(
|
|
223
|
+
'cp .env.example .env',
|
|
224
|
+
)}`,
|
|
225
|
+
);
|
|
226
|
+
console.log(
|
|
227
|
+
` 👉 Run the application: ${styles.command('npm run dev')}`,
|
|
185
228
|
);
|
|
186
229
|
console.log();
|
|
187
|
-
console.log('
|
|
188
|
-
console.log(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
console.log(
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
console.log(
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
console.log(` ${
|
|
202
|
-
console.log(
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
console.log();
|
|
206
|
-
console.log(` ${colors.cyan}cd${colors.reset} ${projectName}`);
|
|
207
|
-
console.log(` ${colors.cyan}npm install${colors.reset}`);
|
|
208
|
-
console.log(` ${colors.cyan}cp .env.example .env${colors.reset}`);
|
|
209
|
-
console.log(` ${colors.cyan}npm run dev${colors.reset}`);
|
|
210
|
-
console.log();
|
|
211
|
-
console.log(`${colors.bright}Happy coding!${colors.reset} 🚀`);
|
|
230
|
+
console.log(styles.heading('Available Commands:\n'));
|
|
231
|
+
console.log(
|
|
232
|
+
` ${styles.command(
|
|
233
|
+
'npm run dev',
|
|
234
|
+
)} - Start development server with hot-reload`,
|
|
235
|
+
);
|
|
236
|
+
console.log(
|
|
237
|
+
` ${styles.command('npm run build')} - Build for production`,
|
|
238
|
+
);
|
|
239
|
+
console.log(
|
|
240
|
+
` ${styles.command(
|
|
241
|
+
'npm start',
|
|
242
|
+
)} - Build and run production server`,
|
|
243
|
+
);
|
|
244
|
+
console.log(` ${styles.command('npm test')} - Run test suite`);
|
|
245
|
+
console.log(
|
|
246
|
+
` ${styles.command('npm run lint')} - Check for linting errors`,
|
|
247
|
+
);
|
|
212
248
|
console.log();
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
249
|
+
console.log(chalk.bold('Happy coding! 🚀\n'));
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Recursively copy all files and folders
|
|
253
|
+
function copyDir(src, dest) {
|
|
254
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
255
|
+
|
|
256
|
+
for (const file of fs.readdirSync(src)) {
|
|
257
|
+
const srcPath = path.join(src, file);
|
|
258
|
+
const destPath = path.join(dest, file);
|
|
259
|
+
|
|
260
|
+
if (fs.statSync(srcPath).isDirectory()) {
|
|
261
|
+
copyDir(srcPath, destPath);
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
fs.copyFileSync(srcPath, destPath);
|
|
266
|
+
}
|
|
217
267
|
}
|
|
268
|
+
|
|
269
|
+
createExpressMongo().catch((error) => {
|
|
270
|
+
console.error(styles.error('An error occurred:'), error);
|
|
271
|
+
process.exit(1);
|
|
272
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-express-mongo-ts",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "Create Express + MongoDB applications with TypeScript, authentication, and best practices out of the box",
|
|
5
5
|
"main": "bin/cli.js",
|
|
6
6
|
"bin": {
|
|
@@ -36,8 +36,12 @@
|
|
|
36
36
|
"url": "https://github.com/sofikulsk02/express-mongobd-template/issues"
|
|
37
37
|
},
|
|
38
38
|
"homepage": "https://github.com/sofikulsk02/express-mongobd-template#readme",
|
|
39
|
-
"type": "
|
|
39
|
+
"type": "module",
|
|
40
40
|
"engines": {
|
|
41
41
|
"node": ">=18.0.0"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"chalk": "^5.3.0",
|
|
45
|
+
"inquirer": "^9.2.12"
|
|
42
46
|
}
|
|
43
47
|
}
|