befly 3.9.38 → 3.9.40

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 (155) hide show
  1. package/README.md +37 -38
  2. package/befly.config.ts +62 -40
  3. package/checks/checkApi.ts +16 -16
  4. package/checks/checkApp.ts +19 -25
  5. package/checks/checkTable.ts +42 -42
  6. package/docs/README.md +42 -35
  7. package/docs/{api.md → api/api.md} +223 -231
  8. package/docs/cipher.md +71 -69
  9. package/docs/database.md +143 -141
  10. package/docs/{examples.md → guide/examples.md} +181 -181
  11. package/docs/guide/quickstart.md +331 -0
  12. package/docs/hooks/auth.md +38 -0
  13. package/docs/hooks/cors.md +28 -0
  14. package/docs/{hook.md → hooks/hook.md} +140 -57
  15. package/docs/hooks/parser.md +19 -0
  16. package/docs/hooks/rateLimit.md +47 -0
  17. package/docs/{redis.md → infra/redis.md} +84 -93
  18. package/docs/plugins/cipher.md +61 -0
  19. package/docs/plugins/database.md +128 -0
  20. package/docs/{plugin.md → plugins/plugin.md} +83 -81
  21. package/docs/quickstart.md +26 -26
  22. package/docs/{addon.md → reference/addon.md} +46 -46
  23. package/docs/{config.md → reference/config.md} +32 -80
  24. package/docs/{logger.md → reference/logger.md} +52 -52
  25. package/docs/{sync.md → reference/sync.md} +32 -35
  26. package/docs/{table.md → reference/table.md} +1 -1
  27. package/docs/{validator.md → reference/validator.md} +57 -57
  28. package/hooks/auth.ts +8 -4
  29. package/hooks/cors.ts +13 -13
  30. package/hooks/parser.ts +37 -17
  31. package/hooks/permission.ts +26 -14
  32. package/hooks/rateLimit.ts +276 -0
  33. package/hooks/validator.ts +8 -8
  34. package/lib/asyncContext.ts +43 -0
  35. package/lib/cacheHelper.ts +212 -77
  36. package/lib/cacheKeys.ts +38 -0
  37. package/lib/cipher.ts +30 -30
  38. package/lib/connect.ts +28 -28
  39. package/lib/dbHelper.ts +183 -102
  40. package/lib/jwt.ts +16 -16
  41. package/lib/logger.ts +610 -19
  42. package/lib/redisHelper.ts +185 -44
  43. package/lib/sqlBuilder.ts +90 -91
  44. package/lib/validator.ts +59 -39
  45. package/loader/loadApis.ts +48 -44
  46. package/loader/loadHooks.ts +40 -14
  47. package/loader/loadPlugins.ts +16 -17
  48. package/main.ts +57 -47
  49. package/package.json +47 -45
  50. package/paths.ts +15 -14
  51. package/plugins/cache.ts +5 -4
  52. package/plugins/cipher.ts +3 -3
  53. package/plugins/config.ts +2 -2
  54. package/plugins/db.ts +9 -9
  55. package/plugins/jwt.ts +3 -3
  56. package/plugins/logger.ts +8 -12
  57. package/plugins/redis.ts +8 -8
  58. package/plugins/tool.ts +6 -6
  59. package/router/api.ts +85 -56
  60. package/router/static.ts +12 -12
  61. package/sync/syncAll.ts +12 -12
  62. package/sync/syncApi.ts +55 -52
  63. package/sync/syncDb/apply.ts +20 -19
  64. package/sync/syncDb/constants.ts +25 -23
  65. package/sync/syncDb/ddl.ts +35 -36
  66. package/sync/syncDb/helpers.ts +6 -9
  67. package/sync/syncDb/schema.ts +10 -9
  68. package/sync/syncDb/sqlite.ts +7 -8
  69. package/sync/syncDb/table.ts +37 -35
  70. package/sync/syncDb/tableCreate.ts +21 -20
  71. package/sync/syncDb/types.ts +23 -20
  72. package/sync/syncDb/version.ts +10 -10
  73. package/sync/syncDb.ts +43 -36
  74. package/sync/syncDev.ts +74 -65
  75. package/sync/syncMenu.ts +190 -55
  76. package/tests/api-integration-array-number.test.ts +282 -0
  77. package/tests/befly-config-env.test.ts +78 -0
  78. package/tests/cacheHelper.test.ts +135 -104
  79. package/tests/cacheKeys.test.ts +41 -0
  80. package/tests/cipher.test.ts +90 -89
  81. package/tests/dbHelper-advanced.test.ts +140 -134
  82. package/tests/dbHelper-all-array-types.test.ts +316 -0
  83. package/tests/dbHelper-array-serialization.test.ts +258 -0
  84. package/tests/dbHelper-columns.test.ts +56 -55
  85. package/tests/dbHelper-execute.test.ts +45 -44
  86. package/tests/dbHelper-joins.test.ts +124 -119
  87. package/tests/fields-redis-cache.test.ts +29 -27
  88. package/tests/fields-validate.test.ts +38 -38
  89. package/tests/getClientIp.test.ts +54 -0
  90. package/tests/integration.test.ts +69 -67
  91. package/tests/jwt.test.ts +27 -26
  92. package/tests/logger.test.ts +267 -34
  93. package/tests/rateLimit-hook.test.ts +477 -0
  94. package/tests/redisHelper.test.ts +187 -188
  95. package/tests/redisKeys.test.ts +6 -73
  96. package/tests/scanConfig.test.ts +144 -0
  97. package/tests/sqlBuilder-advanced.test.ts +217 -215
  98. package/tests/sqlBuilder.test.ts +92 -91
  99. package/tests/sync-connection.test.ts +29 -29
  100. package/tests/syncDb-apply.test.ts +97 -96
  101. package/tests/syncDb-array-number.test.ts +160 -0
  102. package/tests/syncDb-constants.test.ts +48 -47
  103. package/tests/syncDb-ddl.test.ts +99 -98
  104. package/tests/syncDb-helpers.test.ts +29 -28
  105. package/tests/syncDb-schema.test.ts +61 -60
  106. package/tests/syncDb-types.test.ts +60 -59
  107. package/tests/syncMenu-paths.test.ts +68 -0
  108. package/tests/util.test.ts +42 -41
  109. package/tests/validator-array-number.test.ts +310 -0
  110. package/tests/validator-default.test.ts +373 -0
  111. package/tests/validator.test.ts +271 -266
  112. package/tsconfig.json +4 -5
  113. package/types/api.d.ts +7 -12
  114. package/types/befly.d.ts +60 -13
  115. package/types/cache.d.ts +8 -4
  116. package/types/common.d.ts +17 -9
  117. package/types/context.d.ts +2 -2
  118. package/types/crypto.d.ts +23 -0
  119. package/types/database.d.ts +19 -19
  120. package/types/hook.d.ts +2 -2
  121. package/types/jwt.d.ts +118 -0
  122. package/types/logger.d.ts +30 -0
  123. package/types/plugin.d.ts +4 -4
  124. package/types/redis.d.ts +7 -3
  125. package/types/roleApisCache.ts +23 -0
  126. package/types/sync.d.ts +10 -10
  127. package/types/table.d.ts +50 -9
  128. package/types/validate.d.ts +69 -0
  129. package/utils/addonHelper.ts +90 -0
  130. package/utils/arrayKeysToCamel.ts +18 -0
  131. package/utils/calcPerfTime.ts +13 -0
  132. package/utils/configTypes.ts +3 -0
  133. package/utils/cors.ts +19 -0
  134. package/utils/fieldClear.ts +75 -0
  135. package/utils/genShortId.ts +12 -0
  136. package/utils/getClientIp.ts +45 -0
  137. package/utils/keysToCamel.ts +22 -0
  138. package/utils/keysToSnake.ts +22 -0
  139. package/utils/modules.ts +98 -0
  140. package/utils/pickFields.ts +19 -0
  141. package/utils/process.ts +56 -0
  142. package/utils/regex.ts +225 -0
  143. package/utils/response.ts +115 -0
  144. package/utils/route.ts +23 -0
  145. package/utils/scanConfig.ts +142 -0
  146. package/utils/scanFiles.ts +48 -0
  147. package/.prettierignore +0 -2
  148. package/.prettierrc +0 -12
  149. package/docs/1-/345/237/272/346/234/254/344/273/213/347/273/215.md +0 -35
  150. package/docs/2-/345/210/235/346/255/245/344/275/223/351/252/214.md +0 -64
  151. package/docs/3-/347/254/254/344/270/200/344/270/252/346/216/245/345/217/243.md +0 -46
  152. package/docs/4-/346/223/215/344/275/234/346/225/260/346/215/256/345/272/223.md +0 -172
  153. package/hooks/requestLogger.ts +0 -84
  154. package/types/index.ts +0 -24
  155. package/util.ts +0 -283
