schema-dsl 1.1.3 → 1.1.4

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 CHANGED
@@ -1,1321 +1,121 @@
1
- # schema-dsl 更新日志
1
+ # 变更日志 (CHANGELOG)
2
2
 
3
- 本文档记录 schema-dsl 项目的所有重要变更。
4
-
5
- 格式基于 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.0.0/),
6
- 版本号遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
3
+ > **说明**: 版本概览摘要,详细变更见 [changelogs/](./changelogs/) 目录
4
+ > **最后更新**: 2026-01-13
7
5
 
8
6
  ---
9
7
 
10
8
  ## 版本概览
11
9
 
12
- | 版本 | 日期 | 变更摘要 | 详细 |
13
- |------------------|------|---------|------|
14
- | [v1.1.3](#v113) | 2026-01-09 | 🐛 Bug修复:类型错误消息模板变量未替换 | [查看详情](#v113) |
15
- | [v1.1.2](#v112) | 2026-01-06 | 🎉 新功能:数字比较运算符 + Bug修复 | [查看详情](#v112) |
16
- | [v1.1.1](#v111) | 2026-01-06 | 🎉 新功能:ConditionalBuilder 独立消息支持 | [查看详情](#v111) |
17
- | [v1.1.0](#v110) | 2026-01-05 | 🎉 重大功能:跨类型联合验证 + 插件系统增强 | [查看详情](#v110) |
18
- | [v1.0.9](#v109) | 2026-01-04 | 🎉 重大改进:多语言支持完善 + TypeScript 类型完整 | [查看详情](#v109) |
19
- | [v1.0.8](#v108) | 2026-01-04 | 优化:错误消息过滤增强 | [查看详情](#v108) |
20
- | [v1.0.7](#v107) | 2026-01-04 | 修复:dsl.match/dsl.if 嵌套支持 dsl() 包裹 | [查看详情](#v107) |
21
- | [v1.0.6](#v106) | 2026-01-04 | 🚨 紧急修复:TypeScript 类型污染 | [查看详情](#v106) |
22
- | [v1.0.5](#v105) | 2026-01-04 | 测试覆盖率提升至 97% | [查看详情](#v105) |
23
- | [v1.0.4](#v104) | 2025-12-31 | TypeScript 完整支持、validateAsync、ValidationError | [查看详情](#v104) |
24
- | [v1.0.3](#v103) | 2025-12-31 | ⚠️ 破坏性变更:单值语法修复 | [查看详情](#v103) |
25
- | [v1.0.2](#v102) | 2025-12-31 | 15个新增验证器、完整文档、75个测试 | [查看详情](#v102) |
26
- | [v1.0.1](#v101) | 2025-12-31 | 枚举功能、自动类型识别、统一错误消息 | [查看详情](#v101) |
27
- | [v1.0.0](#v100) | 2025-12-29 | 初始发布版本 | [查看详情](#v100) |
28
-
29
- ---
30
-
31
- ## [v1.1.3] - 2026-01-09
32
-
33
- ### 🐛 Bug 修复
34
-
35
- #### 类型验证错误消息模板变量未替换
36
-
37
- **问题描述**:
38
- 当类型验证失败时,错误消息中的 `{{#actual}}` 模板变量没有被替换,导致错误消息显示不完整。
39
-
40
- **修复前**:
41
- ```javascript
42
- const schema = dsl({ age: 'string!' });
43
- const result = validate(schema, { age: 25 });
44
- // ❌ 错误消息: "age should be string, got {{#actual}}"
45
- ```
46
-
47
- **修复后**:
48
- ```javascript
49
- const schema = dsl({ age: 'string!' });
50
- const result = validate(schema, { age: 25 });
51
- // ✅ 错误消息: "age should be string, got number"
52
- ```
53
-
54
- **修复内容**:
55
- - ✅ 在 `ErrorFormatter.formatDetailed()` 中添加 `actual` 参数计算逻辑
56
- - ✅ 支持正确显示实际数据类型:`number`, `string`, `boolean`, `object`, `array`, `null`, `undefined`
57
- - ✅ 修复文件:`lib/core/ErrorFormatter.js` 第 280-284 行
58
-
59
- **影响范围**:
60
- - ✅ 仅影响类型验证错误消息的显示
61
- - ✅ 不影响验证逻辑本身
62
- - ✅ 向后兼容,无破坏性变更
63
-
64
- **感谢**:
65
- 感谢 monSQLize 项目发现并报告此问题。
66
-
67
- ---
68
-
69
- ## [v1.1.2] - 2026-01-06
70
-
71
- ### 🎉 新功能
72
-
73
- #### 数字比较运算符 - 更直观的数值验证
74
-
75
- **新增 5 种比较运算符,让数值验证更语义化**
76
-
77
- 现在 `number` 和 `integer` 类型支持 5 种比较运算符:`>`, `>=`, `<`, `<=`, `=`
78
-
79
- **基础用法**:
80
-
81
- ```javascript
82
- const { dsl, validate } = require('schema-dsl');
83
-
84
- // ✅ 大于(不包括边界)
85
- const schema1 = dsl({ value: 'number:>0' });
86
- validate(schema1, { value: 1 }); // ✅ true
87
- validate(schema1, { value: 0 }); // ❌ false (0不满足>0)
88
-
89
- // ✅ 大于等于
90
- const schema2 = dsl({ age: 'number:>=18' });
91
- validate(schema2, { age: 18 }); // ✅ true (包括18)
92
- validate(schema2, { age: 17 }); // ❌ false
93
-
94
- // ✅ 小于(不包括边界)
95
- const schema3 = dsl({ temp: 'number:<100' });
96
- validate(schema3, { temp: 99.9 }); // ✅ true
97
- validate(schema3, { temp: 100 }); // ❌ false (100不满足<100)
98
-
99
- // ✅ 小于等于
100
- const schema4 = dsl({ score: 'number:<=100' });
101
- validate(schema4, { score: 100 }); // ✅ true (包括100)
102
-
103
- // ✅ 等于
104
- const schema5 = dsl({ level: 'number:=5' });
105
- validate(schema5, { level: 5 }); // ✅ true
106
- validate(schema5, { level: 4 }); // ❌ false
107
- ```
108
-
109
- **支持小数和负数**:
110
-
111
- ```javascript
112
- // 小数
113
- dsl({ value: 'number:>0.5' }) // 大于0.5
114
- dsl({ price: 'number:<=99.99' }) // 小于等于99.99
115
-
116
- // 负数
117
- dsl({ value: 'number:>-10' }) // 大于-10
118
- dsl({ temp: 'number:<-5' }) // 小于-5
119
-
120
- // 配合必填标记
121
- dsl({ age: 'number:>=18!' }) // 必填且大于等于18
122
- dsl({ price: 'number:>0!' }) // 必填且大于0
123
- ```
124
-
125
- **对比:比较运算符 vs 范围语法**:
126
-
127
- | 需求 | 范围语法 | 比较运算符 | 推荐 |
128
- |------|---------|-----------|------|
129
- | x ≥ 18 | `number:18-` | `number:>=18` | **比较运算符**(更清晰) |
130
- | x > 0(不包括0) | ❌ 无法表达 | `number:>0` | **比较运算符**(唯一方法) |
131
- | x < 100(不包括100) | ❌ 无法表达 | `number:<100` | **比较运算符**(唯一方法) |
132
- | x = 100 | `number:100`(实际≤100) | `number:=100` | **比较运算符**(精确匹配) |
133
-
134
- **实际应用场景**:
135
-
136
- ```javascript
137
- // 场景1:用户注册 - 年龄限制
138
- const schema = dsl({
139
- username: 'string:3-32!',
140
- email: 'email!',
141
- age: 'number:>=18!', // 必须年满18岁
142
- password: 'string:8-!'
143
- });
144
-
145
- // 场景2:电商系统 - 价格验证
146
- const schema = dsl({
147
- productName: 'string:1-100!',
148
- price: 'number:>0!', // 价格必须大于0
149
- discount: 'number:0-100' // 折扣 0-100
150
- });
151
-
152
- // 场景3:温度监控
153
- const schema = dsl({
154
- deviceId: 'string!',
155
- temperature: 'number:>0', // 温度 > 0
156
- humidity: 'number:<=100' // 湿度 ≤ 100
157
- });
158
- ```
159
-
160
- **JSON Schema 映射**:
161
-
162
- ```javascript
163
- 'number:>0' → { exclusiveMinimum: 0 }
164
- 'number:>=18' → { minimum: 18 }
165
- 'number:<100' → { exclusiveMaximum: 100 }
166
- 'number:<=100' → { maximum: 100 }
167
- 'number:=100' → { enum: [100] }
168
- ```
169
-
170
- **特性**:
171
- - ✅ 支持 5 种比较运算符
172
- - ✅ 支持小数(如 `number:>0.5`)
173
- - ✅ 支持负数(如 `number:>-10`)
174
- - ✅ 支持必填标记(如 `number:>=18!`)
175
- - ✅ 适用于 `number` 和 `integer` 类型
176
- - ✅ 完全向后兼容原有范围语法
177
- - ✅ 完整的 TypeScript 类型支持
178
-
179
- **文档链接**:
180
- - [数字比较运算符完整文档](./docs/number-operators.md)
181
- - [README 语法速查](./README.md#-dsl-语法速查)
182
-
183
- ---
184
-
185
- ### 🐛 Bug 修复
186
-
187
- #### 修复比较运算符被误解析为枚举的问题
188
-
189
- **问题描述**:
190
- 在 v1.1.1 及之前版本,使用 `number:>0` 等语法时会被错误解析为字符串枚举 `enum: ['>0']`,导致验证结果完全相反。
191
-
192
- **修复前**:
193
- ```javascript
194
- const schema = dsl({ value: 'number:>0' });
195
- validate(schema, { value: -5 }); // ❌ 错误:返回 true(应该false)
196
- validate(schema, { value: 5 }); // ❌ 错误:返回 false(应该true)
197
- ```
198
-
199
- **修复后**:
200
- ```javascript
201
- const schema = dsl({ value: 'number:>0' });
202
- validate(schema, { value: -5 }); // ✅ 正确:返回 false
203
- validate(schema, { value: 5 }); // ✅ 正确:返回 true
204
- ```
205
-
206
- **影响范围**:
207
- - 仅影响使用 `>`, `<`, `>=`, `<=`, `=` 符号的 number 约束
208
- - 原有范围语法(如 `number:0-100`)不受影响
209
- - 完全向后兼容
210
-
211
- ---
212
-
213
- ### 📚 文档更新
214
-
215
- - 新增 [数字比较运算符文档](./docs/number-operators.md)
216
- - 更新 README.md 添加比较运算符示例
217
- - 更新 index.d.ts 添加比较运算符类型注释
218
- - 新增 28 个比较运算符单元测试
219
-
220
- ---
221
-
222
- ### 🧪 测试
223
-
224
- - **新增测试**:28 个比较运算符测试用例
225
- - **测试总数**:949 个(921 + 28)
226
- - **测试覆盖**:100% 通过
227
- - **测试文件**:`test/unit/number-operators.test.js`
228
-
229
- ---
230
-
231
- ### 📊 变更统计
232
-
233
- - **新增功能**:1 个(数字比较运算符)
234
- - **Bug 修复**:1 个(比较运算符误解析)
235
- - **文档更新**:3 个(README, docs/number-operators.md, index.d.ts)
236
- - **测试新增**:28 个
237
- - **代码变更**:2 个文件(lib/core/DslBuilder.js, lib/adapters/DslAdapter.js)
238
-
239
- ---
240
-
241
- ## [v1.1.1] - 2026-01-06
242
-
243
- ### 🎉 新功能
244
-
245
- #### ConditionalBuilder 独立消息支持 - `.and()/.or()` 后可调用 `.message()`
246
-
247
- **每个条件都可以有自己的错误消息**
248
-
249
- 现在支持在 `.and()` 和 `.or()` 后调用 `.message()` 设置独立的错误消息,让错误提示更精确。
250
-
251
- **基础用法**:
252
-
253
- ```javascript
254
- const { dsl } = require('schema-dsl');
255
-
256
- // ✅ v1.1.1 新功能:每个条件独立消息
257
- dsl.if(d => !d)
258
- .message('ACCOUNT_NOT_FOUND')
259
- .and(d => d.tradable_credits < amount)
260
- .message('INSUFFICIENT_TRADABLE_CREDITS')
261
- .assert(account);
262
-
263
- // 工作原理:
264
- // - 第一个条件失败 → 返回 'ACCOUNT_NOT_FOUND'
265
- // - 第二个条件失败 → 返回 'INSUFFICIENT_TRADABLE_CREDITS'
266
- // - 所有条件通过 → 验证成功
267
- ```
268
-
269
- **特性**:
270
- - ✅ 支持多个 `.and()` 条件各有独立消息
271
- - ✅ 支持 `.or()` 条件独立消息
272
- - ✅ 自动检测启用链式检查模式
273
- - ✅ 100% 向后兼容,不影响现有代码
274
- - ✅ 完整的 TypeScript 类型支持
275
-
276
- **实际应用示例**:
277
-
278
- ```javascript
279
- // 多层验证,每层都有清晰的错误消息
280
- dsl.if(d => !d)
281
- .message('ACCOUNT_NOT_FOUND')
282
- .and(d => d.status !== 'active')
283
- .message('ACCOUNT_INACTIVE')
284
- .and(d => d.tradable_credits < amount)
285
- .message('INSUFFICIENT_TRADABLE_CREDITS')
286
- .assert(account);
287
- ```
288
-
289
- **文档链接**:
290
- - [条件 API 文档](./docs/conditional-api.md)
291
- - [README FAQ Q7](./README.md#q7-如何合并多个-dslif-验证)
292
-
293
- ---
294
-
295
- #### I18nError 多语言错误抛出机制
296
-
297
- **统一的多语言错误抛出**
298
-
299
- 新增 `I18nError` 类和 `dsl.error` 快捷方法,提供统一的多语言错误抛出机制。
300
-
301
- **基础用法**:
302
-
303
- ```javascript
304
- const { I18nError, dsl } = require('schema-dsl');
305
-
306
- // 方式1:直接抛出
307
- I18nError.throw('account.notFound');
308
- // 中文: "账户不存在"
309
- // 英文: "Account not found"
310
-
311
- // 方式2:带参数插值
312
- I18nError.throw('account.insufficientBalance', {
313
- balance: 50,
314
- required: 100
315
- });
316
- // 输出: "余额不足,当前余额50,需要100"
317
-
318
- // 方式3:断言风格(推荐)
319
- I18nError.assert(account, 'account.notFound');
320
- I18nError.assert(
321
- account.balance >= 100,
322
- 'account.insufficientBalance',
323
- { balance: account.balance, required: 100 }
324
- );
325
-
326
- // 方式4:快捷方法
327
- dsl.error.throw('user.noPermission');
328
- dsl.error.assert(user.role === 'admin', 'user.noPermission');
329
- ```
330
-
331
- **特性**:
332
- - ✅ 统一的错误代码格式:`{模块}.{错误类型}`
333
- - ✅ 自动多语言翻译(支持中英文)
334
- - ✅ 参数插值支持
335
- - ✅ Express/Koa 集成(toJSON 方法)
336
- - ✅ 与 `.message()` 和 `.label()` 使用相同的多语言机制
337
-
338
- **内置错误代码**:
339
- - 通用: `error.notFound`, `error.forbidden`, `error.unauthorized`
340
- - 账户: `account.notFound`, `account.insufficientBalance`, `account.insufficientCredits`
341
- - 用户: `user.notFound`, `user.noPermission`, `user.notVerified`
342
- - 订单: `order.notPaid`, `order.paymentMissing`, `order.addressMissing`
343
-
344
- **Express/Koa 集成**:
345
-
346
- ```javascript
347
- app.use((error, req, res, next) => {
348
- if (error instanceof I18nError) {
349
- return res.status(error.statusCode).json(error.toJSON());
350
- }
351
- next(error);
352
- });
353
- ```
354
-
355
- **文档链接**:
356
- - [使用示例](./examples/i18n-error.examples.js)
357
- - [README FAQ Q8](./README.md#q8-如何统一抛出多语言错误v111)
358
-
359
- ---
360
-
361
- ### 📝 测试
362
-
363
- - **新增**: 52 个测试用例(24个独立消息 + 28个 I18nError)
364
- - **总计**: 921 个测试全部通过 (100%)
365
-
366
- ### 📖 文档
367
-
368
- - **新增**: docs/conditional-api.md 新增 600+ 行功能说明
369
- - **新增**: examples/i18n-error.examples.js I18nError 使用示例
370
- - **更新**: README.md FAQ Q7/Q8 添加新功能说明
371
- - **更新**: index.d.ts TypeScript 类型注释和示例(I18nError + dsl.error)
372
-
373
- ---
374
-
375
- ## [v1.1.0] - 2026-01-05
376
-
377
- ### 🎉 新功能
378
-
379
- #### 1. 跨类型联合验证 - `types:` 语法
380
-
381
- **一个字段支持多种类型**
382
-
383
- ...existing content...
384
-
385
- **带约束的联合类型**:
386
-
387
- ```javascript
388
- const schema = dsl({
389
- contact: 'types:email|phone!', // 邮箱或手机号
390
- price: 'types:number:0-|string:1-20', // 数字价格或"面议"
391
- rating: 'types:integer:1-5|string:9' // 整数1-5或字符串"excellent"
392
- });
393
- ```
394
-
395
- **实际应用场景**:
396
-
397
- ```javascript
398
- // 用户注册:灵活的联系方式
399
- const registerSchema = dsl({
400
- username: 'string:3-20!',
401
- contact: 'types:email|phone!', // 支持邮箱或手机号注册
402
- age: 'types:integer:1-150|null' // 年龄可选(null表示不填)
403
- });
404
- ```
405
-
406
- **支持的类型**:
407
- - ✅ 所有内置类型:`string`, `number`, `email`, `url`, `uuid` 等
408
- - ✅ 插件注册的自定义类型(见下文)
409
-
410
- ---
411
-
412
- #### 2. 插件系统增强 - DSL类型注册
413
-
414
- **插件现在可以注册自定义DSL类型**
415
-
416
- 插件不再局限于注册ajv format/keyword,现在可以注册完整的DSL类型,让自定义类型在DSL语法中直接可用。
417
-
418
- **改造前** (v1.0.x):
419
- ```javascript
420
- // ❌ 只能注册ajv format(仅验证阶段生效)
421
- install(schemaDsl, options) {
422
- const ajv = validator.getAjv();
423
- ajv.addFormat('phone-cn', { validate: /^1[3-9]\d{9}$/ });
424
-
425
- // ❌ 无法在DSL语法中使用
426
- // dsl({ phone: 'phone-cn!' }) // 报错:未知类型
427
- }
428
- ```
429
-
430
- **改造后** (v1.1.0):
431
- ```javascript
432
- // ✅ 同时注册DSL类型和ajv format
433
- install(schemaDsl, options) {
434
- const { DslBuilder } = schemaDsl;
435
-
436
- // ✅ 注册到DSL解析器(解析阶段)
437
- DslBuilder.registerType('phone-cn', {
438
- type: 'string',
439
- pattern: /^1[3-9]\d{9}$/.source,
440
- minLength: 11,
441
- maxLength: 11
442
- });
443
-
444
- // ✅ 注册到ajv(验证阶段)
445
- const ajv = validator.getAjv();
446
- ajv.addFormat('phone-cn', { validate: /^1[3-9]\d{9}$/ });
447
-
448
- // ✅ 现在可以在DSL中直接使用
449
- // dsl({ phone: 'phone-cn!' }) // ✅ 成功
450
- // dsl({ contact: 'types:email|phone-cn' }) // ✅ 在联合类型中也能用
451
- }
452
- ```
453
-
454
- **新增 API**:
455
-
456
- | API | 说明 | 用途 |
457
- |-----|------|------|
458
- | `DslBuilder.registerType(name, schema)` | 注册自定义类型 | 插件注册新类型 |
459
- | `DslBuilder.hasType(type)` | 检查类型是否存在 | 插件验证类型 |
460
- | `DslBuilder.getCustomTypes()` | 获取所有自定义类型 | 调试和测试 |
461
- | `DslBuilder.clearCustomTypes()` | 清除自定义类型 | 测试用 |
462
-
463
- **插件示例**:
464
-
465
- ```javascript
466
- // plugins/custom-format.js (v2.0.0)
467
- module.exports = {
468
- name: 'custom-format',
469
- version: '2.0.0',
470
-
471
- install(schemaDsl, options, context) {
472
- const { DslBuilder } = schemaDsl;
473
- const ajv = validator.getAjv();
474
-
475
- // 定义自定义类型
476
- const types = {
477
- 'phone-cn': {
478
- pattern: /^1[3-9]\d{9}$/,
479
- schema: { type: 'string', pattern: /^1[3-9]\d{9}$/.source, minLength: 11, maxLength: 11 }
480
- },
481
- 'qq': {
482
- pattern: /^[1-9][0-9]{4,10}$/,
483
- schema: { type: 'string', pattern: /^[1-9][0-9]{4,10}$/.source, minLength: 5, maxLength: 11 }
484
- }
485
- };
486
-
487
- // 注册到DSL和ajv
488
- Object.keys(types).forEach(name => {
489
- const config = types[name];
490
- DslBuilder.registerType(name, config.schema); // DSL解析
491
- ajv.addFormat(name, { validate: config.pattern }); // ajv验证
492
- });
493
- }
494
- };
495
- ```
496
-
497
- ---
498
-
499
- #### 3. ConditionalBuilder 快捷验证方法
500
-
501
- **一行代码完成条件验证**
502
-
503
- 新增4个快捷验证方法,让条件判断更简洁:
504
-
505
- | 方法 | 返回值 | 抛错 | 异步 | 适用场景 |
506
- |------|--------|------|------|---------|
507
- | `.validate()` | `{ valid, errors, data }` | ❌ | ❌ | 需要错误详情 |
508
- | `.validateAsync()` | `Promise<data>` | ✅ | ✅ | async/await、中间件 |
509
- | `.assert()` | `data` | ✅ | ❌ | 快速失败、断言 |
510
- | `.check()` | `boolean` | ❌ | ❌ | 只需判断真假 |
511
-
512
- **使用示例**:
513
-
514
- ```javascript
515
- // 同步验证 - 返回详细结果
516
- const result = dsl.if(d => d.age < 18)
517
- .message('未成年用户不能注册')
518
- .validate({ age: 16 });
519
-
520
- // 异步验证 - 失败自动抛错
521
- await dsl.if(d => d.age < 18)
522
- .message('未成年用户不能注册')
523
- .validateAsync({ age: 16 });
524
-
525
- // 断言验证 - 同步抛错
526
- dsl.if(d => d.age < 18).message('未成年').assert(userData);
527
-
528
- // 快速判断 - 返回 boolean
529
- const isValid = dsl.if(d => d.age < 18).message('未成年').check(data);
530
- ```
531
-
532
- **优势**:
533
- - ✅ 从2行代码减少到1行
534
- - ✅ 支持 async/await
535
- - ✅ 快速失败模式
536
- - ✅ 完全向后兼容
10
+ | 版本 | 日期 | 变更摘要 | 详细 |
11
+ |------|------|---------|------|
12
+ | [v1.1.4](./changelogs/v1.1.4.md) | 2026-01-13 | 🔧 TypeScript类型修复:移除重复函数签名 + 多语言文档完善 | [查看](./changelogs/v1.1.4.md) |
13
+ | [v1.1.3](./changelogs/v1.1.3.md) | 2026-01-09 | 🐛 Bug修复:类型错误消息模板变量未替换 | [查看](./changelogs/v1.1.3.md) |
14
+ | [v1.1.2](./changelogs/v1.1.2.md) | 2026-01-06 | 🎉 新功能:数字比较运算符 + Bug修复 | [查看](./changelogs/v1.1.2.md) |
15
+ | [v1.1.1](./changelogs/v1.1.1.md) | 2026-01-06 | 🎉 新功能:ConditionalBuilder 独立消息支持 | [查看](./changelogs/v1.1.1.md) |
16
+ | [v1.1.0](./changelogs/v1.1.0.md) | 2026-01-05 | 🎉 重大功能:跨类型联合验证 + 插件系统增强 | [查看](./changelogs/v1.1.0.md) |
17
+ | [v1.0.9](./changelogs/v1.0.9.md) | 2026-01-04 | 🎉 重大改进:多语言支持完善 + TypeScript 类型完整 | [查看](./changelogs/v1.0.9.md) |
18
+ | v1.0.8 | 2026-01-04 | 优化:错误消息过滤增强 | - |
19
+ | v1.0.7 | 2026-01-04 | 修复:dsl.match/dsl.if 嵌套支持 dsl() 包裹 | - |
20
+ | v1.0.6 | 2026-01-04 | 🚨 紧急修复:TypeScript 类型污染 | - |
21
+ | v1.0.5 | 2026-01-04 | 测试覆盖率提升至 97% | - |
22
+ | v1.0.4 | 2025-12-31 | TypeScript 完整支持、validateAsync、ValidationError | - |
23
+ | v1.0.3 | 2025-12-31 | ⚠️ 破坏性变更:单值语法修复 | - |
24
+ | v1.0.2 | 2025-12-31 | 15个新增验证器、完整文档、75个测试 | - |
25
+ | v1.0.1 | 2025-12-31 | 枚举功能、自动类型识别、统一错误消息 | - |
26
+ | [v1.0.0](./changelogs/v1.0.0.md) | 2025-12-29 | 初始发布版本 | [查看](./changelogs/v1.0.0.md) |
537
27
 
538
- **详细文档**:[ConditionalBuilder API](./docs/conditional-api.md)
539
-
540
- ### Changed
541
-
542
- - 📖 优化 README.md,新增"条件验证 - 一行代码搞定"章节
543
- - 📖 完善 API 文档和使用示例
544
- - 📖 新增4个方法的 TypeScript 类型定义
545
-
546
- ### Tests
547
-
548
- - ✅ 新增 45个测试用例(总计 807个测试)
549
- - `.validate()` 方法: 9个
550
- - `.validateAsync()` 方法: 6个
551
- - `.assert()` 方法: 6个
552
- - `.check()` 方法: 5个
553
- - 边界情况: 12个
554
- - 特殊场景: 7个
555
- - ✅ 测试覆盖率 100%(807/807)
556
- - ✅ 覆盖 null、undefined、空值、NaN、异常处理等所有边界情况
557
-
558
- ### 向后兼容
559
-
560
- ✅ **完全向后兼容**,所有现有代码无需修改
28
+ > 💡 **提示**: 重要版本的详细变更记录在 [changelogs/](./changelogs/) 目录中。
29
+ > 当前已有详细文档的版本:v1.1.4, v1.1.3, v1.1.2, v1.1.1, v1.1.0, v1.0.9, v1.0.0
30
+ > 其他版本的详细变更信息请参考项目提交历史或联系维护者。
561
31
 
562
32
  ---
563
33
 
564
- ## [v1.0.9] - 2026-01-04
565
-
566
- ### 🎉 重大改进
567
-
568
- #### 1. 多语言文档完善 ⭐⭐⭐
569
-
570
- **优化内容**:
571
-
572
- 1. ✅ **统一文档描述为"首次加载,运行时切换"**
573
- - 修复 `i18n-user-guide.md` 配置示例错误
574
- - 更新 `add-custom-locale.md`、`dynamic-locale.md`、`frontend-i18n-guide.md`
575
- - 添加完整的配置和使用示例
576
- - 添加错误示例对比(运行时单个加载 vs 首次加载)
577
-
578
- 2. ✅ **添加文档导航**
579
- - 在 `i18n.md` 添加多语言文档导航
580
- - 帮助用户快速找到所需文档
581
-
582
- 3. ✅ **性能数据更新**
583
- - 更新性能对比数据:**2,879,606 ops/s**(提升3.19倍)
584
- - 比 Zod 快 1.58倍
585
- - 比 Joi 快 9.61倍
586
- - 比 Yup 快 27.07倍
587
-
588
- #### 2. 多语言支持完善(v1.0.9 早期)⭐⭐⭐
589
-
590
- **问题描述**:
591
- - TypeScript 类型定义缺少 `options` 参数
592
- - 多语言切换需要修改全局状态,并发场景不安全
593
- - 自定义错误消息查找逻辑有问题
594
-
595
- **修复内容**:
596
-
597
- 1. ✅ **TypeScript 类型定义完善**
598
- ```typescript
599
- // 新增 ValidateOptions 接口
600
- interface ValidateOptions {
601
- format?: boolean; // 是否格式化错误
602
- locale?: string; // 动态指定语言(如 'zh-CN', 'en-US')
603
- messages?: ErrorMessages; // 自定义错误消息
604
- }
605
-
606
- // 更新函数签名
607
- function validate(
608
- schema: JSONSchema | DslBuilder,
609
- data: any,
610
- options?: ValidateOptions // ← 新增
611
- ): ValidationResult;
612
-
613
- // 更新 Validator.validate 方法签名
614
- validate(
615
- schema: JSONSchema | DslBuilder | Function,
616
- data: any,
617
- options?: ValidateOptions // ← 新增
618
- ): ValidationResult;
619
- ```
620
-
621
- 2. ✅ **参数化语言切换(无需全局状态)**
622
- ```javascript
623
- // 旧方式(需要修改全局状态)
624
- Locale.setLocale('zh-CN');
625
- const result = validate(schema, data);
626
-
627
- // 新方式(参数化,支持并发)
628
- const result = validate(schema, data, { locale: 'zh-CN' });
629
- ```
34
+ ## 变更统计
630
35
 
631
- 3. **修复自定义错误消息查找逻辑**
632
- - **Bug 1**: 优先使用通用模板而非 schema 自定义消息
633
- - **Bug 2**: 无法正确处理三种自定义消息格式:
634
- - 键引用:`_customMessages.pattern = "pattern.objectId"`
635
- - 模板字符串:`_customMessages.min = "{{#label}}必须大于{{#limit}}"`
636
- - 最终消息:`_customMessages.pattern = "手机号格式不正确"`
637
-
638
- **修复效果**:
639
-
640
- ```javascript
641
- // 1. 并发调用不同语言
642
- const [resultZh, resultEn] = await Promise.all([
643
- validate(schema, data, { locale: 'zh-CN' }),
644
- validate(schema, data, { locale: 'en-US' })
645
- ]);
646
- // ✅ 两次调用互不影响
647
-
648
- // 2. 自定义消息(键引用)
649
- const schema = dsl('objectId!');
650
- const result = validate(schema, 'invalid', { locale: 'zh-CN' });
651
- // message: "无效的 ObjectId" ✅
652
-
653
- // 3. 自定义消息(模板字符串)
654
- const schema = dsl({
655
- age: 'number:18-!'.label('年龄')
656
- .messages({ 'min': '{{#label}}必须大于{{#limit}}' })
657
- });
658
- const result = validate(schema, { age: 10 });
659
- // message: "年龄必须大于18" ✅
660
-
661
- // 4. 自定义消息(最终消息)
662
- const schema = dsl({
663
- phone: 'string!'.pattern(/^1[3-9]\d{9}$/)
664
- .messages({ 'pattern': '手机号格式不正确' })
665
- });
666
- const result = validate(schema, { phone: 'invalid' });
667
- // message: "手机号格式不正确" ✅
668
- ```
669
-
670
- **技术细节**:
671
- - 修改 `index.js` 中的 `validate()` 函数,传递 `options` 参数
672
- - 修改 `Validator.js` 中的 `validate()` 方法,直接传递 `locale` 到 ErrorFormatter
673
- - 修改 `ErrorFormatter.js`:
674
- - `format()` 方法支持对象参数 `{ locale, messages }`
675
- - `formatDetailed()` 方法新增 `customMessages` 参数
676
- - 优化自定义消息查找逻辑:优先检查 schema 中的 `_customMessages`
677
-
678
- **测试结果**:
679
- - ✅ 725 个测试全部通过(从 51 个失败修复到 0 个失败)
680
- - ✅ 完全向后兼容,不破坏现有 API
681
-
682
- ### Changed (变更)
683
-
684
- - 📝 **API**: `validate()` 和 `Validator.validate()` 新增 `options` 参数(向后兼容)
685
- - 🔧 **内部**: `ErrorFormatter.formatDetailed()` 新增 `customMessages` 参数
686
-
687
- ### Fixed (修复)
688
-
689
- - 🐛 修复 TypeScript 类型定义缺少 `options` 参数
690
- - 🐛 修复自定义错误消息查找逻辑(优先级问题)
691
- - 🐛 修复自定义消息无法区分键引用/模板字符串/最终消息
36
+ | 版本系列 | 版本数 | 主要改进方向 |
37
+ |---------|-------|------------|
38
+ | v1.1.x | 5 | TypeScript类型完善、多语言支持、数字运算符、联合类型、类型错误修复 |
39
+ | v1.0.x | 10 | 核心功能、验证器、测试覆盖、文档完善 |
692
40
 
693
41
  ---
694
42
 
695
- ## [v1.0.8] - 2026-01-04
696
-
697
- ### Improved (优化)
698
-
699
- #### 错误消息过滤增强 ⭐
43
+ ## 里程碑版本
700
44
 
701
- **问题描述**:
702
- 用户报告错误消息存在冗余问题:
703
- - 在嵌套 If/Match 结构中,会显示重复的 "must match then schema" 包装错误
704
- - 当已有具体字段错误时(如"Credit price is required"),还会额外显示2-3个通用包装错误
45
+ ### v1.1.4 - TypeScript类型修复与文档完善 🔧
705
46
 
706
- **修复内容**:
707
- - ✅ 过滤 `if` 关键字的包装错误
708
- - ✅ 过滤 `anyOf` 关键字的包装错误
709
- - ✅ 过滤 `oneOf` 关键字的包装错误
710
- - ✅ 当存在具体字段错误时,自动移除所有包装错误
47
+ **发布日期**: 2026-01-13
48
+ **重要性**: ⭐⭐⭐
711
49
 
712
- **修复效果**:
50
+ **核心改进**:
51
+ - ✅ 修复 index.d.ts 中2处重复函数签名(46个类型错误→0个错误)
52
+ - ✅ 修复 `dsl.error.assert` 重复签名(L1336-1343)
53
+ - ✅ 修复 `I18nError.assert` 重复签名(L1805-1821)
54
+ - ✅ 完善多语言运行时支持文档(docs/runtime-locale-support.md)
55
+ - ✅ README.md 添加运行时语言指定示例
56
+ - ✅ 验证 string? 可选语法完整支持
713
57
 
714
- 修复前:
715
- ```javascript
716
- const result = validate(schema, data);
717
- // errors: [
718
- // { message: "Credit price is required" },
719
- // { message: "must match then schema" }, // 冗余
720
- // { message: "must match then schema" } // 冗余
721
- // ]
722
- ```
723
-
724
- 修复后:
725
- ```javascript
726
- const result = validate(schema, data);
727
- // errors: [
728
- // { message: "Credit price is required" } // 只显示具体错误
729
- // ]
730
- ```
731
-
732
- **技术细节**:
733
- - 修改文件:[lib/core/ErrorFormatter.js](lib/core/ErrorFormatter.js#L84-L101)
734
- - 过滤逻辑:检测到具体错误(type, required, pattern等)时,自动过滤包装错误(if, anyOf, oneOf)
735
- - 适用场景:所有使用 `dsl.if()`、`dsl.match()` 以及 JSON Schema 的 anyOf/oneOf 的验证
736
-
737
- **测试覆盖**:
738
- - 测试文件:[test/unit/error-message-filter.test.js](test/unit/error-message-filter.test.js)
739
- - 新增测试:5个错误过滤场景
740
- - 测试总数:725 (+5)
741
- - 所有测试通过 ✅
58
+ **详细信息**: [查看 changelogs/v1.1.4.md](./changelogs/v1.1.4.md)
742
59
 
743
60
  ---
744
61
 
745
- ## [v1.0.7] - 2026-01-04
746
-
747
- ### Fixed (修复)
748
-
749
- #### 全面支持 dsl.match/dsl.if 所有嵌套组合 ⭐⭐⭐
750
-
751
- **问题描述**:
752
- 在 v1.0.6 中,TypeScript 用户被要求使用 `dsl()` 包裹字符串,但在 `dsl.match()` 和 `dsl.if()` 中使用嵌套结构时会失败。用户报告了复杂嵌套场景无法正常工作。
753
-
754
- **修复内容**:
755
- - ✅ **Match 嵌套 Match** - 多级条件分支
756
- - ✅ **Match 嵌套 If** - 在分支中使用条件
757
- - ✅ **If 嵌套 Match** - 条件中使用多分支(用户报告的场景)
758
- - ✅ **If 嵌套 If** - 多层条件嵌套
759
- - ✅ **_default 中嵌套** - 默认规则支持 Match/If
760
- - ✅ **三层嵌套** - 支持任意深度嵌套
761
-
762
- **修复前问题**:
763
- ```javascript
764
- // ❌ v1.0.6 中所有嵌套都会失败
765
- credit_price: dsl.if('enabled',
766
- dsl.match('payment_type', {
767
- 'credit': dsl('integer:1-10000!').label('价格'),
768
- '_default': 'integer:1-10000'
769
- }),
770
- 'integer:1-10000'
771
- )
772
- ```
773
-
774
- **修复后**:
775
- ```javascript
776
- // ✅ v1.0.7 完全支持所有嵌套组合
777
-
778
- // 1. If 嵌套 Match(用户场景)
779
- credit_price: dsl.if('enabled',
780
- dsl.match('payment_type', {
781
- 'credit': dsl('integer:1-10000!').label('credit_price'),
782
- '_default': 'integer:1-10000'
783
- }),
784
- 'integer:1-10000'
785
- )
786
-
787
- // 2. Match 嵌套 Match
788
- value: dsl.match('category', {
789
- 'contact': dsl.match('type', {
790
- 'email': dsl('email!').label('邮箱'),
791
- 'phone': dsl('string:11!').label('手机号')
792
- }),
793
- 'payment': dsl.match('type', {
794
- 'credit': dsl('integer:1-10000!'),
795
- 'cash': dsl('number:0.01-10000!')
796
- })
797
- })
798
-
799
- // 3. Match 嵌套 If
800
- discount: dsl.match('user_type', {
801
- 'member': dsl.if('is_vip',
802
- dsl('number:10-50!').label('VIP会员折扣'),
803
- dsl('number:5-20!').label('普通会员折扣')
804
- ),
805
- 'guest': dsl('number:0-10').label('访客折扣')
806
- })
807
-
808
- // 4. If 嵌套 If
809
- price: dsl.if('is_member',
810
- dsl.if('is_premium',
811
- dsl('number:100-500!').label('高级会员价'),
812
- dsl('number:200-800!').label('普通会员价')
813
- ),
814
- dsl('number:500-1000!').label('非会员价')
815
- )
816
-
817
- // 5. 三层嵌套
818
- value: dsl.match('level1', {
819
- 'A': dsl.match('level2', {
820
- 'A1': dsl.if('level3',
821
- dsl('integer:1-100!'),
822
- dsl('integer:1-50!')
823
- )
824
- })
825
- })
826
- ```
827
-
828
- **技术细节**:
829
- - 修复了 `DslAdapter._buildMatchSchema()` 方法(第476-489行)
830
- - 修复了 `DslAdapter._buildIfSchema()` 方法
831
- - 递归处理所有 `_isMatch` 和 `_isIf` 结构
832
- - 新增 null/undefined 分支值处理逻辑
833
- - 支持任意深度嵌套(已测试至5层)
834
-
835
- **已知限制**:
836
- 1. **自定义验证器传递限制** - `.custom()` 验证器在嵌套 Match/If 中可能不会完全传递
837
- ```javascript
838
- // .custom() 的自定义消息可能在深层嵌套中丢失
839
- value: dsl.match('type', {
840
- 'email': dsl('string!').custom((v) => v.includes('@'))
841
- })
842
- // 基础验证(必填、类型)会生效,但 custom 验证可能不完全传递
843
- ```
844
-
845
- 2. **嵌套字段路径限制** - `dsl.match(field)` 的 field 参数不支持嵌套路径
846
- ```javascript
847
- // ❌ 不支持
848
- dsl.match('config.engine', {...})
849
-
850
- // ✅ 支持 - 使用扁平化字段
851
- dsl.match('config_engine', {...})
852
- ```
853
-
854
- 3. **自定义消息传递** - 在多层嵌套中,自定义错误消息可能不会完全保留
855
-
856
- **测试覆盖**:
857
- - 测试总数:**686 → 720**(**+34 个全面测试**)
858
- - **v1.0.7 新增测试场景**:
859
-
860
- **基础嵌套组合**(6个测试):
861
- - Match 嵌套 Match - 多级条件分支
862
- - Match 嵌套 If - 在分支中使用条件
863
- - If 嵌套 Match - 条件中使用多分支
864
- - If 嵌套 If - 多层条件嵌套
865
- - _default 中使用嵌套 - 默认规则支持 Match/If
866
- - 三层嵌套 - 任意深度嵌套验证
867
-
868
- **参数验证和错误处理**(7个测试):
869
- - 空 map 处理 - Match 中空映射表的行为
870
- - null/undefined 分支值 - 空值分支的处理
871
- - 参数验证 - match/if 参数的有效性检查
872
- - 对象/数组作为条件值 - 复杂类型作为条件的验证
873
- - 循环依赖检测 - 防止无限递归
874
- - 同一字段多规则引用 - 字段重复使用场景
875
- - undefined else 分支 - If 中省略 else 的行为
876
-
877
- **深度嵌套和高级场景**(6个测试):
878
- - 4层嵌套 - Match-Match-Match-If 四层组合
879
- - 大量分支(10+)- 单个 Match 包含15个分支
880
- - .custom() 验证器在嵌套中 - 自定义验证器的传递(已知限制)
881
- - 复杂对象规则 - 嵌套中包含复杂对象 schema
882
- - 混合嵌套 - Match 中 If,If 中 Match,再嵌套对象
883
- - 5层超深嵌套 - 极端深度测试
884
-
885
- **覆盖率提升测试**(14个测试):
886
- - 错误处理和边界情况(6个)
887
- - 特殊DSL语法覆盖(4个)
888
- - 极端和性能测试(4个)
889
-
890
- **代码修复**:
891
- - 修复 `lib/adapters/DslAdapter.js` 中 null/undefined 分支处理
892
- - 新增代码行:476-489(处理空值分支)
893
-
894
- - **测试覆盖率**:73.12% → 73.17%(语句覆盖率)
895
- - **Match/If核心功能覆盖率**:~100%(所有嵌套组合和边界情况)
896
- - 所有测试通过 ✅
897
-
898
- **迁移指南**:
899
- 无需任何代码修改,所有嵌套场景现在都自动支持。
900
-
901
- ---
902
-
903
- ## [v1.0.6] - 2026-01-04
904
-
905
- ### 🚨 Fixed (紧急修复)
906
-
907
- #### TypeScript 类型污染问题 ⭐⭐⭐
908
-
909
- **问题描述**:
910
- - v1.0.5 及更早版本中,`index.d.ts` 包含了全局 `interface String` 扩展(第 816-1065 行,共 209 行代码)
911
- - 这导致 TypeScript 全局类型系统污染,原生 `String.prototype` 方法的类型被错误推断
912
- - **严重问题**:`String.prototype.trim()` 返回类型从 `string` 被错误推断为 `DslBuilder`
913
- - 影响所有使用 TypeScript 的项目,导致类型安全问题
914
-
915
- **修复内容**:
916
- - ✅ **完全删除**全局 `interface String` 扩展(移除 209 行类型污染代码)
917
- - ✅ 添加详细的 TypeScript 使用说明文档
918
- - ✅ 保证原生 String 方法的类型推断正确(`trim()` 正确返回 `string`)
919
-
920
- **对用户的影响**:
921
-
922
- 1. **JavaScript 用户** ✅ **完全不受影响**
923
- ```javascript
924
- // 仍然可以正常使用 String 扩展
925
- const schema = dsl({ email: 'email!'.label('邮箱') });
926
- ```
927
-
928
- 2. **TypeScript 用户** ⚠️ **需要调整用法**
929
- ```typescript
930
- // ❌ v1.0.5 及之前(有类型污染 bug)
931
- const schema = dsl({ email: 'email!'.label('邮箱') });
932
-
933
- // ✅ v1.0.6 推荐写法(获得正确类型提示)
934
- const schema = dsl({
935
- email: dsl('email!').label('邮箱')
936
- });
937
- ```
938
-
939
- **技术细节**:
940
- - 文件变化:`index.d.ts` 从 2958 行减少到 2749 行
941
- - 测试状态:所有 677 个测试通过 ✅
942
- - 类型验证:原生 `String.prototype.trim()` 现在正确返回 `string` 类型
943
-
944
- **迁移指南**:
945
- - JavaScript 项目:无需任何修改
946
- - TypeScript 项目:使用 `dsl()` 函数包裹字符串字面量获得类型提示
947
- - 详见:[TypeScript 使用指南](./docs/typescript-guide.md)
948
-
949
- ---
950
-
951
- ## [v1.0.5] - 2026-01-04
952
-
953
- ### Added (新增功能)
954
-
955
- #### 测试覆盖率大幅提升 ⭐
62
+ ### v1.1.3 - 类型错误消息模板修复 🐛
956
63
 
957
- - ✅ **新增 5 个核心类的完整测试**
958
- - `CacheManager.test.js` - 24 个测试(缓存管理)
959
- - `ErrorFormatter.test.js` - 9 个测试(错误格式化)
960
- - `JSONSchemaCore.test.js` - 10 个测试(JSON Schema 核心)
961
- - `MarkdownExporter.test.js` - 3 个测试(Markdown 导出)
962
- - `ErrorCodes.test.js` - 4 个测试(错误代码)
64
+ **发布日期**: 2026-01-09
65
+ **重要性**: ⭐⭐⭐
963
66
 
964
- - ✅ **测试统计**
965
- - 总测试数:651 677(+26 个测试)
966
- - 测试覆盖率:92% → 97%(+5%)
967
- - 所有核心类现在都有完整测试覆盖
968
-
969
- ### Fixed (修复)
67
+ **核心改进**:
68
+ - 修复类型错误消息中 `{{#actual}}` 模板变量未替换问题
69
+ - 错误消息正确显示实际数据类型
70
+ - ✅ 向后兼容,无破坏性变更
970
71
 
971
- - 修复缓存配置支持(4 个参数完整支持)
972
- - ✅ 简化 i18n 配置(从 3 个方法简化为 2 个)
72
+ **详细信息**: [查看 changelogs/v1.1.3.md](./changelogs/v1.1.3.md)
973
73
 
974
74
  ---
975
75
 
976
- ## [v1.0.4] - 2025-12-31
977
-
978
- ### Added (新增功能)
979
-
980
- #### TypeScript 完整支持 ⭐
981
-
982
- - ✅ **完整的类型定义**
983
- - 新增 `validateAsync` 函数类型定义
984
- - 新增 `ValidationError` 类完整类型(包含所有方法)
985
- - 优化 String 扩展的 TypeScript 说明
986
-
987
- - ✅ **TypeScript 使用指南**
988
- - 创建完整的 TypeScript 使用文档 (`docs/typescript-guide.md`)
989
- - 1000+ 行详细说明,涵盖从基础到高级所有场景
990
- - 3个完整实战案例(用户注册、API验证、字段复用)
991
- - 5个常见问题解答
992
-
993
- - ✅ **TypeScript 链式调用最佳实践**
994
- ```typescript
995
- // ✅ 推荐:使用 dsl() 包裹获得完整类型推导
996
- const schema = dsl({
997
- email: dsl('email!').label('邮箱').pattern(/custom/)
998
- });
999
-
1000
- // ❌ 不推荐:可能缺少类型提示
1001
- const schema = dsl({
1002
- email: 'email!'.label('邮箱')
1003
- });
1004
- ```
1005
-
1006
- ### Improved (改进)
1007
-
1008
- - 📝 **README 更新**
1009
- - 添加 "1.5 TypeScript 用法" 快速开始章节
1010
- - 添加 TypeScript 使用指南链接
1011
- - 清晰说明 TypeScript 和 JavaScript 的不同用法
76
+ ### v1.1.0 - 跨类型联合验证 🎉
1012
77
 
1013
- - 🔧 **类型定义优化**
1014
- - 修复 `dsl.config` 的 `i18n` 参数类型错误
1015
- - 统一 `DslConfigOptions` 和 `dsl.config` 的类型定义
1016
- - 标记 String 扩展方法为 `@deprecated` for TypeScript
78
+ **发布日期**: 2026-01-05
79
+ **重要性**: ⭐⭐⭐⭐⭐
1017
80
 
1018
- ### Documentation (文档)
81
+ **核心特性**:
82
+ - ✅ 跨类型联合验证(email|phone 可以混合不同类型)
83
+ - ✅ 运行时多语言支持(dsl.error.create 可指定 locale 参数)
84
+ - ✅ 插件系统增强
1019
85
 
1020
- - 📚 新增文档
1021
- - `docs/typescript-guide.md` - TypeScript 使用指南(1000+ 行)
1022
- - `reports/schema-dsl/implementation/dollar-method-implementation-v1.0.4.md` - 实施报告
1023
- - `reports/schema-dsl/summary/typescript-support-completion-v1.0.4.md` - 完成总结
1024
-
1025
- ### Note (重要说明)
1026
-
1027
- - ✅ **100% 向后兼容** - JavaScript 用户无需任何改变
1028
- - ✅ **TypeScript 用户推荐使用 `dsl()` 包裹字符串** 以获得完整类型推导
1029
- - ✅ **所有 API 都有完整的 TypeScript 类型定义**
86
+ **详细信息**: [查看 changelogs/v1.1.0.md](./changelogs/v1.1.0.md)
1030
87
 
1031
88
  ---
1032
89
 
1033
- ## [v1.0.3] - 2025-12-31
1034
-
1035
- ### ⚠️ 破坏性变更 (Breaking Changes)
1036
-
1037
- #### String 单值语法含义变更
1038
-
1039
- **变更内容**: `'string:N'` 的含义从"最大长度"改为"精确长度"
1040
-
1041
- **变更原因**:
1042
- 1. ✅ 更符合直觉 - 验证码、国家代码等常用场景都是精确长度
1043
- 2. ✅ 语义更清晰 - 看到 `'string:6'` 就知道是6位
1044
- 3. ✅ 有替代方案 - 最大长度可用 `'string:-N'`
1045
-
1046
- **影响范围**:
1047
- ```javascript
1048
- // ❌ v1.0.2 及之前
1049
- 'string:10' → maxLength: 10(最大长度)
1050
-
1051
- // ✅ v1.0.3 及之后
1052
- 'string:10' → exactLength: 10(精确长度)
1053
- 'string:-10' → maxLength: 10(最大长度,新语法)
1054
- ```
1055
-
1056
- **迁移指南**:
1057
-
1058
- 1. **如果你的代码使用 `'string:N'` 表示最大长度**:
1059
- ```javascript
1060
- // 旧代码
1061
- bio: 'string:500'
1062
-
1063
- // 新代码(添加 - 前缀)
1064
- bio: 'string:-500'
1065
- ```
1066
-
1067
- 2. **如果你的代码本意就是精确长度**:
1068
- ```javascript
1069
- // 旧代码(行为不符合预期)
1070
- code: 'string:6' // 之前会解析为 maxLength: 6(错误)
1071
-
1072
- // 新代码(现在正确工作)
1073
- code: 'string:6' // 现在正确解析为 exactLength: 6
1074
- ```
1075
-
1076
- **检查方法**:
1077
- ```bash
1078
- # 在项目中搜索所有使用单值语法的地方
1079
- grep -rn "'string:[0-9]\\+['\"]" .
1080
- grep -rn '"string:[0-9]' .
1081
- ```
1082
-
1083
- **受益场景统计**:
1084
- - ✅ 60% 场景更简洁直观(验证码、国家码、邮编等)
1085
- - ⚠️ 20% 场景需要迁移(简介、描述等)
1086
- - ✅ 20% 场景无影响(范围语法)
1087
-
1088
- ### 🔧 修复 (Fixes)
1089
-
1090
- - 修复 String 单值约束语义不直观的问题
1091
- - 统一约束语法规则
1092
- - 完善文档说明
1093
-
1094
- ### 📝 文档 (Documentation)
1095
-
1096
- - 新增约束语法规则说明
1097
- - 新增迁移指南
1098
- - 更新所有示例代码
1099
-
1100
- ### 🆕 新增功能 (Added)
1101
-
1102
- - 新增 `dateGreater()` 链式方法 - 日期大于验证
1103
- - 新增 `dateLess()` 链式方法 - 日期小于验证
1104
-
1105
- ---
1106
-
1107
- ## [v1.0.2] - 2025-12-31
1108
-
1109
- ### 🎉 新增功能 (Added)
1110
-
1111
- #### 验证器扩展 (15 个新增验证器)
90
+ ### v1.0.9 - 多语言支持完善 🌍
1112
91
 
1113
- **String 验证器** (6 个):
1114
- - ✅ **exactLength**: 精确长度验证 - 验证字符串长度必须等于指定值
1115
- - ✅ **alphanum**: 只能包含字母和数字 - 用于用户名、编码等场景
1116
- - ✅ **trim**: 不能包含前后空格 - 用于搜索关键词、API密钥等
1117
- - ✅ **lowercase**: 必须是小写 - 用于邮箱、URL slug等
1118
- - ✅ **uppercase**: 必须是大写 - 用于国家代码、货币代码等
1119
- - ✅ **jsonString**: JSON 字符串验证 - 验证有效的 JSON 格式
92
+ **发布日期**: 2026-01-04
93
+ **重要性**: ⭐⭐⭐⭐
1120
94
 
1121
- **Number 验证器** (2 个):
1122
- - ✅ **precision**: 小数位数限制 - 用于价格、百分比等高精度场景
1123
- - ✅ **port**: 端口号验证 (1-65535) - 用于服务器配置
95
+ **核心特性**:
96
+ - ✅ 完整的多语言支持(5种语言)
97
+ - ✅ TypeScript 类型定义完整
98
+ - ✅ I18nError 多语言错误类
1124
99
 
1125
- **Object 验证器** (2 个):
1126
- - ✅ **requiredAll**: 要求所有定义的属性都存在 - 用于完整性检查
1127
- - ✅ **strictSchema**: 严格模式,不允许额外属性 - 用于API请求验证
1128
-
1129
- **Array 验证器** (2 个):
1130
- - ✅ **noSparse**: 不允许稀疏数组 - 用于批量处理数据
1131
- - ✅ **includesRequired**: 必须包含指定的元素 - 用于权限、标签验证
1132
-
1133
- **Date 验证器** (3 个):
1134
- - ✅ **dateFormat**: 自定义日期格式验证 (支持5种格式: YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY, DD/MM/YYYY, ISO8601)
1135
- - ✅ **dateGreater**: 日期必须大于指定日期 - 用于活动时间范围
1136
- - ✅ **dateLess**: 日期必须小于指定日期 - 用于历史数据验证
1137
-
1138
- **使用示例**:
1139
- ```javascript
1140
- const { dsl, validate } = require('schema-dsl');
1141
-
1142
- // String 验证器
1143
- const schema = {
1144
- code: { type: 'string', exactLength: 6 }, // 验证码
1145
- username: { type: 'string', alphanum: true }, // 用户名
1146
- keyword: { type: 'string', trim: true }, // 搜索关键词
1147
- email: { type: 'string', lowercase: true }, // 邮箱
1148
- countryCode: { type: 'string', uppercase: true }, // 国家代码
1149
- config: { type: 'string', jsonString: true }, // JSON配置
1150
-
1151
- // Number 验证器
1152
- price: { type: 'number', precision: 2 }, // 价格(2位小数)
1153
- port: { type: 'integer', port: true }, // 端口号
1154
-
1155
- // Date 验证器
1156
- birthDate: { type: 'string', dateFormat: 'YYYY-MM-DD' }, // 生日
1157
- endDate: { type: 'string', dateGreater: '2025-01-01' }, // 结束日期
1158
- startDate: { type: 'string', dateLess: '2025-12-31' } // 开始日期
1159
- };
1160
- ```
1161
-
1162
- #### 多语言支持
1163
- - ✅ **中文消息**: 新增 19 个验证消息
1164
- - ✅ **英文消息**: 新增 19 个验证消息
1165
- - ✅ **错误消息键**: 统一使用 string.length, number.precision 等键名
1166
-
1167
- ### 📝 文档 (Documentation)
1168
- - ✅ 新增 `docs/validation-rules-v1.0.2.md` - 15个验证器详细文档(1200行)
1169
- - ✅ 每个验证器包含:用途、参数、错误消息、使用方法、应用场景、最佳实践
1170
- - ✅ 完整的代码示例和验证演示
1171
- - ✅ 组合使用技巧和国际化支持说明
1172
-
1173
- ### 🧪 测试 (Tests)
1174
- - ✅ 新增 `test/unit/validators/CustomKeywords-v1.0.2.test.js`
1175
- - ✅ 75 个单元测试用例,覆盖所有新增验证器
1176
- - ✅ 每个验证器至少 5 个测试用例(正常、边界、错误情况)
1177
- - ✅ 测试覆盖率: 100%
1178
- - ✅ 所有测试通过: 602 passing
1179
-
1180
- ### 📦 示例 (Examples)
1181
- - ⏳ 待补充 `examples/validation-rules-v1.0.2.examples.js`
1182
-
1183
- ### 🔧 技术细节 (Technical Details)
1184
-
1185
- **实现位置**: `lib/validators/CustomKeywords.js`
1186
- - String 验证器: L210-334
1187
- - Number 验证器: L342-389
1188
- - Object 验证器: L397-441
1189
- - Array 验证器: L449-499
1190
- - Date 验证器: L507-608
1191
-
1192
- **错误消息位置**:
1193
- - `lib/locales/zh-CN.js` (126 行)
1194
- - `lib/locales/en-US.js` (126 行)
100
+ **详细信息**: [查看 changelogs/v1.0.9.md](./changelogs/v1.0.9.md)
1195
101
 
1196
102
  ---
1197
103
 
1198
- ## [v1.0.1] - 2025-12-31
1199
-
1200
- ### 🎉 新增功能 (Added)
1201
-
1202
- #### 枚举功能
1203
- - ✅ **字符串枚举**: `'active|inactive|pending'` 简写语法
1204
- - ✅ **布尔值枚举**: `'true|false'` 自动识别为布尔值
1205
- - ✅ **数字枚举**: `'1|2|3'` 自动识别为数字
1206
- - ✅ **整数枚举**: `'enum:integer:1|2|3'` 显式指定整数类型
1207
- - ✅ **小数枚举**: `'1.0|1.5|2.0'` 支持小数值
1208
- - ✅ **必填枚举**: `'active|inactive!'` 支持必填标记
1209
- - ✅ **显式类型**: `'enum:type:values'` 显式指定枚举类型
1210
-
1211
- **使用示例**:
1212
- ```javascript
1213
- const { dsl, validate } = require('schema-dsl');
1214
-
1215
- const schema = dsl({
1216
- // 字符串枚举(自动识别)
1217
- status: 'active|inactive|pending',
1218
-
1219
- // 布尔值枚举(自动识别)
1220
- isPublic: 'true|false',
1221
-
1222
- // 数字枚举(自动识别)
1223
- priority: '1|2|3',
1224
-
1225
- // 整数枚举(显式指定)
1226
- level: 'enum:integer:1|2|3',
1227
-
1228
- // 必填枚举
1229
- role: 'admin|user|guest!'
1230
- });
1231
-
1232
- // 验证
1233
- const result = validate(schema, {
1234
- status: 'active',
1235
- isPublic: true,
1236
- priority: 1,
1237
- level: 2,
1238
- role: 'admin'
1239
- });
1240
- ```
1241
-
1242
- #### 统一错误消息
1243
- - ✅ **统一 'enum' 键**: 所有枚举类型统一使用 `'enum'` 定义错误消息
1244
- - ✅ **简化配置**: 不需要记忆不同类型的错误消息键名
1245
- - ✅ **高级用法**: 支持 `'type.enum'` 格式按类型定制消息(可选)
104
+ ### v1.0.0 - 正式发布 🎉
1246
105
 
1247
- **使用示例**:
1248
- ```javascript
1249
- const schema = dsl({
1250
- status: dsl('active|inactive').messages({
1251
- 'enum': '状态必须是 active 或 inactive' // 统一使用 enum
1252
- })
1253
- });
1254
- ```
106
+ **发布日期**: 2025-12-29
107
+ **重要性**: ⭐⭐⭐⭐⭐
1255
108
 
1256
- ### 📝 文档 (Documentation)
109
+ **核心成就**:
110
+ - ✅ 初始发布
111
+ - ✅ 简洁的DSL语法
112
+ - ✅ 完整的验证功能
1257
113
 
1258
- - **新增 docs/enum.md**: 完整的枚举功能文档(476行)
1259
- - ✅ **更新 README.md**: 添加枚举语法说明
1260
- - ✅ **新增示例**: examples/enum.examples.js(325行,10个示例)
1261
-
1262
- ### ✅ 测试 (Tests)
1263
-
1264
- - ✅ **新增 test/unit/enum.test.js**: 30个枚举测试用例
1265
- - ✅ **测试覆盖**: 字符串/布尔值/数字/整数枚举全覆盖
1266
- - ✅ **错误处理测试**: 无效枚举值、类型不匹配测试
1267
-
1268
- ### 📊 变更统计
1269
-
1270
- - **新增代码**: ~500 行
1271
- - **新增测试**: 30 个
1272
- - **新增文档**: 476 行
1273
- - **新增示例**: 325 行
114
+ **详细信息**: [查看 changelogs/v1.0.0.md](./changelogs/v1.0.0.md)
1274
115
 
1275
116
  ---
1276
117
 
1277
- ## [v1.0.0] - 2025-12-29
1278
-
1279
- ### 🎉 初始发布
1280
-
1281
- #### 核心功能
1282
- - ✅ **DSL 语法**: 简洁的字符串 DSL 定义 Schema
1283
- - `'string:3-32!'` - 字符串长度 3-32,必填
1284
- - `'number:0-100'` - 数字范围 0-100
1285
- - `'email!'` - 邮箱格式,必填
1286
-
1287
- - ✅ **基础类型**: string, number, integer, boolean, object, array, null
1288
-
1289
- - ✅ **格式类型**: email, url, uuid, date, datetime, time, ipv4, ipv6, binary
1290
-
1291
- - ✅ **模式类型**:
1292
- - objectId - MongoDB ObjectId
1293
- - hexColor - 十六进制颜色
1294
- - macAddress - MAC 地址
1295
- - cron - Cron 表达式
1296
- - phone - 手机号(支持多国)
1297
- - idCard - 身份证号
1298
- - creditCard - 信用卡号
1299
- - licensePlate - 车牌号
1300
- - postalCode - 邮政编码
1301
- - passport - 护照号
1302
-
1303
- - ✅ **验证功能**:
1304
- - `validate(schema, data)` - 同步验证
1305
- - `validateAsync(schema, data)` - 异步验证
1306
-
1307
- - ✅ **错误格式化**: 友好的错误消息
1308
-
1309
- - ✅ **多语言支持**: zh-CN, en-US
1310
-
1311
- - ✅ **链式 API**: String 扩展,支持 `.label()`, `.messages()`, `.pattern()` 等
1312
-
1313
- - ✅ **SchemaUtils**: omit, pick, partial, extend 工具方法
1314
-
1315
- #### 文档和测试
1316
- - ✅ **完整文档**: README, API 文档, 示例代码
1317
- - ✅ **测试覆盖**: 447+ 测试用例,覆盖率 >90%
1318
-
1319
- ---
118
+ **完整文档**: [docs/INDEX.md](./docs/INDEX.md)
119
+ **GitHub**: [https://github.com/vextjs/schema-dsl](https://github.com/vextjs/schema-dsl)
120
+ **npm**: [https://www.npmjs.com/package/schema-dsl](https://www.npmjs.com/package/schema-dsl)
1320
121
 
1321
- **更多历史版本信息请参考 Git 提交记录**