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.
Files changed (79) hide show
  1. package/.github/workflows/release.yml +26 -26
  2. package/CHANGELOG.md +301 -211
  3. package/LICENSE +21 -21
  4. package/README.md +354 -213
  5. package/bin/index.js +444 -288
  6. package/bin/lib/pkgManager.js +49 -49
  7. package/bin/lib/templateHandler.js +33 -33
  8. package/create-charcole-2.1.0.tgz +0 -0
  9. package/package.json +42 -27
  10. package/packages/swagger/BACKWARD_COMPATIBILITY.md +145 -0
  11. package/packages/swagger/CHANGELOG.md +404 -0
  12. package/packages/swagger/README.md +578 -0
  13. package/packages/swagger/charcole-swagger-1.0.0.tgz +0 -0
  14. package/packages/swagger/package-lock.json +1715 -0
  15. package/packages/swagger/package.json +57 -0
  16. package/packages/swagger/src/helpers.js +427 -0
  17. package/packages/swagger/src/index.d.ts +126 -0
  18. package/packages/swagger/src/index.js +12 -0
  19. package/packages/swagger/src/setup.js +100 -0
  20. package/template/js/.env.example +15 -15
  21. package/template/js/README.md +978 -855
  22. package/template/js/basePackage.json +26 -26
  23. package/template/js/src/app.js +81 -78
  24. package/template/js/src/config/constants.js +20 -20
  25. package/template/js/src/config/env.js +26 -26
  26. package/template/js/src/config/swagger.config.js +15 -0
  27. package/template/js/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
  28. package/template/js/src/middlewares/errorHandler.js +180 -180
  29. package/template/js/src/middlewares/requestLogger.js +33 -33
  30. package/template/js/src/middlewares/validateRequest.js +42 -42
  31. package/template/js/src/modules/auth/auth.constants.js +3 -3
  32. package/template/js/src/modules/auth/auth.controller.js +29 -29
  33. package/template/js/src/modules/auth/auth.middlewares.js +19 -19
  34. package/template/js/src/modules/auth/auth.routes.js +131 -9
  35. package/template/js/src/modules/auth/auth.schemas.js +60 -60
  36. package/template/js/src/modules/auth/auth.service.js +67 -67
  37. package/template/js/src/modules/auth/package.json +6 -6
  38. package/template/js/src/modules/health/controller.js +151 -50
  39. package/template/js/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
  40. package/template/js/src/modules/swagger/package.json +5 -0
  41. package/template/js/src/repositories/user.repo.js +19 -19
  42. package/template/js/src/routes/index.js +25 -25
  43. package/template/js/src/routes/protected.js +57 -13
  44. package/template/js/src/server.js +38 -38
  45. package/template/js/src/utils/AppError.js +182 -182
  46. package/template/js/src/utils/logger.js +73 -73
  47. package/template/js/src/utils/response.js +51 -51
  48. package/template/ts/.env.example +15 -15
  49. package/template/ts/README.md +978 -855
  50. package/template/ts/basePackage.json +36 -36
  51. package/template/ts/build.js +46 -46
  52. package/template/ts/src/app.ts +71 -67
  53. package/template/ts/src/config/constants.ts +27 -27
  54. package/template/ts/src/config/env.ts +40 -40
  55. package/template/ts/src/config/swagger.config.ts +30 -0
  56. package/template/ts/src/lib/swagger/SWAGGER_GUIDE.md +561 -0
  57. package/template/ts/src/middlewares/errorHandler.ts +201 -201
  58. package/template/ts/src/middlewares/requestLogger.ts +38 -38
  59. package/template/ts/src/middlewares/validateRequest.ts +46 -46
  60. package/template/ts/src/modules/auth/auth.constants.ts +6 -6
  61. package/template/ts/src/modules/auth/auth.controller.ts +32 -32
  62. package/template/ts/src/modules/auth/auth.middlewares.ts +46 -46
  63. package/template/ts/src/modules/auth/auth.routes.ts +52 -9
  64. package/template/ts/src/modules/auth/auth.schemas.ts +73 -73
  65. package/template/ts/src/modules/auth/auth.service.ts +106 -106
  66. package/template/ts/src/modules/auth/package.json +10 -10
  67. package/template/ts/src/modules/health/controller.ts +80 -64
  68. package/template/ts/src/modules/swagger/charcole-swagger-1.0.0.tgz +0 -0
  69. package/template/ts/src/modules/swagger/package.json +5 -0
  70. package/template/ts/src/repositories/user.repo.ts +33 -33
  71. package/template/ts/src/routes/index.ts +24 -24
  72. package/template/ts/src/routes/protected.ts +46 -13
  73. package/template/ts/src/server.ts +41 -41
  74. package/template/ts/src/types/express.d.ts +9 -9
  75. package/template/ts/src/utils/AppError.ts +220 -220
  76. package/template/ts/src/utils/logger.ts +55 -55
  77. package/template/ts/src/utils/response.ts +100 -100
  78. package/template/ts/tsconfig.json +26 -26
  79. 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
