perf(patina): prefilter prop destructure scan#2730
Conversation
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: |
📝 WalkthroughWalkthroughAdds a heuristic source-text prefilter to the no-deep-destructure-in-props rule so the AST visitor only runs when ChangesDeep Destructure Prefilter
Estimated code review effort: 3 (Moderate) | ~20 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
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_patina/src/rules/script/no_deep_destructure_in_props.rs`:
- Around line 211-215: Avoid slicing source by byte index in
declaration_keyword_at, because contains_object_binding_declaration can pass a
non-char-boundary index and panic on UTF-8 input. Update declaration_keyword_at
to work on source.as_bytes() (or otherwise avoid source[index..]) while still
checking the same keyword matches and boundaries, and keep the logic aligned
with has_keyword_boundaries and the existing contains_object_binding_declaration
flow.
🪄 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: f035c801-1d60-406b-b5f6-4be291e017ad
📒 Files selected for processing (1)
crates/vize_patina/src/rules/script/no_deep_destructure_in_props.rs
📜 Review details
⏰ Context from checks skipped due to timeout. (16)
- GitHub Check: pr-benchmark
- GitHub Check: dialect-guard
- GitHub Check: criterion-ab
- GitHub Check: cargo-semver-checks (vize_fresco)
- GitHub Check: cargo-semver-checks (vize_atelier_vapor)
- GitHub Check: cargo-semver-checks (vize_atelier_core)
- GitHub Check: cargo-semver-checks (vize_atelier_dom)
- GitHub Check: editor-extensions
- GitHub Check: clippy-and-test
- GitHub Check: vue-parity
- GitHub Check: test-scripts
- GitHub Check: test-js-packages
- GitHub Check: build-js-packages
- GitHub Check: cargo-semver-checks (vize_carton)
- 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_patina/src/rules/script/no_deep_destructure_in_props.rs
🔇 Additional comments (2)
crates/vize_patina/src/rules/script/no_deep_destructure_in_props.rs (2)
73-80: LGTM!
303-303: LGTM!
| fn declaration_keyword_at(source: &str, index: usize) -> Option<&'static str> { | ||
| ["const", "let", "var"].into_iter().find(|keyword| { | ||
| source[index..].starts_with(keyword) && has_keyword_boundaries(source, index, keyword) | ||
| }) | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Reproduce the mid-char slice panic path: any multi-byte char makes `index` land off-boundary.
rg -nP 'source\[index\.\.\]|index \+= 1' crates/vize_patina/src/rules/script/no_deep_destructure_in_props.rsRepository: ubugeeei-prod/vize
Length of output: 283
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the relevant functions with line numbers.
sed -n '175,225p' crates/vize_patina/src/rules/script/no_deep_destructure_in_props.rs
# Run a small read-only probe to see whether the current `declaration_keyword_at`
# pattern panics when `index` lands inside a multi-byte UTF-8 character.
python3 - <<'PY'
source = "aéconst"
for i in range(len(source.encode("utf-8"))):
try:
_ = source[i:]
ok = True
except Exception as e:
ok = False
print(i, ok)
PYRepository: ubugeeei-prod/vize
Length of output: 1623
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Show whether Rust slicing panics on a non-char boundary and whether byte-by-byte
# scanning can hit such a boundary for a multibyte string.
cat >/tmp/utf8_slice_probe.rs <<'RS'
fn main() {
let s = "aéconst"; // "é" is two bytes in UTF-8
let bytes = s.as_bytes();
for i in 0..bytes.len() {
let res = std::panic::catch_unwind(|| {
let _ = &s[i..];
});
println!("{i}: {}", if res.is_ok() { "ok" } else { "panic" });
}
}
RS
if command -v rustc >/dev/null 2>&1; then
rustc /tmp/utf8_slice_probe.rs -O -o /tmp/utf8_slice_probe
/tmp/utf8_slice_probe
else
echo "rustc unavailable"
fiRepository: ubugeeei-prod/vize
Length of output: 174
Avoid slicing source by byte index here contains_object_binding_declaration advances index one byte at a time, but declaration_keyword_at does source[index..]. Any multibyte UTF-8 character can put index on a non-char boundary and panic the linter/LSP; compare against source.as_bytes() instead.
🤖 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_patina/src/rules/script/no_deep_destructure_in_props.rs` around
lines 211 - 215, Avoid slicing source by byte index in declaration_keyword_at,
because contains_object_binding_declaration can pass a non-char-boundary index
and panic on UTF-8 input. Update declaration_keyword_at to work on
source.as_bytes() (or otherwise avoid source[index..]) while still checking the
same keyword matches and boundaries, and keep the logic aligned with
has_keyword_boundaries and the existing contains_object_binding_declaration
flow.
Source: Path instructions
Detailed Test ReportCommit: Area Summary
Test InventoryTotal tracked cases: 8620 across 1212 files.
Files
Comment truncated at 64000 characters. Open the workflow run for the full job log. |
Tool BenchmarkMeasured: 2026-07-08T17:48:02.663Z
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
Refs #2703
Validation
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by CodeRabbit
Performance Improvements
Bug Fixes