@ifecodes/backend-template 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/cli.js CHANGED
@@ -184,6 +184,28 @@ if (!isInMicroserviceProject) {
184
184
  const readmeContent = generateReadme(config);
185
185
  fs.writeFileSync(path.join(target, "README.md"), readmeContent);
186
186
 
187
+ // Rename gitignore to .gitignore (npm doesn't publish .gitignore files)
188
+ if (config.projectType === "microservice") {
189
+ const servicesDir = path.join(target, "services");
190
+ const allServices = fs.readdirSync(servicesDir).filter((f) =>
191
+ fs.statSync(path.join(servicesDir, f)).isDirectory()
192
+ );
193
+
194
+ for (const service of allServices) {
195
+ const gitignorePath = path.join(servicesDir, service, "gitignore");
196
+ const dotGitignorePath = path.join(servicesDir, service, ".gitignore");
197
+ if (fs.existsSync(gitignorePath)) {
198
+ fs.renameSync(gitignorePath, dotGitignorePath);
199
+ }
200
+ }
201
+ } else {
202
+ const gitignorePath = path.join(target, "gitignore");
203
+ const dotGitignorePath = path.join(target, ".gitignore");
204
+ if (fs.existsSync(gitignorePath)) {
205
+ fs.renameSync(gitignorePath, dotGitignorePath);
206
+ }
207
+ }
208
+
187
209
  // Generate .env from .env.example for each service or root
188
210
  console.log("📄 Setting up environment files...\n");
189
211
  if (config.projectType === "microservice") {
@@ -47,6 +47,24 @@ export const getProjectConfig = async () => {
47
47
  message: "Project name",
48
48
  initial: "my-backend",
49
49
  },
50
+ {
51
+ type: isInMicroserviceProject || hasCliArgs || isCI ? null : "text",
52
+ name: "description",
53
+ message: "Project description (optional)",
54
+ initial: "",
55
+ },
56
+ {
57
+ type: isInMicroserviceProject || hasCliArgs || isCI ? null : "text",
58
+ name: "author",
59
+ message: "Author (optional)",
60
+ initial: "",
61
+ },
62
+ {
63
+ type: isInMicroserviceProject || hasCliArgs || isCI ? null : "text",
64
+ name: "keywords",
65
+ message: "Keywords (comma-separated, optional)",
66
+ initial: "",
67
+ },
50
68
  {
51
69
  type: isInMicroserviceProject || (hasCliArgs && cliProjectType) || isCI ? null : "select",
52
70
  name: "projectType",
@@ -14,6 +14,7 @@ export const setupService = async (
14
14
  let imports = [];
15
15
  let middlewares = [];
16
16
  let deps = [];
17
+ let devDeps = [];
17
18
  let v1Imports = [];
18
19
  let v1Routes = [];
19
20
 
@@ -61,6 +62,9 @@ export const setupService = async (
61
62
  imports.push(feature.imports);
62
63
  middlewares.push(feature.middleware);
63
64
  deps.push(...feature.deps);
65
+ if (feature.devDeps) {
66
+ devDeps.push(...feature.devDeps);
67
+ }
64
68
  }
65
69
  }
66
70
 
@@ -70,6 +74,9 @@ export const setupService = async (
70
74
  "../../template/features/auth/base/inject.js"
71
75
  );
72
76
  deps.push(...baseAuth.deps);
77
+ if (baseAuth.devDeps) {
78
+ devDeps.push(...baseAuth.devDeps);
79
+ }
73
80
 
74
81
  for (const file in baseAuth.files) {
75
82
  const fullPath = path.join(serviceRoot, file);
@@ -103,6 +110,9 @@ export const setupService = async (
103
110
  `../../template/features/auth/${algo.hasher}/inject.js`
104
111
  );
105
112
  deps.push(...hashFeature.deps);
113
+ if (hashFeature.devDeps) {
114
+ devDeps.push(...hashFeature.devDeps);
115
+ }
106
116
 
107
117
  for (const file in hashFeature.files) {
108
118
  const fullPath = path.join(serviceRoot, file);
@@ -291,10 +301,41 @@ await connectDB();`
291
301
  // Update package.json
292
302
  const packageJsonPath = path.join(serviceRoot, "package.json");
293
303
  const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
294
- packageJson.name = serviceName || res.sanitizedName;
304
+
305
+ // Create new package.json with name at the top
306
+ const orderedPackageJson = {
307
+ name: serviceName || res.sanitizedName,
308
+ version: packageJson.version,
309
+ description: res.description || packageJson.description,
310
+ ...packageJson,
311
+ };
312
+
313
+ // Remove duplicate keys that were moved to the top
314
+ delete orderedPackageJson.name;
315
+ delete orderedPackageJson.version;
316
+ delete orderedPackageJson.description;
317
+
318
+ // Re-add them at the top in correct order
319
+ const finalPackageJson = {
320
+ name: serviceName || res.sanitizedName,
321
+ version: packageJson.version,
322
+ description: res.description || packageJson.description,
323
+ ...orderedPackageJson,
324
+ };
325
+
326
+ // Add author if provided
327
+ if (res.author) {
328
+ finalPackageJson.author = res.author;
329
+ }
330
+
331
+ // Add keywords if provided
332
+ if (res.keywords && res.keywords.trim()) {
333
+ finalPackageJson.keywords = res.keywords.split(',').map(k => k.trim()).filter(Boolean);
334
+ }
335
+
295
336
  fs.writeFileSync(
296
337
  packageJsonPath,
297
- JSON.stringify(packageJson, null, 2) + "\n"
338
+ JSON.stringify(finalPackageJson, null, 2) + "\n"
298
339
  );
299
340
 
300
341
  // Install dependencies
@@ -311,6 +352,12 @@ await connectDB();`
311
352
  stdio: "inherit",
312
353
  });
313
354
  }
355
+ if (devDeps.length) {
356
+ execSync(`npm install -D ${devDeps.join(" ")}`, {
357
+ cwd: serviceRoot,
358
+ stdio: "inherit",
359
+ });
360
+ }
314
361
  execSync("npm install", { cwd: serviceRoot, stdio: "inherit" });
315
362
  installSucceeded = true;
316
363
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifecodes/backend-template",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Production-ready Express + TypeScript backend generator with optional features and microservice support",
5
5
  "bin": {
6
6
  "ifecodes-template": "bin/cli.js"
@@ -0,0 +1,31 @@
1
+ # Dependencies
2
+ node_modules/
3
+ package-lock.json
4
+
5
+ # Build output
6
+ dist/
7
+
8
+ # Environment variables
9
+ .env
10
+ .env.local
11
+ .env.*.local
12
+
13
+ # Logs
14
+ logs/
15
+ *.log
16
+ npm-debug.log*
17
+ yarn-debug.log*
18
+
19
+ # ESLint
20
+ .eslintcache
21
+
22
+ # OS files
23
+ .DS_Store
24
+ Thumbs.db
25
+
26
+ # IDE
27
+ .vscode/
28
+ .idea/
29
+ *.swp
30
+ *.swo
31
+
@@ -1,4 +1,7 @@
1
1
  {
2
+ "version": "1.0.0",
3
+ "description": "",
4
+ "main": "index.js",
2
5
  "scripts": {
3
6
  "dev": "ts-node-dev --respawn --transpile-only -r tsconfig-paths/register src/server.ts",
4
7
  "start": "node dist/server.js",
@@ -8,6 +11,10 @@
8
11
  "check-format": "prettier --check \"src/**/*.{ts,json}\"",
9
12
  "prepare": "husky"
10
13
  },
14
+ "keywords": [],
15
+ "author": "",
16
+ "license": "ISC",
17
+ "type": "commonjs",
11
18
  "dependencies": {
12
19
  "dotenv": "^16.3.1",
13
20
  "express": "^5.2.1",
@@ -4,29 +4,30 @@ function format(tag: string, args: unknown[]) {
4
4
  return [`%c[${tag}]`, "color:#6366f1;font-weight:600", ...args];
5
5
  }
6
6
 
7
- const environment =
8
- ENV.NODE_ENV === "development" || ENV.NODE_ENV === "staging"
7
+ function getEnvironment() {
8
+ return ENV.NODE_ENV === "development" || ENV.NODE_ENV === "staging"
9
9
  ? "development"
10
10
  : ENV.NODE_ENV;
11
+ }
11
12
 
12
13
  const logger = {
13
14
  log(tag: string, ...args: unknown[]) {
14
- if (environment !== "development") return;
15
+ if (getEnvironment() !== "development") return;
15
16
  console.log(...format(tag, args));
16
17
  },
17
18
 
18
19
  info(tag: string, ...args: unknown[]) {
19
- if (environment !== "development") return;
20
+ if (getEnvironment() !== "development") return;
20
21
  console.info(...format(tag, args));
21
22
  },
22
23
 
23
24
  warn(tag: string, ...args: unknown[]) {
24
- if (environment !== "development") return;
25
+ if (getEnvironment() !== "development") return;
25
26
  console.warn(...format(tag, args));
26
27
  },
27
28
 
28
29
  error(tag: string, ...args: unknown[]) {
29
- if (environment !== "development") return;
30
+ if (getEnvironment() !== "development") return;
30
31
  console.error(...format(tag, args));
31
32
  },
32
33
  };
@@ -84,6 +84,7 @@ export const imports = `import { authRoutes } from "./auth";`;
84
84
 
85
85
  export const middleware = `router.use("/auth", authRoutes);`;
86
86
 
87
- export const deps = ["jsonwebtoken", "@types/jsonwebtoken", "mongoose"];
87
+ export const deps = ["jsonwebtoken", "mongoose"];
88
+ export const devDeps = ["@types/jsonwebtoken"];
88
89
 
89
90
  export const targetFile = "src/modules/v1/index.ts";
@@ -1,5 +1,7 @@
1
1
  export const deps = ["bcrypt"];
2
2
 
3
+ export const devDeps = ["@types/bcrypt"];
4
+
3
5
  export const files = {
4
6
  "src/utils/hash.ts": `
5
7
  import bcrypt from "bcrypt";
@@ -1,5 +1,6 @@
1
- export const deps = ["cors", "@types/cors"];
2
- export const imports = `import cors from "cors";`;
1
+ export const deps = ["cors"];
2
+ export const devDeps = ["@types/cors"];
3
+ export const imports = `import cors from "cors";\nimport { ENV } from "@/config";`;
3
4
  export const middleware = `
4
5
  const corsOptions = {
5
6
  origin: ENV.ALLOWED_ORIGIN,
@@ -1,3 +1,4 @@
1
- export const deps = ["morgan", "@types/morgan"];
1
+ export const deps = ["morgan"];
2
+ export const devDeps = ["@types/morgan"];
2
3
  export const imports = `import morgan from "morgan";`;
3
4
  export const middleware = `app.use(morgan("dev"));`;