- if (excludeFiles.includes(entry.name)) {
59
- console.log(`Skipping excluded file: ${entry.name}`);
60
- continue;
61
- }
62
-
63
- if (entry.isDirectory()) {
64
- copyDirRecursive(srcPath, destPath, excludeFiles);
65
- } else {
66
- fs.copyFileSync(srcPath, destPath);
67
- }
68
- }
69
- }
70
-
71
- (async function main() {
72
- try {
73
- console.log("🔥 Welcome to Charcole v2.1 CLI");
74
-
75
- // Check if project name is provided as command line argument
76
- const args = process.argv.slice(2);
77
- let projectNameFromArgs = null;
78
-
79
- if (args.length > 0) {
80
- // The first argument that doesn't start with '-' is likely the project name
81
- for (const arg of args) {
82
- if (!arg.startsWith("-")) {
83
- projectNameFromArgs = arg;
84
- break;
85
- }
86
- }
87
- }
88
-
89
- const questions = [];
90
-
91
- // Only ask for project name if not provided in command line
92
- if (!projectNameFromArgs) {
93
- questions.push({
94
- type: "text",
95
- name: "projectName",
96
- message: "Project name:",
97
- validate: (name) => (name ? true : "Project name is required"),
98
- });
99
- }
100
-
101
- questions.push(
102
- {
103
- type: "select",
104
- name: "language",
105
- message: "Language:",
106
- choices: [
107
- { title: "TypeScript", value: "ts" },
108
- { title: "JavaScript", value: "js" },
109
- ],
110
- },
111
- {
112
- type: "confirm",
113
- name: "auth",
114
- message: "Include JWT authentication module?",
115
- initial: true,
116
- },
117
- );
118
-
119
- const responses = await prompts(questions);
120
-
121
- // Use command line project name if provided, otherwise use prompt response
122
- const projectName = projectNameFromArgs || responses.projectName;
123
- const { language, auth } = responses;
124
-
125
- if (!projectName || projectName.trim() === "") {
126
- console.error(" Project name is required");
127
- process.exit(1);
128
- }
129
-
130
- const targetDir = path.join(process.cwd(), projectName);
131
-
132
- if (fs.existsSync(targetDir)) {
133
- console.error(`❌ Folder "${projectName}" already exists.`);
134
- process.exit(1);
135
- }
136
-
137
- const pkgManager = detectPackageManager();
138
- const templateDir = path.join(__dirname, "..", "template", language);
139
-
140
- console.log(
141
- `\n📁 Creating project "${projectName}" in ${language.toUpperCase()}...`,
142
- );
143
-
144
- fs.mkdirSync(targetDir, { recursive: true });
145
-
146
- const basePkgPath = path.join(templateDir, "basePackage.json");
147
- if (!fs.existsSync(basePkgPath)) {
148
- throw new Error(`basePackage.json not found at ${basePkgPath}`);
149
- }
150
-
151
- let mergedPkg = JSON.parse(fs.readFileSync(basePkgPath, "utf-8"));
152
- console.log("✓ Loaded base package configuration");
153
-
154
- console.log("\n📁 Copying base template structure...");
155
-
156
- copyDirRecursive(templateDir, targetDir, ["basePackage.json"]);
157
-
158
- const templateModulesDir = path.join(templateDir, "src", "modules");
159
- const targetModulesDir = path.join(targetDir, "src", "modules");
160
-
161
- if (fs.existsSync(templateModulesDir)) {
162
- if (!fs.existsSync(targetModulesDir)) {
163
- fs.mkdirSync(targetModulesDir, { recursive: true });
164
- }
165
-
166
- const moduleEntries = fs.readdirSync(templateModulesDir, {
167
- withFileTypes: true,
168
- });
169
-
170
- for (const entry of moduleEntries) {
171
- if (entry.isDirectory()) {
172
- const moduleName = entry.name;
173
- const moduleSrcPath = path.join(templateModulesDir, moduleName);
174
-
175
- if (moduleName === "auth") {
176
- if (!auth) {
177
- console.log(`⏭️ Skipping auth module (not selected)`);
178
- continue;
179
- }
180
- } else {
181
- const moduleDestPath = path.join(targetModulesDir, moduleName);
182
- console.log(`📦 Copying ${moduleName} module...`);
183
- copyDirRecursive(moduleSrcPath, moduleDestPath);
184
- }
185
- }
186
- }
187
- }
188
-
189
- // Handle JWT authentication module if selected
190
- if (auth) {
191
- console.log("\n📦 Adding JWT authentication module...");
192
-
193
- // The auth module is in src/modules/auth in the template
194
- const authModulePath = path.join(templateDir, "src", "modules", "auth");
195
-
196
- if (!fs.existsSync(authModulePath)) {
197
- console.error(`❌ Auth module not found at ${authModulePath}`);
198
- } else {
199
- // 1. Merge auth module's package.json
200
- const authPkgPath = path.join(authModulePath, "package.json");
201
-
202
- if (fs.existsSync(authPkgPath)) {
203
- try {
204
- const authPkg = JSON.parse(fs.readFileSync(authPkgPath, "utf-8"));
205
- console.log("✓ Found auth module package.json");
206
-
207
- mergedPkg = mergePackageJson(mergedPkg, authPkg);
208
- console.log("✓ Merged auth module dependencies");
209
- console.log(
210
- " Added dependencies:",
211
- Object.keys(authPkg.dependencies || {}).join(", "),
212
- );
213
- if (authPkg.devDependencies) {
214
- console.log(
215
- " Added devDependencies:",
216
- Object.keys(authPkg.devDependencies).join(", "),
217
- );
218
- }
219
- } catch (error) {
220
- console.error(
221
- `❌ Failed to parse auth module package.json:`,
222
- error.message,
223
- );
224
- }
225
- } else {
226
- console.error(
227
- "❌ Auth module package.json not found at:",
228
- authPkgPath,
229
- );
230
- }
231
-
232
- const targetAuthPath = path.join(targetModulesDir, "auth");
233
- console.log(
234
- `Copying auth module to: ${targetAuthPath} (excluding package.json)`,
235
- );
236
-
237
- copyDirRecursive(authModulePath, targetAuthPath, ["package.json"]);
238
- console.log("✓ Copied auth module files (package.json was excluded)");
239
-
240
- const copiedPkgPath = path.join(targetAuthPath, "package.json");
241
- if (fs.existsSync(copiedPkgPath)) {
242
- console.warn(
243
- "⚠️ package.json was accidentally copied, removing it...",
244
- );
245
- fs.unlinkSync(copiedPkgPath);
246
- }
247
- }
248
- } else {
249
- console.log("\n⏭️ Skipping JWT authentication module");
250
-
251
- const targetAuthPath = path.join(targetDir, "src", "modules", "auth");
252
- if (fs.existsSync(targetAuthPath)) {
253
- console.log("Cleaning up auth directory (not selected)...");
254
- fs.rmSync(targetAuthPath, { recursive: true, force: true });
255
- }
256
- }
257
-
258
- mergedPkg.name = projectName;
259
-
260
- const finalPkgPath = path.join(targetDir, "package.json");
261
- fs.writeFileSync(finalPkgPath, JSON.stringify(mergedPkg, null, 2));
262
- console.log(`\n📝 Created package.json at ${finalPkgPath}`);
263
-
264
- console.log("\n📦 Final package.json dependencies:");
265
- console.log(
266
- " dependencies:",
267
- Object.keys(mergedPkg.dependencies || {}).join(", "),
268
- );
269
- console.log(
270
- " devDependencies:",
271
- Object.keys(mergedPkg.devDependencies || {}).join(", "),
272
- );
273
-
274
- console.log(`\n📦 Installing dependencies using ${pkgManager}...`);
275
- installDependencies(targetDir, pkgManager);
276
-
277
- console.log("\n✅ Charcole project created successfully!");
278
- console.log(
279
- `\n🚀 Next steps:\n cd ${projectName}\n ${
280
- pkgManager === "npm" ? "npm run dev" : `${pkgManager} run dev`
281
- }`,
282
- );
283
- } catch (err) {
284
- console.error("❌ Failed to create Charcole project:", err.message);
285
- console.error(err.stack);
286
- process.exit(1);
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
+ })();