create-xpress-backend 1.0.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/package.json ADDED
@@ -0,0 +1,43 @@
1
+ {
2
+ "name": "create-xpress-backend",
3
+ "version": "1.0.0",
4
+ "description": "Scaffold a production-ready Express + Prisma + PostgreSQL backend in seconds",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "create-xpress-backend": "src/index.js"
8
+ },
9
+ "scripts": {
10
+ "start": "node src/index.js"
11
+ },
12
+ "keywords": [
13
+ "express",
14
+ "backend",
15
+ "scaffold",
16
+ "prisma",
17
+ "postgresql",
18
+ "cli",
19
+ "boilerplate",
20
+ "starter",
21
+ "generator",
22
+ "node"
23
+ ],
24
+ "author": "ayushsolanki29",
25
+ "license": "MIT",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/ayushsolanki29/create-xpress-backend.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/ayushsolanki29/create-xpress-backend/issues"
32
+ },
33
+ "homepage": "https://github.com/ayushsolanki29/create-xpress-backend#readme",
34
+ "engines": {
35
+ "node": ">=18.0.0"
36
+ },
37
+ "dependencies": {
38
+ "chalk": "^4.1.2",
39
+ "fs-extra": "^11.2.0",
40
+ "inquirer": "^8.2.6",
41
+ "ora": "^5.4.1"
42
+ }
43
+ }
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const fs = require('fs-extra');
5
+ const { execSync } = require('child_process');
6
+ const { buildTemplates } = require('./templates');
7
+
8
+ /**
9
+ * Main generator — writes every file into the new project directory.
10
+ * @param {object} answers - Inquirer answers
11
+ * @param {object} spinner - Ora spinner instance
12
+ */
13
+ async function generateProject(answers, spinner) {
14
+ const { projectName, language, port, includeFileUpload, includeAuth, initGit } = answers;
15
+ const isTs = language === 'ts';
16
+ const destDir = path.resolve(process.cwd(), projectName);
17
+
18
+ // 1. Create root folder
19
+ spinner.text = 'Creating project folder...';
20
+ await fs.ensureDir(destDir);
21
+
22
+ // 2. Build all file contents from templates
23
+ const files = buildTemplates({ projectName, language, port, includeFileUpload, includeAuth });
24
+
25
+ // 3. Write every file
26
+ for (const [relPath, content] of Object.entries(files)) {
27
+ spinner.text = `Writing ${relPath}`;
28
+ const absPath = path.join(destDir, relPath);
29
+ await fs.ensureDir(path.dirname(absPath));
30
+ await fs.writeFile(absPath, content, 'utf8');
31
+ }
32
+
33
+ // 4. Create uploads dir placeholder if file upload included
34
+ if (includeFileUpload) {
35
+ await fs.ensureDir(path.join(destDir, 'uploads'));
36
+ await fs.writeFile(path.join(destDir, 'uploads', '.gitkeep'), '', 'utf8');
37
+ }
38
+
39
+ // 5. Git init
40
+ if (initGit) {
41
+ spinner.text = 'Initialising git...';
42
+ try {
43
+ execSync('git init', { cwd: destDir, stdio: 'ignore' });
44
+ } catch {
45
+ // git not available — not fatal
46
+ }
47
+ }
48
+ }
49
+
50
+ module.exports = { generateProject };
package/src/index.js ADDED
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+
3
+ 'use strict';
4
+
5
+ const chalk = require('chalk');
6
+ const inquirer = require('inquirer');
7
+ const ora = require('ora');
8
+ const path = require('path');
9
+ const fs = require('fs-extra');
10
+
11
+ const { generateProject } = require('./generator');
12
+
13
+ const VERSION = require('../package.json').version;
14
+
15
+ // ─── Banner ───────────────────────────────────────────────────────────────────
16
+ function printBanner() {
17
+ console.log('');
18
+ console.log(chalk.bold.cyan(' ┌─────────────────────────────────────────────┐'));
19
+ console.log(
20
+ chalk.bold.cyan(' │') +
21
+ chalk.bold.white(' 🚀 create-xpress-backend') +
22
+ chalk.gray(` v${VERSION}`) +
23
+ chalk.bold.cyan(' │')
24
+ );
25
+ console.log(
26
+ chalk.bold.cyan(' │') +
27
+ chalk.dim(' Express · Prisma · PostgreSQL · Node.js ') +
28
+ chalk.bold.cyan('│')
29
+ );
30
+ console.log(chalk.bold.cyan(' └─────────────────────────────────────────────┘'));
31
+ console.log('');
32
+ }
33
+
34
+ // ─── Prompts ──────────────────────────────────────────────────────────────────
35
+ async function askQuestions() {
36
+ return inquirer.prompt([
37
+ {
38
+ type: 'input',
39
+ name: 'projectName',
40
+ message: chalk.cyan('project_name') + chalk.gray(' : '),
41
+ validate(input) {
42
+ const name = input.trim();
43
+ if (!name) return 'Project name cannot be empty.';
44
+ if (!/^[a-z0-9-_]+$/i.test(name))
45
+ return 'Use only letters, numbers, hyphens or underscores.';
46
+ if (fs.existsSync(path.resolve(process.cwd(), name)))
47
+ return `Folder "${name}" already exists — pick a different name.`;
48
+ return true;
49
+ },
50
+ filter: (v) => v.trim(),
51
+ },
52
+ {
53
+ type: 'list',
54
+ name: 'language',
55
+ message: chalk.cyan('language') + chalk.gray(' : '),
56
+ choices: [
57
+ { name: 'TypeScript (recommended)', value: 'ts' },
58
+ { name: 'JavaScript', value: 'js' },
59
+ ],
60
+ default: 'ts',
61
+ },
62
+ {
63
+ type: 'input',
64
+ name: 'port',
65
+ message: chalk.cyan('port') + chalk.gray(' : '),
66
+ default: '5050',
67
+ validate: (v) => (/^\d+$/.test(v.trim()) ? true : 'Port must be a number.'),
68
+ filter: (v) => v.trim(),
69
+ },
70
+ {
71
+ type: 'confirm',
72
+ name: 'includeFileUpload',
73
+ message: chalk.cyan('file upload system') + chalk.gray(' : include?'),
74
+ default: true,
75
+ },
76
+ {
77
+ type: 'confirm',
78
+ name: 'includeAuth',
79
+ message: chalk.cyan('JWT auth module') + chalk.gray(' : include?'),
80
+ default: false,
81
+ },
82
+ {
83
+ type: 'confirm',
84
+ name: 'initGit',
85
+ message: chalk.cyan('git init') + chalk.gray(' : initialize?'),
86
+ default: true,
87
+ },
88
+ ]);
89
+ }
90
+
91
+ // ─── Success output ───────────────────────────────────────────────────────────
92
+ function printSuccess(projectName, port, language) {
93
+ const isTs = language === 'ts';
94
+
95
+ console.log('');
96
+ console.log(chalk.bold.green(' ✔ Done! Your project is ready.\n'));
97
+
98
+ console.log(chalk.bold(' Get started:'));
99
+ console.log(chalk.white(` cd ${projectName}`));
100
+ console.log(chalk.white(' npm install'));
101
+ console.log(chalk.dim(' # configure DATABASE_URL in .env, then:'));
102
+ console.log(chalk.white(' npm run db:push'));
103
+ console.log(chalk.white(' npm run dev\n'));
104
+
105
+ if (isTs) {
106
+ console.log(chalk.dim(' Build for production:'));
107
+ console.log(chalk.white(' npm run build'));
108
+ console.log(chalk.white(' npm start\n'));
109
+ }
110
+
111
+ console.log(chalk.dim(' Health check → ') + chalk.cyan(`http://localhost:${port}/health`));
112
+ console.log(chalk.dim(' Prisma Studio → ') + chalk.cyan('npm run db:studio'));
113
+ console.log('');
114
+ }
115
+
116
+ // ─── Main ─────────────────────────────────────────────────────────────────────
117
+ async function main() {
118
+ printBanner();
119
+
120
+ let answers;
121
+ try {
122
+ answers = await askQuestions();
123
+ } catch {
124
+ console.log('\n' + chalk.yellow(' Cancelled.'));
125
+ process.exit(0);
126
+ }
127
+
128
+ console.log('');
129
+
130
+ const isTs = answers.language === 'ts';
131
+ const langLabel = isTs
132
+ ? chalk.blue('TypeScript')
133
+ : chalk.yellow('JavaScript');
134
+
135
+ const spinner = ora({
136
+ text: chalk.cyan(`Scaffolding ${chalk.bold(answers.projectName)} `) + chalk.gray(`[${langLabel}${chalk.gray(']')}...`),
137
+ color: 'cyan',
138
+ }).start();
139
+
140
+ try {
141
+ await generateProject(answers, spinner);
142
+ spinner.succeed(
143
+ chalk.green(`Project "${chalk.bold(answers.projectName)}" created! `) +
144
+ chalk.gray(`(${isTs ? 'TypeScript' : 'JavaScript'})`)
145
+ );
146
+ printSuccess(answers.projectName, answers.port, answers.language);
147
+ } catch (err) {
148
+ spinner.fail(chalk.red('Something went wrong.'));
149
+ console.error(chalk.red(`\n ${err.message}\n`));
150
+ process.exit(1);
151
+ }
152
+ }
153
+
154
+ main();
@@ -0,0 +1,15 @@
1
+ 'use strict';
2
+
3
+ const { buildJsTemplates } = require('./js');
4
+ const { buildTsTemplates } = require('./ts');
5
+
6
+ /**
7
+ * Routes to the correct template set based on chosen language.
8
+ */
9
+ function buildTemplates(opts) {
10
+ return opts.language === 'ts'
11
+ ? buildTsTemplates(opts)
12
+ : buildJsTemplates(opts);
13
+ }
14
+
15
+ module.exports = { buildTemplates };