create-fullstack-setup 1.0.9 → 1.0.11

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,16 +6,12 @@ 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
17
  type: "list",
@@ -27,7 +23,7 @@ const answers = await inquirer.prompt([
27
23
  type: "list",
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
29
  type: "list",
@@ -35,88 +31,72 @@ const answers = await inquirer.prompt([
35
31
  message: "Choose language:",
36
32
  choices: ["JavaScript", "TypeScript"]
37
33
  },
38
-
39
- /* ----------------------- Backend Feature Gate ---------------------------- */
40
-
41
34
  {
42
- type: "confirm",
43
- name: "useBackendFeatures",
44
- message: "Select backend features?",
45
- default: true
46
- },
47
-
48
- /* ---------------------- Conditional Feature Prompts ---------------------- */
35
+ type: "confirm",
36
+ name: "useBackendFeatures",
37
+ message: "Select backend features?",
38
+ default: true
39
+ },
49
40
 
50
41
  {
51
42
  type: "confirm",
52
- name: "useJWT",
43
+ name: "JWT",
53
44
  message: "Use JWT authentication?",
54
45
  default: true,
55
- when: ans => ans.useBackendFeatures
46
+ when: (ans) => ans.useBackendFeatures
56
47
  },
57
48
  {
58
49
  type: "confirm",
59
- name: "useCORS",
50
+ name: "CORS",
60
51
  message: "Enable CORS?",
61
52
  default: true,
62
- when: ans => ans.useBackendFeatures
53
+ when: (ans) => ans.useBackendFeatures
63
54
  },
64
55
  {
65
56
  type: "confirm",
66
- name: "useCookieParser",
57
+ name: "CookieParser",
67
58
  message: "Use Cookie Parser?",
68
59
  default: true,
69
- when: ans => ans.useBackendFeatures
60
+ when: (ans) => ans.useBackendFeatures
70
61
  },
71
62
  {
72
63
  type: "confirm",
73
- name: "useCloudinary",
74
- message: "Use Cloudinary?",
64
+ name: "dotenv",
65
+ message: "Use environment variable ?",
75
66
  default: true,
76
- when: ans => ans.useBackendFeatures
67
+ when: (ans) => ans.useBackendFeatures
77
68
  },
78
69
  {
79
70
  type: "confirm",
80
- name: "useMongoose",
81
- message: "Use MongoDB (Mongoose)?",
71
+ name: "Zod",
72
+ message: "Use Zod validator?",
82
73
  default: true,
83
- when: ans => ans.useBackendFeatures
74
+ when: (ans) => ans.useBackendFeatures
84
75
  },
85
76
  {
86
77
  type: "confirm",
87
- name: "useZod",
88
- message: "Use Zod validation?",
78
+ name: "multer",
79
+ message: "Use multer ?",
89
80
  default: true,
90
- when: ans => ans.useBackendFeatures
81
+ when: (ans) => ans.useBackendFeatures
91
82
  },
92
83
  {
93
84
  type: "confirm",
94
- name: "useDotenv",
95
- message: "Use Dotenv?",
85
+ name: "Mongoose",
86
+ message: "Use MongoDB (Mongoose)?",
96
87
  default: true,
97
- when: ans => ans.useBackendFeatures
88
+ when: (ans) => ans.useBackendFeatures
98
89
  },
99
90
  {
100
91
  type: "confirm",
101
- name: "useBcrypt",
92
+ name: "Bcrypt",
102
93
  message: "Use Bcrypt for password hashing?",
103
94
  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
95
+ when: (ans) => ans.useBackendFeatures
112
96
  }
113
97
  ]);
114
98
 
115
99
 
