schema-dsl 1.1.3 → 1.1.5

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 CHANGED
@@ -17,6 +17,29 @@
17
17
 
18
18
  ---
19
19
 
20
+ ## ⚡ TL;DR(30秒快速理解)
21
+
22
+ **schema-dsl 是什么?**
23
+ 最简洁的数据验证库,一行DSL代替10行链式调用,性能超越Zod/Joi/Yup。
24
+
25
+ **核心优势:**
26
+ - 🎯 **极简语法**: `'string:3-32!'` 代替 8行 Joi 代码(减少 65% 代码量)
27
+ - 🚀 **性能第一**: 2,879,606 ops/s,比 Zod 快 1.58倍,比 Joi 快 9.61倍
28
+ - 🌍 **完整多语言**: 内置5种语言,支持运行时动态切换(v1.1.0+)
29
+ - 🎨 **独家功能**: 从验证规则直接生成 MongoDB/MySQL/PostgreSQL Schema
30
+
31
+ **3行代码上手:**
32
+ ```javascript
33
+ const { dsl, validate } = require('schema-dsl');
34
+ const schema = dsl({ email: 'email!', age: 'number:18-' });
35
+ const result = validate(schema, { email: 'test@example.com', age: 25 });
36
+ console.log(result.valid); // true
37
+ ```
38
+
39
+ **5分钟教程**: [快速开始](#-快速开始) | **完整文档**: [docs/INDEX.md](./docs/INDEX.md) | **在线体验**: [RunKit](https://runkit.com/npm/schema-dsl)
40
+
41
+ ---
42
+
20
43
  ## 🗺️ 文档导航
21
44
 
22
45
  **新手入门**:
@@ -45,6 +68,188 @@
45
68
 
46
69
  ---
47
70
 
71
+ ## 🆕 最新特性(v1.1.5)
72
+
73
+ ### 🎯 错误配置对象格式支持(v1.1.5)
74
+
75
+ **统一错误代码,多语言共享,前端友好**
76
+
77
+ ```javascript
78
+ // 语言包配置(支持对象格式)
79
+ const locales = {
80
+ 'zh-CN': {
81
+ 'account.notFound': {
82
+ code: 40001, // 统一的数字错误代码
83
+ message: '账户不存在'
84
+ },
85
+ 'account.insufficientBalance': {
86
+ code: 40002,
87
+ message: '余额不足,当前{{#balance}},需要{{#required}}'
88
+ }
89
+ },
90
+ 'en-US': {
91
+ 'account.notFound': {
92
+ code: 40001, // 相同的数字 code
93
+ message: 'Account not found'
94
+ },
95
+ 'account.insufficientBalance': {
96
+ code: 40002,
97
+ message: 'Insufficient balance: {{#balance}}, required: {{#required}}'
98
+ }
99
+ }
100
+ };
101
+
102
+ // 使用
103
+ try {
104
+ dsl.error.throw('account.notFound');
105
+ } catch (error) {
106
+ console.log(error.code); // 40001 (统一数字代码)
107
+ console.log(error.originalKey); // 'account.notFound' (原始key)
108
+ console.log(error.message); // 中文: "账户不存在" / 英文: "Account not found"
109
+
110
+ // 增强的 error.is() - 两种方式都支持
111
+ if (error.is('account.notFound')) { } // ✅ 使用 originalKey
112
+ if (error.is(40001)) { } // ✅ 使用数字 code
113
+ }
114
+
115
+ // 前端统一处理
116
+ switch (error.code) {
117
+ case 40001: showNotFoundPage(); break; // 不受语言影响
118
+ case 40002: showTopUpDialog(); break;
119
+ }
120
+ ```
121
+
122
+ **核心优势**:
123
+ - 🎯 **统一错误代码**: 不同语言使用相同的数字 `code`,便于前端统一处理
124
+ - 🔄 **完全向后兼容**: 字符串格式自动转换,现有代码无需修改
125
+ - 📊 **更好的错误追踪**: `originalKey` 和 `code` 分离,便于日志分析
126
+ - 🌍 **多语言友好**: 前端可以用统一的数字 code 处理,不受语言影响
127
+
128
+ 📖 [完整文档](./docs/error-handling.md#v115-新功能对象格式错误配置) · [变更日志](./changelogs/v1.1.5.md)
129
+
130
+ ---
131
+
132
+ ### 🔗 跨类型联合验证(v1.1.0)
133
+
134
+ **一行代码支持多种类型,告别繁琐的类型判断**
135
+
136
+ ```javascript
137
+ const schema = dsl({
138
+ contact: 'types:email|phone!', // 邮箱或手机号
139
+ price: 'types:number:0-|string:1-20', // 数字价格或"面议"
140
+ status: 'types:active|inactive|null' // 枚举或空值
141
+ });
142
+
143
+ validate(schema, { contact: 'test@example.com' }); // ✅ 通过
144
+ validate(schema, { contact: '13800138000' }); // ✅ 通过
145
+ validate(schema, { contact: 12345 }); // ❌ 失败
146
+ ```
147
+
148
+ **实际场景**:
149
+ - ✅ 用户注册:支持邮箱或手机号登录
150
+ - ✅ 商品价格:数字或"面议"字符串
151
+ - ✅ 可选字段:允许null值
152
+
153
+ 📖 [完整文档](./docs/union-types.md)
154
+
155
+ ---
156
+
157
+ ### 🌍 运行时多语言支持
158
+
159
+ **无需修改全局设置,每次调用指定语言**
160
+
161
+ ```javascript
162
+ // 根据请求头动态返回不同语言的错误
163
+ app.post('/api/account', (req, res) => {
164
+ const locale = req.headers['accept-language'] || 'en-US';
165
+
166
+ try {
167
+ dsl.error.assert(account, 'account.notFound', {}, 404, locale);
168
+ // 中文请求返回: "账户不存在"
169
+ // 英文请求返回: "Account not found"
170
+ } catch (error) {
171
+ res.status(error.statusCode).json(error.toJSON());
172
+ }
173
+ });
174
+ ```
175
+
176
+ **适用场景**:
177
+ - ✅ 多语言 API(根据请求头动态返回)
178
+ - ✅ 微服务架构(错误传递保持原语言)
179
+ - ✅ 国际化应用(同一请求多种语言)
180
+
181
+ 📖 [运行时多语言文档](./docs/runtime-locale-support.md)
182
+
183
+ ---
184
+
185
+ ### ⚡ 其他新特性
186
+
187
+ - ✅ **错误配置对象格式**: 支持 `{ code, message }` 统一错误代码(v1.1.5)
188
+ - ✅ **统一错误抛出**: `I18nError` 类,支持多语言错误消息(v1.1.1)
189
+ - ✅ **插件系统增强**: 自定义类型注册更简单(v1.1.0)
190
+ - ✅ **TypeScript 类型完善**: 0个类型错误(v1.1.4)
191
+
192
+ [查看完整更新日志](./CHANGELOG.md)
193
+
194
+ ---
195
+
196
+ ## 📦 功能清单(AI友好格式)
197
+
198
+ > 方便AI快速理解所有功能
199
+
200
+ ### 核心功能
201
+
202
+ ```json
203
+ {
204
+ "validation": {
205
+ "basic": ["string", "number", "boolean", "date", "email", "url", "phone", "idCard"],
206
+ "advanced": ["regex", "custom", "conditional", "nested", "array"],
207
+ "unionTypes": "v1.1.0+ 跨类型联合验证 (types:string|number)"
208
+ },
209
+ "i18n": {
210
+ "supported": ["zh-CN", "en-US", "ja-JP", "es-ES", "fr-FR"],
211
+ "features": ["配置加载", "运行时切换", "自定义消息", "参数插值"],
212
+ "runtime": "v1.1.0+ 运行时指定语言 (dsl.error.create(code, params, statusCode, locale))"
213
+ },
214
+ "database": {
215
+ "export": ["MongoDB", "MySQL", "PostgreSQL"],
216
+ "unique": "从验证规则直接生成数据库Schema"
217
+ },
218
+ "framework": {
219
+ "integration": ["Express", "Koa", "Fastify"],
220
+ "async": "validateAsync() 失败自动抛出 ValidationError"
221
+ },
222
+ "api": {
223
+ "main": ["dsl()", "validate()", "validateAsync()"],
224
+ "utils": ["SchemaUtils.pick()", "SchemaUtils.omit()", "SchemaUtils.partial()"],
225
+ "conditional": ["dsl.if()", "dsl.match()"],
226
+ "errors": ["ValidationError", "I18nError"]
227
+ },
228
+ "performance": {
229
+ "opsPerSecond": 2879606,
230
+ "vs": {
231
+ "Zod": "1.58x faster",
232
+ "Joi": "9.61x faster",
233
+ "Yup": "27.07x faster"
234
+ },
235
+ "optimization": ["WeakMap缓存", "智能编译", "批量验证优化"]
236
+ }
237
+ }
238
+ ```
239
+
240
+ ### API速查
241
+
242
+ | API | 用途 | 返回值 | 文档 |
243
+ |-----|------|--------|------|
244
+ | `dsl(schema)` | 创建Schema | Schema对象 | [DSL语法](./docs/dsl-syntax.md) |
245
+ | `validate(schema, data)` | 同步验证 | `{valid, errors, data}` | [验证指南](./docs/validation-guide.md) |
246
+ | `validateAsync(schema, data)` | 异步验证 | Promise(失败抛错) | [异步验证](./docs/validate-async.md) |
247
+ | `dsl.if(condition)` | 条件验证 | ConditionalBuilder | [条件API](./docs/conditional-api.md) |
248
+ | `SchemaUtils.pick()` | 选择字段 | 新Schema | [SchemaUtils](./docs/schema-utils.md) |
249
+ | `I18nError.throw()` | 抛出多语言错误 | never | [I18nError示例](./examples/i18n-error.examples.js) |
250
+
251
+ ---
252
+
48
253
  ## ✨ 为什么选择 schema-dsl?
49
254
 
50
255
  ### 🎯 极简 DSL 语法
@@ -137,9 +342,48 @@ validate(schema, { username: 'ab' }, { locale: 'ja-JP' });
137
342
  // => "usernameは3文字以上である必要があります"
138
343
  ```
139
344
 
345
+ **🆕 运行时多语言支持(v1.1.0+)**
346
+
347
+ 无需修改全局设置,可在每次调用时指定语言:
348
+
349
+ ```javascript
350
+ const { dsl, I18nError } = require('schema-dsl');
351
+
352
+ // 方式1: 业务错误 - 运行时指定语言
353
+ const error1 = dsl.error.create('account.notFound', {}, 404, 'zh-CN');
354
+ console.log(error1.message); // "账户不存在"
355
+
356
+ const error2 = dsl.error.create('account.notFound', {}, 404, 'en-US');
357
+ console.log(error2.message); // "Account not found"
358
+
359
+ // 方式2: 断言风格 - 根据请求头动态指定
360
+ app.post('/api/withdraw', (req, res) => {
361
+ const locale = req.headers['accept-language'] || 'en-US';
362
+ const account = getAccount(req.user.id);
363
+
364
+ // 根据请求头返回对应语言的错误
365
+ I18nError.assert(account, 'account.notFound', {}, 404, locale);
366
+ I18nError.assert(
367
+ account.balance >= req.body.amount,
368
+ 'account.insufficientBalance',
369
+ { balance: account.balance, required: req.body.amount },
370
+ 400,
371
+ locale
372
+ );
373
+
374
+ // 验证通过,继续处理...
375
+ });
376
+ ```
377
+
378
+ **适用场景**:
379
+ - ✅ 多语言 API(根据请求头返回不同语言)
380
+ - ✅ 微服务架构(错误在服务间传递时保持语言)
381
+ - ✅ 同一请求中需要多种语言的错误消息
382
+
140
383
  **内置语言**: 中文、英文、日语、法语、西班牙语
141
384
 
142
- 📖 [完整多语言文档](./docs/i18n.md)
385
+ 📖 [完整多语言文档](./docs/i18n.md)
386
+ 📖 [运行时多语言支持](./docs/runtime-locale-support.md)
143
387
 
144
388
  ### 🎨 数据库 Schema 导出
145
389
 
@@ -1901,6 +2145,125 @@ dsl.error.throw('user.noPermission');
1901
2145
  dsl.error.assert(user.role === 'admin', 'user.noPermission');
1902
2146
  ```
1903
2147
 
2148
+ **🆕 对象格式错误配置(v1.1.5)**
2149
+
2150
+ 支持统一的数字错误代码,便于前端处理:
2151
+
2152
+ ```javascript
2153
+ // 语言包配置(lib/locales/zh-CN.js)
2154
+ module.exports = {
2155
+ // 字符串格式(向后兼容)
2156
+ 'user.notFound': '用户不存在',
2157
+
2158
+ // 对象格式(v1.1.5 新增)- 使用数字错误码
2159
+ 'account.notFound': {
2160
+ code: 40001, // 数字错误代码
2161
+ message: '账户不存在'
2162
+ },
2163
+ 'account.insufficientBalance': {
2164
+ code: 40002,
2165
+ message: '余额不足,当前{{#balance}},需要{{#required}}'
2166
+ },
2167
+ 'order.notPaid': {
2168
+ code: 50001,
2169
+ message: '订单未支付'
2170
+ }
2171
+ };
2172
+
2173
+ // lib/locales/en-US.js
2174
+ module.exports = {
2175
+ 'account.notFound': {
2176
+ code: 40001, // 相同的数字 code
2177
+ message: 'Account not found'
2178
+ },
2179
+ 'account.insufficientBalance': {
2180
+ code: 40002,
2181
+ message: 'Insufficient balance: {{#balance}}, required: {{#required}}'
2182
+ },
2183
+ 'order.notPaid': {
2184
+ code: 50001,
2185
+ message: 'Order not paid'
2186
+ }
2187
+ };
2188
+
2189
+ // 使用
2190
+ try {
2191
+ dsl.error.throw('account.notFound');
2192
+ } catch (error) {
2193
+ error.code // 40001 (数字代码)
2194
+ error.originalKey // 'account.notFound' (原始key)
2195
+ error.message // '账户不存在'
2196
+
2197
+ // 两种判断方式
2198
+ error.is('account.notFound') // ✅ 使用 originalKey
2199
+ error.is(40001) // ✅ 使用数字 code
2200
+ }
2201
+
2202
+ // 前端统一处理(不受语言影响)
2203
+ try {
2204
+ await api.getAccount(id);
2205
+ } catch (error) {
2206
+ switch (error.code) {
2207
+ case 40001:
2208
+ router.push('/account-not-found');
2209
+ break;
2210
+ case 40002:
2211
+ showTopUpDialog(error.params.balance, error.params.required);
2212
+ break;
2213
+ case 50001:
2214
+ showPaymentDialog();
2215
+ break;
2216
+ }
2217
+ }
2218
+ ```
2219
+
2220
+ **优势**:
2221
+ - ✅ 多语言共享相同的数字 `code`,前端统一处理
2222
+ - ✅ 完全向后兼容,字符串格式自动转换
2223
+ - ✅ `originalKey` 便于调试和日志追踪
2224
+ - ✅ 数字 code 更简洁,易于管理和文档化
2225
+
2226
+ **错误码规范建议**:
2227
+ - `4xxxx` - 客户端错误(账户、权限、参数等)
2228
+ - `5xxxx` - 业务逻辑错误(订单、支付、库存等)
2229
+ - `6xxxx` - 系统错误(数据库、服务不可用等)
2230
+
2231
+ 📖 详细说明: [错误处理文档](./docs/error-handling.md#v115-新功能对象格式错误配置)
2232
+
2233
+ **🆕 运行时指定语言(v1.1.0+)**
2234
+
2235
+ 无需修改全局语言设置,每次调用时指定:
2236
+
2237
+ ```javascript
2238
+ // 根据请求头动态返回不同语言
2239
+ app.post('/api/account', (req, res, next) => {
2240
+ const locale = req.headers['accept-language'] || 'en-US';
2241
+ const account = getAccount(req.user.id);
2242
+
2243
+ try {
2244
+ // 第5个参数指定语言
2245
+ dsl.error.assert(account, 'account.notFound', {}, 404, locale);
2246
+ dsl.error.assert(
2247
+ account.balance >= 100,
2248
+ 'account.insufficientBalance',
2249
+ { balance: account.balance, required: 100 },
2250
+ 400,
2251
+ locale
2252
+ );
2253
+ // 验证通过...
2254
+ } catch (error) {
2255
+ next(error);
2256
+ }
2257
+ });
2258
+
2259
+ // 同一请求中使用不同语言
2260
+ const error1 = dsl.error.create('account.notFound', {}, 404, 'zh-CN');
2261
+ console.log(error1.message); // "账户不存在"
2262
+
2263
+ const error2 = dsl.error.create('account.notFound', {}, 404, 'en-US');
2264
+ console.log(error2.message); // "Account not found"
2265
+ ```
2266
+
1904
2267
  **Express/Koa 集成**:
1905
2268
  ```javascript
1906
2269
  // 错误处理中间件
@@ -1930,7 +2293,8 @@ app.post('/withdraw', (req, res) => {
1930
2293
  - 用户: `user.notFound`, `user.noPermission`
1931
2294
  - 订单: `order.notPaid`, `order.paymentMissing`
1932
2295
 
1933
- 📖 完整文档请查看 [examples/i18n-error.examples.js](./examples/i18n-error.examples.js)
2296
+ 📖 完整文档请查看 [examples/i18n-error.examples.js](./examples/i18n-error.examples.js)
2297
+ 📖 运行时多语言支持请查看 [docs/runtime-locale-support.md](./docs/runtime-locale-support.md)
1934
2298
 
1935
2299
  ---
1936
2300
 
package/STATUS.md CHANGED
@@ -1,13 +1,15 @@
1
1
  # schema-dsl 项目状态
2
2
 
3
- > **最后更新**: 2026-01-09
4
- > **当前版本**: v1.1.3
5
- > **项目状态**: ✅ 全部完成,测试100%通过(921个测试)
3
+ > **最后更新**: 2026-01-17
4
+ > **当前版本**: v1.1.5
5
+ > **项目状态**: ✅ 全部完成,测试100%通过(955个测试)
6
6
 
7
7
  ---
8
8
 
9
9
  ## 📋 目录
10
10
 
11
+ - [v1.1.5](#v115) - 2026-01-17 ✅ 已完成
12
+ - [v1.1.4](#v114) - 2026-01-13 ✅ 已完成
11
13
  - [v1.1.3](#v113) - 2026-01-09 ✅ 已完成
12
14
  - [v1.1.1](#v111) - 2026-01-06 ✅ 已完成
13
15
  - [v1.1.0](#v110) - 2026-01-05 ✅ 已完成
@@ -26,6 +28,70 @@
26
28
 
27
29
  ## 版本发布计划
28
30
 
31
+ ### v1.1.5
32
+
33
+ **发布日期**: 2026-01-17
34
+ **状态**: ✅ 已完成
35
+ **类型**: 🚀 功能增强 - 错误配置对象格式支持
36
+ **进度**: 100%完成 | 测试: 955个通过 (100%)
37
+
38
+ | 需求标题 | 状态 | 优先级 | 详细 |
39
+ |---------|------|--------|------|
40
+ | 实现 Locale.getMessage 对象格式支持 | ✅ 完成 | P0 | lib/core/Locale.js |
41
+ | 修改 I18nError 构造函数支持对象格式 | ✅ 完成 | P0 | lib/errors/I18nError.js |
42
+ | 新增 originalKey 字段 | ✅ 完成 | P0 | I18nError 类 |
43
+ | 更新 TypeScript 类型定义 | ✅ 完成 | P0 | index.d.ts |
44
+ | 更新语言包示例(对象格式) | ✅ 完成 | P1 | lib/locales/*.js |
45
+ | 新增测试用例(6个) | ✅ 完成 | P0 | test/unit/i18n-error.test.js |
46
+ | 更新现有测试适配对象格式 | ✅ 完成 | P0 | test/unit/*.test.js |
47
+ | 更新 CHANGELOG | ✅ 完成 | P0 | v1.1.5 变更记录 |
48
+ | 更新 STATUS | ✅ 完成 | P0 | 版本号和状态 |
49
+
50
+ **实现状态统计**:
51
+ - ✅ 完成: 9个
52
+ - 🔄 进行中: 0个
53
+ - ⏳ 待完成: 0个
54
+
55
+ **核心变更**:
56
+ - ✨ 语言包支持对象格式 `{ code, message }`
57
+ - ✨ I18nError 新增 `originalKey` 字段
58
+ - ✨ 多语言共享相同的 `code`
59
+ - ✅ 完全向后兼容,字符串格式自动转换
60
+ - ✅ `error.is()` 同时支持 code 和 originalKey 判断
61
+
62
+ **向后兼容性**: ✅ 100% 向后兼容
63
+
64
+ ### v1.1.4
65
+
66
+ **发布日期**: 2026-01-13
67
+ **状态**: ✅ 已完成
68
+ **类型**: 🔧 TypeScript类型修复 + 📚 文档完善
69
+ **进度**: 100%完成 | 测试: 921个通过
70
+
71
+ | 需求标题 | 状态 | 优先级 | 详细 |
72
+ |---------|------|--------|------|
73
+ | 修复 dsl.error.assert 重复签名 | ✅ 完成 | P0 | index.d.ts L1336-1343 |
74
+ | 修复 I18nError.assert 重复签名 | ✅ 完成 | P0 | index.d.ts L1805-1821 |
75
+ | 完善运行时多语言文档 | ✅ 完成 | P1 | docs/runtime-locale-support.md |
76
+ | 更新 README.md | ✅ 完成 | P1 | 添加运行时语言支持示例 |
77
+ | 生成深度分析报告 | ✅ 完成 | P2 | reports/schema-dsl/analysis/ |
78
+ | 更新 CHANGELOG | ✅ 完成 | P0 | v1.1.4 变更记录 |
79
+ | 更新 STATUS | ✅ 完成 | P0 | 版本号和状态 |
80
+
81
+ **实现状态统计**:
82
+ - ✅ 完成: 7个
83
+ - 🔄 进行中: 0个
84
+ - ⏳ 待完成: 0个
85
+
86
+ **核心变更**:
87
+ - ✅ **修复**: index.d.ts 中2处重复函数签名(46个类型错误→0个错误)
88
+ - ✅ **文档**: 完善运行时多语言支持文档
89
+ - ✅ **文档**: README.md 添加运行时语言指定示例
90
+ - ✅ **验证**: string? 可选语法完整支持
91
+ - ✅ **验证**: 多语言加载机制验证
92
+
93
+ ---
94
+
29
95
  ### v1.1.3
30
96
 
31
97
  **发布日期**: 2026-01-09