schema-dsl 1.0.8 → 1.1.0

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +338 -3
  2. package/README.md +296 -17
  3. package/STATUS.md +74 -3
  4. package/docs/FEATURE-INDEX.md +1 -1
  5. package/docs/add-custom-locale.md +395 -0
  6. package/docs/best-practices.md +3 -3
  7. package/docs/cache-manager.md +1 -1
  8. package/docs/conditional-api.md +1032 -0
  9. package/docs/dsl-syntax.md +1 -1
  10. package/docs/dynamic-locale.md +76 -30
  11. package/docs/error-handling.md +2 -2
  12. package/docs/export-guide.md +2 -2
  13. package/docs/export-limitations.md +3 -3
  14. package/docs/faq.md +6 -6
  15. package/docs/frontend-i18n-guide.md +19 -16
  16. package/docs/i18n-user-guide.md +7 -9
  17. package/docs/i18n.md +65 -2
  18. package/docs/mongodb-exporter.md +3 -3
  19. package/docs/multi-type-support.md +12 -2
  20. package/docs/mysql-exporter.md +1 -1
  21. package/docs/plugin-system.md +4 -4
  22. package/docs/postgresql-exporter.md +1 -1
  23. package/docs/quick-start.md +4 -4
  24. package/docs/troubleshooting.md +2 -2
  25. package/docs/type-reference.md +5 -5
  26. package/docs/typescript-guide.md +5 -6
  27. package/docs/union-type-guide.md +147 -0
  28. package/docs/union-types.md +277 -0
  29. package/docs/validate-async.md +1 -1
  30. package/examples/array-dsl-example.js +1 -1
  31. package/examples/conditional-example.js +288 -0
  32. package/examples/conditional-non-object.js +129 -0
  33. package/examples/conditional-validate-example.js +321 -0
  34. package/examples/union-type-example.js +127 -0
  35. package/examples/union-types-example.js +77 -0
  36. package/index.d.ts +395 -12
  37. package/index.js +31 -4
  38. package/lib/adapters/DslAdapter.js +14 -5
  39. package/lib/core/ConditionalBuilder.js +401 -0
  40. package/lib/core/DslBuilder.js +113 -0
  41. package/lib/core/ErrorFormatter.js +81 -33
  42. package/lib/core/Locale.js +13 -8
  43. package/lib/core/Validator.js +252 -16
  44. package/lib/locales/en-US.js +14 -0
  45. package/lib/locales/es-ES.js +4 -0
  46. package/lib/locales/fr-FR.js +4 -0
  47. package/lib/locales/ja-JP.js +9 -0
  48. package/lib/locales/zh-CN.js +14 -0
  49. package/package.json +5 -2
