doctor.config.ts
The full config schema, defineConfig helper, extends layering, presets, and per-rule overrides.
The doctor reads its config from the first file it finds, in this order:
- The path passed to
--config <path> doctor.config.tsin the project rootdoctor.config.mjsin the project rootdoctor.config.jsin the project rootdoctor.config.jsonin the project root- The
"doctor"key inpackage.json - Built-in defaults (the
recommendedpreset)
TypeScript is the recommended format. The doctor ships
defineConfig for autocompletion.
The defineConfig helper
import { defineConfig } from '@geoql/doctor-core';
export default defineConfig({
preset: 'recommended',
failOn: 'error',
rootDir: '.',
include: ['app/**', 'components/**', 'pages/**'],
exclude: ['node_modules', 'dist', '.doctor', '.nuxt', '.output'],
rules: {
'no-em-dash-in-str': 'off',
'watch-without-cleanup': 'error',
},
fixExcludes: ['app/content/**'],
extends: ['./doctor.base.ts'],
});
defineConfig is a type-only helper — it returns the config object
unchanged at runtime. Its job is to give you autocompletion and a
type error if you mistype a rule id.
Schema
The config object is typed as DoctorUserConfig. Every field is
optional; missing fields fall back to the built-in defaults.
interface DoctorUserConfig {
/** Project root (relative to the config file). Default: '.'. */
rootDir?: string;
/** Glob patterns to include. Default: ['app/**', 'components/**', 'pages/**', 'composables/**', 'layouts/**', 'middleware/**', 'plugins/**', 'server/**', 'utils/**']. */
include?: string[];
/** Glob patterns to exclude. Default: ['node_modules', 'dist', '.nuxt', '.output', '.doctor', 'coverage']. */
exclude?: string[];
/** Severity threshold for non-zero exit. 'error' | 'warn' | 'none'. Default: 'error'. */
failOn?: 'error' | 'warn' | 'none';
/** Score threshold (0–100). The audit exits non-zero if the score falls below. Default: 0. */
threshold?: number;
/** Base rule set. 'minimal' | 'recommended' | 'strict' | 'all'. Default: 'recommended'. */
preset?: 'minimal' | 'recommended' | 'strict' | 'all';
/** Per-rule severity overrides. Use 'off' to disable. */
rules?: Record<string, 'error' | 'warn' | 'info' | 'off'>;
/** Other config files to layer on top of this one. */
extends?: string[];
/** Globs to never auto-fix, even when --fix is set. */
fixExcludes?: string[];
}
Presets
Presets are the base layer of the rule set. They enable or disable rules by severity.
| preset | what it includes |
|---|---|
minimal | error findings only — warn and info rules are off |
recommended | error + warn findings (the default) |
strict | error + warn + info at their registered severities |
all | alias of strict, reserved for future expansion |
Use minimal for a fast first pass on a legacy codebase, then
graduate to recommended once the error findings are triaged.
The doctor ships with recommended as the default so the first run
on a clean project produces a 0 errors, 0 warns, N info report. If
you want stricter CI from day one, set preset: 'strict' in your
config.
Per-rule overrides
The rules field is merged on top of the preset. The value can be
error, warn, info, or off. The off switch is intentional —
it's the only way to silence a rule project-wide that you don't
want flagged:
export default defineConfig({
rules: {
'no-em-dash-in-str': 'off',
'no-destructure-props-without-toRefs': 'warn',
},
});
To silence a rule for a single line, use an inline disable — see Quickstart.
extends
extends layers multiple config files. Later entries win.
export default defineConfig({
extends: [
'./doctor.base.ts', // team-wide baseline
'./doctor.local.ts', // your local overrides
],
});
The merge order is:
- The preset's base rule set
- The config file's
rules(withextendsapplied in order) - CLI
--ruleoverrides
A field that appears in two layers is overwritten by the later
layer. Arrays (include, exclude, fixExcludes) are concatenated.
fixExcludes
When --fix is set, the doctor will not modify files matching any
glob in fixExcludes. The default is [] (everything is fixable
unless excluded).
export default defineConfig({
fixExcludes: [
'app/content/**', // generated content
'**/*.generated.ts', // codegen output
],
});
JSON / package.json form
If you'd rather not have a .ts file, the doctor accepts JSON:
{
"preset": "recommended",
"rules": {
"no-em-dash-in-str": "off"
}
}
Or inline in package.json:
{
"doctor": {
"preset": "recommended",
"rules": {
"no-em-dash-in-str": "off"
}
}
}
The TypeScript form is still preferred — the type-checker catches
typos in rule ids, and defineConfig gives you autocompletion.
Where to put it
doctor.config.ts lives at the project root, next to package.json.
In a monorepo, you can put one in each package and let each audit
target its own scope. The doctor walks up from the current
directory until it finds a config, just like ESLint.