fix(core): invoke structured Signal listeners with runtime args before bound args#2987
Conversation
…e bound args Previously `Signal._addListener` applied bound arguments first and runtime signal args last, producing `method(...boundArgs, ...signalArgs)`. This made the event object's position shift with the number of bound arguments and diverged from the DOM / Cocos `(event, customEventData)` convention. Flip the order so the listener method receives runtime args first and bound args last: `method(...signalArgs, ...boundArgs)`. The event object now always sits at index 0, making migrated Cocos scripts with `(event, customData)` signatures work without rewrites. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add three test cases verifying that runtime signal args are passed before bound args: - "runtime args precede bound args" — full ordering with two of each. - "event object stays at index 0 regardless of bound args count" — position invariant of the conventional event argument. - "once: runtime + bound args order preserved" — same guarantee for once-style listeners. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
WalkthroughSignal's structured binding listener invocation now passes runtime signal arguments before pre-resolved bound arguments. The implementation is updated in the listener wrapper, documented in JSDoc for both ChangesSignal Argument Ordering for Structured Binding
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Commit 6728ba4 flipped structured-binding invocation to `method(...signalArgs, ...boundArgs)`, but two fixtures still treated the bound arg as the first parameter and captured the runtime signal arg instead of the prefix. Add the leading runtime arg to both `handleClickWithPrefix` fixtures so `prefix` resolves to the bound value. Fixes CI failures at UIInteractive.test.ts:241 and CloneUtils.test.ts:618. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
tests/src/ui/UIInteractive.test.ts (1)
16-28:⚠️ Potential issue | 🔴 CriticalUpdate
handleClick()to acceptPointerEventDataparameter.The
handleClick()method is missing thePointerEventDataparameter that was added tohandleClickWithPrefix(). Both methods are used as Signal handlers and should follow the same argument ordering. UpdatehandleClick()to:handleClick(event: PointerEventData) { this.callCount++; }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/src/ui/UIInteractive.test.ts` around lines 16 - 28, The handleClick() method in the ClickHandler class is missing the PointerEventData parameter that is required for Signal handlers. Update the handleClick() method signature to include the event parameter of type PointerEventData as the first parameter, matching the signature pattern used in handleClickWithPrefix(). This ensures both methods can be properly used as Signal handlers with consistent argument ordering.tests/src/core/CloneUtils.test.ts (1)
95-107:⚠️ Potential issue | 🔴 CriticalUpdate
handleClick()to accept the Signal data parameter.The
handleClick()method should receive the number argument emitted by the Signal, matching the structured binding convention wheremethod(...signalArgs, ...args)places runtime signal arguments first. Change:handleClick(): void { this.callCount++; }to:
handleClick(arg: number): void { this.callCount++; }The
handleClickWithPrefix()method is already correct. No other handler methods exist in this test file.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/src/core/CloneUtils.test.ts` around lines 95 - 107, The handleClick() method in the ClickHandler class does not accept the Signal data parameter that is being emitted, while handleClickWithPrefix() correctly accepts parameters. Update the handleClick() method signature to accept the arg: number parameter as the first parameter, matching the signal binding convention where runtime signal arguments are passed before custom arguments.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@tests/src/core/CloneUtils.test.ts`:
- Around line 95-107: The handleClick() method in the ClickHandler class does
not accept the Signal data parameter that is being emitted, while
handleClickWithPrefix() correctly accepts parameters. Update the handleClick()
method signature to accept the arg: number parameter as the first parameter,
matching the signal binding convention where runtime signal arguments are passed
before custom arguments.
In `@tests/src/ui/UIInteractive.test.ts`:
- Around line 16-28: The handleClick() method in the ClickHandler class is
missing the PointerEventData parameter that is required for Signal handlers.
Update the handleClick() method signature to include the event parameter of type
PointerEventData as the first parameter, matching the signature pattern used in
handleClickWithPrefix(). This ensures both methods can be properly used as
Signal handlers with consistent argument ordering.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro
Run ID: fb3b2753-084b-4402-a3a6-c19939f1c0b2
📒 Files selected for processing (2)
tests/src/core/CloneUtils.test.tstests/src/ui/UIInteractive.test.ts
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## dev/2.0 #2987 +/- ##
===========================================
+ Coverage 78.25% 79.89% +1.64%
===========================================
Files 900 919 +19
Lines 99234 102586 +3352
Branches 10172 11348 +1176
===========================================
+ Hits 77657 81966 +4309
+ Misses 21406 20438 -968
- Partials 171 182 +11
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
GuoLei1990
left a comment
There was a problem hiding this comment.
已关闭问题清单
历史 24+ 轮 review 的问题均已关闭:
- 参数顺序正确性(
method(...boundArgs, ...signalArgs)→method(...signalArgs, ...boundArgs))— 多轮验证正确,关闭。 - call-site 影响分析(closure vs structured binding) — 已确认引擎内无 listener 依赖旧顺序,关闭(详见下方复核)。
- breaking change 需记入 CHANGELOG — 历轮反复提出,最终结论为非阻塞 P2,按既定结论不再重提。
- fixture 对齐(commit
74800f28) — 已审,根因正确,关闭。
总结
本轮 HEAD 仍为 74800f28,与上轮审查的 commit 完全一致,无新 delta——稳态复审。核心修复(method(...signalArgs, ...args),让 event 对象固定在 index 0,对齐 DOM addEventListener / Cocos (event, customData) 约定)方向正确,实现最小化。
第一性原理复核(独立于历轮共识,基于本次读源码)
- 方向正确性 — 确认。
git log -S追溯显示旧顺序(...args, ...signalArgs)是 PR #2921(新建Signal.ts)引入的初始设计选择,本 PR 不是回退某个fix:commit,而是修正一个从未正确过的顺序。event/signal 系统里回调第一参恒为事件本身,是本质正确的约定;JSDoc 已显式写明method(...signalArgs, ...args),契约自洽。 - 向后兼容 — 4 个生产 Signal 实例(
Button.onClick/XRSessionManager.onStateChanged/XRInputManager.onTrackedDeviceChanged/XRTrackableFeature.onChanged)全部走 closure 形式(传函数,不传 component+methodName),参数顺序翻转对它们零影响。唯一的 structured-binding 生产调用点是ReflectionParser.ts:181(反序列化 scene 数据时透传signal.on(targetComponent, methodName, ...resolvedArgs)),本身不含 handler 逻辑,不会"坏"。 - 回归测试反向证伪 — 有效。新测试 "runtime args precede bound args" 期望
["event", 42, "boundA", "boundB"],把 fix revert 回(...args, ...signalArgs)→ 变成["boundA", "boundB", "event", 42]fail;once 测试期望[99, "bound"]→ 变成["bound", 99]fail。测试通过invoke()触发 + 断言lastArgs走公开链路,不戳私有字段,符合规范。 - fixture 修复落点 — commit
74800f28把CloneUtils.test.ts/UIInteractive.test.ts的handleClickWithPrefix从单参(prefix)补成(arg, prefix)/(event, prefix),是补全首个 fix commit 漏改的部分,prefix重新解析到绑定值;Signal.test.ts同名 fixture 因两处调用均零 runtime arg invoke 而无需改,改与不改的边界划得准。 - 注释合规 — 新增 JSDoc 多行块结尾带句号、
@param用破折号不带类型不带句号,均合规。
问题
无新问题。
关于 CodeRabbit 历轮的 outside-diff 🔴 Critical(要求给 handleClick() 补 event/arg 形参)——误报,不需要改:handleClick() 方法体不消费 runtime 参数(只 callCount++),JS 对多余实参直接丢弃、TS 不要求声明未使用的形参,相关用例只断言 callCount,行为正确。补形参纯属把误报落成噪声改动,不建议执行。
LGTM,可合入。
Summary
method(...boundArgs, ...signalArgs)tomethod(...signalArgs, ...boundArgs), so the event object always sits at index 0.(event, customData)convention.Background
Cherry-picked from
b16d8b5d7on fix/shaderlab.Test plan
Signal.test.tscases: arg ordering, event index 0 invariant,once()parity🤖 Generated with Claude Code
Summary by CodeRabbit
Summary by CodeRabbit
Bug Fixes
Tests
Chores