@zhin.js/core 1.0.57 → 1.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/adapter.d.ts +1 -26
- package/lib/adapter.d.ts.map +1 -1
- package/lib/adapter.js +20 -117
- package/lib/adapter.js.map +1 -1
- package/lib/ai/index.d.ts +2 -0
- package/lib/ai/index.d.ts.map +1 -1
- package/lib/ai/index.js +1 -0
- package/lib/ai/index.js.map +1 -1
- package/lib/built/adapter-process.d.ts +0 -4
- package/lib/built/adapter-process.d.ts.map +1 -1
- package/lib/built/adapter-process.js +0 -95
- package/lib/built/adapter-process.js.map +1 -1
- package/lib/built/agent-preset.d.ts +2 -0
- package/lib/built/agent-preset.d.ts.map +1 -1
- package/lib/built/agent-preset.js +4 -0
- package/lib/built/agent-preset.js.map +1 -1
- package/lib/built/command.d.ts +4 -0
- package/lib/built/command.d.ts.map +1 -1
- package/lib/built/command.js +6 -0
- package/lib/built/command.js.map +1 -1
- package/lib/built/component.d.ts.map +1 -1
- package/lib/built/component.js +1 -0
- package/lib/built/component.js.map +1 -1
- package/lib/built/dispatcher.d.ts.map +1 -1
- package/lib/built/dispatcher.js +0 -13
- package/lib/built/dispatcher.js.map +1 -1
- package/lib/built/message-filter.d.ts +2 -0
- package/lib/built/message-filter.d.ts.map +1 -1
- package/lib/built/message-filter.js +5 -0
- package/lib/built/message-filter.js.map +1 -1
- package/lib/built/skill.d.ts +11 -0
- package/lib/built/skill.d.ts.map +1 -1
- package/lib/built/skill.js +14 -0
- package/lib/built/skill.js.map +1 -1
- package/lib/built/tool.d.ts +11 -44
- package/lib/built/tool.d.ts.map +1 -1
- package/lib/built/tool.js +14 -353
- package/lib/built/tool.js.map +1 -1
- package/lib/plugin.d.ts +1 -25
- package/lib/plugin.d.ts.map +1 -1
- package/lib/plugin.js +1 -77
- package/lib/plugin.js.map +1 -1
- package/lib/types.d.ts +0 -25
- package/lib/types.d.ts.map +1 -1
- package/package.json +10 -7
- package/CHANGELOG.md +0 -538
- package/REFACTORING_COMPLETE.md +0 -178
- package/REFACTORING_STATUS.md +0 -263
- package/src/adapter.ts +0 -275
- package/src/ai/index.ts +0 -52
- package/src/ai/providers/anthropic.ts +0 -379
- package/src/ai/providers/base.ts +0 -175
- package/src/ai/providers/index.ts +0 -13
- package/src/ai/providers/ollama.ts +0 -302
- package/src/ai/providers/openai.ts +0 -174
- package/src/ai/types.ts +0 -348
- package/src/bot.ts +0 -37
- package/src/built/adapter-process.ts +0 -177
- package/src/built/agent-preset.ts +0 -136
- package/src/built/ai-trigger.ts +0 -259
- package/src/built/command.ts +0 -108
- package/src/built/common-adapter-tools.ts +0 -242
- package/src/built/component.ts +0 -130
- package/src/built/config.ts +0 -335
- package/src/built/cron.ts +0 -156
- package/src/built/database.ts +0 -134
- package/src/built/dispatcher.ts +0 -496
- package/src/built/login-assist.ts +0 -131
- package/src/built/message-filter.ts +0 -390
- package/src/built/permission.ts +0 -151
- package/src/built/schema-feature.ts +0 -190
- package/src/built/skill.ts +0 -221
- package/src/built/tool.ts +0 -948
- package/src/command.ts +0 -87
- package/src/component.ts +0 -565
- package/src/cron.ts +0 -4
- package/src/errors.ts +0 -46
- package/src/feature.ts +0 -7
- package/src/index.ts +0 -53
- package/src/jsx-dev-runtime.ts +0 -2
- package/src/jsx-runtime.ts +0 -12
- package/src/jsx.ts +0 -135
- package/src/message.ts +0 -48
- package/src/models/system-log.ts +0 -20
- package/src/models/user.ts +0 -15
- package/src/notice.ts +0 -98
- package/src/plugin.ts +0 -896
- package/src/prompt.ts +0 -293
- package/src/request.ts +0 -95
- package/src/scheduler/index.ts +0 -19
- package/src/scheduler/scheduler.ts +0 -372
- package/src/scheduler/types.ts +0 -74
- package/src/tool-zod.ts +0 -115
- package/src/types-generator.ts +0 -78
- package/src/types.ts +0 -505
- package/src/utils.ts +0 -227
- package/tests/adapter.test.ts +0 -638
- package/tests/ai/ai-trigger.test.ts +0 -368
- package/tests/ai/providers.integration.test.ts +0 -227
- package/tests/ai/setup.ts +0 -308
- package/tests/ai/tool.test.ts +0 -800
- package/tests/bot.test.ts +0 -151
- package/tests/command.test.ts +0 -737
- package/tests/component-new.test.ts +0 -361
- package/tests/config.test.ts +0 -372
- package/tests/cron.test.ts +0 -82
- package/tests/dispatcher.test.ts +0 -293
- package/tests/errors.test.ts +0 -21
- package/tests/expression-evaluation.test.ts +0 -258
- package/tests/features-builtin.test.ts +0 -191
- package/tests/jsx-runtime.test.ts +0 -45
- package/tests/jsx.test.ts +0 -319
- package/tests/message-filter.test.ts +0 -566
- package/tests/message.test.ts +0 -402
- package/tests/notice.test.ts +0 -198
- package/tests/plugin.test.ts +0 -779
- package/tests/prompt.test.ts +0 -78
- package/tests/redos-protection.test.ts +0 -198
- package/tests/request.test.ts +0 -221
- package/tests/schema.test.ts +0 -248
- package/tests/skill-feature.test.ts +0 -179
- package/tests/test-utils.ts +0 -59
- package/tests/tool-feature.test.ts +0 -254
- package/tests/types.test.ts +0 -162
- package/tests/utils.test.ts +0 -135
- package/tsconfig.json +0 -24
|
@@ -1,254 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ToolFeature 补全测试
|
|
3
|
-
* 测试 toolToCommand / commandToTool / ToolFeature.add / filterByContext
|
|
4
|
-
*/
|
|
5
|
-
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
6
|
-
import {
|
|
7
|
-
generatePattern,
|
|
8
|
-
extractParamInfo,
|
|
9
|
-
toolToCommand,
|
|
10
|
-
commandToTool,
|
|
11
|
-
canAccessTool,
|
|
12
|
-
inferPermissionLevel,
|
|
13
|
-
hasPermissionLevel,
|
|
14
|
-
ZhinTool,
|
|
15
|
-
isZhinTool,
|
|
16
|
-
ToolFeature,
|
|
17
|
-
} from '../src/built/tool.js';
|
|
18
|
-
import type { Tool, ToolContext } from '../src/types.js';
|
|
19
|
-
|
|
20
|
-
describe('generatePattern', () => {
|
|
21
|
-
it('应生成无参数的模式', () => {
|
|
22
|
-
const tool: Tool = {
|
|
23
|
-
name: 'ping',
|
|
24
|
-
description: '测试',
|
|
25
|
-
parameters: { type: 'object', properties: {} },
|
|
26
|
-
execute: async () => 'pong',
|
|
27
|
-
};
|
|
28
|
-
expect(generatePattern(tool)).toBe('ping');
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
it('应生成有必填参数的模式', () => {
|
|
32
|
-
const tool: Tool = {
|
|
33
|
-
name: 'weather',
|
|
34
|
-
description: '天气',
|
|
35
|
-
parameters: {
|
|
36
|
-
type: 'object',
|
|
37
|
-
properties: { city: { type: 'string', description: '城市' } },
|
|
38
|
-
required: ['city'],
|
|
39
|
-
},
|
|
40
|
-
execute: async () => '',
|
|
41
|
-
};
|
|
42
|
-
expect(generatePattern(tool)).toBe('weather <city:text>');
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
it('应生成有可选参数的模式', () => {
|
|
46
|
-
const tool: Tool = {
|
|
47
|
-
name: 'search',
|
|
48
|
-
description: '搜索',
|
|
49
|
-
parameters: {
|
|
50
|
-
type: 'object',
|
|
51
|
-
properties: { query: { type: 'string' }, limit: { type: 'number' } },
|
|
52
|
-
required: ['query'],
|
|
53
|
-
},
|
|
54
|
-
execute: async () => '',
|
|
55
|
-
};
|
|
56
|
-
const pattern = generatePattern(tool);
|
|
57
|
-
expect(pattern).toContain('<query:text>');
|
|
58
|
-
expect(pattern).toContain('[limit:number]');
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
it('应使用自定义 command.pattern', () => {
|
|
62
|
-
const tool: Tool = {
|
|
63
|
-
name: 'custom',
|
|
64
|
-
description: '自定义',
|
|
65
|
-
parameters: { type: 'object', properties: {} },
|
|
66
|
-
execute: async () => '',
|
|
67
|
-
command: { pattern: 'my-custom <arg:text>', enabled: true },
|
|
68
|
-
};
|
|
69
|
-
expect(generatePattern(tool)).toBe('my-custom <arg:text>');
|
|
70
|
-
});
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('extractParamInfo', () => {
|
|
74
|
-
it('应从空 properties 返回空数组', () => {
|
|
75
|
-
expect(extractParamInfo({ type: 'object', properties: {} })).toEqual([]);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it('应提取参数信息', () => {
|
|
79
|
-
const result = extractParamInfo({
|
|
80
|
-
type: 'object',
|
|
81
|
-
properties: {
|
|
82
|
-
city: { type: 'string', description: '城市名' },
|
|
83
|
-
days: { type: 'number', description: '天数' },
|
|
84
|
-
},
|
|
85
|
-
required: ['city'],
|
|
86
|
-
});
|
|
87
|
-
expect(result).toHaveLength(2);
|
|
88
|
-
expect(result[0]).toMatchObject({ name: 'city', type: 'string', required: true, description: '城市名' });
|
|
89
|
-
expect(result[1]).toMatchObject({ name: 'days', type: 'number', required: false, description: '天数' });
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
describe('canAccessTool', () => {
|
|
94
|
-
const baseTool: Tool = {
|
|
95
|
-
name: 'test',
|
|
96
|
-
description: '测试',
|
|
97
|
-
parameters: { type: 'object', properties: {} },
|
|
98
|
-
execute: async () => '',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
const baseContext: ToolContext = {
|
|
102
|
-
platform: 'qq',
|
|
103
|
-
botId: 'bot1',
|
|
104
|
-
sceneId: 'scene1',
|
|
105
|
-
senderId: 'user1',
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
it('无限制的工具应始终可访问', () => {
|
|
109
|
-
expect(canAccessTool(baseTool, baseContext)).toBe(true);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
it('应检查平台限制', () => {
|
|
113
|
-
const tool = { ...baseTool, platforms: ['discord'] };
|
|
114
|
-
expect(canAccessTool(tool, { ...baseContext, platform: 'qq' })).toBe(false);
|
|
115
|
-
expect(canAccessTool(tool, { ...baseContext, platform: 'discord' })).toBe(true);
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
it('应检查场景限制', () => {
|
|
119
|
-
const tool = { ...baseTool, scopes: ['group' as const] };
|
|
120
|
-
expect(canAccessTool(tool, { ...baseContext, scope: 'private' })).toBe(false);
|
|
121
|
-
expect(canAccessTool(tool, { ...baseContext, scope: 'group' })).toBe(true);
|
|
122
|
-
});
|
|
123
|
-
|
|
124
|
-
it('应检查权限级别', () => {
|
|
125
|
-
const tool = { ...baseTool, permissionLevel: 'group_admin' as const };
|
|
126
|
-
expect(canAccessTool(tool, { ...baseContext })).toBe(false); // user level
|
|
127
|
-
expect(canAccessTool(tool, { ...baseContext, isGroupAdmin: true })).toBe(true);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
describe('inferPermissionLevel', () => {
|
|
132
|
-
it('应使用 senderPermissionLevel 优先', () => {
|
|
133
|
-
expect(inferPermissionLevel({ senderPermissionLevel: 'owner' } as any)).toBe('owner');
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
it('应按优先级推断', () => {
|
|
137
|
-
expect(inferPermissionLevel({ isOwner: true } as any)).toBe('owner');
|
|
138
|
-
expect(inferPermissionLevel({ isBotAdmin: true } as any)).toBe('bot_admin');
|
|
139
|
-
expect(inferPermissionLevel({ isGroupOwner: true } as any)).toBe('group_owner');
|
|
140
|
-
expect(inferPermissionLevel({ isGroupAdmin: true } as any)).toBe('group_admin');
|
|
141
|
-
expect(inferPermissionLevel({} as any)).toBe('user');
|
|
142
|
-
});
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
describe('hasPermissionLevel', () => {
|
|
146
|
-
it('相同级别应返回 true', () => {
|
|
147
|
-
expect(hasPermissionLevel('user', 'user')).toBe(true);
|
|
148
|
-
expect(hasPermissionLevel('owner', 'owner')).toBe(true);
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
it('高级别应能访问低级别', () => {
|
|
152
|
-
expect(hasPermissionLevel('owner', 'user')).toBe(true);
|
|
153
|
-
expect(hasPermissionLevel('bot_admin', 'group_admin')).toBe(true);
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
it('低级别不能访问高级别', () => {
|
|
157
|
-
expect(hasPermissionLevel('user', 'group_admin')).toBe(false);
|
|
158
|
-
expect(hasPermissionLevel('group_admin', 'owner')).toBe(false);
|
|
159
|
-
});
|
|
160
|
-
});
|
|
161
|
-
|
|
162
|
-
describe('ToolFeature', () => {
|
|
163
|
-
let feature: ToolFeature;
|
|
164
|
-
|
|
165
|
-
beforeEach(() => {
|
|
166
|
-
feature = new ToolFeature();
|
|
167
|
-
});
|
|
168
|
-
|
|
169
|
-
describe('基础操作', () => {
|
|
170
|
-
it('初始状态应无工具', () => {
|
|
171
|
-
expect(feature.items).toHaveLength(0);
|
|
172
|
-
expect(feature.byName.size).toBe(0);
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
it('toJSON 应返回正确结构', () => {
|
|
176
|
-
const json = feature.toJSON();
|
|
177
|
-
expect(json).toMatchObject({
|
|
178
|
-
name: 'tool',
|
|
179
|
-
icon: 'Wrench',
|
|
180
|
-
desc: '工具',
|
|
181
|
-
count: 0,
|
|
182
|
-
items: [],
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
});
|
|
186
|
-
|
|
187
|
-
describe('filterByContext', () => {
|
|
188
|
-
it('应过滤不符合权限的工具', () => {
|
|
189
|
-
const tools: Tool[] = [
|
|
190
|
-
{ name: 'public', description: '公开', parameters: { type: 'object', properties: {} }, execute: async () => '' },
|
|
191
|
-
{ name: 'admin', description: '管理', parameters: { type: 'object', properties: {} }, execute: async () => '', permissionLevel: 'bot_admin' },
|
|
192
|
-
];
|
|
193
|
-
const context: ToolContext = { platform: 'qq', botId: 'b', sceneId: 's', senderId: 'u' };
|
|
194
|
-
const filtered = feature.filterByContext(tools, context);
|
|
195
|
-
expect(filtered).toHaveLength(1);
|
|
196
|
-
expect(filtered[0].name).toBe('public');
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('应过滤不符合平台的工具', () => {
|
|
200
|
-
const tools: Tool[] = [
|
|
201
|
-
{ name: 'all', description: '', parameters: { type: 'object', properties: {} }, execute: async () => '' },
|
|
202
|
-
{ name: 'discord-only', description: '', parameters: { type: 'object', properties: {} }, execute: async () => '', platforms: ['discord'] },
|
|
203
|
-
];
|
|
204
|
-
const context: ToolContext = { platform: 'qq', botId: 'b', sceneId: 's', senderId: 'u' };
|
|
205
|
-
const filtered = feature.filterByContext(tools, context);
|
|
206
|
-
expect(filtered).toHaveLength(1);
|
|
207
|
-
expect(filtered[0].name).toBe('all');
|
|
208
|
-
});
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
describe('ZhinTool', () => {
|
|
213
|
-
it('应构建完整的 Tool 对象', () => {
|
|
214
|
-
const zt = new ZhinTool('test')
|
|
215
|
-
.desc('测试工具')
|
|
216
|
-
.param('city', { type: 'string', description: '城市' }, true)
|
|
217
|
-
.execute(async ({ city }) => `${city}: 晴`);
|
|
218
|
-
|
|
219
|
-
const tool = zt.toTool();
|
|
220
|
-
expect(tool.name).toBe('test');
|
|
221
|
-
expect(tool.description).toBe('测试工具');
|
|
222
|
-
expect(tool.parameters.properties).toHaveProperty('city');
|
|
223
|
-
expect(tool.parameters.required).toEqual(['city']);
|
|
224
|
-
expect(typeof tool.execute).toBe('function');
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('无 execute 应抛错', () => {
|
|
228
|
-
const zt = new ZhinTool('no-exec').desc('无执行');
|
|
229
|
-
expect(() => zt.toTool()).toThrow('has no execute()');
|
|
230
|
-
});
|
|
231
|
-
|
|
232
|
-
it('isZhinTool 应正确判断', () => {
|
|
233
|
-
expect(isZhinTool(new ZhinTool('x'))).toBe(true);
|
|
234
|
-
expect(isZhinTool({})).toBe(false);
|
|
235
|
-
expect(isZhinTool(null)).toBe(false);
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('toJSON 应返回序列化数据', () => {
|
|
239
|
-
const zt = new ZhinTool('test')
|
|
240
|
-
.desc('描述')
|
|
241
|
-
.param('a', { type: 'string' }, true)
|
|
242
|
-
.tag('t1')
|
|
243
|
-
.platform('qq')
|
|
244
|
-
.permission('bot_admin')
|
|
245
|
-
.execute(async () => '');
|
|
246
|
-
|
|
247
|
-
const json = zt.toJSON();
|
|
248
|
-
expect(json.name).toBe('test');
|
|
249
|
-
expect(json.description).toBe('描述');
|
|
250
|
-
expect(json.tags).toEqual(['t1']);
|
|
251
|
-
expect(json.platforms).toEqual(['qq']);
|
|
252
|
-
expect(json.permissionLevel).toBe('bot_admin');
|
|
253
|
-
});
|
|
254
|
-
});
|
package/tests/types.test.ts
DELETED
|
@@ -1,162 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect } from 'vitest'
|
|
2
|
-
import {
|
|
3
|
-
createTestMessageSegment,
|
|
4
|
-
createTestSender,
|
|
5
|
-
createTestChannel,
|
|
6
|
-
createTestMessage
|
|
7
|
-
} from './test-utils'
|
|
8
|
-
import type {
|
|
9
|
-
MessageSegment,
|
|
10
|
-
Message,
|
|
11
|
-
MessageSender,
|
|
12
|
-
MessageChannel,
|
|
13
|
-
User,
|
|
14
|
-
Group,
|
|
15
|
-
BotConfig,
|
|
16
|
-
AppConfig,
|
|
17
|
-
SendOptions
|
|
18
|
-
} from '../src/types'
|
|
19
|
-
|
|
20
|
-
describe('消息片段类型测试', () => {
|
|
21
|
-
it('应该正确创建文本消息片段', () => {
|
|
22
|
-
const segment: MessageSegment = createTestMessageSegment('text', { content: '测试消息' })
|
|
23
|
-
expect(segment.type).toBe('text')
|
|
24
|
-
expect(segment.data).toEqual({ content: '测试消息' })
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
it('应该正确创建图片消息片段', () => {
|
|
28
|
-
const segment: MessageSegment = createTestMessageSegment('image', { url: 'http://example.com/image.jpg' })
|
|
29
|
-
expect(segment.type).toBe('image')
|
|
30
|
-
expect(segment.data).toEqual({ url: 'http://example.com/image.jpg' })
|
|
31
|
-
})
|
|
32
|
-
})
|
|
33
|
-
|
|
34
|
-
describe('消息发送者类型测试', () => {
|
|
35
|
-
it('应该正确创建消息发送者', () => {
|
|
36
|
-
const sender: MessageSender = createTestSender('123', '测试用户')
|
|
37
|
-
expect(sender.id).toBe('123')
|
|
38
|
-
expect(sender.name).toBe('测试用户')
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('应该允许创建没有名称的发送者', () => {
|
|
42
|
-
const sender: MessageSender = createTestSender('123')
|
|
43
|
-
expect(sender.id).toBe('123')
|
|
44
|
-
expect(sender.name).toBeUndefined()
|
|
45
|
-
})
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
describe('消息频道类型测试', () => {
|
|
49
|
-
it('应该正确创建群组频道', () => {
|
|
50
|
-
const channel: MessageChannel = createTestChannel('123', 'group')
|
|
51
|
-
expect(channel.id).toBe('123')
|
|
52
|
-
expect(channel.type).toBe('group')
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
it('应该正确创建私聊频道', () => {
|
|
56
|
-
const channel: MessageChannel = createTestChannel('123', 'private')
|
|
57
|
-
expect(channel.id).toBe('123')
|
|
58
|
-
expect(channel.type).toBe('private')
|
|
59
|
-
})
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
describe('消息类型测试', () => {
|
|
63
|
-
it('应该正确创建完整的消息对象', async () => {
|
|
64
|
-
const sender = createTestSender('123', '测试用户')
|
|
65
|
-
const channel = createTestChannel('456', 'group')
|
|
66
|
-
const content = [
|
|
67
|
-
createTestMessageSegment('text', { content: '测试消息' })
|
|
68
|
-
]
|
|
69
|
-
const message: Message = createTestMessage('789', content, sender, channel, '原始消息')
|
|
70
|
-
|
|
71
|
-
expect(message.id).toBe('789')
|
|
72
|
-
expect(message.content).toEqual(content)
|
|
73
|
-
expect(message.sender).toEqual(sender)
|
|
74
|
-
expect(message.channel).toEqual(channel)
|
|
75
|
-
expect(message.raw).toBe('原始消息')
|
|
76
|
-
expect(message.timestamp).toBeDefined()
|
|
77
|
-
expect(typeof message.reply).toBe('function')
|
|
78
|
-
|
|
79
|
-
// 测试回复功能
|
|
80
|
-
await expect(message.reply('测试回复')).resolves.toBeUndefined()
|
|
81
|
-
})
|
|
82
|
-
})
|
|
83
|
-
|
|
84
|
-
describe('用户类型测试', () => {
|
|
85
|
-
it('应该正确定义用户属性', () => {
|
|
86
|
-
const user: User = {
|
|
87
|
-
user_id: '123',
|
|
88
|
-
nickname: '测试用户',
|
|
89
|
-
card: '群名片',
|
|
90
|
-
role: '管理员'
|
|
91
|
-
}
|
|
92
|
-
expect(user.user_id).toBe('123')
|
|
93
|
-
expect(user.nickname).toBe('测试用户')
|
|
94
|
-
expect(user.card).toBe('群名片')
|
|
95
|
-
expect(user.role).toBe('管理员')
|
|
96
|
-
})
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
describe('群组类型测试', () => {
|
|
100
|
-
it('应该正确定义群组属性', () => {
|
|
101
|
-
const group: Group = {
|
|
102
|
-
group_id: '123',
|
|
103
|
-
group_name: '测试群组',
|
|
104
|
-
member_count: 100
|
|
105
|
-
}
|
|
106
|
-
expect(group.group_id).toBe('123')
|
|
107
|
-
expect(group.group_name).toBe('测试群组')
|
|
108
|
-
expect(group.member_count).toBe(100)
|
|
109
|
-
})
|
|
110
|
-
})
|
|
111
|
-
|
|
112
|
-
describe('机器人配置类型测试', () => {
|
|
113
|
-
it('应该正确定义机器人配置', () => {
|
|
114
|
-
const config: BotConfig = {
|
|
115
|
-
name: '测试机器人',
|
|
116
|
-
context: 'test',
|
|
117
|
-
platform: 'qq',
|
|
118
|
-
token: '123456'
|
|
119
|
-
}
|
|
120
|
-
expect(config.name).toBe('测试机器人')
|
|
121
|
-
expect(config.context).toBe('test')
|
|
122
|
-
expect(config.platform).toBe('qq')
|
|
123
|
-
expect(config.token).toBe('123456')
|
|
124
|
-
})
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
describe('应用配置类型测试', () => {
|
|
128
|
-
it('应该正确定义应用配置', () => {
|
|
129
|
-
const config: AppConfig = {
|
|
130
|
-
bots: [{
|
|
131
|
-
name: '测试机器人',
|
|
132
|
-
context: 'test'
|
|
133
|
-
}],
|
|
134
|
-
plugin_dirs: ['./plugins'],
|
|
135
|
-
plugins: ['test-plugin'],
|
|
136
|
-
disable_dependencies: ['disabled-plugin'],
|
|
137
|
-
debug: true
|
|
138
|
-
}
|
|
139
|
-
expect(config.bots).toHaveLength(1)
|
|
140
|
-
expect(config.plugin_dirs).toEqual(['./plugins'])
|
|
141
|
-
expect(config.plugins).toEqual(['test-plugin'])
|
|
142
|
-
expect(config.disable_dependencies).toEqual(['disabled-plugin'])
|
|
143
|
-
expect(config.debug).toBe(true)
|
|
144
|
-
})
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
describe('发送选项类型测试', () => {
|
|
148
|
-
it('应该正确定义发送选项', () => {
|
|
149
|
-
const options: SendOptions = {
|
|
150
|
-
id: '123',
|
|
151
|
-
type: 'group',
|
|
152
|
-
context: 'test',
|
|
153
|
-
bot: 'test-bot',
|
|
154
|
-
content: '测试消息'
|
|
155
|
-
}
|
|
156
|
-
expect(options.id).toBe('123')
|
|
157
|
-
expect(options.type).toBe('group')
|
|
158
|
-
expect(options.context).toBe('test')
|
|
159
|
-
expect(options.bot).toBe('test-bot')
|
|
160
|
-
expect(options.content).toBe('测试消息')
|
|
161
|
-
})
|
|
162
|
-
})
|
package/tests/utils.test.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Core 特有的工具函数测试(通用工具测试已迁移到 @zhin.js/kernel)
|
|
3
|
-
*/
|
|
4
|
-
import { describe, it, expect } from 'vitest'
|
|
5
|
-
import { compose, segment } from '../src/utils'
|
|
6
|
-
|
|
7
|
-
describe('compose middleware', () => {
|
|
8
|
-
it('should return empty function for empty middlewares', async () => {
|
|
9
|
-
const composed = compose([])
|
|
10
|
-
await expect(composed({} as any, async () => {})).resolves.toBeUndefined()
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
it('should handle single middleware', async () => {
|
|
14
|
-
let called = false
|
|
15
|
-
const middleware = async (msg: any, next: any) => {
|
|
16
|
-
called = true
|
|
17
|
-
await next()
|
|
18
|
-
}
|
|
19
|
-
const composed = compose([middleware])
|
|
20
|
-
await composed({} as any, async () => {})
|
|
21
|
-
expect(called).toBe(true)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('should compose multiple middlewares in order', async () => {
|
|
25
|
-
const order: number[] = []
|
|
26
|
-
const middleware1 = async (msg: any, next: any) => {
|
|
27
|
-
order.push(1)
|
|
28
|
-
await next()
|
|
29
|
-
order.push(4)
|
|
30
|
-
}
|
|
31
|
-
const middleware2 = async (msg: any, next: any) => {
|
|
32
|
-
order.push(2)
|
|
33
|
-
await next()
|
|
34
|
-
order.push(3)
|
|
35
|
-
}
|
|
36
|
-
const composed = compose([middleware1, middleware2])
|
|
37
|
-
await composed({} as any, async () => {})
|
|
38
|
-
expect(order).toEqual([1, 2, 3, 4])
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('should handle middleware execution order correctly', async () => {
|
|
42
|
-
const order: string[] = []
|
|
43
|
-
const middleware1 = async (msg: any, next: any) => {
|
|
44
|
-
order.push('m1-before')
|
|
45
|
-
await next()
|
|
46
|
-
order.push('m1-after')
|
|
47
|
-
}
|
|
48
|
-
const middleware2 = async (msg: any, next: any) => {
|
|
49
|
-
order.push('m2-before')
|
|
50
|
-
await next()
|
|
51
|
-
order.push('m2-after')
|
|
52
|
-
}
|
|
53
|
-
const middleware3 = async (msg: any, next: any) => {
|
|
54
|
-
order.push('m3')
|
|
55
|
-
await next()
|
|
56
|
-
}
|
|
57
|
-
const composed = compose([middleware1, middleware2, middleware3])
|
|
58
|
-
await composed({} as any, async () => { order.push('final') })
|
|
59
|
-
expect(order).toEqual(['m1-before', 'm2-before', 'm3', 'final', 'm2-after', 'm1-after'])
|
|
60
|
-
})
|
|
61
|
-
|
|
62
|
-
it('should catch and rethrow middleware errors', async () => {
|
|
63
|
-
const middleware = async () => { throw new Error('Middleware error') }
|
|
64
|
-
const composed = compose([middleware])
|
|
65
|
-
await expect(composed({} as any, async () => {})).rejects.toThrow('Middleware error')
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
|
|
69
|
-
describe('segment utilities', () => {
|
|
70
|
-
describe('escape and unescape', () => {
|
|
71
|
-
it('should escape HTML entities', () => {
|
|
72
|
-
expect(segment.escape('<div>&"\'</div>')).toBe('<div>&"'</div>')
|
|
73
|
-
})
|
|
74
|
-
|
|
75
|
-
it('should unescape HTML entities', () => {
|
|
76
|
-
expect(segment.unescape('<div>&"'</div>')).toBe('<div>&"\'</div>')
|
|
77
|
-
})
|
|
78
|
-
})
|
|
79
|
-
|
|
80
|
-
describe('text and face', () => {
|
|
81
|
-
it('should create text segment', () => {
|
|
82
|
-
expect(segment.text('Hello')).toEqual({ type: 'text', data: { text: 'Hello' } })
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
it('should create face segment', () => {
|
|
86
|
-
expect(segment.face('smile', '😊')).toEqual({
|
|
87
|
-
type: 'face',
|
|
88
|
-
data: { id: 'smile', text: '😊' }
|
|
89
|
-
})
|
|
90
|
-
})
|
|
91
|
-
})
|
|
92
|
-
|
|
93
|
-
describe('from', () => {
|
|
94
|
-
it('should parse simple text', () => {
|
|
95
|
-
const result = segment.from('Hello World')
|
|
96
|
-
expect(result).toEqual([{ type: 'text', data: { text: 'Hello World' } }])
|
|
97
|
-
})
|
|
98
|
-
|
|
99
|
-
it('should parse self-closing tags', () => {
|
|
100
|
-
const result = segment.from('<image url="test.jpg" />')
|
|
101
|
-
expect(result.find(el => el.type === 'image')).toBeDefined()
|
|
102
|
-
})
|
|
103
|
-
|
|
104
|
-
it('should handle malformed templates gracefully', () => {
|
|
105
|
-
const result = segment.from('Hello <unclosed')
|
|
106
|
-
expect(result[0].type).toBe('text')
|
|
107
|
-
})
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
describe('raw', () => {
|
|
111
|
-
it('should convert segments to raw text', () => {
|
|
112
|
-
const content = [
|
|
113
|
-
{ type: 'text', data: { text: 'Hello' } },
|
|
114
|
-
{ type: 'face', data: { text: '😊' } },
|
|
115
|
-
]
|
|
116
|
-
expect(segment.raw(content)).toBe('Hello{face}(😊)')
|
|
117
|
-
})
|
|
118
|
-
|
|
119
|
-
it('should handle string input', () => {
|
|
120
|
-
expect(segment.raw('Hello')).toBe('Hello')
|
|
121
|
-
})
|
|
122
|
-
})
|
|
123
|
-
|
|
124
|
-
describe('toString', () => {
|
|
125
|
-
it('should convert segments to string', () => {
|
|
126
|
-
const content = [
|
|
127
|
-
{ type: 'text', data: { text: 'Hello' } },
|
|
128
|
-
{ type: 'image', data: { url: 'test.jpg' } },
|
|
129
|
-
]
|
|
130
|
-
const result = segment.toString(content)
|
|
131
|
-
expect(result).toContain('Hello')
|
|
132
|
-
expect(result).toContain('<image')
|
|
133
|
-
})
|
|
134
|
-
})
|
|
135
|
-
})
|
package/tsconfig.json
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ES2022",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"outDir": "./lib",
|
|
7
|
-
"rootDir": "./src",
|
|
8
|
-
"strict": true,
|
|
9
|
-
"esModuleInterop": true,
|
|
10
|
-
"skipLibCheck": true,
|
|
11
|
-
"forceConsistentCasingInFileNames": true,
|
|
12
|
-
"resolveJsonModule": true,
|
|
13
|
-
"isolatedModules": true,
|
|
14
|
-
"allowSyntheticDefaultImports": true,
|
|
15
|
-
"experimentalDecorators": true,
|
|
16
|
-
"emitDecoratorMetadata": true,
|
|
17
|
-
"declaration": true,
|
|
18
|
-
"declarationMap": true,
|
|
19
|
-
"sourceMap": true,
|
|
20
|
-
"verbatimModuleSyntax": false
|
|
21
|
-
},
|
|
22
|
-
"include": ["src/**/*"],
|
|
23
|
-
"exclude": ["lib", "node_modules"]
|
|
24
|
-
}
|