stack-starter-cli 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/README.md ADDED
@@ -0,0 +1,33 @@
1
+ # starter-cli
2
+
3
+ A simple CLI tool to quickly create full stack starter projects.
4
+
5
+ ## Features
6
+
7
+ - HTML / CSS / JavaScript starter
8
+ - React.js starter using Vite
9
+ - Node.js backend using Express
10
+ - Automatic starter files and folder structure
11
+
12
+ ## Run locally
13
+
14
+ ```bash
15
+ npm install
16
+ node bin/index.js
17
+
18
+ After that:
19
+
20
+ git add .
21
+ git commit -m "Add README"
22
+ ```
23
+
24
+ ```bash
25
+ shortcuts:
26
+ - stack-starter
27
+ - stack-starter my-app
28
+ - stack-starter my-app --react
29
+ - stack-starter my-app --html
30
+ - stack-starter my-app --react --node
31
+ - stack-starter my-app --html --node
32
+ - stack-starter --help
33
+ - stack-starter --version
package/bin/index.js ADDED
@@ -0,0 +1,364 @@
1
+ #!/usr/bin/env node
2
+
3
+ // -----------------------------
4
+ // Required packages
5
+ // -----------------------------
6
+ const inquirer = require("inquirer").default;
7
+ const fs = require("fs");
8
+ const path = require("path");
9
+ const { execSync } = require("child_process");
10
+
11
+ // -----------------------------
12
+ // starter --help and --version
13
+ // -----------------------------
14
+ const packageJson = require("../package.json");
15
+
16
+ if (process.argv.includes("--help") || process.argv.includes("-h")) {
17
+ console.log(`
18
+ starter - project scaffolding CLI
19
+
20
+ Usage:
21
+ starter
22
+ starter my-app
23
+ starter my-app --react --node
24
+ starter my-app --html
25
+
26
+ Options:
27
+ --help, -h Show help
28
+ --version, -v Show version
29
+ --react Use React.js (Vite)
30
+ --html Use HTML / CSS / JavaScript
31
+ --node Use Node.js (Express)
32
+
33
+ What it can create:
34
+ • HTML / CSS / JavaScript starter
35
+ • React.js (Vite) starter
36
+ • Node.js (Express) backend
37
+ `);
38
+ process.exit(0);
39
+ }
40
+
41
+ if (process.argv.includes("--version") || process.argv.includes("-v")) {
42
+ console.log(packageJson.version);
43
+ process.exit(0);
44
+ }
45
+
46
+ // -----------------------------
47
+ // CLI flags
48
+ // -----------------------------
49
+ const cliProjectName =
50
+ process.argv[2] && !process.argv[2].startsWith("-")
51
+ ? process.argv[2]
52
+ : null;
53
+
54
+ const useReact = process.argv.includes("--react");
55
+ const useHtml = process.argv.includes("--html");
56
+ const useNode = process.argv.includes("--node");
57
+
58
+ // -----------------------------
59
+ // Resolve CLI-selected frontend/backend
60
+ // -----------------------------
61
+ let cliFrontend = null;
62
+ let cliBackend = null;
63
+
64
+ if (useReact) cliFrontend = "React.js (Vite)";
65
+ if (useHtml) cliFrontend = "HTML / CSS / JavaScript";
66
+ if (useNode) cliBackend = "Node.js (Express)";
67
+
68
+ // -----------------------------
69
+ // Helper: copy template files
70
+ // -----------------------------
71
+ function copyTemplate(source, destination) {
72
+ const content = fs.readFileSync(source, "utf-8");
73
+ fs.writeFileSync(destination, content);
74
+ }
75
+
76
+ // -----------------------------
77
+ // Ask user for project details
78
+ // -----------------------------
79
+ inquirer
80
+ .prompt([
81
+ {
82
+ name: "projectName",
83
+ message: "Enter your project name:",
84
+ default: cliProjectName || undefined,
85
+ when: !cliProjectName,
86
+ validate(input) {
87
+ const projectName = cliProjectName || input;
88
+
89
+ if (!projectName.trim()) {
90
+ return "Project name cannot be empty.";
91
+ }
92
+
93
+ if (!/^[a-zA-Z0-9_-]+$/.test(projectName)) {
94
+ return "Use only letters, numbers, hyphen (-), or underscore (_).";
95
+ }
96
+
97
+ return true;
98
+ },
99
+ },
100
+ {
101
+ name: "frontend",
102
+ message: "Choose frontend:",
103
+ type: "rawlist",
104
+ choices: ["HTML / CSS / JavaScript", "React.js (Vite)", "None"],
105
+ default: 2,
106
+ when: !cliFrontend,
107
+ },
108
+ {
109
+ name: "backend",
110
+ message: "Choose backend:",
111
+ type: "rawlist",
112
+ choices: ["Node.js (Express)", "None"],
113
+ default: 1,
114
+ when: !cliBackend,
115
+ },
116
+ ])
117
+ .then((answers) => {
118
+ if (cliProjectName) {
119
+ answers.projectName = cliProjectName;
120
+ }
121
+
122
+ if (cliFrontend) {
123
+ answers.frontend = cliFrontend;
124
+ }
125
+
126
+ if (cliBackend) {
127
+ answers.backend = cliBackend;
128
+ }
129
+
130
+ if (!answers.frontend) {
131
+ answers.frontend = "None";
132
+ }
133
+
134
+ if (!answers.backend) {
135
+ answers.backend = "None";
136
+ }
137
+
138
+ const projectPath = path.join(process.cwd(), answers.projectName);
139
+
140
+ // -----------------------------
141
+ // Prevent duplicate folder names
142
+ // -----------------------------
143
+ if (fs.existsSync(projectPath)) {
144
+ console.log("\nA project with this name already exists.");
145
+ return;
146
+ }
147
+
148
+ // -----------------------------
149
+ // Create root project folder
150
+ // -----------------------------
151
+ fs.mkdirSync(projectPath);
152
+
153
+ // -----------------------------
154
+ // Base project files
155
+ // -----------------------------
156
+ fs.writeFileSync(
157
+ path.join(projectPath, ".gitignore"),
158
+ "node_modules\n.env\ndist\n.vite\n.DS_Store\ncoverage"
159
+ );
160
+
161
+ fs.writeFileSync(
162
+ path.join(projectPath, "README.md"),
163
+ `# ${answers.projectName}`
164
+ );
165
+
166
+ // =====================================================
167
+ // BACKEND SETUP
168
+ // =====================================================
169
+ if (answers.backend === "Node.js (Express)") {
170
+ const serverPath = path.join(projectPath, "server");
171
+
172
+ fs.mkdirSync(serverPath);
173
+
174
+ console.log("\nSetting up backend...");
175
+
176
+ try {
177
+ execSync("npm init -y", {
178
+ cwd: serverPath,
179
+ stdio: "inherit",
180
+ shell: process.env.ComSpec,
181
+ });
182
+
183
+ const pkgPath = path.join(serverPath, "package.json");
184
+
185
+ if (fs.existsSync(pkgPath)) {
186
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
187
+
188
+ pkg.scripts = {
189
+ start: "node index.js",
190
+ dev: "nodemon index.js",
191
+ };
192
+
193
+ fs.writeFileSync(pkgPath, JSON.stringify(pkg, null, 2));
194
+
195
+ console.log("✅ Scripts added to package.json");
196
+ }
197
+
198
+ execSync("npm install express cors dotenv", {
199
+ cwd: serverPath,
200
+ stdio: "inherit",
201
+ shell: process.env.ComSpec,
202
+ });
203
+
204
+ execSync("npm install -D nodemon", {
205
+ cwd: serverPath,
206
+ stdio: "inherit",
207
+ shell: process.env.ComSpec,
208
+ });
209
+
210
+ copyTemplate(
211
+ path.join(__dirname, "..", "templates", "server", "index.js"),
212
+ path.join(serverPath, "index.js")
213
+ );
214
+ } catch (error) {
215
+ console.log("\n❌ Backend setup failed.");
216
+ console.log("Check npm installation or internet connection.");
217
+ return;
218
+ }
219
+ }
220
+
221
+ // =====================================================
222
+ // FRONTEND SETUP - HTML / CSS / JS
223
+ // =====================================================
224
+ if (answers.frontend === "HTML / CSS / JavaScript") {
225
+ const clientPath = path.join(projectPath, "client");
226
+
227
+ fs.mkdirSync(clientPath);
228
+
229
+ console.log("\nSetting up HTML / CSS / JavaScript frontend...");
230
+
231
+ fs.writeFileSync(
232
+ path.join(clientPath, "index.html"),
233
+ `<!DOCTYPE html>
234
+ <html lang="en">
235
+ <head>
236
+ <meta charset="UTF-8">
237
+ <title>${answers.projectName}</title>
238
+ <link rel="stylesheet" href="style.css">
239
+ </head>
240
+ <body>
241
+ <h1>Frontend Status: <span id="status">Loading...</span></h1>
242
+
243
+ <div id="response-box" style="padding: 20px; border: 1px solid #ccc; margin-top: 20px;">
244
+ Backend Message: <strong id="message">Please wait...</strong>
245
+ </div>
246
+
247
+ <script src="script.js"></script>
248
+ </body>
249
+ </html>`
250
+ );
251
+
252
+ fs.writeFileSync(
253
+ path.join(clientPath, "style.css"),
254
+ `body {
255
+ font-family: Arial, sans-serif;
256
+ padding: 40px;
257
+ text-align: center;
258
+ background: #f5f5f5;
259
+ }
260
+
261
+ #response-box {
262
+ background: white;
263
+ display: inline-block;
264
+ padding: 20px;
265
+ border-radius: 8px;
266
+ }`
267
+ );
268
+
269
+ if (answers.backend === "Node.js (Express)") {
270
+ copyTemplate(
271
+ path.join(__dirname, "..", "templates", "html", "script.js"),
272
+ path.join(clientPath, "script.js")
273
+ );
274
+ } else {
275
+ fs.writeFileSync(
276
+ path.join(clientPath, "script.js"),
277
+ `const statusEl = document.getElementById("status");
278
+ const messageEl = document.getElementById("message");
279
+
280
+ statusEl.textContent = "Standalone";
281
+ statusEl.style.color = "green";
282
+
283
+ messageEl.textContent = "No backend selected. Frontend is ready.";`
284
+ );
285
+ }
286
+ }
287
+
288
+ // =====================================================
289
+ // FRONTEND SETUP - REACT
290
+ // =====================================================
291
+ else if (answers.frontend === "React.js (Vite)") {
292
+ const clientPath = path.join(projectPath, "client");
293
+
294
+ console.log("\nScaffolding React project...");
295
+
296
+ try {
297
+ execSync("npm create vite@latest client --yes -- --template react", {
298
+ cwd: projectPath,
299
+ stdio: ["ignore", "pipe", "pipe"],
300
+ shell: process.env.ComSpec,
301
+ });
302
+
303
+ console.log("Installing React dependencies...");
304
+
305
+ execSync("npm install", {
306
+ cwd: clientPath,
307
+ stdio: "inherit",
308
+ shell: process.env.ComSpec,
309
+ });
310
+
311
+ console.log("✅ React installation complete!");
312
+
313
+ if (answers.backend === "Node.js (Express)") {
314
+ copyTemplate(
315
+ path.join(__dirname, "..", "templates", "react", "App.jsx"),
316
+ path.join(clientPath, "src", "App.jsx")
317
+ );
318
+ }
319
+ } catch (error) {
320
+ console.log("\n❌ React setup failed.");
321
+ console.log("Check npm installation or internet connection.");
322
+ return;
323
+ }
324
+ }
325
+
326
+ // =====================================================
327
+ // FINAL INSTRUCTIONS
328
+ // =====================================================
329
+ console.log(`\n✅ Project "${answers.projectName}" created successfully!`);
330
+
331
+ if (
332
+ answers.frontend === "HTML / CSS / JavaScript" &&
333
+ answers.backend === "Node.js (Express)"
334
+ ) {
335
+ console.log("\nRun backend:");
336
+ console.log(`cd ${answers.projectName}/server`);
337
+ console.log("npm run dev");
338
+
339
+ console.log("\nThen open frontend:");
340
+ console.log(`${answers.projectName}/client/index.html`);
341
+ } else if (
342
+ answers.frontend === "React.js (Vite)" &&
343
+ answers.backend === "Node.js (Express)"
344
+ ) {
345
+ console.log("\nRun backend:");
346
+ console.log(`cd ${answers.projectName}/server`);
347
+ console.log("npm run dev");
348
+
349
+ console.log("\nOpen another terminal and run frontend:");
350
+ console.log(`cd ${answers.projectName}/client`);
351
+ console.log("npm run dev");
352
+ } else if (answers.frontend === "HTML / CSS / JavaScript") {
353
+ console.log("\nOpen frontend:");
354
+ console.log(`${answers.projectName}/client/index.html`);
355
+ } else if (answers.frontend === "React.js (Vite)") {
356
+ console.log("\nRun frontend:");
357
+ console.log(`cd ${answers.projectName}/client`);
358
+ console.log("npm run dev");
359
+ } else if (answers.backend === "Node.js (Express)") {
360
+ console.log("\nRun backend:");
361
+ console.log(`cd ${answers.projectName}/server`);
362
+ console.log("npm run dev");
363
+ }
364
+ });
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "stack-starter-cli",
3
+ "version": "1.0.0",
4
+ "description": "CLI to generate frontend and backend starter projects",
5
+ "main": "bin/index.js",
6
+ "bin": {
7
+ "stack-starter": "./bin/index.js"
8
+ },
9
+ "files": [
10
+ "bin",
11
+ "templates"
12
+ ],
13
+ "scripts": {
14
+ "start": "node bin/index.js"
15
+ },
16
+ "keywords": [
17
+ "cli",
18
+ "starter",
19
+ "scaffold",
20
+ "node",
21
+ "react",
22
+ "express"
23
+ ],
24
+ "author": "SACHITH KASA",
25
+ "license": "MIT",
26
+ "type": "commonjs",
27
+ "dependencies": {
28
+ "inquirer": "^13.4.2"
29
+ }
30
+ }
@@ -0,0 +1,16 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Starter Project</title>
6
+ <link rel="stylesheet" href="style.css">
7
+ <script src="script.js" defer></script>
8
+ </head>
9
+ <body>
10
+ <h1>Frontend Status: <span id="status">Connecting...</span></h1>
11
+ <div id="response-box">
12
+ Backend Message: <strong id="message">Waiting for server...</strong>
13
+ </div>
14
+
15
+ </body>
16
+ </html>
@@ -0,0 +1,13 @@
1
+ const messageEl = document.getElementById("message");
2
+ const statusEl = document.getElementById("status");
3
+
4
+ fetch("http://localhost:5000/")
5
+ .then((res) => res.text())
6
+ .then((data) => {
7
+ statusEl.textContent = "Online";
8
+ messageEl.textContent = data;
9
+ })
10
+ .catch(() => {
11
+ statusEl.textContent = "Offline";
12
+ messageEl.textContent = "Could not connect to backend";
13
+ });
@@ -0,0 +1,11 @@
1
+ body {
2
+ font-family: Arial, sans-serif;
3
+ padding: 40px;
4
+ text-align: center;
5
+ }
6
+
7
+ #response-box {
8
+ margin-top: 20px;
9
+ padding: 20px;
10
+ border: 1px solid #ccc;
11
+ }
@@ -0,0 +1,21 @@
1
+ import { useEffect, useState } from "react";
2
+
3
+ function App() {
4
+ const [message, setMessage] = useState("Connecting to backend...");
5
+
6
+ useEffect(() => {
7
+ fetch("http://localhost:5000/")
8
+ .then((res) => res.text())
9
+ .then((data) => setMessage(data))
10
+ .catch(() => setMessage("Could not connect to backend"));
11
+ }, []);
12
+
13
+ return (
14
+ <div style={{ padding: "40px", fontFamily: "Arial" }}>
15
+ <h1>React Frontend Connected</h1>
16
+ <p>{message}</p>
17
+ </div>
18
+ );
19
+ }
20
+
21
+ export default App;
@@ -0,0 +1,18 @@
1
+ const express = require("express");
2
+ const cors = require("cors");
3
+ require("dotenv").config();
4
+
5
+ const app = express();
6
+
7
+ app.use(cors());
8
+ app.use(express.json());
9
+
10
+ app.get("/", (req, res) => {
11
+ res.send("Server is running and connected to Frontend!");
12
+ });
13
+
14
+ const PORT = process.env.PORT || 5000;
15
+
16
+ app.listen(PORT, () => {
17
+ console.log(`Server running on port ${PORT}`);
18
+ });