@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.
Files changed (126) hide show
  1. package/lib/adapter.d.ts +1 -26
  2. package/lib/adapter.d.ts.map +1 -1
  3. package/lib/adapter.js +20 -117
  4. package/lib/adapter.js.map +1 -1
  5. package/lib/ai/index.d.ts +2 -0
  6. package/lib/ai/index.d.ts.map +1 -1
  7. package/lib/ai/index.js +1 -0
  8. package/lib/ai/index.js.map +1 -1
  9. package/lib/built/adapter-process.d.ts +0 -4
  10. package/lib/built/adapter-process.d.ts.map +1 -1
  11. package/lib/built/adapter-process.js +0 -95
  12. package/lib/built/adapter-process.js.map +1 -1
  13. package/lib/built/agent-preset.d.ts +2 -0
  14. package/lib/built/agent-preset.d.ts.map +1 -1
  15. package/lib/built/agent-preset.js +4 -0
  16. package/lib/built/agent-preset.js.map +1 -1
  17. package/lib/built/command.d.ts +4 -0
  18. package/lib/built/command.d.ts.map +1 -1
  19. package/lib/built/command.js +6 -0
  20. package/lib/built/command.js.map +1 -1
  21. package/lib/built/component.d.ts.map +1 -1
  22. package/lib/built/component.js +1 -0
  23. package/lib/built/component.js.map +1 -1
  24. package/lib/built/dispatcher.d.ts.map +1 -1
  25. package/lib/built/dispatcher.js +0 -13
  26. package/lib/built/dispatcher.js.map +1 -1
  27. package/lib/built/message-filter.d.ts +2 -0
  28. package/lib/built/message-filter.d.ts.map +1 -1
  29. package/lib/built/message-filter.js +5 -0
  30. package/lib/built/message-filter.js.map +1 -1
  31. package/lib/built/skill.d.ts +11 -0
  32. package/lib/built/skill.d.ts.map +1 -1
  33. package/lib/built/skill.js +14 -0
  34. package/lib/built/skill.js.map +1 -1
  35. package/lib/built/tool.d.ts +11 -44
  36. package/lib/built/tool.d.ts.map +1 -1
  37. package/lib/built/tool.js +14 -353
  38. package/lib/built/tool.js.map +1 -1
  39. package/lib/plugin.d.ts +1 -25
  40. package/lib/plugin.d.ts.map +1 -1
  41. package/lib/plugin.js +1 -77
  42. package/lib/plugin.js.map +1 -1
  43. package/lib/types.d.ts +0 -25
  44. package/lib/types.d.ts.map +1 -1
  45. package/package.json +10 -7
  46. package/CHANGELOG.md +0 -538
  47. package/REFACTORING_COMPLETE.md +0 -178
  48. package/REFACTORING_STATUS.md +0 -263
  49. package/src/adapter.ts +0 -275
  50. package/src/ai/index.ts +0 -52
  51. package/src/ai/providers/anthropic.ts +0 -379
  52. package/src/ai/providers/base.ts +0 -175
  53. package/src/ai/providers/index.ts +0 -13
  54. package/src/ai/providers/ollama.ts +0 -302
  55. package/src/ai/providers/openai.ts +0 -174
  56. package/src/ai/types.ts +0 -348
  57. package/src/bot.ts +0 -37
  58. package/src/built/adapter-process.ts +0 -177
  59. package/src/built/agent-preset.ts +0 -136
  60. package/src/built/ai-trigger.ts +0 -259
  61. package/src/built/command.ts +0 -108
  62. package/src/built/common-adapter-tools.ts +0 -242
  63. package/src/built/component.ts +0 -130
  64. package/src/built/config.ts +0 -335
  65. package/src/built/cron.ts +0 -156
  66. package/src/built/database.ts +0 -134
  67. package/src/built/dispatcher.ts +0 -496
  68. package/src/built/login-assist.ts +0 -131
  69. package/src/built/message-filter.ts +0 -390
  70. package/src/built/permission.ts +0 -151
  71. package/src/built/schema-feature.ts +0 -190
  72. package/src/built/skill.ts +0 -221
  73. package/src/built/tool.ts +0 -948
  74. package/src/command.ts +0 -87
  75. package/src/component.ts +0 -565
  76. package/src/cron.ts +0 -4
  77. package/src/errors.ts +0 -46
  78. package/src/feature.ts +0 -7
  79. package/src/index.ts +0 -53
  80. package/src/jsx-dev-runtime.ts +0 -2
  81. package/src/jsx-runtime.ts +0 -12
  82. package/src/jsx.ts +0 -135
  83. package/src/message.ts +0 -48
  84. package/src/models/system-log.ts +0 -20
  85. package/src/models/user.ts +0 -15
  86. package/src/notice.ts +0 -98
  87. package/src/plugin.ts +0 -896
  88. package/src/prompt.ts +0 -293
  89. package/src/request.ts +0 -95
  90. package/src/scheduler/index.ts +0 -19
  91. package/src/scheduler/scheduler.ts +0 -372
  92. package/src/scheduler/types.ts +0 -74
  93. package/src/tool-zod.ts +0 -115
  94. package/src/types-generator.ts +0 -78
  95. package/src/types.ts +0 -505
  96. package/src/utils.ts +0 -227
  97. package/tests/adapter.test.ts +0 -638
  98. package/tests/ai/ai-trigger.test.ts +0 -368
  99. package/tests/ai/providers.integration.test.ts +0 -227
  100. package/tests/ai/setup.ts +0 -308
  101. package/tests/ai/tool.test.ts +0 -800
  102. package/tests/bot.test.ts +0 -151
  103. package/tests/command.test.ts +0 -737
  104. package/tests/component-new.test.ts +0 -361
  105. package/tests/config.test.ts +0 -372
  106. package/tests/cron.test.ts +0 -82
  107. package/tests/dispatcher.test.ts +0 -293
  108. package/tests/errors.test.ts +0 -21
  109. package/tests/expression-evaluation.test.ts +0 -258
  110. package/tests/features-builtin.test.ts +0 -191
  111. package/tests/jsx-runtime.test.ts +0 -45
  112. package/tests/jsx.test.ts +0 -319
  113. package/tests/message-filter.test.ts +0 -566
  114. package/tests/message.test.ts +0 -402
  115. package/tests/notice.test.ts +0 -198
  116. package/tests/plugin.test.ts +0 -779
  117. package/tests/prompt.test.ts +0 -78
  118. package/tests/redos-protection.test.ts +0 -198
  119. package/tests/request.test.ts +0 -221
  120. package/tests/schema.test.ts +0 -248
  121. package/tests/skill-feature.test.ts +0 -179
  122. package/tests/test-utils.ts +0 -59
  123. package/tests/tool-feature.test.ts +0 -254
  124. package/tests/types.test.ts +0 -162
  125. package/tests/utils.test.ts +0 -135
  126. package/tsconfig.json +0 -24
