How does eslint-config-prettier works ?

Mohamed Lamine Allal
8 min readNov 27, 2023

--

This article details how eslint-config-prettier works. Which is also used in eslint-plugin-prettier. That also helps understand better the difference between the two.

What does the package do ?

▪️ provide rules that

  • disable conflicting rules of eslint with prettier
    intended so that you use prettier separately from eslint
    ◌ And not have eslint screw prettier formating and conflicting

▪️ Does also provide a CLI to check if there are any conflicts between

  • prettier config
  • and actual eslint config

String resolution

extends: ['prettier']

Whatever is typed in extends

=> That would be prefixed with eslint-config-
prettier = giving => eslint-config-prettier

Which is this package

"prettier/prettier" = give => "eslint-config-prettier/prettier"

  • which would be resolved to node_modules/eslint-config-prettier/prettier.js

▪️ That’s why eslint-config-* repos if they want to provide extra configs

  • They generate files with names
  • And they would be accessible
  • or they would use npm files resolution

▪️ at the end, the resolution algorithm

  • after adding "eslint-config-"
    ◌ gonna be nodejs module resolution algorithm
    - commonjs
    - or esm
    - path.resolve() does use it

Flat config and old config

  • The package supports both

✨ Old config

  • all keep running the same and the resolution is used
{
"extends": [
"some-other-config-you-use",
"prettier"
]
}

✨ Flat config (new)

  • Works simply, because this package provides rules only
  • rules are easy to integrate with flat config object
  • So no validation issue
  • and it would work well simply
import someConfig from "some-other-config-you-use";
import eslintConfigPrettier from "eslint-config-prettier";

export default [
someConfig,
eslintConfigPrettier,
];

◌ Here we used the cascading merging nature of Flat config.
◌ It goes second after our main config, because it’s a disabling set of rules => We need to override so that we disable 🔥
◌ If not familiar with Flat config . Check the Eslint flat config and new system an ultimate deep dive 2023 article 🔥

you can do as well

import someConfig from "some-other-config-you-use";
import eslintConfigPrettier from "eslint-config-prettier";

export default [
{
files: '**/*.{js,mjs,cjs}',
rules: {
...someCustomRules,
...eslintConfigPrettier.rules
}
];
  • it comes after because it does disable the conflicting rules (disable❗)
    ◌ and it’s the whole point
    ◌ The rules are flat ( no nested structure ). So the merging with the spread operator above works effectively.

Relation with eslint-plugin-prettier

  • Two separate packages. By different entities
  • eslint-plugin-prettier does use eslint-config-prettier
  • eslint-plugin-prettier provide plugin:prettier/recommended config for extends

which is

{
"extends": ["prettier"],
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error",
"arrow-body-style": "off",
"prefer-arrow-callback": "off"
}
}
"extends": ["prettier"],

=> eslint-config-prettier

"plugins": ["prettier"],

=> eslint-plugin-prettier

This is the eslint string resolution algorithms

Package and deprecated configs

  • prettier
  • prettier/prettier
    very short rules prettier
  • prettier/flowtype
    error moved to prettier
  • prettier/babel
    error moved to prettier
  • prettier/react
    error moved to prettier
  • prettier/vue
    error moved to prettier
  • prettier/unicorn
    error moved to prettier
  • prettier/standard
    error moved to prettier
  • files are left for the sake of showing the helpful message 🔥

prettier rules

  • node_modules/eslint-config-prettier/index.js (at the time of writing) [2023-09-04]
"use strict";

