Catch Svelte 5 migration time bombs that npm run check misses.
npx svelte5-shield src/svelte5-shield detects patterns that are syntactically valid but semantically broken in Svelte 5's runes system. These are the bugs that pass type checking, pass linting, but silently break reactivity at runtime.
| Rule | What | Severity |
|---|---|---|
| S018 | Side effects inside $derived (fetch, await, .set()) |
Bug |
| S019 | Destructuring $state() loses reactivity tracking |
Bug |
| S021 | get() from svelte/store in runes-mode .svelte.ts files |
Migration |
| S026 | Plain field in class with $state siblings — invisible to $effect |
Bug |
| S028 | Store writes ($store = val) in runes components |
Migration |
| S029 | $effect with listeners/timers but no cleanup return |
Bug |
Unlike naive regex linters, svelte5-shield uses structural block analysis to minimize false positives:
- Block extraction: Parses
$derived.by(),$effect(), and class boundaries to validate patterns within their actual scope — not across the whole file - Confidence scoring: Every hit is rated HIGH, MEDIUM, or LOW. Default output shows MEDIUM+ only
- Contextual guards: S026 checks if a plain field is actually mutated and read reactively. S021 distinguishes imperative
get()calls from reactive context usage - Known-safe exclusions: Common library patterns (
$t,$locale,$page) are excluded automatically - Inline suppression: Add
// svelte5-okto any line to silence its warning
# Scan a directory (default: MEDIUM+ confidence)
npx svelte5-shield src/
# Show code context and fix suggestions
npx svelte5-shield src/ --verbose
# Include LOW confidence (informational) hits
npx svelte5-shield src/ --min-confidence LOW
# JSON output (for CI integration)
npx svelte5-shield src/ --json
# Disable specific rules
npx svelte5-shield src/ --disable S028,S029
# List all rules
npx svelte5-shield --list-rulessvelte5-shield exits with code 1 if any HIGH confidence issues are found:
# GitHub Actions
- name: Svelte 5 safety check
run: npx svelte5-shield src/// package.json
{
"scripts": {
"check:svelte5": "svelte5-shield src/"
}
}Create .svelte5rc.json in your project root:
{
"minConfidence": "MEDIUM",
"disableRules": ["S028"],
"exclude": ["**/legacy/**"],
"suppressionComment": "svelte5-ok"
}import { scan, formatText, formatJson } from 'svelte5-shield';
const result = scan('./src', {
minConfidence: 'MEDIUM',
disableRules: ['S028'],
});
console.log(formatText(result, './src'));
// or
console.log(formatJson(result));svelte5-shield uses a three-layer analysis pipeline:
- Regex match: Fast pattern matching to find candidate lines
- Block extraction: Lightning-style structural analysis extracts the containing block (class body,
$derived.by()callback,$effect()body) using brace/paren depth tracking - Contextual validation: Checks structural properties within the block — does the class have
$statesiblings? Is the field mutated? Is the store reference actually inside the reactive block?
This approach achieves 98% false positive reduction compared to naive regex scanning, while running in under 100ms for a 500-file codebase.
MIT