## Summary
Two small compiler optimizations that reduce redundant work:
- **Cache `element_interactivity` per element in a11y checks**:
`check_element` was calling `element_interactivity()` up to 10 times per
element (via `is_interactive_element`, `is_non_interactive_element`,
`is_static_element` wrappers), each time re-iterating schema arrays. Now
computed once after building the attribute map and reused. The
now-unused wrapper functions are removed.
- **Split source lines once in `state.set_source`**: Every compiler
warning called `get_code_frame` which split the entire source string
with `source.split('\n')`. Now the split happens once in `set_source()`
and is exported as `state.source_lines`, naturally cleared by `reset()`.
## Benchmark
Synthetic component (80 state vars, 30 each blocks, ~1300 lines):
```
Min Best3 Median
Before 66.55ms 67.03ms 73.44ms
After 61.14ms 61.90ms 70.63ms
Improvement 8.1% 7.7% 3.8%
```
Realistic component (~80 lines, ~25 elements, few warnings): **~1-4%**
improvement. The a11y cache scales with element count, the source.split
saving scales with warning count.
## Test plan
- [x] All 326 validator tests pass (includes all a11y tests)
- [x] All 5671 runtime tests pass
- [x] 145 compiler-error tests pass
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>