const includeDeprecated = !process.env.ESLINT_CONFIG_PRETTIER_NO_DEPRECATED;
module.exports = {
rules: {
// The following rules can be used in some cases. See the README for more
// information. (These are marked with `0` instead of `"off"` so that a
// script can distinguish them.)
"curly": 0,
"lines-around-comment": 0,
"max-len": 0,
"no-confusing-arrow": 0,
"no-mixed-operators": 0,
"no-tabs": 0,
"no-unexpected-multiline": 0,
"quotes": 0,
"@typescript-eslint/lines-around-comment": 0,
"@typescript-eslint/quotes": 0,
"babel/quotes": 0,
"vue/html-self-closing": 0,
"vue/max-len": 0,
// The rest are rules that you never need to enable when using Prettier.
"array-bracket-newline": "off",
"array-bracket-spacing": "off",
"array-element-newline": "off",
"arrow-parens": "off",
"arrow-spacing": "off",
"block-spacing": "off",
"brace-style": "off",
"comma-dangle": "off",
"comma-spacing": "off",
"comma-style": "off",
"computed-property-spacing": "off",
"dot-location": "off",
"eol-last": "off",
"func-call-spacing": "off",
"function-call-argument-newline": "off",
"function-paren-newline": "off",
"generator-star-spacing": "off",
"implicit-arrow-linebreak": "off",
"indent": "off",
"jsx-quotes": "off",
"key-spacing": "off",
"keyword-spacing": "off",
"linebreak-style": "off",
"max-statements-per-line": "off",
"multiline-ternary": "off",
"newline-per-chained-call": "off",
"new-parens": "off",
"no-extra-parens": "off",
"no-extra-semi": "off",
"no-floating-decimal": "off",
"no-mixed-spaces-and-tabs": "off",
"no-multi-spaces": "off",
"no-multiple-empty-lines": "off",
"no-trailing-spaces": "off",
"no-whitespace-before-property": "off",
"nonblock-statement-body-position": "off",
"object-curly-newline": "off",
"object-curly-spacing": "off",
"object-property-newline": "off",
"one-var-declaration-per-line": "off",
"operator-linebreak": "off",
"padded-blocks": "off",
"quote-props": "off",
"rest-spread-spacing": "off",
"semi": "off",
"semi-spacing": "off",
"semi-style": "off",
"space-before-blocks": "off",
"space-before-function-paren": "off",
"space-in-parens": "off",
"space-infix-ops": "off",
"space-unary-ops": "off",
"switch-colon-spacing": "off",
"template-curly-spacing": "off",
"template-tag-spacing": "off",
"wrap-iife": "off",
"wrap-regex": "off",
"yield-star-spacing": "off",
"@babel/object-curly-spacing": "off",
"@babel/semi": "off",
"@typescript-eslint/block-spacing": "off",
"@typescript-eslint/brace-style": "off",
"@typescript-eslint/comma-dangle": "off",
"@typescript-eslint/comma-spacing": "off",
"@typescript-eslint/func-call-spacing": "off",
"@typescript-eslint/indent": "off",
"@typescript-eslint/key-spacing": "off",
"@typescript-eslint/keyword-spacing": "off",
"@typescript-eslint/member-delimiter-style": "off",
"@typescript-eslint/no-extra-parens": "off",
"@typescript-eslint/no-extra-semi": "off",
"@typescript-eslint/object-curly-spacing": "off",
"@typescript-eslint/semi": "off",
"@typescript-eslint/space-before-blocks": "off",
"@typescript-eslint/space-before-function-paren": "off",
"@typescript-eslint/space-infix-ops": "off",
"@typescript-eslint/type-annotation-spacing": "off",
"babel/object-curly-spacing": "off",
"babel/semi": "off",
"flowtype/boolean-style": "off",
"flowtype/delimiter-dangle": "off",
"flowtype/generic-spacing": "off",
"flowtype/object-type-curly-spacing": "off",
"flowtype/object-type-delimiter": "off",
"flowtype/quotes": "off",
"flowtype/semi": "off",
"flowtype/space-after-type-colon": "off",
"flowtype/space-before-generic-bracket": "off",
"flowtype/space-before-type-colon": "off",
"flowtype/union-intersection-spacing": "off",
"react/jsx-child-element-spacing": "off",
"react/jsx-closing-bracket-location": "off",
"react/jsx-closing-tag-location": "off",
"react/jsx-curly-newline": "off",
"react/jsx-curly-spacing": "off",
"react/jsx-equals-spacing": "off",
"react/jsx-first-prop-new-line": "off",
"react/jsx-indent": "off",
"react/jsx-indent-props": "off",
"react/jsx-max-props-per-line": "off",
"react/jsx-newline": "off",
"react/jsx-one-expression-per-line": "off",
"react/jsx-props-no-multi-spaces": "off",
"react/jsx-tag-spacing": "off",
"react/jsx-wrap-multilines": "off",
"standard/array-bracket-even-spacing": "off",
"standard/computed-property-even-spacing": "off",
"standard/object-curly-even-spacing": "off",
"unicorn/empty-brace-spaces": "off",
"unicorn/no-nested-ternary": "off",
"unicorn/number-literal-case": "off",
"vue/array-bracket-newline": "off",
"vue/array-bracket-spacing": "off",
"vue/array-element-newline": "off",
"vue/arrow-spacing": "off",
"vue/block-spacing": "off",
"vue/block-tag-newline": "off",
"vue/brace-style": "off",
"vue/comma-dangle": "off",
"vue/comma-spacing": "off",
"vue/comma-style": "off",
"vue/dot-location": "off",
"vue/func-call-spacing": "off",
"vue/html-closing-bracket-newline": "off",
"vue/html-closing-bracket-spacing": "off",
"vue/html-end-tags": "off",
"vue/html-indent": "off",
"vue/html-quotes": "off",
"vue/key-spacing": "off",
"vue/keyword-spacing": "off",
"vue/max-attributes-per-line": "off",
"vue/multiline-html-element-content-newline": "off",
"vue/multiline-ternary": "off",
"vue/mustache-interpolation-spacing": "off",
"vue/no-extra-parens": "off",
"vue/no-multi-spaces": "off",
"vue/no-spaces-around-equal-signs-in-attribute": "off",
"vue/object-curly-newline": "off",
"vue/object-curly-spacing": "off",
"vue/object-property-newline": "off",
"vue/operator-linebreak": "off",
"vue/quote-props": "off",
"vue/script-indent": "off",
"vue/singleline-html-element-content-newline": "off",
"vue/space-in-parens": "off",
"vue/space-infix-ops": "off",
"vue/space-unary-ops": "off",
"vue/template-curly-spacing": "off",
...(includeDeprecated && {
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/generator-star
"generator-star": "off",
// Deprecated since version 4.0.0.
// https://github.com/eslint/eslint/pull/8286
"indent-legacy": "off",
// Removed in version 2.0.0.
// https://eslint.org/docs/latest/rules/no-arrow-condition
"no-arrow-condition": "off",
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/no-comma-dangle
"no-comma-dangle": "off",
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/no-reserved-keys
"no-reserved-keys": "off",
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/no-space-before-semi
"no-space-before-semi": "off",
// Deprecated since version 3.3.0.
// https://eslint.org/docs/rules/no-spaced-func
"no-spaced-func": "off",
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/no-wrap-func
"no-wrap-func": "off",
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/space-after-function-name
"space-after-function-name": "off",
// Removed in version 2.0.0.
// https://eslint.org/docs/latest/rules/space-after-keywords
"space-after-keywords": "off",
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/space-before-function-parentheses
"space-before-function-parentheses": "off",
// Removed in version 2.0.0.
// https://eslint.org/docs/latest/rules/space-before-keywords
"space-before-keywords": "off",
// Removed in version 1.0.0.
// https://eslint.org/docs/latest/rules/space-in-brackets
"space-in-brackets": "off",
// Removed in version 2.0.0.
// https://eslint.org/docs/latest/rules/space-return-throw-case
"space-return-throw-case": "off",
// Removed in version 0.10.0.
// https://eslint.org/docs/latest/rules/space-unary-word-ops
"space-unary-word-ops": "off",
// Deprecated since version 7.0.0.
// https://github.com/yannickcr/eslint-plugin-react/blob/master/CHANGELOG.md#700---2017-05-06
"react/jsx-space-before-closing": "off",
}),
},
};

prettier/prettier rules

"use strict";

module.exports = {
rules: {
// These are safe to use as long as the `"prettier/prettier"` rule from
// eslint-plugin-prettier isn't enabled.
// These are also included in `"plugin:prettier/recommended"`:
// https://github.com/prettier/eslint-plugin-prettier#recommended-configuration
"arrow-body-style": 0,
"prefer-arrow-callback": 0,
},
};

How to name the plugins

My Other Eslint related articles

Helpful

--

--

Mohamed Lamine Allal

Developper, Entrepreneur, CTO, Writer! A magic chaser! And A passionate thinker! Obsessed with Performance! And magic for life! And deep thinking!