@@ -3,15 +3,16 @@
3
3
  * 测试静态类方法、返回结构、各种验证场景
4
4
  */
5
5
 
6
- import { describe, test, expect } from 'bun:test';
7
- import { Validator } from '../lib/validator';
6
+ import { describe, test, expect } from "bun:test";
7
+
8
+ import { Validator } from "../lib/validator";
8
9
 
9
10
  // ========== 返回结构测试 ==========
10
11
 
11
- describe('Validator.validate - 返回结构', () => {
12
- test('验证通过时返回正确结构', () => {
13
- const data = { name: 'test' };
14
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 10 } };
12
+ describe("Validator.validate - 返回结构", () => {
13
+ test("验证通过时返回正确结构", () => {
14
+ const data = { name: "test" };
15
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 10 } };
15
16
 
16
17
  const result = Validator.validate(data, rules);
17
18
 
@@ -23,9 +24,9 @@ describe('Validator.validate - 返回结构', () => {
23
24
  expect(result.fieldErrors).toEqual({});
24
25
  });
25
26
 
26
- test('验证失败时返回正确结构', () => {
27
- const data = { name: 'a' };
28
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 10 } };
27
+ test("验证失败时返回正确结构", () => {
28
+ const data = { name: "a" };
29
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 10 } };
29
30
 
30
31
  const result = Validator.validate(data, rules);
31
32
 
@@ -33,15 +34,15 @@ describe('Validator.validate - 返回结构', () => {
33
34
  expect(result.failed).toBe(true);
34
35
  expect(result.firstError).toBeDefined();
35
36
  expect(result.errors.length).toBeGreaterThan(0);
36
- expect(result.errorFields).toContain('name');
37
+ expect(result.errorFields).toContain("name");
37
38
  expect(result.fieldErrors.name).toBeDefined();
38
39
  });
39
40
 
40
- test('多字段错误时返回所有错误', () => {
41
- const data = { name: 'a', age: 200 };
41
+ test("多字段错误时返回所有错误", () => {
42
+ const data = { name: "a", age: 200 };
42
43
  const rules = {
43
- name: { name: '名称', type: 'string', min: 2, max: 10 },
44
- age: { name: '年龄', type: 'number', min: 0, max: 150 }
44
+ name: { name: "名称", type: "string", min: 2, max: 10 },
45
+ age: { name: "年龄", type: "number", min: 0, max: 150 }
45
46
  };
46
47
 
47
48
  const result = Validator.validate(data, rules);
@@ -49,183 +50,183 @@ describe('Validator.validate - 返回结构', () => {
49
50
  expect(result.code).toBe(1);
50
51
  expect(result.errors.length).toBe(2);
51
52
  expect(result.errorFields.length).toBe(2);
52
- expect(result.errorFields).toContain('name');
53
- expect(result.errorFields).toContain('age');
53
+ expect(result.errorFields).toContain("name");
54
+ expect(result.errorFields).toContain("age");
54
55
  });
55
56
  });
56
57
 
57
58
  // ========== 参数检查测试 ==========
58
59
 
59
- describe('Validator.validate - 参数检查', () => {
60
- test('data 为 null', () => {
60
+ describe("Validator.validate - 参数检查", () => {
61
+ test("data 为 null", () => {
61
62
  const result = Validator.validate(null as any, {});
62
63
 
63
64
  expect(result.code).toBe(1);
64
- expect(result.firstError).toContain('对象格式');
65
+ expect(result.firstError).toContain("对象格式");
65
66
  });
66
67
 
67
- test('data 为 undefined', () => {
68
+ test("data 为 undefined", () => {
68
69
  const result = Validator.validate(undefined as any, {});
69
70
 
70
71
  expect(result.code).toBe(1);
71
- expect(result.firstError).toContain('对象格式');
72
+ expect(result.firstError).toContain("对象格式");
72
73
  });
73
74
 
74
- test('data 为数组', () => {
75
+ test("data 为数组", () => {
75
76
  const result = Validator.validate([] as any, {});
76
77
 
77
78
  expect(result.code).toBe(1);
78
- expect(result.firstError).toContain('对象格式');
79
+ expect(result.firstError).toContain("对象格式");
79
80
  });
80
81
 
81
- test('data 为字符串', () => {
82
- const result = Validator.validate('string' as any, {});
82
+ test("data 为字符串", () => {
83
+ const result = Validator.validate("string" as any, {});
83
84
 
84
85
  expect(result.code).toBe(1);
85
- expect(result.firstError).toContain('对象格式');
86
+ expect(result.firstError).toContain("对象格式");
86
87
  });
87
88
 
88
- test('rules 为 null', () => {
89
+ test("rules 为 null", () => {
89
90
  const result = Validator.validate({}, null as any);
90
91
 
91
92
  expect(result.code).toBe(1);
92
- expect(result.firstError).toContain('对象格式');
93
+ expect(result.firstError).toContain("对象格式");
93
94
  });
94
95
 
95
- test('rules 为 undefined', () => {
96
+ test("rules 为 undefined", () => {
96
97
  const result = Validator.validate({}, undefined as any);
97
98
 
98
99
  expect(result.code).toBe(1);
99
- expect(result.firstError).toContain('对象格式');
100
+ expect(result.firstError).toContain("对象格式");
100
101
  });
101
102
  });
102
103
 
103
104
  // ========== 必填字段测试 ==========
104
105
 
105
- describe('Validator.validate - 必填字段', () => {
106
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 20 } };
106
+ describe("Validator.validate - 必填字段", () => {
107
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 20 } };
107
108
 
108
- test('字段存在且有值 - 通过', () => {
109
- const result = Validator.validate({ name: 'test' }, rules, ['name']);
109
+ test("字段存在且有值 - 通过", () => {
110
+ const result = Validator.validate({ name: "test" }, rules, ["name"]);
110
111
  expect(result.code).toBe(0);
111
112
  });
112
113
 
113
- test('字段不存在 - 失败', () => {
114
- const result = Validator.validate({}, rules, ['name']);
114
+ test("字段不存在 - 失败", () => {
115
+ const result = Validator.validate({}, rules, ["name"]);
115
116
  expect(result.code).toBe(1);
116
- expect(result.fieldErrors.name).toContain('必填项');
117
+ expect(result.fieldErrors.name).toContain("必填项");
117
118
  });
118
119
 
119
- test('字段值为空字符串 - 失败', () => {
120
- const result = Validator.validate({ name: '' }, rules, ['name']);
120
+ test("字段值为空字符串 - 失败", () => {
121
+ const result = Validator.validate({ name: "" }, rules, ["name"]);
121
122
  expect(result.code).toBe(1);
122
- expect(result.fieldErrors.name).toContain('必填项');
123
+ expect(result.fieldErrors.name).toContain("必填项");
123
124
  });
124
125
 
125
- test('字段值为 null - 失败', () => {
126
- const result = Validator.validate({ name: null }, rules, ['name']);
126
+ test("字段值为 null - 失败", () => {
127
+ const result = Validator.validate({ name: null }, rules, ["name"]);
127
128
  expect(result.code).toBe(1);
128
- expect(result.fieldErrors.name).toContain('必填项');
129
+ expect(result.fieldErrors.name).toContain("必填项");
129
130
  });
130
131
 
131
- test('字段值为 undefined - 失败', () => {
132
- const result = Validator.validate({ name: undefined }, rules, ['name']);
132
+ test("字段值为 undefined - 失败", () => {
133
+ const result = Validator.validate({ name: undefined }, rules, ["name"]);
133
134
  expect(result.code).toBe(1);
134
- expect(result.fieldErrors.name).toContain('必填项');
135
+ expect(result.fieldErrors.name).toContain("必填项");
135
136
  });
136
137
 
137
- test('多个必填字段全部缺失', () => {
138
+ test("多个必填字段全部缺失", () => {
138
139
  const multiRules = {
139
- name: { name: '名称', type: 'string', min: 2, max: 20 },
140
- email: { name: '邮箱', type: 'string', regexp: '@email' }
140
+ name: { name: "名称", type: "string", min: 2, max: 20 },
141
+ email: { name: "邮箱", type: "string", regexp: "@email" }
141
142
  };
142
143
 
143
- const result = Validator.validate({}, multiRules, ['name', 'email']);
144
+ const result = Validator.validate({}, multiRules, ["name", "email"]);
144
145
 
145
146
  expect(result.code).toBe(1);
146
147
  expect(result.errors.length).toBe(2);
147
- expect(result.fieldErrors.name).toContain('必填项');
148
- expect(result.fieldErrors.email).toContain('必填项');
148
+ expect(result.fieldErrors.name).toContain("必填项");
149
+ expect(result.fieldErrors.email).toContain("必填项");
149
150
  });
150
151
 
151
- test('必填字段使用字段标签', () => {
152
- const result = Validator.validate({}, rules, ['name']);
153
- expect(result.firstError).toContain('名称');
152
+ test("必填字段使用字段标签", () => {
153
+ const result = Validator.validate({}, rules, ["name"]);
154
+ expect(result.firstError).toContain("名称");
154
155
  });
155
156
 
156
- test('必填字段无标签时使用字段名', () => {
157
- const noLabelRules = { name: { type: 'string', min: 2, max: 20 } };
158
- const result = Validator.validate({}, noLabelRules, ['name']);
159
- expect(result.firstError).toContain('name');
157
+ test("必填字段无标签时使用字段名", () => {
158
+ const noLabelRules = { name: { type: "string", min: 2, max: 20 } };
159
+ const result = Validator.validate({}, noLabelRules, ["name"]);
160
+ expect(result.firstError).toContain("name");
160
161
  });
161
162
  });
162
163
 
163
164
  // ========== string 类型测试 ==========
164
165
 
165
- describe('Validator.validate - string 类型', () => {
166
- test('有效字符串 - 通过', () => {
167
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 10 } };
168
- const result = Validator.validate({ name: 'test' }, rules);
166
+ describe("Validator.validate - string 类型", () => {
167
+ test("有效字符串 - 通过", () => {
168
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 10 } };
169
+ const result = Validator.validate({ name: "test" }, rules);
169
170
  expect(result.code).toBe(0);
170
171
  });
171
172
 
172
- test('非字符串类型 - 失败', () => {
173
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 10 } };
173
+ test("非字符串类型 - 失败", () => {
174
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 10 } };
174
175
  const result = Validator.validate({ name: 123 }, rules);
175
176
  expect(result.code).toBe(1);
176
- expect(result.firstError).toContain('字符串');
177
+ expect(result.firstError).toContain("字符串");
177
178
  });
178
179
 
179
- test('长度小于 min - 失败', () => {
180
- const rules = { name: { name: '名称', type: 'string', min: 5, max: 20 } };
181
- const result = Validator.validate({ name: 'abc' }, rules);
180
+ test("长度小于 min - 失败", () => {
181
+ const rules = { name: { name: "名称", type: "string", min: 5, max: 20 } };
182
+ const result = Validator.validate({ name: "abc" }, rules);
182
183
  expect(result.code).toBe(1);
183
- expect(result.firstError).toContain('5');
184
+ expect(result.firstError).toContain("5");
184
185
  });
185
186
 
186
- test('长度等于 min - 通过', () => {
187
- const rules = { name: { name: '名称', type: 'string', min: 3, max: 20 } };
188
- const result = Validator.validate({ name: 'abc' }, rules);
187
+ test("长度等于 min - 通过", () => {
188
+ const rules = { name: { name: "名称", type: "string", min: 3, max: 20 } };
189
+ const result = Validator.validate({ name: "abc" }, rules);
189
190
  expect(result.code).toBe(0);
190
191
  });
191
192
 
192
- test('长度大于 max - 失败', () => {
193
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 5 } };
194
- const result = Validator.validate({ name: 'abcdefg' }, rules);
193
+ test("长度大于 max - 失败", () => {
194
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 5 } };
195
+ const result = Validator.validate({ name: "abcdefg" }, rules);
195
196
  expect(result.code).toBe(1);
196
- expect(result.firstError).toContain('5');
197
+ expect(result.firstError).toContain("5");
197
198
  });
198
199
 
199
- test('长度等于 max - 通过', () => {
200
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 5 } };
201
- const result = Validator.validate({ name: 'abcde' }, rules);
200
+ test("长度等于 max - 通过", () => {
201
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 5 } };
202
+ const result = Validator.validate({ name: "abcde" }, rules);
202
203
  expect(result.code).toBe(0);
203
204
  });
204
205
 
205
- test('中文字符按字符数计算', () => {
206
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 5 } };
207
- const result = Validator.validate({ name: '你好世界' }, rules); // 4 个字符
206
+ test("中文字符按字符数计算", () => {
207
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 5 } };
208
+ const result = Validator.validate({ name: "你好世界" }, rules); // 4 个字符
208
209
  expect(result.code).toBe(0);
209
210
  });
210
211
 
211
- test('max 为 0 时不检查最大长度', () => {
212
- const rules = { name: { name: '名称', type: 'string', min: 0, max: 0 } };
213
- const result = Validator.validate({ name: 'a'.repeat(1000) }, rules);
212
+ test("max 为 0 时不检查最大长度", () => {
213
+ const rules = { name: { name: "名称", type: "string", min: 0, max: 0 } };
214
+ const result = Validator.validate({ name: "a".repeat(1000) }, rules);
214
215
  expect(result.code).toBe(0);
215
216
  });
216
217
  });
217
218
 
218
219
  // ========== text 类型测试 ==========
219
220
 
220
- describe('Validator.validate - text 类型', () => {
221
- test('text 类型与 string 类型行为一致', () => {
222
- const rules = { content: { name: '内容', type: 'text', min: 2, max: 100 } };
223
- const result = Validator.validate({ content: 'hello world' }, rules);
221
+ describe("Validator.validate - text 类型", () => {
222
+ test("text 类型与 string 类型行为一致", () => {
223
+ const rules = { content: { name: "内容", type: "text", min: 2, max: 100 } };
224
+ const result = Validator.validate({ content: "hello world" }, rules);
224
225
  expect(result.code).toBe(0);
225
226
  });
226
227
 
227
- test('text 类型非字符串 - 失败', () => {
228
- const rules = { content: { name: '内容', type: 'text', min: 2, max: 100 } };
228
+ test("text 类型非字符串 - 失败", () => {
229
+ const rules = { content: { name: "内容", type: "text", min: 2, max: 100 } };
229
230
  const result = Validator.validate({ content: 123 }, rules);
230
231
  expect(result.code).toBe(1);
231
232
  });
@@ -233,90 +234,90 @@ describe('Validator.validate - text 类型', () => {
233
234
 
234
235
  // ========== number 类型测试 ==========
235
236
 
236
- describe('Validator.validate - number 类型', () => {
237
- test('有效数字 - 通过', () => {
238
- const rules = { age: { name: '年龄', type: 'number', min: 0, max: 150 } };
237
+ describe("Validator.validate - number 类型", () => {
238
+ test("有效数字 - 通过", () => {
239
+ const rules = { age: { name: "年龄", type: "number", min: 0, max: 150 } };
239
240
  const result = Validator.validate({ age: 25 }, rules);
240
241
  expect(result.code).toBe(0);
241
242
  });
242
243
 
243
- test('字符串数字自动转换 - 通过', () => {
244
- const rules = { age: { name: '年龄', type: 'number', min: 0, max: 150 } };
245
- const result = Validator.validate({ age: '25' }, rules);
244
+ test("字符串数字自动转换 - 通过", () => {
245
+ const rules = { age: { name: "年龄", type: "number", min: 0, max: 150 } };
246
+ const result = Validator.validate({ age: "25" }, rules);
246
247
  expect(result.code).toBe(0);
247
248
  });
248
249
 
249
- test('非数字字符串 - 失败', () => {
250
- const rules = { age: { name: '年龄', type: 'number', min: 0, max: 150 } };
251
- const result = Validator.validate({ age: 'abc' }, rules);
250
+ test("非数字字符串 - 失败", () => {
251
+ const rules = { age: { name: "年龄", type: "number", min: 0, max: 150 } };
252
+ const result = Validator.validate({ age: "abc" }, rules);
252
253
  expect(result.code).toBe(1);
253
- expect(result.firstError).toContain('数字');
254
+ expect(result.firstError).toContain("数字");
254
255
  });
255
256
 
256
- test('NaN - 失败', () => {
257
- const rules = { age: { name: '年龄', type: 'number', min: 0, max: 150 } };
257
+ test("NaN - 失败", () => {
258
+ const rules = { age: { name: "年龄", type: "number", min: 0, max: 150 } };
258
259
  const result = Validator.validate({ age: NaN }, rules);
259
260
  expect(result.code).toBe(1);
260
261
  });
261
262
 
262
- test('Infinity - 失败', () => {
263
- const rules = { value: { name: '', type: 'number', min: 0, max: 100 } };
263
+ test("Infinity - 失败", () => {
264
+ const rules = { value: { name: "", type: "number", min: 0, max: 100 } };
264
265
  const result = Validator.validate({ value: Infinity }, rules);
265
266
  expect(result.code).toBe(1);
266
267
  });
267
268
 
268
- test('-Infinity - 失败', () => {
269
- const rules = { value: { name: '', type: 'number', min: 0, max: 100 } };
269
+ test("-Infinity - 失败", () => {
270
+ const rules = { value: { name: "", type: "number", min: 0, max: 100 } };
270
271
  const result = Validator.validate({ value: -Infinity }, rules);
271
272
  expect(result.code).toBe(1);
272
273
  });
273
274
 
274
- test('0 是有效值', () => {
275
- const rules = { count: { name: '计数', type: 'number', min: 0, max: 100 } };
275
+ test("0 是有效值", () => {
276
+ const rules = { count: { name: "计数", type: "number", min: 0, max: 100 } };
276
277
  const result = Validator.validate({ count: 0 }, rules);
277
278
  expect(result.code).toBe(0);
278
279
  });
279
280
 
280
- test('负数范围验证', () => {
281
- const rules = { temp: { name: '温度', type: 'number', min: -50, max: 50 } };
281
+ test("负数范围验证", () => {
282
+ const rules = { temp: { name: "温度", type: "number", min: -50, max: 50 } };
282
283
  const result = Validator.validate({ temp: -30 }, rules);
283
284
  expect(result.code).toBe(0);
284
285
  });
285
286
 
286
- test('小于 min - 失败', () => {
287
- const rules = { age: { name: '年龄', type: 'number', min: 18, max: 100 } };
287
+ test("小于 min - 失败", () => {
288
+ const rules = { age: { name: "年龄", type: "number", min: 18, max: 100 } };
288
289
  const result = Validator.validate({ age: 10 }, rules);
289
290
  expect(result.code).toBe(1);
290
- expect(result.firstError).toContain('18');
291
+ expect(result.firstError).toContain("18");
291
292
  });
292
293
 
293
- test('等于 min - 通过', () => {
294
- const rules = { age: { name: '年龄', type: 'number', min: 18, max: 100 } };
294
+ test("等于 min - 通过", () => {
295
+ const rules = { age: { name: "年龄", type: "number", min: 18, max: 100 } };
295
296
  const result = Validator.validate({ age: 18 }, rules);
296
297
  expect(result.code).toBe(0);
297
298
  });
298
299
 
299
- test('大于 max - 失败', () => {
300
- const rules = { age: { name: '年龄', type: 'number', min: 0, max: 100 } };
300
+ test("大于 max - 失败", () => {
301
+ const rules = { age: { name: "年龄", type: "number", min: 0, max: 100 } };
301
302
  const result = Validator.validate({ age: 150 }, rules);
302
303
  expect(result.code).toBe(1);
303
- expect(result.firstError).toContain('100');
304
+ expect(result.firstError).toContain("100");
304
305
  });
305
306
 
306
- test('等于 max - 通过', () => {
307
- const rules = { age: { name: '年龄', type: 'number', min: 0, max: 100 } };
307
+ test("等于 max - 通过", () => {
308
+ const rules = { age: { name: "年龄", type: "number", min: 0, max: 100 } };
308
309
  const result = Validator.validate({ age: 100 }, rules);
309
310
  expect(result.code).toBe(0);
310
311
  });
311
312
 
312
- test('浮点数', () => {
313
- const rules = { price: { name: '价格', type: 'number', min: 0, max: 1000 } };
313
+ test("浮点数", () => {
314
+ const rules = { price: { name: "价格", type: "number", min: 0, max: 1000 } };
314
315
  const result = Validator.validate({ price: 99.99 }, rules);
315
316
  expect(result.code).toBe(0);
316
317
  });
317
318
 
318
- test('max 为 0 时不检查最大值', () => {
319
- const rules = { value: { name: '', type: 'number', min: 0, max: 0 } };
319
+ test("max 为 0 时不检查最大值", () => {
320
+ const rules = { value: { name: "", type: "number", min: 0, max: 0 } };
320
321
  const result = Validator.validate({ value: 999999 }, rules);
321
322
  expect(result.code).toBe(0);
322
323
  });
@@ -324,143 +325,147 @@ describe('Validator.validate - number 类型', () => {
324
325
 
325
326
  // ========== array_string 类型测试 ==========
326
327
 
327
- describe('Validator.validate - array_string 类型', () => {
328
- test('有效数组 - 通过', () => {
329
- const rules = { tags: { name: '标签', type: 'array_string', min: 1, max: 5 } };
330
- const result = Validator.validate({ tags: ['a', 'b', 'c'] }, rules);
328
+ describe("Validator.validate - array_string 类型", () => {
329
+ test("有效数组 - 通过", () => {
330
+ const rules = { tags: { name: "标签", type: "array_string", min: 1, max: 5 } };
331
+ const result = Validator.validate({ tags: ["a", "b", "c"] }, rules);
331
332
  expect(result.code).toBe(0);
332
333
  });
333
334
 
334
- test('非数组类型 - 失败', () => {
335
- const rules = { tags: { name: '标签', type: 'array_string', min: 1, max: 5 } };
336
- const result = Validator.validate({ tags: 'not array' }, rules);
335
+ test("非数组类型 - 失败", () => {
336
+ const rules = { tags: { name: "标签", type: "array_string", min: 1, max: 5 } };
337
+ const result = Validator.validate({ tags: "not array" }, rules);
337
338
  expect(result.code).toBe(1);
338
- expect(result.firstError).toContain('数组');
339
+ expect(result.firstError).toContain("数组");
339
340
  });
340
341
 
341
- test('元素数量小于 min - 失败', () => {
342
- const rules = { tags: { name: '标签', type: 'array_string', min: 3, max: 10 } };
343
- const result = Validator.validate({ tags: ['a', 'b'] }, rules);
342
+ test("元素数量小于 min - 失败", () => {
343
+ const rules = { tags: { name: "标签", type: "array_string", min: 3, max: 10 } };
344
+ const result = Validator.validate({ tags: ["a", "b"] }, rules);
344
345
  expect(result.code).toBe(1);
345
- expect(result.firstError).toContain('3');
346
+ expect(result.firstError).toContain("3");
346
347
  });
347
348
 
348
- test('元素数量等于 min - 通过', () => {
349
- const rules = { tags: { name: '标签', type: 'array_string', min: 2, max: 10 } };
350
- const result = Validator.validate({ tags: ['a', 'b'] }, rules);
349
+ test("元素数量等于 min - 通过", () => {
350
+ const rules = { tags: { name: "标签", type: "array_string", min: 2, max: 10 } };
351
+ const result = Validator.validate({ tags: ["a", "b"] }, rules);
351
352
  expect(result.code).toBe(0);
352
353
  });
353
354
 
354
- test('元素数量大于 max - 失败', () => {
355
- const rules = { tags: { name: '标签', type: 'array_string', min: 1, max: 3 } };
356
- const result = Validator.validate({ tags: ['a', 'b', 'c', 'd', 'e'] }, rules);
355
+ test("元素数量大于 max - 失败", () => {
356
+ const rules = { tags: { name: "标签", type: "array_string", min: 1, max: 3 } };
357
+ const result = Validator.validate({ tags: ["a", "b", "c", "d", "e"] }, rules);
357
358
  expect(result.code).toBe(1);
358
- expect(result.firstError).toContain('3');
359
+ expect(result.firstError).toContain("3");
359
360
  });
360
361
 
361
- test('元素数量等于 max - 通过', () => {
362
- const rules = { tags: { name: '标签', type: 'array_string', min: 1, max: 3 } };
363
- const result = Validator.validate({ tags: ['a', 'b', 'c'] }, rules);
362
+ test("元素数量等于 max - 通过", () => {
363
+ const rules = { tags: { name: "标签", type: "array_string", min: 1, max: 3 } };
364
+ const result = Validator.validate({ tags: ["a", "b", "c"] }, rules);
364
365
  expect(result.code).toBe(0);
365
366
  });
366
367
 
367
- test('空数组', () => {
368
- const rules = { tags: { name: '标签', type: 'array_string', min: 0, max: 10 } };
368
+ test("空数组", () => {
369
+ const rules = { tags: { name: "标签", type: "array_string", min: 0, max: 10 } };
369
370
  const result = Validator.validate({ tags: [] }, rules);
370
371
  expect(result.code).toBe(0);
371
372
  });
372
373
 
373
- test('数组元素正则验证 - 全部通过', () => {
374
- const rules = { emails: { name: '邮箱列表', type: 'array_string', min: 1, max: 10, regexp: '@email' } };
375
- const result = Validator.validate({ emails: ['a@test.com', 'b@test.com'] }, rules);
374
+ test("数组元素正则验证 - 全部通过", () => {
375
+ const rules = {
376
+ emails: { name: "邮箱列表", type: "array_string", min: 1, max: 10, regexp: "@email" }
377
+ };
378
+ const result = Validator.validate({ emails: ["a@test.com", "b@test.com"] }, rules);
376
379
  expect(result.code).toBe(0);
377
380
  });
378
381
 
379
- test('数组元素正则验证 - 部分失败', () => {
380
- const rules = { emails: { name: '邮箱列表', type: 'array_string', min: 1, max: 10, regexp: '@email' } };
381
- const result = Validator.validate({ emails: ['a@test.com', 'invalid'] }, rules);
382
+ test("数组元素正则验证 - 部分失败", () => {
383
+ const rules = {
384
+ emails: { name: "邮箱列表", type: "array_string", min: 1, max: 10, regexp: "@email" }
385
+ };
386
+ const result = Validator.validate({ emails: ["a@test.com", "invalid"] }, rules);
382
387
  expect(result.code).toBe(1);
383
- expect(result.firstError).toContain('格式');
388
+ expect(result.firstError).toContain("格式");
384
389
  });
385
390
  });
386
391
 
387
392
  // ========== array_text 类型测试 ==========
388
393
 
389
- describe('Validator.validate - array_text 类型', () => {
390
- test('array_text 与 array_string 行为一致', () => {
391
- const rules = { items: { name: '条目', type: 'array_text', min: 1, max: 5 } };
392
- const result = Validator.validate({ items: ['item1', 'item2'] }, rules);
394
+ describe("Validator.validate - array_text 类型", () => {
395
+ test("array_text 与 array_string 行为一致", () => {
396
+ const rules = { items: { name: "条目", type: "array_text", min: 1, max: 5 } };
397
+ const result = Validator.validate({ items: ["item1", "item2"] }, rules);
393
398
  expect(result.code).toBe(0);
394
399
  });
395
400
  });
396
401
 
397
402
  // ========== 正则验证测试 ==========
398
403
 
399
- describe('Validator.validate - 正则别名', () => {
400
- test('@email - 有效邮箱', () => {
401
- const validEmails = ['test@example.com', 'user.name@domain.co.uk', 'admin+tag@site.org', 'test123@test.cn'];
404
+ describe("Validator.validate - 正则别名", () => {
405
+ test("@email - 有效邮箱", () => {
406
+ const validEmails = ["test@example.com", "user.name@domain.co.uk", "admin+tag@site.org", "test123@test.cn"];
402
407
 
403
408
  validEmails.forEach((email) => {
404
- const rules = { email: { name: '邮箱', type: 'string', regexp: '@email' } };
409
+ const rules = { email: { name: "邮箱", type: "string", regexp: "@email" } };
405
410
  const result = Validator.validate({ email: email }, rules);
406
411
  expect(result.code).toBe(0);
407
412
  });
408
413
  });
409
414
 
410
- test('@email - 无效邮箱', () => {
411
- const invalidEmails = ['plaintext', '@example.com', 'user@', 'user @domain.com'];
415
+ test("@email - 无效邮箱", () => {
416
+ const invalidEmails = ["plaintext", "@example.com", "user@", "user @domain.com"];
412
417
 
413
418
  invalidEmails.forEach((email) => {
414
- const rules = { email: { name: '邮箱', type: 'string', regexp: '@email' } };
419
+ const rules = { email: { name: "邮箱", type: "string", regexp: "@email" } };
415
420
  const result = Validator.validate({ email: email }, rules);
416
421
  expect(result.code).toBe(1);
417
422
  });
418
423
  });
419
424
 
420
- test('@phone - 有效手机号', () => {
421
- const validPhones = ['13800138000', '15012345678', '18888888888', '19912345678'];
425
+ test("@phone - 有效手机号", () => {
426
+ const validPhones = ["13800138000", "15012345678", "18888888888", "19912345678"];
422
427
 
423
428
  validPhones.forEach((phone) => {
424
- const rules = { phone: { name: '手机号', type: 'string', regexp: '@phone' } };
429
+ const rules = { phone: { name: "手机号", type: "string", regexp: "@phone" } };
425
430
  const result = Validator.validate({ phone: phone }, rules);
426
431
  expect(result.code).toBe(0);
427
432
  });
428
433
  });
429
434
 
430
- test('@phone - 无效手机号', () => {
435
+ test("@phone - 无效手机号", () => {
431
436
  const invalidPhones = [
432
- '12345678901', // 首位不是 1 开头的有效段
433
- '1380013800', // 10 位
434
- '138001380001', // 12 位
435
- 'abc'
437
+ "12345678901", // 首位不是 1 开头的有效段
438
+ "1380013800", // 10 位
439
+ "138001380001", // 12 位
440
+ "abc"
436
441
  ];
437
442
 
438
443
  invalidPhones.forEach((phone) => {
439
- const rules = { phone: { name: '手机号', type: 'string', regexp: '@phone' } };
444
+ const rules = { phone: { name: "手机号", type: "string", regexp: "@phone" } };
440
445
  const result = Validator.validate({ phone: phone }, rules);
441
446
  expect(result.code).toBe(1);
442
447
  });
443
448
  });
444
449
  });
445
450
 
446
- describe('Validator.validate - 自定义正则', () => {
447
- test('纯数字', () => {
448
- const rules = { code: { name: '验证码', type: 'string', regexp: '^\\d+$' } };
451
+ describe("Validator.validate - 自定义正则", () => {
452
+ test("纯数字", () => {
453
+ const rules = { code: { name: "验证码", type: "string", regexp: "^\\d+$" } };
449
454
 
450
- expect(Validator.validate({ code: '123456' }, rules).code).toBe(0);
451
- expect(Validator.validate({ code: '12a34' }, rules).code).toBe(1);
455
+ expect(Validator.validate({ code: "123456" }, rules).code).toBe(0);
456
+ expect(Validator.validate({ code: "12a34" }, rules).code).toBe(1);
452
457
  });
453
458
 
454
- test('字母数字组合', () => {
455
- const rules = { username: { name: '用户名', type: 'string', regexp: '^[a-zA-Z0-9]+$' } };
459
+ test("字母数字组合", () => {
460
+ const rules = { username: { name: "用户名", type: "string", regexp: "^[a-zA-Z0-9]+$" } };
456
461
 
457
- expect(Validator.validate({ username: 'user123' }, rules).code).toBe(0);
458
- expect(Validator.validate({ username: 'user@123' }, rules).code).toBe(1);
462
+ expect(Validator.validate({ username: "user123" }, rules).code).toBe(0);
463
+ expect(Validator.validate({ username: "user@123" }, rules).code).toBe(1);
459
464
  });
460
465
 
461
- test('无效正则不抛出异常', () => {
462
- const rules = { value: { name: '', type: 'string', regexp: '[invalid(' } };
463
- const result = Validator.validate({ value: 'test' }, rules);
466
+ test("无效正则不抛出异常", () => {
467
+ const rules = { value: { name: "", type: "string", regexp: "[invalid(" } };
468
+ const result = Validator.validate({ value: "test" }, rules);
464
469
  // 无效正则应该导致验证失败,但不应抛出异常
465
470
  expect(result.code).toBe(1);
466
471
  });
@@ -468,27 +473,27 @@ describe('Validator.validate - 自定义正则', () => {
468
473
 
469
474
  // ========== 非必填字段测试 ==========
470
475
 
471
- describe('Validator.validate - 非必填字段', () => {
472
- test('非必填字段不存在时不验证', () => {
476
+ describe("Validator.validate - 非必填字段", () => {
477
+ test("非必填字段不存在时不验证", () => {
473
478
  const rules = {
474
- name: { name: '名称', type: 'string', min: 2, max: 20 },
475
- age: { name: '年龄', type: 'number', min: 0, max: 150 }
479
+ name: { name: "名称", type: "string", min: 2, max: 20 },
480
+ age: { name: "年龄", type: "number", min: 0, max: 150 }
476
481
  };
477
482
 
478
483
  // 只提供 name,不提供 age(age 不在 required 中)
479
- const result = Validator.validate({ name: 'test' }, rules, ['name']);
484
+ const result = Validator.validate({ name: "test" }, rules, ["name"]);
480
485
 
481
486
  expect(result.code).toBe(0);
482
487
  });
483
488
 
484
- test('非必填字段存在时会验证', () => {
489
+ test("非必填字段存在时会验证", () => {
485
490
  const rules = {
486
- name: { name: '名称', type: 'string', min: 2, max: 20 },
487
- age: { name: '年龄', type: 'number', min: 0, max: 150 }
491
+ name: { name: "名称", type: "string", min: 2, max: 20 },
492
+ age: { name: "年龄", type: "number", min: 0, max: 150 }
488
493
  };
489
494
 
490
495
  // 提供了 age 但值无效
491
- const result = Validator.validate({ name: 'test', age: 200 }, rules, ['name']);
496
+ const result = Validator.validate({ name: "test", age: 200 }, rules, ["name"]);
492
497
 
493
498
  expect(result.code).toBe(1);
494
499
  expect(result.fieldErrors.age).toBeDefined();
@@ -497,178 +502,178 @@ describe('Validator.validate - 非必填字段', () => {
497
502
 
498
503
  // ========== Validator.single 测试 ==========
499
504
 
500
- describe('Validator.single - 单值验证', () => {
501
- test('有效值返回转换后的值', () => {
502
- const fieldDef = { name: '年龄', type: 'number', min: 0, max: 150 };
505
+ describe("Validator.single - 单值验证", () => {
506
+ test("有效值返回转换后的值", () => {
507
+ const fieldDef = { name: "年龄", type: "number", min: 0, max: 150 };
503
508
  const result = Validator.single(25, fieldDef);
504
509
 
505
510
  expect(result.error).toBeNull();
506
511
  expect(result.value).toBe(25);
507
512
  });
508
513
 
509
- test('字符串数字自动转换', () => {
510
- const fieldDef = { name: '年龄', type: 'number', min: 0, max: 150 };
511
- const result = Validator.single('30', fieldDef);
514
+ test("字符串数字自动转换", () => {
515
+ const fieldDef = { name: "年龄", type: "number", min: 0, max: 150 };
516
+ const result = Validator.single("30", fieldDef);
512
517
 
513
518
  expect(result.error).toBeNull();
514
519
  expect(result.value).toBe(30);
515
520
  });
516
521
 
517
- test('无效值返回错误', () => {
518
- const fieldDef = { name: '年龄', type: 'number', min: 0, max: 150 };
519
- const result = Validator.single('abc', fieldDef);
522
+ test("无效值返回错误", () => {
523
+ const fieldDef = { name: "年龄", type: "number", min: 0, max: 150 };
524
+ const result = Validator.single("abc", fieldDef);
520
525
 
521
526
  expect(result.error).toBeDefined();
522
527
  expect(result.value).toBeNull();
523
528
  });
524
529
 
525
- test('空值返回默认值 - number', () => {
526
- const fieldDef = { name: '计数', type: 'number', default: null };
530
+ test("空值返回默认值 - number", () => {
531
+ const fieldDef = { name: "计数", type: "number", default: null };
527
532
  const result = Validator.single(null, fieldDef);
528
533
 
529
534
  expect(result.error).toBeNull();
530
535
  expect(result.value).toBe(0); // number 类型默认值
531
536
  });
532
537
 
533
- test('空值返回默认值 - string', () => {
534
- const fieldDef = { name: '名称', type: 'string', default: null };
538
+ test("空值返回默认值 - string", () => {
539
+ const fieldDef = { name: "名称", type: "string", default: null };
535
540
  const result = Validator.single(undefined, fieldDef);
536
541
 
537
542
  expect(result.error).toBeNull();
538
- expect(result.value).toBe(''); // string 类型默认值
543
+ expect(result.value).toBe(""); // string 类型默认值
539
544
  });
540
545
 
541
- test('空值返回默认值 - array_string', () => {
542
- const fieldDef = { name: '标签', type: 'array_string', default: null };
543
- const result = Validator.single('', fieldDef);
546
+ test("空值返回默认值 - array_string", () => {
547
+ const fieldDef = { name: "标签", type: "array_string", default: null };
548
+ const result = Validator.single("", fieldDef);
544
549
 
545
550
  expect(result.error).toBeNull();
546
551
  expect(result.value).toEqual([]); // array 类型默认值
547
552
  });
548
553
 
549
- test('使用自定义默认值', () => {
550
- const fieldDef = { name: '状态', type: 'number', default: 1 };
554
+ test("使用自定义默认值", () => {
555
+ const fieldDef = { name: "状态", type: "number", default: 1 };
551
556
  const result = Validator.single(null, fieldDef);
552
557
 
553
558
  expect(result.error).toBeNull();
554
559
  expect(result.value).toBe(1);
555
560
  });
556
561
 
557
- test('字符串数字默认值转换', () => {
558
- const fieldDef = { name: '计数', type: 'number', default: '100' };
562
+ test("字符串数字默认值转换", () => {
563
+ const fieldDef = { name: "计数", type: "number", default: "100" };
559
564
  const result = Validator.single(null, fieldDef);
560
565
 
561
566
  expect(result.error).toBeNull();
562
567
  expect(result.value).toBe(100);
563
568
  });
564
569
 
565
- test('数组默认值解析', () => {
566
- const fieldDef = { name: '标签', type: 'array_string', default: '["a","b"]' };
570
+ test("数组默认值解析", () => {
571
+ const fieldDef = { name: "标签", type: "array_string", default: '["a","b"]' };
567
572
  const result = Validator.single(null, fieldDef);
568
573
 
569
574
  expect(result.error).toBeNull();
570
- expect(result.value).toEqual(['a', 'b']);
575
+ expect(result.value).toEqual(["a", "b"]);
571
576
  });
572
577
 
573
- test('空数组默认值', () => {
574
- const fieldDef = { name: '标签', type: 'array_string', default: '[]' };
578
+ test("空数组默认值", () => {
579
+ const fieldDef = { name: "标签", type: "array_string", default: "[]" };
575
580
  const result = Validator.single(null, fieldDef);
576
581
 
577
582
  expect(result.error).toBeNull();
578
583
  expect(result.value).toEqual([]);
579
584
  });
580
585
 
581
- test('规则验证失败', () => {
582
- const fieldDef = { name: '年龄', type: 'number', min: 18, max: 100 };
586
+ test("规则验证失败", () => {
587
+ const fieldDef = { name: "年龄", type: "number", min: 18, max: 100 };
583
588
  const result = Validator.single(10, fieldDef);
584
589
 
585
590
  expect(result.error).toBeDefined();
586
- expect(result.error).toContain('18');
591
+ expect(result.error).toContain("18");
587
592
  });
588
593
 
589
- test('正则验证失败', () => {
590
- const fieldDef = { name: '邮箱', type: 'string', regexp: '@email' };
591
- const result = Validator.single('invalid', fieldDef);
594
+ test("正则验证失败", () => {
595
+ const fieldDef = { name: "邮箱", type: "string", regexp: "@email" };
596
+ const result = Validator.single("invalid", fieldDef);
592
597
 
593
598
  expect(result.error).toBeDefined();
594
- expect(result.error).toContain('格式');
599
+ expect(result.error).toContain("格式");
595
600
  });
596
601
  });
597
602
 
598
603
  // ========== 错误消息测试 ==========
599
604
 
600
- describe('Validator - 错误消息格式', () => {
601
- test('错误消息包含字段标签', () => {
602
- const rules = { age: { name: '年龄', type: 'number', min: 18, max: 100 } };
605
+ describe("Validator - 错误消息格式", () => {
606
+ test("错误消息包含字段标签", () => {
607
+ const rules = { age: { name: "年龄", type: "number", min: 18, max: 100 } };
603
608
  const result = Validator.validate({ age: 10 }, rules);
604
609
 
605
- expect(result.firstError).toContain('年龄');
610
+ expect(result.firstError).toContain("年龄");
606
611
  });
607
612
 
608
- test('必填错误消息格式', () => {
609
- const rules = { name: { name: '姓名', type: 'string', min: 2, max: 20 } };
610
- const result = Validator.validate({}, rules, ['name']);
613
+ test("必填错误消息格式", () => {
614
+ const rules = { name: { name: "姓名", type: "string", min: 2, max: 20 } };
615
+ const result = Validator.validate({}, rules, ["name"]);
611
616
 
612
- expect(result.firstError).toBe('姓名为必填项');
617
+ expect(result.firstError).toBe("姓名为必填项");
613
618
  });
614
619
 
615
- test('长度错误消息格式', () => {
616
- const rules = { name: { name: '姓名', type: 'string', min: 5, max: 20 } };
617
- const result = Validator.validate({ name: 'abc' }, rules);
620
+ test("长度错误消息格式", () => {
621
+ const rules = { name: { name: "姓名", type: "string", min: 5, max: 20 } };
622
+ const result = Validator.validate({ name: "abc" }, rules);
618
623
 
619
- expect(result.firstError).toContain('姓名');
620
- expect(result.firstError).toContain('5');
624
+ expect(result.firstError).toContain("姓名");
625
+ expect(result.firstError).toContain("5");
621
626
  });
622
627
 
623
- test('数值范围错误消息格式', () => {
624
- const rules = { age: { name: '年龄', type: 'number', min: 18, max: 100 } };
628
+ test("数值范围错误消息格式", () => {
629
+ const rules = { age: { name: "年龄", type: "number", min: 18, max: 100 } };
625
630
  const result = Validator.validate({ age: 10 }, rules);
626
631
 
627
- expect(result.firstError).toContain('年龄');
628
- expect(result.firstError).toContain('18');
632
+ expect(result.firstError).toContain("年龄");
633
+ expect(result.firstError).toContain("18");
629
634
  });
630
635
  });
631
636
 
632
637
  // ========== 边界条件测试 ==========
633
638
 
634
- describe('Validator - 边界条件', () => {
635
- test('空 rules 对象', () => {
636
- const result = Validator.validate({ name: 'test' }, {});
639
+ describe("Validator - 边界条件", () => {
640
+ test("空 rules 对象", () => {
641
+ const result = Validator.validate({ name: "test" }, {});
637
642
  expect(result.code).toBe(0);
638
643
  });
639
644
 
640
- test('空 required 数组', () => {
641
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 20 } };
642
- const result = Validator.validate({ name: 'test' }, rules, []);
645
+ test("空 required 数组", () => {
646
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 20 } };
647
+ const result = Validator.validate({ name: "test" }, rules, []);
643
648
  expect(result.code).toBe(0);
644
649
  });
645
650
 
646
- test('required 中的字段不在 rules 中', () => {
647
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 20 } };
648
- const result = Validator.validate({}, rules, ['unknown']);
651
+ test("required 中的字段不在 rules 中", () => {
652
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 20 } };
653
+ const result = Validator.validate({}, rules, ["unknown"]);
649
654
 
650
655
  // 应该报错,显示 unknown 为必填项
651
656
  expect(result.code).toBe(1);
652
657
  expect(result.fieldErrors.unknown).toBeDefined();
653
658
  });
654
659
 
655
- test('data 中的字段不在 rules 中', () => {
656
- const rules = { name: { name: '名称', type: 'string', min: 2, max: 20 } };
657
- const result = Validator.validate({ name: 'test', extra: 'ignored' }, rules);
660
+ test("data 中的字段不在 rules 中", () => {
661
+ const rules = { name: { name: "名称", type: "string", min: 2, max: 20 } };
662
+ const result = Validator.validate({ name: "test", extra: "ignored" }, rules);
658
663
 
659
664
  // extra 字段应该被忽略
660
665
  expect(result.code).toBe(0);
661
666
  });
662
667
 
663
- test('min/max 为 null 时不检查', () => {
664
- const rules = { value: { name: '', type: 'string', min: null, max: null } };
665
- const result = Validator.validate({ value: 'any length string here' }, rules);
668
+ test("min/max 为 null 时不检查", () => {
669
+ const rules = { value: { name: "", type: "string", min: null, max: null } };
670
+ const result = Validator.validate({ value: "any length string here" }, rules);
666
671
  expect(result.code).toBe(0);
667
672
  });
668
673
 
669
- test('regexp 为 null 时不检查正则', () => {
670
- const rules = { value: { name: '', type: 'string', min: 0, max: 100, regexp: null } };
671
- const result = Validator.validate({ value: 'anything' }, rules);
674
+ test("regexp 为 null 时不检查正则", () => {
675
+ const rules = { value: { name: "", type: "string", min: 0, max: 100, regexp: null } };
676
+ const result = Validator.validate({ value: "anything" }, rules);
672
677
  expect(result.code).toBe(0);
673
678
  });
674
679
  });