116
- /* -------------------------------------------------------------------------- */
117
- /* MAP ANSWERS → TEMPLATE KEYS */
118
- /* -------------------------------------------------------------------------- */
119
-
120
100
  const frontendMap = {
121
101
  React: {
122
102
  JavaScript: "react-js",
@@ -136,27 +116,19 @@ const backendMap = {
136
116
  }
137
117
  };
138
118
 
139
- /* -------------------------------------------------------------------------- */
140
- /* BUILD backendFeatures ARRAY (IMPORTANT) */
141
- /* -------------------------------------------------------------------------- */
142
-
143
119
  const backendFeatures = [];
144
120
 
145
121
  if (answers.useBackendFeatures) {
146
- if (answers.useJWT) backendFeatures.push("JWT");
147
- if (answers.useCORS) backendFeatures.push("CORS");
148
- if (answers.useCookieParser) backendFeatures.push("Cookie-Parser");
149
- if (answers.useMongoose) backendFeatures.push("Mongoose");
150
- 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");
122
+ if (answers.JWT) backendFeatures.push("JWT");
123
+ if (answers.CORS) backendFeatures.push("CORS");
124
+ if (answers.CookieParser) backendFeatures.push("Cookie-Parser");
125
+ if (answers.dotenv) backendFeatures.push("Dotenv");
126
+ if (answers.Zod) backendFeatures.push("Zod");
127
+ if (answers.multer) backendFeatures.push("Multer");
128
+ if (answers.Mongoose) backendFeatures.push("Mongoose");
129
+ if (answers.Bcrypt) backendFeatures.push("Bcrypt");
155
130
  }
156
131
 
157
- /* -------------------------------------------------------------------------- */
158
- /* BUILD CONFIG OBJECT */
159
- /* -------------------------------------------------------------------------- */
160
132
 
161
133
  const config = {
162
134
  projectName: answers.projectName,
@@ -165,11 +137,7 @@ const config = {
165
137
  ? "None"
166
138
  : frontendMap[answers.frontend][answers.language],
167
139
  backend: backendMap[answers.backend][answers.language],
168
- backendFeatures // āœ… ALWAYS ARRAY
140
+ backendFeatures
169
141
  };
170
142
 
171
- /* -------------------------------------------------------------------------- */
172
- /* CREATE PROJECT */
173
- /* -------------------------------------------------------------------------- */
174
-
175
- await createProject(config);
143
+ await createProject(config);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-fullstack-setup",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "CLI to generate ready-to-run fullstack or backend applications",
5
5
  "bin": {
6
6
  "create-fullstack-setup": "bin/index.js"
@@ -1,10 +1,5 @@
1
- /* -------------------------------------------------------------------------- */
2
- /* Backend Feature Configuration */
3
- /* -------------------------------------------------------------------------- */
4
1
 
5
2
  export const FEATURES = {
6
- /* =============================== CORS ================================= */
7
-
8
3
  CORS: {
9
4
  middleware: `
10
5
  import cors from "cors";
@@ -13,8 +8,6 @@ app.use(cors());
13
8
  env: []
14
9
  },
15
10
 
16
- /* =========================== COOKIE PARSER ============================= */
17
-
18
11
  "Cookie-Parser": {
19
12
  middleware: `
20
13
  import cookieParser from "cookie-parser";
@@ -23,48 +16,32 @@ app.use(cookieParser());
23
16
  env: []
24
17
  },
25
18
 
26
- /* ================================ JWT ================================= */
27
-
28
19
  JWT: {
29
20
  middleware: "",
30
21
  files: {
31
22
  js: [
32
- {
33
- path: "middlewares/Auth.middleware.js",
34
- fromTemplate:true,
35
- }
23
+ { path: "middlewares/Auth.middleware.js", fromTemplate: true }
36
24
  ],
37
25
  ts: [
38
- {
39
- path: "src/middlewares/auth.middleware.ts",
40
- fromTemplate:true,
41
- }
26
+ { path: "src/middlewares/auth.middleware.ts", fromTemplate: true }
42
27
  ]
43
28
  },
29
+ env: ["ACCESS_TOKEN_SECRET=your_secret"]
44
30
  },
45
31
 
46
- /* ============================ CLOUDINARY ============================== */
47
-
48
32
  Cloudinary: {
49
33
  middleware: "",
50
34
  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
- }
35
+ js: [{ path: "Utils/Cloudinary.js", fromTemplate: true }],
36
+ ts: [{ path: "src/utils/Cloudinary.ts", fromTemplate: true }]
37
+ },
38
+ env: [
39
+ "CLOUDINARY_NAME=",
40
+ "CLOUDINARY_API_KEY=",
41
+ "CLOUDINARY_API_SECRET="
42
+ ]
64
43
  },
65
44
 
66
- /* ============================== DOTENV ================================ */
67
-
68
45
  Dotenv: {
69
46
  middleware: `import "dotenv/config";`,
70
47
  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)) {
package/utils/prompts.js CHANGED
@@ -1,59 +0,0 @@
1
- import { type } from "os";
2
-
3
- const answers = await inquirer.prompt([
4
- {
5
- type:"confirm",
6
- name:"express",
7
- message:"install express ?",
8
- default:true
9
- },
10
-
11
- {
12
- type: "confirm",
13
- name: "JWT",
14
- message: "Use JWT authentication?",
15
- default: true
16
- },
17
- {
18
- type: "confirm",
19
- name: "CORS",
20
- message: "Enable CORS?",
21
- default: true
22
- },
23
- {
24
- type: "confirm",
25
- name: "CookieParser",
26
- message: "Use Cookie Parser?",
27
- default: true
28
- },
29
- {
30
- type: "confirm",
31
- name: "dotenv",
32
- message: "Use environment variable ?",
33
- default: true
34
- },
35
- {
36
- type: "confirm",
37
- name: "Zod",
38
- message: "Use Zod validator?",
39
- default: true
40
- },
41
- {
42
- type: "confirm",
43
- name: "multer",
44
- message: "Use multer ?",
45
- default: true
46
- },
47
- {
48
- type: "confirm",
49
- name: "Mongoose",
50
- message: "Use MongoDB (Mongoose)?",
51
- default: false
52
- },
53
- {
54
- type: "confirm",
55
- name: "Bcrypt",
56
- message: "Use Bcrypt for password hashing?",
57
- default: true
58
- }
59
- ]);