fix(canon): loosen component fallthrough listener events#2732
Conversation
📝 WalkthroughWalkthroughThe PR changes component event argument type inference to fall back to ChangesAvoid native DOM typing for component fallthrough listeners
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
vize
@vizejs/fresco
@vizejs/musea-mcp-server
oxlint-plugin-vize
@vizejs/rspack-plugin
@vizejs/unplugin
@vizejs/vite-plugin
@vizejs/vite-plugin-musea
@vizejs/musea-nuxt
@vizejs/nuxt
commit: |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In
`@crates/vize_canon/src/batch/type_checker/tests/component_fallthrough_listeners.rs`:
- Around line 34-39: Strengthen the regression test in
component_fallthrough_listeners.rs by replacing the narrow snapshot filter
around the existing assert! with a full no-diagnostics check, since the repro is
expected to type-check cleanly. Update the test around snapshot so it asserts
the snapshot is empty (or otherwise verifies there are no diagnostics for the
file), using the existing snapshot variable and the same test case setup to
catch any unexpected errors, not just TS2345/TouchEvent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: 3581ef1a-b4eb-497e-a909-4dc49c6cfa9f
📒 Files selected for processing (4)
crates/vize_canon/src/batch/type_checker/tests.rscrates/vize_canon/src/batch/type_checker/tests/component_fallthrough_listeners.rscrates/vize_canon/src/virtual_ts/scope/component_events.rscrates/vize_canon/src/virtual_ts/tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (28)
- GitHub Check: Publish preview packages
- GitHub Check: cargo-semver-checks (vize_carton)
- GitHub Check: cargo-semver-checks (vize_atelier_vapor)
- GitHub Check: cargo-semver-checks (vize_croquis)
- GitHub Check: cargo-semver-checks (vize_atelier_dom)
- GitHub Check: cargo-semver-checks (vize_musea)
- GitHub Check: cargo-semver-checks (vize_atelier_sfc)
- GitHub Check: cargo-semver-checks (vize_relief)
- GitHub Check: cargo-semver-checks (vize_fresco)
- GitHub Check: cargo-semver-checks (vize_armature)
- GitHub Check: cargo-semver-checks (vize_atelier_ssr)
- GitHub Check: cargo-semver-checks (vize_atelier_core)
- GitHub Check: editor-extensions
- GitHub Check: clippy-and-test
- GitHub Check: node-engine-compat (22)
- GitHub Check: coverage
- GitHub Check: test-js-packages
- GitHub Check: security-audit
- GitHub Check: check-vize-apps
- GitHub Check: test-scripts
- GitHub Check: vue-parity
- GitHub Check: check-js
- GitHub Check: build-js-packages
- GitHub Check: dialect-guard
- GitHub Check: pr-benchmark
- GitHub Check: criterion-ab
- GitHub Check: tool-benchmark
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (1)
crates/**
⚙️ CodeRabbit configuration file
crates/**: Focus on parser/compiler correctness, source locations, UTF-8/UTF-16 offset handling, and panic-free LSP behavior. Flag changes that only work for small fixtures but break real Vue/Nuxt projects.
Files:
crates/vize_canon/src/batch/type_checker/tests/component_fallthrough_listeners.rscrates/vize_canon/src/batch/type_checker/tests.rscrates/vize_canon/src/virtual_ts/scope/component_events.rscrates/vize_canon/src/virtual_ts/tests.rs
🔇 Additional comments (4)
crates/vize_canon/src/virtual_ts/scope/component_events.rs (1)
12-12: Fallback logic correctly avoids native DOM typing.The reordered ternary (
extends [] ? any : unknown[] extends {args_type} ? any : {args_type}[0]) ensures theunknown[](unresolved) case is caught and resolves toanybefore the{args_type}[0]indexing branch is reached, so no unsafe indexing into an empty/unresolved tuple occurs. This correctly implements the PR's intent of treating undeclared component listeners as loose rather than DOM-typed.Also applies to: 133-138
crates/vize_canon/src/virtual_ts/tests.rs (1)
1586-1637: LGTM!crates/vize_canon/src/batch/type_checker/tests.rs (1)
12-12: LGTM!crates/vize_canon/src/batch/type_checker/tests/component_fallthrough_listeners.rs (1)
4-42: LGTM!
| assert!( | ||
| snapshot.iter().all(|(file, code, message)| { | ||
| !(file == "src/Foo.vue" && *code == Some(2345) && message.contains("TouchEvent")) | ||
| }), | ||
| "component fallthrough listeners should not be checked as native DOM listeners, got: {snapshot:#?}" | ||
| ); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
Consider asserting zero diagnostics for a stronger regression guard.
The test only checks that no TS2345/"TouchEvent" diagnostic exists for src/Foo.vue, rather than asserting the snapshot is fully clean. Since the repro is expected to type-check cleanly (matching vue-tsc), asserting snapshot.is_empty() (or filtering to file-level diagnostics being empty) would catch other regressions the narrower filter might miss.
♻️ Suggested stronger assertion
- assert!(
- snapshot.iter().all(|(file, code, message)| {
- !(file == "src/Foo.vue" && *code == Some(2345) && message.contains("TouchEvent"))
- }),
- "component fallthrough listeners should not be checked as native DOM listeners, got: {snapshot:#?}"
- );
+ assert!(
+ snapshot.iter().all(|(file, _, _)| file != "src/Foo.vue"),
+ "component fallthrough listeners should not produce diagnostics, got: {snapshot:#?}"
+ );📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| assert!( | |
| snapshot.iter().all(|(file, code, message)| { | |
| !(file == "src/Foo.vue" && *code == Some(2345) && message.contains("TouchEvent")) | |
| }), | |
| "component fallthrough listeners should not be checked as native DOM listeners, got: {snapshot:#?}" | |
| ); | |
| assert!( | |
| snapshot.iter().all(|(file, _, _)| file != "src/Foo.vue"), | |
| "component fallthrough listeners should not produce diagnostics, got: {snapshot:#?}" | |
| ); |
🤖 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
`@crates/vize_canon/src/batch/type_checker/tests/component_fallthrough_listeners.rs`
around lines 34 - 39, Strengthen the regression test in
component_fallthrough_listeners.rs by replacing the narrow snapshot filter
around the existing assert! with a full no-diagnostics check, since the repro is
expected to type-check cleanly. Update the test around snapshot so it asserts
the snapshot is empty (or otherwise verifies there are no diagnostics for the
file), using the existing snapshot variable and the same test case setup to
catch any unexpected errors, not just TS2345/TouchEvent.
PR BenchmarkBase:
Raw run timesCompile SFC
Lint
Format
Type check (1T)
Type check (max)
|
Detailed Test ReportCommit: Area Summary
Test InventoryTotal tracked cases: 8622 across 1213 files.
Files
Comment truncated at 64000 characters. Open the workflow run for the full job log. |
998dd44 to
5ec12f5
Compare
PR BenchmarkBase:
Raw run timesCompile SFC
Lint
Format
Type check (1T)
Type check (max)
|
5ec12f5 to
14cafe7
Compare
Detailed Test ReportCommit: Area Summary
Test InventoryTotal tracked cases: 8622 across 1212 files.
Files
Comment truncated at 64000 characters. Open the workflow run for the full job log. |
PR BenchmarkBase:
Raw run timesCompile SFC
Lint
Format
Type check (1T)
Type check (max)
|
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 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.
Inline comments:
In
`@crates/vize_canon/src/batch/type_checker/tests/generic_component_listener_payload.rs`:
- Around line 3-43: The new regression test in
batch_type_checker_accepts_component_fallthrough_touch_listener only filters out
TS2345 TouchEvent diagnostics, so unrelated errors on src/Foo.vue could still
slip through. Tighten the assertion around snapshot_project_diagnostics in this
test by checking that the file has no diagnostics at all, or otherwise
explicitly excluding only the expected fallthrough-listener behavior, so the
test fully covers the intended scenario.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: a6e043cc-cc70-4267-af28-b36ae57d90ef
⛔ Files ignored due to path filters (1)
crates/vize_canon/snapshots/vize_canon__virtual_ts__tests__virtual_ts_kebab_case_component_names.snapis excluded by!**/*.snap,!**/*.snap
📒 Files selected for processing (4)
crates/vize_canon/src/batch/type_checker/tests/generic_component_listener_payload.rscrates/vize_canon/src/virtual_ts/legacy_vue2_vuetify_tests.rscrates/vize_canon/src/virtual_ts/scope/component_events.rscrates/vize_canon/src/virtual_ts/tests.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (6)
- GitHub Check: tool-benchmark
- GitHub Check: dialect-guard
- GitHub Check: criterion-ab
- GitHub Check: Publish preview packages
- GitHub Check: pr-benchmark
- GitHub Check: Analyze (javascript-typescript)
🧰 Additional context used
📓 Path-based instructions (1)
crates/**
⚙️ CodeRabbit configuration file
crates/**: Focus on parser/compiler correctness, source locations, UTF-8/UTF-16 offset handling, and panic-free LSP behavior. Flag changes that only work for small fixtures but break real Vue/Nuxt projects.
Files:
crates/vize_canon/src/batch/type_checker/tests/generic_component_listener_payload.rscrates/vize_canon/src/virtual_ts/legacy_vue2_vuetify_tests.rscrates/vize_canon/src/virtual_ts/scope/component_events.rscrates/vize_canon/src/virtual_ts/tests.rs
🔇 Additional comments (3)
crates/vize_canon/src/virtual_ts/tests.rs (1)
1586-1637: LGTM!crates/vize_canon/src/virtual_ts/legacy_vue2_vuetify_tests.rs (1)
70-89: LGTM!crates/vize_canon/src/virtual_ts/scope/component_events.rs (1)
12-12: 🎯 Functional CorrectnessFallback logic stays scoped to component listeners.
| #[test] | ||
| fn batch_type_checker_accepts_component_fallthrough_touch_listener() { | ||
| if resolve_test_tsgo_binary().is_none() { | ||
| return; | ||
| } | ||
| let project_root = create_project_case( | ||
| "component-fallthrough-touch-listener", | ||
| &[( | ||
| "src/Foo.vue", | ||
| r#"<script setup lang="ts"> | ||
| import { defineComponent, h } from "vue"; | ||
|
|
||
| const Child = defineComponent(() => () => h("button")); | ||
|
|
||
| function onPress(event: MouseEvent) { | ||
| event.preventDefault(); | ||
| } | ||
| </script> | ||
|
|
||
| <template> | ||
| <Child @touchstart="onPress" /> | ||
| </template> | ||
| "#, | ||
| )], | ||
| ); | ||
|
|
||
| let Some(snapshot) = snapshot_project_diagnostics(&project_root) else { | ||
| let _ = std::fs::remove_dir_all(&project_root); | ||
| return; | ||
| }; | ||
|
|
||
| assert!( | ||
| snapshot.iter().all(|(file, code, message)| { | ||
| !(file == "src/Foo.vue" && *code == Some(2345) && message.contains("TouchEvent")) | ||
| }), | ||
| "component fallthrough listeners should not be checked as native DOM listeners, got: {snapshot:#?}" | ||
| ); | ||
|
|
||
| let _ = std::fs::remove_dir_all(&project_root); | ||
| } | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🔵 Trivial | 💤 Low value
Good regression coverage for the exact reported issue.
Test correctly reproduces the #2720 repro (component without declared touchstart emit, handler typed MouseEvent) and asserts absence of TS2345/TouchEvent diagnostics on src/Foo.vue.
One minor gap: the assertion only checks that no 2345+"TouchEvent" diagnostic exists; it doesn't assert that zero diagnostics exist overall for the file, so an unrelated new diagnostic on onPress/Child wouldn't be caught. Given this mirrors the narrow scope of the bug being fixed, this is a reasonable tradeoff.
🤖 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
`@crates/vize_canon/src/batch/type_checker/tests/generic_component_listener_payload.rs`
around lines 3 - 43, The new regression test in
batch_type_checker_accepts_component_fallthrough_touch_listener only filters out
TS2345 TouchEvent diagnostics, so unrelated errors on src/Foo.vue could still
slip through. Tighten the assertion around snapshot_project_diagnostics in this
test by checking that the file has no diagnostics at all, or otherwise
explicitly excluding only the expected fallthrough-listener behavior, so the
test fully covers the intended scenario.
Detailed Test ReportCommit: Area Summary
Test InventoryTotal tracked cases: 8623 across 1212 files.
Files
Comment truncated at 64000 characters. Open the workflow run for the full job log. |
Tool BenchmarkMeasured: 2026-07-08T18:23:36.536Z
Fairness notes:
Commands: gh workflow run tool-benchmark.yml --ref <branch> -f file_count=3000 -f check_file_count=500 -f vite_file_count=1000 -f nuxt_file_count=250 -f large_blocks=300 -f runs=3 -f warmups=1 -f commit_results=true
node bench/generate.mjs 3000
node bench/compare-tools.mjs --input bench/__in__ --vize-bin target/release/vize --runs 3 --warmups 1 --check-file-count 500 --vite-file-count 1000 --nuxt-file-count 250 --large-blocks 300 --runner-label "blacksmith-32vcpu-ubuntu-2404" --out tool-benchmark-summary.md --json tool-benchmark-results.json --doc performance-blacksmith.mdVariant details and raw run timesSFC compile
Large SFC compile
Large SFC type check
Lint
Format
Type check
Vite build (end-to-end)
Nuxt SPA build (end-to-end)
|
Summary
Tests
Closes #2720
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by CodeRabbit