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 +37 -69
- package/package.json +1 -1
- package/utils/features.config.js +11 -34
- package/utils/injectFeatures.js +16 -38
- package/utils/prompts.js +0 -59
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"]
|
|
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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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: "
|
|
74
|
-
message: "Use
|
|
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: "
|
|
81
|
-
message: "Use
|
|
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: "
|
|
88
|
-
message: "Use
|
|
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: "
|
|
95
|
-
message: "Use
|
|
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: "
|
|
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.
|
|
147
|
-
if (answers.
|
|
148
|
-
if (answers.
|
|
149
|
-
if (answers.
|
|
150
|
-
if (answers.
|
|
151
|
-
if (answers.
|
|
152
|
-
if (answers.
|
|
153
|
-
if (answers.
|
|
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
|
|
140
|
+
backendFeatures
|
|
169
141
|
};
|
|
170
142
|
|
|
171
|
-
|
|
172
|
-
/* CREATE PROJECT */
|
|
173
|
-
/* -------------------------------------------------------------------------- */
|
|
174
|
-
|
|
175
|
-
await createProject(config);
|
|
143
|
+
await createProject(config);
|
package/package.json
CHANGED
package/utils/features.config.js
CHANGED
|
@@ -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
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
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"]
|
package/utils/injectFeatures.js
CHANGED
|
@@ -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
|
-
|
|
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();
|
|
57
|
+
const featureKey = feature.toLowerCase();
|
|
67
58
|
|
|
68
|
-
|
|
59
|
+
// Middlewares
|
|
69
60
|
if (config.middleware && !appContent.includes(config.middleware)) {
|
|
70
61
|
middlewareCode += `${config.middleware}\n`;
|
|
71
62
|
}
|
|
72
63
|
|
|
73
|
-
|
|
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
|
-
|
|
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
|
-
|
|
97
|
+
// ENV
|
|
108
98
|
if (Array.isArray(config.env)) {
|
|
109
99
|
envVars.push(...config.env);
|
|
110
100
|
}
|
|
111
101
|
|
|
112
|
-
|
|
113
|
-
if (featureKey === "
|
|
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
|
-
]);
|