typespeed 2.4.10 → 2.5.0

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.
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ /**
3
+ * 装饰器双签名感知工具。
4
+ *
5
+ * typespeed 2.5.x 起,装饰器同时支持两套运行时签名:
6
+ * - legacy(experimentalDecorators: true,2.4.x 现状):
7
+ * 类装饰器 (ctor);方法/属性装饰器 (target, key);带 descriptor 的方法 (target, key, descriptor);参数 (target, key, index)
8
+ * - 标准(TC39 装饰器提案,当前 Stage 2.7,experimentalDecorators: false):
9
+ * 统一 (value, context),context 恒为带 kind 字段的对象
10
+ *
11
+ * 装饰器函数本质是普通函数,运行时收到什么签名由「调用方(用户代码)」的编译模式决定,
12
+ * 因此库可以单份源码、运行时按签名形态分流:legacy 分支逻辑与 2.4.x 逐字一致,标准分支为新增。
13
+ */
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.getStdArgs = exports.isStd = void 0;
16
+ /**
17
+ * 判断装饰器收到的运行时参数是否为标准装饰器签名 (value, context)。
18
+ *
19
+ * 判据(与 `2.5.x-新版装饰器使用方案.md` 一致):
20
+ * 参数个数 === 2 且第二个参数是「带 string 类型 kind 字段」的对象。
21
+ *
22
+ * 为什么这个判据可靠:
23
+ * - legacy 类装饰器只有 1 参 → 不满足 length === 2
24
+ * - legacy 方法/属性装饰器第二参是 string 的 key → 不是对象
25
+ * - legacy 带 descriptor 的方法 / 参数装饰器是 3 参 → 不满足 length === 2
26
+ * - 标准模式第二参恒是带 kind 的对象 → 命中
27
+ */
28
+ function isStd(args) {
29
+ return args.length === 2
30
+ && typeof args[1] === "object"
31
+ && args[1] !== null
32
+ && typeof args[1].kind === "string";
33
+ }
34
+ exports.isStd = isStd;
35
+ /**
36
+ * 从标准装饰器参数中解出 (value, context)。
37
+ * 仅应在 isStd(args) 为 true 时调用。
38
+ */
39
+ function getStdArgs(args) {
40
+ return [args[0], args[1]];
41
+ }
42
+ exports.getStdArgs = getStdArgs;
@@ -4,6 +4,8 @@ exports.jwt = exports.upload = exports.setRouter = exports.requestMapping = expo
4
4
  const multiparty = require("multiparty");
5
5
  const express_jwt_1 = require("express-jwt");
6
6
  const core_decorator_1 = require("./core.decorator");
