fix(core): invoke structured Signal listeners with runtime args before bound args#2987
fix(core): invoke structured Signal listeners with runtime args before bound args#2987cptbtptpbcptdtptp wants to merge 3 commits into
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 |
GuoLei1990
left a comment
There was a problem hiding this comment.
已关闭问题清单
历史 23 轮 review 的问题均已关闭:
- 参数顺序正确性 — 已多次验证正确,关闭。
- call-site 影响分析(closure vs structured binding) — 已确认引擎内无 listener 依赖旧顺序,关闭。
- breaking change 需记入 CHANGELOG — 历轮反复提出(P2/P1 均出现过),最终结论为非阻塞 P2,状态确认仍未落入 CHANGELOG 但不阻塞合入。按既定结论不再重提。
总结
将 structured binding listener 的调用顺序从 method(...boundArgs, ...signalArgs) 翻转为 method(...signalArgs, ...boundArgs),使 runtime signal 参数在前、bound 参数在后,event 对象固定在 index 0。
方向正确。这里刻意不遵循 Function.prototype.bind(bind 是前置 bound args),而是对齐 DOM addEventListener / Cocos (event, customData) 的事件回调约定——对 signal/event 系统而言这是本质正确的选择:回调第一个参数永远是事件本身。JSDoc 已显式写明 method(...signalArgs, ...args),契约自洽。
第一性原理复核(基于 PR HEAD eb8ac58b):
- 语义正确性 — 确认。runtime 在前、bound 在后,与 closure listener 语义一致,event 恒在 index 0。
- 向后兼容 — 4 个生产 Signal 实例(
onClick/onStateChanged/onTrackedDeviceChanged/onChanged)全部走 closure 形式,不受影响;唯一 structured-binding 生产调用点ReflectionParser.ts:181是反序列化透传,无 handler 逻辑;两个既有 bound-args 测试都用零 runtime args invoke,翻转后结果不变。 - 回归测试反向证伪 — 有效。把 fix revert 回
(...args, ...signalArgs):测试 "runtime args precede bound args" 期望["event", 42, "boundA", "boundB"]会变成["boundA", "boundB", "event", 42]→ fail;once 测试期望[99, "bound"]会变成["bound", 99]→ fail。测试真实守住了 bug。链路方式(invoke()触发 + 断言lastArgs)符合规范。 - 注释合规 — 新增 JSDoc 多行块结尾带句号、
@param用破折号不带句号,均合规。
问题
无新问题。LGTM,可合入。
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 的问题均已关闭:
- 参数顺序正确性(
...boundArgs, ...signalArgs→...signalArgs, ...boundArgs)— 多轮验证正确,关闭。 - call-site 影响分析(closure vs structured binding) — 已确认引擎内无 listener 依赖旧顺序(4 个 Signal 实例全 closure 形式,唯一 structured-binding 生产调用点是
ReflectionParser.ts:181透传),关闭。 - breaking change 需记入 CHANGELOG — 历轮反复提出,最终结论为非阻塞 P2,按既定结论不再重提。
- fixture 对齐(commit
74800f282) — 上轮(HEAD74800f282)已审,根因正确,关闭。
总结
本轮 HEAD 仍为 74800f282,与上轮审查的 commit 完全一致,无新 delta——稳态复审。生产代码 Signal.ts 自 eb8ac58b 起零改动(git diff eb8ac58b..74800f282 -- packages/core/src/Signal.ts 为空),核心修复(method(...signalArgs, ...args),event 固定在 index 0,对齐 DOM (event, customData))保持正确。
CI 全绿(build × 3 平台 / codecov-patch / e2e × 4 / lint 均 pass),74800f282 的 fixture 对齐已达成目的(修复了此前 UIInteractive.test.ts:241 与 CloneUtils.test.ts:618 的 CI 红)。
逐路径手验两处 fixture 翻转后正确:
CloneUtils.test.ts:604on(handler, "handleClickWithPrefix", "myPrefix")+invoke(1)→handleClickWithPrefix(arg=1, prefix="myPrefix"),断言lastPrefix==="myPrefix"✓(翻转前签名(prefix)会让prefix捕获到1→ 必红)。UIInteractive.test.ts:239on(handler, "handleClickWithPrefix", "myPrefix")+invoke(new PointerEventData())→handleClickWithPrefix(event=eventData, prefix="myPrefix"),断言lastPrefix==="myPrefix"✓。
问题
无新问题。
关于 CodeRabbit 本轮的两条 outside-diff 🔴 Critical(要求给 CloneUtils.test.ts 与 UIInteractive.test.ts 的 handleClick() 补 event/arg 形参)——均为误报,不需要改:handleClick() 经 structured binding 绑定后虽被携带 runtime 参数 invoke,但方法体本就不消费该参数(只 callCount++),JS 对多余实参直接丢弃、TS 不要求声明未使用的形参。三处用例(...:568/587/624 与 UI ...:189/215)只断言 callCount,行为完全正确。给这两个方法补形参纯属把误报落成噪声改动,不建议执行 CodeRabbit 的修复建议。
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