Overview

How the vinicuncaESLint factory combines its options, your own flat configs and the composer API into one ESLint config.

The factory

Everything starts from the vinicuncaESLint factory, a named export of the package:

function vinicuncaESLint(
  options?: OptionsConfig & Omit<TypedFlatConfigItem, 'files' | 'ignores'>,
  ...userConfigs: Array<Awaitable<
    TypedFlatConfigItem | Array<TypedFlatConfigItem> | FlatConfigComposer | Array<Linter.Config>
  >>
): FlatConfigComposer<TypedFlatConfigItem, ConfigNames>;
  • The first argument holds global options that turn integrations on or off and tune them.
  • Every following argument is a regular ESLint flat config (or an array, a promise, or another composer) appended after the generated configs.
  • The return value is a FlatConfigComposer. ESLint accepts it directly as the default export, and you can chain methods on it to edit the generated configs.
eslint.config.js
import { vinicuncaESLint } from '@vinicunca/eslint-config';

export default vinicuncaESLint(
  // 1. Options
  {
    type: 'lib',
    typescript: {
      tsconfigPath: 'tsconfig.json',
    },
  },

  // 2. Extra flat configs, applied in order
  {
    files: ['**/*.ts'],
    rules: {
      'ts/no-explicit-any': 'error',
    },
  },
  {
    rules: {
      'no-console': 'off',
    },
  },
)
  // 3. Composer methods
  .override('vinicunca/stylistic/rules', {
    rules: {
      'style/max-statements-per-line': 'off',
    },
  });

Options

Each integration is controlled by an option with the same name. Most accept true/false, or an object to configure it:

eslint.config.js
import { vinicuncaESLint } from '@vinicunca/eslint-config';

export default vinicuncaESLint({
  // Turn an integration off
  yaml: false,

  // Turn one on with defaults
  react: true,

  // Configure it with an object (also turns it on)
  vue: {
    a11y: true,
    overrides: {
      'vue/no-v-html': 'error',
    },
  },
});

Most integrations accept an overrides object. Its rules are merged into that integration's config, so they apply to the same files (for example, vue.overrides only applies to .vue files). See Rules & renaming for all the ways to change rules.

The first argument is meant for global options, so it has two special cases:

  • ignores extends the global ignore list instead of acting like a flat config ignores. Pass an array to add globs, or a function to edit the defaults.
  • files is not allowed. The factory throws an error if you pass it; put file-scoped rules in a later argument instead.

The first argument also accepts these flat config properties: name, languageOptions, linterOptions, processor, plugins, rules and settings. They are collected into one extra config item placed after the generated configs and before your extra configs.

eslint.config.js
import { vinicuncaESLint } from '@vinicunca/eslint-config';

export default vinicuncaESLint({
  vue: true,
  rules: {
    'no-console': 'off',
  },
});

The options reference lists every option with its type and default.

Generated configs

