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:
$derived.by(), $effect(), and class boundaries to validate patterns within their actual scope — not across the whole fileget() calls from reactive context usage$t, $locale, $page) are excluded automatically// svelte5-ok to 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-rules
svelte5-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:
$derived.by() callback, $effect() body) using brace/paren depth tracking$state siblings? 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