typespeed 2.5.1 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -0
- package/README.en.md +169 -0
- package/README.md +123 -37
- package/dist/bind.decorator.js +2 -3
- package/dist/core.decorator.js +10 -11
- package/dist/database.decorator.js +8 -8
- package/dist/decorator-utils.js +2 -3
- package/dist/default/default-authentication.class.js +1 -1
- package/dist/default/express-server.class.js +1 -1
- package/dist/default/log-default.class.js +1 -1
- package/dist/default/node-cache.class.js +1 -1
- package/dist/default/rabbitmq.class.js +3 -3
- package/dist/default/read-write-db.class.js +1 -1
- package/dist/default/redis.class.js +3 -3
- package/dist/route.decorator.js +15 -15
- package/dist/typespeed.js +6 -7
- package/package.json +8 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
|
|
3
3
|
typespeed 版本演进记录。本文件 2026-09-06 从 git 历史反推建立;git 最早提交 2022-09-18(ch01)。
|
|
4
4
|
|
|
5
|
+
## 2.6.x
|
|
6
|
+
|
|
7
|
+
- **2.6.1**:Node/TS 升级——TypeScript 4.9 → 5.9.3(legacy 装饰器零改动兼容,标准装饰器双轨同步验证);`@types/node` 对齐 22;声明 `engines`(node >=18)(2026-09-07)
|
|
8
|
+
|
|
5
9
|
## 2.5.x
|
|
6
10
|
|
|
11
|
+
- **2.5.2**:README 重写(专业丰富版:30+ 装饰器分类、书籍体系突出)+ 新增英文版 `README.en.md`(中英切换,默认中文)(2026-09-07)
|
|
7
12
|
- **2.5.1**:补全 `default/` 族装饰器双签名(`rabbitListener` / `redisSubscriber` / `SocketIo.onEvent`/`onError`/`onDisconnect`/`onConnected`);打包瘦身(`files` 白名单 108→31 文件);`npm pkg fix` 修正 bin 字段;修正 `redisSubscriber` 的 d.ts 签名(2026-09-07)
|
|
8
13
|
- **2.5.0**:装饰器双轨——支持 TC39 标准装饰器(Stage 2.7),legacy 装饰器零破坏。单份源码运行时双签名感知(`isStd` 判据),覆盖 core/route/database 三族 + 入口 `app`/`value`;新增方法级 `@bind` 装饰器(route 参数名→来源、database 占位符→索引,替代标准模式删除的参数装饰器);`@autoware`/`@resource`/`@bean` 支持显式 token(标准模式无 `design:type`);类型声明宽松化;新增标准模式示例 `introduction/decorator-next/` + `isStd` 单测(2026-09-07)
|
|
9
14
|
|
package/README.en.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">TypeSpeed</h1>
|
|
3
|
+
<p align="center">A decorator-driven TypeScript web framework — build web services declaratively with decorators</p>
|
|
4
|
+
</p>
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="README.md">简体中文</a> · <b>English</b>
|
|
8
|
+
</p>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/typespeed"><img src="https://badgen.net/npm/v/typespeed?color=cyan" alt="npm version"></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/typespeed"><img src="https://badgen.net/npm/dt/typespeed?color=pink" alt="npm downloads"></a>
|
|
13
|
+
<a href="https://github.com/speedphp/typespeed/blob/main/LICENSE"><img src="https://badgen.net/github/license/speedphp/typespeed" alt="license"></a>
|
|
14
|
+
<a href="https://github.com/speedphp/typespeed/actions"><img src="https://img.shields.io/github/actions/workflow/status/speedphp/typespeed/test.yml?label=CI" alt="build"></a>
|
|
15
|
+
<a href="https://badgen.net/badge/icon/TypeScript?icon=typescript&label"><img src="https://badgen.net/badge/icon/TypeScript?icon=typescript&label" alt="TypeScript"></a>
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
TypeSpeed is a **web framework written in TypeScript**, built on top of [Express](https://expressjs.com/). It organizes your application declaratively through **decorators** — dependency injection, routing, database, caching, authentication, and message queues are all declared with decorators, with zero configuration to start.
|
|
21
|
+
|
|
22
|
+
> 📖 The companion book **《TypeScript 框架开发实践(微课视频版)》(TypeScript Framework Development in Practice, Tsinghua University Press)** systematically explains the design and implementation of this framework, taking you from zero to building a framework.
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## ✨ Features
|
|
27
|
+
|
|
28
|
+
### 🎯 Decorator-Driven
|
|
29
|
+
Provides **30+ decorators** covering the full spectrum of web development — object management, web routing, parameter binding, database operations, caching, authentication, message queues, and sockets. One annotation, one feature:
|
|
30
|
+
|
|
31
|
+
| Category | Decorators | Description |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| **Object management** | `@component` `@bean` `@autoware` `@resource` | Component registration & dependency injection |
|
|
34
|
+
| **Web routing** | `@getMapping` `@postMapping` `@requestMapping` | REST route declaration |
|
|
35
|
+
| **Route parameters** | `@req` `@res` `@next` `@reqBody` `@reqParam` `@reqQuery` `@reqForm` | Request parameter injection |
|
|
36
|
+
| **AOP** | `@before` `@after` | Before / after interception |
|
|
37
|
+
| **Database** | `@insert` `@update` `@remove` `@select` `@param` `@resultType` `@cache` | Declarative SQL operations |
|
|
38
|
+
| **Security / upload** | `@jwt` `@upload` | JWT authentication, file upload |
|
|
39
|
+
| **Scheduling / config** | `@schedule` `@value` `@config` | Scheduled tasks, config injection |
|
|
40
|
+
| **Messaging / cache** | `@rabbitListener` `@redisSubscriber` | MQ listener, Redis subscriber |
|
|
41
|
+
| **Socket.IO** | `@SocketIo.onEvent` `@onConnected` `@onDisconnect` `@onError` | Real-time communication events |
|
|
42
|
+
| **Parameter binding** (2.5+) | `@bind` | Method-level parameter binding under standard decorators |
|
|
43
|
+
|
|
44
|
+
### 🧩 Core Mechanisms
|
|
45
|
+
- **Dependency Injection (DI)**: `@autoware` / `@resource` auto-inject instances, `@bean` provides factory methods, with explicit token support (standard decorator mode)
|
|
46
|
+
- **AOP**: `@before` / `@after` intercept methods non-invasively
|
|
47
|
+
- **Middleware**: pluggable middleware chain + global authentication (`AuthenticationFactory`)
|
|
48
|
+
- **Startup scanning**: automatically scans core and application modules, zero-config startup
|
|
49
|
+
|
|
50
|
+
### 🗄️ Database (two styles)
|
|
51
|
+
- **Decorator style**: `@select("SQL")` + `@param` / `@resultType` / `@cache` — declarative SQL execution, result type mapping, automatic caching
|
|
52
|
+
- **Model ORM style**: extend `Model` — `findAll` / `find` / `create` / `update` / `delete` / `findCount` / `incr` / `decr` / `pager`, chainable queries, condition building, pagination
|
|
53
|
+
|
|
54
|
+
### 🔌 Built-in Components
|
|
55
|
+
- **Cache**: `NodeCache` (in-memory) + Redis (extensible via `CacheFactory`)
|
|
56
|
+
- **Message queue**: RabbitMQ wrapper (`RabbitMQ` / `@rabbitListener`)
|
|
57
|
+
- **Redis**: connection management + `@redisSubscriber` + leaderboards (`zranking` / `zrevranking`)
|
|
58
|
+
- **Socket.IO**: event decorators + rooms + connection management
|
|
59
|
+
- **Session / static / templates / upload**: session (Redis store), static assets, multi template engines (consolidate), file upload
|
|
60
|
+
|
|
61
|
+
### 🚀 Standard Decorator Dual-Track (2.5+)
|
|
62
|
+
Supports both **legacy decorators** (`experimentalDecorators: true`, the book's style) and **TC39 standard decorators** (Stage 2.7, `experimentalDecorators: false`), auto-detected at runtime from a single codebase — legacy code works unchanged.
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 📦 Quick Start
|
|
67
|
+
|
|
68
|
+
**Requirements**: Node.js 16+ (18/20/22 recommended), TypeScript.
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# 1. Install the CLI globally
|
|
72
|
+
npm install typespeed -g
|
|
73
|
+
|
|
74
|
+
# 2. Create a project (zero config)
|
|
75
|
+
typespeed new blog
|
|
76
|
+
cd blog
|
|
77
|
+
|
|
78
|
+
# 3. Install dependencies and start
|
|
79
|
+
npm install
|
|
80
|
+
npm run start
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## 📝 Example
|
|
86
|
+
|
|
87
|
+
A minimal example combining component, routing, database, and caching:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import { component, app, autoware, getMapping, insert, select, resultType, cache, CacheFactory, ServerFactory } from "typespeed";
|
|
91
|
+
|
|
92
|
+
// Component (service)
|
|
93
|
+
@component
|
|
94
|
+
class UserService {
|
|
95
|
+
|
|
96
|
+
// Dependency injection
|
|
97
|
+
@autoware
|
|
98
|
+
private cacheBean: CacheFactory;
|
|
99
|
+
|
|
100
|
+
// Route + parameter injection
|
|
101
|
+
@getMapping("/user/:id")
|
|
102
|
+
async getUser(@reqParam id: number, @res res) {
|
|
103
|
+
res.json({ id, name: "typespeed" });
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Database: declarative SQL
|
|
107
|
+
@insert("Insert into `user` (id, name) values (#{id}, #{name})")
|
|
108
|
+
async addUser(@param("id") id: number, @param("name") name: string) {}
|
|
109
|
+
|
|
110
|
+
// Query + result type mapping + caching
|
|
111
|
+
@cache(1800)
|
|
112
|
+
@select("Select * from `user` where id = #{id}")
|
|
113
|
+
@resultType(UserDto)
|
|
114
|
+
async findUser(@param("id") id: number): Promise<UserDto[]> { return; }
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Application entry: @app auto-starts main()
|
|
118
|
+
@app
|
|
119
|
+
class Main {
|
|
120
|
+
@autoware
|
|
121
|
+
private server: ServerFactory;
|
|
122
|
+
|
|
123
|
+
main() {
|
|
124
|
+
this.server.start(8081);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
> See the [`app/`](https://github.com/speedphp/typespeed/tree/main/app) directory and the book's companion source for more complete examples.
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 📚 Learning Resources
|
|
134
|
+
|
|
135
|
+
TypeSpeed is not just a framework — it comes with a complete **"book + video + dual source code" learning system**:
|
|
136
|
+
|
|
137
|
+
| Resource | Description | Link |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| 📖 **Book** | 《TypeScript 框架开发实践(微课视频版)》by 曾振中, Tsinghua University Press | [JD.com](https://item.jd.com/14275373.html) |
|
|
140
|
+
| 🎬 **Video course** | Accompanying micro-lecture videos, one source snapshot per lesson | Bundled with the book |
|
|
141
|
+
| 📂 **Book source · ts-book** | Organized by chapter (chapter01~chapter06), runnable examples per chapter | [github.com/speedphp/ts-book](https://github.com/speedphp/ts-book) |
|
|
142
|
+
| 🏷️ **Video code · ts-practice** | Tagged by book section number (e.g. `4.10.4` = Chapter 4, Section 10, Step 4), one runnable snapshot per lesson | [github.com/speedphp/ts-practice](https://github.com/speedphp/ts-practice) |
|
|
143
|
+
|
|
144
|
+
> To learn the framework's design and implementation systematically, start with the book + ts-book; to follow along hands-on, use ts-practice.
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 🗺️ Roadmap
|
|
149
|
+
|
|
150
|
+
| Version | Content | Status |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| 2.4.x | Documentation revival, CI modernization, all tests green | ✅ Released |
|
|
153
|
+
| 2.5.x | **Standard decorator dual-track** (TC39 Stage 2.7) + `@bind` + explicit token | ✅ Released (latest) |
|
|
154
|
+
| 2.6.x | Node/TS upgrade + health checks + graceful shutdown + Docker/k8s manifests | 🚧 In progress |
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
## 🤝 Contributing
|
|
159
|
+
|
|
160
|
+
Issues and pull requests are welcome. Development and testing:
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npm run build # compile
|
|
164
|
+
npm test # test (requires MySQL / Redis / RabbitMQ)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## 📄 License
|
|
168
|
+
|
|
169
|
+
[MIT](LICENSE) © [speedphp](https://github.com/speedphp)
|
package/README.md
CHANGED
|
@@ -1,83 +1,169 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<h1 align="center">TypeSpeed</h1>
|
|
3
|
+
<p align="center">一个装饰器驱动的 TypeScript Web 框架 —— 用声明式装饰器,快速构建 Web 服务</p>
|
|
4
|
+
</p>
|
|
2
5
|
|
|
6
|
+
<p align="center">
|
|
7
|
+
<b>简体中文</b> · <a href="README.en.md">English</a>
|
|
8
|
+
</p>
|
|
3
9
|
|
|
10
|
+
<p align="center">
|
|
11
|
+
<a href="https://www.npmjs.com/package/typespeed"><img src="https://badgen.net/npm/v/typespeed?color=cyan" alt="npm version"></a>
|
|
12
|
+
<a href="https://www.npmjs.com/package/typespeed"><img src="https://badgen.net/npm/dt/typespeed?color=pink" alt="npm downloads"></a>
|
|
13
|
+
<a href="https://github.com/speedphp/typespeed/blob/main/LICENSE"><img src="https://badgen.net/github/license/speedphp/typespeed" alt="license"></a>
|
|
14
|
+
<a href="https://github.com/speedphp/typespeed/actions"><img src="https://img.shields.io/github/actions/workflow/status/speedphp/typespeed/test.yml?label=CI" alt="build"></a>
|
|
15
|
+
<a href="https://badgen.net/badge/icon/TypeScript?icon=typescript&label"><img src="https://badgen.net/badge/icon/TypeScript?icon=typescript&label" alt="TypeScript"></a>
|
|
16
|
+
</p>
|
|
4
17
|
|
|
5
|
-
|
|
18
|
+
---
|
|
6
19
|
|
|
20
|
+
TypeSpeed 是一个 **TypeScript 编写的 Web 框架**,底层基于 [Express](https://expressjs.com/),通过**装饰器**以声明式的方式组织你的应用——依赖注入、路由、数据库、缓存、鉴权、消息队列,全部用装饰器声明,零配置启动。
|
|
7
21
|
|
|
22
|
+
> 📖 配套图书 **《TypeScript 框架开发实践(微课视频版)》**(曾振中 著,清华大学出版社)系统讲解本框架的设计与实现,从零带你写出一个框架。
|
|
8
23
|
|
|
9
|
-
|
|
24
|
+
---
|
|
10
25
|
|
|
26
|
+
## ✨ 特性
|
|
11
27
|
|
|
28
|
+
### 🎯 装饰器驱动
|
|
29
|
+
提供 **30+ 个装饰器**,覆盖 Web 开发全流程——对象管理、Web 路由、参数绑定、数据库操作、缓存、鉴权、消息队列、Socket,一个注解搞定一个功能:
|
|
12
30
|
|
|
13
|
-
|
|
31
|
+
| 分类 | 装饰器 | 说明 |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| **对象管理** | `@component` `@bean` `@autoware` `@resource` | 组件注册与依赖注入 |
|
|
34
|
+
| **Web 路由** | `@getMapping` `@postMapping` `@requestMapping` | REST 路由声明 |
|
|
35
|
+
| **路由参数** | `@req` `@res` `@next` `@reqBody` `@reqParam` `@reqQuery` `@reqForm` | 请求参数注入 |
|
|
36
|
+
| **切面 AOP** | `@before` `@after` | 前置 / 后置拦截 |
|
|
37
|
+
| **数据库** | `@insert` `@update` `@remove` `@select` `@param` `@resultType` `@cache` | SQL 声明式操作 |
|
|
38
|
+
| **安全 / 上传** | `@jwt` `@upload` | JWT 鉴权、文件上传 |
|
|
39
|
+
| **定时 / 配置** | `@schedule` `@value` `@config` | 定时任务、配置注入 |
|
|
40
|
+
| **消息 / 缓存** | `@rabbitListener` `@redisSubscriber` | MQ 监听、Redis 订阅 |
|
|
41
|
+
| **Socket.IO** | `@SocketIo.onEvent` `@onConnected` `@onDisconnect` `@onError` | 实时通信事件 |
|
|
42
|
+
| **参数绑定**(2.5+) | `@bind` | 标准装饰器下的方法级参数绑定 |
|
|
14
43
|
|
|
44
|
+
### 🧩 核心机制
|
|
45
|
+
- **依赖注入(DI)**:`@autoware` / `@resource` 自动注入实例,`@bean` 提供工厂方法,支持显式 token(标准装饰器模式)
|
|
46
|
+
- **AOP 切面**:`@before` / `@after` 无侵入拦截方法
|
|
47
|
+
- **中间件**:可插拔中间件链 + 全局认证(`AuthenticationFactory`)
|
|
48
|
+
- **启动扫描**:自动扫描核心模块与应用模块,零配置启动
|
|
15
49
|
|
|
50
|
+
### 🗄️ 数据库(两种风格)
|
|
51
|
+
- **装饰器风格**:`@select("SQL")` + `@param` / `@resultType` / `@cache`,SQL 声明式执行、结果类型映射、自动缓存
|
|
52
|
+
- **Model ORM 风格**:继承 `Model`,`findAll` / `find` / `create` / `update` / `delete` / `findCount` / `incr` / `decr` / `pager`,链式查询、条件构建、分页
|
|
16
53
|
|
|
17
|
-
|
|
54
|
+
### 🔌 内置组件
|
|
55
|
+
- **缓存**:`NodeCache`(内存)+ Redis(`CacheFactory` 可扩展)
|
|
56
|
+
- **消息队列**:RabbitMQ 封装(`RabbitMQ` / `@rabbitListener`)
|
|
57
|
+
- **Redis**:连接管理 + `@redisSubscriber` 订阅 + 排行榜(`zranking` / `zrevranking`)
|
|
58
|
+
- **Socket.IO**:事件装饰器 + 房间 + 连接管理
|
|
59
|
+
- **会话 / 静态 / 模板 / 上传**:session(Redis 存储)、静态资源、多模板引擎(consolidate)、文件上传
|
|
18
60
|
|
|
61
|
+
### 🚀 标准装饰器双轨(2.5+)
|
|
62
|
+
同时支持 **legacy 装饰器**(`experimentalDecorators: true`,书中写法)与 **TC39 标准装饰器**(Stage 2.7,`experimentalDecorators: false`),单份源码运行时自动识别,旧代码零改动。
|
|
19
63
|
|
|
64
|
+
---
|
|
20
65
|
|
|
21
|
-
|
|
66
|
+
## 📦 快速开始
|
|
22
67
|
|
|
68
|
+
**环境要求**:Node.js 16+(推荐 18/20/22),TypeScript。
|
|
23
69
|
|
|
70
|
+
```bash
|
|
71
|
+
# 1. 全局安装脚手架
|
|
72
|
+
npm install typespeed -g
|
|
24
73
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
TypeSpeed 不只提供一个框架,还配有完整的「书 + 视频 + 双源码」学习资料:
|
|
30
|
-
|
|
31
|
-
|
|
74
|
+
# 2. 创建项目(零配置)
|
|
75
|
+
typespeed new blog
|
|
76
|
+
cd blog
|
|
32
77
|
|
|
33
|
-
|
|
78
|
+
# 3. 安装依赖并启动
|
|
79
|
+
npm install
|
|
80
|
+
npm run start
|
|
81
|
+
```
|
|
34
82
|
|
|
35
|
-
|
|
83
|
+
---
|
|
36
84
|
|
|
37
|
-
|
|
85
|
+
## 📝 示例
|
|
38
86
|
|
|
39
|
-
|
|
87
|
+
一个组件 + 路由 + 数据库 + 缓存的最小示例:
|
|
40
88
|
|
|
41
|
-
|
|
89
|
+
```typescript
|
|
90
|
+
import { component, app, autoware, getMapping, insert, select, resultType, cache, CacheFactory, ServerFactory } from "typespeed";
|
|
42
91
|
|
|
92
|
+
// 组件(服务)
|
|
93
|
+
@component
|
|
94
|
+
class UserService {
|
|
43
95
|
|
|
96
|
+
// 依赖注入
|
|
97
|
+
@autoware
|
|
98
|
+
private cacheBean: CacheFactory;
|
|
44
99
|
|
|
45
|
-
|
|
100
|
+
// 路由 + 参数注入
|
|
101
|
+
@getMapping("/user/:id")
|
|
102
|
+
async getUser(@reqParam id: number, @res res) {
|
|
103
|
+
res.json({ id, name: "typespeed" });
|
|
104
|
+
}
|
|
46
105
|
|
|
47
|
-
|
|
106
|
+
// 数据库:声明式 SQL
|
|
107
|
+
@insert("Insert into `user` (id, name) values (#{id}, #{name})")
|
|
108
|
+
async addUser(@param("id") id: number, @param("name") name: string) {}
|
|
48
109
|
|
|
49
|
-
|
|
110
|
+
// 查询 + 结果类型映射 + 缓存
|
|
111
|
+
@cache(1800)
|
|
112
|
+
@select("Select * from `user` where id = #{id}")
|
|
113
|
+
@resultType(UserDto)
|
|
114
|
+
async findUser(@param("id") id: number): Promise<UserDto[]> { return; }
|
|
115
|
+
}
|
|
50
116
|
|
|
51
|
-
|
|
117
|
+
// 应用入口:@app 自动启动 main()
|
|
118
|
+
@app
|
|
119
|
+
class Main {
|
|
120
|
+
@autoware
|
|
121
|
+
private server: ServerFactory;
|
|
52
122
|
|
|
53
|
-
|
|
123
|
+
main() {
|
|
124
|
+
this.server.start(8081);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
```
|
|
54
128
|
|
|
55
|
-
|
|
129
|
+
> 更多完整示例见仓库 [`app/`](https://github.com/speedphp/typespeed/tree/main/app) 目录与随书源码。
|
|
56
130
|
|
|
57
|
-
|
|
131
|
+
---
|
|
58
132
|
|
|
59
|
-
|
|
133
|
+
## 📚 学习资料体系
|
|
60
134
|
|
|
135
|
+
TypeSpeed 不只是一个框架,还配有**完整的「书 + 视频 + 双源码」学习体系**:
|
|
61
136
|
|
|
137
|
+
| 资料 | 说明 | 链接 |
|
|
138
|
+
|---|---|---|
|
|
139
|
+
| 📖 **图书** | 《TypeScript 框架开发实践(微课视频版)》曾振中 著,清华大学出版社 | [京东购买](https://item.jd.com/14275373.html) |
|
|
140
|
+
| 🎬 **视频课程** | 随书微课视频,每节配套源码 | 随书附带 |
|
|
141
|
+
| 📂 **附书源码 ts-book** | 按章组织(chapter01~chapter06),每章可运行示例 | [github.com/speedphp/ts-book](https://github.com/speedphp/ts-book) |
|
|
142
|
+
| 🏷️ **视频代码 ts-practice** | 按书籍章节号打 tag(如 `4.10.4` = 第 4 章第 10 节第 4 步),每节对应可跑源码快照 | [github.com/speedphp/ts-practice](https://github.com/speedphp/ts-practice) |
|
|
62
143
|
|
|
63
|
-
|
|
64
|
-
npm install typespeed -g
|
|
65
|
-
```
|
|
144
|
+
> 想系统学习框架原理与实现,从图书 + ts-book 入手;想跟随视频动手,用 ts-practice。
|
|
66
145
|
|
|
67
|
-
|
|
146
|
+
---
|
|
68
147
|
|
|
148
|
+
## 🗺️ 版本路线图
|
|
69
149
|
|
|
150
|
+
| 版本 | 内容 | 状态 |
|
|
151
|
+
|---|---|---|
|
|
152
|
+
| 2.4.x | 文档复活、CI 现代化、测试全绿 | ✅ 已发布 |
|
|
153
|
+
| 2.5.x | **标准装饰器双轨**(TC39 Stage 2.7)+ `@bind` + 显式 token | ✅ 已发布(latest) |
|
|
154
|
+
| 2.6.x | Node/TS 升级 + 健康检查 + 优雅停机 + Docker/k8s 部署清单 | 🚧 进行中 |
|
|
70
155
|
|
|
71
|
-
|
|
72
|
-
typespeed new blog
|
|
156
|
+
---
|
|
73
157
|
|
|
74
|
-
|
|
158
|
+
## 🤝 参与贡献
|
|
75
159
|
|
|
76
|
-
|
|
160
|
+
欢迎提交 Issue 与 Pull Request。开发与测试:
|
|
77
161
|
|
|
78
|
-
|
|
162
|
+
```bash
|
|
163
|
+
npm run build # 编译
|
|
164
|
+
npm test # 测试(需 MySQL / Redis / RabbitMQ)
|
|
79
165
|
```
|
|
80
166
|
|
|
81
|
-
|
|
167
|
+
## 📄 开源协议
|
|
82
168
|
|
|
83
|
-
[MIT](LICENSE) © speedphp
|
|
169
|
+
[MIT](LICENSE) © [speedphp](https://github.com/speedphp)
|
package/dist/bind.decorator.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.bind = bind;
|
|
4
|
+
exports.getBindMapping = getBindMapping;
|
|
4
5
|
const decorator_utils_1 = require("./decorator-utils");
|
|
5
6
|
/**
|
|
6
7
|
* 方法级参数绑定注册表:key = `[className, methodName]`,value = 绑定声明。
|
|
@@ -42,9 +43,7 @@ function bind(mapping) {
|
|
|
42
43
|
bindParamMap.set([target.constructor.name, propertyKey].toString(), mapping);
|
|
43
44
|
};
|
|
44
45
|
}
|
|
45
|
-
exports.bind = bind;
|
|
46
46
|
/** 读取某方法上的 @bind 声明(route/database 内部使用) */
|
|
47
47
|
function getBindMapping(className, methodName) {
|
|
48
48
|
return bindParamMap.get([className, methodName].toString());
|
|
49
49
|
}
|
|
50
|
-
exports.getBindMapping = getBindMapping;
|
package/dist/core.decorator.js
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.component = component;
|
|
4
|
+
exports.bean = bean;
|
|
5
|
+
exports.resource = resource;
|
|
6
|
+
exports.log = log;
|
|
7
|
+
exports.logx = logx;
|
|
8
|
+
exports.error = error;
|
|
9
|
+
exports.autoware = autoware;
|
|
10
|
+
exports.getBean = getBean;
|
|
11
|
+
exports.getComponent = getComponent;
|
|
12
|
+
exports.schedule = schedule;
|
|
4
13
|
require("reflect-metadata");
|
|
5
14
|
const cron = require("cron");
|
|
6
15
|
const log_factory_class_1 = require("./factory/log-factory.class");
|
|
@@ -19,11 +28,9 @@ function component(...args) {
|
|
|
19
28
|
const constructorFunction = args[0];
|
|
20
29
|
objectMapper.set(constructorFunction.name, new constructorFunction());
|
|
21
30
|
}
|
|
22
|
-
exports.component = component;
|
|
23
31
|
function getComponent(constructorFunction) {
|
|
24
32
|
return objectMapper.get(constructorFunction.name);
|
|
25
33
|
}
|
|
26
|
-
exports.getComponent = getComponent;
|
|
27
34
|
function bean(...args) {
|
|
28
35
|
if (args.length >= 2) {
|
|
29
36
|
// 直接装饰器形式:@bean(无 token,走 legacy design:returntype)
|
|
@@ -32,7 +39,6 @@ function bean(...args) {
|
|
|
32
39
|
// 工厂形式:@bean(Token)(显式返回类型 token,标准模式必需)
|
|
33
40
|
return beanWithToken(args[0]);
|
|
34
41
|
}
|
|
35
|
-
exports.bean = bean;
|
|
36
42
|
function beanWithToken(token) {
|
|
37
43
|
return function (...args) {
|
|
38
44
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -59,7 +65,6 @@ function getBean(mappingClass) {
|
|
|
59
65
|
const bean = beanMapper.get(mappingClass.name);
|
|
60
66
|
return bean["factory"];
|
|
61
67
|
}
|
|
62
|
-
exports.getBean = getBean;
|
|
63
68
|
function autoware(...args) {
|
|
64
69
|
if (args.length >= 2) {
|
|
65
70
|
// 直接装饰器形式:@autoware(无 token,走 legacy design:type)
|
|
@@ -68,7 +73,6 @@ function autoware(...args) {
|
|
|
68
73
|
// 工厂形式:@autoware(Token)(显式 token,标准模式必需)
|
|
69
74
|
return autowareWithToken(args[0]);
|
|
70
75
|
}
|
|
71
|
-
exports.autoware = autoware;
|
|
72
76
|
function autowareWithToken(token) {
|
|
73
77
|
return function (...args) {
|
|
74
78
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -138,7 +142,6 @@ function resource(...args) {
|
|
|
138
142
|
});
|
|
139
143
|
};
|
|
140
144
|
}
|
|
141
|
-
exports.resource = resource;
|
|
142
145
|
function log(message, ...optionalParams) {
|
|
143
146
|
const logObject = beanMapper.get(log_factory_class_1.default.name);
|
|
144
147
|
if (logObject) {
|
|
@@ -148,7 +151,6 @@ function log(message, ...optionalParams) {
|
|
|
148
151
|
console.log(message, ...optionalParams);
|
|
149
152
|
}
|
|
150
153
|
}
|
|
151
|
-
exports.log = log;
|
|
152
154
|
function logx(message) {
|
|
153
155
|
message = JSON.stringify(message);
|
|
154
156
|
const logObject = beanMapper.get(log_factory_class_1.default.name);
|
|
@@ -159,7 +161,6 @@ function logx(message) {
|
|
|
159
161
|
console.log(message);
|
|
160
162
|
}
|
|
161
163
|
}
|
|
162
|
-
exports.logx = logx;
|
|
163
164
|
function error(message, ...optionalParams) {
|
|
164
165
|
const logObject = beanMapper.get(log_factory_class_1.default.name);
|
|
165
166
|
if (logObject) {
|
|
@@ -169,7 +170,6 @@ function error(message, ...optionalParams) {
|
|
|
169
170
|
console.error(message, ...optionalParams);
|
|
170
171
|
}
|
|
171
172
|
}
|
|
172
|
-
exports.error = error;
|
|
173
173
|
function schedule(cronTime) {
|
|
174
174
|
return (...args) => {
|
|
175
175
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -184,4 +184,3 @@ function schedule(cronTime) {
|
|
|
184
184
|
new cron.CronJob(cronTime, target[propertyKey]).start();
|
|
185
185
|
};
|
|
186
186
|
}
|
|
187
|
-
exports.schedule = schedule;
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Model =
|
|
3
|
+
exports.Model = void 0;
|
|
4
|
+
exports.insert = insert;
|
|
5
|
+
exports.update = update;
|
|
6
|
+
exports.remove = remove;
|
|
7
|
+
exports.select = select;
|
|
8
|
+
exports.param = param;
|
|
9
|
+
exports.resultType = resultType;
|
|
10
|
+
exports.cache = cache;
|
|
4
11
|
const core_decorator_1 = require("./core.decorator");
|
|
5
12
|
const decorator_utils_1 = require("./decorator-utils");
|
|
6
13
|
const bind_decorator_1 = require("./bind.decorator");
|
|
@@ -38,7 +45,6 @@ function insert(sql) {
|
|
|
38
45
|
};
|
|
39
46
|
};
|
|
40
47
|
}
|
|
41
|
-
exports.insert = insert;
|
|
42
48
|
function update(sql) {
|
|
43
49
|
return (...args) => {
|
|
44
50
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -66,7 +72,6 @@ function update(sql) {
|
|
|
66
72
|
};
|
|
67
73
|
};
|
|
68
74
|
}
|
|
69
|
-
exports.update = update;
|
|
70
75
|
function remove(sql) {
|
|
71
76
|
return (...args) => {
|
|
72
77
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -94,7 +99,6 @@ function remove(sql) {
|
|
|
94
99
|
};
|
|
95
100
|
};
|
|
96
101
|
}
|
|
97
|
-
exports.remove = remove;
|
|
98
102
|
function select(sql) {
|
|
99
103
|
return (...args) => {
|
|
100
104
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -144,7 +148,6 @@ function select(sql) {
|
|
|
144
148
|
};
|
|
145
149
|
};
|
|
146
150
|
}
|
|
147
|
-
exports.select = select;
|
|
148
151
|
function resultType(dataClass) {
|
|
149
152
|
return function (...args) {
|
|
150
153
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -160,7 +163,6 @@ function resultType(dataClass) {
|
|
|
160
163
|
//never return
|
|
161
164
|
};
|
|
162
165
|
}
|
|
163
|
-
exports.resultType = resultType;
|
|
164
166
|
function param(name) {
|
|
165
167
|
return function (target, propertyKey, parameterIndex) {
|
|
166
168
|
const existingParameters = Reflect.getOwnMetadata(paramMetadataKey, target, propertyKey) || [];
|
|
@@ -168,7 +170,6 @@ function param(name) {
|
|
|
168
170
|
Reflect.defineMetadata(paramMetadataKey, existingParameters, target, propertyKey);
|
|
169
171
|
};
|
|
170
172
|
}
|
|
171
|
-
exports.param = param;
|
|
172
173
|
async function queryForExecute(sql, args, target, propertyKey) {
|
|
173
174
|
const [newSql, sqlValues] = convertSQLParams(sql, target, propertyKey, args);
|
|
174
175
|
return actionExecute(newSql, sqlValues);
|
|
@@ -255,7 +256,6 @@ function cache(ttl) {
|
|
|
255
256
|
}
|
|
256
257
|
};
|
|
257
258
|
}
|
|
258
|
-
exports.cache = cache;
|
|
259
259
|
function getTableAndVersion(name, sql) {
|
|
260
260
|
const regExpMap = {
|
|
261
261
|
insert: /insert\sinto\s+([\w`\'\"]+)/i,
|
package/dist/decorator-utils.js
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* 因此库可以单份源码、运行时按签名形态分流:legacy 分支逻辑与 2.4.x 逐字一致,标准分支为新增。
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.
|
|
15
|
+
exports.isStd = isStd;
|
|
16
|
+
exports.getStdArgs = getStdArgs;
|
|
16
17
|
/**
|
|
17
18
|
* 判断装饰器收到的运行时参数是否为标准装饰器签名 (value, context)。
|
|
18
19
|
*
|
|
@@ -31,7 +32,6 @@ function isStd(args) {
|
|
|
31
32
|
&& args[1] !== null
|
|
32
33
|
&& typeof args[1].kind === "string";
|
|
33
34
|
}
|
|
34
|
-
exports.isStd = isStd;
|
|
35
35
|
/**
|
|
36
36
|
* 从标准装饰器参数中解出 (value, context)。
|
|
37
37
|
* 仅应在 isStd(args) 为 true 时调用。
|
|
@@ -39,4 +39,3 @@ exports.isStd = isStd;
|
|
|
39
39
|
function getStdArgs(args) {
|
|
40
40
|
return [args[0], args[1]];
|
|
41
41
|
}
|
|
42
|
-
exports.getStdArgs = getStdArgs;
|
|
@@ -16,10 +16,10 @@ class DefaultAuthentication extends authentication_factory_class_1.default {
|
|
|
16
16
|
return new DefaultAuthentication();
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
exports.default = DefaultAuthentication;
|
|
19
20
|
__decorate([
|
|
20
21
|
core_decorator_1.bean,
|
|
21
22
|
__metadata("design:type", Function),
|
|
22
23
|
__metadata("design:paramtypes", []),
|
|
23
24
|
__metadata("design:returntype", authentication_factory_class_1.default)
|
|
24
25
|
], DefaultAuthentication.prototype, "getAuthentication", null);
|
|
25
|
-
exports.default = DefaultAuthentication;
|
|
@@ -115,6 +115,7 @@ class ExpressServer extends server_factory_class_1.default {
|
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
|
+
exports.default = ExpressServer;
|
|
118
119
|
__decorate([
|
|
119
120
|
(0, typespeed_1.value)("view"),
|
|
120
121
|
__metadata("design:type", String)
|
|
@@ -165,4 +166,3 @@ __decorate([
|
|
|
165
166
|
__metadata("design:paramtypes", []),
|
|
166
167
|
__metadata("design:returntype", server_factory_class_1.default)
|
|
167
168
|
], ExpressServer.prototype, "getSever", null);
|
|
168
|
-
exports.default = ExpressServer;
|
|
@@ -16,10 +16,10 @@ class LogDefault extends log_factory_class_1.default {
|
|
|
16
16
|
return new LogDefault();
|
|
17
17
|
}
|
|
18
18
|
}
|
|
19
|
+
exports.default = LogDefault;
|
|
19
20
|
__decorate([
|
|
20
21
|
core_decorator_1.bean,
|
|
21
22
|
__metadata("design:type", Function),
|
|
22
23
|
__metadata("design:paramtypes", []),
|
|
23
24
|
__metadata("design:returntype", log_factory_class_1.default)
|
|
24
25
|
], LogDefault.prototype, "createLog", null);
|
|
25
|
-
exports.default = LogDefault;
|
|
@@ -38,6 +38,7 @@ class NodeCache extends cache_factory_class_1.default {
|
|
|
38
38
|
this.NodeCache.flushAll();
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
|
+
exports.default = NodeCache;
|
|
41
42
|
__decorate([
|
|
42
43
|
(0, typespeed_1.value)("cache"),
|
|
43
44
|
__metadata("design:type", Object)
|
|
@@ -48,4 +49,3 @@ __decorate([
|
|
|
48
49
|
__metadata("design:paramtypes", []),
|
|
49
50
|
__metadata("design:returntype", cache_factory_class_1.default)
|
|
50
51
|
], NodeCache.prototype, "getNodeCache", null);
|
|
51
|
-
exports.default = NodeCache;
|
|
@@ -9,7 +9,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
12
|
+
exports.RabbitMQ = void 0;
|
|
13
|
+
exports.rabbitListener = rabbitListener;
|
|
13
14
|
const core_decorator_1 = require("../core.decorator");
|
|
14
15
|
const typespeed_1 = require("../typespeed");
|
|
15
16
|
const amqplib_1 = require("amqplib");
|
|
@@ -41,13 +42,13 @@ class RabbitMQ {
|
|
|
41
42
|
await this.sendMessageToQueue(queue, message);
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
exports.RabbitMQ = RabbitMQ;
|
|
44
46
|
__decorate([
|
|
45
47
|
core_decorator_1.bean,
|
|
46
48
|
__metadata("design:type", Function),
|
|
47
49
|
__metadata("design:paramtypes", []),
|
|
48
50
|
__metadata("design:returntype", RabbitMQ)
|
|
49
51
|
], RabbitMQ.prototype, "getRabbitMQ", null);
|
|
50
|
-
exports.RabbitMQ = RabbitMQ;
|
|
51
52
|
async function getChannel() {
|
|
52
53
|
if (rabbitConnection === null) {
|
|
53
54
|
rabbitConnection = await (0, amqplib_1.connect)((0, typespeed_1.config)("rabbitmq"));
|
|
@@ -84,4 +85,3 @@ function rabbitListener(queue) {
|
|
|
84
85
|
}());
|
|
85
86
|
};
|
|
86
87
|
}
|
|
87
|
-
exports.rabbitListener = rabbitListener;
|
|
@@ -57,10 +57,10 @@ class ReadWriteDb extends data_source_factory_class_1.default {
|
|
|
57
57
|
return this.writeSession;
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
exports.default = ReadWriteDb;
|
|
60
61
|
__decorate([
|
|
61
62
|
core_decorator_1.bean,
|
|
62
63
|
__metadata("design:type", Function),
|
|
63
64
|
__metadata("design:paramtypes", []),
|
|
64
65
|
__metadata("design:returntype", data_source_factory_class_1.default)
|
|
65
66
|
], ReadWriteDb.prototype, "getDataSource", null);
|
|
66
|
-
exports.default = ReadWriteDb;
|
|
@@ -9,7 +9,8 @@ var __metadata = (this && this.__metadata) || function (k, v) {
|
|
|
9
9
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
-
exports.
|
|
12
|
+
exports.Redis = void 0;
|
|
13
|
+
exports.redisSubscriber = redisSubscriber;
|
|
13
14
|
const core_decorator_1 = require("../core.decorator");
|
|
14
15
|
const ioredis_1 = require("ioredis");
|
|
15
16
|
const typespeed_1 = require("../typespeed");
|
|
@@ -57,6 +58,7 @@ class Redis extends ioredis_1.default {
|
|
|
57
58
|
}
|
|
58
59
|
}
|
|
59
60
|
}
|
|
61
|
+
exports.Redis = Redis;
|
|
60
62
|
Redis.pubObj = null;
|
|
61
63
|
Redis.subObj = null;
|
|
62
64
|
__decorate([
|
|
@@ -65,7 +67,6 @@ __decorate([
|
|
|
65
67
|
__metadata("design:paramtypes", []),
|
|
66
68
|
__metadata("design:returntype", Redis)
|
|
67
69
|
], Redis.prototype, "getRedis", null);
|
|
68
|
-
exports.Redis = Redis;
|
|
69
70
|
function redisSubscriber(channel) {
|
|
70
71
|
if (!(0, typespeed_1.config)("redis"))
|
|
71
72
|
return function () {
|
|
@@ -95,7 +96,6 @@ function redisSubscriber(channel) {
|
|
|
95
96
|
};
|
|
96
97
|
};
|
|
97
98
|
}
|
|
98
|
-
exports.redisSubscriber = redisSubscriber;
|
|
99
99
|
if ((0, typespeed_1.config)("redis")) {
|
|
100
100
|
Redis.getInstanceOfRedis("sub").on("message", async function (channel, message) {
|
|
101
101
|
await (0, core_decorator_1.getComponent)(redisSubscribers[channel].target.constructor)[redisSubscribers[channel].propertyKey](message);
|
package/dist/route.decorator.js
CHANGED
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.requestMapping = exports.postMapping = exports.getMapping = void 0;
|
|
4
|
+
exports.next = next;
|
|
5
|
+
exports.reqBody = reqBody;
|
|
6
|
+
exports.reqQuery = reqQuery;
|
|
7
|
+
exports.reqForm = reqForm;
|
|
8
|
+
exports.reqParam = reqParam;
|
|
9
|
+
exports.req = req;
|
|
10
|
+
exports.request = req;
|
|
11
|
+
exports.res = res;
|
|
12
|
+
exports.response = res;
|
|
13
|
+
exports.before = before;
|
|
14
|
+
exports.after = after;
|
|
15
|
+
exports.setRouter = setRouter;
|
|
16
|
+
exports.upload = upload;
|
|
17
|
+
exports.jwt = jwt;
|
|
4
18
|
const multiparty = require("multiparty");
|
|
5
19
|
const express_jwt_1 = require("express-jwt");
|
|
6
20
|
const core_decorator_1 = require("./core.decorator");
|
|
@@ -28,7 +42,6 @@ function setRouter(app) {
|
|
|
28
42
|
}
|
|
29
43
|
});
|
|
30
44
|
}
|
|
31
|
-
exports.setRouter = setRouter;
|
|
32
45
|
function mapperFunction(method, value) {
|
|
33
46
|
return (...args) => {
|
|
34
47
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -137,7 +150,6 @@ function upload(...args) {
|
|
|
137
150
|
routerMiddleware[key] = [uploadMiddleware];
|
|
138
151
|
}
|
|
139
152
|
}
|
|
140
|
-
exports.upload = upload;
|
|
141
153
|
function uploadMiddleware(req, res, next) {
|
|
142
154
|
const form = new multiparty.Form();
|
|
143
155
|
form.parse(req, (err, fields, files) => {
|
|
@@ -171,7 +183,6 @@ function jwt(jwtConfig) {
|
|
|
171
183
|
}
|
|
172
184
|
};
|
|
173
185
|
}
|
|
174
|
-
exports.jwt = jwt;
|
|
175
186
|
function before(constructorFunction, methodName) {
|
|
176
187
|
const targetBean = (0, core_decorator_1.getComponent)(constructorFunction);
|
|
177
188
|
return function (...args) {
|
|
@@ -206,7 +217,6 @@ function before(constructorFunction, methodName) {
|
|
|
206
217
|
});
|
|
207
218
|
};
|
|
208
219
|
}
|
|
209
|
-
exports.before = before;
|
|
210
220
|
function after(constructorFunction, methodName) {
|
|
211
221
|
const targetBean = (0, core_decorator_1.getComponent)(constructorFunction);
|
|
212
222
|
return function (...args) {
|
|
@@ -243,35 +253,27 @@ function after(constructorFunction, methodName) {
|
|
|
243
253
|
});
|
|
244
254
|
};
|
|
245
255
|
}
|
|
246
|
-
exports.after = after;
|
|
247
256
|
function req(target, propertyKey, parameterIndex) {
|
|
248
257
|
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
249
258
|
routerParams[key] = (req, res, next) => req;
|
|
250
259
|
}
|
|
251
|
-
exports.req = req;
|
|
252
|
-
exports.request = req;
|
|
253
260
|
function res(target, propertyKey, parameterIndex) {
|
|
254
261
|
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
255
262
|
routerParams[key] = (req, res, next) => res;
|
|
256
263
|
}
|
|
257
|
-
exports.res = res;
|
|
258
|
-
exports.response = res;
|
|
259
264
|
function next(target, propertyKey, parameterIndex) {
|
|
260
265
|
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
261
266
|
routerParams[key] = (req, res, next) => next;
|
|
262
267
|
}
|
|
263
|
-
exports.next = next;
|
|
264
268
|
function reqBody(target, propertyKey, parameterIndex) {
|
|
265
269
|
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
266
270
|
routerParams[key] = (req, res, next) => req.body;
|
|
267
271
|
}
|
|
268
|
-
exports.reqBody = reqBody;
|
|
269
272
|
function reqParam(target, propertyKey, parameterIndex) {
|
|
270
273
|
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
271
274
|
const paramName = getParamInFunction(target[propertyKey], parameterIndex);
|
|
272
275
|
routerParams[key] = (req, res, next) => req.params[paramName];
|
|
273
276
|
}
|
|
274
|
-
exports.reqParam = reqParam;
|
|
275
277
|
function getParamInFunction(fn, index) {
|
|
276
278
|
const code = fn.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '').replace(/=>.*$/mg, '').replace(/=[^,]+/mg, '');
|
|
277
279
|
const result = code.slice(code.indexOf('(') + 1, code.indexOf(')')).match(/([^\s,]+)/g);
|
|
@@ -330,14 +332,12 @@ function reqQuery(target, propertyKey, parameterIndex) {
|
|
|
330
332
|
const paramName = getParamInFunction(target[propertyKey], parameterIndex);
|
|
331
333
|
routerParams[key] = (req, res, next) => req.query[paramName];
|
|
332
334
|
}
|
|
333
|
-
exports.reqQuery = reqQuery;
|
|
334
335
|
function reqForm(paramName) {
|
|
335
336
|
return (target, propertyKey, parameterIndex) => {
|
|
336
337
|
const key = [target.constructor.name, propertyKey, parameterIndex].toString();
|
|
337
338
|
routerParams[key] = (req, res, next) => req.body[paramName];
|
|
338
339
|
};
|
|
339
340
|
}
|
|
340
|
-
exports.reqForm = reqForm;
|
|
341
341
|
const getMapping = (value) => mapperFunction("get", value);
|
|
342
342
|
exports.getMapping = getMapping;
|
|
343
343
|
const postMapping = (value) => mapperFunction("post", value);
|
package/dist/typespeed.js
CHANGED
|
@@ -14,7 +14,10 @@ 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
|
-
exports.ReadWriteDb = exports.redisSubscriber = exports.Redis = exports.NodeCache = exports.LogDefault = exports.ExpressServer = exports.AuthenticationFactory = exports.ServerFactory = exports.DataSourceFactory = exports.CacheFactory = exports.LogFactory =
|
|
17
|
+
exports.ReadWriteDb = exports.redisSubscriber = exports.Redis = exports.NodeCache = exports.LogDefault = exports.ExpressServer = exports.AuthenticationFactory = exports.ServerFactory = exports.DataSourceFactory = exports.CacheFactory = exports.LogFactory = void 0;
|
|
18
|
+
exports.app = app;
|
|
19
|
+
exports.value = value;
|
|
20
|
+
exports.config = config;
|
|
18
21
|
require("reflect-metadata");
|
|
19
22
|
const fs = require("fs");
|
|
20
23
|
const path = require("path");
|
|
@@ -44,20 +47,18 @@ function app(...args) {
|
|
|
44
47
|
}
|
|
45
48
|
startApp(args[0]);
|
|
46
49
|
}
|
|
47
|
-
exports.app = app;
|
|
48
50
|
function startApp(constructor) {
|
|
49
51
|
const coreFiles = walkSync(corePath, { globs: ['**/*.ts'], ignore: ['**/*.d.ts', 'scaffold/**'] });
|
|
50
52
|
const mainFiles = walkSync(mainPath, { globs: ['**/*.ts'] });
|
|
51
53
|
(async function () {
|
|
52
|
-
var _a, _b;
|
|
53
54
|
try {
|
|
54
55
|
for (let p of coreFiles) {
|
|
55
56
|
let moduleName = p.replace(".d.ts", "").replace(".ts", "");
|
|
56
|
-
await (
|
|
57
|
+
await Promise.resolve(`${corePath + "/" + moduleName}`).then(s => require(s));
|
|
57
58
|
}
|
|
58
59
|
for (let p of mainFiles) {
|
|
59
60
|
let moduleName = p.replace(".d.ts", "").replace(".ts", "");
|
|
60
|
-
await (
|
|
61
|
+
await Promise.resolve(`${mainPath + "/" + moduleName}`).then(s => require(s));
|
|
61
62
|
}
|
|
62
63
|
}
|
|
63
64
|
catch (err) {
|
|
@@ -71,7 +72,6 @@ function startApp(constructor) {
|
|
|
71
72
|
function config(node) {
|
|
72
73
|
return globalConfig[node] || null;
|
|
73
74
|
}
|
|
74
|
-
exports.config = config;
|
|
75
75
|
function value(configPath) {
|
|
76
76
|
return function (...args) {
|
|
77
77
|
if ((0, decorator_utils_1.isStd)(args)) {
|
|
@@ -111,7 +111,6 @@ function value(configPath) {
|
|
|
111
111
|
}
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
|
-
exports.value = value;
|
|
115
114
|
function getRootPath(lines) {
|
|
116
115
|
// 兼容新旧 Node 栈帧(Node<22: "Function.Module._load" / Node22+: "Function._load")、
|
|
117
116
|
// mocha(ts-node) 下 "Context.<anonymous>" 与中间可能插入的 "wrapModuleLoad" 帧:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "typespeed",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.1",
|
|
4
4
|
"description": "A new Framework for TypeScript.",
|
|
5
5
|
"author": "speedphp",
|
|
6
6
|
"license": "MIT License",
|
|
@@ -13,9 +13,13 @@
|
|
|
13
13
|
"prebuild": "rm -rf dist"
|
|
14
14
|
},
|
|
15
15
|
"main": "dist/typespeed.js",
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=18"
|
|
18
|
+
},
|
|
16
19
|
"files": [
|
|
17
20
|
"dist",
|
|
18
|
-
"CHANGELOG.md"
|
|
21
|
+
"CHANGELOG.md",
|
|
22
|
+
"README.en.md"
|
|
19
23
|
],
|
|
20
24
|
"bin": {
|
|
21
25
|
"typespeed": "dist/scaffold/command.js"
|
|
@@ -61,13 +65,13 @@
|
|
|
61
65
|
"devDependencies": {
|
|
62
66
|
"@types/express": "^4.17.13",
|
|
63
67
|
"@types/mocha": "^10.0.1",
|
|
64
|
-
"@types/node": "^
|
|
68
|
+
"@types/node": "^22.0.0",
|
|
65
69
|
"chai": "4.3.7",
|
|
66
70
|
"chai-http": "^4.4.0",
|
|
67
71
|
"mocha": "10.2.0",
|
|
68
72
|
"nyc": "^15.1.0",
|
|
69
73
|
"socket.io-client": "4.7.1",
|
|
70
74
|
"ts-node": "^10.9.1",
|
|
71
|
-
"typescript": "^
|
|
75
|
+
"typescript": "^5.9.3"
|
|
72
76
|
}
|
|
73
77
|
}
|