The factory builds a list of named config items. Each name starts with vinicunca/, which is what you pass to composer methods such as .override(). With the defaults, the order is:

  1. vinicunca/gitignore, vinicunca/ignores
  2. vinicunca/javascript/*, vinicunca/eslint-comments/rules, vinicunca/command/rules
  3. vinicunca/perfectionist/rules, vinicunca/node/rules, vinicunca/jsdoc/*, vinicunca/imports/rules, vinicunca/e18e/rules, vinicunca/unicorn/*, vinicunca/jsx/setup
  4. vinicunca/typescript/*, then vinicunca/antislop/* (on by default)
  5. vinicunca/stylistic/rules, vinicunca/regexp/rules, vinicunca/test/*
  6. Framework configs: vinicunca/vue/*, vinicunca/react/*, vinicunca/nextjs/*, vinicunca/solid/*, vinicunca/svelte/*, vinicunca/unocss, vinicunca/astro/*
  7. vinicunca/jsonc/*, vinicunca/sort/package-json, vinicunca/sort/tsconfig, vinicunca/pnpm/*, vinicunca/yaml/*, vinicunca/toml/*, vinicunca/markdown/*
  8. vinicunca/formatter/* when formatters are enabled
  9. vinicunca/disables/*: relaxed rules for scripts/, cli/, bin/, *.d.ts, *.js/*.cjs and *.config.* files

Your extra configs come after all of these, so they win when they set the same rule. Use the config inspector to see the exact list for your project.

Composer API

vinicuncaESLint() returns a FlatConfigComposer from eslint-flat-config-utils. Its methods are chainable and are resolved when ESLint loads the config:

  • .append(...configs) / .prepend(...configs): add configs at the end or the start.
  • .insertBefore(name, ...configs) / .insertAfter(name, ...configs): add configs next to a named config.
  • .override(name, config): merge into a named config, or pass a function that receives and returns it. .overrides({ [name]: config }) does several at once.
  • .overrideRules(rules): change rule entries everywhere they are configured.
  • .remove(name) / .replace(name, ...configs): drop or swap a named config.
  • .removeRules(...ruleIds) / .removePlugins(...names): strip rules or plugins from every config.
  • .renamePlugins(map): rename plugin prefixes in every config.
  • .disableRulesFix(ruleIds, options): keep rules reporting but make them non-fixable.
  • .onResolved(callback): inspect or edit the final array.
  • .toConfigs(): resolve to a plain Linter.Config[].
eslint.config.js
import { vinicuncaESLint } from '@vinicunca/eslint-config';

export default vinicuncaESLint()
  .insertAfter('vinicunca/javascript/rules', {
    name: 'my-project/legacy',
    files: ['legacy/**/*.js'],
    rules: {
      'no-var': 'off',
    },
  })
  .overrideRules({
    'no-console': ['error', { allow: ['info', 'warn', 'error'] }],
  })
  .remove('vinicunca/sort/tsconfig');

Typed configs

The package exports its types, so you get autocompletion for options and rule names in eslint.config.ts or with JSDoc:

eslint.config.ts
import type { TypedFlatConfigItem } from '@vinicunca/eslint-config';
import { vinicuncaESLint } from '@vinicunca/eslint-config';

const legacy: TypedFlatConfigItem = {
  files: ['legacy/**/*.js'],
  rules: {
    'no-var': 'off',
  },
};

export default vinicuncaESLint({ type: 'app' }, legacy);

Useful exports include OptionsConfig (the options type), TypedFlatConfigItem, ConfigNames (every generated config name) and Rules.

Building your own composition

Each integration is also exported as a function (javascript, typescript, stylistic, vue, jsonc, markdown and so on), together with helpers such as combine, renameRules, renamePluginInConfigs and the GLOB_* constants. You can compose them by hand when you need full control:

eslint.config.js
import {
  combine,
  comments,
  ignores,
  imports,
  javascript,
  jsdoc,
  jsonc,
  markdown,
  node,
  sortPackageJson,
  sortTsconfig,
  stylistic,
  toml,
  typescript,
  unicorn,
  vue,
  yaml,
} from '@vinicunca/eslint-config';

export default combine(
  ignores(),
  javascript(),
  comments(),
  node(),
  jsdoc(),
  imports(),
  unicorn(),
  typescript(),
  stylistic(),
  vue({ typescript: true }),
  jsonc(),
  sortPackageJson(),
  sortTsconfig(),
  yaml(),
  toml(),
  markdown(),
);
Hand-composed configs skip what the factory does for you: auto-detection, sharing stylistic options between integrations, editor detection, plugin renaming of your own configs and the composer API. Prefer the factory unless you have a specific reason not to.

In this section

Options

Every option with its type and default.

Frameworks

Vue, React, Next.js, Svelte, Solid, Astro and UnoCSS.

Formatters

Format CSS, HTML, XML, SVG, Markdown, GraphQL and Astro files.

TypeScript

TypeScript support, type-aware rules and erasable-syntax-only mode.

Rules & renaming

Override rules and understand the renamed plugin prefixes.

Optional configs

Anti-slop, pnpm workspace, e18e, regexp and command rules.