@@ -1,293 +0,0 @@
1
- /**
2
- * MessageDispatcher 测试
3
- */
4
- import { describe, it, expect, vi, beforeEach } from 'vitest';
5
- import { EventEmitter } from 'node:events';
6
- import {
7
- createMessageDispatcher,
8
- type MessageDispatcherService,
9
- } from '../src/built/dispatcher.js';
10
- import type { Message } from '../src/message.js';
11
- import type { Plugin } from '../src/plugin.js';
12
- import type { BeforeSendHandler } from '../src/types.js';
13
-
14
- function makeMessage(text: string, overrides: Partial<Message<any>> = {}): Message<any> {
15
- return {
16
- $id: '1',
17
- $content: [{ type: 'text', data: { text } }],
18
- $raw: text,
19
- $sender: { id: 'user1', name: 'User' },
20
- $channel: { id: 'ch1', type: 'group' },
21
- $adapter: 'test',
22
- $bot: 'bot1',
23
- $timestamp: Date.now(),
24
- $reply: vi.fn(),
25
- $recall: vi.fn(),
26
- ...overrides,
27
- } as any;
28
- }
29
-
30
- function makeRootWithCommand(
31
- handleImpl?: (msg: Message<any>, root: Plugin) => Promise<string | void>,
32
- ) {
33
- const handle = handleImpl ?? vi.fn(async () => 'cmd-ok');
34
- const cmdService = {
35
- items: [{ pattern: '/help ping' }],
36
- handle,
37
- };
38
- const root = new EventEmitter() as unknown as Plugin;
39
- (root as any).inject = (name: string) => {
40
- if (name === 'command') return cmdService;
41
- return undefined;
42
- };
43
- (root as any).root = root;
44
- return root;
45
- }
46
-
47
- /** 模拟 $reply → adapter.sendMessage → renderSendMessage(before.sendMessage) */
48
- function wireMessageReplyThroughBeforeSend(msg: Message<any>, root: EventEmitter) {
49
- msg.$reply = vi.fn(async (content: any) => {
50
- let options = {
51
- content,
52
- bot: msg.$bot,
53
- id: msg.$channel.id,
54
- type: msg.$channel.type,
55
- context: 'test',
56
- };
57
- const fns = root.listeners('before.sendMessage') as BeforeSendHandler[];
58
- for (const fn of fns) {
59
- const r = await fn(options);
60
- if (r) options = r;
61
- }
62
- return 'mock-msg-id';
63
- });
64
- }
65
-
66
- describe('createMessageDispatcher', () => {
67
- let context: ReturnType<typeof createMessageDispatcher>;
68
- let service: MessageDispatcherService;
69
-
70
- beforeEach(() => {
71
- context = createMessageDispatcher();
72
- service = context.value;
73
- });
74
-
75
- it('应返回正确的 context 结构', () => {
76
- expect(context.name).toBe('dispatcher');
77
- expect(context.description).toContain('消息调度器');
78
- expect(context.value).toBeDefined();
79
- expect(typeof context.value.dispatch).toBe('function');
80
- expect(typeof context.value.addGuardrail).toBe('function');
81
- expect(typeof context.value.setCommandMatcher).toBe('function');
82
- expect(typeof context.value.setAITriggerMatcher).toBe('function');
83
- expect(typeof context.value.setAIHandler).toBe('function');
84
- expect(typeof context.value.hasAIHandler).toBe('function');
85
- expect(typeof context.value.addOutboundPolish).toBe('function');
86
- expect(typeof context.value.replyWithPolish).toBe('function');
87
- expect(typeof service.matchCommand).toBe('function');
88
- expect(typeof service.matchAI).toBe('function');
89
- });
90
-
91
- describe('Guardrail', () => {
92
- it('应能添加和移除 Guardrail', () => {
93
- const guardrail = vi.fn(async (_msg: any, next: any) => next());
94
- const remove = service.addGuardrail(guardrail);
95
-
96
- expect(typeof remove).toBe('function');
97
- remove();
98
- });
99
-
100
- it('Guardrail 应在 dispatch 中执行', async () => {
101
- const calls: string[] = [];
102
-
103
- service.addGuardrail(async (_msg, next) => {
104
- calls.push('g1');
105
- await next();
106
- });
107
- service.addGuardrail(async (_msg, next) => {
108
- calls.push('g2');
109
- await next();
110
- });
111
-
112
- const msg = makeMessage('hello');
113
- await service.dispatch(msg);
114
-
115
- expect(calls).toEqual(['g1', 'g2']);
116
- });
117
-
118
- it('Guardrail 抛异常应拦截消息', async () => {
119
- service.addGuardrail(async () => {
120
- throw new Error('blocked');
121
- });
122
-
123
- const aiHandler = vi.fn();
124
- service.setAIHandler(aiHandler);
125
- service.setAITriggerMatcher(() => ({ triggered: true, content: 'test' }));
126
-
127
- const msg = makeMessage('hello');
128
- await service.dispatch(msg);
129
-
130
- expect(aiHandler).not.toHaveBeenCalled();
131
- });
132
- });
133
-
134
- describe('AI Handler', () => {
135
- it('初始无 AI handler', () => {
136
- expect(service.hasAIHandler()).toBe(false);
137
- });
138
-
139
- it('注册后 hasAIHandler 返回 true', () => {
140
- service.setAIHandler(async () => {});
141
- expect(service.hasAIHandler()).toBe(true);
142
- });
143
-
144
- it('AI 触发时应调用 handler', async () => {
145
- const handler = vi.fn();
146
- service.setAIHandler(handler);
147
- service.setAITriggerMatcher(() => ({
148
- triggered: true,
149
- content: 'processed content',
150
- }));
151
-
152
- const msg = makeMessage('你好');
153
- await service.dispatch(msg);
154
-
155
- expect(handler).toHaveBeenCalledWith(msg, 'processed content');
156
- });
157
-
158
- it('AI 不触发时不应调用 handler', async () => {
159
- const handler = vi.fn();
160
- service.setAIHandler(handler);
161
- service.setAITriggerMatcher(() => ({ triggered: false, content: '' }));
162
-
163
- const msg = makeMessage('random');
164
- await service.dispatch(msg);
165
-
166
- expect(handler).not.toHaveBeenCalled();
167
- });
168
- });
169
-
170
- describe('Command Matcher (exclusive)', () => {
171
- it('自定义命令匹配器应优先并阻断 AI(互斥模式)', async () => {
172
- const exclusiveCtx = createMessageDispatcher({ dualRoute: { mode: 'exclusive' } });
173
- const d = exclusiveCtx.value;
174
- const aiHandler = vi.fn();
175
- d.setAIHandler(aiHandler);
176
- d.setAITriggerMatcher(() => ({ triggered: true, content: '' }));
177
- d.setCommandMatcher((text) => text.startsWith('/'));
178
-
179
- const msg = makeMessage('/help');
180
- await d.dispatch(msg);
181
-
182
- expect(aiHandler).not.toHaveBeenCalled();
183
- });
184
- });
185
-
186
- describe('双轨 dual 模式', () => {
187
- it('同时命中指令与 AI 时应各执行一次(默认 command-first)', async () => {
188
- const root = makeRootWithCommand();
189
- const fakePlugin = { root } as Plugin;
190
- context.mounted(fakePlugin);
191
-
192
- const aiHandler = vi.fn();
193
- service.setAIHandler(aiHandler);
194
- service.setAITriggerMatcher(() => ({ triggered: true, content: 'hi' }));
195
- service.setDualRouteConfig({ mode: 'dual', order: 'command-first', allowDualReply: true });
196
-
197
- const msg = makeMessage('/help');
198
- wireMessageReplyThroughBeforeSend(msg, root as unknown as EventEmitter);
199
- await service.dispatch(msg);
200
-
201
- const cmd = root.inject('command') as any;
202
- expect(cmd.handle).toHaveBeenCalled();
203
- expect(aiHandler).toHaveBeenCalledWith(msg, 'hi');
204
- expect(msg.$reply).toHaveBeenCalledWith('cmd-ok');
205
- });
206
-
207
- it('ai-first 时应先 AI 后指令', async () => {
208
- const order: string[] = [];
209
- const root = makeRootWithCommand(async () => {
210
- order.push('cmd');
211
- return 'c';
212
- });
213
- const fakePlugin = { root } as Plugin;
214
- context.mounted(fakePlugin);
215
-
216
- service.setAIHandler(async () => {
217
- order.push('ai');
218
- });
219
- service.setAITriggerMatcher(() => ({ triggered: true, content: 'x' }));
220
- service.setDualRouteConfig({ mode: 'dual', order: 'ai-first', allowDualReply: true });
221
-
222
- const msg = makeMessage('/help');
223
- wireMessageReplyThroughBeforeSend(msg, root as unknown as EventEmitter);
224
- await service.dispatch(msg);
225
-
226
- expect(order).toEqual(['ai', 'cmd']);
227
- });
228
-
229
- it('allowDualReply false 且 command-first 时仅执行指令', async () => {
230
- const root = makeRootWithCommand();
231
- const fakePlugin = { root } as Plugin;
232
- context.mounted(fakePlugin);
233
-
234
- const aiHandler = vi.fn();
235
- service.setAIHandler(aiHandler);
236
- service.setAITriggerMatcher(() => ({ triggered: true, content: 'x' }));
237
- service.setDualRouteConfig({ mode: 'dual', order: 'command-first', allowDualReply: false });
238
-
239
- const msg = makeMessage('/help');
240
- wireMessageReplyThroughBeforeSend(msg, root as unknown as EventEmitter);
241
- await service.dispatch(msg);
242
-
243
- expect(aiHandler).not.toHaveBeenCalled();
244
- expect(msg.$reply).toHaveBeenCalled();
245
- });
246
- });
247
-
248
- describe('出站润色', () => {
249
- it('replyWithPolish 应经 before.sendMessage 链式润色再发出($reply 入参仍为原文)', async () => {
250
- const root = new EventEmitter() as unknown as Plugin;
251
- (root as any).inject = () => undefined;
252
- (root as any).root = root;
253
- context.mounted({ root } as Plugin);
254
-
255
- const p1 = vi.fn(async (ctx: any) => `[1]${ctx.content}`);
256
- const p2 = vi.fn(async (ctx: any) => `${ctx.content}[2]`);
257
- service.addOutboundPolish(p1);
258
- service.addOutboundPolish(p2);
259
-
260
- const msg = makeMessage('x');
261
- wireMessageReplyThroughBeforeSend(msg, root as unknown as EventEmitter);
262
- await service.replyWithPolish(msg, 'ai', 'hello');
263
-
264
- expect(p1).toHaveBeenCalled();
265
- expect(p2).toHaveBeenCalled();
266
- expect(msg.$reply).toHaveBeenCalledWith('hello');
267
- });
268
-
269
- it('指令路径应经过润色', async () => {
270
- const root = makeRootWithCommand(async () => 'out');
271
- const fakePlugin = { root } as Plugin;
272
- context.mounted(fakePlugin);
273
-
274
- service.addOutboundPolish(async (ctx) => `<<${ctx.content}>>`);
275
- service.setDualRouteConfig({ mode: 'exclusive' });
276
-
277
- const msg = makeMessage('/help');
278
- wireMessageReplyThroughBeforeSend(msg, root as unknown as EventEmitter);
279
- await service.dispatch(msg);
280
-
281
- expect(msg.$reply).toHaveBeenCalledWith('out');
282
- });
283
- });
284
-
285
- describe('extensions', () => {
286
- it('应提供 addGuardrail 扩展', () => {
287
- expect(typeof context.extensions.addGuardrail).toBe('function');
288
- });
289
- it('应提供 addOutboundPolish 扩展', () => {
290
- expect(typeof context.extensions.addOutboundPolish).toBe('function');
291
- });
292
- });
293
- });
@@ -1,21 +0,0 @@
1
- /**
2
- * Core 特有的错误类型测试(通用错误测试已迁移到 @zhin.js/kernel)
3
- */
4
- import { describe, it, expect } from 'vitest'
5
- import { AdapterError, MessageError } from '../src/errors.js'
6
-
7
- describe('Core 特有错误类型', () => {
8
- it('AdapterError应该包含适配器信息', () => {
9
- const error = new AdapterError('适配器连接失败', 'icqq', 'bot-123')
10
- expect(error.code).toBe('ADAPTER_ERROR')
11
- expect(error.adapterName).toBe('icqq')
12
- expect(error.botName).toBe('bot-123')
13
- })
14
-
15
- it('MessageError应该包含消息信息', () => {
16
- const error = new MessageError('消息发送失败', 'msg-123', 'channel-456')
17
- expect(error.code).toBe('MESSAGE_ERROR')
18
- expect(error.messageId).toBe('msg-123')
19
- expect(error.channelId).toBe('channel-456')
20
- })
21
- })
@@ -1,258 +0,0 @@
1
- import { describe, it, expect, beforeEach, vi } from 'vitest'
2
- import {
3
- defineComponent,
4
- createComponentContext,
5
- getProps,
6
- ComponentContext
7
- } from '../src/component'
8
-
9
- // Mock utils functions
10
- vi.mock('../src/utils', () => ({
11
- getValueWithRuntime: vi.fn((expression, context) => {
12
- // 简单的表达式求值实现,用于测试
13
- try {
14
- // 创建一个安全的执行环境,不使用 with 语句
15
- const safeEval = new Function('context', `
16
- const { user, items, config, Math, String, Array } = context || {};
17
- return (${expression});
18
- `)
19
- return safeEval(context || {})
20
- } catch (error) {
21
- return expression
22
- }
23
- }),
24
- compiler: vi.fn((template, context) => template),
25
- segment: {
26
- toString: vi.fn((content) => typeof content === 'string' ? content : JSON.stringify(content)),
27
- from: vi.fn((content) => content),
28
- escape: vi.fn((content) => content.replace(/</g, '&lt;').replace(/>/g, '&gt;'))
29
- }
30
- }))
31
-
32
- describe('表达式求值测试', () => {
33
- let mockContext: ComponentContext
34
-
35
- beforeEach(() => {
36
- mockContext = createComponentContext(
37
- {
38
- user: { name: 'John', age: 25 },
39
- items: [1, 2, 3],
40
- config: { theme: 'dark', lang: 'en' },
41
- Math: Math,
42
- String: String,
43
- Array: Array
44
- },
45
- undefined,
46
- 'test template'
47
- )
48
- })
49
-
50
- describe('基本数学运算', () => {
51
- it('应该正确计算加法', () => {
52
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
53
- return 'test'
54
- }, 'test')
55
-
56
- const template = '<test sum={1+2+3} />'
57
- const props = getProps(TestComponent, template, mockContext)
58
-
59
- expect(props.sum).toBe(6)
60
- })
61
-
62
- it('应该正确计算乘法和除法', () => {
63
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
64
- return 'test'
65
- }, 'test')
66
-
67
- const template = '<test product={2*3*4} quotient={10/2} />'
68
- const props = getProps(TestComponent, template, mockContext)
69
-
70
- expect(props.product).toBe(24)
71
- expect(props.quotient).toBe(5)
72
- })
73
-
74
- it('应该正确处理负数和小数', () => {
75
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
76
- return 'test'
77
- }, 'test')
78
-
79
- const template = '<test negative={-5} decimal={3.14} />'
80
- const props = getProps(TestComponent, template, mockContext)
81
-
82
- expect(props.negative).toBe(-5)
83
- expect(props.decimal).toBe(3.14)
84
- })
85
- })
86
-
87
- describe('比较运算', () => {
88
- it('应该正确比较数字', () => {
89
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
90
- return 'test'
91
- }, 'test')
92
-
93
- const template = '<test greater={5>3} less={2<4} equal={3==3} />'
94
- const props = getProps(TestComponent, template, mockContext)
95
-
96
- expect(props.greater).toBe(true)
97
- expect(props.less).toBe(true)
98
- expect(props.equal).toBe(true)
99
- })
100
-
101
- it('应该正确处理字符串比较', () => {
102
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
103
- return 'test'
104
- }, 'test')
105
-
106
- const template = '<test strEqual={"hello" == "hello"} strNotEqual={"a" != "b"} />'
107
- const props = getProps(TestComponent, template, mockContext)
108
-
109
- // 字符串比较表达式解析有问题,暂时跳过
110
- // expect(props.strEqual).toBe(true)
111
- // expect(props.strNotEqual).toBe(true)
112
- expect(props.strEqual).toBe('hello" == "hello')
113
- expect(props.strNotEqual).toBe('a" != "b')
114
- })
115
- })
116
-
117
- describe('逻辑运算', () => {
118
- it('应该正确处理 AND 和 OR 运算', () => {
119
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
120
- return 'test'
121
- }, 'test')
122
-
123
- const template = '<test and={true && false} or={true || false} />'
124
- const props = getProps(TestComponent, template, mockContext)
125
-
126
- expect(props.and).toBe(false)
127
- expect(props.or).toBe(true)
128
- })
129
-
130
- it('应该正确处理 NOT 运算', () => {
131
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
132
- return 'test'
133
- }, 'test')
134
-
135
- const template = '<test notTrue={!true} notFalse={!false} />'
136
- const props = getProps(TestComponent, template, mockContext)
137
-
138
- expect(props.notTrue).toBe(false)
139
- expect(props.notFalse).toBe(true)
140
- })
141
- })
142
-
143
- describe('三元运算符', () => {
144
- it('应该正确处理条件表达式', () => {
145
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
146
- return 'test'
147
- }, 'test')
148
-
149
- const template = '<test result={5>3 ? "yes" : "no"} />'
150
- const props = getProps(TestComponent, template, mockContext)
151
-
152
- expect(props.result).toBe('yes')
153
- })
154
-
155
- it('应该正确处理嵌套三元运算符', () => {
156
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
157
- return 'test'
158
- }, 'test')
159
-
160
- const template = '<test result={5>10 ? "big" : 5>3 ? "medium" : "small"} />'
161
- const props = getProps(TestComponent, template, mockContext)
162
-
163
- expect(props.result).toBe('medium')
164
- })
165
- })
166
-
167
- describe('数组和对象操作', () => {
168
- it('应该正确处理数组字面量', () => {
169
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
170
- return 'test'
171
- }, 'test')
172
-
173
- const template = '<test items={[1,2,3]} />'
174
- const props = getProps(TestComponent, template, mockContext)
175
-
176
- expect(props.items).toEqual([1, 2, 3])
177
- })
178
-
179
- it('应该正确处理对象字面量', () => {
180
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
181
- return 'test'
182
- }, 'test')
183
-
184
- const template = '<test config={{name:"test",value:42}} />'
185
- const props = getProps(TestComponent, template, mockContext)
186
-
187
- expect(props.config).toEqual({ name: 'test', value: 42 })
188
- })
189
-
190
- })
191
-
192
-
193
- describe('上下文变量访问', () => {
194
- it('应该正确访问上下文中的变量', () => {
195
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
196
- return 'test'
197
- }, 'test')
198
-
199
- const template = '<test userName={user.name} userAge={user.age} />'
200
- const props = getProps(TestComponent, template, mockContext)
201
-
202
- expect(props.userName).toBe('John')
203
- expect(props.userAge).toBe(25)
204
- })
205
-
206
- it('应该正确处理嵌套对象访问', () => {
207
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
208
- return 'test'
209
- }, 'test')
210
-
211
- const template = '<test theme={config.theme} lang={config.lang} />'
212
- const props = getProps(TestComponent, template, mockContext)
213
-
214
- expect(props.theme).toBe('dark')
215
- expect(props.lang).toBe('en')
216
- })
217
- })
218
-
219
- describe('复杂表达式', () => {
220
- it('应该正确处理复杂的数学表达式', () => {
221
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
222
- return 'test'
223
- }, 'test')
224
-
225
- const template = '<test result={(1+2)*3+4/2} />'
226
- const props = getProps(TestComponent, template, mockContext)
227
-
228
- expect(props.result).toBe(11)
229
- })
230
-
231
- })
232
-
233
- describe('错误处理', () => {
234
- it('应该正确处理无效表达式', () => {
235
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
236
- return 'test'
237
- }, 'test')
238
-
239
- const template = '<test invalid={invalid.expression} />'
240
- const props = getProps(TestComponent, template, mockContext)
241
-
242
- // 无效表达式应该返回原始字符串
243
- expect(props.invalid).toBe('invalid.expression')
244
- })
245
-
246
- it('应该正确处理语法错误', () => {
247
- const TestComponent = defineComponent(async function TestComponent(props: any, context: ComponentContext) {
248
- return 'test'
249
- }, 'test')
250
-
251
- const template = '<test syntax={1+} />'
252
- const props = getProps(TestComponent, template, mockContext)
253
-
254
- // 语法错误应该返回原始字符串
255
- expect(props.syntax).toBe('1+')
256
- })
257
- })
258
- })