befly 3.9.37 → 3.9.39

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 +38 -39
  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} +225 -235
  8. package/docs/cipher.md +71 -69
  9. package/docs/database.md +155 -153
  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} +7 -7
  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 +15 -7
  34. package/lib/asyncContext.ts +43 -0
  35. package/lib/cacheHelper.ts +212 -81
  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 +211 -109
  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 +53 -47
  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 -54
  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 -66
  75. package/sync/syncMenu.ts +190 -57
  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
@@ -0,0 +1,310 @@
1
+ /**
2
+ * 测试 Validator 对 array_number_string 和 array_number_text 类型的支持
3
+ */
4
+
5
+ import type { FieldDefinition } from "befly/types/validate";
6
+
7
+ import { describe, expect, test } from "bun:test";
8
+
9
+ import { Validator } from "../lib/validator.js";
10
+
11
+ describe("Validator - array_number 类型验证", () => {
12
+ // ==================== 类型转换测试 ====================
13
+
14
+ test("array_number_string: 接受数字数组", () => {
15
+ const field: FieldDefinition = {
16
+ name: "数字数组",
17
+ type: "array_number_string",
18
+ min: null,
19
+ max: null,
20
+ default: null,
21
+ regexp: null
22
+ };
23
+
24
+ const result = Validator.single([1, 2, 3], field);
25
+ expect(result.error).toBeNull();
26
+ expect(result.value).toEqual([1, 2, 3]);
27
+ });
28
+
29
+ test("array_number_string: 拒绝字符串数组", () => {
30
+ const field: FieldDefinition = {
31
+ name: "数字数组",
32
+ type: "array_number_string",
33
+ min: null,
34
+ max: null,
35
+ default: null,
36
+ regexp: null
37
+ };
38
+
39
+ const result = Validator.single(["1", "2", "3"], field);
40
+ expect(result.error).toBe("数组元素必须是数字");
41
+ expect(result.value).toBeNull();
42
+ });
43
+
44
+ test("array_number_string: 拒绝混合类型数组", () => {
45
+ const field: FieldDefinition = {
46
+ name: "数字数组",
47
+ type: "array_number_string",
48
+ min: null,
49
+ max: null,
50
+ default: null,
51
+ regexp: null
52
+ };
53
+
54
+ const result = Validator.single([1, "2", 3], field);
55
+ expect(result.error).toBe("数组元素必须是数字");
56
+ });
57
+
58
+ test("array_number_string: 拒绝非数组值", () => {
59
+ const field: FieldDefinition = {
60
+ name: "数字数组",
61
+ type: "array_number_string",
62
+ min: null,
63
+ max: null,
64
+ default: null,
65
+ regexp: null
66
+ };
67
+
68
+ const result = Validator.single("123", field);
69
+ expect(result.error).toBe("必须是数组");
70
+ });
71
+
72
+ test("array_number_text: 接受数字数组", () => {
73
+ const field: FieldDefinition = {
74
+ name: "长数字数组",
75
+ type: "array_number_text",
76
+ min: null,
77
+ max: null,
78
+ default: null,
79
+ regexp: null
80
+ };
81
+
82
+ const result = Validator.single([100, 200, 300], field);
83
+ expect(result.error).toBeNull();
84
+ expect(result.value).toEqual([100, 200, 300]);
85
+ });
86
+
87
+ test("array_number_text: 拒绝 NaN 和 Infinity", () => {
88
+ const field: FieldDefinition = {
89
+ name: "数字数组",
90
+ type: "array_number_text",
91
+ min: null,
92
+ max: null,
93
+ default: null,
94
+ regexp: null
95
+ };
96
+
97
+ const result1 = Validator.single([1, NaN, 3], field);
98
+ expect(result1.error).toBe("数组元素必须是数字");
99
+
100
+ const result2 = Validator.single([1, Infinity, 3], field);
101
+ expect(result2.error).toBe("数组元素必须是数字");
102
+ });
103
+
104
+ // ==================== 规则验证测试 ====================
105
+
106
+ test("array_number_string: min 规则验证", () => {
107
+ const field: FieldDefinition = {
108
+ name: "数字数组",
109
+ type: "array_number_string",
110
+ min: 2,
111
+ max: null,
112
+ default: null,
113
+ regexp: null
114
+ };
115
+
116
+ const result1 = Validator.single([1], field);
117
+ expect(result1.error).toBe("至少需要2个元素");
118
+
119
+ const result2 = Validator.single([1, 2], field);
120
+ expect(result2.error).toBeNull();
121
+
122
+ const result3 = Validator.single([1, 2, 3], field);
123
+ expect(result3.error).toBeNull();
124
+ });
125
+
126
+ test("array_number_string: max 规则验证", () => {
127
+ const field: FieldDefinition = {
128
+ name: "数字数组",
129
+ type: "array_number_string",
130
+ min: null,
131
+ max: 3,
132
+ default: null,
133
+ regexp: null
134
+ };
135
+
136
+ const result1 = Validator.single([1, 2, 3], field);
137
+ expect(result1.error).toBeNull();
138
+
139
+ const result2 = Validator.single([1, 2, 3, 4], field);
140
+ expect(result2.error).toBe("最多只能有3个元素");
141
+ });
142
+
143
+ test("array_number_text: min + max 规则验证", () => {
144
+ const field: FieldDefinition = {
145
+ name: "长数字数组",
146
+ type: "array_number_text",
147
+ min: 1,
148
+ max: 5,
149
+ default: null,
150
+ regexp: null
151
+ };
152
+
153
+ const result1 = Validator.single([], field);
154
+ expect(result1.error).toBe("至少需要1个元素");
155
+
156
+ const result2 = Validator.single([1, 2, 3], field);
157
+ expect(result2.error).toBeNull();
158
+
159
+ const result3 = Validator.single([1, 2, 3, 4, 5, 6], field);
160
+ expect(result3.error).toBe("最多只能有5个元素");
161
+ });
162
+
163
+ // ==================== 默认值测试 ====================
164
+
165
+ test("array_number_string: 无 default 时返回空数组", () => {
166
+ const field: FieldDefinition = {
167
+ name: "数字数组",
168
+ type: "array_number_string",
169
+ min: null,
170
+ max: null,
171
+ default: null,
172
+ regexp: null
173
+ };
174
+
175
+ const result1 = Validator.single(undefined, field);
176
+ expect(result1.error).toBeNull();
177
+ expect(result1.value).toEqual([]);
178
+
179
+ const result2 = Validator.single(null, field);
180
+ expect(result2.error).toBeNull();
181
+ expect(result2.value).toEqual([]);
182
+
183
+ const result3 = Validator.single("", field);
184
+ expect(result3.error).toBeNull();
185
+ expect(result3.value).toEqual([]);
186
+ });
187
+
188
+ test("array_number_string: 有 default 时返回自定义默认值", () => {
189
+ const field: FieldDefinition = {
190
+ name: "数字数组",
191
+ type: "array_number_string",
192
+ min: null,
193
+ max: null,
194
+ default: [10, 20, 30],
195
+ regexp: null
196
+ };
197
+
198
+ const result = Validator.single(undefined, field);
199
+ expect(result.error).toBeNull();
200
+ expect(result.value).toEqual([10, 20, 30]);
201
+ });
202
+
203
+ test('array_number_string: default 为字符串 "[]" 时返回空数组', () => {
204
+ const field: FieldDefinition = {
205
+ name: "数字数组",
206
+ type: "array_number_string",
207
+ min: null,
208
+ max: null,
209
+ default: "[]",
210
+ regexp: null
211
+ };
212
+
213
+ const result = Validator.single(null, field);
214
+ expect(result.error).toBeNull();
215
+ expect(result.value).toEqual([]);
216
+ });
217
+
218
+ test("array_number_text: 无 default 时返回空数组", () => {
219
+ const field: FieldDefinition = {
220
+ name: "长数字数组",
221
+ type: "array_number_text",
222
+ min: null,
223
+ max: null,
224
+ default: null,
225
+ regexp: null
226
+ };
227
+
228
+ const result = Validator.single(undefined, field);
229
+ expect(result.error).toBeNull();
230
+ expect(result.value).toEqual([]);
231
+ });
232
+
233
+ test("array_number_text: 有 default 时返回自定义默认值", () => {
234
+ const field: FieldDefinition = {
235
+ name: "长数字数组",
236
+ type: "array_number_text",
237
+ min: null,
238
+ max: null,
239
+ default: [100, 200],
240
+ regexp: null
241
+ };
242
+
243
+ const result = Validator.single(undefined, field);
244
+ expect(result.error).toBeNull();
245
+ expect(result.value).toEqual([100, 200]);
246
+ });
247
+
248
+ // ==================== validate 方法测试 ====================
249
+
250
+ test("validate: array_number_string 字段验证", () => {
251
+ const rules = {
252
+ tags: {
253
+ name: "标签ID",
254
+ type: "array_number_string",
255
+ min: 1,
256
+ max: 10,
257
+ default: null,
258
+ regexp: null
259
+ }
260
+ };
261
+
262
+ const result1 = Validator.validate({ tags: [1, 2, 3] }, rules as any, ["tags"]);
263
+ expect(result1.failed).toBe(false);
264
+
265
+ const result2 = Validator.validate({ tags: [] }, rules as any, ["tags"]);
266
+ expect(result2.failed).toBe(true);
267
+ expect(result2.firstError).toBe("标签ID至少需要1个元素");
268
+
269
+ const result3 = Validator.validate({ tags: ["1", "2"] }, rules as any, ["tags"]);
270
+ expect(result3.failed).toBe(true);
271
+ expect(result3.firstError).toBe("标签ID数组元素必须是数字");
272
+ });
273
+
274
+ test("validate: array_number_text 字段验证", () => {
275
+ const rules = {
276
+ ids: {
277
+ name: "关联ID",
278
+ type: "array_number_text",
279
+ min: null,
280
+ max: null,
281
+ default: null,
282
+ regexp: null
283
+ }
284
+ };
285
+
286
+ const result1 = Validator.validate({ ids: [100, 200, 300] }, rules as any, []);
287
+ expect(result1.failed).toBe(false);
288
+
289
+ const result2 = Validator.validate({ ids: "not-array" }, rules as any, []);
290
+ expect(result2.failed).toBe(true);
291
+ expect(result2.firstError).toBe("关联ID必须是数组");
292
+ });
293
+
294
+ test("validate: undefined 参数跳过验证", () => {
295
+ const rules = {
296
+ tags: {
297
+ name: "标签",
298
+ type: "array_number_string",
299
+ min: 1,
300
+ max: null,
301
+ default: null,
302
+ regexp: null
303
+ }
304
+ };
305
+
306
+ // undefined 且不是必填字段,应跳过验证
307
+ const result = Validator.validate({ other: "value" }, rules as any, []);
308
+ expect(result.failed).toBe(false);
309
+ });
310
+ });
@@ -0,0 +1,373 @@
1
+ /**
2
+ * 测试 Validator 的默认值处理逻辑
3
+ */
4
+
5
+ import type { FieldDefinition } from "befly/types/validate";
6
+
7
+ import { describe, expect, test } from "bun:test";
8
+
9
+ import { Validator } from "../lib/validator.js";
10
+
11
+ describe("Validator - 默认值处理逻辑", () => {
12
+ // ==================== number 类型默认值 ====================
13
+
14
+ test("number: 无 default 时返回 0", () => {
15
+ const field: FieldDefinition = {
16
+ name: "数字",
17
+ type: "number",
18
+ min: null,
19
+ max: null,
20
+ default: null,
21
+ regexp: null
22
+ };
23
+
24
+ const result = Validator.single(undefined, field);
25
+ expect(result.error).toBeNull();
26
+ expect(result.value).toBe(0);
27
+ });
28
+
29
+ test("number: 有 default 时返回自定义值", () => {
30
+ const field: FieldDefinition = {
31
+ name: "数字",
32
+ type: "number",
33
+ min: null,
34
+ max: null,
35
+ default: 100,
36
+ regexp: null
37
+ };
38
+
39
+ const result = Validator.single(undefined, field);
40
+ expect(result.error).toBeNull();
41
+ expect(result.value).toBe(100);
42
+ });
43
+
44
+ test("number: default 为字符串时自动转换", () => {
45
+ const field: FieldDefinition = {
46
+ name: "数字",
47
+ type: "number",
48
+ min: null,
49
+ max: null,
50
+ default: "999",
51
+ regexp: null
52
+ };
53
+
54
+ const result = Validator.single(null, field);
55
+ expect(result.error).toBeNull();
56
+ expect(result.value).toBe(999);
57
+ });
58
+
59
+ test("number: default 为无效字符串时返回 0", () => {
60
+ const field: FieldDefinition = {
61
+ name: "数字",
62
+ type: "number",
63
+ min: null,
64
+ max: null,
65
+ default: "invalid",
66
+ regexp: null
67
+ };
68
+
69
+ const result = Validator.single(undefined, field);
70
+ expect(result.error).toBeNull();
71
+ expect(result.value).toBe(0);
72
+ });
73
+
74
+ // ==================== string 类型默认值 ====================
75
+
76
+ test("string: 无 default 时返回空字符串", () => {
77
+ const field: FieldDefinition = {
78
+ name: "字符串",
79
+ type: "string",
80
+ min: null,
81
+ max: null,
82
+ default: null,
83
+ regexp: null
84
+ };
85
+
86
+ const result = Validator.single(undefined, field);
87
+ expect(result.error).toBeNull();
88
+ expect(result.value).toBe("");
89
+ });
90
+
91
+ test("string: 有 default 时返回自定义值", () => {
92
+ const field: FieldDefinition = {
93
+ name: "字符串",
94
+ type: "string",
95
+ min: null,
96
+ max: null,
97
+ default: "admin",
98
+ regexp: null
99
+ };
100
+
101
+ const result = Validator.single(undefined, field);
102
+ expect(result.error).toBeNull();
103
+ expect(result.value).toBe("admin");
104
+ });
105
+
106
+ // ==================== text 类型默认值 ====================
107
+
108
+ test("text: 无 default 时返回空字符串", () => {
109
+ const field: FieldDefinition = {
110
+ name: "文本",
111
+ type: "text",
112
+ min: null,
113
+ max: null,
114
+ default: null,
115
+ regexp: null
116
+ };
117
+
118
+ const result = Validator.single(undefined, field);
119
+ expect(result.error).toBeNull();
120
+ expect(result.value).toBe("");
121
+ });
122
+
123
+ test("text: 有 default 时返回自定义值", () => {
124
+ const field: FieldDefinition = {
125
+ name: "文本",
126
+ type: "text",
127
+ min: null,
128
+ max: null,
129
+ default: "这是长文本内容",
130
+ regexp: null
131
+ };
132
+
133
+ const result = Validator.single(null, field);
134
+ expect(result.error).toBeNull();
135
+ expect(result.value).toBe("这是长文本内容");
136
+ });
137
+
138
+ // ==================== array_string 类型默认值 ====================
139
+
140
+ test("array_string: 无 default 时返回空数组", () => {
141
+ const field: FieldDefinition = {
142
+ name: "字符串数组",
143
+ type: "array_string",
144
+ min: null,
145
+ max: null,
146
+ default: null,
147
+ regexp: null
148
+ };
149
+
150
+ const result = Validator.single(undefined, field);
151
+ expect(result.error).toBeNull();
152
+ expect(result.value).toEqual([]);
153
+ });
154
+
155
+ test("array_string: 有 default 时返回自定义数组", () => {
156
+ const field: FieldDefinition = {
157
+ name: "字符串数组",
158
+ type: "array_string",
159
+ min: null,
160
+ max: null,
161
+ default: ["a", "b", "c"],
162
+ regexp: null
163
+ };
164
+
165
+ const result = Validator.single(undefined, field);
166
+ expect(result.error).toBeNull();
167
+ expect(result.value).toEqual(["a", "b", "c"]);
168
+ });
169
+
170
+ test('array_string: default 为字符串 "[]" 时返回空数组', () => {
171
+ const field: FieldDefinition = {
172
+ name: "字符串数组",
173
+ type: "array_string",
174
+ min: null,
175
+ max: null,
176
+ default: "[]",
177
+ regexp: null
178
+ };
179
+
180
+ const result = Validator.single(null, field);
181
+ expect(result.error).toBeNull();
182
+ expect(result.value).toEqual([]);
183
+ });
184
+
185
+ test("array_string: default 为 JSON 字符串时解析为数组", () => {
186
+ const field: FieldDefinition = {
187
+ name: "字符串数组",
188
+ type: "array_string",
189
+ min: null,
190
+ max: null,
191
+ default: '["x", "y", "z"]',
192
+ regexp: null
193
+ };
194
+
195
+ const result = Validator.single(undefined, field);
196
+ expect(result.error).toBeNull();
197
+ expect(result.value).toEqual(["x", "y", "z"]);
198
+ });
199
+
200
+ test("array_string: default 为无效 JSON 时返回空数组", () => {
201
+ const field: FieldDefinition = {
202
+ name: "字符串数组",
203
+ type: "array_string",
204
+ min: null,
205
+ max: null,
206
+ default: "invalid-json",
207
+ regexp: null
208
+ };
209
+
210
+ const result = Validator.single(null, field);
211
+ expect(result.error).toBeNull();
212
+ expect(result.value).toEqual([]);
213
+ });
214
+
215
+ // ==================== array_text 类型默认值 ====================
216
+
217
+ test("array_text: 无 default 时返回空数组", () => {
218
+ const field: FieldDefinition = {
219
+ name: "文本数组",
220
+ type: "array_text",
221
+ min: null,
222
+ max: null,
223
+ default: null,
224
+ regexp: null
225
+ };
226
+
227
+ const result = Validator.single(undefined, field);
228
+ expect(result.error).toBeNull();
229
+ expect(result.value).toEqual([]);
230
+ });
231
+
232
+ test("array_text: 有 default 时返回自定义数组", () => {
233
+ const field: FieldDefinition = {
234
+ name: "文本数组",
235
+ type: "array_text",
236
+ min: null,
237
+ max: null,
238
+ default: ["长文本1", "长文本2"],
239
+ regexp: null
240
+ };
241
+
242
+ const result = Validator.single(null, field);
243
+ expect(result.error).toBeNull();
244
+ expect(result.value).toEqual(["长文本1", "长文本2"]);
245
+ });
246
+
247
+ // ==================== 空值处理测试 ====================
248
+
249
+ test("undefined 应使用默认值", () => {
250
+ const field: FieldDefinition = {
251
+ name: "测试",
252
+ type: "string",
253
+ min: null,
254
+ max: null,
255
+ default: "test",
256
+ regexp: null
257
+ };
258
+
259
+ const result = Validator.single(undefined, field);
260
+ expect(result.error).toBeNull();
261
+ expect(result.value).toBe("test");
262
+ });
263
+
264
+ test("null 应使用默认值", () => {
265
+ const field: FieldDefinition = {
266
+ name: "测试",
267
+ type: "number",
268
+ min: null,
269
+ max: null,
270
+ default: 999,
271
+ regexp: null
272
+ };
273
+
274
+ const result = Validator.single(null, field);
275
+ expect(result.error).toBeNull();
276
+ expect(result.value).toBe(999);
277
+ });
278
+
279
+ test("空字符串应使用默认值", () => {
280
+ const field: FieldDefinition = {
281
+ name: "测试",
282
+ type: "string",
283
+ min: null,
284
+ max: null,
285
+ default: "fallback",
286
+ regexp: null
287
+ };
288
+
289
+ const result = Validator.single("", field);
290
+ expect(result.error).toBeNull();
291
+ expect(result.value).toBe("fallback");
292
+ });
293
+
294
+ // ==================== 默认值优先级测试 ====================
295
+
296
+ test("字段 default 应覆盖类型默认值(number)", () => {
297
+ const fieldWithDefault: FieldDefinition = {
298
+ name: "数字",
299
+ type: "number",
300
+ min: null,
301
+ max: null,
302
+ default: 888,
303
+ regexp: null
304
+ };
305
+
306
+ const fieldWithoutDefault: FieldDefinition = {
307
+ name: "数字",
308
+ type: "number",
309
+ min: null,
310
+ max: null,
311
+ default: null,
312
+ regexp: null
313
+ };
314
+
315
+ const result1 = Validator.single(undefined, fieldWithDefault);
316
+ expect(result1.value).toBe(888); // 使用字段 default
317
+
318
+ const result2 = Validator.single(undefined, fieldWithoutDefault);
319
+ expect(result2.value).toBe(0); // 使用类型默认值
320
+ });
321
+
322
+ test("字段 default 应覆盖类型默认值(string)", () => {
323
+ const fieldWithDefault: FieldDefinition = {
324
+ name: "字符串",
325
+ type: "string",
326
+ min: null,
327
+ max: null,
328
+ default: "custom",
329
+ regexp: null
330
+ };
331
+
332
+ const fieldWithoutDefault: FieldDefinition = {
333
+ name: "字符串",
334
+ type: "string",
335
+ min: null,
336
+ max: null,
337
+ default: null,
338
+ regexp: null
339
+ };
340
+
341
+ const result1 = Validator.single(undefined, fieldWithDefault);
342
+ expect(result1.value).toBe("custom"); // 使用字段 default
343
+
344
+ const result2 = Validator.single(undefined, fieldWithoutDefault);
345
+ expect(result2.value).toBe(""); // 使用类型默认值
346
+ });
347
+
348
+ test("字段 default 应覆盖类型默认值(array)", () => {
349
+ const fieldWithDefault: FieldDefinition = {
350
+ name: "数组",
351
+ type: "array_number_string",
352
+ min: null,
353
+ max: null,
354
+ default: [1, 2, 3],
355
+ regexp: null
356
+ };
357
+
358
+ const fieldWithoutDefault: FieldDefinition = {
359
+ name: "数组",
360
+ type: "array_number_string",
361
+ min: null,
362
+ max: null,
363
+ default: null,
364
+ regexp: null
365
+ };
366
+
367
+ const result1 = Validator.single(undefined, fieldWithDefault);
368
+ expect(result1.value).toEqual([1, 2, 3]); // 使用字段 default
369
+
370
+ const result2 = Validator.single(undefined, fieldWithoutDefault);
371
+ expect(result2.value).toEqual([]); // 使用类型默认值
372
+ });
373
+ });