ESLint Config
ESLint Config
@pleaseai/eslint-config is an opinionated ESLint flat config built on top of @antfu/eslint-config. It gives you a single pleaseai() function that wires up linting and formatting for JS/TS/JSX/Vue/JSON/YAML/Markdown out of the box — no Prettier required.
Features
- ESLint flat config format, composable and future-proof
- Auto-fix for formatting — use standalone without Prettier
- TypeScript, JSX, Vue, JSON, YAML, Markdown, TOML, XML, GraphQL, Svelte, Astro, CSS support
- Optional React, Next.js, Svelte, UnoCSS, Astro, Solid, Angular integrations
- Optional formatters for CSS / HTML / Markdown via
eslint-plugin-format - Includes
eslint-plugin-package-jsonconfigs - Auto-detects
.gitignorepatterns - Requires ESLint v9.10.0+
Installation
bun add -D @pleaseai/eslint-config eslint
pnpm add -D @pleaseai/eslint-config eslint
npm install -D @pleaseai/eslint-config eslint
bunx @pleaseai/code-style — the CLI installs the packages, writes eslint.config.mjs, and can also manage a rules block in AGENTS.md for AI coding assistants.Usage
Create eslint.config.ts (or eslint.config.mjs) in your project root:
import pleaseai from '@pleaseai/eslint-config'
export default pleaseai()
That's it. ESLint will pick it up automatically on the next run.
With Options
pleaseai() accepts the same options as @antfu/eslint-config:
import pleaseai from '@pleaseai/eslint-config'
export default pleaseai({
// Override PleaseAI defaults
stylistic: {
indent: 4,
},
// Enable framework support
vue: true,
react: true,
// Add ignores
ignores: [
'**/fixtures',
],
})
See Framework Integrations for the full list of framework flags and their peer dependencies.
With Additional Configs
Pass additional flat config items as rest arguments — they're merged after the PleaseAI preset:
import pleaseai from '@pleaseai/eslint-config'
export default pleaseai(
{
typescript: true,
},
{
files: ['**/*.ts'],
rules: {
'no-console': 'warn',
},
},
)
Rules Overrides
Every framework integration accepts an overrides object so you can tune rules without replacing the whole preset:
import pleaseai from '@pleaseai/eslint-config'
export default pleaseai({
vue: {
overrides: {
'vue/operator-linebreak': ['error', 'before'],
},
},
typescript: {
overrides: {
'ts/consistent-type-definitions': ['error', 'interface'],
},
},
})
For overrides that don't fit a specific integration, pass a second argument with a rules object as shown in With Additional Configs.
ts/*, style/*, test/*, import/*, etc. See the full mapping in Advanced Usage.NPM Scripts
Add the lint commands to your package.json:
{
"scripts": {
"lint": "eslint .",
"lint:fix": "eslint . --fix"
}
}
Run npm run lint to check, or npm run lint:fix to auto-fix.
PleaseAI Defaults
This config wraps @antfu/eslint-config with these PleaseAI-specific defaults:
| Option | Value | Note |
|---|---|---|
stylistic.indent | 2 | Two-space indent |
stylistic.quotes | single | Single quotes |
stylistic.semi | false | No trailing semicolons |
typescript | true | Enabled out of the box |
gitignore | true | Ignores anything in .gitignore |
lessOpinionated | true | Disables antfu/if-newline and antfu/curly, enables curly: ['error', 'all'] |
antfu/top-level-function | Re-enabled | Prefer function declarations at top level |
test/prefer-lowercase-title | Disabled | Test titles can start with any case |
The lessOpinionated: true + curly: ['error', 'all'] combination is the key PleaseAI divergence from antfu's defaults: control-flow statements must always use braces, but antfu's top-level-function preference is still honoured.
Formatters
ESLint can't natively format .css, .html, .xml, or Markdown frontmatter. Opt in to the formatters feature to delegate those files to eslint-plugin-format (which wraps Prettier / dprint) while keeping everything else on pure ESLint:
import pleaseai from '@pleaseai/eslint-config'
export default pleaseai({
formatters: {
css: true,
html: true,
markdown: 'prettier',
},
})
bun add -D eslint-plugin-format
pnpm add -D eslint-plugin-format
npm install -D eslint-plugin-format
formatters only handles formatting, not linting. For proper CSS linting use Stylelint alongside it.Type Aware Rules
The strongest TypeScript rules require type information. Opt in by pointing at your tsconfig.json:
import pleaseai from '@pleaseai/eslint-config'
export default pleaseai({
typescript: {
tsconfigPath: 'tsconfig.json',
},
})
Read more in Advanced Usage → Type Aware Rules.
Next Steps
FAQ
Prettier?
This config uses ESLint for both linting and formatting, so Prettier isn't needed. See Why I don't use Prettier by Anthony Fu for the reasoning.
If you need to format files ESLint can't handle yet (.css, .html, etc.), use the formatters option — it wraps Prettier/dprint under the hood without adding a separate tool to your workflow.
How do I format CSS?
Opt in to the formatters feature. It formats but does not lint — for proper CSS linting pair it with Stylelint.
Curly braces style?
PleaseAI enforces curly: ['error', 'all'] — always wrap control-flow bodies in braces:
// ✓ required
function example() {
if (foo) {
return true
}
}
// ✗ rejected
function example() {
if (foo) return true
}
This diverges from antfu's default (which allows brace-less single-line if). We made this choice because brace-less bodies interact badly with our other rules like style/max-statements-per-line — mixing them produces hard-to-read one-liners.
Top-level function style?
PleaseAI re-enables antfu/top-level-function, so top-level functions should use a function declaration rather than an arrow assigned to a const:
// ✓ preferred
export function greet(name: string) {
return `Hello, ${name}`
}
// ✗ flagged
export const greet = (name: string) => `Hello, ${name}`
Arrow functions are still fine inside function bodies, as callbacks, or for inline JSX handlers — the rule only targets top-level declarations. If you disagree, override it:
import pleaseai from '@pleaseai/eslint-config'
export default pleaseai({
rules: {
'antfu/top-level-function': 'off',
},
})