schema-dsl 1.1.6 → 1.1.7

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,7 +1,7 @@
1
1
  # 变更日志 (CHANGELOG)
2
2
 
3
3
  > **说明**: 版本概览摘要,详细变更见 [changelogs/](./changelogs/) 目录
4
- > **最后更新**: 2026-01-23
4
+ > **最后更新**: 2026-01-27
5
5
 
6
6
  ---
7
7
 
@@ -9,6 +9,7 @@
9
9
 
10
10
  | 版本 | 日期 | 变更摘要 | 详细 |
11
11
  |------|------|---------|------|
12
+ | [v1.1.7](./changelogs/v1.1.7.md) | 2026-01-27 | 🐛 Bug修复:错误消息路径显示优化 - 所有错误类型的 message 只显示字段名 | [查看](./changelogs/v1.1.7.md) |
12
13
  | [v1.1.6](./changelogs/v1.1.6.md) | 2026-01-23 | 🐛 Bug修复:enum和additionalProperties错误消息模板变量未替换 | [查看](./changelogs/v1.1.6.md) |
13
14
  | [v1.1.5](./changelogs/v1.1.5.md) | 2026-01-17 | 🚀 新功能:错误配置对象格式支持 - 语言包支持 `{ code, message }` 对象格式 | [查看](./changelogs/v1.1.5.md) |
14
15
  | [v1.1.4](./changelogs/v1.1.4.md) | 2026-01-13 | 🔧 TypeScript类型修复:移除重复函数签名 + 多语言文档完善 | [查看](./changelogs/v1.1.4.md) |
@@ -28,7 +29,7 @@
28
29
  | [v1.0.0](./changelogs/v1.0.0.md) | 2025-12-29 | 初始发布版本 | [查看](./changelogs/v1.0.0.md) |
29
30
 
30
31
  > 💡 **提示**: 重要版本的详细变更记录在 [changelogs/](./changelogs/) 目录中。
31
- > 当前已有详细文档的版本:v1.1.6, v1.1.5, v1.1.4, v1.1.3, v1.1.2, v1.1.1, v1.1.0, v1.0.9, v1.0.0
32
+ > 当前已有详细文档的版本:v1.1.7, v1.1.6, v1.1.5, v1.1.4, v1.1.3, v1.1.2, v1.1.1, v1.1.0, v1.0.9, v1.0.0
32
33
  > 其他版本的详细变更信息请参考项目提交历史或联系维护者。
33
34
 
34
35
  ---
@@ -37,13 +38,31 @@
37
38
 
38
39
  | 版本系列 | 版本数 | 主要改进方向 |
39
40
  |---------|-------|------------|
40
- | v1.1.x | 7 | Bug修复、错误配置增强、TypeScript类型完善、多语言支持、数字运算符、联合类型 |
41
+ | v1.1.x | 8 | Bug修复、错误消息优化、错误配置增强、TypeScript类型完善、多语言支持、数字运算符、联合类型 |
41
42
  | v1.0.x | 10 | 核心功能、验证器、测试覆盖、文档完善 |
42
43
 
43
44
  ---
44
45
 
45
46
  ## 里程碑版本
46
47
 
48
+ ### v1.1.7 - 错误消息路径显示优化 🐛
49
+
50
+ **发布日期**: 2026-01-27
51
+ **重要性**: ⭐⭐⭐⭐
52
+
53
+ **主要改进**:
54
+ - 🐛 修复嵌套对象错误消息显示完整路径的问题(如 `user/profile/age should be number` → `age should be number`)
55
+ - ✅ 统一所有错误类型的 label 生成逻辑,message 只显示字段名而非完整路径
56
+ - ✅ path 保留完整路径用于定位(符合 JSON Pointer RFC 6901 标准)
57
+ - ✅ 修复范围:required、type、minLength、maxLength、pattern、format、enum、minimum、maximum、minItems、maxItems、additionalProperties 等所有错误类型
58
+ - ✅ 新增 6 个测试用例,测试总数 983 个
59
+
60
+ **技术细节**:
61
+ - 修改文件:`lib/core/ErrorFormatter.js`
62
+ - 从完整路径中提取最后一级字段名作为 label
63
+ - 遵循 JSON Pointer (RFC 6901) 标准使用 `/` 作为路径分隔符
64
+ - 测试修复:添加 `beforeEach` 钩子重置语言为英文,避免测试污染
65
+
47
66
  ### v1.1.6 - ErrorFormatter Bug修复 🐛