@@ -0,0 +1,288 @@
1
+ /**
2
+ * ConditionalBuilder 完整示例
3
+ *
4
+ * 展示链式条件构建器的各种用法
5
+ */
6
+
7
+ const { dsl, validate } = require('../index');
8
+
9
+ console.log('========================================');
10
+ console.log('ConditionalBuilder 示例');
11
+ console.log('========================================\n');
12
+
13
+ // ============================================
14
+ // 示例1:简单条件 + 错误消息
15
+ // ============================================
16
+ console.log('【示例1】简单条件 + 错误消息');
17
+ console.log('----------------------------');
18
+
19
+ const schema1 = dsl({
20
+ age: 'number!',
21
+ status: dsl.if((data) => data.age >= 18)
22
+ .message('未成年用户不能注册')
23
+ });
24
+
25
+ const testData1a = { age: 20, status: 'active' };
26
+ const result1a = validate(schema1, testData1a);
27
+ console.log('✅ 成年用户:', result1a.valid ? '验证通过' : '验证失败');
28
+
29
+ const testData1b = { age: 16, status: 'active' };
30
+ const result1b = validate(schema1, testData1b);
31
+ console.log('❌ 未成年用户:', result1b.valid ? '验证通过' : '验证失败');
32
+ if (!result1b.valid) {
33
+ console.log(' 错误消息:', result1b.errors[0].message);
34
+ }
35
+
36
+ // ============================================
37
+ // 示例2:条件 + then/else(动态Schema)
38
+ // ============================================
39
+ console.log('\n【示例2】条件 + then/else(动态Schema)');
40
+ console.log('----------------------------');
41
+
42
+ const schema2 = dsl({
43
+ userType: 'string!',
44
+ email: dsl.if((data) => data.userType === 'admin')
45
+ .then('email!') // 管理员必填
46
+ .else('email') // 普通用户可选
47
+ });
48
+
49
+ const testData2a = { userType: 'admin', email: 'admin@example.com' };
50
+ const result2a = validate(schema2, testData2a);
51
+ console.log('✅ 管理员有邮箱:', result2a.valid ? '验证通过' : '验证失败');
52
+
53
+ const testData2b = { userType: 'admin', email: '' };
54
+ const result2b = validate(schema2, testData2b);
55
+ console.log('❌ 管理员无邮箱:', result2b.valid ? '验证通过' : '验证失败');
56
+
57
+ const testData2c = { userType: 'user', email: '' };
58
+ const result2c = validate(schema2, testData2c);
59
+ console.log('✅ 普通用户无邮箱:', result2c.valid ? '验证通过' : '验证失败');
60
+
61
+ // ============================================
62
+ // 示例3:else 可选(不写 else 就不验证)
63
+ // ============================================
64
+ console.log('\n【示例3】else 可选');
65
+ console.log('----------------------------');
66
+
67
+ const schema3 = dsl({
68
+ userType: 'string!',
69
+ vipLevel: dsl.if((data) => data.userType === 'vip')
70
+ .then('enum:gold|silver|bronze!')
71
+ // 不写 else,非 vip 用户不验证 vipLevel
72
+ });
73
+
74
+ const testData3a = { userType: 'vip', vipLevel: 'gold' };
75
+ const result3a = validate(schema3, testData3a);
76
+ console.log('✅ VIP用户有等级:', result3a.valid ? '验证通过' : '验证失败');
77
+
78
+ const testData3b = { userType: 'user' };
79
+ const result3b = validate(schema3, testData3b);
80
+ console.log('✅ 普通用户无等级:', result3b.valid ? '验证通过' : '验证失败');
81
+
82
+ const testData3c = { userType: 'user', vipLevel: 'invalid_level' };
83
+ const result3c = validate(schema3, testData3c);
84
+ console.log('✅ 普通用户有无效等级:', result3c.valid ? '验证通过(不验证)' : '验证失败');
85
+
86
+ // ============================================
87
+ // 示例4:多条件 AND
88
+ // ============================================
89
+ console.log('\n【示例4】多条件 AND');
90
+ console.log('----------------------------');
91
+
92
+ const schema4 = dsl({
93
+ age: 'number!',
94
+ userType: 'string!',
95
+ email: dsl.if((data) => data.age >= 18)
96
+ .and((data) => data.userType === 'admin')
97
+ .then('email!')
98
+ .else('email')
99
+ });
100
+
101
+ const testData4a = { age: 20, userType: 'admin', email: 'admin@example.com' };
102
+ const result4a = validate(schema4, testData4a);
103
+ console.log('✅ 成年管理员有邮箱:', result4a.valid ? '验证通过' : '验证失败');
104
+
105
+ const testData4b = { age: 20, userType: 'user', email: '' };
106
+ const result4b = validate(schema4, testData4b);
107
+ console.log('✅ 成年普通用户无邮箱:', result4b.valid ? '验证通过' : '验证失败');
108
+
109
+ const testData4c = { age: 16, userType: 'admin', email: '' };
110
+ const result4c = validate(schema4, testData4c);
111
+ console.log('✅ 未成年管理员无邮箱:', result4c.valid ? '验证通过' : '验证失败');
112
+
113
+ // ============================================
114
+ // 示例5:多条件 OR
115
+ // ============================================
116
+ console.log('\n【示例5】多条件 OR');
117
+ console.log('----------------------------');
118
+
119
+ const schema5 = dsl({
120
+ age: 'number!',
121
+ status: 'string!',
122
+ reason: dsl.if((data) => data.age < 18)
123
+ .or((data) => data.status === 'blocked')
124
+ .message('不允许注册')
125
+ });
126
+
127
+ const testData5a = { age: 16, status: 'active', reason: 'test' };
128
+ const result5a = validate(schema5, testData5a);
129
+ console.log('❌ 未成年用户:', result5a.valid ? '验证通过' : `验证失败(${result5a.errors[0].message})`);
130
+
131
+ const testData5b = { age: 20, status: 'blocked', reason: 'test' };
132
+ const result5b = validate(schema5, testData5b);
133
+ console.log('❌ 被封禁用户:', result5b.valid ? '验证通过' : `验证失败(${result5b.errors[0].message})`);
134
+
135
+ const testData5c = { age: 20, status: 'active', reason: 'test' };
136
+ const result5c = validate(schema5, testData5c);
137
+ console.log('✅ 正常用户:', result5c.valid ? '验证通过' : '验证失败');
138
+
139
+ // ============================================
140
+ // 示例6:elseIf 多分支
141
+ // ============================================
142
+ console.log('\n【示例6】elseIf 多分支');
143
+ console.log('----------------------------');
144
+
145
+ const schema6 = dsl({
146
+ userType: 'string!',
147
+ permissions: dsl.if((data) => data.userType === 'admin')
148
+ .then('array<string>!')
149
+ .elseIf((data) => data.userType === 'vip')
150
+ .then('array<string>')
151
+ .else(null)
152
+ });
153
+
154
+ const testData6a = { userType: 'admin', permissions: ['read', 'write'] };
155
+ const result6a = validate(schema6, testData6a);
156
+ console.log('✅ 管理员有权限:', result6a.valid ? '验证通过' : '验证失败');
157
+
158
+ const testData6b = { userType: 'vip' };
159
+ const result6b = validate(schema6, testData6b);
160
+ console.log('✅ VIP无权限:', result6b.valid ? '验证通过' : '验证失败');
161
+
162
+ const testData6c = { userType: 'guest' };
163
+ const result6c = validate(schema6, testData6c);
164
+ console.log('✅ 游客无权限:', result6c.valid ? '验证通过' : '验证失败');
165
+
166
+ // ============================================
167
+ // 示例7:复杂场景 - 用户注册
168
+ // ============================================
169
+ console.log('\n【示例7】复杂场景 - 用户注册');
170
+ console.log('----------------------------');
171
+
172
+ const userRegistrationSchema = dsl({
173
+ username: 'string:3-32!',
174
+ age: 'number:1-120!',
175
+ userType: 'enum:admin|vip|user!',
176
+
177
+ // 未成年禁止注册
178
+ ageCheck: dsl.if((data) => data.age < 18)
179
+ .message('未成年用户不能注册'),
180
+
181
+ // 管理员必须有邮箱
182
+ email: dsl.if((data) => data.userType === 'admin')
183
+ .then('email!')
184
+ .else('email'),
185
+
186
+ // VIP用户必须有手机号
187
+ phone: dsl.if((data) => data.userType === 'vip')
188
+ .then('string:11!')
189
+ .else(null),
190
+
191
+ // 管理员和VIP可以设置昵称
192
+ nickname: dsl.if((data) => data.userType === 'admin')
193
+ .or((data) => data.userType === 'vip')
194
+ .then('string:2-20')
195
+ .else(null)
196
+ });
197
+
198
+ const testData7a = {
199
+ username: 'admin1',
200
+ age: 25,
201
+ userType: 'admin',
202
+ email: 'admin@example.com',
203
+ nickname: 'Super Admin'
204
+ };
205
+ const result7a = validate(userRegistrationSchema, testData7a);
206
+ console.log('✅ 成年管理员:', result7a.valid ? '注册成功' : '注册失败');
207
+
208
+ const testData7b = {
209
+ username: 'vip1',
210
+ age: 30,
211
+ userType: 'vip',
212
+ phone: '13800138000',
213
+ nickname: 'VIP User'
214
+ };
215
+ const result7b = validate(userRegistrationSchema, testData7b);
216
+ console.log('✅ VIP用户:', result7b.valid ? '注册成功' : '注册失败');
217
+
218
+ const testData7c = {
219
+ username: 'kid',
220
+ age: 15,
221
+ userType: 'user'
222
+ };
223
+ const result7c = validate(userRegistrationSchema, testData7c);
224
+ console.log('❌ 未成年用户:', result7c.valid ? '注册成功' : `注册失败(${result7c.errors[0].message})`);
225
+
226
+ // ============================================
227
+ // 示例8:复杂场景 - 商品发布
228
+ // ============================================
229
+ console.log('\n【示例8】复杂场景 - 商品发布');
230
+ console.log('----------------------------');
231
+
232
+ const productSchema = dsl({
233
+ title: 'string:1-100!',
234
+ price: 'number:0-!',
235
+ type: 'enum:physical|digital|service!',
236
+
237
+ // 实体商品需要重量和尺寸
238
+ weight: dsl.if((data) => data.type === 'physical')
239
+ .then('number:0-!')
240
+ .else(null),
241
+
242
+ dimensions: dsl.if((data) => data.type === 'physical')
243
+ .then('string!')
244
+ .else(null),
245
+
246
+ // 数字商品需要下载链接
247
+ downloadUrl: dsl.if((data) => data.type === 'digital')
248
+ .then('url!')
249
+ .else(null),
250
+
251
+ // 服务类需要服务时长
252
+ duration: dsl.if((data) => data.type === 'service')
253
+ .then('number:1-!')
254
+ .else(null)
255
+ });
256
+
257
+ const testData8a = {
258
+ title: '笔记本电脑',
259
+ price: 5999,
260
+ type: 'physical',
261
+ weight: 1.5,
262
+ dimensions: '30x20x2cm'
263
+ };
264
+ const result8a = validate(productSchema, testData8a);
265
+ console.log('✅ 实体商品:', result8a.valid ? '发布成功' : '发布失败');
266
+
267
+ const testData8b = {
268
+ title: '电子书',
269
+ price: 29.9,
270
+ type: 'digital',
271
+ downloadUrl: 'https://example.com/download'
272
+ };
273
+ const result8b = validate(productSchema, testData8b);
274
+ console.log('✅ 数字商品:', result8b.valid ? '发布成功' : '发布失败');
275
+
276
+ const testData8c = {
277
+ title: '咨询服务',
278
+ price: 200,
279
+ type: 'service',
280
+ duration: 60
281
+ };
282
+ const result8c = validate(productSchema, testData8c);
283
+ console.log('✅ 服务类:', result8c.valid ? '发布成功' : '发布失败');
284
+
285
+ console.log('\n========================================');
286
+ console.log('示例运行完成!');
287
+ console.log('========================================');
288
+
@@ -0,0 +1,129 @@
1
+ /**
2
+ * ConditionalBuilder 非对象类型示例
3
+ *
4
+ * 展示如何直接验证字符串、数组、布尔值等非对象类型
5
+ */
6
+
7
+ const { dsl, validate } = require('../index');
8
+
9
+ console.log('========================================');
10
+ console.log('ConditionalBuilder - 非对象类型示例');
11
+ console.log('========================================\n');
12
+
13
+ // ============================================
14
+ // 示例1:直接验证字符串
15
+ // ============================================
16
+ console.log('【示例1】直接验证字符串');
17
+ console.log('----------------------------');
18
+
19
+ const stringSchema = dsl.if((data) => typeof data === 'string' && data.includes('@'))
20
+ .then('email!')
21
+ .else('string:1-50');
22
+
23
+ const r1 = validate(stringSchema, 'test@example.com');
24
+ console.log('✅ 邮箱格式:', r1.valid ? '验证通过' : '验证失败');
25
+
26
+ const r2 = validate(stringSchema, 'just a text');
27
+ console.log('✅ 普通文本:', r2.valid ? '验证通过' : '验证失败');
28
+
29
+ // ============================================
30
+ // 示例2:直接验证数组
31
+ // ============================================
32
+ console.log('\n【示例2】直接验证数组');
33
+ console.log('----------------------------');
34
+
35
+ const arraySchema = dsl.if((data) => Array.isArray(data) && data.length > 5)
36
+ .message('数组最多5个元素');
37
+
38
+ const r3 = validate(arraySchema, [1, 2, 3]);
39
+ console.log('✅ 3个元素:', r3.valid ? '验证通过' : '验证失败');
40
+
41
+ const r4 = validate(arraySchema, [1, 2, 3, 4, 5, 6]);
42
+ console.log('❌ 6个元素:', r4.valid ? '验证通过' : '验证失败');
43
+ if (!r4.valid) {
44
+ console.log(' 错误:', r4.errors[0].message);
45
+ }
46
+
47
+ // ============================================
48
+ // 示例3:直接验证数字
49
+ // ============================================
50
+ console.log('\n【示例3】直接验证数字');
51
+ console.log('----------------------------');
52
+
53
+ const numberSchema = dsl.if((data) => typeof data === 'number' && data < 0)
54
+ .message('不允许负数')
55
+ .else(null); // 不需要额外验证
56
+
57
+ const r5 = validate(numberSchema, 10);
58
+ console.log('✅ 正数:', r5.valid ? '验证通过' : '验证失败');
59
+
60
+ const r6 = validate(numberSchema, -5);
61
+ console.log('❌ 负数:', r6.valid ? '验证通过' : '验证失败');
62
+ if (!r6.valid) {
63
+ console.log(' 错误:', r6.errors[0].message);
64
+ }
65
+
66
+ // ============================================
67
+ // 示例4:字符串类型判断(邮箱或手机号)
68
+ // ============================================
69
+ console.log('\n【示例4】自动识别邮箱或手机号');
70
+ console.log('----------------------------');
71
+
72
+ const contactSchema = dsl.if((data) => typeof data === 'string' && data.includes('@'))
73
+ .then('email!')
74
+ .else('string:11!');
75
+
76
+ const r7 = validate(contactSchema, 'user@example.com');
77
+ console.log('✅ 邮箱:', r7.valid ? '验证通过' : '验证失败');
78
+
79
+ const r8 = validate(contactSchema, '13800138000');
80
+ console.log('✅ 手机号:', r8.valid ? '验证通过' : '验证失败');
81
+
82
+ const r9 = validate(contactSchema, 'invalid');
83
+ console.log('❌ 无效输入:', r9.valid ? '验证通过' : '验证失败');
84
+ if (!r9.valid) {
85
+ console.log(' 错误:', r9.errors[0].message);
86
+ }
87
+
88
+ // ============================================
89
+ // 示例5:复杂条件组合
90
+ // ============================================
91
+ console.log('\n【示例5】字符串长度 + 内容组合判断');
92
+ console.log('----------------------------');
93
+
94
+ const complexSchema = dsl.if((data) => typeof data === 'string' && data.length > 20)
95
+ .and((data) => data.includes('@'))
96
+ .then('email!')
97
+ .else('string:1-50');
98
+
99
+ const r10 = validate(complexSchema, 'short');
100
+ console.log('✅ 短字符串:', r10.valid ? '验证通过' : '验证失败');
101
+
102
+ const r11 = validate(complexSchema, 'this-is-a-long-email@example.com');
103
+ console.log('✅ 长邮箱:', r11.valid ? '验证通过' : '验证失败');
104
+
105
+ const r12 = validate(complexSchema, 'this is a very long string without at symbol');
106
+ console.log('✅ 长文本(无@):', r12.valid ? '验证通过' : '验证失败');
107
+
108
+ // ============================================
109
+ // 示例6:边界值处理
110
+ // ============================================
111
+ console.log('\n【示例6】边界值处理');
112
+ console.log('----------------------------');
113
+
114
+ const boundarySchema = dsl.if((data) => data === null || data === undefined || data === '')
115
+ .message('值不能为空');
116
+
117
+ const r13 = validate(boundarySchema, 'valid value');
118
+ console.log('✅ 有效值:', r13.valid ? '验证通过' : '验证失败');
119
+
120
+ const r14 = validate(boundarySchema, '');
121
+ console.log('❌ 空字符串:', r14.valid ? '验证通过' : '验证失败');
122
+ if (!r14.valid) {
123
+ console.log(' 错误:', r14.errors[0].message);
124
+ }
125
+
126
+ console.log('\n========================================');
127
+ console.log('示例运行完成!');
128
+ console.log('========================================');
129
+