create-fullstack-setup 1.0.8 → 1.0.10

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/bin/index.js CHANGED
@@ -6,117 +6,67 @@ import { createProject } from "../utils/installer.js";
6
6
 
7
7
  console.log(chalk.green("\nšŸš€ Welcome to FullStack App Generator\n"));
8
8
 
9
- /* -------------------------------------------------------------------------- */
10
- /* PROMPTS */
11
- /* -------------------------------------------------------------------------- */
12
-
13
9
  const answers = await inquirer.prompt([
14
10
  {
15
11
  type: "input",
16
12
  name: "projectName",
17
13
  message: "Project name:",
18
- validate: input => (input ? true : "Project name is required")
14
+ validate: (input) => (input ? true : "Project name is required")
19
15
  },
20
16
  {
21
- type: "list",
17
+ type: "rawlist",
22
18
  name: "frontend",
23
19
  message: "Choose frontend:",
24
20
  choices: ["React", "Next.js", "None"]
25
21
  },
26
22
  {
27
- type: "list",
23
+ type: "rawlist",
28
24
  name: "backend",
29
25
  message: "Choose backend:",
30
- choices: ["Express"] // Fastify can be added later
26
+ choices: ["Express"]
31
27
  },
32
28
  {
33
- type: "list",
29
+ type: "rawlist",
34
30
  name: "language",
35
31
  message: "Choose language:",
36
32
  choices: ["JavaScript", "TypeScript"]
37
33
  },
38
-
39
- /* ----------------------- Backend Feature Gate ---------------------------- */
40
-
41
34
  {
42
35
  type: "confirm",
43
36
  name: "useBackendFeatures",
44
37
  message: "Select backend features?",
45
38
  default: true
46
39
  },
47
-
48
- /* ---------------------- Conditional Feature Prompts ---------------------- */
49
-
50
40
  {
51
41
  type: "confirm",
52
42
  name: "useJWT",
53
43
  message: "Use JWT authentication?",
54
44
  default: true,
55
- when: ans => ans.useBackendFeatures
45
+ when: (ans) => ans.useBackendFeatures
56
46
  },
57
47
  {
58
48
  type: "confirm",
59
49
  name: "useCORS",
60
50
  message: "Enable CORS?",
61
51
  default: true,
62
- when: ans => ans.useBackendFeatures
52
+ when: (ans) => ans.useBackendFeatures
63
53
  },
64
54
  {
65
55
  type: "confirm",
66
56
  name: "useCookieParser",
67
57
  message: "Use Cookie Parser?",
68
58
  default: true,
69
- when: ans => ans.useBackendFeatures
59
+ when: (ans) => ans.useBackendFeatures
70
60
  },
71
61
  {
72
62
  type: "confirm",
73
63
  name: "useCloudinary",
74
64
  message: "Use Cloudinary?",
75
65
  default: true,
76
- when: ans => ans.useBackendFeatures
77
- },
78
- {
79
- type: "confirm",
80
- name: "useMongoose",
81
- message: "Use MongoDB (Mongoose)?",
82
- default: true,
83
- when: ans => ans.useBackendFeatures
84
- },
85
- {
86
- type: "confirm",
87
- name: "useZod",
88
- message: "Use Zod validation?",
89
- default: true,
90
- when: ans => ans.useBackendFeatures
91
- },
92
- {
93
- type: "confirm",
94
- name: "useDotenv",
95
- message: "Use Dotenv?",
96
- default: true,
97
- when: ans => ans.useBackendFeatures
98
- },
99
- {
100
- type: "confirm",
101
- name: "useBcrypt",
102
- message: "Use Bcrypt for password hashing?",
103
- default: true,
104
- when: ans => ans.useBackendFeatures
105
- },
106
- {
107
- type: "confirm",
108
- name: "useMulter",
109
- message: "Use Multer for file uploads?",
110
- default: true,
111
- when: ans => ans.useBackendFeatures
66
+ when: (ans) => ans.useBackendFeatures
112
67
  }
113
68
  ]);
114
69
 
