@hestjs/core 0.1.8 → 0.1.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/README.md +330 -266
- package/dist/application/application-factory.d.ts +4 -0
- package/dist/application/application-factory.d.ts.map +1 -1
- package/dist/application/application-factory.js +37 -7
- package/dist/application/application-factory.js.map +1 -1
- package/dist/application/application-hooks.d.ts +29 -0
- package/dist/application/application-hooks.d.ts.map +1 -0
- package/dist/application/application-hooks.js +50 -0
- package/dist/application/application-hooks.js.map +1 -0
- package/dist/application/index.d.ts +2 -1
- package/dist/application/index.d.ts.map +1 -1
- package/dist/application/index.js +2 -1
- package/dist/application/index.js.map +1 -1
- package/dist/container/container.d.ts +38 -1
- package/dist/container/container.d.ts.map +1 -1
- package/dist/container/container.js +44 -1
- package/dist/container/container.js.map +1 -1
- package/dist/container/index.d.ts +3 -2
- package/dist/container/index.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
@@ -1,387 +1,451 @@
|
|
1
|
-
#
|
1
|
+
# @hestjs/core
|
2
2
|
|
3
|
-
|
3
|
+
<div align="center">
|
4
4
|
|
5
|
+
[](https://www.npmjs.com/package/@hestjs/core)
|
5
6
|
[](https://www.typescriptlang.org/)
|
6
|
-
[](https://bun.sh/)
|
7
7
|
[](https://hono.dev/)
|
8
|
-
[](
|
8
|
+
[](https://opensource.org/licenses/MIT)
|
9
9
|
|
10
|
-
|
10
|
+
</div>
|
11
11
|
|
12
|
-
-
|
13
|
-
- 💉 **依赖注入** - 基于 TSyringe 的完整 DI 容器,用户透明
|
14
|
-
- 🏗️ **模块化架构** - 采用模块系统组织代码
|
15
|
-
- ⚡ **高性能** - 基于 Hono 和 Bun 获得最佳性能
|
16
|
-
- 🔒 **类型安全** - 完全的 TypeScript 支持
|
17
|
-
- 🛡️ **验证系统** - 基于 TypeBox 的强大验证功能
|
18
|
-
- 🔄 **拦截器** - 灵活的请求/响应拦截机制
|
19
|
-
- 🚨 **异常处理** - 完善的异常过滤和处理系统
|
12
|
+
HestJS 核心包 - 基于 Hono 构建的现代化 TypeScript 后端库,提供装饰器驱动的开发体验和依赖注入系统。
|
20
13
|
|
21
|
-
##
|
14
|
+
## 🎯 核心理念
|
15
|
+
|
16
|
+
- **🔓 拒绝过度封装**:直接暴露原生 Hono 实例,保留所有底层功能
|
17
|
+
- **✈️ 零配置**:你看不到类似 `hestjs.config.ts`这样的配置文件,无需任何配置
|
18
|
+
- **🎯 装饰器驱动**:提供熟悉的 NestJS 风格开发体验
|
19
|
+
- **💉 轻量依赖注入**:基于 TSyringe 的简洁 DI 容器
|
20
|
+
- **⚡ 极致性能**:基于 Hono 和 Bun 的高性能运行时
|
22
21
|
|
23
|
-
|
22
|
+
## 📦 安装
|
24
23
|
|
25
24
|
```bash
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
npm install @hestjs/core
|
26
|
+
# 或
|
27
|
+
yarn add @hestjs/core
|
28
|
+
# 或
|
29
|
+
bun add @hestjs/core
|
30
|
+
```
|
31
|
+
|
32
|
+
## 🚀 快速开始
|
29
33
|
|
30
|
-
|
31
|
-
bun install
|
34
|
+
### 1. 创建基础应用
|
32
35
|
|
33
|
-
|
34
|
-
bun run build
|
36
|
+
在此之前你应该在tsconfig中添加以下内容:
|
35
37
|
|
36
|
-
|
37
|
-
|
38
|
-
|
38
|
+
```json
|
39
|
+
{
|
40
|
+
"compilerOptions": {
|
41
|
+
...
|
42
|
+
"experimentalDecorators": true,
|
43
|
+
"emitDecoratorMetadata": true,
|
44
|
+
"esModuleInterop": true
|
45
|
+
}
|
46
|
+
}
|
39
47
|
```
|
40
48
|
|
41
|
-
### 创建你的第一个应用
|
42
|
-
|
43
49
|
```typescript
|
44
|
-
|
45
|
-
import { Controller, Get, Post, Body } from "@hestjs/core";
|
46
|
-
import { IsString, IsEmail, IsNumber } from "@hestjs/validation";
|
50
|
+
import { Controller, Get, HestFactory, Module } from "@hestjs/core";
|
47
51
|
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
@Controller("/")
|
53
|
+
export class WelcomeController {
|
54
|
+
@Get("/welcome")
|
55
|
+
async welcome() {
|
56
|
+
return "Welcome to HestJS!";
|
57
|
+
}
|
58
|
+
}
|
51
59
|
|
52
|
-
|
53
|
-
|
60
|
+
@Module({
|
61
|
+
controllers: [WelcomeController],
|
62
|
+
providers: [],
|
63
|
+
imports: [],
|
64
|
+
exports: [],
|
65
|
+
})
|
66
|
+
export class AppModule {}
|
67
|
+
|
68
|
+
async function bootstrap() {
|
69
|
+
const app = await HestFactory.create(AppModule);
|
70
|
+
const hono = app.hono();
|
54
71
|
|
55
|
-
|
56
|
-
|
72
|
+
Bun.serve({
|
73
|
+
port: 3000,
|
74
|
+
fetch: hono.fetch,
|
75
|
+
});
|
57
76
|
}
|
58
77
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
78
|
+
bootstrap();
|
79
|
+
```
|
80
|
+
|
81
|
+
### 2. 定义控制器
|
82
|
+
|
83
|
+
```typescript
|
84
|
+
import { Controller, Get, Post, Context, Body, Param } from "@hestjs/core";
|
85
|
+
import type { HestContext } from "@hestjs/core";
|
86
|
+
|
87
|
+
@Controller("/users")
|
88
|
+
export class UsersController {
|
89
|
+
@Get("/")
|
90
|
+
async getAllUsers() {
|
91
|
+
return { message: "Get all users" };
|
64
92
|
}
|
65
93
|
|
66
|
-
@
|
67
|
-
|
68
|
-
|
69
|
-
|
94
|
+
@Get("/:id")
|
95
|
+
async getUser(@Param("id") id: string, @Context() c: HestContext) {
|
96
|
+
return { id, message: `Get user ${id}` };
|
97
|
+
}
|
98
|
+
|
99
|
+
@Post("/")
|
100
|
+
async createUser(@Body() body: any, @Context() c: HestContext) {
|
101
|
+
return { message: "User created", data: body };
|
70
102
|
}
|
71
103
|
}
|
72
104
|
```
|
73
105
|
|
106
|
+
### 3. 创建模块
|
107
|
+
|
74
108
|
```typescript
|
75
|
-
// app.module.ts
|
76
109
|
import { Module } from "@hestjs/core";
|
77
|
-
import {
|
110
|
+
import { UsersController } from "./users.controller";
|
111
|
+
import { UsersService } from "./users.service";
|
78
112
|
|
79
113
|
@Module({
|
80
|
-
controllers: [
|
114
|
+
controllers: [UsersController],
|
115
|
+
providers: [UsersService],
|
116
|
+
exports: [UsersService],
|
81
117
|
})
|
82
|
-
export class
|
118
|
+
export class UsersModule {}
|
83
119
|
```
|
84
120
|
|
85
|
-
|
86
|
-
// main.ts
|
87
|
-
import { HestFactory } from "@hestjs/core";
|
88
|
-
import { ValidationInterceptor } from "@hestjs/validation";
|
89
|
-
import { AppModule } from "./app.module";
|
121
|
+
### 4. 创建服务
|
90
122
|
|
91
|
-
|
92
|
-
|
123
|
+
```typescript
|
124
|
+
import { injectable } from "@hestjs/core";
|
93
125
|
|
94
|
-
|
95
|
-
|
126
|
+
@injectable()
|
127
|
+
export class UsersService {
|
128
|
+
findAll() {
|
129
|
+
return [
|
130
|
+
{ id: 1, name: "John" },
|
131
|
+
{ id: 2, name: "Jane" },
|
132
|
+
];
|
133
|
+
}
|
96
134
|
|
97
|
-
|
98
|
-
|
135
|
+
findOne(id: number) {
|
136
|
+
return { id, name: `User ${id}` };
|
137
|
+
}
|
99
138
|
}
|
100
|
-
|
101
|
-
bootstrap();
|
102
139
|
```
|
103
140
|
|
104
|
-
##
|
141
|
+
## 🏗️ 架构概览
|
142
|
+
|
143
|
+
### 核心模块
|
144
|
+
|
145
|
+
HestJS Core 包含以下主要模块:
|
105
146
|
|
106
147
|
```
|
107
|
-
|
108
|
-
├──
|
109
|
-
│ ├──
|
110
|
-
│
|
111
|
-
|
112
|
-
│
|
113
|
-
├──
|
114
|
-
│ ├──
|
115
|
-
│
|
116
|
-
|
117
|
-
|
148
|
+
@hestjs/core/
|
149
|
+
├── application/ # 应用工厂和实例
|
150
|
+
│ ├── HestFactory # 应用工厂
|
151
|
+
│ └── HestApplicationInstance # 应用实例
|
152
|
+
├── decorators/ # 装饰器系统
|
153
|
+
│ ├── @Controller # 控制器装饰器
|
154
|
+
│ ├── @Module # 模块装饰器
|
155
|
+
│ ├── @injectable # 可注入装饰器
|
156
|
+
│ └── 路由装饰器 # @Get, @Post, @Put, @Delete, @Patch
|
157
|
+
├── container/ # 依赖注入容器
|
158
|
+
├── router/ # 路由系统
|
159
|
+
├── exceptions/ # 异常处理
|
160
|
+
├── interceptors/ # 拦截器
|
161
|
+
├── interfaces/ # 类型定义
|
162
|
+
└── utils/ # 工具函数
|
118
163
|
```
|
119
164
|
|
120
|
-
##
|
165
|
+
## 📚 API 参考
|
166
|
+
|
167
|
+
### 🏭 应用工厂
|
168
|
+
|
169
|
+
#### `HestFactory.create(moduleClass)`
|
121
170
|
|
122
|
-
|
171
|
+
创建应用实例的静态方法。
|
123
172
|
|
124
173
|
```typescript
|
125
|
-
@
|
126
|
-
|
127
|
-
@Get("/")
|
128
|
-
findAll() {
|
129
|
-
return { users: [] };
|
130
|
-
}
|
174
|
+
import { HestFactory } from "@hestjs/core";
|
175
|
+
import { AppModule } from "./app.module";
|
131
176
|
|
132
|
-
|
133
|
-
|
134
|
-
return { user: { id } };
|
135
|
-
}
|
177
|
+
const app = await HestFactory.create(AppModule);
|
178
|
+
```
|
136
179
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
180
|
+
### 🎮 控制器装饰器
|
181
|
+
|
182
|
+
#### `@Controller(path?: string)`
|
183
|
+
|
184
|
+
定义控制器类和基础路径。
|
185
|
+
|
186
|
+
```typescript
|
187
|
+
@Controller("/api/users")
|
188
|
+
export class UsersController {
|
189
|
+
// 控制器方法
|
141
190
|
}
|
142
191
|
```
|
143
192
|
|
144
|
-
###
|
193
|
+
### 🛣️ 路由装饰器
|
145
194
|
|
146
|
-
|
147
|
-
@Injectable()
|
148
|
-
export class UserService {
|
149
|
-
async findAll() {
|
150
|
-
return [];
|
151
|
-
}
|
195
|
+
#### HTTP 方法装饰器
|
152
196
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
197
|
+
- `@Get(path?: string)` - GET 请求
|
198
|
+
- `@Post(path?: string)` - POST 请求
|
199
|
+
- `@Put(path?: string)` - PUT 请求
|
200
|
+
- `@Delete(path?: string)` - DELETE 请求
|
201
|
+
- `@Patch(path?: string)` - PATCH 请求
|
202
|
+
|
203
|
+
```typescript
|
204
|
+
@Controller('/users')
|
205
|
+
export class UsersController {
|
206
|
+
@Get('/') // GET /users/
|
207
|
+
@Get('/:id') // GET /users/:id
|
208
|
+
@Post('/') // POST /users/
|
209
|
+
@Put('/:id') // PUT /users/:id
|
210
|
+
@Delete('/:id') // DELETE /users/:id
|
211
|
+
@Patch('/:id') // PATCH /users/:id
|
157
212
|
}
|
213
|
+
```
|
158
214
|
|
159
|
-
|
160
|
-
export class UserController {
|
161
|
-
constructor(private readonly userService: UserService) {}
|
215
|
+
### 📥 参数装饰器
|
162
216
|
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
217
|
+
#### `@Context()`
|
218
|
+
|
219
|
+
获取完整的 Hono Context 对象。
|
220
|
+
|
221
|
+
```typescript
|
222
|
+
@Get('/')
|
223
|
+
async getUsers(@Context() c: HestContext) {
|
224
|
+
// 访问所有 Hono Context 功能
|
225
|
+
const userAgent = c.req.header('User-Agent');
|
226
|
+
return c.json({ message: 'Hello' });
|
167
227
|
}
|
168
228
|
```
|
169
229
|
|
170
|
-
|
230
|
+
#### `@Body()`
|
171
231
|
|
172
|
-
|
232
|
+
获取请求体数据。
|
173
233
|
|
174
234
|
```typescript
|
175
|
-
|
176
|
-
|
177
|
-
|
235
|
+
@Post('/')
|
236
|
+
async createUser(@Body() userData: CreateUserDto) {
|
237
|
+
return userData;
|
238
|
+
}
|
239
|
+
```
|
178
240
|
|
179
|
-
|
180
|
-
email!: string;
|
241
|
+
#### `@Param(key?: string)`
|
181
242
|
|
182
|
-
|
183
|
-
age!: number;
|
243
|
+
获取路径参数。
|
184
244
|
|
185
|
-
|
186
|
-
|
187
|
-
|
245
|
+
```typescript
|
246
|
+
@Get('/:id')
|
247
|
+
async getUser(@Param('id') id: string) {
|
248
|
+
return { id };
|
188
249
|
}
|
189
250
|
```
|
190
251
|
|
191
|
-
####
|
252
|
+
#### `@Query(key?: string)`
|
253
|
+
|
254
|
+
获取查询参数。
|
192
255
|
|
193
256
|
```typescript
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
export class AdvancedDto {
|
198
|
-
// 使用 TypeBox API 自定义验证
|
199
|
-
@Custom(
|
200
|
-
Type.String({
|
201
|
-
minLength: 3,
|
202
|
-
maxLength: 20,
|
203
|
-
pattern: "^[a-zA-Z0-9_]+$",
|
204
|
-
})
|
205
|
-
)
|
206
|
-
username!: string;
|
207
|
-
|
208
|
-
// 使用联合类型
|
209
|
-
@Custom(
|
210
|
-
Type.Union([
|
211
|
-
Type.Literal("admin"),
|
212
|
-
Type.Literal("user"),
|
213
|
-
Type.Literal("guest"),
|
214
|
-
])
|
215
|
-
)
|
216
|
-
role!: "admin" | "user" | "guest";
|
217
|
-
|
218
|
-
// 使用常用验证器
|
219
|
-
@CommonValidators.UUID()
|
220
|
-
userId!: string;
|
221
|
-
|
222
|
-
// 使用便捷构建器
|
223
|
-
@Custom(SchemaFactory.chinesePhoneNumber())
|
224
|
-
phoneNumber!: string;
|
225
|
-
|
226
|
-
// 复杂对象验证
|
227
|
-
@Custom(
|
228
|
-
Type.Object({
|
229
|
-
lat: Type.Number({ minimum: -90, maximum: 90 }),
|
230
|
-
lng: Type.Number({ minimum: -180, maximum: 180 }),
|
231
|
-
})
|
232
|
-
)
|
233
|
-
location!: { lat: number; lng: number };
|
257
|
+
@Get('/')
|
258
|
+
async getUsers(@Query('page') page: string) {
|
259
|
+
return { page };
|
234
260
|
}
|
235
261
|
```
|
236
262
|
|
237
|
-
|
263
|
+
#### `@Header(key?: string)`
|
264
|
+
|
265
|
+
获取请求头。
|
238
266
|
|
239
267
|
```typescript
|
240
|
-
|
268
|
+
@Get('/')
|
269
|
+
async getUsers(@Header('authorization') auth: string) {
|
270
|
+
return { auth };
|
271
|
+
}
|
272
|
+
```
|
241
273
|
|
242
|
-
|
243
|
-
intercept(context: ExecutionContext, next: CallHandler) {
|
244
|
-
console.log("Before...");
|
274
|
+
### 🏗️ 模块系统
|
245
275
|
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
276
|
+
#### `@Module(options)`
|
277
|
+
|
278
|
+
定义模块和依赖关系。
|
279
|
+
|
280
|
+
```typescript
|
281
|
+
interface ModuleOptions {
|
282
|
+
imports?: any[]; // 导入的模块
|
283
|
+
controllers?: any[]; // 控制器
|
284
|
+
providers?: any[]; // 提供者(服务)
|
285
|
+
exports?: any[]; // 导出的提供者
|
251
286
|
}
|
252
287
|
|
253
|
-
|
254
|
-
|
288
|
+
@Module({
|
289
|
+
imports: [DatabaseModule],
|
290
|
+
controllers: [UsersController],
|
291
|
+
providers: [UsersService],
|
292
|
+
exports: [UsersService],
|
293
|
+
})
|
294
|
+
export class UsersModule {}
|
255
295
|
```
|
256
296
|
|
257
|
-
###
|
297
|
+
### 💉 依赖注入
|
258
298
|
|
259
|
-
|
260
|
-
import {
|
261
|
-
HttpException,
|
262
|
-
NotFoundException,
|
263
|
-
BadRequestException,
|
264
|
-
} from "@hestjs/core";
|
299
|
+
#### `@injectable()`
|
265
300
|
|
266
|
-
|
267
|
-
export class UserController {
|
268
|
-
@Get("/:id")
|
269
|
-
findOne(@Param("id") id: string) {
|
270
|
-
const user = this.findUserById(id);
|
271
|
-
if (!user) {
|
272
|
-
throw new NotFoundException(`User with id ${id} not found`);
|
273
|
-
}
|
274
|
-
return user;
|
275
|
-
}
|
301
|
+
标记类为可注入的服务。
|
276
302
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
}
|
282
|
-
return this.createUser(userData);
|
283
|
-
}
|
303
|
+
```typescript
|
304
|
+
@injectable()
|
305
|
+
export class UsersService {
|
306
|
+
constructor(private readonly databaseService: DatabaseService) {}
|
284
307
|
}
|
285
308
|
```
|
286
309
|
|
287
|
-
|
310
|
+
### 🔄 拦截器和过滤器
|
288
311
|
|
289
|
-
|
312
|
+
#### 全局拦截器
|
290
313
|
|
291
|
-
|
292
|
-
|
293
|
-
- 依赖注入容器 (基于 TSyringe)
|
294
|
-
- 应用工厂 (`HestFactory.create()`)
|
295
|
-
- 路由系统和参数注入
|
314
|
+
```typescript
|
315
|
+
const app = await HestFactory.create(AppModule);
|
296
316
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
317
|
+
// 添加全局拦截器
|
318
|
+
app.useGlobalInterceptors(new ValidationInterceptor());
|
319
|
+
app.useGlobalInterceptors(new ResponseInterceptor());
|
320
|
+
```
|
301
321
|
|
302
|
-
|
303
|
-
- 基于 TypeBox 的验证装饰器
|
304
|
-
- @Custom() 装饰器支持完整 TypeBox API
|
305
|
-
- ValidationInterceptor 自动验证
|
306
|
-
- SchemaFactory 和 CommonValidators
|
307
|
-
- 详细验证错误处理
|
322
|
+
#### 全局异常过滤器
|
308
323
|
|
309
|
-
|
324
|
+
```typescript
|
325
|
+
const app = await HestFactory.create(AppModule);
|
310
326
|
|
311
|
-
|
312
|
-
|
313
|
-
|
327
|
+
// 添加全局异常过滤器
|
328
|
+
app.useGlobalFilters(new HttpExceptionFilter());
|
329
|
+
```
|
314
330
|
|
315
|
-
|
331
|
+
### 🌐 直接访问 Hono
|
316
332
|
|
317
|
-
|
333
|
+
HestJS 不会封装 Hono,你可以直接使用所有 Hono 功能:
|
318
334
|
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
335
|
+
```typescript
|
336
|
+
const app = await HestFactory.create(AppModule);
|
337
|
+
const honoApp = app.hono();
|
338
|
+
|
339
|
+
// 使用 Hono 原生中间件
|
340
|
+
honoApp.use(cors());
|
341
|
+
honoApp.use("/api/*", async (c, next) => {
|
342
|
+
console.log(`${c.req.method} ${c.req.url}`);
|
343
|
+
await next();
|
344
|
+
});
|
345
|
+
|
346
|
+
// 添加自定义路由
|
347
|
+
honoApp.get("/health", (c) => c.text("OK"));
|
348
|
+
```
|
323
349
|
|
324
|
-
##
|
350
|
+
## 🧪 类型系统
|
325
351
|
|
326
|
-
###
|
352
|
+
### HestContext
|
327
353
|
|
328
|
-
|
329
|
-
# 安装依赖
|
330
|
-
bun install
|
354
|
+
提供完整的 Hono Context 类型安全:
|
331
355
|
|
332
|
-
|
333
|
-
|
356
|
+
```typescript
|
357
|
+
import type { HestContext } from '@hestjs/core';
|
334
358
|
|
335
|
-
|
336
|
-
|
359
|
+
@Get('/')
|
360
|
+
async handler(@Context() c: HestContext) {
|
361
|
+
// 完整的 Hono Context API
|
362
|
+
const method = c.req.method;
|
363
|
+
const url = c.req.url;
|
364
|
+
const headers = c.req.header();
|
337
365
|
|
338
|
-
|
339
|
-
|
340
|
-
bun run dev
|
366
|
+
return c.json({ method, url });
|
367
|
+
}
|
341
368
|
```
|
342
369
|
|
343
|
-
|
370
|
+
## 🔮 未来路线图
|
344
371
|
|
345
|
-
|
346
|
-
# 运行 Phase 3 验证测试
|
347
|
-
bun test-phase3.ts
|
348
|
-
```
|
372
|
+
### v0.2.x - 增强功能
|
349
373
|
|
350
|
-
|
374
|
+
- [ ] **中间件系统** - 完善的中间件装饰器支持
|
375
|
+
- [ ] **管道系统** - 数据转换和验证管道
|
376
|
+
- [ ] **守卫系统** - 路由级别的访问控制
|
377
|
+
- [ ] **元数据增强** - 更丰富的反射元数据支持
|
351
378
|
|
352
|
-
###
|
379
|
+
### v0.3.x - 性能优化
|
353
380
|
|
354
|
-
-
|
355
|
-
-
|
356
|
-
-
|
357
|
-
-
|
358
|
-
- `@Body(dtoClass?)`, `@Param(key?)`, `@Query(key?)` - 参数注入
|
359
|
-
- `@IsString()`, `@IsEmail()`, `@IsNumber()` - 基础验证
|
360
|
-
- `@Custom(schema, options?)` - 自定义 TypeBox 验证
|
381
|
+
- [ ] **路由缓存** - 路由匹配性能优化
|
382
|
+
- [ ] **依赖注入优化** - 容器解析性能提升
|
383
|
+
- [ ] **热重载支持** - 开发环境下的热重载
|
384
|
+
- [ ] **构建优化** - 更小的打包体积
|
361
385
|
|
362
|
-
###
|
386
|
+
### v0.4.x - 生态系统
|
363
387
|
|
364
|
-
-
|
365
|
-
-
|
366
|
-
-
|
367
|
-
-
|
368
|
-
|
388
|
+
- [ ] **WebSocket 支持** - 实时通信功能
|
389
|
+
- [ ] **文件上传** - 内置文件处理能力
|
390
|
+
- [ ] **缓存系统** - 多级缓存支持
|
391
|
+
- [ ] **任务调度** - 定时任务和队列系统
|
392
|
+
|
393
|
+
### v0.5.x - 企业级功能
|
394
|
+
|
395
|
+
- [ ] **微服务支持** - 服务发现和通信
|
396
|
+
- [ ] **配置管理** - 环境配置和动态配置
|
397
|
+
- [ ] **健康检查** - 应用监控和诊断
|
398
|
+
- [ ] **链路追踪** - 分布式追踪支持
|
399
|
+
|
400
|
+
### v1.0.x - 稳定版本
|
401
|
+
|
402
|
+
- [ ] **API 稳定** - 向后兼容的 API
|
403
|
+
- [ ] **完整文档** - 全面的使用指南
|
404
|
+
- [ ] **性能基准** - 与其他框架的对比
|
405
|
+
- [ ] **生产就绪** - 企业级部署支持
|
406
|
+
|
407
|
+
## 📋 当前功能状态
|
408
|
+
|
409
|
+
### ✅ 已实现功能
|
410
|
+
|
411
|
+
- [x] **应用工厂** - `HestFactory.create()`
|
412
|
+
- [x] **控制器系统** - `@Controller()` 装饰器
|
413
|
+
- [x] **路由装饰器** - `@Get()`, `@Post()`, `@Put()`, `@Delete()`, `@Patch()`
|
414
|
+
- [x] **参数装饰器** - `@Context()`, `@Body()`, `@Param()`, `@Query()`, `@Header()`
|
415
|
+
- [x] **模块系统** - `@Module()` 装饰器
|
416
|
+
- [x] **依赖注入** - 基于 TSyringe 的 DI 容器
|
417
|
+
- [x] **异常处理** - 基础异常过滤器
|
418
|
+
- [x] **拦截器** - 全局拦截器支持
|
419
|
+
- [x] **类型安全** - 完整的 TypeScript 支持
|
420
|
+
- [x] **Hono 集成** - 直接访问 Hono 实例
|
421
|
+
|
422
|
+
### 🚧 开发中功能
|
423
|
+
|
424
|
+
- [ ] **装饰器中间件** - `@UseMiddleware()` 装饰器
|
425
|
+
- [ ] **路由守卫** - `@UseGuards()` 装饰器
|
426
|
+
- [ ] **数据管道** - `@UsePipes()` 装饰器
|
427
|
+
- [ ] **OpenAPI 集成** - 自动 API 文档生成
|
428
|
+
|
429
|
+
## 💡 设计原则
|
430
|
+
|
431
|
+
1. **最小封装** - 不隐藏底层框架的功能
|
432
|
+
2. **类型安全** - 完整的 TypeScript 支持
|
433
|
+
3. **性能优先** - 基于高性能的 Hono 和 Bun
|
434
|
+
4. **开发体验** - 熟悉的装饰器语法
|
435
|
+
5. **渐进式** - 可以逐步采用各种功能
|
369
436
|
|
370
437
|
## 🤝 贡献
|
371
438
|
|
372
|
-
|
439
|
+
欢迎提交 Issue 和 Pull Request!
|
373
440
|
|
374
441
|
## 📄 许可证
|
375
442
|
|
376
443
|
[MIT](LICENSE)
|
377
444
|
|
378
|
-
## 🔗 相关链接
|
379
|
-
|
380
|
-
- [Hono](https://hono.dev/) - 快速、轻量级的 Web 框架
|
381
|
-
- [Bun](https://bun.sh/) - 快速的 JavaScript 运行时
|
382
|
-
- [TSyringe](https://github.com/microsoft/tsyringe) - 依赖注入容器
|
383
|
-
- [TypeBox](https://github.com/sinclairzx81/typebox) - JSON Schema 类型构建器
|
384
|
-
|
385
445
|
---
|
386
446
|
|
387
|
-
|
447
|
+
**更多信息**:
|
448
|
+
|
449
|
+
- 📚 [完整文档](https://aqz236.github.io/hestjs-demo)
|
450
|
+
- 🎮 [示例项目](https://github.com/aqz236/hestjs-demo)
|
451
|
+
- 🐛 [问题反馈](https://github.com/aqz236/hest/issues)
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"application-factory.d.ts","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;
|
1
|
+
{"version":3,"file":"application-factory.d.ts","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,uBAAuB,EAAE,MAAM,oBAAoB,CAAC;AAI7D;;GAEG;AACH,qBAAa,WAAW;IACtB;;OAEG;WACU,MAAM,CAAC,WAAW,EAAE,GAAG,GAAG,OAAO,CAAC,uBAAuB,CAAC;IA8BvE;;OAEG;mBACkB,gBAAgB;IAiDrC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,qBAAqB;CA4BrC"}
|
@@ -6,6 +6,7 @@ const container_1 = require("../container/container");
|
|
6
6
|
const metadata_scanner_1 = require("../metadata/metadata-scanner");
|
7
7
|
const router_explorer_1 = require("../router/router-explorer");
|
8
8
|
const hest_application_1 = require("./hest-application");
|
9
|
+
const application_hooks_1 = require("./application-hooks");
|
9
10
|
const logger_1 = require("@hestjs/logger");
|
10
11
|
/**
|
11
12
|
* HestJS 应用工厂
|
@@ -27,10 +28,13 @@ class HestFactory {
|
|
27
28
|
const routerExplorer = new router_explorer_1.RouterExplorer(app, container);
|
28
29
|
routerExplorer.setGlobalFilters(appInstance.getGlobalFilters());
|
29
30
|
routerExplorer.setGlobalInterceptors(appInstance.getGlobalInterceptors());
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
// 收集所有模块的控制器
|
32
|
+
const allControllers = HestFactory.collectAllControllers(moduleClass);
|
33
|
+
if (allControllers.length > 0) {
|
34
|
+
routerExplorer.explore(allControllers);
|
33
35
|
}
|
36
|
+
// 执行所有注册的应用启动钩子
|
37
|
+
await application_hooks_1.ApplicationHooks.getInstance().executeHooks(container);
|
34
38
|
return appInstance;
|
35
39
|
}
|
36
40
|
/**
|
@@ -42,15 +46,15 @@ class HestFactory {
|
|
42
46
|
throw new Error(`Module metadata not found for ${moduleClass.name}`);
|
43
47
|
}
|
44
48
|
// 注册模块自身
|
45
|
-
container.register(moduleClass, moduleClass);
|
49
|
+
container.register(moduleClass, moduleClass, 'module');
|
46
50
|
// 注册提供者
|
47
51
|
if (moduleMetadata.providers) {
|
48
52
|
for (const provider of moduleMetadata.providers) {
|
49
53
|
if (metadata_scanner_1.MetadataScanner.isInjectable(provider)) {
|
50
54
|
// 注册类本身作为令牌
|
51
|
-
container.register(provider, provider);
|
55
|
+
container.register(provider, provider, 'provider');
|
52
56
|
// 同时注册类名字符串作为令牌,以支持 @Inject('ClassName') 语法
|
53
|
-
container.register(provider.name, provider);
|
57
|
+
container.register(provider.name, provider, 'provider');
|
54
58
|
}
|
55
59
|
else {
|
56
60
|
console.warn(`Provider ${provider.name} is not injectable, skipping registration`);
|
@@ -61,7 +65,7 @@ class HestFactory {
|
|
61
65
|
if (moduleMetadata.controllers) {
|
62
66
|
for (const controller of moduleMetadata.controllers) {
|
63
67
|
if (metadata_scanner_1.MetadataScanner.isController(controller)) {
|
64
|
-
container.register(controller, controller);
|
68
|
+
container.register(controller, controller, 'controller');
|
65
69
|
}
|
66
70
|
else {
|
67
71
|
throw new Error(`${controller.name} is not a valid controller`);
|
@@ -76,6 +80,32 @@ class HestFactory {
|
|
76
80
|
}
|
77
81
|
logger_1.logger.info(`✅ Module ${moduleClass.name} initialized`);
|
78
82
|
}
|
83
|
+
/**
|
84
|
+
* 递归收集所有模块的控制器
|
85
|
+
*/
|
86
|
+
static collectAllControllers(moduleClass, visited = new Set()) {
|
87
|
+
// 防止循环依赖
|
88
|
+
if (visited.has(moduleClass)) {
|
89
|
+
return [];
|
90
|
+
}
|
91
|
+
visited.add(moduleClass);
|
92
|
+
const controllers = [];
|
93
|
+
const moduleMetadata = metadata_scanner_1.MetadataScanner.scanModule(moduleClass);
|
94
|
+
if (!moduleMetadata) {
|
95
|
+
return controllers;
|
96
|
+
}
|
97
|
+
// 收集当前模块的控制器
|
98
|
+
if (moduleMetadata.controllers) {
|
99
|
+
controllers.push(...moduleMetadata.controllers);
|
100
|
+
}
|
101
|
+
// 递归收集导入模块的控制器
|
102
|
+
if (moduleMetadata.imports) {
|
103
|
+
for (const importedModule of moduleMetadata.imports) {
|
104
|
+
controllers.push(...HestFactory.collectAllControllers(importedModule, visited));
|
105
|
+
}
|
106
|
+
}
|
107
|
+
return controllers;
|
108
|
+
}
|
79
109
|
}
|
80
110
|
exports.HestFactory = HestFactory;
|
81
111
|
//# sourceMappingURL=application-factory.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"application-factory.js","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":";;;AAAA,+BAA4B;AAC5B,sDAAmD;AACnD,mEAA+D;AAC/D,+DAA2D;AAC3D,yDAA6D;AAC7D,2CAAwC;AAExC;;GAEG;AACH,MAAa,WAAW;IACtB;;OAEG;IACH,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,WAAgB;QAClC,aAAa;QACb,MAAM,GAAG,GAAG,IAAI,WAAI,EAAE,CAAC;QAEvB,WAAW;QACX,MAAM,SAAS,GAAG,qBAAS,CAAC,WAAW,EAAE,CAAC;QAE1C,QAAQ;QACR,MAAM,WAAW,CAAC,gBAAgB,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;QAE3D,SAAS;QACT,MAAM,WAAW,GAAG,IAAI,0CAAuB,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAEhE,OAAO;QACP,MAAM,cAAc,GAAG,IAAI,gCAAc,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC1D,cAAc,CAAC,gBAAgB,CAAC,WAAW,CAAC,gBAAgB,EAAE,CAAC,CAAC;QAChE,cAAc,CAAC,qBAAqB,CAAC,WAAW,CAAC,qBAAqB,EAAE,CAAC,CAAC;QAE1E,MAAM,cAAc,GAAG,
|
1
|
+
{"version":3,"file":"application-factory.js","sourceRoot":"","sources":["../../src/application/application-factory.ts"],"names":[],"mappings":"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"}
|
@@ -0,0 +1,29 @@
|
|
1
|
+
/**
|
2
|
+
* 应用启动钩子系统
|
3
|
+
*
|
4
|
+
* 这是一个通用的钩子系统,允许外部包注册自己的初始化逻辑
|
5
|
+
* 而不会让 core 包与特定的外部包产生耦合
|
6
|
+
*/
|
7
|
+
export type ApplicationHook = (container: any) => Promise<void> | void;
|
8
|
+
/**
|
9
|
+
* 应用钩子管理器
|
10
|
+
*/
|
11
|
+
export declare class ApplicationHooks {
|
12
|
+
private static instance;
|
13
|
+
private hooks;
|
14
|
+
private constructor();
|
15
|
+
static getInstance(): ApplicationHooks;
|
16
|
+
/**
|
17
|
+
* 注册应用启动钩子
|
18
|
+
*/
|
19
|
+
registerHook(hook: ApplicationHook): void;
|
20
|
+
/**
|
21
|
+
* 执行所有注册的钩子
|
22
|
+
*/
|
23
|
+
executeHooks(container: any): Promise<void>;
|
24
|
+
/**
|
25
|
+
* 清空所有钩子
|
26
|
+
*/
|
27
|
+
clearHooks(): void;
|
28
|
+
}
|
29
|
+
//# sourceMappingURL=application-hooks.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"application-hooks.d.ts","sourceRoot":"","sources":["../../src/application/application-hooks.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAEvE;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAmB;IAC1C,OAAO,CAAC,KAAK,CAAyB;IAEtC,OAAO;IAEP,MAAM,CAAC,WAAW,IAAI,gBAAgB;IAOtC;;OAEG;IACH,YAAY,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIzC;;OAEG;IACG,YAAY,CAAC,SAAS,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC;IAUjD;;OAEG;IACH,UAAU,IAAI,IAAI;CAGnB"}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
"use strict";
|
2
|
+
/**
|
3
|
+
* 应用启动钩子系统
|
4
|
+
*
|
5
|
+
* 这是一个通用的钩子系统,允许外部包注册自己的初始化逻辑
|
6
|
+
* 而不会让 core 包与特定的外部包产生耦合
|
7
|
+
*/
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
9
|
+
exports.ApplicationHooks = void 0;
|
10
|
+
/**
|
11
|
+
* 应用钩子管理器
|
12
|
+
*/
|
13
|
+
class ApplicationHooks {
|
14
|
+
static instance;
|
15
|
+
hooks = [];
|
16
|
+
constructor() { }
|
17
|
+
static getInstance() {
|
18
|
+
if (!ApplicationHooks.instance) {
|
19
|
+
ApplicationHooks.instance = new ApplicationHooks();
|
20
|
+
}
|
21
|
+
return ApplicationHooks.instance;
|
22
|
+
}
|
23
|
+
/**
|
24
|
+
* 注册应用启动钩子
|
25
|
+
*/
|
26
|
+
registerHook(hook) {
|
27
|
+
this.hooks.push(hook);
|
28
|
+
}
|
29
|
+
/**
|
30
|
+
* 执行所有注册的钩子
|
31
|
+
*/
|
32
|
+
async executeHooks(container) {
|
33
|
+
for (const hook of this.hooks) {
|
34
|
+
try {
|
35
|
+
await hook(container);
|
36
|
+
}
|
37
|
+
catch (error) {
|
38
|
+
console.warn('Failed to execute application hook:', error);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
}
|
42
|
+
/**
|
43
|
+
* 清空所有钩子
|
44
|
+
*/
|
45
|
+
clearHooks() {
|
46
|
+
this.hooks = [];
|
47
|
+
}
|
48
|
+
}
|
49
|
+
exports.ApplicationHooks = ApplicationHooks;
|
50
|
+
//# sourceMappingURL=application-hooks.js.map
|
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"application-hooks.js","sourceRoot":"","sources":["../../src/application/application-hooks.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAIH;;GAEG;AACH,MAAa,gBAAgB;IACnB,MAAM,CAAC,QAAQ,CAAmB;IAClC,KAAK,GAAsB,EAAE,CAAC;IAEtC,gBAAuB,CAAC;IAExB,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,CAAC;YAC/B,gBAAgB,CAAC,QAAQ,GAAG,IAAI,gBAAgB,EAAE,CAAC;QACrD,CAAC;QACD,OAAO,gBAAgB,CAAC,QAAQ,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,IAAqB;QAChC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,YAAY,CAAC,SAAc;QAC/B,KAAK,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YAC9B,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC;YACxB,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,qCAAqC,EAAE,KAAK,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;IAClB,CAAC;CACF;AAvCD,4CAuCC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAC;AACnC,cAAc,
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
|
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
15
15
|
};
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
17
|
-
__exportStar(require("./hest-application"), exports);
|
18
17
|
__exportStar(require("./application-factory"), exports);
|
18
|
+
__exportStar(require("./hest-application"), exports);
|
19
|
+
__exportStar(require("./application-hooks"), exports);
|
19
20
|
//# sourceMappingURL=index.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,qDAAmC;AACnC,
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/application/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wDAAsC;AACtC,qDAAmC;AACnC,sDAAoC"}
|
@@ -1,16 +1,37 @@
|
|
1
1
|
import "reflect-metadata";
|
2
2
|
import { DependencyContainer, InjectionToken } from "tsyringe";
|
3
|
+
import type { InjectableMetadata, ControllerMetadata, ModuleMetadata } from "../interfaces/metadata";
|
4
|
+
import type { ControllerConstructor } from "../interfaces/router";
|
5
|
+
import { Scope } from "../utils/constants";
|
3
6
|
declare global {
|
4
7
|
namespace Reflect {
|
5
8
|
function getMetadata(key: any, target: any, propertyKey?: string | symbol): any;
|
6
9
|
}
|
7
10
|
}
|
11
|
+
/**
|
12
|
+
* 逻辑容器项类型
|
13
|
+
*/
|
14
|
+
export interface LogicalContainerItem<T = any> {
|
15
|
+
token: InjectionToken<T>;
|
16
|
+
provider: T;
|
17
|
+
type: 'controller' | 'provider' | 'module';
|
18
|
+
metadata?: ControllerMetadata | InjectableMetadata | ModuleMetadata;
|
19
|
+
scope?: Scope;
|
20
|
+
}
|
21
|
+
/**
|
22
|
+
* 控制器容器项特化类型
|
23
|
+
*/
|
24
|
+
export interface ControllerContainerItem extends LogicalContainerItem<ControllerConstructor> {
|
25
|
+
type: 'controller';
|
26
|
+
metadata?: ControllerMetadata;
|
27
|
+
}
|
8
28
|
/**
|
9
29
|
* HestJS DI 容器封装
|
10
30
|
*/
|
11
31
|
export declare class Container {
|
12
32
|
private static instance;
|
13
33
|
private container;
|
34
|
+
private logicalContainer;
|
14
35
|
constructor();
|
15
36
|
/**
|
16
37
|
* 获取容器单例
|
@@ -19,7 +40,7 @@ export declare class Container {
|
|
19
40
|
/**
|
20
41
|
* 注册服务
|
21
42
|
*/
|
22
|
-
register<T>(token: InjectionToken<T>, provider: any): void;
|
43
|
+
register<T>(token: InjectionToken<T>, provider: any, type?: 'controller' | 'provider' | 'module'): void;
|
23
44
|
/**
|
24
45
|
* 注册实例
|
25
46
|
*/
|
@@ -44,5 +65,21 @@ export declare class Container {
|
|
44
65
|
* 获取底层容器实例
|
45
66
|
*/
|
46
67
|
getContainer(): DependencyContainer;
|
68
|
+
/**
|
69
|
+
* 获取逻辑容器中的所有项
|
70
|
+
*/
|
71
|
+
getLogicalContainer(): Map<InjectionToken<any>, LogicalContainerItem>;
|
72
|
+
/**
|
73
|
+
* 获取指定类型的所有项
|
74
|
+
*/
|
75
|
+
getItemsByType(type: 'controller' | 'provider' | 'module'): LogicalContainerItem[];
|
76
|
+
/**
|
77
|
+
* 获取所有控制器
|
78
|
+
*/
|
79
|
+
getAllControllers(): ControllerContainerItem[];
|
80
|
+
/**
|
81
|
+
* 提取元数据信息
|
82
|
+
*/
|
83
|
+
private extractMetadata;
|
47
84
|
}
|
48
85
|
//# sourceMappingURL=container.d.ts.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,cAAc,EAEf,MAAM,UAAU,CAAC;
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EACL,mBAAmB,EACnB,cAAc,EAEf,MAAM,UAAU,CAAC;AAClB,OAAO,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACrG,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,EAAiB,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAG1D,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,SAAS,WAAW,CAAC,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,GAAG,CAAC;KACjF;CACF;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB,CAAC,CAAC,GAAG,GAAG;IAC3C,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IACzB,QAAQ,EAAE,CAAC,CAAC;IACZ,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,QAAQ,CAAC;IAC3C,QAAQ,CAAC,EAAE,kBAAkB,GAAG,kBAAkB,GAAG,cAAc,CAAC;IACpE,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,oBAAoB,CAAC,qBAAqB,CAAC;IAC1F,IAAI,EAAE,YAAY,CAAC;IACnB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAY;IACnC,OAAO,CAAC,SAAS,CAAsB;IACvC,OAAO,CAAC,gBAAgB,CAA6D;;IAMrF;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,SAAS;IAO/B;;OAEG;IACH,QAAQ,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,GAAE,YAAY,GAAG,UAAU,GAAG,QAAqB,GAAG,IAAI;IA0BnH;;OAEG;IACH,gBAAgB,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI;IAIhE;;OAEG;IACH,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,CAAC;IAIvC;;OAEG;IACH,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,OAAO;IAIlD;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,WAAW,IAAI,SAAS;IAMxB;;OAEG;IACH,YAAY,IAAI,mBAAmB;IAInC;;OAEG;IACH,mBAAmB,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,EAAE,oBAAoB,CAAC;IAIrE;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,YAAY,GAAG,UAAU,GAAG,QAAQ,GAAG,oBAAoB,EAAE;IAIlF;;OAEG;IACH,iBAAiB,IAAI,uBAAuB,EAAE;IAI9C;;OAEG;IACH,OAAO,CAAC,eAAe;CAYxB"}
|
@@ -10,6 +10,7 @@ const constants_1 = require("../utils/constants");
|
|
10
10
|
class Container {
|
11
11
|
static instance;
|
12
12
|
container;
|
13
|
+
logicalContainer = new Map();
|
13
14
|
constructor() {
|
14
15
|
this.container = tsyringe_1.container.createChildContainer();
|
15
16
|
}
|
@@ -25,8 +26,17 @@ class Container {
|
|
25
26
|
/**
|
26
27
|
* 注册服务
|
27
28
|
*/
|
28
|
-
register(token, provider) {
|
29
|
+
register(token, provider, type = 'provider') {
|
29
30
|
const metadata = Reflect.getMetadata(constants_1.METADATA_KEYS.INJECTABLE, provider) || {};
|
31
|
+
// 保存到逻辑容器
|
32
|
+
const logicalItem = {
|
33
|
+
token,
|
34
|
+
provider,
|
35
|
+
type,
|
36
|
+
metadata: this.extractMetadata(provider, type),
|
37
|
+
scope: metadata.scope
|
38
|
+
};
|
39
|
+
this.logicalContainer.set(token, logicalItem);
|
30
40
|
switch (metadata.scope) {
|
31
41
|
case constants_1.Scope.SINGLETON:
|
32
42
|
this.container.registerSingleton(token, provider);
|
@@ -76,6 +86,39 @@ class Container {
|
|
76
86
|
getContainer() {
|
77
87
|
return this.container;
|
78
88
|
}
|
89
|
+
/**
|
90
|
+
* 获取逻辑容器中的所有项
|
91
|
+
*/
|
92
|
+
getLogicalContainer() {
|
93
|
+
return this.logicalContainer;
|
94
|
+
}
|
95
|
+
/**
|
96
|
+
* 获取指定类型的所有项
|
97
|
+
*/
|
98
|
+
getItemsByType(type) {
|
99
|
+
return Array.from(this.logicalContainer.values()).filter(item => item.type === type);
|
100
|
+
}
|
101
|
+
/**
|
102
|
+
* 获取所有控制器
|
103
|
+
*/
|
104
|
+
getAllControllers() {
|
105
|
+
return this.getItemsByType('controller');
|
106
|
+
}
|
107
|
+
/**
|
108
|
+
* 提取元数据信息
|
109
|
+
*/
|
110
|
+
extractMetadata(provider, type) {
|
111
|
+
switch (type) {
|
112
|
+
case 'controller':
|
113
|
+
return Reflect.getMetadata(constants_1.METADATA_KEYS.CONTROLLER, provider);
|
114
|
+
case 'module':
|
115
|
+
return Reflect.getMetadata(constants_1.METADATA_KEYS.MODULE, provider);
|
116
|
+
case 'provider':
|
117
|
+
return Reflect.getMetadata(constants_1.METADATA_KEYS.INJECTABLE, provider);
|
118
|
+
default:
|
119
|
+
return null;
|
120
|
+
}
|
121
|
+
}
|
79
122
|
}
|
80
123
|
exports.Container = Container;
|
81
124
|
//# sourceMappingURL=container.js.map
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":";;;AAAA,4BAA0B;AAC1B,uCAIkB;
|
1
|
+
{"version":3,"file":"container.js","sourceRoot":"","sources":["../../src/container/container.ts"],"names":[],"mappings":";;;AAAA,4BAA0B;AAC1B,uCAIkB;AAGlB,kDAA0D;AA4B1D;;GAEG;AACH,MAAa,SAAS;IACZ,MAAM,CAAC,QAAQ,CAAY;IAC3B,SAAS,CAAsB;IAC/B,gBAAgB,GAAmD,IAAI,GAAG,EAAE,CAAC;IAErF;QACE,IAAI,CAAC,SAAS,GAAG,oBAAiB,CAAC,oBAAoB,EAAE,CAAC;IAC5D,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC;YACxB,SAAS,CAAC,QAAQ,GAAG,IAAI,SAAS,EAAE,CAAC;QACvC,CAAC;QACD,OAAO,SAAS,CAAC,QAAQ,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,QAAQ,CAAI,KAAwB,EAAE,QAAa,EAAE,OAA6C,UAAU;QAC1G,MAAM,QAAQ,GACZ,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC;QAEhE,UAAU;QACV,MAAM,WAAW,GAAyB;YACxC,KAAK;YACL,QAAQ;YACR,IAAI;YACJ,QAAQ,EAAE,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,IAAI,CAAC;YAC9C,KAAK,EAAE,QAAQ,CAAC,KAAc;SAC/B,CAAC;QACF,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;QAE9C,QAAQ,QAAQ,CAAC,KAAK,EAAE,CAAC;YACvB,KAAK,iBAAK,CAAC,SAAS;gBAClB,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;gBAClD,MAAM;YACR,KAAK,iBAAK,CAAC,SAAS;gBAClB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACvD,MAAM;YACR;gBACE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAI,KAAwB,EAAE,QAAW;QACvD,IAAI,CAAC,SAAS,CAAC,gBAAgB,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACH,OAAO,CAAI,KAAwB;QACjC,OAAO,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACvC,CAAC;IAED;;OAEG;IACH,YAAY,CAAI,KAAwB;QACtC,OAAO,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,KAAK;QACH,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE,CAAC;IAClC,CAAC;IAED;;OAEG;IACH,WAAW;QACT,MAAM,KAAK,GAAG,IAAI,SAAS,EAAE,CAAC;QAC9B,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,oBAAoB,EAAE,CAAC;QACxD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,YAAY;QACV,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,mBAAmB;QACjB,OAAO,IAAI,CAAC,gBAAgB,CAAC;IAC/B,CAAC;IAED;;OAEG;IACH,cAAc,CAAC,IAA0C;QACvD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IACvF,CAAC;IAED;;OAEG;IACH,iBAAiB;QACf,OAAO,IAAI,CAAC,cAAc,CAAC,YAAY,CAA8B,CAAC;IACxE,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,QAAa,EAAE,IAA0C;QAC/E,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,YAAY;gBACf,OAAO,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACjE,KAAK,QAAQ;gBACX,OAAO,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC7D,KAAK,UAAU;gBACb,OAAO,OAAO,CAAC,WAAW,CAAC,yBAAa,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACjE;gBACE,OAAO,IAAI,CAAC;QAChB,CAAC;IACH,CAAC;CACF;AAhID,8BAgIC"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/container/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC"}
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/container/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,mBAAmB,CAAC;AAClC,YAAY,EAAE,oBAAoB,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC"}
|
package/package.json
CHANGED