Your AI agent writes bad Vue/Svelte code. This catches it.
vue-doctor is an open-source CLI tool that scans Vue 3 and Svelte files for common AI-generated code smells, anti-patterns, and quality issues. Inspired by react-doctor (8.8K+ stars on GitHub), vue-doctor brings the same quality assurance to the Vue and Svelte ecosystems.
AI coding assistants (Claude, Copilot, Cursor, etc.) are great at generating code fast, but they often produce code that:
:key in v-for loops$:) in Svelteconsole.log statementsvue-doctor catches all of these ā and more ā with actionable fix hints.
# Clone the repo
git clone https://github.com/gardvori/vue-doctor.git
cd vue-doctor
# No dependencies! Uses only Python stdlib
# Requires Python 3.7+
# Optionally create a symlink for global use
chmod +x vuedoctor.py
ln -s "$(pwd)/vuedoctor.py" /usr/local/bin/vuedoctor
No pip install needed. Pure Python stdlib.
# Scan current directory
vuedoctor
# Scan specific directory
vuedoctor src/
# Only Vue files
vuedoctor src/ --vue-only
# Only Svelte files
vuedoctor src/ --svelte-only
# Strict mode (more rules including accessibility & magic numbers)
vuedoctor src/ --strict
# JSON output (for CI/CD integration)
vuedoctor src/ --json
# Disable colored output
vuedoctor src/ --no-color
𩺠vue-doctor ā AI Code Quality Report
Files scanned: 12 (Vue: 8, Svelte: 4)
Issues found: 4 (Errors: 2, Warnings: 1, Info: 1)
src/components/UserList.vue
ā [ERROR] Line 3: v-for without :key binding. This causes rendering bugs.
ā Fix: Add :key="item.id" or :key="index" to the v-for element
ā ļø [WARNING] Line 15: Options API detected: data() method. Vue 3 prefers Composition API.
ā Fix: Use reactive() or ref() instead
src/components/Counter.svelte
ā [ERROR] Line 8: {#each} block without key. Add (item) at the end for keyed each.
ā Fix: {#each items as item (item.id)}
ā¹ļø [INFO] Line 2: console.log() statement found. Remove before production.
ā Fix: Remove console statement or use a proper logger
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā 2 error(s) need immediate attention.
ā ļø 1 warning(s) should be reviewed.
ā¹ļø 1 info(s) for consideration.
| Rule | Severity | Description |
|---|---|---|
vue/no-script-setup |
ā ļø Warning | Vue 3 file should use <script setup> |
vue/no-options-api |
ā ļø Warning | Options API detected (data, methods, computed, watch, lifecycle hooks) |
vue/v-for-no-key |
ā Error | v-for without :key binding |
vue/no-prop-mutation |
ā Error | Direct prop mutation detected |
vue/missing-define-props |
ā Error | Props used without defineProps() declaration |
vue/no-prop-types |
ā ļø Warning | defineProps using array syntax without type validation |
vue/async-no-error-handling |
ā ļø Warning | await without try/catch |
vue/reactivity-loss |
ā ļø Warning | Destructuring reactive object may lose reactivity |
vue/deep-watcher |
ā¹ļø Info | Deep watcher (strict mode) |
| Rule | Severity | Description |
|---|---|---|
svelte/each-no-key |
ā Error | {#each} block without key |
svelte/missing-reactive |
ā ļø Warning | Derived state should use $: reactive declaration |
svelte/prop-no-type |
ā¹ļø Info | Prop exported without type annotation |
svelte/await-incomplete |
ā ļø Warning | {#await} missing {:then} or {:catch} |
svelte/store-no-unsubscribe |
ā ļø Warning | Store subscription without onDestroy cleanup |
svelte/missing-keyboard-event |
ā ļø Warning | Click handler on non-interactive element without keyboard support (strict mode) |
| Rule | Severity | Description |
|---|---|---|
common/console-log |
ā¹ļø Info | console.log/debug/warn/error statement |
common/empty-catch |
ā ļø Warning | Empty catch block silently swallows errors |
common/magic-number |
ā¹ļø Info | Magic number detected (strict mode) |
Use --json output to integrate with CI pipelines:
# .github/workflows/vuedoctor.yml
name: Vue Doctor
on: [pull_request]
jobs:
vue-doctor:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python vuedoctor.py src/ --json --strict > report.json
- run: |
ERRORS=$(python -c "import json; print(json.load(open('report.json'))['summary']['errors'])")
if [ "$ERRORS" -gt 0 ]; then
echo "Found $ERRORS errors!"
exit 1
fi
0 ā No errors found (warnings/info are non-blocking)1 ā One or more errors detected| Feature | react-doctor | vue-doctor |
|---|---|---|
| Vue support | ā | ā Vue 3 Composition API |
| Svelte support | ā | ā Svelte 4/5 |
| TypeScript support | Partial | ā Full type annotation checks |
| Strict mode | ā | ā More rules including a11y |
| Zero dependencies | ā | ā |
| JSON output | ā | ā CI/CD ready |
| Fix hints | Basic | ā Detailed per-rule hints |
Contributions welcome! Areas we'd love help with:
$state, $derived, $effect)--fix flag implementation).vuedoctorrc)MIT ā see LICENSE for details.