create-charcole 2.1.0 → 2.2.1
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/.github/workflows/release.yml +26 -26
- package/CHANGELOG.md +301 -211
- package/LICENSE +21 -21
- package/README.md +354 -213
- package/bin/index.js +444 -288
- package/bin/lib/pkgManager.js +49 -49
- package/bin/lib/templateHandler.js +33 -33
- package/create-charcole-2.1.0.tgz +0 -0
- package/package.json +42 -27
- package/packages/swagger/BACKWARD_COMPATIBILITY.md +145 -0
- package/packages/swagger/CHANGELOG.md +404 -0
- package/packages/swagger/README.md +578 -0
- package/packages/swagger/charcole-swagger-1.0.0.tgz +0 -0
- package/packages/swagger/package-lock.json +1715 -0
- package/packages/swagger/package.json +57 -0
- package/packages/swagger/src/helpers.js +427 -0
- package/packages/swagger/src/index.d.ts +126 -0
- package/packages/swagger/src/index.js +12 -0
- package/packages/swagger/src/setup.js +100 -0
- package/template/js/.env.example +15 -15
- package/template/js/README.md +978 -855
- package/template/js/basePackage.json +26 -26
- package/template/js/src/app.js +81 -78
- package/template/js/src/config/constants.js +20 -20
- package/template/js/src/config/env.js +26 -26
- package/template/js/src/config/swagger.config.js +15 -0
- package/template/js/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
- package/template/js/src/middlewares/errorHandler.js +180 -180
- package/template/js/src/middlewares/requestLogger.js +33 -33
- package/template/js/src/middlewares/validateRequest.js +42 -42
- package/template/js/src/modules/auth/auth.constants.js +3 -3
- package/template/js/src/modules/auth/auth.controller.js +29 -29
- package/template/js/src/modules/auth/auth.middlewares.js +19 -19
- package/template/js/src/modules/auth/auth.routes.js +131 -9
- package/template/js/src/modules/auth/auth.schemas.js +60 -60
- package/template/js/src/modules/auth/auth.service.js +67 -67
- package/template/js/src/modules/auth/package.json +6 -6
- package/template/js/src/modules/health/controller.js +151 -50
- package/template/js/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
- package/template/js/src/modules/swagger/package.json +5 -0
- package/template/js/src/repositories/user.repo.js +19 -19
- package/template/js/src/routes/index.js +25 -25
- package/template/js/src/routes/protected.js +57 -13
- package/template/js/src/server.js +38 -38
- package/template/js/src/utils/AppError.js +182 -182
- package/template/js/src/utils/logger.js +73 -73
- package/template/js/src/utils/response.js +51 -51
- package/template/ts/.env.example +15 -15
- package/template/ts/README.md +978 -855
- package/template/ts/basePackage.json +36 -36
- package/template/ts/build.js +46 -46
- package/template/ts/src/app.ts +71 -67
- package/template/ts/src/config/constants.ts +27 -27
- package/template/ts/src/config/env.ts +40 -40
- package/template/ts/src/config/swagger.config.ts +30 -0
- package/template/ts/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
- package/template/ts/src/middlewares/errorHandler.ts +201 -201
- package/template/ts/src/middlewares/requestLogger.ts +38 -38
- package/template/ts/src/middlewares/validateRequest.ts +46 -46
- package/template/ts/src/modules/auth/auth.constants.ts +6 -6
- package/template/ts/src/modules/auth/auth.controller.ts +32 -32
- package/template/ts/src/modules/auth/auth.middlewares.ts +46 -46
- package/template/ts/src/modules/auth/auth.routes.ts +52 -9
- package/template/ts/src/modules/auth/auth.schemas.ts +73 -73
- package/template/ts/src/modules/auth/auth.service.ts +106 -106
- package/template/ts/src/modules/auth/package.json +10 -10
- package/template/ts/src/modules/health/controller.ts +80 -64
- package/template/ts/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
- package/template/ts/src/modules/swagger/package.json +5 -0
- package/template/ts/src/repositories/user.repo.ts +33 -33
- package/template/ts/src/routes/index.ts +24 -24
- package/template/ts/src/routes/protected.ts +46 -13
- package/template/ts/src/server.ts +41 -41
- package/template/ts/src/types/express.d.ts +9 -9
- package/template/ts/src/utils/AppError.ts +220 -220
- package/template/ts/src/utils/logger.ts +55 -55
- package/template/ts/src/utils/response.ts +100 -100
- package/template/ts/tsconfig.json +26 -26
- package/plans/V2_1_PLAN.md +0 -20
package/bin/index.js
CHANGED
|
@@ -1,288 +1,444 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const path = require("path");
|
|
4
|
-
const fs = require("fs");
|
|
5
|
-
const prompts = require("prompts");
|
|
6
|
-
|
|
7
|
-
const {
|
|
8
|
-
detectPackageManager,
|
|
9
|
-
installDependencies,
|
|
10
|
-
} = require("./lib/pkgManager");
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* Merge base package.json with a feature package.json
|
|
14
|
-
*/
|
|
15
|
-
function mergePackageJson(base, fragment) {
|
|
16
|
-
const merged = { ...base };
|
|
17
|
-
|
|
18
|
-
// Merge dependencies
|
|
19
|
-
if (fragment.dependencies) {
|
|
20
|
-
merged.dependencies = {
|
|
21
|
-
...merged.dependencies,
|
|
22
|
-
...fragment.dependencies,
|
|
23
|
-
};
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Merge devDependencies
|
|
27
|
-
if (fragment.devDependencies) {
|
|
28
|
-
merged.devDependencies = {
|
|
29
|
-
...merged.devDependencies,
|
|
30
|
-
...fragment.devDependencies,
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Merge scripts
|
|
35
|
-
if (fragment.scripts) {
|
|
36
|
-
merged.scripts = {
|
|
37
|
-
...merged.scripts,
|
|
38
|
-
...fragment.scripts,
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return merged;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function copyDirRecursive(src, dest, excludeFiles = []) {
|
|
46
|
-
if (!fs.existsSync(src)) return;
|
|
47
|
-
|
|
48
|
-
if (!fs.existsSync(dest)) {
|
|
49
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
53
|
-
|
|
54
|
-
for (const entry of entries) {
|
|
55
|
-
const srcPath = path.join(src, entry.name);
|
|
56
|
-
const destPath = path.join(dest, entry.name);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
questions
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const path = require("path");
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const prompts = require("prompts");
|
|
6
|
+
|
|
7
|
+
const {
|
|
8
|
+
detectPackageManager,
|
|
9
|
+
installDependencies,
|
|
10
|
+
} = require("./lib/pkgManager");
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Merge base package.json with a feature package.json
|
|
14
|
+
*/
|
|
15
|
+
function mergePackageJson(base, fragment) {
|
|
16
|
+
const merged = { ...base };
|
|
17
|
+
|
|
18
|
+
// Merge dependencies
|
|
19
|
+
if (fragment.dependencies) {
|
|
20
|
+
merged.dependencies = {
|
|
21
|
+
...merged.dependencies,
|
|
22
|
+
...fragment.dependencies,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Merge devDependencies
|
|
27
|
+
if (fragment.devDependencies) {
|
|
28
|
+
merged.devDependencies = {
|
|
29
|
+
...merged.devDependencies,
|
|
30
|
+
...fragment.devDependencies,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Merge scripts
|
|
35
|
+
if (fragment.scripts) {
|
|
36
|
+
merged.scripts = {
|
|
37
|
+
...merged.scripts,
|
|
38
|
+
...fragment.scripts,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return merged;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function copyDirRecursive(src, dest, excludeFiles = [], excludeDirs = []) {
|
|
46
|
+
if (!fs.existsSync(src)) return;
|
|
47
|
+
|
|
48
|
+
if (!fs.existsSync(dest)) {
|
|
49
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
53
|
+
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
const srcPath = path.join(src, entry.name);
|
|
56
|
+
const destPath = path.join(dest, entry.name);
|
|
57
|
+
|
|
58
|
+
// Skip excluded files
|
|
59
|
+
if (excludeFiles.includes(entry.name)) {
|
|
60
|
+
console.log(`Skipping excluded file: ${entry.name}`);
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Skip .tgz files (tarball packages)
|
|
65
|
+
if (entry.name.endsWith(".tgz")) {
|
|
66
|
+
console.log(`Skipping tarball: ${entry.name}`);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (entry.isDirectory()) {
|
|
71
|
+
// Skip excluded directories
|
|
72
|
+
if (excludeDirs.includes(entry.name)) {
|
|
73
|
+
console.log(`Skipping excluded directory: ${entry.name}`);
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
copyDirRecursive(srcPath, destPath, excludeFiles, excludeDirs);
|
|
77
|
+
} else {
|
|
78
|
+
fs.copyFileSync(srcPath, destPath);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
(async function main() {
|
|
84
|
+
try {
|
|
85
|
+
console.log("🔥 Welcome to Charcole v2.2 CLI");
|
|
86
|
+
|
|
87
|
+
// Check if project name is provided as command line argument
|
|
88
|
+
const args = process.argv.slice(2);
|
|
89
|
+
let projectNameFromArgs = null;
|
|
90
|
+
|
|
91
|
+
if (args.length > 0) {
|
|
92
|
+
// The first argument that doesn't start with '-' is likely the project name
|
|
93
|
+
for (const arg of args) {
|
|
94
|
+
if (!arg.startsWith("-")) {
|
|
95
|
+
projectNameFromArgs = arg;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const questions = [];
|
|
102
|
+
|
|
103
|
+
// Only ask for project name if not provided in command line
|
|
104
|
+
if (!projectNameFromArgs) {
|
|
105
|
+
questions.push({
|
|
106
|
+
type: "text",
|
|
107
|
+
name: "projectName",
|
|
108
|
+
message: "Project name:",
|
|
109
|
+
validate: (name) => (name ? true : "Project name is required"),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
questions.push(
|
|
114
|
+
{
|
|
115
|
+
type: "select",
|
|
116
|
+
name: "language",
|
|
117
|
+
message: "Language:",
|
|
118
|
+
choices: [
|
|
119
|
+
{ title: "TypeScript", value: "ts" },
|
|
120
|
+
{ title: "JavaScript", value: "js" },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
type: "confirm",
|
|
125
|
+
name: "auth",
|
|
126
|
+
message: "Include JWT authentication module?",
|
|
127
|
+
initial: true,
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
type: "confirm",
|
|
131
|
+
name: "swagger",
|
|
132
|
+
message: "Include auto-generated Swagger documentation?",
|
|
133
|
+
initial: true,
|
|
134
|
+
},
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
const responses = await prompts(questions);
|
|
138
|
+
|
|
139
|
+
// Use command line project name if provided, otherwise use prompt response
|
|
140
|
+
const projectName = projectNameFromArgs || responses.projectName;
|
|
141
|
+
const { language, auth, swagger } = responses;
|
|
142
|
+
|
|
143
|
+
if (!projectName || projectName.trim() === "") {
|
|
144
|
+
console.error("❌ Project name is required");
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const targetDir = path.join(process.cwd(), projectName);
|
|
149
|
+
|
|
150
|
+
if (fs.existsSync(targetDir)) {
|
|
151
|
+
console.error(`❌ Folder "${projectName}" already exists.`);
|
|
152
|
+
process.exit(1);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const pkgManager = detectPackageManager();
|
|
156
|
+
const templateDir = path.join(__dirname, "..", "template", language);
|
|
157
|
+
|
|
158
|
+
console.log(
|
|
159
|
+
`\n📁 Creating project "${projectName}" in ${language.toUpperCase()}...`,
|
|
160
|
+
);
|
|
161
|
+
|
|
162
|
+
fs.mkdirSync(targetDir, { recursive: true });
|
|
163
|
+
|
|
164
|
+
const basePkgPath = path.join(templateDir, "basePackage.json");
|
|
165
|
+
if (!fs.existsSync(basePkgPath)) {
|
|
166
|
+
throw new Error(`basePackage.json not found at ${basePkgPath}`);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
let mergedPkg = JSON.parse(fs.readFileSync(basePkgPath, "utf-8"));
|
|
170
|
+
console.log("✓ Loaded base package configuration");
|
|
171
|
+
|
|
172
|
+
console.log("\n📁 Copying base template structure...");
|
|
173
|
+
|
|
174
|
+
// Exclude basePackage.json and swagger module directory from initial copy
|
|
175
|
+
// We'll handle modules separately based on user selection
|
|
176
|
+
const srcModulesDir = path.join(templateDir, "src", "modules");
|
|
177
|
+
|
|
178
|
+
// Copy everything except basePackage.json and the modules directory
|
|
179
|
+
copyDirRecursive(templateDir, targetDir, ["basePackage.json"], ["modules"]);
|
|
180
|
+
|
|
181
|
+
// Now handle modules directory manually
|
|
182
|
+
const templateModulesDir = srcModulesDir;
|
|
183
|
+
const targetModulesDir = path.join(targetDir, "src", "modules");
|
|
184
|
+
|
|
185
|
+
if (fs.existsSync(templateModulesDir)) {
|
|
186
|
+
if (!fs.existsSync(targetModulesDir)) {
|
|
187
|
+
fs.mkdirSync(targetModulesDir, { recursive: true });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const moduleEntries = fs.readdirSync(templateModulesDir, {
|
|
191
|
+
withFileTypes: true,
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
for (const entry of moduleEntries) {
|
|
195
|
+
if (entry.isDirectory()) {
|
|
196
|
+
const moduleName = entry.name;
|
|
197
|
+
const moduleSrcPath = path.join(templateModulesDir, moduleName);
|
|
198
|
+
|
|
199
|
+
if (moduleName === "auth") {
|
|
200
|
+
if (!auth) {
|
|
201
|
+
console.log(`⏭️ Skipping auth module (not selected)`);
|
|
202
|
+
continue;
|
|
203
|
+
}
|
|
204
|
+
} else if (moduleName === "swagger") {
|
|
205
|
+
if (!swagger) {
|
|
206
|
+
console.log(`⏭️ Skipping swagger module (not selected)`);
|
|
207
|
+
continue;
|
|
208
|
+
} else {
|
|
209
|
+
// Do not copy swagger module folder, just merge package.json below
|
|
210
|
+
console.log(
|
|
211
|
+
`⏭️ Not copying swagger module folder (merging dependencies only)`,
|
|
212
|
+
);
|
|
213
|
+
continue;
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
const moduleDestPath = path.join(targetModulesDir, moduleName);
|
|
217
|
+
console.log(`📦 Copying ${moduleName} module...`);
|
|
218
|
+
// Exclude package.json files from module folders
|
|
219
|
+
copyDirRecursive(moduleSrcPath, moduleDestPath, ["package.json"]);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
// Handle Swagger module if selected
|
|
225
|
+
if (swagger) {
|
|
226
|
+
console.log("\n📦 Adding Swagger module dependencies...");
|
|
227
|
+
const swaggerModuleDir = path.join(
|
|
228
|
+
templateDir,
|
|
229
|
+
"src",
|
|
230
|
+
"modules",
|
|
231
|
+
"swagger",
|
|
232
|
+
);
|
|
233
|
+
const swaggerPkgPath = path.join(swaggerModuleDir, "package.json");
|
|
234
|
+
const swaggerTgzPath = path.join(
|
|
235
|
+
swaggerModuleDir,
|
|
236
|
+
"charcole-swagger-1.0.0.tgz",
|
|
237
|
+
);
|
|
238
|
+
|
|
239
|
+
// Copy tarball temporarily for npm install (will be cleaned up after)
|
|
240
|
+
if (fs.existsSync(swaggerTgzPath)) {
|
|
241
|
+
fs.copyFileSync(
|
|
242
|
+
swaggerTgzPath,
|
|
243
|
+
path.join(targetDir, "charcole-swagger-1.0.0.tgz"),
|
|
244
|
+
);
|
|
245
|
+
console.log("✓ Copied Swagger tarball temporarily for installation");
|
|
246
|
+
} else {
|
|
247
|
+
console.error("❌ Swagger tarball not found at:", swaggerTgzPath);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (fs.existsSync(swaggerPkgPath)) {
|
|
251
|
+
try {
|
|
252
|
+
const swaggerPkg = JSON.parse(
|
|
253
|
+
fs.readFileSync(swaggerPkgPath, "utf-8"),
|
|
254
|
+
);
|
|
255
|
+
mergedPkg = mergePackageJson(mergedPkg, swaggerPkg);
|
|
256
|
+
console.log("✓ Merged Swagger module dependencies");
|
|
257
|
+
console.log(
|
|
258
|
+
" Added dependencies:",
|
|
259
|
+
Object.keys(swaggerPkg.dependencies || {}).join(", "),
|
|
260
|
+
);
|
|
261
|
+
if (swaggerPkg.devDependencies) {
|
|
262
|
+
console.log(
|
|
263
|
+
" Added devDependencies:",
|
|
264
|
+
Object.keys(swaggerPkg.devDependencies).join(", "),
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
} catch (error) {
|
|
268
|
+
console.error(
|
|
269
|
+
`❌ Failed to parse Swagger module package.json:`,
|
|
270
|
+
error.message,
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
} else {
|
|
274
|
+
console.error(
|
|
275
|
+
"❌ Swagger module package.json not found at:",
|
|
276
|
+
swaggerPkgPath,
|
|
277
|
+
);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
// Handle JWT authentication module if selected
|
|
282
|
+
if (auth) {
|
|
283
|
+
console.log("\n📦 Adding JWT authentication module...");
|
|
284
|
+
|
|
285
|
+
// The auth module is in src/modules/auth in the template
|
|
286
|
+
const authModulePath = path.join(templateDir, "src", "modules", "auth");
|
|
287
|
+
|
|
288
|
+
if (!fs.existsSync(authModulePath)) {
|
|
289
|
+
console.error(`❌ Auth module not found at ${authModulePath}`);
|
|
290
|
+
} else {
|
|
291
|
+
// 1. Merge auth module's package.json
|
|
292
|
+
const authPkgPath = path.join(authModulePath, "package.json");
|
|
293
|
+
|
|
294
|
+
if (fs.existsSync(authPkgPath)) {
|
|
295
|
+
try {
|
|
296
|
+
const authPkg = JSON.parse(fs.readFileSync(authPkgPath, "utf-8"));
|
|
297
|
+
console.log("✓ Found auth module package.json");
|
|
298
|
+
|
|
299
|
+
mergedPkg = mergePackageJson(mergedPkg, authPkg);
|
|
300
|
+
console.log("✓ Merged auth module dependencies");
|
|
301
|
+
console.log(
|
|
302
|
+
" Added dependencies:",
|
|
303
|
+
Object.keys(authPkg.dependencies || {}).join(", "),
|
|
304
|
+
);
|
|
305
|
+
if (authPkg.devDependencies) {
|
|
306
|
+
console.log(
|
|
307
|
+
" Added devDependencies:",
|
|
308
|
+
Object.keys(authPkg.devDependencies).join(", "),
|
|
309
|
+
);
|
|
310
|
+
}
|
|
311
|
+
} catch (error) {
|
|
312
|
+
console.error(
|
|
313
|
+
`❌ Failed to parse auth module package.json:`,
|
|
314
|
+
error.message,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
} else {
|
|
318
|
+
console.error(
|
|
319
|
+
"❌ Auth module package.json not found at:",
|
|
320
|
+
authPkgPath,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
const targetAuthPath = path.join(targetModulesDir, "auth");
|
|
325
|
+
console.log(
|
|
326
|
+
`Copying auth module to: ${targetAuthPath} (excluding package.json)`,
|
|
327
|
+
);
|
|
328
|
+
|
|
329
|
+
copyDirRecursive(authModulePath, targetAuthPath, ["package.json"], []);
|
|
330
|
+
console.log("✓ Copied auth module files (package.json was excluded)");
|
|
331
|
+
|
|
332
|
+
const copiedPkgPath = path.join(targetAuthPath, "package.json");
|
|
333
|
+
if (fs.existsSync(copiedPkgPath)) {
|
|
334
|
+
console.warn(
|
|
335
|
+
"⚠️ package.json was accidentally copied, removing it...",
|
|
336
|
+
);
|
|
337
|
+
fs.unlinkSync(copiedPkgPath);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
} else {
|
|
341
|
+
console.log("\n⏭️ Skipping JWT authentication module");
|
|
342
|
+
|
|
343
|
+
const targetAuthPath = path.join(targetDir, "src", "modules", "auth");
|
|
344
|
+
if (fs.existsSync(targetAuthPath)) {
|
|
345
|
+
console.log("Cleaning up auth directory (not selected)...");
|
|
346
|
+
fs.rmSync(targetAuthPath, { recursive: true, force: true });
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
// Remove Swagger imports and setup from app file if not selected
|
|
351
|
+
if (!swagger) {
|
|
352
|
+
console.log("\n🧹 Removing Swagger references from app file...");
|
|
353
|
+
const appFileName = language === "ts" ? "app.ts" : "app.js";
|
|
354
|
+
const appFilePath = path.join(targetDir, "src", appFileName);
|
|
355
|
+
|
|
356
|
+
if (fs.existsSync(appFilePath)) {
|
|
357
|
+
let appContent = fs.readFileSync(appFilePath, "utf-8");
|
|
358
|
+
|
|
359
|
+
// Remove swagger-related imports
|
|
360
|
+
const swaggerConfigImport =
|
|
361
|
+
language === "ts"
|
|
362
|
+
? 'import swaggerOptions from "./config/swagger.config";'
|
|
363
|
+
: 'import swaggerOptions from "./config/swagger.config.js";';
|
|
364
|
+
const setupSwaggerImport =
|
|
365
|
+
'import { setupSwagger } from "@charcoles/swagger";';
|
|
366
|
+
|
|
367
|
+
appContent = appContent
|
|
368
|
+
.split("\n")
|
|
369
|
+
.filter((line) => {
|
|
370
|
+
const trimmedLine = line.trim();
|
|
371
|
+
return (
|
|
372
|
+
!trimmedLine.includes(swaggerConfigImport.trim()) &&
|
|
373
|
+
!trimmedLine.includes(setupSwaggerImport.trim()) &&
|
|
374
|
+
!trimmedLine.includes("setupSwagger(app, swaggerOptions);")
|
|
375
|
+
);
|
|
376
|
+
})
|
|
377
|
+
.join("\n");
|
|
378
|
+
|
|
379
|
+
fs.writeFileSync(appFilePath, appContent, "utf-8");
|
|
380
|
+
console.log(`✓ Removed Swagger references from ${appFileName}`);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Remove swagger config file
|
|
384
|
+
const swaggerConfigFile =
|
|
385
|
+
language === "ts" ? "swagger.config.ts" : "swagger.config.js";
|
|
386
|
+
const swaggerConfigPath = path.join(
|
|
387
|
+
targetDir,
|
|
388
|
+
"src",
|
|
389
|
+
"config",
|
|
390
|
+
swaggerConfigFile,
|
|
391
|
+
);
|
|
392
|
+
if (fs.existsSync(swaggerConfigPath)) {
|
|
393
|
+
fs.unlinkSync(swaggerConfigPath);
|
|
394
|
+
console.log(`✓ Removed ${swaggerConfigFile}`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
// Remove lib/swagger directory
|
|
398
|
+
const swaggerLibPath = path.join(targetDir, "src", "lib", "swagger");
|
|
399
|
+
if (fs.existsSync(swaggerLibPath)) {
|
|
400
|
+
fs.rmSync(swaggerLibPath, { recursive: true, force: true });
|
|
401
|
+
console.log("✓ Removed lib/swagger directory");
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
mergedPkg.name = projectName;
|
|
406
|
+
|
|
407
|
+
const finalPkgPath = path.join(targetDir, "package.json");
|
|
408
|
+
fs.writeFileSync(finalPkgPath, JSON.stringify(mergedPkg, null, 2));
|
|
409
|
+
console.log(`\n📝 Created package.json at ${finalPkgPath}`);
|
|
410
|
+
|
|
411
|
+
console.log("\n📦 Final package.json dependencies:");
|
|
412
|
+
console.log(
|
|
413
|
+
" dependencies:",
|
|
414
|
+
Object.keys(mergedPkg.dependencies || {}).join(", "),
|
|
415
|
+
);
|
|
416
|
+
console.log(
|
|
417
|
+
" devDependencies:",
|
|
418
|
+
Object.keys(mergedPkg.devDependencies || {}).join(", "),
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
console.log(`\n📦 Installing dependencies using ${pkgManager}...`);
|
|
422
|
+
installDependencies(targetDir, pkgManager);
|
|
423
|
+
|
|
424
|
+
// Clean up the swagger tarball after installation
|
|
425
|
+
if (swagger) {
|
|
426
|
+
const tgzPath = path.join(targetDir, "charcole-swagger-1.0.0.tgz");
|
|
427
|
+
if (fs.existsSync(tgzPath)) {
|
|
428
|
+
fs.unlinkSync(tgzPath);
|
|
429
|
+
console.log("✓ Cleaned up temporary Swagger tarball");
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
console.log("\n✅ Charcole project created successfully!");
|
|
434
|
+
console.log(
|
|
435
|
+
`\n🚀 Next steps:\n cd ${projectName}\n ${
|
|
436
|
+
pkgManager === "npm" ? "npm run dev" : `${pkgManager} run dev`
|
|
437
|
+
}`,
|
|
438
|
+
);
|
|
439
|
+
} catch (err) {
|
|
440
|
+
console.error("❌ Failed to create Charcole project:", err.message);
|
|
441
|
+
console.error(err.stack);
|
|
442
|
+
process.exit(1);
|
|
443
|
+
}
|
|
444
|
+
})();
|