schema-dsl 1.1.5 → 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 +34 -3
- package/changelogs/v1.1.6.md +211 -0
- package/changelogs/v1.1.7.md +317 -0
- package/docs/best-practices-project-structure.md +408 -0
- package/docs/issues-resolved-summary.md +196 -0
- package/docs/performance-quick-reference.md +123 -0
- package/docs/user-questions-answered.md +353 -0
- package/docs/validate-dsl-object-support.md +573 -0
- package/lib/adapters/DslAdapter.js +94 -7
- package/lib/core/ErrorFormatter.js +34 -5
- package/lib/locales/en-US.js +2 -0
- package/lib/locales/es-ES.js +2 -0
- package/lib/locales/fr-FR.js +2 -0
- package/lib/locales/ja-JP.js +2 -0
- package/lib/locales/zh-CN.js +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 变更日志 (CHANGELOG)
|
|
2
2
|
|
|
3
3
|
> **说明**: 版本概览摘要,详细变更见 [changelogs/](./changelogs/) 目录
|
|
4
|
-
> **最后更新**: 2026-01-
|
|
4
|
+
> **最后更新**: 2026-01-27
|
|
5
5
|
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -9,6 +9,8 @@
|
|
|
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) |
|
|
13
|
+
| [v1.1.6](./changelogs/v1.1.6.md) | 2026-01-23 | 🐛 Bug修复:enum和additionalProperties错误消息模板变量未替换 | [查看](./changelogs/v1.1.6.md) |
|
|
12
14
|
| [v1.1.5](./changelogs/v1.1.5.md) | 2026-01-17 | 🚀 新功能:错误配置对象格式支持 - 语言包支持 `{ code, message }` 对象格式 | [查看](./changelogs/v1.1.5.md) |
|
|
13
15
|
| [v1.1.4](./changelogs/v1.1.4.md) | 2026-01-13 | 🔧 TypeScript类型修复:移除重复函数签名 + 多语言文档完善 | [查看](./changelogs/v1.1.4.md) |
|
|
14
16
|
| [v1.1.3](./changelogs/v1.1.3.md) | 2026-01-09 | 🐛 Bug修复:类型错误消息模板变量未替换 | [查看](./changelogs/v1.1.3.md) |
|
|
@@ -27,7 +29,7 @@
|
|
|
27
29
|
| [v1.0.0](./changelogs/v1.0.0.md) | 2025-12-29 | 初始发布版本 | [查看](./changelogs/v1.0.0.md) |
|
|
28
30
|
|
|
29
31
|
> 💡 **提示**: 重要版本的详细变更记录在 [changelogs/](./changelogs/) 目录中。
|
|
30
|
-
> 当前已有详细文档的版本: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
|
|
31
33
|
> 其他版本的详细变更信息请参考项目提交历史或联系维护者。
|
|
32
34
|
|
|
33
35
|
---
|
|
@@ -36,13 +38,42 @@
|
|
|
36
38
|
|
|
37
39
|
| 版本系列 | 版本数 | 主要改进方向 |
|
|
38
40
|
|---------|-------|------------|
|
|
39
|
-
| v1.1.x |
|
|
41
|
+
| v1.1.x | 8 | Bug修复、错误消息优化、错误配置增强、TypeScript类型完善、多语言支持、数字运算符、联合类型 |
|
|
40
42
|
| v1.0.x | 10 | 核心功能、验证器、测试覆盖、文档完善 |
|
|
41
43
|
|
|
42
44
|
---
|
|
43
45
|
|
|
44
46
|
## 里程碑版本
|
|
45
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
|
+
|
|
66
|
+
### v1.1.6 - ErrorFormatter Bug修复 🐛
|
|
67
|
+
|
|
68
|
+
**发布日期**: 2026-01-23
|
|
69
|
+
**重要性**: ⭐⭐⭐⭐
|
|
70
|
+
|
|
71
|
+
**主要改进**:
|
|
72
|
+
- 🐛 修复 enum 错误消息模板变量 `{{#valids}}` 未替换问题
|
|
73
|
+
- 🐛 修复 additionalProperties 错误消息缺少属性名问题
|
|
74
|
+
- ✅ 新增完整的错误消息插值测试(14个测试用例)
|
|
75
|
+
- ✅ 确保所有 ajv 错误参数正确映射到模板变量
|
|
76
|
+
|
|
46
77
|
### v1.1.5 - 错误配置对象格式支持 🚀
|
|
47
78
|
|
|
48
79
|
**发布日期**: 2026-01-17
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
# v1.1.6 - Bug修复与测试增强
|
|
2
|
+
|
|
3
|
+
**发布日期**: 2026-01-23
|
|
4
|
+
|
|
5
|
+
## 🐛 Bug 修复
|
|
6
|
+
|
|
7
|
+
### ErrorFormatter - 参数映射完整性修复
|
|
8
|
+
|
|
9
|
+
修复了 `ErrorFormatter` 中 ajv 错误参数映射不完整的问题,**支持所有5种内置语言**(en-US, zh-CN, es-ES, fr-FR, ja-JP),确保所有模板变量都能正确替换。
|
|
10
|
+
|
|
11
|
+
#### 1. **修复 enum 错误消息中的模板变量未替换问题** 🔴
|
|
12
|
+
|
|
13
|
+
**问题描述**:
|
|
14
|
+
- 当 enum 验证失败时,错误消息显示 `"must be one of: {{#valids}}"`
|
|
15
|
+
- 模板变量 `{{#valids}}` 没有被实际的枚举值替换
|
|
16
|
+
|
|
17
|
+
**根本原因**:
|
|
18
|
+
- ajv 返回的 enum 错误参数字段名是 `allowedValues`
|
|
19
|
+
- 错误消息模板使用的是 `{{#valids}}` 和 `{{#allowed}}`
|
|
20
|
+
- ErrorFormatter 没有将 `allowedValues` 映射到这两个变量
|
|
21
|
+
|
|
22
|
+
**修复方案**:
|
|
23
|
+
```javascript
|
|
24
|
+
// lib/core/ErrorFormatter.js
|
|
25
|
+
const interpolateData = {
|
|
26
|
+
...err.params,
|
|
27
|
+
// ... 其他映射
|
|
28
|
+
// ✅ 修复 enum 错误:将 allowedValues 映射为 valids 和 allowed
|
|
29
|
+
valids: err.params && err.params.allowedValues ? err.params.allowedValues.join(', ') : undefined,
|
|
30
|
+
allowed: err.params && err.params.allowedValues ? err.params.allowedValues.join(', ') : undefined
|
|
31
|
+
};
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
**修复效果**:
|
|
35
|
+
- 修复前: `"plan_type must be one of: {{#valids}}"`
|
|
36
|
+
- 修复后: `"plan_type must be one of: pro, basic, free"`
|
|
37
|
+
|
|
38
|
+
#### 2. **修复 additionalProperties 错误消息参数映射**
|
|
39
|
+
|
|
40
|
+
**问题描述**:
|
|
41
|
+
- additionalProperties 错误消息应该显示未知属性名,但实际没有
|
|
42
|
+
|
|
43
|
+
**根本原因**:
|
|
44
|
+
- ajv 返回的参数字段名是 `additionalProperty`
|
|
45
|
+
- 模板使用的是 `{{#key}}`
|
|
46
|
+
- ErrorFormatter 没有映射,且语言包中缺少 additionalProperties 的消息模板
|
|
47
|
+
|
|
48
|
+
**修复方案**:
|
|
49
|
+
1. 在 ErrorFormatter 中添加参数映射:
|
|
50
|
+
```javascript
|
|
51
|
+
// ✅ 修复 additionalProperties 错误:将 additionalProperty 映射为 key
|
|
52
|
+
key: err.params && err.params.additionalProperty ? err.params.additionalProperty : undefined
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
2. 在**所有5种内置语言包**中添加消息模板:
|
|
56
|
+
```javascript
|
|
57
|
+
// lib/locales/en-US.js (英文)
|
|
58
|
+
'additionalProperties': '{{#label}} must NOT have additional properties: {{#key}}'
|
|
59
|
+
|
|
60
|
+
// lib/locales/zh-CN.js (中文)
|
|
61
|
+
'additionalProperties': '{{#label}}不允许有额外属性: {{#key}}'
|
|
62
|
+
|
|
63
|
+
// lib/locales/es-ES.js (西班牙语)
|
|
64
|
+
'additionalProperties': '{{#label}} NO debe tener propiedades adicionales: {{#key}}'
|
|
65
|
+
|
|
66
|
+
// lib/locales/fr-FR.js (法语)
|
|
67
|
+
'additionalProperties': '{{#label}} NE doit PAS avoir de propriétés supplémentaires : {{#key}}'
|
|
68
|
+
|
|
69
|
+
// lib/locales/ja-JP.js (日语)
|
|
70
|
+
'additionalProperties': '{{#label}}に追加のプロパティを含めてはいけません: {{#key}}'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
**修复效果**:
|
|
74
|
+
- 修复前: `"must NOT have additional properties"`
|
|
75
|
+
- 修复后: `"value must NOT have additional properties: email"`
|
|
76
|
+
|
|
77
|
+
## ✅ 测试增强
|
|
78
|
+
|
|
79
|
+
### 新增错误消息插值完整性测试
|
|
80
|
+
|
|
81
|
+
创建了完整的测试套件,全面验证所有错误类型和所有语言的参数映射:
|
|
82
|
+
|
|
83
|
+
#### 1. 基础参数映射测试 (`test/unit/error-message-interpolation.test.js`)
|
|
84
|
+
**测试覆盖**:
|
|
85
|
+
- ✅ enum 错误消息(必填/可选/数字枚举/中文)
|
|
86
|
+
- ✅ additionalProperties 错误消息
|
|
87
|
+
- ✅ required 错误消息
|
|
88
|
+
- ✅ minLength/maxLength 错误消息
|
|
89
|
+
- ✅ minimum/maximum 错误消息
|
|
90
|
+
- ✅ type 错误消息
|
|
91
|
+
- ✅ minItems/maxItems 错误消息
|
|
92
|
+
- ✅ format 错误消息
|
|
93
|
+
- ✅ 多语言支持(中文/英文)
|
|
94
|
+
|
|
95
|
+
#### 2. 多语言完整性测试 (`test/unit/multi-language-error-messages.test.js`)
|
|
96
|
+
**测试覆盖**:
|
|
97
|
+
- ✅ enum 错误消息 - 所有5种语言(en-US, zh-CN, es-ES, fr-FR, ja-JP)
|
|
98
|
+
- ✅ additionalProperties 错误消息 - 所有5种语言
|
|
99
|
+
- ✅ 验证每种语言的模板变量都正确替换
|
|
100
|
+
- ✅ 验证每种语言的错误消息都包含必要信息
|
|
101
|
+
|
|
102
|
+
#### 3. 三轮深度检查 (`test-three-rounds-check.js`)
|
|
103
|
+
**第一轮 - 所有ajv错误类型验证**(16个错误类型):
|
|
104
|
+
- ✅ required, minLength, maxLength, minimum, maximum
|
|
105
|
+
- ✅ enum, pattern, format, type
|
|
106
|
+
- ✅ minItems, maxItems, minProperties, maxProperties
|
|
107
|
+
- ✅ additionalProperties, uniqueItems, const
|
|
108
|
+
|
|
109
|
+
**第二轮 - 边界情况和极端值**(10个测试):
|
|
110
|
+
- ✅ 空字符串枚举、超长枚举列表(100个值)
|
|
111
|
+
- ✅ 数字0作为枚举值、null作为枚举值
|
|
112
|
+
- ✅ undefined作为数据、非常深的嵌套对象
|
|
113
|
+
- ✅ 包含特殊字符的属性名(`user-name`, `user.email`)
|
|
114
|
+
- ✅ 极大数值(MAX_SAFE_INTEGER)、极小数值(MIN_SAFE_INTEGER)
|
|
115
|
+
- ✅ Infinity值
|
|
116
|
+
|
|
117
|
+
**第三轮 - 多语言一致性**(4个场景 × 5种语言 = 20个测试):
|
|
118
|
+
- ✅ enum错误 - 所有语言正确
|
|
119
|
+
- ✅ additionalProperties错误 - 所有语言正确
|
|
120
|
+
- ✅ required错误 - 所有语言正确
|
|
121
|
+
- ✅ type错误 - 所有语言正确
|
|
122
|
+
- ✅ minItems/maxItems 错误消息
|
|
123
|
+
- ✅ format 错误消息
|
|
124
|
+
- ✅ 多语言支持(中文/英文)
|
|
125
|
+
|
|
126
|
+
**测试原则**:
|
|
127
|
+
- 不仅验证验证结果(valid: true/false)
|
|
128
|
+
- 还验证错误消息内容是否正确
|
|
129
|
+
- 确保所有模板变量都被正确替换
|
|
130
|
+
- 确保不包含未替换的模板语法(如 `{{#xxx}}`)
|
|
131
|
+
|
|
132
|
+
## 🔍 为什么之前的单元测试没有测试到?
|
|
133
|
+
|
|
134
|
+
### 问题分析
|
|
135
|
+
|
|
136
|
+
1. **现有测试只验证验证结果,不验证错误消息**:
|
|
137
|
+
- 现有的 enum 测试(`test/unit/enum.test.js`)只检查 `result.valid === false`
|
|
138
|
+
- 没有检查 `error.message` 的具体内容
|
|
139
|
+
- 因此即使错误消息包含未替换的模板变量,测试也会通过
|
|
140
|
+
|
|
141
|
+
2. **缺少专门的错误消息格式化测试**:
|
|
142
|
+
- ErrorFormatter 的测试覆盖不够全面
|
|
143
|
+
- 没有验证所有 ajv 错误参数类型的映射
|
|
144
|
+
|
|
145
|
+
### 改进措施
|
|
146
|
+
|
|
147
|
+
新增的测试确保:
|
|
148
|
+
- ✅ 所有错误消息都检查实际内容
|
|
149
|
+
- ✅ 验证枚举值是否正确显示
|
|
150
|
+
- ✅ 验证模板变量是否完全替换
|
|
151
|
+
- ✅ 覆盖所有 ajv 错误类型的参数映射
|
|
152
|
+
|
|
153
|
+
## 📝 变更文件
|
|
154
|
+
|
|
155
|
+
### 核心修复 (6个文件)
|
|
156
|
+
- `lib/core/ErrorFormatter.js` - 添加 enum 和 additionalProperties 参数映射
|
|
157
|
+
- `lib/locales/en-US.js` - 添加 additionalProperties 错误消息模板
|
|
158
|
+
- `lib/locales/zh-CN.js` - 添加 additionalProperties 错误消息模板
|
|
159
|
+
- `lib/locales/es-ES.js` - 添加 additionalProperties 错误消息模板 🆕
|
|
160
|
+
- `lib/locales/fr-FR.js` - 添加 additionalProperties 错误消息模板 🆕
|
|
161
|
+
- `lib/locales/ja-JP.js` - 添加 additionalProperties 错误消息模板 🆕
|
|
162
|
+
|
|
163
|
+
### 测试增强 (3个文件)
|
|
164
|
+
- `test/unit/error-message-interpolation.test.js` - 基础参数映射测试(14个测试)
|
|
165
|
+
- `test/unit/multi-language-error-messages.test.js` - 多语言完整性测试(10个测试)🆕
|
|
166
|
+
- `test-three-rounds-check.js` - 三轮深度检查脚本(30个检查项)🆕
|
|
167
|
+
|
|
168
|
+
## 🔄 向后兼容性
|
|
169
|
+
|
|
170
|
+
✅ **完全向后兼容**
|
|
171
|
+
- 只是修复了错误消息显示的Bug,不影响验证逻辑
|
|
172
|
+
- 所有现有API保持不变
|
|
173
|
+
- 所有现有测试(967个)全部通过
|
|
174
|
+
- 新增10个多语言测试,总计977个测试全部通过
|
|
175
|
+
|
|
176
|
+
## 📊 测试覆盖
|
|
177
|
+
|
|
178
|
+
- **原测试数**: 967个
|
|
179
|
+
- **新增测试**: 10个(多语言完整性测试)
|
|
180
|
+
- **总测试数**: 977个
|
|
181
|
+
- **通过率**: 100%
|
|
182
|
+
- **深度检查**: 30个检查项全部通过
|
|
183
|
+
|
|
184
|
+
## 🎯 影响范围
|
|
185
|
+
|
|
186
|
+
### 受益场景
|
|
187
|
+
1. 所有使用 enum 验证的场景
|
|
188
|
+
2. 使用 additionalProperties: false 的场景
|
|
189
|
+
3. 需要准确错误消息的场景
|
|
190
|
+
4. 多语言国际化场景
|
|
191
|
+
|
|
192
|
+
### 用户体验改进
|
|
193
|
+
- ✅ 错误消息更清晰明确
|
|
194
|
+
- ✅ 枚举值正确显示,用户知道可选值
|
|
195
|
+
- ✅ 额外属性名正确显示,用户知道哪个字段不该提交
|
|
196
|
+
- ✅ 多语言错误消息更准确
|
|
197
|
+
|
|
198
|
+
## 🔗 相关Issue
|
|
199
|
+
|
|
200
|
+
无(内部发现的Bug)
|
|
201
|
+
|
|
202
|
+
## 📚 文档更新
|
|
203
|
+
|
|
204
|
+
无需文档更新(只是Bug修复)
|
|
205
|
+
|
|
206
|
+
---
|
|
207
|
+
|
|
208
|
+
**升级建议**:
|
|
209
|
+
- 建议所有用户升级到 v1.1.6
|
|
210
|
+
- 无需修改任何代码
|
|
211
|
+
- 仅需执行 `npm update schema-dsl`
|
|
@@ -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)
|