ESLint Config

Advanced Usage

Config Composer, type-aware rules, command codemods, plugin renaming, and versioning policy.

Advanced Usage

Type Aware Rules

Some of the strongest TypeScript lint rules require type information — they need to resolve what a value actually is at runtime, not just what its local syntax looks like. Opt into type-aware linting by pointing at your tsconfig.json:

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

export default pleaseai({
  typescript: {
    tsconfigPath: 'tsconfig.json',
  },
})
Type-aware linting is slower than syntax-only linting because ESLint has to build a TypeScript program for every run. Start with it on small/medium projects; for very large monorepos consider scoping it to a subset of files.

Config Composer

pleaseai() returns a FlatConfigComposer, so you can fluently override, prepend, remove, or rename named config blocks when the plain options object isn't granular enough:

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

export default pleaseai()
  .prepend(
    // flat configs before the main PleaseAI config
  )
  .override('antfu/stylistic/rules', {
    rules: {
      'style/generator-star-spacing': ['error', { after: true, before: false }],
    },
  })
  .renamePlugins({
    'old-prefix': 'new-prefix',
  })
  .remove('antfu/stylistic')

Reach for this API when:

  • You want to remove a named config block entirely
  • You need to rename a plugin prefix without writing a custom config
  • You want to override rules inside a specific named block (more surgical than the top-level overrides)

command Codemods

@pleaseai/eslint-config ships eslint-plugin-command — an on-demand micro-codemod system triggered by triple-slash comments. It's not a typical lint rule; you explicitly opt in per-site.

Built-in triggers include:

  • /// to-function — arrow function → function declaration
  • /// to-arrowfunction declaration → arrow function
  • /// to-for-eachfor loop → .forEach()
  • /// to-for-of.forEach()for-of
  • /// keep-sorted — sort the next object/array/interface

See the plugin docs for the full catalogue.

Usage — place the trigger one line above the code:

before.ts
/// to-function
const greet = async (name: string): Promise<void> => {
  console.log(`Hello, ${name}`)
}

After eslint --fix:

after.ts
async function greet(name: string): Promise<void> {
  console.log(`Hello, ${name}`)
}

The trigger comment is one-off — it's removed along with the transformation.

Plugins Renaming

@pleaseai/eslint-config inherits @antfu/eslint-config's plugin renaming for a shorter, consistent DX:

New prefixOriginal prefixSource plugin
import/*import-lite/*eslint-plugin-import-lite
node/*n/*eslint-plugin-n
yaml/*yml/*eslint-plugin-yml
ts/*@typescript-eslint/*@typescript-eslint/eslint-plugin
style/*@stylistic/*@stylistic/eslint-plugin
test/*vitest/*@vitest/eslint-plugin

So when you override a rule, use the new prefix:

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

export default pleaseai({
  rules: {
    'ts/consistent-type-definitions': ['error', 'interface'],
    'style/max-statements-per-line': ['error', { max: 2 }],
  },
})

View Enabled Rules

Use @eslint/config-inspector to visualise the fully-resolved config in a browser — every enabled rule, every plugin, every file glob:

Terminal
npx @eslint/config-inspector

It opens a local server showing the flat config graph. Indispensable when you're debugging "why is this rule firing" or "which preset added this".

Re-exports

Every export from @antfu/eslint-config is re-exported, so you can import fine-grained configs directly when you want to compose them by hand instead of using the pleaseai() factory:

eslint.config.ts
import { combine, javascript, typescript, vue } from '@pleaseai/eslint-config'

export default combine(
  javascript(),
  typescript(),
  vue(),
)

Versioning Policy

@pleaseai/eslint-config follows Semantic Versioning, but because it's an opinionated style preset with many moving parts, rule changes are not treated as breaking changes.

Breaking (major bump)

  • Node.js version requirement changes
  • Large refactors that may break downstream configs
  • Major plugin upgrades that may break existing rules
  • Changes that likely affect most codebases

Non-breaking (minor/patch)

  • Enabling or disabling individual rules (even if stricter)
  • Changing rule options
  • Dependency version bumps

If a rule tightening breaks your build, pin to the previous minor version and open an issue so we can discuss the trade-off.

Copyright © 2026