befly-shared 1.2.8 → 1.3.1

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 (98) hide show
  1. package/package.json +13 -30
  2. package/utils/arrayToTree.ts +135 -0
  3. package/utils/buildTreeByParentPath.ts +127 -0
  4. package/utils/scanViewsDir.ts +148 -0
  5. package/README.md +0 -439
  6. package/dist/addonHelper.js +0 -83
  7. package/dist/arrayKeysToCamel.js +0 -18
  8. package/dist/arrayToTree.js +0 -23
  9. package/dist/calcPerfTime.js +0 -13
  10. package/dist/configTypes.js +0 -1
  11. package/dist/constants.js +0 -46
  12. package/dist/deepTransformKeys.js +0 -139
  13. package/dist/fieldClear.js +0 -57
  14. package/dist/genShortId.js +0 -12
  15. package/dist/hashPassword.js +0 -22
  16. package/dist/index.js +0 -26
  17. package/dist/keysToCamel.js +0 -21
  18. package/dist/keysToSnake.js +0 -21
  19. package/dist/layouts.js +0 -59
  20. package/dist/pickFields.js +0 -16
  21. package/dist/redisKeys.js +0 -34
  22. package/dist/regex.js +0 -202
  23. package/dist/scanConfig.js +0 -83
  24. package/dist/scanFiles.js +0 -39
  25. package/dist/scanViews.js +0 -48
  26. package/dist/withDefaultColumns.js +0 -32
  27. package/src/addonHelper.ts +0 -88
  28. package/src/arrayKeysToCamel.ts +0 -18
  29. package/src/arrayToTree.ts +0 -31
  30. package/src/calcPerfTime.ts +0 -13
  31. package/src/configTypes.ts +0 -29
  32. package/src/constants.ts +0 -60
  33. package/src/deepTransformKeys.ts +0 -172
  34. package/src/fieldClear.ts +0 -75
  35. package/src/genShortId.ts +0 -12
  36. package/src/hashPassword.ts +0 -27
  37. package/src/index.ts +0 -29
  38. package/src/keysToCamel.ts +0 -22
  39. package/src/keysToSnake.ts +0 -22
  40. package/src/layouts.ts +0 -90
  41. package/src/pickFields.ts +0 -19
  42. package/src/redisKeys.ts +0 -44
  43. package/src/regex.ts +0 -225
  44. package/src/scanConfig.ts +0 -106
  45. package/src/scanFiles.ts +0 -49
  46. package/src/scanViews.ts +0 -55
  47. package/src/withDefaultColumns.ts +0 -36
  48. package/tests/addonHelper.test.ts +0 -55
  49. package/tests/arrayKeysToCamel.test.ts +0 -21
  50. package/tests/arrayToTree.test.ts +0 -98
  51. package/tests/calcPerfTime.test.ts +0 -19
  52. package/tests/deepTransformKeys.test.ts +0 -466
  53. package/tests/fieldClear.test.ts +0 -39
  54. package/tests/keysToCamel.test.ts +0 -22
  55. package/tests/keysToSnake.test.ts +0 -22
  56. package/tests/layouts.test.ts +0 -93
  57. package/tests/pickFields.test.ts +0 -22
  58. package/tests/regex.test.ts +0 -308
  59. package/tests/scanFiles.test.ts +0 -58
  60. package/tests/types.test.ts +0 -289
  61. package/types/addon.d.ts +0 -50
  62. package/types/addonConfigMerge.d.ts +0 -17
  63. package/types/addonHelper.d.ts +0 -24
  64. package/types/api.d.ts +0 -63
  65. package/types/arrayKeysToCamel.d.ts +0 -13
  66. package/types/arrayToTree.d.ts +0 -8
  67. package/types/calcPerfTime.d.ts +0 -4
  68. package/types/common.d.ts +0 -8
  69. package/types/configMerge.d.ts +0 -49
  70. package/types/configTypes.d.ts +0 -28
  71. package/types/constants.d.ts +0 -48
  72. package/types/context.d.ts +0 -38
  73. package/types/crypto.d.ts +0 -23
  74. package/types/database.d.ts +0 -55
  75. package/types/deepTransformKeys.d.ts +0 -84
  76. package/types/fieldClear.d.ts +0 -16
  77. package/types/genShortId.d.ts +0 -10
  78. package/types/hashPassword.d.ts +0 -11
  79. package/types/index.d.ts +0 -23
  80. package/types/jwt.d.ts +0 -99
  81. package/types/keysToCamel.d.ts +0 -10
  82. package/types/keysToSnake.d.ts +0 -10
  83. package/types/layouts.d.ts +0 -29
  84. package/types/loadAndMergeConfig.d.ts +0 -7
  85. package/types/logger.d.ts +0 -22
  86. package/types/menu.d.ts +0 -49
  87. package/types/mergeConfig.d.ts +0 -7
  88. package/types/pickFields.d.ts +0 -4
  89. package/types/redisKeys.d.ts +0 -34
  90. package/types/regex.d.ts +0 -145
  91. package/types/scanConfig.d.ts +0 -7
  92. package/types/scanFiles.d.ts +0 -12
  93. package/types/scanViews.d.ts +0 -11
  94. package/types/table.d.ts +0 -49
  95. package/types/tool.d.ts +0 -67
  96. package/types/types.d.ts +0 -44
  97. package/types/validate.d.ts +0 -69
  98. package/types/withDefaultColumns.d.ts +0 -7
