Vue rules

The full @geoql/oxlint-plugin-vue-doctor rule catalogue. ai-slop, composition, performance, reactivity.

The Vue plugin ships 12 rules across four categories. All rules are auto-loaded by @geoql/vue-doctor and @geoql/nuxt-doctor — no plugin registration needed.

ai-slop

Patterns that AI agents emit reflexively. None of these are bugs, but all of them are tells — the model is optimizing for looking right instead of being right.

rule idseveritywhat it catches
no-destructure-props-without-toRefswarndestructuring defineProps() without toRefs
no-destructure-reactive-without-toRefswarndestructuring reactive() without toRefs
no-em-dash-in-strinfo in string literals
no-imports-from-vue-when-auto-importedwarnexplicit import { ref } from 'vue' in Nuxt
no-non-null-assertion-on-ref-valueerrorref.value! — drops reactivity guarantees

composition

Vue 3 idioms for <script setup> and the Composition API.

rule idseveritywhat it catches
defineProps-typedwarndefineProps() without a type or runtime schema
prefer-script-setup-for-new-filesinfonew .vue files using Options API

defineProps-typed is the highest-signal rule in this set. A defineProps() call without a type is a regression — the macro was specifically designed to carry TypeScript types, and skipping the type means every consumer has to fall back to inference.

performance

Runtime and build-time perf landmines. Smaller set, but each rule catches something that's hard to spot in code review.

rule idseveritywhat it catches
prefer-defineAsyncComponent-on-routewarneager-importing a route component (kills code-splitting)

reactivity

The rules in this set all guard against the silent failure modes of Vue's reactivity system. The model "works" but the template never re-renders, or it re-renders in a way that breaks memoization.

rule idseveritywhat it catches
prefer-readonly-for-injectedwarnmutable inject() — the parent may not react
prefer-shallowRef-for-large-datainforef(hugeArray) for read-only data
watch-without-cleanuperrorwatch() with a side-effect that needs teardown

watch-without-cleanup is the only error in the Vue set. Uncleaned watchers leak — the previous callback keeps running after the component unmounts, and you'll see it as a 100% CPU tail in production.

What's not here

A few things we deliberately don't ship in the Vue plugin:

  • General ESLint-style correctness — that's what oxlint is for. The doctor does not duplicate vue/no-mutating-props or vue/no-unused-components. Run oxlint alongside.
  • Type-correctness for <template> — the <template> AST is lossy on purpose; inferring ref types from <MyComp :foo="x" /> is not a doctor job.
  • A11y checkseslint-plugin-vue-a11y exists, and the doctor will not reimplement it.

If you find a rule that should be in the doctor but isn't, open an issue. We add rules when there's a documented AI-agent pattern behind them.