@gieo/express 1.0.6 → 1.0.8
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/dist/index.js +48 -3
- package/package.json +5 -2
- package/src/index.ts +58 -5
package/dist/index.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
2
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
6
|
const http_1 = require("http");
|
|
4
7
|
const url_1 = require("url");
|
|
8
|
+
const ejs_1 = __importDefault(require("ejs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
5
11
|
class ExpressPlus {
|
|
6
12
|
constructor() {
|
|
7
13
|
this.routes = {
|
|
@@ -12,6 +18,10 @@ class ExpressPlus {
|
|
|
12
18
|
DELETE: [],
|
|
13
19
|
};
|
|
14
20
|
this.middlewares = [];
|
|
21
|
+
// Định nghĩa thư mục chứa views (mặc định là "views")
|
|
22
|
+
this.viewsPath = path_1.default.join(process.cwd(), "views");
|
|
23
|
+
// Có thể cho phép tùy chỉnh viewsPath qua constructor nếu cần
|
|
24
|
+
// this.viewsPath = options.viewsPath || path.join(process.cwd(), "views");
|
|
15
25
|
}
|
|
16
26
|
addRoute(method, path, handler) {
|
|
17
27
|
this.routes[method].push({ path, handler });
|
|
@@ -35,14 +45,14 @@ class ExpressPlus {
|
|
|
35
45
|
this.addRoute("DELETE", path, handler);
|
|
36
46
|
}
|
|
37
47
|
listen(port, callback) {
|
|
38
|
-
const server = (0, http_1.createServer)((req, res) => {
|
|
48
|
+
const server = (0, http_1.createServer)(async (req, res) => {
|
|
39
49
|
const method = req.method;
|
|
40
50
|
const parsedUrl = (0, url_1.parse)(req.url || "", true);
|
|
41
51
|
const pathname = parsedUrl.pathname || "/";
|
|
42
|
-
const route = this.routes[method].find((r) => r.path === pathname);
|
|
43
52
|
const extendedReq = req;
|
|
44
53
|
const extendedRes = res;
|
|
45
54
|
extendedReq.query = parsedUrl.query;
|
|
55
|
+
extendedReq.params = {};
|
|
46
56
|
extendedReq.getBody = async () => {
|
|
47
57
|
if (extendedReq.body)
|
|
48
58
|
return extendedReq.body;
|
|
@@ -68,6 +78,41 @@ class ExpressPlus {
|
|
|
68
78
|
extendedRes.setHeader("Content-Type", "application/json");
|
|
69
79
|
extendedRes.end(JSON.stringify(data));
|
|
70
80
|
};
|
|
81
|
+
// Thêm phương thức render cho EJS
|
|
82
|
+
extendedRes.render = function (view, data = {}) {
|
|
83
|
+
const filePath = path_1.default.join(this.viewsPath, `${view}.ejs`);
|
|
84
|
+
if (!fs_1.default.existsSync(filePath)) {
|
|
85
|
+
extendedRes.status(404).end("View not found");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const html = ejs_1.default.render(fs_1.default.readFileSync(filePath, "utf-8"), data);
|
|
89
|
+
extendedRes.setHeader("Content-Type", "text/html");
|
|
90
|
+
extendedRes.end(html);
|
|
91
|
+
};
|
|
92
|
+
// 🔍 Tìm route phù hợp (hỗ trợ dynamic route)
|
|
93
|
+
const route = this.routes[method].find((r) => {
|
|
94
|
+
const routeParts = r.path.split("/").filter(Boolean);
|
|
95
|
+
const urlParts = pathname.split("/").filter(Boolean);
|
|
96
|
+
if (routeParts.length !== urlParts.length)
|
|
97
|
+
return false;
|
|
98
|
+
return routeParts.every((part, i) => {
|
|
99
|
+
return part.startsWith(":") || part === urlParts[i];
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
// 🧠 Trích xuất params nếu có
|
|
103
|
+
if (route) {
|
|
104
|
+
const routeParts = route.path.split("/").filter(Boolean);
|
|
105
|
+
const urlParts = pathname.split("/").filter(Boolean);
|
|
106
|
+
routeParts.forEach((part, i) => {
|
|
107
|
+
if (part.startsWith(":")) {
|
|
108
|
+
const key = part.slice(1);
|
|
109
|
+
extendedReq.params[key] = urlParts[i];
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
// 🧪 Logging đơn giản
|
|
114
|
+
console.log(`[${method}] ${pathname}`);
|
|
115
|
+
// 🧩 Middleware + Route handler
|
|
71
116
|
let i = 0;
|
|
72
117
|
const next = () => {
|
|
73
118
|
const middleware = this.middlewares[i++];
|
|
@@ -78,7 +123,7 @@ class ExpressPlus {
|
|
|
78
123
|
route.handler(extendedReq, extendedRes);
|
|
79
124
|
}
|
|
80
125
|
else {
|
|
81
|
-
extendedRes.status(404).
|
|
126
|
+
extendedRes.status(404).json({ message: "Not Found" });
|
|
82
127
|
}
|
|
83
128
|
};
|
|
84
129
|
next();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gieo/express",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"keywords": [],
|
|
@@ -8,10 +8,13 @@
|
|
|
8
8
|
"license": "ISC",
|
|
9
9
|
"devDependencies": {
|
|
10
10
|
"@gieo/utils": "^1.0.5",
|
|
11
|
-
"@types/node": "^24.2.
|
|
11
|
+
"@types/node": "^24.2.1",
|
|
12
12
|
"jiti": "^2.5.1",
|
|
13
13
|
"typescript": "^5.9.2"
|
|
14
14
|
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"ejs": "^3.1.10"
|
|
17
|
+
},
|
|
15
18
|
"scripts": {
|
|
16
19
|
"test": "node dist/test.js"
|
|
17
20
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import { createServer, IncomingMessage, ServerResponse } from "http";
|
|
2
2
|
import { parse } from "url";
|
|
3
|
-
|
|
3
|
+
import ejs from "ejs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import fs from "fs";
|
|
4
6
|
// Mở rộng Request
|
|
5
7
|
interface ExtendedRequest extends IncomingMessage {
|
|
6
8
|
query?: Record<string, string | string[]>;
|
|
9
|
+
params?: Record<string, string>;
|
|
7
10
|
bodyRaw?: string;
|
|
8
11
|
body?: any;
|
|
9
12
|
getBody: () => Promise<any>;
|
|
@@ -13,6 +16,7 @@ interface ExtendedRequest extends IncomingMessage {
|
|
|
13
16
|
interface ExtendedResponse extends ServerResponse {
|
|
14
17
|
status: (code: number) => ExtendedResponse;
|
|
15
18
|
json: (data: any) => void;
|
|
19
|
+
render: (view: string, data?: any) => void; // Thêm phương thức render
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
type Method = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
|
|
@@ -38,6 +42,14 @@ class ExpressPlus {
|
|
|
38
42
|
next: () => void
|
|
39
43
|
) => void)[] = [];
|
|
40
44
|
|
|
45
|
+
// Định nghĩa thư mục chứa views (mặc định là "views")
|
|
46
|
+
private viewsPath: string = path.join(process.cwd(), "views");
|
|
47
|
+
|
|
48
|
+
constructor() {
|
|
49
|
+
// Có thể cho phép tùy chỉnh viewsPath qua constructor nếu cần
|
|
50
|
+
// this.viewsPath = options.viewsPath || path.join(process.cwd(), "views");
|
|
51
|
+
}
|
|
52
|
+
|
|
41
53
|
private addRoute(method: Method, path: string, handler: Handler): void {
|
|
42
54
|
this.routes[method].push({ path, handler });
|
|
43
55
|
}
|
|
@@ -73,17 +85,16 @@ class ExpressPlus {
|
|
|
73
85
|
}
|
|
74
86
|
|
|
75
87
|
listen(port: number, callback: () => void): void {
|
|
76
|
-
const server = createServer((req, res) => {
|
|
88
|
+
const server = createServer(async (req, res) => {
|
|
77
89
|
const method = req.method as Method;
|
|
78
90
|
const parsedUrl = parse(req.url || "", true);
|
|
79
91
|
const pathname = parsedUrl.pathname || "/";
|
|
80
92
|
|
|
81
|
-
const route = this.routes[method].find((r) => r.path === pathname);
|
|
82
|
-
|
|
83
93
|
const extendedReq = req as ExtendedRequest;
|
|
84
94
|
const extendedRes = res as ExtendedResponse;
|
|
85
95
|
|
|
86
96
|
extendedReq.query = parsedUrl.query;
|
|
97
|
+
extendedReq.params = {};
|
|
87
98
|
extendedReq.getBody = async () => {
|
|
88
99
|
if (extendedReq.body) return extendedReq.body;
|
|
89
100
|
|
|
@@ -114,6 +125,47 @@ class ExpressPlus {
|
|
|
114
125
|
extendedRes.end(JSON.stringify(data));
|
|
115
126
|
};
|
|
116
127
|
|
|
128
|
+
// Thêm phương thức render cho EJS
|
|
129
|
+
extendedRes.render = function (view: string, data: any = {}) {
|
|
130
|
+
const filePath = path.join(this.viewsPath, `${view}.ejs`);
|
|
131
|
+
if (!fs.existsSync(filePath)) {
|
|
132
|
+
extendedRes.status(404).end("View not found");
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
const html = ejs.render(fs.readFileSync(filePath, "utf-8"), data);
|
|
136
|
+
extendedRes.setHeader("Content-Type", "text/html");
|
|
137
|
+
extendedRes.end(html);
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// 🔍 Tìm route phù hợp (hỗ trợ dynamic route)
|
|
141
|
+
const route = this.routes[method].find((r) => {
|
|
142
|
+
const routeParts = r.path.split("/").filter(Boolean);
|
|
143
|
+
const urlParts = pathname.split("/").filter(Boolean);
|
|
144
|
+
|
|
145
|
+
if (routeParts.length !== urlParts.length) return false;
|
|
146
|
+
|
|
147
|
+
return routeParts.every((part, i) => {
|
|
148
|
+
return part.startsWith(":") || part === urlParts[i];
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
// 🧠 Trích xuất params nếu có
|
|
153
|
+
if (route) {
|
|
154
|
+
const routeParts = route.path.split("/").filter(Boolean);
|
|
155
|
+
const urlParts = pathname.split("/").filter(Boolean);
|
|
156
|
+
|
|
157
|
+
routeParts.forEach((part, i) => {
|
|
158
|
+
if (part.startsWith(":")) {
|
|
159
|
+
const key = part.slice(1);
|
|
160
|
+
extendedReq.params![key] = urlParts[i];
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// 🧪 Logging đơn giản
|
|
166
|
+
console.log(`[${method}] ${pathname}`);
|
|
167
|
+
|
|
168
|
+
// 🧩 Middleware + Route handler
|
|
117
169
|
let i = 0;
|
|
118
170
|
const next = () => {
|
|
119
171
|
const middleware = this.middlewares[i++];
|
|
@@ -122,7 +174,7 @@ class ExpressPlus {
|
|
|
122
174
|
} else if (route) {
|
|
123
175
|
route.handler(extendedReq, extendedRes);
|
|
124
176
|
} else {
|
|
125
|
-
extendedRes.status(404).
|
|
177
|
+
extendedRes.status(404).json({ message: "Not Found" });
|
|
126
178
|
}
|
|
127
179
|
};
|
|
128
180
|
|
|
@@ -134,3 +186,4 @@ class ExpressPlus {
|
|
|
134
186
|
}
|
|
135
187
|
|
|
136
188
|
export default ExpressPlus;
|
|
189
|
+
export { ExtendedRequest, ExtendedResponse };
|