imean-service-engine 2.0.0 → 2.0.2

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 (72) hide show
  1. package/dist/index.d.mts +77 -52
  2. package/dist/index.d.ts +77 -52
  3. package/dist/index.js +2078 -1945
  4. package/dist/index.mjs +2076 -1944
  5. package/package.json +9 -2
  6. package/.vscode/settings.json +0 -8
  7. package/src/core/checker.ts +0 -33
  8. package/src/core/decorators.test.ts +0 -96
  9. package/src/core/decorators.ts +0 -68
  10. package/src/core/engine.test.ts +0 -218
  11. package/src/core/engine.ts +0 -635
  12. package/src/core/errors.ts +0 -28
  13. package/src/core/factory.test.ts +0 -73
  14. package/src/core/factory.ts +0 -92
  15. package/src/core/logger.ts +0 -65
  16. package/src/core/testing.ts +0 -73
  17. package/src/core/types.ts +0 -191
  18. package/src/index.ts +0 -49
  19. package/src/metadata/README.md +0 -422
  20. package/src/metadata/metadata.test.ts +0 -369
  21. package/src/metadata/metadata.ts +0 -512
  22. package/src/plugins/action/action-plugin.test.ts +0 -660
  23. package/src/plugins/action/decorator.ts +0 -14
  24. package/src/plugins/action/index.ts +0 -4
  25. package/src/plugins/action/plugin.ts +0 -349
  26. package/src/plugins/action/types.ts +0 -49
  27. package/src/plugins/action/utils.test.ts +0 -196
  28. package/src/plugins/action/utils.ts +0 -111
  29. package/src/plugins/cache/adapter.test.ts +0 -689
  30. package/src/plugins/cache/adapter.ts +0 -324
  31. package/src/plugins/cache/cache-plugin.test.ts +0 -269
  32. package/src/plugins/cache/decorator.ts +0 -26
  33. package/src/plugins/cache/index.ts +0 -20
  34. package/src/plugins/cache/plugin.ts +0 -299
  35. package/src/plugins/cache/types.ts +0 -69
  36. package/src/plugins/client-code/client-code-plugin.test.ts +0 -511
  37. package/src/plugins/client-code/format.ts +0 -9
  38. package/src/plugins/client-code/generator.test.ts +0 -52
  39. package/src/plugins/client-code/generator.ts +0 -263
  40. package/src/plugins/client-code/index.ts +0 -15
  41. package/src/plugins/client-code/plugin.ts +0 -158
  42. package/src/plugins/client-code/types.ts +0 -52
  43. package/src/plugins/client-code/utils.ts +0 -164
  44. package/src/plugins/graceful-shutdown/graceful-shutdown-plugin.test.ts +0 -401
  45. package/src/plugins/graceful-shutdown/index.ts +0 -3
  46. package/src/plugins/graceful-shutdown/plugin.ts +0 -279
  47. package/src/plugins/graceful-shutdown/types.ts +0 -17
  48. package/src/plugins/rate-limit/rate-limit-plugin.example.ts +0 -171
  49. package/src/plugins/route/components/Layout.tsx +0 -42
  50. package/src/plugins/route/components/ServiceStatusPage.tsx +0 -141
  51. package/src/plugins/route/decorator.ts +0 -50
  52. package/src/plugins/route/index.ts +0 -16
  53. package/src/plugins/route/plugin.ts +0 -218
  54. package/src/plugins/route/route-plugin.test.ts +0 -759
  55. package/src/plugins/route/types.ts +0 -72
  56. package/src/plugins/schedule/README.md +0 -309
  57. package/src/plugins/schedule/decorator.ts +0 -25
  58. package/src/plugins/schedule/index.ts +0 -12
  59. package/src/plugins/schedule/mock-etcd.ts +0 -145
  60. package/src/plugins/schedule/plugin.ts +0 -164
  61. package/src/plugins/schedule/schedule-plugin.test.ts +0 -312
  62. package/src/plugins/schedule/scheduler.ts +0 -164
  63. package/src/plugins/schedule/types.ts +0 -94
  64. package/src/plugins/schedule/utils.test.ts +0 -163
  65. package/src/plugins/schedule/utils.ts +0 -41
  66. package/tests/integration/client.test.ts +0 -203
  67. package/tests/integration/dev-service.ts +0 -301
  68. package/tests/integration/generated/client.ts +0 -123
  69. package/tests/integration/start-service.ts +0 -21
  70. package/tsconfig.json +0 -27
  71. package/tsup.config.ts +0 -16
  72. package/vitest.config.ts +0 -19
