ESLint Config

ESLint Config

Opinionated ESLint flat config for PleaseAI projects — built on @antfu/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

Installation

bun add -D @pleaseai/eslint-config eslint
Prefer not to set this up by hand? Run 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:

eslint.config.ts
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:

eslint.config.ts
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:

eslint.config.ts
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:

eslint.config.ts
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.

Plugin prefixes are renamed for ergonomics — use ts/*, style/*, test/*, import/*, etc. See the full mapping in Advanced Usage.

NPM Scripts

Add the lint commands to your package.json:

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:

OptionValueNote
stylistic.indent2Two-space indent
stylistic.quotessingleSingle quotes
stylistic.semifalseNo trailing semicolons
typescripttrueEnabled out of the box
gitignoretrueIgnores anything in .gitignore
lessOpinionatedtrueDisables antfu/if-newline and antfu/curly, enables curly: ['error', 'all']
antfu/top-level-functionRe-enabledPrefer function declarations at top level
test/prefer-lowercase-titleDisabledTest 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:

eslint.config.ts
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  formatters: {
    css: true,
    html: true,
    markdown: 'prettier',
  },
})
bun add -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:

eslint.config.ts
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  typescript: {
    tsconfigPath: 'tsconfig.json',
  },
})

Read more in Advanced Usage → Type Aware Rules.

Next Steps

Framework Integrations

React, Next.js, Vue, Svelte, Astro, Solid, UnoCSS, and Angular — with peer deps.

Advanced Usage

Config Composer, command codemods, plugin renaming, versioning policy.

Editor & CI

VS Code, Neovim, editor-specific disables, and lint-staged.

Nuxt Integration

Compose with @nuxt/eslint for auto-import-aware linting.

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:

eslint.config.ts
import pleaseai from '@pleaseai/eslint-config'

export default pleaseai({
  rules: {
    'antfu/top-level-function': 'off',
  },
})
Copyright © 2026