48
67
 
49
68
  **发布日期**: 2026-01-23
@@ -0,0 +1,317 @@
1
+ # v1.1.7 - 错误消息路径显示优化
2
+
3
+ **发布日期**: 2026-01-27
4
+ **类型**: Bug修复 🐛
5
+ **重要性**: ⭐⭐⭐⭐
6
+
7
+ ---
8
+
9
+ ## 📋 概述
10
+
11
+ 本次更新修复了嵌套对象错误消息中显示完整路径的问题,提升了错误消息的可读性和友好性。
12
+
13
+ **核心改进**:
14
+ - 错误消息 (`message`) 现在只显示字段名,而不是完整路径
15
+ - 错误路径 (`path`) 保留完整路径用于定位
16
+ - 统一所有错误类型的处理逻辑
17
+
18
+ ---
19
+
20
+ ## 🐛 问题描述
21
+
22
+ ### 修复前
23
+
24
+ 嵌套对象的错误消息包含完整路径,冗长且不友好:
25
+
26
+ ```javascript
27
+ {
28
+ path: 'user/profile/age',
29
+ message: 'user/profile/age should be number, got string', // ❌ 包含完整路径
30
+ keyword: 'type'
31
+ }
32
+ ```
33
+
34
+ ### 修复后
35
+
36
+ 错误消息只显示字段名,更加简洁友好:
37
+
38
+ ```javascript
39
+ {
40
+ path: 'user/profile/age', // ✅ 保留完整路径用于定位
41
+ message: 'age should be number, got string', // ✅ 只显示字段名
42
+ keyword: 'type'
43
+ }
44
+ ```
45
+
46
+ ---
47
+
48
+ ## 🔧 修复内容
49
+
50
+ ### 1. 修复范围
51
+
52
+ 修改了 `lib/core/ErrorFormatter.js`,优化了所有错误类型的 label 生成逻辑:
53
+
54
+ **修复的错误类型**(全覆盖):
55
+ - ✅ `required` - 缺少必填字段
56
+ - ✅ `type` - 类型不匹配
57
+ - ✅ `minLength`/`maxLength` - 字符串长度限制
58
+ - ✅ `pattern`/`format` - 格式验证
59
+ - ✅ `enum` - 枚举验证
60
+ - ✅ `minimum`/`maximum` - 数值范围
61
+ - ✅ `minItems`/`maxItems` - 数组长度
62
+ - ✅ `additionalProperties` - 额外属性
63
+ - ✅ 所有其他 ajv 错误类型
64
+
65
+ ### 2. 技术实现
66
+
67
+ #### 修复1:正确处理 required 错误的字段路径(第139-158行)
68
+
69
+ ```javascript
70
+ let fieldName;
71
+ if (keyword === 'required' && err.params && err.params.missingProperty) {
72
+ // required 错误:字段名应该是父路径 + 缺失属性
73
+ const parentPath = instancePath.replace(/^\//, '');
74
+ const missingProp = err.params.missingProperty;
75
+ fieldName = parentPath ? `${parentPath}/${missingProp}` : missingProp;
76
+ } else {
77
+ // 其他错误:直接使用 instancePath
78
+ fieldName = instancePath.replace(/^\//, '') || 'value';
79
+ }
80
+ ```
81
+
82
+ #### 修复2:统一优化所有错误类型的 label 生成(第160-185行)
83
+
84
+ ```javascript
85
+ let labelKey;
86
+ if (keyword === 'required' && err.params && err.params.missingProperty) {
87
+ // required 错误:使用 missingProperty(缺失的字段名)
88
+ labelKey = err.params.missingProperty;
89
+ } else {
90
+ // 其他错误:从完整路径中提取最后一级字段名
91
+ // 例如: "user/profile/age" -> "age"
92
+ // "user/scores/1" -> "1"
93
+ const parts = fieldName.split('/');
94
+ labelKey = parts[parts.length - 1];
95
+ }
96
+ ```
97
+
98
+ ---
99
+
100
+ ## 📊 修复效果对比
101
+
102
+ | 场景 | path(定位) | message(修复前) | message(修复后) |
103
+ |------|-------------|------------------|------------------|
104
+ | 顶层必填 | `name` | `name is required` | `name is required` ✅ |
105
+ | 嵌套必填 | `project/project_id` | `project is required` ❌ | `project_id is required` ✅ |
106
+ | 类型错误 | `user/profile/age` | `user/profile/age should be number` ❌ | `age should be number` ✅ |
107
+ | 长度错误 | `user/profile/username` | `user/profile/username must be at least 3` ❌ | `username must be at least 3` ✅ |
108
+ | 格式错误 | `user/contact/email` | `user/contact/email must be valid` ❌ | `email must be valid` ✅ |
109
+ | 枚举错误 | `user/settings/theme` | `user/settings/theme must be one of: ...` ❌ | `theme must be one of: ...` ✅ |
110
+ | 数组元素 | `user/scores/1` | `user/scores/1 should be number` ❌ | `1 should be number` ✅ |
111
+
112
+ ---
113
+
114
+ ## 🧪 测试
115
+
116
+ ### 新增测试
117
+
118
+ 创建了 `test/unit/required-error-fix.test.js`,包含 **6 个测试用例**:
119
+
120
+ 1. ✅ 顶层必填字段:应该显示正确的错误消息
121
+ 2. ✅ 嵌套对象必填字段:path 应该是完整路径,message 只显示字段名
122
+ 3. ✅ 多层嵌套必填字段:应该显示正确的路径和消息
123
+ 4. ✅ 对象本身是必填:应该显示正确的消息
124
+ 5. ✅ 同时缺少多个字段:每个错误应该正确显示
125
+ 6. ✅ 用户提供的真实场景:应该正确处理
126
+
127
+ ### 测试修复
128
+
129
+ **问题**:npm test 失败,但单独运行测试通过
130
+
131
+ **原因**:其他测试修改了全局语言设置(`Locale.setLocale('zh-CN')`),导致测试污染
132
+
133
+ **解决方案**:添加 `beforeEach` 钩子,在每个测试前重置语言为英文
134
+
135
+ ```javascript
136
+ beforeEach(function() {
137
+ Locale.setLocale('en-US');
138
+ });
139
+ ```
140
+
141
+ ### 测试结果
142
+
143
+ - ✅ **983 个测试全部通过**(新增 6 个)
144
+ - ✅ 无回归问题
145
+ - ✅ 覆盖所有错误类型
146
+
147
+ ---
148
+
149
+ ## 📝 路径分隔符说明
150
+
151
+ ### 为什么使用 `/` 而不是 `.`?
152
+
153
+ **回答**:遵循 **JSON Pointer (RFC 6901)** 标准
154
+
155
+ #### 对比分析
156
+
157
+ | 使用 `/`(JSON Pointer) | 使用 `.`(JavaScript 风格) |
158
+ |-------------------------|---------------------------|
159
+ | ✅ 符合 RFC 6901 标准 | ❌ 不是标准格式 |
160
+ | ✅ 与 ajv 原始格式一致 | ❌ 需要额外转换 |
161
+ | ✅ 支持包含 `.` 的字段名 | ❌ 无法区分字段名中的 `.` 和分隔符 |
162
+ | ✅ JSON Schema 生态系统通用 | ❌ 可能与其他工具不兼容 |
163
+
164
+ #### 示例对比
165
+
166
+ ```javascript
167
+ // ✅ 使用 / (JSON Pointer 标准)
168
+ path: "user/profile/age" // 清晰
169
+ path: "config/version" // 明确
170
+ path: "api/v1.2.3/endpoint" // 字段名包含 . 也没问题
171
+
172
+ // ❌ 使用 . (JavaScript 风格)
173
+ path: "user.profile.age" // 非标准
174
+ path: "api.v1.2.3.endpoint" // 歧义!无法区分
175
+ ```
176
+
177
+ #### AJV 原始格式
178
+
179
+ ```javascript
180
+ {
181
+ instancePath: "/user/profile", // ajv 使用 /
182
+ schemaPath: "#/properties/user/properties/profile/required"
183
+ }
184
+ ```
185
+
186
+ **参考**:
187
+ - [RFC 6901 - JSON Pointer](https://datatracker.ietf.org/doc/html/rfc6901)
188
+ - [JSON Schema](https://json-schema.org/)
189
+ - [AJV - JSON Schema Validator](https://ajv.js.org/)
190
+
191
+ ---
192
+
193
+ ## 💡 使用示例
194
+
195
+ ### 基本用法
196
+
197
+ ```javascript
198
+ const { dsl } = require('schema-dsl');
199
+
200
+ const schema = dsl({
201
+ user: {
202
+ profile: {
203
+ age: "number!"
204
+ }
205
+ }
206
+ });
207
+
208
+ const result = dsl.validate(schema, {
209
+ user: {
210
+ profile: {
211
+ age: "not a number" // 类型错误
212
+ }
213
+ }
214
+ });
215
+
216
+ if (!result.valid) {
217
+ console.log(result.errors[0]);
218
+ // {
219
+ // path: 'user/profile/age', // 完整路径,用于定位
220
+ // message: 'age should be number', // 友好提示,只显示字段名
221
+ // keyword: 'type'
222
+ // }
223
+ }
224
+ ```
225
+
226
+ ### 嵌套对象必填字段
227
+
228
+ ```javascript
229
+ const schema = dsl({
230
+ project: {
231
+ project_id: "objectId!",
232
+ trip_id: "objectId!"
233
+ }
234
+ });
235
+
236
+ const result = dsl.validate(schema, {
237
+ project: {
238
+ // 缺少 project_id
239
+ trip_id: "69771ab94d7ff6963d1e93ff"
240
+ }
241
+ });
242
+
243
+ console.log(result.errors[0]);
244
+ // {
245
+ // path: 'project/project_id', // ✅ 完整路径
246
+ // message: 'project_id is required', // ✅ 只显示字段名
247
+ // keyword: 'required'
248
+ // }
249
+ ```
250
+
251
+ ---
252
+
253
+ ## 🔄 升级指南
254
+
255
+ ### 破坏性变更
256
+
257
+ ❌ **无破坏性变更**
258
+
259
+ ### 兼容性
260
+
261
+ ✅ **完全向后兼容**
262
+
263
+ - `path` 仍然包含完整路径
264
+ - `message` 格式更友好(只影响显示)
265
+ - 所有 API 保持不变
266
+
267
+ ### 升级步骤
268
+
269
+ ```bash
270
+ npm install schema-dsl@1.1.7
271
+ ```
272
+
273
+ 无需修改代码,直接升级即可。
274
+
275
+ ---
276
+
277
+ ## 📦 修改文件清单
278
+
279
+ 1. **lib/core/ErrorFormatter.js** - 核心修复
280
+ - 优化 `fieldName` 生成逻辑(第139-158行)
281
+ - 优化 `label` 生成逻辑(第160-185行)
282
+
283
+ 2. **test/unit/required-error-fix.test.js** - 新增测试
284
+ - 新增 6 个测试用例
285
+ - 添加 `beforeEach` 钩子避免测试污染
286
+
287
+ 3. **CHANGELOG.md** - 更新变更日志
288
+ - 添加 v1.1.7 版本信息
289
+
290
+ 4. **changelogs/v1.1.7.md** - 详细变更文档(本文件)
291
+
292
+ 5. **package.json** - 版本号更新为 1.1.7
293
+
294
+ ---
295
+
296
+ ## 📚 相关资源
297
+
298
+ - **修复总结文档**: [ERROR-MESSAGE-FIX-SUMMARY.md](../ERROR-MESSAGE-FIX-SUMMARY.md)
299
+ - **测试脚本**: `test-all-errors.js`(验证所有错误类型)
300
+ - **GitHub Issue**: 用户反馈的嵌套对象错误消息问题
301
+
302
+ ---
303
+
304
+ ## 🙏 致谢
305
+
306
+ 感谢用户反馈此问题,帮助我们改进错误消息的可读性!
307
+
308
+ ---
309
+
310
+ **下一步计划**:
311
+ - 继续优化错误消息格式
312
+ - 完善多语言支持
313
+ - 提升测试覆盖率
314
+
315
+ **完整变更日志**: [CHANGELOG.md](../CHANGELOG.md)
316
+ **GitHub**: [https://github.com/vextjs/schema-dsl](https://github.com/vextjs/schema-dsl)
317
+ **npm**: [https://www.npmjs.com/package/schema-dsl](https://www.npmjs.com/package/schema-dsl)