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.
总结
自上轮 review(HEAD eb8ac58b)以来,新增一个 commit 74800f282(test: align Signal structured-binding fixtures with new arg order)。生产代码 Signal.ts 零改动,本 commit 纯粹是把两个既有 fixture 补上前导 runtime 参数以修复 CI 红 + prettier 格式化。方向正确。
增量核对:
- 根因正确 — 原 fix commit
6728ba456翻转了调用顺序为method(...signalArgs, ...boundArgs),但漏改了CloneUtils.test.ts与UIInteractive.test.ts里的handleClickWithPrefixfixture(仍是单参(prefix))。翻转后这两处 fixture 的prefix会捕获到 runtime 信号参数而非绑定值 → CI 红。本 commit 把签名补成(arg: number, prefix)/(event: PointerEventData, prefix),prefix重新解析到绑定值"myPrefix",是补全6728ba456应做而未做的工作,落点正确。 - 逐路径验证 —
CloneUtils.test.ts:604注册("myPrefix")+invoke(1)→handleClickWithPrefix(1, "myPrefix")→prefix="myPrefix"✓;UIInteractive.test.ts:239注册("myPrefix")+invoke(PointerEventData)→handleClickWithPrefix(pointerEvent, "myPrefix")→prefix="myPrefix"✓。两处断言lastPrefix==="myPrefix"均成立。 - 反向证伪有效 — 把生产 fix revert 回
...args, ...signalArgs:两处会变成handleClickWithPrefix("myPrefix", runtimeArg)→prefix=runtimeArg(数字 1 / PointerEventData)→expect(lastPrefix).toBe("myPrefix")fail。新签名下这两个 fixture 真实守住回归。 - 非对称性自洽 —
Signal.test.ts同名 fixturehandleClickWithPrefix(prefix: string)保持单参且无需改,因为它的两处调用(206、407 行)都是零 runtime arg invoke(invoke()),顺序翻转对零参是 no-op,断言不受影响。改与不改的边界划得准。 - CI — 全绿(build / lint / e2e / codecov 全 pass)。
问题
无新问题。本 commit 是干净的 CI 修复,生产逻辑未变,历史已关闭问题(参数顺序正确性、call-site 影响、breaking-change CHANGELOG 非阻塞结论)均不复现。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