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/lib/pkgManager.js
CHANGED
|
@@ -1,49 +1,49 @@
|
|
|
1
|
-
const { execSync } = require("child_process");
|
|
2
|
-
const fs = require("fs");
|
|
3
|
-
const path = require("path");
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Detect which package manager the user is using
|
|
7
|
-
* Priority: pnpm > yarn > npm
|
|
8
|
-
*/
|
|
9
|
-
function detectPackageManager() {
|
|
10
|
-
const userAgent = process.env.npm_config_user_agent;
|
|
11
|
-
|
|
12
|
-
if (userAgent) {
|
|
13
|
-
if (userAgent.includes("pnpm")) return "pnpm";
|
|
14
|
-
if (userAgent.includes("yarn")) return "yarn";
|
|
15
|
-
if (userAgent.includes("npm")) return "npm";
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
const lockFiles = {
|
|
19
|
-
"pnpm-lock.yaml": "pnpm",
|
|
20
|
-
"yarn.lock": "yarn",
|
|
21
|
-
"package-lock.json": "npm",
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
for (const [lockFile, manager] of Object.entries(lockFiles)) {
|
|
25
|
-
if (fs.existsSync(path.join(process.cwd(), lockFile))) {
|
|
26
|
-
return manager;
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return "npm";
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Install dependencies
|
|
35
|
-
*/
|
|
36
|
-
function installDependencies(targetDir, pkgManager) {
|
|
37
|
-
const installCmd =
|
|
38
|
-
pkgManager === "yarn" ? "yarn install" : `${pkgManager} install`;
|
|
39
|
-
|
|
40
|
-
execSync(installCmd, {
|
|
41
|
-
cwd: targetDir,
|
|
42
|
-
stdio: "inherit",
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = {
|
|
47
|
-
detectPackageManager,
|
|
48
|
-
installDependencies,
|
|
49
|
-
};
|
|
1
|
+
const { execSync } = require("child_process");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const path = require("path");
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Detect which package manager the user is using
|
|
7
|
+
* Priority: pnpm > yarn > npm
|
|
8
|
+
*/
|
|
9
|
+
function detectPackageManager() {
|
|
10
|
+
const userAgent = process.env.npm_config_user_agent;
|
|
11
|
+
|
|
12
|
+
if (userAgent) {
|
|
13
|
+
if (userAgent.includes("pnpm")) return "pnpm";
|
|
14
|
+
if (userAgent.includes("yarn")) return "yarn";
|
|
15
|
+
if (userAgent.includes("npm")) return "npm";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const lockFiles = {
|
|
19
|
+
"pnpm-lock.yaml": "pnpm",
|
|
20
|
+
"yarn.lock": "yarn",
|
|
21
|
+
"package-lock.json": "npm",
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
for (const [lockFile, manager] of Object.entries(lockFiles)) {
|
|
25
|
+
if (fs.existsSync(path.join(process.cwd(), lockFile))) {
|
|
26
|
+
return manager;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return "npm";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Install dependencies
|
|
35
|
+
*/
|
|
36
|
+
function installDependencies(targetDir, pkgManager) {
|
|
37
|
+
const installCmd =
|
|
38
|
+
pkgManager === "yarn" ? "yarn install" : `${pkgManager} install`;
|
|
39
|
+
|
|
40
|
+
execSync(installCmd, {
|
|
41
|
+
cwd: targetDir,
|
|
42
|
+
stdio: "inherit",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
module.exports = {
|
|
47
|
+
detectPackageManager,
|
|
48
|
+
installDependencies,
|
|
49
|
+
};
|
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
const fs = require("fs");
|
|
2
|
-
const path = require("path");
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Recursively copy directory contents, excluding specific files
|
|
6
|
-
*/
|
|
7
|
-
function copyDir(src, dest, excludeFiles = []) {
|
|
8
|
-
if (!fs.existsSync(dest)) {
|
|
9
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
13
|
-
|
|
14
|
-
for (const entry of entries) {
|
|
15
|
-
const srcPath = path.join(src, entry.name);
|
|
16
|
-
const destPath = path.join(dest, entry.name);
|
|
17
|
-
|
|
18
|
-
// Skip excluded files
|
|
19
|
-
if (excludeFiles.includes(entry.name)) {
|
|
20
|
-
continue;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (entry.isDirectory()) {
|
|
24
|
-
copyDir(srcPath, destPath, excludeFiles);
|
|
25
|
-
} else {
|
|
26
|
-
fs.copyFileSync(srcPath, destPath);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
module.exports = {
|
|
32
|
-
copyDir,
|
|
33
|
-
};
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Recursively copy directory contents, excluding specific files
|
|
6
|
+
*/
|
|
7
|
+
function copyDir(src, dest, excludeFiles = []) {
|
|
8
|
+
if (!fs.existsSync(dest)) {
|
|
9
|
+
fs.mkdirSync(dest, { recursive: true });
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const entries = fs.readdirSync(src, { withFileTypes: true });
|
|
13
|
+
|
|
14
|
+
for (const entry of entries) {
|
|
15
|
+
const srcPath = path.join(src, entry.name);
|
|
16
|
+
const destPath = path.join(dest, entry.name);
|
|
17
|
+
|
|
18
|
+
// Skip excluded files
|
|
19
|
+
if (excludeFiles.includes(entry.name)) {
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (entry.isDirectory()) {
|
|
24
|
+
copyDir(srcPath, destPath, excludeFiles);
|
|
25
|
+
} else {
|
|
26
|
+
fs.copyFileSync(srcPath, destPath);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
module.exports = {
|
|
32
|
+
copyDir,
|
|
33
|
+
};
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,27 +1,42 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "create-charcole",
|
|
3
|
-
"version": "2.1
|
|
4
|
-
"description": "CLI to create production-ready Node.js Express APIs with TypeScript/JavaScript, JWT auth, and repository pattern",
|
|
5
|
-
"license": "MIT",
|
|
6
|
-
"author": {
|
|
7
|
-
"name": "Sheraz Manzoor",
|
|
8
|
-
"email": "sheraz.dev121@gmail.com"
|
|
9
|
-
},
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
"charcole"
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "create-charcole",
|
|
3
|
+
"version": "2.2.1",
|
|
4
|
+
"description": "CLI to create production-ready Node.js Express APIs with TypeScript/JavaScript, JWT auth, auto-generated Swagger docs, and repository pattern",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": {
|
|
7
|
+
"name": "Sheraz Manzoor",
|
|
8
|
+
"email": "sheraz.dev121@gmail.com"
|
|
9
|
+
},
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "https://github.com/sheraz4196/create-charcole.git"
|
|
13
|
+
},
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/sheraz4196/create-charcole/issues"
|
|
16
|
+
},
|
|
17
|
+
"homepage": "https://www.charcole.site/",
|
|
18
|
+
"bin": {
|
|
19
|
+
"create-charcole": "bin/index.js"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"express",
|
|
23
|
+
"backend",
|
|
24
|
+
"starter",
|
|
25
|
+
"boilerplate",
|
|
26
|
+
"production",
|
|
27
|
+
"charcole",
|
|
28
|
+
"nodejs starter",
|
|
29
|
+
"express starter",
|
|
30
|
+
"typescript backend",
|
|
31
|
+
"swagger",
|
|
32
|
+
"backend template",
|
|
33
|
+
"api-boilerplate",
|
|
34
|
+
"zod validation"
|
|
35
|
+
],
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=16"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"prompts": "^2.4.2"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# @charcoles/swagger v2.0.0 - Backward Compatibility Test
|
|
2
|
+
|
|
3
|
+
## Test Cases
|
|
4
|
+
|
|
5
|
+
### ✅ Old JSDoc Approach (Still Works)
|
|
6
|
+
|
|
7
|
+
The traditional manual schema approach still works without any changes:
|
|
8
|
+
|
|
9
|
+
```typescript
|
|
10
|
+
/**
|
|
11
|
+
* @swagger
|
|
12
|
+
* /api/old-endpoint:
|
|
13
|
+
* post:
|
|
14
|
+
* summary: Old style endpoint
|
|
15
|
+
* requestBody:
|
|
16
|
+
* content:
|
|
17
|
+
* application/json:
|
|
18
|
+
* schema:
|
|
19
|
+
* type: object
|
|
20
|
+
* required:
|
|
21
|
+
* - name
|
|
22
|
+
* properties:
|
|
23
|
+
* name:
|
|
24
|
+
* type: string
|
|
25
|
+
* responses:
|
|
26
|
+
* 200:
|
|
27
|
+
* description: Success
|
|
28
|
+
*/
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Status:** ✅ Fully compatible
|
|
32
|
+
|
|
33
|
+
### ✅ Minimal Setup (Still Works)
|
|
34
|
+
|
|
35
|
+
Old setup without new options:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
setupSwagger(app, {
|
|
39
|
+
title: "My API",
|
|
40
|
+
version: "1.0.0",
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
**Status:** ✅ Fully compatible (new options are optional)
|
|
45
|
+
|
|
46
|
+
### ✅ Mixed Approach (Old + New)
|
|
47
|
+
|
|
48
|
+
You can mix manual schemas and auto-generated ones:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
setupSwagger(app, {
|
|
52
|
+
schemas: {
|
|
53
|
+
createUserSchema, // New: auto-generated from Zod
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Old manual approach
|
|
58
|
+
/**
|
|
59
|
+
* @swagger
|
|
60
|
+
* /api/manual:
|
|
61
|
+
* get:
|
|
62
|
+
* responses:
|
|
63
|
+
* 200:
|
|
64
|
+
* description: Success
|
|
65
|
+
*/
|
|
66
|
+
|
|
67
|
+
// New reference approach
|
|
68
|
+
/**
|
|
69
|
+
* @swagger
|
|
70
|
+
* /api/auto:
|
|
71
|
+
* post:
|
|
72
|
+
* requestBody:
|
|
73
|
+
* content:
|
|
74
|
+
* application/json:
|
|
75
|
+
* schema:
|
|
76
|
+
* $ref: '#/components/schemas/createUserSchema'
|
|
77
|
+
*/
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
**Status:** ✅ Fully compatible
|
|
81
|
+
|
|
82
|
+
### ✅ No Zod (Non-Charcole Projects)
|
|
83
|
+
|
|
84
|
+
Works fine without Zod schemas:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { setupSwagger } from "@charcoles/swagger";
|
|
88
|
+
|
|
89
|
+
setupSwagger(app, {
|
|
90
|
+
title: "My API",
|
|
91
|
+
// No schemas - just use manual JSDoc approach
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Status:** ✅ Fully compatible
|
|
96
|
+
|
|
97
|
+
### ✅ Disable Common Responses
|
|
98
|
+
|
|
99
|
+
Can disable built-in responses if not wanted:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
setupSwagger(app, {
|
|
103
|
+
includeCommonResponses: false, // Opt-out
|
|
104
|
+
});
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Status:** ✅ Fully compatible
|
|
108
|
+
|
|
109
|
+
## Migration Path
|
|
110
|
+
|
|
111
|
+
### No Breaking Changes
|
|
112
|
+
|
|
113
|
+
All existing code continues to work:
|
|
114
|
+
|
|
115
|
+
1. **Don't want to use new features?**
|
|
116
|
+
- No changes needed
|
|
117
|
+
- Everything works as before
|
|
118
|
+
|
|
119
|
+
2. **Want to gradually adopt?**
|
|
120
|
+
- Start using schema references one endpoint at a time
|
|
121
|
+
- Mix old and new approaches
|
|
122
|
+
|
|
123
|
+
3. **Want full benefits?**
|
|
124
|
+
- Register schemas in config
|
|
125
|
+
- Update JSDoc to use `$ref`
|
|
126
|
+
- Enjoy 60-80% less code
|
|
127
|
+
|
|
128
|
+
## Compatibility Matrix
|
|
129
|
+
|
|
130
|
+
| Feature | v1.0.0 | v2.0.0 | Notes |
|
|
131
|
+
| ------------------------ | ------ | ------ | ------------------------------ |
|
|
132
|
+
| Manual JSDoc | ✅ | ✅ | No changes needed |
|
|
133
|
+
| Basic setup | ✅ | ✅ | All old options work |
|
|
134
|
+
| Security schemes | ✅ | ✅ | bearerAuth still auto-included |
|
|
135
|
+
| File scanning | ✅ | ✅ | Same directories scanned |
|
|
136
|
+
| TypeScript detection | ✅ | ✅ | Same auto-detection |
|
|
137
|
+
| Zod schemas (new) | ❌ | ✅ | Optional new feature |
|
|
138
|
+
| Response templates (new) | ❌ | ✅ | Optional new feature |
|
|
139
|
+
| Helper functions (new) | ❌ | ✅ | Optional new feature |
|
|
140
|
+
|
|
141
|
+
## Conclusion
|
|
142
|
+
|
|
143
|
+
**100% backward compatible** ✅
|
|
144
|
+
|
|
145
|
+
No breaking changes. All new features are additive and optional.
|