115
-
116
- /* -------------------------------------------------------------------------- */
117
- /* MAP ANSWERS → TEMPLATE KEYS */
118
- /* -------------------------------------------------------------------------- */
119
-
120
70
  const frontendMap = {
121
71
  React: {
122
72
  JavaScript: "react-js",
@@ -136,28 +86,14 @@ const backendMap = {
136
86
  }
137
87
  };
138
88
 
139
- /* -------------------------------------------------------------------------- */
140
- /* BUILD backendFeatures ARRAY (IMPORTANT) */
141
- /* -------------------------------------------------------------------------- */
142
-
143
89
  const backendFeatures = [];
144
-
145
90
  if (answers.useBackendFeatures) {
146
91
  if (answers.useJWT) backendFeatures.push("JWT");
147
92
  if (answers.useCORS) backendFeatures.push("CORS");
148
93
  if (answers.useCookieParser) backendFeatures.push("Cookie-Parser");
149
- if (answers.useMongoose) backendFeatures.push("Mongoose");
150
94
  if (answers.useCloudinary) backendFeatures.push("Cloudinary");
151
- if (answers.useZod) backendFeatures.push("Zod");
152
- if (answers.useDotenv) backendFeatures.push("Dotenv");
153
- if (answers.useBcrypt) backendFeatures.push("Bcrypt");
154
- if (answers.useMulter) backendFeatures.push("Multer");
155
95
  }
156
96
 
157
- /* -------------------------------------------------------------------------- */
158
- /* BUILD CONFIG OBJECT */
159
- /* -------------------------------------------------------------------------- */
160
-
161
97
  const config = {
162
98
  projectName: answers.projectName,
163
99
  frontend:
@@ -165,11 +101,7 @@ const config = {
165
101
  ? "None"
166
102
  : frontendMap[answers.frontend][answers.language],
167
103
  backend: backendMap[answers.backend][answers.language],
168
- backendFeatures // āœ… ALWAYS ARRAY
104
+ backendFeatures
169
105
  };
170
106
 
171
- /* -------------------------------------------------------------------------- */
172
- /* CREATE PROJECT */
173
- /* -------------------------------------------------------------------------- */
174
-
175
107
  await createProject(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fullstack-setup",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "CLI to generate ready-to-run fullstack or backend applications",
5
5
  "bin": {
6
6
  "create-fullstack-setup": "bin/index.js"
@@ -32,6 +32,8 @@
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
34
  "chalk": "^5.6.2",
35
- "inquirer": "^13.2.1"
35
+ "fs-extra": "^11.3.3",
36
+ "inquirer": "^13.2.1",
37
+ "ora": "^9.1.0"
36
38
  }
37
39
  }
@@ -1,10 +1,4 @@
1
- /* -------------------------------------------------------------------------- */
2
- /* Backend Feature Configuration */
3
- /* -------------------------------------------------------------------------- */
4
-
5
1
  export const FEATURES = {
6
- /* =============================== CORS ================================= */
7
-
8
2
  CORS: {
9
3
  middleware: `
10
4
  import cors from "cors";
@@ -13,8 +7,6 @@ app.use(cors());
13
7
  env: []
14
8
  },
15
9
 
16
- /* =========================== COOKIE PARSER ============================= */
17
-
18
10
  "Cookie-Parser": {
19
11
  middleware: `
20
12
  import cookieParser from "cookie-parser";
@@ -23,48 +15,32 @@ app.use(cookieParser());
23
15
  env: []
24
16
  },
25
17
 
26
- /* ================================ JWT ================================= */
27
-
28
18
  JWT: {
29
19
  middleware: "",
30
20
  files: {
31
21
  js: [
32
- {
33
- path: "middlewares/Auth.middleware.js",
34
- fromTemplate:true,
35
- }
22
+ { path: "middlewares/Auth.middleware.js", fromTemplate: true }
36
23
  ],
37
24
  ts: [
38
- {
39
- path: "src/middlewares/auth.middleware.ts",
40
- fromTemplate:true,
41
- }
25
+ { path: "src/middlewares/auth.middleware.ts", fromTemplate: true }
42
26
  ]
43
27
  },
28
+ env: ["ACCESS_TOKEN_SECRET=your_secret"]
44
29
  },
45
30
 
46
- /* ============================ CLOUDINARY ============================== */
47
-
48
31
  Cloudinary: {
49
32
  middleware: "",
50
33
  files: {
51
- js: [
52
- {
53
- path: "Utils/Cloudinary.js",
54
- fromTemplate:true
55
- }
56
- ],
57
- ts: [
58
- {
59
- path: "src/utils/Cloudinary.ts",
60
- fromTemplate:true,
61
- }
62
- ]
63
- }
34
+ js: [{ path: "Utils/Cloudinary.js", fromTemplate: true }],
35
+ ts: [{ path: "src/utils/Cloudinary.ts", fromTemplate: true }]
36
+ },
37
+ env: [
38
+ "CLOUDINARY_NAME=",
39
+ "CLOUDINARY_API_KEY=",
40
+ "CLOUDINARY_API_SECRET="
41
+ ]
64
42
  },
65
43
 
66
- /* ============================== DOTENV ================================ */
67
-
68
44
  Dotenv: {
69
45
  middleware: `import "dotenv/config";`,
70
46
  env: ["PORT=5000"]
@@ -1,10 +1,11 @@
1
1
  import fs from "fs";
2
2
  import path from "path";
3
+ import { fileURLToPath } from "url";
3
4
  import { FEATURES } from "./features.config.js";
4
5
 
5
- /* -------------------------------------------------------------------------- */
6
- /* Helpers (JS / TS aware) */
7
- /* -------------------------------------------------------------------------- */
6
+ const __filename = fileURLToPath(import.meta.url);
7
+ const __dirname = path.dirname(__filename);
8
+ const CLI_ROOT = path.join(__dirname, "..");
8
9
 
9
10
  function isTypeScriptBackend(serverPath) {
10
11
  return (
@@ -31,10 +32,6 @@ function findServerFile(serverPath) {
31
32
  return null;
32
33
  }
33
34
 
34
- /* -------------------------------------------------------------------------- */
35
- /* Inject Features */
36
- /* -------------------------------------------------------------------------- */
37
-
38
35
  export function injectFeatures(serverPath, selectedFeatures = []) {
39
36
  if (!Array.isArray(selectedFeatures) || selectedFeatures.length === 0) return;
40
37
 
@@ -48,29 +45,23 @@ export function injectFeatures(serverPath, selectedFeatures = []) {
48
45
  }
49
46
 
50
47
  let appContent = fs.readFileSync(appFile, "utf8");
51
- let serverContent = serverFile
52
- ? fs.readFileSync(serverFile, "utf8")
53
- : "";
48
+ let serverContent = serverFile ? fs.readFileSync(serverFile, "utf8") : "";
54
49
 
55
50
  let middlewareCode = "";
56
51
  let envVars = [];
57
52
 
58
- /* ---------------------------------------------------------------------- */
59
- /* Process each feature */
60
- /* ---------------------------------------------------------------------- */
61
-
62
53
  for (const feature of selectedFeatures) {
63
54
  const config = FEATURES[feature];
64
55
  if (!config) continue;
65
56
 
66
- const featureKey = feature.toLowerCase(); // šŸ”„ normalize
57
+ const featureKey = feature.toLowerCase();
67
58
 
68
- /* --------------------------- Middlewares ---------------------------- */
59
+ // Middlewares
69
60
  if (config.middleware && !appContent.includes(config.middleware)) {
70
61
  middlewareCode += `${config.middleware}\n`;
71
62
  }
72
63
 
73
- /* ------------------------------ Files -------------------------------- */
64
+ // Files
74
65
  if (config.files) {
75
66
  const files = isTS ? config.files.ts : config.files.js;
76
67
 
@@ -81,10 +72,9 @@ export function injectFeatures(serverPath, selectedFeatures = []) {
81
72
 
82
73
  if (fs.existsSync(filePath)) continue;
83
74
 
84
- // āœ… FIX: support fromTemplate
85
75
  if (file.fromTemplate) {
86
76
  const templatePath = path.join(
87
- process.cwd(),
77
+ CLI_ROOT,
88
78
  "templates",
89
79
  "backend",
90
80
  isTS ? "express-ts" : "express-js",
@@ -98,23 +88,21 @@ export function injectFeatures(serverPath, selectedFeatures = []) {
98
88
 
99
89
  fs.copyFileSync(templatePath, filePath);
100
90
  } else if (file.content) {
101
- fs.writeFileSync(filePath, file.content.trim());
91
+ fs.writeFileSync(filePath, file.content.trim(), "utf8");
102
92
  }
103
93
  }
104
94
  }
105
95
  }
106
96
 
107
- /* ------------------------------ Env ---------------------------------- */
97
+ // ENV
108
98
  if (Array.isArray(config.env)) {
109
99
  envVars.push(...config.env);
110
100
  }
111
101
 
112
- /* --------------------------- Cloudinary ------------------------------ */
113
- if (featureKey === "Cloudinary" && serverFile) {
102
+ // Cloudinary injection
103
+ if (featureKey === "cloudinary" && serverFile) {
114
104
  if (!serverContent.includes("connectCloudinary")) {
115
- const importPath = isTS
116
- ? "./utils/Cloudinary"
117
- : "./Utils/Cloudinary.js";
105
+ const importPath = isTS ? "./utils/Cloudinary" : "./Utils/Cloudinary.js";
118
106
 
119
107
  serverContent = serverContent.replace(
120
108
  /app\.listen|server\.listen/,
@@ -128,10 +116,7 @@ $&`
128
116
  }
129
117
  }
130
118
 
131
- /* ---------------------------------------------------------------------- */
132
- /* Inject middlewares */
133
- /* ---------------------------------------------------------------------- */
134
-
119
+ // Inject middleware into app file
135
120
  if (middlewareCode && appContent.includes("__INJECT_MIDDLEWARES__")) {
136
121
  appContent = appContent.replace(
137
122
  "// __INJECT_MIDDLEWARES__",
@@ -141,18 +126,11 @@ $&`
141
126
 
142
127
  fs.writeFileSync(appFile, appContent, "utf8");
143
128
 
144
- /* ---------------------------------------------------------------------- */
145
- /* Write server file */
146
- /* ---------------------------------------------------------------------- */
147
-
148
129
  if (serverFile && serverContent) {
149
130
  fs.writeFileSync(serverFile, serverContent, "utf8");
150
131
  }
151
132
 
152
- /* ---------------------------------------------------------------------- */
153
- /* Append env variables */
154
- /* ---------------------------------------------------------------------- */
155
-
133
+ // Append ENV vars
156
134
  const envExamplePath = path.join(serverPath, ".env.example");
157
135
 
158
136
  if (envVars.length && fs.existsSync(envExamplePath)) {