diff --git a/.changeset/brown-eels-care.md b/.changeset/brown-eels-care.md new file mode 100644 index 000000000..6d26027f0 --- /dev/null +++ b/.changeset/brown-eels-care.md @@ -0,0 +1,5 @@ +--- +"eslint-plugin-vue": minor +--- + +Use `error` instead of `warn` in configs when `VUE_ESLINT_ALWAYS_ERROR` env variable is `"true"` diff --git a/docs/user-guide/index.md b/docs/user-guide/index.md index 103471f61..4d8e40b24 100644 --- a/docs/user-guide/index.md +++ b/docs/user-guide/index.md @@ -73,6 +73,8 @@ You can use the following configs by adding them to `eslint.config.js`. :::warning Reporting rules By default, all rules from **base** and **essential** categories report ESLint errors. Other rules - because they're not covering potential bugs in the application - report warnings. What does it mean? By default - nothing, but if you want - you can set up a threshold and break the build after a certain amount of warnings, instead of any. More information [here](https://eslint.org/docs/user-guide/command-line-interface#handling-warnings). + +Alternatively, you can set `process.env.VUE_ESLINT_ALWAYS_ERROR` to `true` in your configuration file to have `error` be used by all rules. ::: #### Specifying Globals (`eslint.config.js`) diff --git a/lib/configs/flat/vue2-recommended.js b/lib/configs/flat/vue2-recommended.js index 8a972bf3d..8dfcec9dd 100644 --- a/lib/configs/flat/vue2-recommended.js +++ b/lib/configs/flat/vue2-recommended.js @@ -6,19 +6,22 @@ 'use strict' const config = require('./vue2-strongly-recommended.js') +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = [ ...config, { name: 'vue/vue2-recommended/rules', rules: { - 'vue/attributes-order': 'warn', - 'vue/block-order': 'warn', - 'vue/no-lone-template': 'warn', - 'vue/no-multiple-slot-args': 'warn', - 'vue/no-required-prop-with-default': 'warn', - 'vue/no-v-html': 'warn', - 'vue/order-in-components': 'warn', - 'vue/this-in-template': 'warn' + 'vue/attributes-order': ruleLevel, + 'vue/block-order': ruleLevel, + 'vue/no-lone-template': ruleLevel, + 'vue/no-multiple-slot-args': ruleLevel, + 'vue/no-required-prop-with-default': ruleLevel, + 'vue/no-v-html': ruleLevel, + 'vue/order-in-components': ruleLevel, + 'vue/this-in-template': ruleLevel } } ] diff --git a/lib/configs/flat/vue2-strongly-recommended.js b/lib/configs/flat/vue2-strongly-recommended.js index e4913f40c..d05f5feb6 100644 --- a/lib/configs/flat/vue2-strongly-recommended.js +++ b/lib/configs/flat/vue2-strongly-recommended.js @@ -6,34 +6,37 @@ 'use strict' const config = require('./vue2-essential.js') +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = [ ...config, { name: 'vue/vue2-strongly-recommended/rules', rules: { - 'vue/attribute-hyphenation': 'warn', - 'vue/component-definition-name-casing': 'warn', - 'vue/first-attribute-linebreak': 'warn', - 'vue/html-closing-bracket-newline': 'warn', - 'vue/html-closing-bracket-spacing': 'warn', - 'vue/html-end-tags': 'warn', - 'vue/html-indent': 'warn', - 'vue/html-quotes': 'warn', - 'vue/html-self-closing': 'warn', - 'vue/max-attributes-per-line': 'warn', - 'vue/multiline-html-element-content-newline': 'warn', - 'vue/mustache-interpolation-spacing': 'warn', - 'vue/no-multi-spaces': 'warn', - 'vue/no-spaces-around-equal-signs-in-attribute': 'warn', - 'vue/no-template-shadow': 'warn', - 'vue/one-component-per-file': 'warn', - 'vue/prop-name-casing': 'warn', - 'vue/require-default-prop': 'warn', - 'vue/require-prop-types': 'warn', - 'vue/singleline-html-element-content-newline': 'warn', - 'vue/v-bind-style': 'warn', - 'vue/v-on-style': 'warn', - 'vue/v-slot-style': 'warn' + 'vue/attribute-hyphenation': ruleLevel, + 'vue/component-definition-name-casing': ruleLevel, + 'vue/first-attribute-linebreak': ruleLevel, + 'vue/html-closing-bracket-newline': ruleLevel, + 'vue/html-closing-bracket-spacing': ruleLevel, + 'vue/html-end-tags': ruleLevel, + 'vue/html-indent': ruleLevel, + 'vue/html-quotes': ruleLevel, + 'vue/html-self-closing': ruleLevel, + 'vue/max-attributes-per-line': ruleLevel, + 'vue/multiline-html-element-content-newline': ruleLevel, + 'vue/mustache-interpolation-spacing': ruleLevel, + 'vue/no-multi-spaces': ruleLevel, + 'vue/no-spaces-around-equal-signs-in-attribute': ruleLevel, + 'vue/no-template-shadow': ruleLevel, + 'vue/one-component-per-file': ruleLevel, + 'vue/prop-name-casing': ruleLevel, + 'vue/require-default-prop': ruleLevel, + 'vue/require-prop-types': ruleLevel, + 'vue/singleline-html-element-content-newline': ruleLevel, + 'vue/v-bind-style': ruleLevel, + 'vue/v-on-style': ruleLevel, + 'vue/v-slot-style': ruleLevel } } ] diff --git a/lib/configs/flat/vue3-recommended.js b/lib/configs/flat/vue3-recommended.js index 21be71a8d..f46bc901a 100644 --- a/lib/configs/flat/vue3-recommended.js +++ b/lib/configs/flat/vue3-recommended.js @@ -6,19 +6,22 @@ 'use strict' const config = require('./vue3-strongly-recommended.js') +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = [ ...config, { name: 'vue/recommended/rules', rules: { - 'vue/attributes-order': 'warn', - 'vue/block-order': 'warn', - 'vue/no-lone-template': 'warn', - 'vue/no-multiple-slot-args': 'warn', - 'vue/no-required-prop-with-default': 'warn', - 'vue/no-v-html': 'warn', - 'vue/order-in-components': 'warn', - 'vue/this-in-template': 'warn' + 'vue/attributes-order': ruleLevel, + 'vue/block-order': ruleLevel, + 'vue/no-lone-template': ruleLevel, + 'vue/no-multiple-slot-args': ruleLevel, + 'vue/no-required-prop-with-default': ruleLevel, + 'vue/no-v-html': ruleLevel, + 'vue/order-in-components': ruleLevel, + 'vue/this-in-template': ruleLevel } } ] diff --git a/lib/configs/flat/vue3-strongly-recommended.js b/lib/configs/flat/vue3-strongly-recommended.js index fee1d3bb8..48db1aa90 100644 --- a/lib/configs/flat/vue3-strongly-recommended.js +++ b/lib/configs/flat/vue3-strongly-recommended.js @@ -6,42 +6,45 @@ 'use strict' const config = require('./vue3-essential.js') +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = [ ...config, { name: 'vue/strongly-recommended/rules', rules: { - 'vue/attribute-hyphenation': 'warn', - 'vue/component-definition-name-casing': 'warn', - 'vue/first-attribute-linebreak': 'warn', - 'vue/html-closing-bracket-newline': 'warn', - 'vue/html-closing-bracket-spacing': 'warn', - 'vue/html-end-tags': 'warn', - 'vue/html-indent': 'warn', - 'vue/html-quotes': 'warn', - 'vue/html-self-closing': 'warn', - 'vue/max-attributes-per-line': 'warn', - 'vue/multiline-html-element-content-newline': 'warn', - 'vue/mustache-interpolation-spacing': 'warn', - 'vue/no-multi-spaces': 'warn', - 'vue/no-spaces-around-equal-signs-in-attribute': 'warn', - 'vue/no-template-shadow': 'warn', - 'vue/one-component-per-file': 'warn', - 'vue/prop-name-casing': 'warn', - 'vue/require-default-prop': 'warn', - 'vue/require-explicit-emits': 'warn', - 'vue/require-prop-types': 'warn', - 'vue/singleline-html-element-content-newline': 'warn', - 'vue/v-bind-style': 'warn', + 'vue/attribute-hyphenation': ruleLevel, + 'vue/component-definition-name-casing': ruleLevel, + 'vue/first-attribute-linebreak': ruleLevel, + 'vue/html-closing-bracket-newline': ruleLevel, + 'vue/html-closing-bracket-spacing': ruleLevel, + 'vue/html-end-tags': ruleLevel, + 'vue/html-indent': ruleLevel, + 'vue/html-quotes': ruleLevel, + 'vue/html-self-closing': ruleLevel, + 'vue/max-attributes-per-line': ruleLevel, + 'vue/multiline-html-element-content-newline': ruleLevel, + 'vue/mustache-interpolation-spacing': ruleLevel, + 'vue/no-multi-spaces': ruleLevel, + 'vue/no-spaces-around-equal-signs-in-attribute': ruleLevel, + 'vue/no-template-shadow': ruleLevel, + 'vue/one-component-per-file': ruleLevel, + 'vue/prop-name-casing': ruleLevel, + 'vue/require-default-prop': ruleLevel, + 'vue/require-explicit-emits': ruleLevel, + 'vue/require-prop-types': ruleLevel, + 'vue/singleline-html-element-content-newline': ruleLevel, + 'vue/v-bind-style': ruleLevel, 'vue/v-on-event-hyphenation': [ - 'warn', + ruleLevel, 'always', { autofix: true } ], - 'vue/v-on-style': 'warn', - 'vue/v-slot-style': 'warn' + 'vue/v-on-style': ruleLevel, + 'vue/v-slot-style': ruleLevel } } ] diff --git a/lib/configs/vue2-recommended.js b/lib/configs/vue2-recommended.js index 9892867c1..a9957d27d 100644 --- a/lib/configs/vue2-recommended.js +++ b/lib/configs/vue2-recommended.js @@ -3,16 +3,19 @@ * This file has been automatically generated, * in order to update its content execute "npm run update" */ +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = { extends: require.resolve('./vue2-strongly-recommended'), rules: { - 'vue/attributes-order': 'warn', - 'vue/block-order': 'warn', - 'vue/no-lone-template': 'warn', - 'vue/no-multiple-slot-args': 'warn', - 'vue/no-required-prop-with-default': 'warn', - 'vue/no-v-html': 'warn', - 'vue/order-in-components': 'warn', - 'vue/this-in-template': 'warn' + 'vue/attributes-order': ruleLevel, + 'vue/block-order': ruleLevel, + 'vue/no-lone-template': ruleLevel, + 'vue/no-multiple-slot-args': ruleLevel, + 'vue/no-required-prop-with-default': ruleLevel, + 'vue/no-v-html': ruleLevel, + 'vue/order-in-components': ruleLevel, + 'vue/this-in-template': ruleLevel } } diff --git a/lib/configs/vue2-strongly-recommended.js b/lib/configs/vue2-strongly-recommended.js index e7b0f3dc7..47ca2ca7f 100644 --- a/lib/configs/vue2-strongly-recommended.js +++ b/lib/configs/vue2-strongly-recommended.js @@ -3,31 +3,34 @@ * This file has been automatically generated, * in order to update its content execute "npm run update" */ +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = { extends: require.resolve('./vue2-essential'), rules: { - 'vue/attribute-hyphenation': 'warn', - 'vue/component-definition-name-casing': 'warn', - 'vue/first-attribute-linebreak': 'warn', - 'vue/html-closing-bracket-newline': 'warn', - 'vue/html-closing-bracket-spacing': 'warn', - 'vue/html-end-tags': 'warn', - 'vue/html-indent': 'warn', - 'vue/html-quotes': 'warn', - 'vue/html-self-closing': 'warn', - 'vue/max-attributes-per-line': 'warn', - 'vue/multiline-html-element-content-newline': 'warn', - 'vue/mustache-interpolation-spacing': 'warn', - 'vue/no-multi-spaces': 'warn', - 'vue/no-spaces-around-equal-signs-in-attribute': 'warn', - 'vue/no-template-shadow': 'warn', - 'vue/one-component-per-file': 'warn', - 'vue/prop-name-casing': 'warn', - 'vue/require-default-prop': 'warn', - 'vue/require-prop-types': 'warn', - 'vue/singleline-html-element-content-newline': 'warn', - 'vue/v-bind-style': 'warn', - 'vue/v-on-style': 'warn', - 'vue/v-slot-style': 'warn' + 'vue/attribute-hyphenation': ruleLevel, + 'vue/component-definition-name-casing': ruleLevel, + 'vue/first-attribute-linebreak': ruleLevel, + 'vue/html-closing-bracket-newline': ruleLevel, + 'vue/html-closing-bracket-spacing': ruleLevel, + 'vue/html-end-tags': ruleLevel, + 'vue/html-indent': ruleLevel, + 'vue/html-quotes': ruleLevel, + 'vue/html-self-closing': ruleLevel, + 'vue/max-attributes-per-line': ruleLevel, + 'vue/multiline-html-element-content-newline': ruleLevel, + 'vue/mustache-interpolation-spacing': ruleLevel, + 'vue/no-multi-spaces': ruleLevel, + 'vue/no-spaces-around-equal-signs-in-attribute': ruleLevel, + 'vue/no-template-shadow': ruleLevel, + 'vue/one-component-per-file': ruleLevel, + 'vue/prop-name-casing': ruleLevel, + 'vue/require-default-prop': ruleLevel, + 'vue/require-prop-types': ruleLevel, + 'vue/singleline-html-element-content-newline': ruleLevel, + 'vue/v-bind-style': ruleLevel, + 'vue/v-on-style': ruleLevel, + 'vue/v-slot-style': ruleLevel } } diff --git a/lib/configs/vue3-recommended.js b/lib/configs/vue3-recommended.js index 083f6c65b..1346a6da3 100644 --- a/lib/configs/vue3-recommended.js +++ b/lib/configs/vue3-recommended.js @@ -3,16 +3,19 @@ * This file has been automatically generated, * in order to update its content execute "npm run update" */ +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = { extends: require.resolve('./vue3-strongly-recommended'), rules: { - 'vue/attributes-order': 'warn', - 'vue/block-order': 'warn', - 'vue/no-lone-template': 'warn', - 'vue/no-multiple-slot-args': 'warn', - 'vue/no-required-prop-with-default': 'warn', - 'vue/no-v-html': 'warn', - 'vue/order-in-components': 'warn', - 'vue/this-in-template': 'warn' + 'vue/attributes-order': ruleLevel, + 'vue/block-order': ruleLevel, + 'vue/no-lone-template': ruleLevel, + 'vue/no-multiple-slot-args': ruleLevel, + 'vue/no-required-prop-with-default': ruleLevel, + 'vue/no-v-html': ruleLevel, + 'vue/order-in-components': ruleLevel, + 'vue/this-in-template': ruleLevel } } diff --git a/lib/configs/vue3-strongly-recommended.js b/lib/configs/vue3-strongly-recommended.js index a3f854fc4..6b984eb4f 100644 --- a/lib/configs/vue3-strongly-recommended.js +++ b/lib/configs/vue3-strongly-recommended.js @@ -3,39 +3,42 @@ * This file has been automatically generated, * in order to update its content execute "npm run update" */ +const ruleLevel = + process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn' + module.exports = { extends: require.resolve('./vue3-essential'), rules: { - 'vue/attribute-hyphenation': 'warn', - 'vue/component-definition-name-casing': 'warn', - 'vue/first-attribute-linebreak': 'warn', - 'vue/html-closing-bracket-newline': 'warn', - 'vue/html-closing-bracket-spacing': 'warn', - 'vue/html-end-tags': 'warn', - 'vue/html-indent': 'warn', - 'vue/html-quotes': 'warn', - 'vue/html-self-closing': 'warn', - 'vue/max-attributes-per-line': 'warn', - 'vue/multiline-html-element-content-newline': 'warn', - 'vue/mustache-interpolation-spacing': 'warn', - 'vue/no-multi-spaces': 'warn', - 'vue/no-spaces-around-equal-signs-in-attribute': 'warn', - 'vue/no-template-shadow': 'warn', - 'vue/one-component-per-file': 'warn', - 'vue/prop-name-casing': 'warn', - 'vue/require-default-prop': 'warn', - 'vue/require-explicit-emits': 'warn', - 'vue/require-prop-types': 'warn', - 'vue/singleline-html-element-content-newline': 'warn', - 'vue/v-bind-style': 'warn', + 'vue/attribute-hyphenation': ruleLevel, + 'vue/component-definition-name-casing': ruleLevel, + 'vue/first-attribute-linebreak': ruleLevel, + 'vue/html-closing-bracket-newline': ruleLevel, + 'vue/html-closing-bracket-spacing': ruleLevel, + 'vue/html-end-tags': ruleLevel, + 'vue/html-indent': ruleLevel, + 'vue/html-quotes': ruleLevel, + 'vue/html-self-closing': ruleLevel, + 'vue/max-attributes-per-line': ruleLevel, + 'vue/multiline-html-element-content-newline': ruleLevel, + 'vue/mustache-interpolation-spacing': ruleLevel, + 'vue/no-multi-spaces': ruleLevel, + 'vue/no-spaces-around-equal-signs-in-attribute': ruleLevel, + 'vue/no-template-shadow': ruleLevel, + 'vue/one-component-per-file': ruleLevel, + 'vue/prop-name-casing': ruleLevel, + 'vue/require-default-prop': ruleLevel, + 'vue/require-explicit-emits': ruleLevel, + 'vue/require-prop-types': ruleLevel, + 'vue/singleline-html-element-content-newline': ruleLevel, + 'vue/v-bind-style': ruleLevel, 'vue/v-on-event-hyphenation': [ - 'warn', + ruleLevel, 'always', { autofix: true } ], - 'vue/v-on-style': 'warn', - 'vue/v-slot-style': 'warn' + 'vue/v-on-style': ruleLevel, + 'vue/v-slot-style': ruleLevel } } diff --git a/tools/update-lib-configs.js b/tools/update-lib-configs.js index 0c2845e45..d7e857e50 100644 --- a/tools/update-lib-configs.js +++ b/tools/update-lib-configs.js @@ -44,17 +44,24 @@ function formatRules(rules, categoryId) { return [rule.ruleId, options] }) ) - return JSON.stringify(obj, null, 2) + // use the ruleLevel variable for rules set to warn so that they can + // be made to error with an env variable if desired + return JSON.stringify(obj, null, 2).replaceAll('"warn"', 'ruleLevel') } function formatCategory(category) { const extendsCategoryId = extendsCategories[category.categoryId] + const formattedRules = formatRules(category.rules, category.categoryId) + const ruleLevelVariable = formattedRules.includes('ruleLevel') + ? "\nconst ruleLevel = process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn'\n" + : '' + if (extendsCategoryId == null) { return `/* * IMPORTANT! * This file has been automatically generated, * in order to update its content execute "npm run update" - */ + */${ruleLevelVariable} module.exports = { parserOptions: { ecmaVersion: 'latest', @@ -63,7 +70,7 @@ module.exports = { plugins: [ 'vue' ], - rules: ${formatRules(category.rules, category.categoryId)}, + rules: ${formattedRules}, overrides: [ { files: '*.vue', @@ -77,10 +84,10 @@ module.exports = { * IMPORTANT! * This file has been automatically generated, * in order to update its content execute "npm run update" - */ + */${ruleLevelVariable} module.exports = { extends: require.resolve('./${extendsCategoryId}'), - rules: ${formatRules(category.rules, category.categoryId)} + rules: ${formattedRules} } ` } diff --git a/tools/update-lib-flat-configs.js b/tools/update-lib-flat-configs.js index e55fb2d01..6894f00d6 100644 --- a/tools/update-lib-flat-configs.js +++ b/tools/update-lib-flat-configs.js @@ -44,17 +44,24 @@ function formatRules(rules, categoryId) { return [rule.ruleId, options] }) ) - return JSON.stringify(obj, null, 2) + // use the ruleLevel variable for rules set to warn so that they can + // be made to error with an env variable if desired + return JSON.stringify(obj, null, 2).replaceAll('"warn"', 'ruleLevel') } function formatCategory(category) { const extendsCategoryId = extendsCategories[category.categoryId] + const formattedRules = formatRules(category.rules, category.categoryId) + const ruleLevelVariable = formattedRules.includes('ruleLevel') + ? "\nconst ruleLevel = process.env.VUE_ESLINT_ALWAYS_ERROR === 'true' ? 'error' : 'warn'\n" + : '' + if (category.categoryId === 'base') { return `/* * IMPORTANT! * This file has been automatically generated, * in order to update its content execute "npm run update" - */ + */${ruleLevelVariable} module.exports = [ { name: 'vue/base/setup', @@ -79,7 +86,7 @@ module.exports = [ parser: require('vue-eslint-parser'), sourceType: 'module', }, - rules: ${formatRules(category.rules, category.categoryId)}, + rules: ${formattedRules}, processor: 'vue/vue' } ] @@ -93,11 +100,13 @@ module.exports = [ 'use strict' const config = require('./${extendsCategoryId}.js') +${ruleLevelVariable} + module.exports = [ ...config, { name: 'vue/${category.categoryId.replace(/^vue3-/u, '')}/rules', - rules: ${formatRules(category.rules, category.categoryId)}, + rules: ${formattedRules}, } ] `