7
+ const decorator_utils_1 = require("./decorator-utils");
8
+ const bind_decorator_1 = require("./bind.decorator");
7
9
  const routerMapper = {
8
10
  "get": {},
9
11
  "post": {},
@@ -28,7 +30,53 @@ function setRouter(app) {
28
30
  }
29
31
  exports.setRouter = setRouter;
30
32
  function mapperFunction(method, value) {
31
- return (target, propertyKey) => {
33
+ return (...args) => {
34
+ if ((0, decorator_utils_1.isStd)(args)) {
35
+ const [methodFn, ctx] = (0, decorator_utils_1.getStdArgs)(args);
36
+ ctx.addInitializer(function () {
37
+ const className = this.constructor.name;
38
+ const propertyKey = String(ctx.name);
39
+ applyRouteBind(className, propertyKey, methodFn);
40
+ routerMapper[method][value] = {
41
+ "path": value,
42
+ "name": [className, propertyKey].toString(),
43
+ "target": this.constructor,
44
+ "propertyKey": propertyKey,
45
+ "invoker": async (req, res, next) => {
46
+ const routerBean = (0, core_decorator_1.getComponent)(this.constructor);
47
+ try {
48
+ let paramTotal = routerBean[propertyKey].length;
49
+ if (routerParamsTotal[[className, propertyKey].toString()]) {
50
+ paramTotal = Math.max(paramTotal, routerParamsTotal[[className, propertyKey].toString()]);
51
+ }
52
+ const callArgs = [req, res, next];
53
+ if (paramTotal > 0) {
54
+ for (let i = 0; i < paramTotal; i++) {
55
+ if (routerParams[[className, propertyKey, i].toString()]) {
56
+ callArgs[i] = routerParams[[className, propertyKey, i].toString()](req, res, next);
57
+ }
58
+ }
59
+ }
60
+ const testResult = await routerBean[propertyKey].apply(routerBean, callArgs);
61
+ if (typeof testResult === "object") {
62
+ res.json(testResult);
63
+ }
64
+ else if (typeof testResult !== "undefined") {
65
+ res.send(testResult);
66
+ }
67
+ return testResult;
68
+ }
69
+ catch (err) {
70
+ next(err);
71
+ }
72
+ }
73
+ };
74
+ });
75
+ return;
76
+ }
77
+ const target = args[0];
78
+ const propertyKey = args[1];
79
+ applyRouteBind(target.constructor.name, propertyKey, target[propertyKey]);
32
80
  routerMapper[method][value] = {
33
81
  "path": value,
34
82
  "name": [target.constructor.name, propertyKey].toString(),
@@ -65,7 +113,22 @@ function mapperFunction(method, value) {
65
113
  };
66
114
  };
67
115
  }
68
- function upload(target, propertyKey) {
116
+ function upload(...args) {
117
+ if ((0, decorator_utils_1.isStd)(args)) {
118
+ const [, ctx] = (0, decorator_utils_1.getStdArgs)(args);
119
+ ctx.addInitializer(function () {
120
+ const key = [this.constructor.name, String(ctx.name)].toString();
121
+ if (routerMiddleware[key]) {
122
+ routerMiddleware[key].push(uploadMiddleware);
123
+ }
124
+ else {
125
+ routerMiddleware[key] = [uploadMiddleware];
126
+ }
127
+ });
128
+ return;
129
+ }
130
+ const target = args[0];
131
+ const propertyKey = args[1];
69
132
  const key = [target.constructor.name, propertyKey].toString();
70
133
  if (routerMiddleware[key]) {
71
134
  routerMiddleware[key].push(uploadMiddleware);
@@ -83,7 +146,22 @@ function uploadMiddleware(req, res, next) {
83
146
  });
84
147
  }
85
148
  function jwt(jwtConfig) {
86
- return (target, propertyKey) => {
149
+ return (...args) => {
150
+ if ((0, decorator_utils_1.isStd)(args)) {
151
+ const [, ctx] = (0, decorator_utils_1.getStdArgs)(args);
152
+ ctx.addInitializer(function () {
153
+ const key = [this.constructor.name, String(ctx.name)].toString();
154
+ if (routerMiddleware[key]) {
155
+ routerMiddleware[key].push((0, express_jwt_1.expressjwt)(jwtConfig));
156
+ }
157
+ else {
158
+ routerMiddleware[key] = [(0, express_jwt_1.expressjwt)(jwtConfig)];
159
+ }
160
+ });
161
+ return;
162
+ }
163
+ const target = args[0];
164
+ const propertyKey = args[1];
87
165
  const key = [target.constructor.name, propertyKey].toString();
88
166
  if (routerMiddleware[key]) {
89
167
  routerMiddleware[key].push((0, express_jwt_1.expressjwt)(jwtConfig));
@@ -96,15 +174,34 @@ function jwt(jwtConfig) {
96
174
  exports.jwt = jwt;
97
175
  function before(constructorFunction, methodName) {
98
176
  const targetBean = (0, core_decorator_1.getComponent)(constructorFunction);
99
- return function (target, propertyKey) {
177
+ return function (...args) {
178
+ if ((0, decorator_utils_1.isStd)(args)) {
179
+ const [, ctx] = (0, decorator_utils_1.getStdArgs)(args);
180
+ const hookKey = String(ctx.name);
181
+ ctx.addInitializer(function () {
182
+ const currentMethod = this[methodName];
183
+ if (currentMethod && currentMethod.length > 0) {
184
+ routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
185
+ }
186
+ Object.assign(this, {
187
+ [methodName]: function (...innerArgs) {
188
+ this[hookKey](...innerArgs);
189
+ return currentMethod.apply(this, innerArgs);
190
+ }
191
+ });
192
+ });
193
+ return;
194
+ }
195
+ const target = args[0];
196
+ const propertyKey = args[1];
100
197
  const currentMethod = targetBean[methodName];
101
198
  if (currentMethod.length > 0) {
102
199
  routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
103
200
  }
104
201
  Object.assign(targetBean, {
105
- [methodName]: function (...args) {
106
- target[propertyKey](...args);
107
- return currentMethod.apply(targetBean, args);
202
+ [methodName]: function (...innerArgs) {
203
+ target[propertyKey](...innerArgs);
204
+ return currentMethod.apply(targetBean, innerArgs);
108
205
  }
109
206
  });
110
207
  };
@@ -112,14 +209,34 @@ function before(constructorFunction, methodName) {
112
209
  exports.before = before;
113
210
  function after(constructorFunction, methodName) {
114
211
  const targetBean = (0, core_decorator_1.getComponent)(constructorFunction);
115
- return function (target, propertyKey) {
212
+ return function (...args) {
213
+ if ((0, decorator_utils_1.isStd)(args)) {
214
+ const [, ctx] = (0, decorator_utils_1.getStdArgs)(args);
215
+ const hookKey = String(ctx.name);
216
+ ctx.addInitializer(function () {
217
+ const currentMethod = this[methodName];
218
+ if (currentMethod && currentMethod.length > 0) {
219
+ routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
220
+ }
221
+ Object.assign(this, {
222
+ [methodName]: function (...innerArgs) {
223
+ const result = currentMethod.apply(this, innerArgs);
224
+ const afterResult = this[hookKey](result);
225
+ return afterResult !== null && afterResult !== void 0 ? afterResult : result;
226
+ }
227
+ });
228
+ });
229
+ return;
230
+ }
231
+ const target = args[0];
232
+ const propertyKey = args[1];
116
233
  const currentMethod = targetBean[methodName];
117
234
  if (currentMethod.length > 0) {
118
235
  routerParamsTotal[[constructorFunction.name, methodName].toString()] = currentMethod.length;
119
236
  }
120
237
  Object.assign(targetBean, {
121
- [methodName]: function (...args) {
122
- const result = currentMethod.apply(targetBean, args);
238
+ [methodName]: function (...innerArgs) {
239
+ const result = currentMethod.apply(targetBean, innerArgs);
123
240
  const afterResult = target[propertyKey](result);
124
241
  return afterResult !== null && afterResult !== void 0 ? afterResult : result;
125
242
  }
@@ -160,6 +277,54 @@ function getParamInFunction(fn, index) {
160
277
  const result = code.slice(code.indexOf('(') + 1, code.indexOf(')')).match(/([^\s,]+)/g);
161
278
  return result[index] || null;
162
279
  }
280
+ /** 解析函数参数名列表(供 route @bind 做「参数名 → 索引」映射) */
281
+ function getParamNames(fn) {
282
+ const code = fn.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '').replace(/=>.*$/mg, '').replace(/=[^,)]+/g, '');
283
+ const paramsStr = code.slice(code.indexOf('(') + 1, code.indexOf(')'));
284
+ if (!paramsStr.trim())
285
+ return [];
286
+ return paramsStr.split(',').map(p => {
287
+ const matched = p.trim().match(/([A-Za-z_$][\w$]*)/);
288
+ return matched ? matched[1] : p.trim();
289
+ }).filter(Boolean);
290
+ }
291
+ /** 把 route @bind 的「来源字符串」转成参数解析器 */
292
+ function getRouteSourceResolver(source, paramName) {
293
+ switch (source) {
294
+ case "req": return (req, res, next) => req;
295
+ case "res": return (req, res, next) => res;
296
+ case "next": return (req, res, next) => next;
297
+ case "reqBody": return (req, res, next) => req.body;
298
+ case "reqParam": return (req, res, next) => req.params[paramName];
299
+ case "reqQuery": return (req, res, next) => req.query[paramName];
300
+ case "reqForm": return (req, res, next) => req.body[paramName];
301
+ default: return null;
302
+ }
303
+ }
304
+ /** 读取 @bind 声明,把「参数名 → 来源」转成 routerParams 的「索引 → 解析器」 */
305
+ function applyRouteBind(className, propertyKey, method) {
306
+ const bindMapping = (0, bind_decorator_1.getBindMapping)(className, propertyKey);
307
+ if (!bindMapping)
308
+ return;
309
+ const paramNames = getParamNames(method);
310
+ const nameToIndex = {};
311
+ paramNames.forEach((paramName, index) => {
312
+ if (paramName && nameToIndex[paramName] === undefined)
313
+ nameToIndex[paramName] = index;
314
+ });
315
+ for (const bindName in bindMapping) {
316
+ const source = bindMapping[bindName];
317
+ if (typeof source !== "string")
318
+ continue; // 跳过 database 的数值映射
319
+ const index = nameToIndex[bindName];
320
+ if (index === undefined)
321
+ continue;
322
+ const resolver = getRouteSourceResolver(source, bindName);
323
+ if (resolver) {
324
+ routerParams[[className, propertyKey, index].toString()] = resolver;
325
+ }
326
+ }
327
+ }
163
328
  function reqQuery(target, propertyKey, parameterIndex) {
164
329
  const key = [target.constructor.name, propertyKey, parameterIndex].toString();
165
330
  const paramName = getParamInFunction(target[propertyKey], parameterIndex);
@@ -5,68 +5,74 @@ import "reflect-metadata";
5
5
 
6
6
  /**设置路由中间件 */
7
7
  declare function setRouter(app: express.Application): void;
8
- /**上传文件装饰器,装饰页面具备解析上传文件的能力 */
9
- declare function upload(target: any, propertyKey: string): void;
8
+ /**上传文件装饰器,装饰页面具备解析上传文件的能力(legacy 方法装饰器;2.5.x 起兼容标准 (value, context) 签名) */
9
+ declare function upload(...args: any[]): any;
10
10
  /**
11
11
  * 页面支持 JWT 鉴权能力
12
12
  * @param jwtConfig jwt 配置
13
13
  */
14
- declare function jwt(jwtConfig: any): (target: any, propertyKey: string) => void;
14
+ declare function jwt(jwtConfig: any): (...args: any[]) => any;
15
15
  /**
16
16
  * GET 请求装饰器
17
17
  * @param value 请求路径
18
18
  */
19
- declare const getMapping: (value: string) => (target: any, propertyKey: string) => void;
19
+ declare const getMapping: (value: string) => (...args: any[]) => any;
20
20
  /**
21
21
  * POST 请求装饰器
22
22
  * @param value 请求路径
23
23
  */
24
- declare const postMapping: (value: string) => (target: any, propertyKey: string) => void;
24
+ declare const postMapping: (value: string) => (...args: any[]) => any;
25
25
  /**
26
26
  * 请求装饰器,不区分请求类型
27
27
  * @param value 请求路径
28
28
  */
29
- declare const requestMapping: (value: string) => (target: any, propertyKey: string) => void;
29
+ declare const requestMapping: (value: string) => (...args: any[]) => any;
30
30
  /**
31
31
  * INSERT 装饰器
32
32
  * 将方法作为 INSERT SQL 使用
33
33
  * @param sql INSERT SQL 语句
34
34
  */
35
- declare function insert(sql: string): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
35
+ declare function insert(sql: string): (...args: any[]) => any;
36
36
  /**
37
37
  * UPDATE 装饰器
38
38
  * 将方法作为 UPDATE SQL 使用
39
39
  * @param sql UPDATE SQL 语句
40
40
  */
41
- declare function update(sql: string): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
41
+ declare function update(sql: string): (...args: any[]) => any;
42
42
  /**
43
43
  * DELETE 装饰器
44
44
  * 将方法作为 DELETE SQL 使用
45
45
  * @param sql DELETE SQL 语句
46
46
  */
47
- declare function remove(sql: string): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
47
+ declare function remove(sql: string): (...args: any[]) => any;
48
48
  /**
49
49
  * SELECT 装饰器
50
50
  * 将方法作为 SELECT SQL 使用
51
51
  * @param sql SELECT SQL 语句
52
52
  */
53
- declare function select(sql: string): (target: any, propertyKey: string, descriptor: PropertyDescriptor) => void;
53
+ declare function select(sql: string): (...args: any[]) => any;
54
54
  /**
55
55
  * SELECT 结果类型装饰器,和 @select 配合使用
56
56
  * @param dataClass 结果类型
57
57
  */
58
- declare function resultType(dataClass: any): (target: any, propertyKey: string) => void;
58
+ declare function resultType(dataClass: any): (...args: any[]) => any;
59
59
  /**
60
60
  * SQL 参数装饰器,标注 SQL 语句的绑定参数值,和 @select @insert @update @remove 配合使用
61
61
  * @param name 参数在 SQL 语句内的标记值
62
62
  */
63
63
  declare function param(name: string): (target: any, propertyKey: string | symbol, parameterIndex: number) => void;
64
+ /**
65
+ * 方法级参数绑定装饰器(标准装饰器删除了参数装饰器后的替代,legacy 模式也可用)。
66
+ * database 场景映射 SQL 占位符 → 参数索引(值为 number);route 场景映射参数名 → 请求来源(值为 string)。
67
+ * @param mapping 绑定声明,如 { name: 0, id: 1 } 或 { id: "reqParam", body: "reqBody" }
68
+ */
69
+ declare function bind(mapping: Record<string, string | number>): (...args: any[]) => any;
64
70
  /**
65
71
  * SELECT 缓存装饰器,自动缓存 SELECT 查询结果,和 @select 配合使用
66
72
  * 当执行 @insert @update @remove 时,会自动清除缓存。
67
73
  * @param ttl 缓存时间,单位秒
68
74
  */
69
- declare function cache(ttl: number): (target: any, propertyKey: string) => void;
75
+ declare function cache(ttl: number): (...args: any[]) => any;
70
76
  /**模型数据操作类 */
71
77
  declare class Model {
72
78
  /**分页数据 */
@@ -139,23 +145,21 @@ declare class Model {
139
145
  *
140
146
  * 被装饰的类将作为应用程序入口,框架将启动该类的 main 方法
141
147
  */
142
- declare function app<T extends {
143
- new(...args: any[]): {};
144
- }>(constructor: T): void;
148
+ declare function app(...args: any[]): any;
145
149
  /**获取配置文件中的配置项 */
146
150
  declare function config(node: string): any;
147
- /**组件装饰器,被装饰的类可以通过 @autoware 取得实例 */
148
- declare function component(constructorFunction: any): void;
151
+ /**组件装饰器,被装饰的类可以通过 @autoware 取得实例(legacy 类装饰器;2.5.x 起兼容标准 (value, context) 签名) */
152
+ declare function component(...args: any[]): any;
149
153
  /**获取组件实例函数,返回结果同 @autoware */
150
154
  declare function getComponent(constructorFunction: any): any;
151
- /**提供对象装饰器,框架将使用 @bean 装饰的方法来获取对象实例 */
152
- declare function bean(target: any, propertyKey: string): void;
155
+ /**提供对象装饰器,框架将使用 @bean 装饰的方法来获取对象实例(legacy 方法装饰器;2.5.x 起兼容标准签名) */
156
+ declare function bean(...args: any[]): any;
153
157
  /**获取对象实例函数,返回结果由 @bean 装饰的方法提供 */
154
158
  declare function getBean(mappingClass: Function): any;
155
159
  /**配置装饰器,装饰类成员变量值,获取配置文件中的配置项 */
156
160
  declare function value(configPath: string): any;
157
161
  /**自动装配装饰器,无参数版本,被装饰的类成员变量将自动注入实例 */
158
- declare function autoware(target: any, propertyKey: string): void;
162
+ declare function autoware(...args: any[]): any;
159
163
  /**自动装配装饰器,带参数版本,可输入参数作为实例初始化参数,被装饰的类成员变量将自动注入实例 */
160
164
  declare function resource(...args: any[]): any;
161
165
  /**日志函数,输出打印日志 */
@@ -165,11 +169,11 @@ declare function logx(message: any): void;
165
169
  /**错误日志函数,输出打印错误日志 */
166
170
  declare function error(message?: any, ...optionalParams: any[]): void;
167
171
  /**路由页面前置执行装饰器,参数指向路由页面方法,被装饰的方法将在路由页面之前执行 */
168
- declare function before(constructorFunction: any, methodName: string): (target: any, propertyKey: string) => void;
172
+ declare function before(constructorFunction: any, methodName: string): (...args: any[]) => any;
169
173
  /**路由页面后置执行装饰器,参数指向路由页面方法,被装饰的方法将在路由页面之后执行 */
170
- declare function after(constructorFunction: any, methodName: string): (target: any, propertyKey: string) => void;
174
+ declare function after(constructorFunction: any, methodName: string): (...args: any[]) => any;
171
175
  /**定时程序装饰器,参数支持 crontab 格式字符串,可根据参数定时执行被装饰的方法 */
172
- declare function schedule(cronTime: string | Date): (target: any, propertyKey: string) => void;
176
+ declare function schedule(cronTime: string | Date): (...args: any[]) => any;
173
177
  /**RabbitMQ 监听装饰器,参数是监听的队列名称,当接受到消息时将执行被装饰方法 */
174
178
  declare function rabbitListener(queue: string): (target: any, propertyKey: string) => void;
175
179
  /**Redis 监听装饰器,参数是监听的队列名称,当接受到消息时将执行被装饰方法 */
@@ -396,4 +400,4 @@ declare class SocketIo {
396
400
  /**Socket IO 服务实现类 */
397
401
  declare const io: IoServer;
398
402
 
399
- export { ExpressServer, LogDefault, NodeCache, RabbitMQ, rabbitListener, redisSubscriber, ReadWriteDb, Redis, CacheFactory, DataSourceFactory, LogFactory, ServerFactory, AuthenticationFactory, next, reqBody, reqQuery, reqForm, reqParam, req, req as request, res, res as response, component, bean, resource, log, logx, app, before, after, value, error, config, autoware, getBean, getComponent, schedule, getMapping, postMapping, requestMapping, setRouter, upload, jwt, insert, update, remove, select, param, resultType, cache, Model, SocketIo, io };
403
+ export { ExpressServer, LogDefault, NodeCache, RabbitMQ, rabbitListener, redisSubscriber, ReadWriteDb, Redis, CacheFactory, DataSourceFactory, LogFactory, ServerFactory, AuthenticationFactory, next, reqBody, reqQuery, reqForm, reqParam, req, req as request, res, res as response, component, bean, resource, log, logx, app, before, after, value, error, config, autoware, getBean, getComponent, schedule, getMapping, postMapping, requestMapping, setRouter, upload, jwt, insert, update, remove, select, param, bind, resultType, cache, Model, SocketIo, io };
package/dist/typespeed.js CHANGED
@@ -19,6 +19,7 @@ require("reflect-metadata");
19
19
  const fs = require("fs");
20
20
  const path = require("path");
21
21
  const walkSync = require("walk-sync");
22
+ const decorator_utils_1 = require("./decorator-utils");
22
23
  let globalConfig = {};
23
24
  const corePath = __dirname;
24
25
  const mainPath = path.dirname(getRootPath(new Error().stack.split("\n")) || process.argv[1]);
@@ -33,7 +34,18 @@ if (fs.existsSync(configFile)) {
33
34
  }
34
35
  globalConfig["MAIN_PATH"] = mainPath;
35
36
  globalConfig["CORE_PATH"] = corePath;
36
- function app(constructor) {
37
+ function app(...args) {
38
+ if ((0, decorator_utils_1.isStd)(args)) {
39
+ const [, ctx] = (0, decorator_utils_1.getStdArgs)(args);
40
+ ctx.addInitializer(function () {
41
+ startApp(this.constructor);
42
+ });
43
+ return;
44
+ }
45
+ startApp(args[0]);
46
+ }
47
+ exports.app = app;
48
+ function startApp(constructor) {
37
49
  const coreFiles = walkSync(corePath, { globs: ['**/*.ts'], ignore: ['**/*.d.ts', 'scaffold/**'] });
38
50
  const mainFiles = walkSync(mainPath, { globs: ['**/*.ts'] });
39
51
  (async function () {
@@ -56,13 +68,28 @@ function app(constructor) {
56
68
  main["main"]();
57
69
  }());
58
70
  }
59
- exports.app = app;
60
71
  function config(node) {
61
72
  return globalConfig[node] || null;
62
73
  }
63
74
  exports.config = config;
64
75
  function value(configPath) {
65
- return function (target, propertyKey) {
76
+ return function (...args) {
77
+ if ((0, decorator_utils_1.isStd)(args)) {
78
+ // 标准 field 装饰器:返回 initializer 注入配置值(标准模式下无 design:type)。
79
+ return (initialValue) => {
80
+ if (globalConfig === undefined) {
81
+ return initialValue;
82
+ }
83
+ let pathNodes = configPath.split(".");
84
+ let nodeValue = globalConfig;
85
+ for (let i = 0; i < pathNodes.length; i++) {
86
+ nodeValue = nodeValue[pathNodes[i]];
87
+ }
88
+ return nodeValue === undefined ? initialValue : nodeValue;
89
+ };
90
+ }
91
+ const target = args[0];
92
+ const propertyKey = args[1];
66
93
  if (globalConfig === undefined) {
67
94
  Object.defineProperty(target, propertyKey, {
68
95
  get: () => {
@@ -86,10 +113,14 @@ function value(configPath) {
86
113
  }
87
114
  exports.value = value;
88
115
  function getRootPath(lines) {
89
- const macths = ["at Function.Module._load", "at Module.require", "at require", "at Object.<anonymous>"];
116
+ // 兼容新旧 Node 栈帧(Node<22: "Function.Module._load" / Node22+: "Function._load")、
117
+ // mocha(ts-node) 下 "Context.<anonymous>" 与中间可能插入的 "wrapModuleLoad" 帧:
118
+ // 按顺序出现匹配(不要求严格相邻),提高在各种加载器下的容错。
119
+ const macths = [/at Function(\.Module)?\._load/, "at Module.require", /at require\b/, /at (Object|Context)\.<anonymous>/];
90
120
  let matchIndex = 0;
91
121
  for (let line of lines) {
92
- if (line.includes(macths[matchIndex])) {
122
+ const matcher = macths[matchIndex];
123
+ if (matcher instanceof RegExp ? matcher.test(line) : line.includes(matcher)) {
93
124
  if (matchIndex === macths.length - 1) {
94
125
  let arr = line.split("(")[1].split(":");
95
126
  arr.pop();
@@ -98,15 +129,13 @@ function getRootPath(lines) {
98
129
  }
99
130
  matchIndex++;
100
131
  }
101
- else {
102
- matchIndex = 0;
103
- }
104
132
  }
105
133
  return undefined;
106
134
  }
107
135
  __exportStar(require("./core.decorator"), exports);
108
136
  __exportStar(require("./route.decorator"), exports);
109
137
  __exportStar(require("./database.decorator"), exports);
138
+ __exportStar(require("./bind.decorator"), exports);
110
139
  var log_factory_class_1 = require("./factory/log-factory.class");
111
140
  Object.defineProperty(exports, "LogFactory", { enumerable: true, get: function () { return log_factory_class_1.default; } });
112
141
  var cache_factory_class_1 = require("./factory/cache-factory.class");
@@ -0,0 +1,116 @@
1
+ "use strict";
2
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
3
+ var useValue = arguments.length > 2;
4
+ for (var i = 0; i < initializers.length; i++) {
5
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
6
+ }
7
+ return useValue ? value : void 0;
8
+ };
9
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
10
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
11
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
12
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
13
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
14
+ var _, done = false;
15
+ for (var i = decorators.length - 1; i >= 0; i--) {
16
+ var context = {};
17
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
18
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
19
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
20
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
21
+ if (kind === "accessor") {
22
+ if (result === void 0) continue;
23
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
24
+ if (_ = accept(result.get)) descriptor.get = _;
25
+ if (_ = accept(result.set)) descriptor.set = _;
26
+ if (_ = accept(result.init)) initializers.unshift(_);
27
+ }
28
+ else if (_ = accept(result)) {
29
+ if (kind === "field") initializers.unshift(_);
30
+ else descriptor[key] = _;
31
+ }
32
+ }
33
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
34
+ done = true;
35
+ };
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ // Symbol.metadata polyfill:Node 22/24/26 都没有 Symbol.metadata,
41
+ // 标准装饰器的 context.metadata 依赖它,缺失会 TypeError,必须最先执行。
42
+ Symbol.metadata ??= Symbol("Symbol.metadata");
43
+ const express_1 = __importDefault(require("express"));
44
+ const typespeed_1 = require("../../../dist/typespeed");
45
+ class CacheBean {
46
+ name = "cache-bean";
47
+ }
48
+ let TestService = (() => {
49
+ let _classDecorators = [typespeed_1.component];
50
+ let _classDescriptor;
51
+ let _classExtraInitializers = [];
52
+ let _classThis;
53
+ let _instanceExtraInitializers = [];
54
+ let _getCache_decorators;
55
+ let _cache_decorators;
56
+ let _cache_initializers = [];
57
+ let _cache_extraInitializers = [];
58
+ let _test_decorators;
59
+ var TestService = class {
60
+ static { _classThis = this; }
61
+ static {
62
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
63
+ _getCache_decorators = [(0, typespeed_1.bean)(CacheBean)];
64
+ _cache_decorators = [(0, typespeed_1.autoware)(CacheBean)];
65
+ _test_decorators = [(0, typespeed_1.getMapping)("/std/test/:id"), (0, typespeed_1.bind)({ id: "reqParam" })];
66
+ __esDecorate(this, null, _getCache_decorators, { kind: "method", name: "getCache", static: false, private: false, access: { has: obj => "getCache" in obj, get: obj => obj.getCache }, metadata: _metadata }, null, _instanceExtraInitializers);
67
+ __esDecorate(this, null, _test_decorators, { kind: "method", name: "test", static: false, private: false, access: { has: obj => "test" in obj, get: obj => obj.test }, metadata: _metadata }, null, _instanceExtraInitializers);
68
+ __esDecorate(null, null, _cache_decorators, { kind: "field", name: "cache", static: false, private: false, access: { has: obj => "cache" in obj, get: obj => obj.cache, set: (obj, value) => { obj.cache = value; } }, metadata: _metadata }, _cache_initializers, _cache_extraInitializers);
69
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
70
+ TestService = _classThis = _classDescriptor.value;
71
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
72
+ __runInitializers(_classThis, _classExtraInitializers);
73
+ }
74
+ getCache() { return new CacheBean(); }
75
+ cache = (__runInitializers(this, _instanceExtraInitializers), __runInitializers(this, _cache_initializers, void 0));
76
+ // 标准模式:无参数装饰器,@bind 声明「参数名 → 来源」
77
+ async test(id) {
78
+ return { id, cache: this.cache.name };
79
+ }
80
+ constructor() {
81
+ __runInitializers(this, _cache_extraInitializers);
82
+ }
83
+ };
84
+ return TestService = _classThis;
85
+ })();
86
+ // 验证 1:@component / @autoware / @bean
87
+ const svc = (0, typespeed_1.getComponent)(TestService);
88
+ console.log("[component] registered:", svc !== undefined);
89
+ console.log("[autoware(CacheBean)] injected:", svc && svc.cache?.name);
90
+ console.log("[bean(CacheBean)] factory:", (0, typespeed_1.getBean)(CacheBean)?.name);
91
+ // 验证 2:@getMapping + @bind 路由,走 setRouter 真实 HTTP 请求
92
+ const app = (0, express_1.default)();
93
+ (0, typespeed_1.setRouter)(app);
94
+ const server = app.listen(0, () => {
95
+ const addr = server.address();
96
+ const port = addr.port;
97
+ httpGet(`http://127.0.0.1:${port}/std/test/123`, (body) => {
98
+ console.log("[route @bind] response:", body);
99
+ const parsed = JSON.parse(body);
100
+ const ok = svc !== undefined
101
+ && svc.cache?.name === "cache-bean"
102
+ && (0, typespeed_1.getBean)(CacheBean)?.name === "cache-bean"
103
+ && parsed.id === "123"
104
+ && parsed.cache === "cache-bean";
105
+ console.log(ok ? "STANDARD DECORATORS OK" : "STANDARD DECORATORS FAILED");
106
+ server.close();
107
+ process.exit(ok ? 0 : 1);
108
+ });
109
+ });
110
+ function httpGet(url, cb) {
111
+ require("http").get(url, (res) => {
112
+ let data = "";
113
+ res.on("data", (chunk) => { data += chunk; });
114
+ res.on("end", () => cb(data));
115
+ });
116
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "name": "typespeed-example-std",
3
+ "version": "1.0.0",
4
+ "private": true,
5
+ "description": "typespeed 标准装饰器(TC39 Stage 2.7)示例:experimentalDecorators: false + Symbol.metadata polyfill",
6
+ "scripts": {
7
+ "build": "tsc -p .",
8
+ "start": "node dist/main.js"
9
+ },
10
+ "devDependencies": {
11
+ "typescript": "^5.9.3",
12
+ "@types/node": "^18.19.3"
13
+ }
14
+ }