@@ -1,422 +0,0 @@
1
- # 通用元数据工具库
2
-
3
- ## 概述
4
-
5
- `metadata.ts` 是一个轻量级的装饰器元数据管理工具库,类似于 `reflect-metadata`,但更简单、更轻量。
6
-
7
- ## 特性
8
-
9
- - ✅ 基于 Stage 3 装饰器标准(TypeScript 5.0+)
10
- - ✅ 无需外部依赖
11
- - ✅ 支持类装饰器和方法装饰器
12
- - ✅ 支持方法装饰器多应用(同一方法可被多个装饰器标注)
13
- - ✅ **支持双向访问**:通过 key 查找类,通过类查找 key
14
- - ✅ 类型安全
15
- - ✅ 简单够用
16
-
17
- ## 设计原理
18
-
19
- ### 核心数据结构
20
-
21
- 新设计采用**双向映射**机制,实现了装饰器 key 和类之间的双向访问:
22
-
23
- #### 1. key -> classes 映射
24
-
25
- ```typescript
26
- const keyToClassesMap = new Map<symbol, Set<Class>>();
27
- ```
28
-
29
- - **用途**:记录某个装饰器 key 装饰了哪些类
30
- - **存储位置**:全局 Map(非 WeakMap),因为需要能够遍历所有被装饰的类
31
- - **访问方式**:通过 `getClassesByKey(key)` 获取所有被该 key 装饰的类
32
-
33
- #### 2. class -> keys 映射
34
-
35
- ```typescript
36
- // 通过 classMetadataStore 和固定的 DECORATED_KEYS_KEY 实现
37
- const DECORATED_KEYS_KEY = Symbol.for("imean:decoratedKeys");
38
- // 存储在 classMetadataStore 中:classMetadataStore.get(class).get(DECORATED_KEYS_KEY) -> Set<symbol>
39
- ```
40
-
41
- - **用途**:记录某个类被哪些装饰器 key 装饰了
42
- - **存储位置**:存储在 `classMetadataStore` 中,使用固定的 `DECORATED_KEYS_KEY` 作为 key
43
- - **访问方式**:通过 `getKeysByClass(target)` 获取装饰该类的所有 key
44
-
45
- #### 3. class + key -> metadata 映射
46
-
47
- ```typescript
48
- const classMetadataStore = new WeakMap<Class, Map<symbol, any>>();
49
- ```
50
-
51
- - **用途**:存储真正的元数据
52
- - **存储结构**:
53
- - key: 类构造函数
54
- - value: Map<symbol, any>
55
- - `DECORATED_KEYS_KEY` -> `Set<symbol>`(记录该类被哪些 key 装饰)
56
- - 其他 key -> 实际的元数据对象
57
- - **访问方式**:通过 `getClassMetadata(target, key)` 获取元数据
58
-
59
- ### 双向映射维护机制
60
-
61
- 当装饰器应用到类上时,系统会自动维护双向映射:
62
-
63
- ```typescript
64
- function registerKeyClassRelation(targetClass: Class, metadataKey: symbol): void {
65
- // 1. 在类上记录这个 key(class -> keys)
66
- const decoratedKeys = getOrCreateDecoratedKeysSet(targetClass);
67
- decoratedKeys.add(metadataKey);
68
-
69
- // 2. 在 keyToClassesMap 中记录这个类(key -> classes)
70
- if (!keyToClassesMap.has(metadataKey)) {
71
- keyToClassesMap.set(metadataKey, new Set());
72
- }
73
- keyToClassesMap.get(metadataKey)!.add(targetClass);
74
- }
75
- ```
76
-
77
- ### 设计优势
78
-
79
- 1. **双向访问**:
80
- - 通过 key 可以找到所有被装饰的类(无需知道类名)
81
- - 通过类可以找到所有装饰它的 key(了解类的装饰情况)
82
-
83
- 2. **元数据存储分离**:
84
- - 映射关系存储在全局 Map 和类上的固定 key
85
- - 真正的元数据存储在类上,通过 key 访问
86
-
87
- 3. **内存安全**:
88
- - 使用 WeakMap 存储类相关的数据,避免内存泄漏
89
- - keyToClassesMap 使用普通 Map,但只存储类引用,不阻止垃圾回收
90
-
91
- ### 使用场景示例
92
-
93
- #### 场景 1:通过 key 查找所有被装饰的类
94
-
95
- ```typescript
96
- const Module = createClassDecorator();
97
- const key = Symbol.for("imean:classMetadata");
98
-
99
- @Module({ name: "user-module" })
100
- class UserService {}
101
-
102
- @Module({ name: "order-module" })
103
- class OrderService {}
104
-
105
- // 无需知道类名,直接通过 key 查找所有模块
106
- const allModules = getClassesByKey(key);
107
- // Set { UserService, OrderService }
108
-
109
- // 遍历所有模块并获取元数据
110
- for (const ModuleClass of allModules) {
111
- const metadata = getClassMetadata(ModuleClass, key);
112
- console.log(metadata.name); // "user-module", "order-module"
113
- }
114
- ```
115
-
116
- #### 场景 2:查看类被哪些装饰器装饰
117
-
118
- ```typescript
119
- const Module = createClassDecorator();
120
- const Config = createClassDecorator(Symbol.for("config"));
121
- const Cache = createClassDecorator(Symbol.for("cache"));
122
-
123
- @Module({ name: "test" })
124
- @Config({ env: "prod" })
125
- @Cache({ ttl: 60 })
126
- class TestService {}
127
-
128
- // 查看类被哪些装饰器装饰
129
- const keys = getKeysByClass(TestService);
130
- // Set { Symbol(imean:classMetadata), Symbol(config), Symbol(cache) }
131
-
132
- // 遍历所有 key 并获取对应的元数据
133
- for (const key of keys) {
134
- const metadata = getClassMetadata(TestService, key);
135
- console.log(key.toString(), metadata);
136
- }
137
- ```
138
-
139
- ## API
140
-
141
- ### 创建装饰器
142
-
143
- #### `createClassDecorator(metadataKey?)`
144
-
145
- 创建类装饰器工厂函数。
146
-
147
- ```typescript
148
- import { createClassDecorator } from "./metadata/metadata";
149
-
150
- const Module = createClassDecorator();
151
-
152
- @Module({ name: "user-module", version: "1.0.0" })
153
- class UserService {}
154
- ```
155
-
156
- #### `createMethodDecorator(metadataKey?)`
157
-
158
- 创建方法装饰器工厂函数。
159
-
160
- ```typescript
161
- import { createMethodDecorator } from "./metadata/metadata";
162
-
163
- const Handler = createMethodDecorator();
164
-
165
- class UserService {
166
- @Handler({ type: "route", options: { method: "GET" } })
167
- getUser() {}
168
- }
169
- ```
170
-
171
- ### 双向访问 API(新功能)
172
-
173
- #### `getClassesByKey(metadataKey)`
174
-
175
- 通过装饰器 key 获取所有被装饰的类。
176
-
177
- ```typescript
178
- import { getClassesByKey } from "./metadata/metadata";
179
-
180
- const key = Symbol.for("imean:classMetadata");
181
- const classes = getClassesByKey(key);
182
- // Set { UserService, OrderService, ... }
183
- ```
184
-
185
- #### `getKeysByClass(target)`
186
-
187
- 获取类被哪些装饰器 key 装饰了。
188
-
189
- ```typescript
190
- import { getKeysByClass } from "./metadata/metadata";
191
-
192
- const keys = getKeysByClass(UserService);
193
- // Set { Symbol(imean:classMetadata), Symbol(config), ... }
194
- ```
195
-
196
- ### 读取元数据
197
-
198
- #### `getClassMetadata(target, metadataKey?)`
199
-
200
- 获取类的元数据。
201
-
202
- ```typescript
203
- import { getClassMetadata } from "./metadata/metadata";
204
-
205
- const metadata = getClassMetadata(UserService);
206
- console.log(metadata.name); // 'user-module'
207
- ```
208
-
209
- #### `getMethodMetadata(target, methodName, metadataKey?)`
210
-
211
- 获取方法的元数据列表。
212
-
213
- ```typescript
214
- import { getMethodMetadata } from "./metadata/metadata";
215
-
216
- const metadataList = getMethodMetadata(UserService, "getUser");
217
- console.log(metadataList); // [{ type: 'route', options: {...} }]
218
- ```
219
-
220
- #### `getAllMethodMetadata(target, metadataKey?)`
221
-
222
- 获取类的所有方法元数据。
223
-
224
- ```typescript
225
- import { getAllMethodMetadata } from "./metadata/metadata";
226
-
227
- const allMetadata = getAllMethodMetadata(UserService);
228
- // Map<string, MethodMetadataItem[]>
229
- ```
230
-
231
- ### 检查元数据
232
-
233
- #### `hasClassMetadata(target, metadataKey?)`
234
-
235
- 检查类是否有元数据。
236
-
237
- #### `hasMethodMetadata(target, methodName, metadataKey?)`
238
-
239
- 检查方法是否有元数据。
240
-
241
- ## 使用示例
242
-
243
- ### 基础用法
244
-
245
- ```typescript
246
- import { createClassDecorator, createMethodDecorator } from "./metadata/metadata";
247
-
248
- // 创建装饰器
249
- const Module = createClassDecorator();
250
- const Handler = createMethodDecorator();
251
-
252
- // 使用装饰器
253
- @Module({ name: "user-service" })
254
- class UserService {
255
- @Handler({ type: "route", options: { method: "GET" } })
256
- getUser() {
257
- return { id: 1 };
258
- }
259
- }
260
-
261
- // 读取元数据
262
- import { getClassMetadata, getMethodMetadata } from "./metadata/metadata";
263
-
264
- const classMeta = getClassMetadata(UserService);
265
- const methodMeta = getMethodMetadata(UserService, "getUser");
266
- ```
267
-
268
- ### 双向访问示例
269
-
270
- ```typescript
271
- import {
272
- createClassDecorator,
273
- getClassesByKey,
274
- getKeysByClass,
275
- getClassMetadata,
276
- } from "./metadata/metadata";
277
-
278
- const Module = createClassDecorator();
279
- const key = Symbol.for("imean:classMetadata");
280
-
281
- @Module({ name: "user-module" })
282
- class UserService {}
283
-
284
- @Module({ name: "order-module" })
285
- class OrderService {}
286
-
287
- // 方式 1:通过 key 查找所有被装饰的类
288
- const allModules = getClassesByKey(key);
289
- console.log(allModules.size); // 2
290
-
291
- // 遍历所有模块
292
- for (const ModuleClass of allModules) {
293
- const metadata = getClassMetadata(ModuleClass, key);
294
- console.log(metadata.name);
295
- }
296
-
297
- // 方式 2:查看类被哪些装饰器装饰
298
- const keys = getKeysByClass(UserService);
299
- console.log(keys.has(key)); // true
300
- ```
301
-
302
- ### 自定义元数据键
303
-
304
- ```typescript
305
- import { createMethodDecorator } from "./metadata/metadata";
306
-
307
- const CUSTOM_KEY = Symbol.for("my-custom-key");
308
- const Handler = createMethodDecorator(CUSTOM_KEY);
309
-
310
- class Service {
311
- @Handler({ type: "custom" })
312
- method() {}
313
- }
314
- ```
315
-
316
- ### 多装饰器应用
317
-
318
- ```typescript
319
- const Handler = createMethodDecorator();
320
-
321
- class Service {
322
- // 同一方法可以被多个装饰器标注
323
- @Handler({ type: "route", options: { method: "GET" } })
324
- @Handler({ type: "cache", options: { ttl: 60 } })
325
- @Handler({ type: "auth", options: { required: true } })
326
- getUser() {}
327
- }
328
-
329
- // 读取时会返回所有元数据
330
- const metadata = getMethodMetadata(Service, "getUser");
331
- // [{ type: 'route', ... }, { type: 'cache', ... }, { type: 'auth', ... }]
332
- ```
333
-
334
- ## 与 reflect-metadata 的区别
335
-
336
- | 特性 | reflect-metadata | metadata.ts |
337
- | -------- | ------------------------ | ---------------------- |
338
- | 标准 | 实验性装饰器 | Stage 3 装饰器 |
339
- | 依赖 | 需要包 | 无依赖 |
340
- | API | `Reflect.defineMetadata` | `createClassDecorator` |
341
- | 性能 | 运行时反射 | 直接属性访问 |
342
- | 类型安全 | 部分 | 完全 |
343
- | 双向访问 | 不支持 | ✅ 支持 |
344
-
345
- ## 设计原则
346
-
347
- 1. **简单够用**:只提供必要的功能,不包含业务逻辑
348
- 2. **类型安全**:完整的 TypeScript 类型支持
349
- 3. **无依赖**:不依赖任何外部库
350
- 4. **标准化**:使用最新的装饰器标准
351
- 5. **双向访问**:支持通过 key 查找类,通过类查找 key
352
-
353
- ## 在框架中的使用
354
-
355
- 框架使用此工具库来实现:
356
-
357
- - `Handler` 装饰器:基于 `createMethodDecorator`
358
- - `Module` 装饰器:基于 `createClassDecorator`
359
- - 元数据读取:使用 `getMethodMetadata` 和 `getAllMethodMetadata`
360
- - **类发现**:使用 `getClassesByKey` 查找所有被装饰的类(无需知道类名)
361
-
362
- 这样的设计使得装饰器功能与框架业务逻辑完全解耦,可以独立使用或替换。
363
-
364
- ## 数据流图
365
-
366
- ```
367
- 装饰器应用流程:
368
- ┌─────────────────────────────────────────────────────────────┐
369
- │ @Module({ name: "user-module" }) │
370
- │ class UserService {} │
371
- └─────────────────────────────────────────────────────────────┘
372
-
373
-
374
- ┌─────────────────────────────────────────────────────────────┐
375
- │ registerKeyClassRelation(UserService, key) │
376
- └─────────────────────────────────────────────────────────────┘
377
-
378
- ┌───────────┴───────────┐
379
- ▼ ▼
380
- ┌───────────────────┐ ┌───────────────────┐
381
- │ keyToClassesMap │ │ classMetadataStore│
382
- │ key -> Set<Class> │ │ class -> Map<...> │
383
- │ │ │ DECORATED_KEYS │
384
- │ key: { │ │ KEY -> Set<key> │
385
- │ UserService │ │ key -> metadata │
386
- │ } │ │ } │
387
- └───────────────────┘ └───────────────────┘
388
- │ │
389
- │ │
390
- ▼ ▼
391
- ┌───────────────────┐ ┌───────────────────┐
392
- │ getClassesByKey() │ │ getKeysByClass() │
393
- │ 通过 key 找类 │ │ 通过类找 key │
394
- └───────────────────┘ └───────────────────┘
395
- ```
396
-
397
- ## 实现细节
398
-
399
- ### 1. 装饰器应用时的处理
400
-
401
- 当装饰器应用到类上时,`createClassDecorator` 会:
402
-
403
- 1. 调用 `registerKeyClassRelation` 注册双向映射
404
- 2. 将元数据存储到 `classMetadataStore` 中
405
-
406
- ### 2. 方法装饰器的处理
407
-
408
- 方法装饰器也会在类上注册 key,这样可以通过 `getKeysByClass` 找到所有装饰该类的 key(包括类装饰器和方法装饰器的 key)。
409
-
410
- ### 3. 内存管理
411
-
412
- - `classMetadataStore` 和 `methodMetadataStore` 使用 WeakMap,不会阻止垃圾回收
413
- - `keyToClassesMap` 使用普通 Map,但只存储类引用,类被回收后引用会失效(虽然 Set 中仍保留引用,但不影响功能)
414
- - 如果需要完全清理,可以考虑添加清理函数(当前版本暂未实现)
415
-
416
- ## 注意事项
417
-
418
- 1. **keyToClassesMap 的内存**:使用普通 Map 而非 WeakMap,因为需要能够遍历所有被装饰的类。如果类被回收,Map 中的引用会变成"僵尸引用",但不影响功能。
419
-
420
- 2. **装饰器执行时机**:装饰器在类定义时执行,但 `addInitializer` 中的代码在类实例化时执行。因此双向映射的注册发生在类实例化时。
421
-
422
- 3. **方法装饰器**:方法装饰器也会在类上注册 key,这意味着 `getKeysByClass` 会返回包括方法装饰器 key 在内的所有 key。