@@ -1,308 +0,0 @@
1
- /**
2
- * 正则表达式别名测试
3
- */
4
- import { describe, expect, it } from 'bun:test';
5
-
6
- import { getRegex, matchRegex, RegexAliases } from '../src/regex.js';
7
-
8
- describe('RegexAliases - 正则别名常量', () => {
9
- describe('数字类型', () => {
10
- it('number - 正整数', () => {
11
- expect(new RegExp(RegexAliases.number).test('123')).toBe(true);
12
- expect(new RegExp(RegexAliases.number).test('0')).toBe(true);
13
- expect(new RegExp(RegexAliases.number).test('-123')).toBe(false);
14
- expect(new RegExp(RegexAliases.number).test('12.3')).toBe(false);
15
- });
16
-
17
- it('integer - 整数(含负数)', () => {
18
- expect(new RegExp(RegexAliases.integer).test('123')).toBe(true);
19
- expect(new RegExp(RegexAliases.integer).test('-123')).toBe(true);
20
- expect(new RegExp(RegexAliases.integer).test('0')).toBe(true);
21
- });
22
-
23
- it('float - 浮点数', () => {
24
- expect(new RegExp(RegexAliases.float).test('12.34')).toBe(true);
25
- expect(new RegExp(RegexAliases.float).test('-12.34')).toBe(true);
26
- expect(new RegExp(RegexAliases.float).test('123')).toBe(true);
27
- });
28
-
29
- it('positive - 正整数(不含0)', () => {
30
- expect(new RegExp(RegexAliases.positive).test('123')).toBe(true);
31
- expect(new RegExp(RegexAliases.positive).test('0')).toBe(false);
32
- expect(new RegExp(RegexAliases.positive).test('-1')).toBe(false);
33
- });
34
- });
35
-
36
- describe('字符串类型', () => {
37
- it('word - 纯字母', () => {
38
- expect(new RegExp(RegexAliases.word).test('Hello')).toBe(true);
39
- expect(new RegExp(RegexAliases.word).test('Hello123')).toBe(false);
40
- });
41
-
42
- it('alphanumeric - 字母和数字', () => {
43
- expect(new RegExp(RegexAliases.alphanumeric).test('Hello123')).toBe(true);
44
- expect(new RegExp(RegexAliases.alphanumeric).test('Hello_123')).toBe(false);
45
- });
46
-
47
- it('alphanumeric_ - 字母、数字和下划线', () => {
48
- expect(new RegExp(RegexAliases.alphanumeric_).test('Hello_123')).toBe(true);
49
- expect(new RegExp(RegexAliases.alphanumeric_).test('Hello-123')).toBe(false);
50
- });
51
- });
52
-
53
- describe('中文', () => {
54
- it('chinese - 纯中文', () => {
55
- expect(new RegExp(RegexAliases.chinese).test('你好')).toBe(true);
56
- expect(new RegExp(RegexAliases.chinese).test('你好World')).toBe(false);
57
- });
58
-
59
- it('chineseWord - 中文和字母', () => {
60
- expect(new RegExp(RegexAliases.chineseWord).test('你好World')).toBe(true);
61
- expect(new RegExp(RegexAliases.chineseWord).test('你好123')).toBe(false);
62
- });
63
- });
64
-
65
- describe('常用格式', () => {
66
- it('email - 邮箱地址', () => {
67
- expect(new RegExp(RegexAliases.email).test('test@example.com')).toBe(true);
68
- expect(new RegExp(RegexAliases.email).test('test.name@example.co.uk')).toBe(true);
69
- expect(new RegExp(RegexAliases.email).test('invalid-email')).toBe(false);
70
- });
71
-
72
- it('phone - 中国大陆手机号', () => {
73
- expect(new RegExp(RegexAliases.phone).test('13812345678')).toBe(true);
74
- expect(new RegExp(RegexAliases.phone).test('12345678901')).toBe(false);
75
- expect(new RegExp(RegexAliases.phone).test('1381234567')).toBe(false);
76
- });
77
-
78
- it('url - URL 地址', () => {
79
- expect(new RegExp(RegexAliases.url).test('https://example.com')).toBe(true);
80
- expect(new RegExp(RegexAliases.url).test('http://example.com')).toBe(true);
81
- expect(new RegExp(RegexAliases.url).test('ftp://example.com')).toBe(false);
82
- });
83
-
84
- it('ip - IPv4 地址', () => {
85
- expect(new RegExp(RegexAliases.ip).test('192.168.1.1')).toBe(true);
86
- expect(new RegExp(RegexAliases.ip).test('255.255.255.255')).toBe(true);
87
- expect(new RegExp(RegexAliases.ip).test('256.1.1.1')).toBe(false);
88
- });
89
- });
90
-
91
- describe('特殊格式', () => {
92
- it('uuid - UUID', () => {
93
- expect(new RegExp(RegexAliases.uuid).test('550e8400-e29b-41d4-a716-446655440000')).toBe(true);
94
- expect(new RegExp(RegexAliases.uuid).test('invalid-uuid')).toBe(false);
95
- });
96
-
97
- it('md5 - MD5 哈希', () => {
98
- expect(new RegExp(RegexAliases.md5).test('d41d8cd98f00b204e9800998ecf8427e')).toBe(true);
99
- expect(new RegExp(RegexAliases.md5).test('invalid')).toBe(false);
100
- });
101
- });
102
-
103
- describe('日期时间', () => {
104
- it('date - 日期 YYYY-MM-DD', () => {
105
- expect(new RegExp(RegexAliases.date).test('2024-01-15')).toBe(true);
106
- expect(new RegExp(RegexAliases.date).test('2024/01/15')).toBe(false);
107
- });
108
-
109
- it('time - 时间 HH:MM:SS', () => {
110
- expect(new RegExp(RegexAliases.time).test('12:30:45')).toBe(true);
111
- expect(new RegExp(RegexAliases.time).test('12:30')).toBe(false);
112
- });
113
- });
114
-
115
- describe('代码相关', () => {
116
- it('variable - 变量名', () => {
117
- expect(new RegExp(RegexAliases.variable).test('myVar')).toBe(true);
118
- expect(new RegExp(RegexAliases.variable).test('_private')).toBe(true);
119
- expect(new RegExp(RegexAliases.variable).test('123var')).toBe(false);
120
- });
121
-
122
- it('constant - 常量名', () => {
123
- expect(new RegExp(RegexAliases.constant).test('MY_CONST')).toBe(true);
124
- expect(new RegExp(RegexAliases.constant).test('myConst')).toBe(false);
125
- });
126
- });
127
-
128
- describe('证件相关', () => {
129
- it('idCard - 中国身份证号', () => {
130
- expect(new RegExp(RegexAliases.idCard).test('11010119900101001X')).toBe(true);
131
- expect(new RegExp(RegexAliases.idCard).test('110101199001010019')).toBe(true);
132
- expect(new RegExp(RegexAliases.idCard).test('1234567890')).toBe(false);
133
- });
134
- });
135
- });
136
-
137
- describe('getRegex - 获取正则表达式', () => {
138
- it('以 @ 开头返回别名对应的正则', () => {
139
- expect(getRegex('@email')).toBe(RegexAliases.email);
140
- expect(getRegex('@phone')).toBe(RegexAliases.phone);
141
- });
142
-
143
- it('未知别名返回原字符串', () => {
144
- expect(getRegex('@unknown')).toBe('@unknown');
145
- });
146
-
147
- it('不以 @ 开头返回原字符串', () => {
148
- expect(getRegex('^\\d+$')).toBe('^\\d+$');
149
- });
150
- });
151
-
152
- describe('matchRegex - 验证值是否匹配', () => {
153
- it('使用别名验证', () => {
154
- expect(matchRegex('test@example.com', '@email')).toBe(true);
155
- expect(matchRegex('invalid', '@email')).toBe(false);
156
- });
157
-
158
- it('使用自定义正则验证', () => {
159
- expect(matchRegex('123', '^\\d+$')).toBe(true);
160
- expect(matchRegex('abc', '^\\d+$')).toBe(false);
161
- });
162
-
163
- it('手机号验证', () => {
164
- expect(matchRegex('13812345678', '@phone')).toBe(true);
165
- expect(matchRegex('12345678901', '@phone')).toBe(false);
166
- });
167
- });
168
-
169
- describe('RegexAliases - 新增正则别名', () => {
170
- describe('账号相关', () => {
171
- it('bankCard - 银行卡号', () => {
172
- expect(new RegExp(RegexAliases.bankCard).test('6222020111122223333')).toBe(true);
173
- expect(new RegExp(RegexAliases.bankCard).test('622202011112222')).toBe(false); // 15位太短
174
- expect(new RegExp(RegexAliases.bankCard).test('62220201111222233334444')).toBe(false); // 20位太长
175
- });
176
-
177
- it('wechat - 微信号', () => {
178
- expect(new RegExp(RegexAliases.wechat).test('abc123')).toBe(true);
179
- expect(new RegExp(RegexAliases.wechat).test('test_user-1')).toBe(true);
180
- expect(new RegExp(RegexAliases.wechat).test('123abc')).toBe(false); // 数字开头
181
- expect(new RegExp(RegexAliases.wechat).test('ab')).toBe(false); // 太短
182
- });
183
-
184
- it('qq - QQ号', () => {
185
- expect(new RegExp(RegexAliases.qq).test('12345')).toBe(true);
186
- expect(new RegExp(RegexAliases.qq).test('123456789')).toBe(true);
187
- expect(new RegExp(RegexAliases.qq).test('01234')).toBe(false); // 0开头
188
- expect(new RegExp(RegexAliases.qq).test('1234')).toBe(false); // 太短
189
- });
190
-
191
- it('alipay - 支付宝账号', () => {
192
- expect(new RegExp(RegexAliases.alipay).test('13812345678')).toBe(true);
193
- expect(new RegExp(RegexAliases.alipay).test('test@example.com')).toBe(true);
194
- });
195
- });
196
-
197
- describe('密码强度', () => {
198
- it('passwordWeak - 弱密码', () => {
199
- expect(new RegExp(RegexAliases.passwordWeak).test('123456')).toBe(true);
200
- expect(new RegExp(RegexAliases.passwordWeak).test('12345')).toBe(false);
201
- });
202
-
203
- it('passwordMedium - 中等密码', () => {
204
- expect(new RegExp(RegexAliases.passwordMedium).test('abc12345')).toBe(true);
205
- expect(new RegExp(RegexAliases.passwordMedium).test('12345678')).toBe(false); // 无字母
206
- });
207
-
208
- it('passwordStrong - 强密码', () => {
209
- expect(new RegExp(RegexAliases.passwordStrong).test('Abc12345!')).toBe(true);
210
- expect(new RegExp(RegexAliases.passwordStrong).test('abc12345!')).toBe(false); // 无大写
211
- });
212
- });
213
-
214
- describe('其他常用', () => {
215
- it('postalCode - 邮政编码', () => {
216
- expect(new RegExp(RegexAliases.postalCode).test('518000')).toBe(true);
217
- expect(new RegExp(RegexAliases.postalCode).test('51800')).toBe(false);
218
- });
219
-
220
- it('semver - 语义化版本号', () => {
221
- expect(new RegExp(RegexAliases.semver).test('1.0.0')).toBe(true);
222
- expect(new RegExp(RegexAliases.semver).test('1.0.0-beta.1')).toBe(true);
223
- expect(new RegExp(RegexAliases.semver).test('1.0.0+build.123')).toBe(true);
224
- expect(new RegExp(RegexAliases.semver).test('v1.0.0')).toBe(false);
225
- });
226
-
227
- it('colorHex - 十六进制颜色', () => {
228
- expect(new RegExp(RegexAliases.colorHex).test('#fff')).toBe(true);
229
- expect(new RegExp(RegexAliases.colorHex).test('#ffffff')).toBe(true);
230
- expect(new RegExp(RegexAliases.colorHex).test('#FFFFFF')).toBe(true);
231
- expect(new RegExp(RegexAliases.colorHex).test('ffffff')).toBe(false);
232
- });
233
-
234
- it('ipv6 - IPv6 地址', () => {
235
- expect(new RegExp(RegexAliases.ipv6).test('2001:0db8:85a3:0000:0000:8a2e:0370:7334')).toBe(true);
236
- expect(new RegExp(RegexAliases.ipv6).test('192.168.1.1')).toBe(false);
237
- });
238
-
239
- it('username - 用户名', () => {
240
- expect(new RegExp(RegexAliases.username).test('admin123')).toBe(true);
241
- expect(new RegExp(RegexAliases.username).test('test_user')).toBe(true);
242
- expect(new RegExp(RegexAliases.username).test('123admin')).toBe(false); // 数字开头
243
- expect(new RegExp(RegexAliases.username).test('abc')).toBe(false); // 太短
244
- });
245
-
246
- it('nickname - 昵称', () => {
247
- expect(new RegExp(RegexAliases.nickname).test('用户昵称')).toBe(true);
248
- expect(new RegExp(RegexAliases.nickname).test('test123')).toBe(true);
249
- expect(new RegExp(RegexAliases.nickname).test('a')).toBe(false); // 太短
250
- });
251
-
252
- it('licensePlate - 车牌号', () => {
253
- expect(new RegExp(RegexAliases.licensePlate).test('京A12345')).toBe(true);
254
- expect(new RegExp(RegexAliases.licensePlate).test('粤B88888')).toBe(true);
255
- });
256
- });
257
- });
258
-
259
- describe('正则缓存功能', () => {
260
- // 导入缓存相关函数
261
- const { getCompiledRegex, clearRegexCache, getRegexCacheSize } = require('../src/regex.js');
262
-
263
- it('getCompiledRegex - 返回 RegExp 对象', () => {
264
- const regex = getCompiledRegex('@email');
265
- expect(regex).toBeInstanceOf(RegExp);
266
- expect(regex.test('test@example.com')).toBe(true);
267
- });
268
-
269
- it('getCompiledRegex - 缓存命中返回相同对象', () => {
270
- clearRegexCache();
271
- const regex1 = getCompiledRegex('@phone');
272
- const regex2 = getCompiledRegex('@phone');
273
- expect(regex1).toBe(regex2); // 同一个对象
274
- });
275
-
276
- it('getCompiledRegex - 支持 flags 参数', () => {
277
- const regexI = getCompiledRegex('^hello$', 'i');
278
- expect(regexI.test('HELLO')).toBe(true);
279
-
280
- const regexNoFlag = getCompiledRegex('^hello$');
281
- expect(regexNoFlag.test('HELLO')).toBe(false);
282
- });
283
-
284
- it('clearRegexCache - 清除缓存', () => {
285
- getCompiledRegex('@email');
286
- expect(getRegexCacheSize()).toBeGreaterThan(0);
287
- clearRegexCache();
288
- expect(getRegexCacheSize()).toBe(0);
289
- });
290
-
291
- it('缓存性能 - 避免重复编译', () => {
292
- clearRegexCache();
293
- const pattern = '@email';
294
-
295
- // 验证缓存命中时返回相同对象
296
- const regex1 = getCompiledRegex(pattern);
297
- const regex2 = getCompiledRegex(pattern);
298
- expect(regex1).toBe(regex2);
299
-
300
- // 验证缓存大小
301
- expect(getRegexCacheSize()).toBe(1);
302
-
303
- // 添加更多缓存
304
- getCompiledRegex('@phone');
305
- getCompiledRegex('@url');
306
- expect(getRegexCacheSize()).toBe(3);
307
- });
308
- });
@@ -1,58 +0,0 @@
1
- import { describe, it, expect, beforeAll, afterAll } from 'bun:test';
2
- import { join } from 'node:path';
3
- import { mkdirSync, writeFileSync, rmSync, existsSync } from 'node:fs';
4
- import { scanFiles } from '../src/scanFiles';
5
-
6
- const TEST_DIR = join(process.cwd(), 'temp_test_scanFiles');
7
-
8
- describe('scanFiles', () => {
9
- beforeAll(() => {
10
- if (existsSync(TEST_DIR)) {
11
- rmSync(TEST_DIR, { recursive: true, force: true });
12
- }
13
- mkdirSync(TEST_DIR, { recursive: true });
14
-
15
- // Create test files
16
- writeFileSync(join(TEST_DIR, 'a.ts'), '');
17
- writeFileSync(join(TEST_DIR, 'b.js'), '');
18
- writeFileSync(join(TEST_DIR, 'c.txt'), ''); // Should be ignored by default pattern
19
- writeFileSync(join(TEST_DIR, '_ignored.ts'), ''); // Should be ignored by ignoreUnderline
20
-
21
- mkdirSync(join(TEST_DIR, 'sub'));
22
- writeFileSync(join(TEST_DIR, 'sub/d.ts'), '');
23
-
24
- mkdirSync(join(TEST_DIR, '_sub_ignored'));
25
- writeFileSync(join(TEST_DIR, '_sub_ignored/e.ts'), ''); // Should be ignored by ignoreUnderline
26
- });
27
-
28
- afterAll(() => {
29
- if (existsSync(TEST_DIR)) {
30
- rmSync(TEST_DIR, { recursive: true, force: true });
31
- }
32
- });
33
-
34
- it('should scan ts and js files by default', async () => {
35
- const files = await scanFiles(TEST_DIR);
36
- const fileNames = files.map((f) => f.fileName).sort();
37
- expect(fileNames).toEqual(['a', 'b', 'd']);
38
- });
39
-
40
- it('should respect custom pattern', async () => {
41
- const files = await scanFiles(TEST_DIR, '**/*.txt');
42
- const fileNames = files.map((f) => f.fileName).sort();
43
- expect(fileNames).toEqual(['c']);
44
- });
45
-
46
- it('should include underline files when ignoreUnderline is false', async () => {
47
- const files = await scanFiles(TEST_DIR, '**/*.{ts,js}', false);
48
- const fileNames = files.map((f) => f.fileName).sort();
49
- expect(fileNames).toEqual(['_ignored', 'a', 'b', 'd', 'e']);
50
- });
51
-
52
- it('should return correct relative paths', async () => {
53
- const files = await scanFiles(TEST_DIR);
54
- const dFile = files.find((f) => f.fileName === 'd');
55
- expect(dFile).toBeDefined();
56
- expect(dFile?.relativePath).toBe('sub/d');
57
- });
58
- });
@@ -1,289 +0,0 @@
1
- /**
2
- * befly-shared 类型定义测试
3
- */
4
- import { describe, expect, it } from 'bun:test';
5
-
6
- import { ApiCode, ErrorMessages } from '../src/constants.js';
7
- import type { DatabaseConfig, FieldDefinition, HttpMethod, MenuItem, PaginatedResult, RedisConfig, ResponseResult, RoleInfo, UserInfo } from '../types/types.js';
8
-
9
- // ValidationResult 在新结构中可能不存在,使用本地定义
10
- interface ValidationResult {
11
- code: 0 | 1;
12
- fields: Record<string, string>;
13
- }
14
-
15
- describe('befly-shared 类型定义', () => {
16
- describe('ResponseResult 类型', () => {
17
- it('成功响应结构正确', () => {
18
- const result: ResponseResult<{ id: number }> = {
19
- code: 0,
20
- msg: '操作成功',
21
- data: { id: 1 }
22
- };
23
- expect(result.code).toBe(0);
24
- expect(result.msg).toBe('操作成功');
25
- expect(result.data).toEqual({ id: 1 });
26
- });
27
-
28
- it('失败响应结构正确', () => {
29
- const result: ResponseResult = {
30
- code: 1,
31
- msg: '操作失败',
32
- error: 'Invalid input'
33
- };
34
- expect(result.code).toBe(1);
35
- expect(result.error).toBe('Invalid input');
36
- });
37
- });
38
-
39
- describe('PaginatedResult 类型', () => {
40
- it('分页结果结构正确', () => {
41
- const result: PaginatedResult<{ name: string }> = {
42
- code: 0,
43
- msg: '查询成功',
44
- data: [{ name: 'test' }],
45
- total: 100,
46
- page: 1,
47
- limit: 10,
48
- pages: 10
49
- };
50
- expect(result.total).toBe(100);
51
- expect(result.pages).toBe(10);
52
- expect(result.data).toHaveLength(1);
53
- });
54
- });
55
-
56
- describe('ValidationResult 类型', () => {
57
- it('验证成功结构正确', () => {
58
- const result: ValidationResult = {
59
- code: 0,
60
- fields: {}
61
- };
62
- expect(result.code).toBe(0);
63
- });
64
-
65
- it('验证失败结构正确', () => {
66
- const result: ValidationResult = {
67
- code: 1,
68
- fields: {
69
- email: '邮箱格式不正确',
70
- password: '密码长度不足'
71
- }
72
- };
73
- expect(result.code).toBe(1);
74
- expect(Object.keys(result.fields)).toHaveLength(2);
75
- });
76
- });
77
-
78
- describe('HttpMethod 类型', () => {
79
- it('支持所有 HTTP 方法', () => {
80
- const methods: HttpMethod[] = ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'];
81
- expect(methods).toHaveLength(7);
82
- });
83
- });
84
-
85
- describe('FieldDefinition 类型', () => {
86
- it('字段定义结构正确', () => {
87
- const field: FieldDefinition = {
88
- name: '用户名',
89
- detail: '用户登录名',
90
- type: 'string',
91
- min: 2,
92
- max: 50,
93
- default: null,
94
- index: true,
95
- unique: true,
96
- comment: '用户名字段',
97
- nullable: false,
98
- unsigned: false,
99
- regexp: '^[a-zA-Z0-9_]+$'
100
- };
101
- expect(field.type).toBe('string');
102
- expect(field.unique).toBe(true);
103
- });
104
- });
105
-
106
- describe('UserInfo 类型', () => {
107
- it('用户信息结构正确', () => {
108
- const user: UserInfo = {
109
- id: 1,
110
- username: 'admin',
111
- email: 'admin@example.com',
112
- roleCode: 'ADMIN',
113
- customField: 'custom value'
114
- };
115
- expect(user.id).toBe(1);
116
- expect(user.customField).toBe('custom value');
117
- });
118
- });
119
-
120
- describe('DatabaseConfig 类型', () => {
121
- it('数据库配置结构正确', () => {
122
- const config: DatabaseConfig = {
123
- type: 'mysql',
124
- host: 'localhost',
125
- port: 3306,
126
- user: 'root',
127
- password: 'password',
128
- database: 'befly'
129
- };
130
- expect(config.type).toBe('mysql');
131
- expect(config.port).toBe(3306);
132
- });
133
- });
134
-
135
- describe('RedisConfig 类型', () => {
136
- it('Redis 配置结构正确', () => {
137
- const config: RedisConfig = {
138
- host: 'localhost',
139
- port: 6379,
140
- password: 'password',
141
- db: 0
142
- };
143
- expect(config.port).toBe(6379);
144
- });
145
-
146
- it('Redis 配置可选字段', () => {
147
- const config: RedisConfig = {
148
- host: 'localhost',
149
- port: 6379
150
- };
151
- expect(config.password).toBeUndefined();
152
- expect(config.db).toBeUndefined();
153
- });
154
- });
155
-
156
- describe('MenuItem 类型', () => {
157
- it('菜单项结构正确', () => {
158
- const menu: MenuItem = {
159
- id: 1,
160
- pid: 0,
161
- name: '系统管理',
162
- path: '/system',
163
- icon: 'Settings',
164
- sort: 1,
165
- hidden: false,
166
- children: [
167
- {
168
- id: 2,
169
- pid: 1,
170
- name: '用户管理',
171
- path: '/system/user',
172
- sort: 1
173
- }
174
- ]
175
- };
176
- expect(menu.children).toHaveLength(1);
177
- expect(menu.children![0].pid).toBe(1);
178
- });
179
- });
180
-
181
- describe('RoleInfo 类型', () => {
182
- it('角色信息结构正确', () => {
183
- const role: RoleInfo = {
184
- id: 1,
185
- code: 'ADMIN',
186
- name: '管理员',
187
- desc: '系统管理员角色'
188
- };
189
- expect(role.code).toBe('ADMIN');
190
- });
191
- });
192
-
193
- describe('ApiCode 常量', () => {
194
- it('SUCCESS 值为 0', () => {
195
- expect(ApiCode.SUCCESS).toBe(0);
196
- });
197
-
198
- it('FAIL 值为 1', () => {
199
- expect(ApiCode.FAIL).toBe(1);
200
- });
201
-
202
- it('UNAUTHORIZED 值为 401', () => {
203
- expect(ApiCode.UNAUTHORIZED).toBe(401);
204
- });
205
-
206
- it('FORBIDDEN 值为 403', () => {
207
- expect(ApiCode.FORBIDDEN).toBe(403);
208
- });
209
-
210
- it('NOT_FOUND 值为 404', () => {
211
- expect(ApiCode.NOT_FOUND).toBe(404);
212
- });
213
-
214
- it('SERVER_ERROR 值为 500', () => {
215
- expect(ApiCode.SERVER_ERROR).toBe(500);
216
- });
217
- });
218
-
219
- describe('ErrorMessages 常量', () => {
220
- it('UNAUTHORIZED 消息正确', () => {
221
- expect(ErrorMessages.UNAUTHORIZED).toBe('请先登录');
222
- });
223
-
224
- it('FORBIDDEN 消息正确', () => {
225
- expect(ErrorMessages.FORBIDDEN).toBe('无访问权限');
226
- });
227
-
228
- it('NOT_FOUND 消息正确', () => {
229
- expect(ErrorMessages.NOT_FOUND).toBe('资源不存在');
230
- });
231
-
232
- it('SERVER_ERROR 消息正确', () => {
233
- expect(ErrorMessages.SERVER_ERROR).toBe('服务器错误');
234
- });
235
-
236
- it('INVALID_PARAMS 消息正确', () => {
237
- expect(ErrorMessages.INVALID_PARAMS).toBe('参数错误');
238
- });
239
-
240
- it('TOKEN_EXPIRED 消息正确', () => {
241
- expect(ErrorMessages.TOKEN_EXPIRED).toBe('Token 已过期');
242
- });
243
-
244
- it('TOKEN_INVALID 消息正确', () => {
245
- expect(ErrorMessages.TOKEN_INVALID).toBe('Token 无效');
246
- });
247
- });
248
-
249
- describe('BaseRequestContext 类型', () => {
250
- it('请求上下文基础结构正确', () => {
251
- // BaseRequestContext 是接口,只验证可以创建符合结构的对象
252
- const ctx = {
253
- body: { username: 'test' },
254
- user: { id: 1 },
255
- now: Date.now(),
256
- ip: '127.0.0.1',
257
- route: 'POST/api/user/login',
258
- requestId: 'abc123'
259
- };
260
- expect(ctx.body.username).toBe('test');
261
- expect(ctx.user.id).toBe(1);
262
- expect(typeof ctx.now).toBe('number');
263
- expect(ctx.ip).toBe('127.0.0.1');
264
- });
265
- });
266
-
267
- describe('BaseApiRoute 类型', () => {
268
- it('API 路由基础结构正确', () => {
269
- // BaseApiRoute 是接口,只验证可以创建符合结构的对象
270
- const route = {
271
- name: '用户登录',
272
- method: 'POST' as const,
273
- auth: false,
274
- fields: {},
275
- required: ['username', 'password']
276
- };
277
- expect(route.name).toBe('用户登录');
278
- expect(route.method).toBe('POST');
279
- expect(route.auth).toBe(false);
280
- });
281
-
282
- it('API 路由最小配置', () => {
283
- const route = {
284
- name: '测试接口'
285
- };
286
- expect(route.name).toBe('测试接口');
287
- });
288
- });
289
- });