From ed9059246c3d319cc21547659535c25cbbd00eac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Nikoli=C4=87?= Date: Fri, 15 Nov 2024 18:47:53 +0100 Subject: [PATCH 1/3] Update rules --- index.js | 5 ++++- vue.js | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 9b6ed5f..d408ad9 100644 --- a/index.js +++ b/index.js @@ -807,6 +807,9 @@ module.exports = { 'template-tag-spacing': [2, 'never'], 'wrap-iife': [2, 'inside'], 'wrap-regex': 0, - 'yield-star-spacing': [1, 'after'] + 'yield-star-spacing': [1, 'after'], + 'jsdoc/check-template-names': 0, + 'jsdoc/convert-to-jsdoc-comments': 0, + 'jsdoc/require-template': 0 } }; diff --git a/vue.js b/vue.js index 6ee7ed8..157518c 100644 --- a/vue.js +++ b/vue.js @@ -355,7 +355,12 @@ module.exports = { svg: 'always', math: 'always' } - ] + ], + 'vue/max-props': 0, + 'vue/max-template-depth': 0, + 'vue/no-deprecated-delete-set': 2, + 'vue/prefer-use-template-ref': 1, + 'vue/require-default-export': 1 }, overrides: [ { From 8363ae534d96f2ec0e9f546d62f7aa9fbe274328 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Nikoli=C4=87?= Date: Fri, 15 Nov 2024 19:37:28 +0100 Subject: [PATCH 2/3] Upgrade to ESLint 9 Closes #65. --- .eslintrc | 36 -- .github/workflows/ci.yml | 2 +- README.md | 84 ++-- browser.js | 16 +- eslint.config.js | 59 +++ index.js | 37 +- package.json | 43 ++- test/.eslintrc | 11 - test/fixtures/all-rules.cjs | 15 - test/index.js | 63 ++- tests.js | 17 +- typescript.js | 8 +- vue.js | 745 ++++++++++++++++++------------------ 13 files changed, 575 insertions(+), 561 deletions(-) delete mode 100644 .eslintrc create mode 100644 eslint.config.js delete mode 100644 test/.eslintrc delete mode 100644 test/fixtures/all-rules.cjs diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 012e4df..0000000 --- a/.eslintrc +++ /dev/null @@ -1,36 +0,0 @@ -{ - "root": true, - "extends": ["./index.js", "eslint-config-prettier"], - "parserOptions": { - "sourceType": "commonjs" - }, - "plugins": [ - "eslint-plugin-prettier", - "eslint-plugin-unicorn", - "eslint-plugin-import" - ], - "rules": { - "prettier/prettier": 1, - "unicorn/prefer-module": 0, - "import/no-commonjs": 0 - }, - "ignorePatterns": ["test/fixtures/*.config.*"], - "overrides": [ - { - "files": "*.js", - "rules": { - "unicorn/prevent-abbreviations": [ - 1, - { - "allowList": { - "env": true, - "props": true, - "prev": true, - "ignoreRefs": true - } - } - ] - } - } - ] -} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3a04bdf..e6faf4c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ jobs: strategy: matrix: node-version: - - 16 + - 18 steps: - name: Clone repository uses: actions/checkout@v2 diff --git a/README.md b/README.md index 8c29d99..aa2e04c 100644 --- a/README.md +++ b/README.md @@ -7,21 +7,21 @@ ## Install ```sh -npm install eslint@8 eslint-config-nitpick --save-dev +npm install eslint@9 eslint-config-nitpick --save-dev ``` ## Usage -Add this config to your `.eslintrc`: +Add this config to your `eslint.config.js`: -```json -{ - "extends": [ - "eslint-config-nitpick" - ] -} +```js +import configNitpick from 'eslint-config-nitpick'; + +export default [ + configNitpick +]; ``` @@ -31,21 +31,21 @@ preset:** -```json -{ - "extends": [ - "eslint-config-nitpick", - "eslint-config-nitpick/other-preset" - ] -} +```js +import configNitpick from 'eslint-config-nitpick'; +import configPreset from 'eslint-config-nitpick/other-preset'; + +export default [ + configNitpick, + configPreset +]; ``` ## Presets -In addition to default preset, there are also specific presets. You can apply -multiple presets with [ESLint `extends` option][eslint-extends]. +In addition to default preset, there are also specific presets. ### Browser @@ -53,12 +53,12 @@ Browser specific rules. -```json -{ - "extends": [ - "eslint-config-nitpick/browser" - ] -} +```js +import configBrowser from 'eslint-config-nitpick/browser'; + +export default [ + configBrowser +]; ``` @@ -69,12 +69,12 @@ Rules for testing frameworks (e.g. Mocha). -```json -{ - "extends": [ - "eslint-config-nitpick/tests" - ] -} +```js +import configTest from 'eslint-config-nitpick/tests'; + +export default [ + configTest +]; ``` @@ -85,12 +85,12 @@ Vue specific rules. -```json -{ - "extends": [ - "eslint-config-nitpick/vue" - ] -} +```js +import configVue from 'eslint-config-nitpick/vue'; + +export default [ + ...configVue +]; ``` @@ -101,12 +101,12 @@ TypeScript specific rules. -```json -{ - "extends": [ - "eslint-config-nitpick/typescript" - ] -} +```js +import configTypescript from 'eslint-config-nitpick/typescript'; + +export default [ + configTypescript +]; ``` @@ -120,7 +120,5 @@ MIT © [Ivan Nikolić](http://ivannikolic.com) [ci]: https://github.com/niksy/eslint-config-nitpick/actions?query=workflow%3ACI [ci-img]: https://github.com/niksy/eslint-config-nitpick/workflows/CI/badge.svg?branch=master [eslint]: http://eslint.org/ -[eslint-extends]: http://eslint.org/docs/user-guide/configuring#extending-configuration-files -[tc39-proposals]: https://github.com/tc39/proposals#active-proposals diff --git a/browser.js b/browser.js index dd931b4..e153540 100644 --- a/browser.js +++ b/browser.js @@ -1,11 +1,15 @@ -'use strict'; +import globals from 'globals'; +import pluginUnicorn from 'eslint-plugin-unicorn'; -module.exports = { - env: { - node: false, - browser: true +export default { + languageOptions: { + globals: { + ...globals.browser + } + }, + plugins: { + unicorn: pluginUnicorn }, - plugins: ['eslint-plugin-unicorn'], rules: { 'no-console': 2, 'no-implicit-globals': 2, diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000..556dda4 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,59 @@ +import configPrettier from 'eslint-config-prettier'; +import pluginPrettier from 'eslint-plugin-prettier'; +import pluginUnicorn from 'eslint-plugin-unicorn'; +import pluginImport from 'eslint-plugin-import'; +import configTest from './tests.js'; +import configBase from './index.js'; + +export default [ + configBase, + configPrettier, + { + plugins: { + prettier: pluginPrettier, + unicorn: pluginUnicorn, + import: pluginImport + }, + 'rules': { + 'prettier/prettier': 1, + 'unicorn/prefer-module': 0, + 'import/no-commonjs': 0 + } + }, + { + 'files': ['*.js'], + plugins: { + unicorn: pluginUnicorn + }, + 'rules': { + 'unicorn/prevent-abbreviations': [ + 1, + { + 'allowList': { + 'env': true, + 'props': true, + 'prev': true, + 'ignoreRefs': true + } + } + ] + } + }, + { + ...configTest, + 'files': ['test/**'], + plugins: { + ...configTest.plugins, + unicorn: pluginUnicorn, + import: pluginImport + }, + 'rules': { + ...configTest.rules, + 'unicorn/prefer-module': 2, + 'import/no-commonjs': 2 + } + }, + { + ignores: ['**/test/fixtures/*.config.*'] + } +]; diff --git a/index.js b/index.js index d408ad9..b118b18 100644 --- a/index.js +++ b/index.js @@ -1,21 +1,26 @@ -'use strict'; +import globals from 'globals'; +import pluginPromise from 'eslint-plugin-promise'; +import pluginNode from 'eslint-plugin-n'; +import pluginUnicorn from 'eslint-plugin-unicorn'; +import pluginJsdoc from 'eslint-plugin-jsdoc'; +import pluginImport from 'eslint-plugin-import'; -module.exports = { - env: { - node: true, - es2022: true - }, - parserOptions: { +export default { + languageOptions: { ecmaVersion: 2022, - sourceType: 'module' + sourceType: 'module', + globals: { + ...globals.node, + ...globals.es2022 + } + }, + plugins: { + promise: pluginPromise, + n: pluginNode, + unicorn: pluginUnicorn, + jsdoc: pluginJsdoc, + import: pluginImport }, - plugins: [ - 'eslint-plugin-promise', - 'eslint-plugin-n', - 'eslint-plugin-unicorn', - 'eslint-plugin-jsdoc', - 'eslint-plugin-import' - ], rules: { 'n/no-sync': 1, 'n/no-restricted-require': 0, @@ -267,7 +272,6 @@ module.exports = { 'no-unexpected-multiline': 2, 'no-unreachable': 2, 'use-isnan': 2, - 'valid-jsdoc': 0, 'valid-typeof': 2, 'no-unsafe-finally': 1, 'no-unsafe-negation': 2, @@ -445,7 +449,6 @@ module.exports = { } ], 'operator-assignment': 0, - 'require-jsdoc': 0, 'sort-keys': 0, 'sort-vars': 0, 'line-comment-position': 0, diff --git a/package.json b/package.json index ad494cb..662f728 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,14 @@ "license": "MIT", "author": "Ivan Nikolić (http://ivannikolic.com)", "main": "index.js", + "type": "module", + "exports": { + ".": "./index.js", + "./browser": "./browser.js", + "./tests": "./tests.js", + "./vue": "./vue.js", + "./typescript": "./typescript.js" + }, "directories": { "test": "test" }, @@ -16,35 +24,36 @@ "scripts": { "lint": "eslint '{index,browser,tests,vue,typescript,test/index}.js'", "release": "np --no-release-draft", - "test": "npm run lint && eslint-find-rules -u ./test/fixtures/all-rules.cjs && mocha 'test/index.js'", + "test": "npm run lint && mocha 'test/index.js'", "test:watch": "npm test -- --watch", "version": "if [ $(git rev-parse --abbrev-ref HEAD) == 'master' ]; then sed -i '' '/\\[unreleased\\]:/d' CHANGELOG.md && version-changelog CHANGELOG.md && changelog-verify CHANGELOG.md && git add CHANGELOG.md; else echo; fi", "postpublish": "GITHUB_TOKEN=$GITHUB_RELEASE_TOKEN github-release-from-changelog", "prerelease": "npm run lint" }, "dependencies": { - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-jsdoc": "^48.2.2", - "eslint-plugin-mocha": "^10.1.0", - "eslint-plugin-n": "^17.2.0", - "eslint-plugin-promise": "^6.1.1", - "eslint-plugin-unicorn": "^51.0.1", - "eslint-plugin-vue": "^9.7.0", - "resolve-from": "^5.0.0" + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.5.0", + "eslint-plugin-mocha": "^10.5.0", + "eslint-plugin-n": "^17.13.2", + "eslint-plugin-promise": "^7.1.0", + "eslint-plugin-unicorn": "^56.0.0", + "eslint-plugin-vue": "^9.31.0", + "globals": "^15.12.0", + "resolve-from": "^5.0.0", + "vue-eslint-parser": "^9.4.3" }, "devDependencies": { "changelog-verify": "^1.1.2", - "eslint": "^8.57.0", + "eslint": "^9.15.0", "eslint-config-prettier": "^9.1.0", - "eslint-find-rules": "^4.0.0", - "eslint-plugin-prettier": "^5.1.3", + "eslint-plugin-prettier": "^5.2.1", "github-release-from-changelog": "^2.1.1", - "husky": "^4.3.0", + "husky": "^4.3.8", "lint-staged": "^10.4.2", - "lodash": "^4.17.10", - "mocha": "^10.4.0", - "np": "^7.6.0", - "prettier": "^3.2.5", + "lodash": "^4.17.21", + "mocha": "^10.8.2", + "np": "^7.7.0", + "prettier": "^3.3.3", "version-changelog": "^3.1.1" }, "peerDependencies": { diff --git a/test/.eslintrc b/test/.eslintrc deleted file mode 100644 index be322cd..0000000 --- a/test/.eslintrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "extends": ["../tests.js"], - "plugins": ["eslint-plugin-unicorn", "eslint-plugin-import"], - "parserOptions": { - "sourceType": "module" - }, - "rules": { - "unicorn/prefer-module": 2, - "import/no-commonjs": 2 - } -} diff --git a/test/fixtures/all-rules.cjs b/test/fixtures/all-rules.cjs deleted file mode 100644 index 200dc30..0000000 --- a/test/fixtures/all-rules.cjs +++ /dev/null @@ -1,15 +0,0 @@ -'use strict'; - -const path = require('path'); - -module.exports = { - 'extends': [ - './index.js', - './browser.js', - './tests.js', - './vue.js', - './typescript.js' - ].map((m) => { - return require.resolve(path.resolve(process.cwd(), m)); - }) -}; diff --git a/test/index.js b/test/index.js index 47a0de2..11a9224 100644 --- a/test/index.js +++ b/test/index.js @@ -1,13 +1,17 @@ import assert from 'node:assert'; -import { createRequire } from 'node:module'; import { fileURLToPath } from 'node:url'; import isPlainObject from 'lodash/isPlainObject.js'; import { ESLint } from 'eslint'; +import configBase from '../index.js'; +import configBrowser from '../browser.js'; +import configTest from '../tests.js'; +import configVue from '../vue.js'; +import configTypescript from '../typescript.js'; async function runEslint(file, config) { const linter = new ESLint({ - useEslintrc: false, - baseConfig: config + overrideConfigFile: true, + overrideConfig: config }); const [results] = await linter.lintFiles([ fileURLToPath(new URL(file, import.meta.url)) @@ -22,21 +26,18 @@ async function runEslint(file, config) { } describe('Config format', function () { - const require = createRequire(import.meta.url); - const config = require('../index.js'); - - it('should have config objects which are plain objects', function () { - assert.ok(isPlainObject(config)); - assert.ok(isPlainObject(config.env)); - assert.ok(isPlainObject(config.rules)); + it('should have config objects which are plain objects', async function () { + assert.ok(isPlainObject(configBase)); + assert.ok(isPlainObject(configBase.rules)); }); }); describe('Default config', function () { it('should return proper validation errors for linted code', async function () { - const errors = await runEslint('./fixtures/default.config.js', { - extends: fileURLToPath(new URL('../index.js', import.meta.url)) - }); + const errors = await runEslint( + './fixtures/default.config.js', + configBase + ); assert.notEqual(errors.indexOf('quotes'), -1); assert.notEqual(errors.indexOf('semi'), -1); assert.notEqual(errors.indexOf('promise/param-names'), -1); @@ -49,22 +50,20 @@ describe('Default config', function () { describe('Browser config', function () { it('should return proper validation errors for linted code', async function () { - const errors = await runEslint('./fixtures/browser.config.js', { - extends: ['../index.js', '../browser.js'].map((entry) => - fileURLToPath(new URL(entry, import.meta.url)) - ) - }); + const errors = await runEslint('./fixtures/browser.config.js', [ + configBase, + configBrowser + ]); assert.notEqual(errors.indexOf('no-console'), -1); }); }); describe('Tests config', function () { it('should return proper validation errors for linted code', async function () { - const errors = await runEslint('./fixtures/tests.config.js', { - extends: ['../index.js', '../tests.js'].map((entry) => - fileURLToPath(new URL(entry, import.meta.url)) - ) - }); + const errors = await runEslint('./fixtures/tests.config.js', [ + configBase, + configTest + ]); assert.notEqual(errors.indexOf('max-nested-callbacks'), -1); assert.notEqual(errors.indexOf('mocha/no-mocha-arrows'), -1); assert.equal(errors.indexOf('promise/always-return'), -1); @@ -73,11 +72,10 @@ describe('Tests config', function () { describe('Vue config', function () { it('should return proper validation errors for linted code', async function () { - const errors = await runEslint('./fixtures/vue.config.vue', { - extends: ['../index.js', '../vue.js'].map((entry) => - fileURLToPath(new URL(entry, import.meta.url)) - ) - }); + const errors = await runEslint('./fixtures/vue.config.vue', [ + configBase, + ...configVue + ]); assert.notEqual(errors.indexOf('vue/no-multiple-template-root'), -1); assert.notEqual(errors.indexOf('vue/script-indent'), -1); }); @@ -85,11 +83,10 @@ describe('Vue config', function () { describe('TypeScript config', function () { it('should return proper validation errors for linted code', async function () { - const errors = await runEslint('./fixtures/typescript.config.js', { - extends: ['../index.js', '../typescript.js'].map((entry) => - fileURLToPath(new URL(entry, import.meta.url)) - ) - }); + const errors = await runEslint('./fixtures/typescript.config.js', [ + configBase, + configTypescript + ]); assert.notEqual(errors.length, 0); }); }); diff --git a/tests.js b/tests.js index 4ffe757..d364373 100644 --- a/tests.js +++ b/tests.js @@ -1,10 +1,17 @@ -'use strict'; +import globals from 'globals'; +import pluginMocha from 'eslint-plugin-mocha'; +import pluginPromise from 'eslint-plugin-promise'; -module.exports = { - env: { - mocha: true +export default { + languageOptions: { + globals: { + ...globals.mocha + } + }, + plugins: { + mocha: pluginMocha, + promise: pluginPromise }, - plugins: ['eslint-plugin-mocha', 'eslint-plugin-promise'], rules: { 'promise/always-return': 0, 'mocha/no-exclusive-tests': 1, diff --git a/typescript.js b/typescript.js index 6dd45b0..ae17742 100644 --- a/typescript.js +++ b/typescript.js @@ -1,7 +1,9 @@ -'use strict'; +import pluginJsdoc from 'eslint-plugin-jsdoc'; -module.exports = { - plugins: ['eslint-plugin-jsdoc'], +export default { + plugins: { + jsdoc: pluginJsdoc + }, settings: { jsdoc: { mode: 'typescript' diff --git a/vue.js b/vue.js index 157518c..1577541 100644 --- a/vue.js +++ b/vue.js @@ -1,379 +1,376 @@ -'use strict'; +import pluginVue from 'eslint-plugin-vue'; +import parserVueEslint from 'vue-eslint-parser'; -const path = require('node:path'); -const resolveFrom = require('resolve-from'); - -module.exports = { - parser: resolveFrom( - path.dirname(require.resolve('eslint-plugin-vue')), - 'vue-eslint-parser' - ), - parserOptions: { - sourceType: 'module' - }, - plugins: ['eslint-plugin-vue'], - rules: { - 'no-param-reassign': [ - 1, - { - props: true, - ignorePropertyModificationsFor: ['state'] - } - ], - 'vue/comment-directive': 2, - 'vue/jsx-uses-vars': 2, - 'vue/no-loss-of-precision': 1, - 'vue/dot-notation': 1, - 'vue/no-irregular-whitespace': 2, - 'vue/no-sparse-arrays': 2, - 'vue/no-useless-concat': 1, - 'vue/prefer-template': 1, - 'vue/no-constant-condition': 2, - 'vue/camelcase': 0, - 'vue/eqeqeq': 0, - 'vue/no-restricted-syntax': 0, - 'vue/object-shorthand': [1, 'consistent-as-needed'], - 'vue/no-useless-template-attributes': 2, - 'vue/no-reserved-props': 2, - 'vue/no-computed-properties-in-data': 2, - 'vue/multi-word-component-names': 0, - 'vue/valid-v-bind-sync': 2, - 'vue/no-setup-props-destructure': 2, - 'vue/no-ref-as-operand': 2, - 'vue/no-mutating-props': 2, - 'vue/no-multiple-template-root': 2, - 'vue/no-custom-modifiers-on-v-model': 2, - 'vue/no-deprecated-data-object-declaration': 2, - 'vue/no-deprecated-filter': 2, - 'vue/no-deprecated-html-element-is': 2, - 'vue/no-deprecated-inline-template': 2, - 'vue/no-deprecated-slot-attribute': 2, - 'vue/no-deprecated-slot-scope-attribute': 2, - 'vue/no-deprecated-v-bind-sync': 2, - 'vue/no-deprecated-vue-config-keycodes': 2, - 'vue/no-dupe-v-else-if': 2, - 'vue/no-lifecycle-after-await': 2, - 'vue/no-watch-after-await': 2, - 'vue/no-v-for-template-key': 2, - 'vue/no-v-model-argument': 2, - 'vue/return-in-emits-validator': 2, - 'vue/use-v-on-exact': 2, - 'vue/no-v-text-v-html-on-component': 2, - 'vue/valid-attribute-name': 2, - 'vue/valid-model-definition': 2, - 'vue/valid-v-memo': 2, - 'vue/no-deprecated-destroyed-lifecycle': 2, - 'vue/no-deprecated-dollar-listeners-api': 2, - 'vue/no-deprecated-dollar-scopedslots-api': 2, - 'vue/no-deprecated-events-api': 2, - 'vue/no-deprecated-functional-template': 2, - 'vue/no-deprecated-props-default-this': 2, - 'vue/no-deprecated-v-on-native-modifier': 2, - 'vue/no-deprecated-v-on-number-modifiers': 2, - 'vue/no-v-for-template-key-on-child': 2, - 'vue/require-slots-as-functions': 2, - 'vue/require-toggle-inside-transition': 2, - 'vue/valid-v-is': 2, - 'vue/no-deprecated-v-is': 2, - 'vue/require-expose': 0, - 'vue/valid-define-emits': 1, - 'vue/valid-define-props': 1, - 'vue/no-deprecated-router-link-tag-prop': 2, - 'vue/no-expose-after-await': 2, - 'vue/prefer-import-from-vue': 2, - 'vue/no-arrow-functions-in-watch': 2, - 'vue/custom-event-name-casing': [2, 'camelCase'], - 'vue/no-async-in-computed-properties': 2, - 'vue/no-dupe-keys': 2, - 'vue/no-duplicate-attributes': [ - 2, - { allowCoexistClass: true, allowCoexistStyle: true } - ], - 'vue/no-parsing-error': 2, - 'vue/no-reserved-keys': 2, - 'vue/no-shared-component-data': 2, - 'vue/no-side-effects-in-computed-properties': 2, - 'vue/no-template-key': 2, - 'vue/no-textarea-mustache': 2, - 'vue/no-unused-vars': 1, - 'vue/require-component-is': 2, - 'vue/require-render-return': 2, - 'vue/require-v-for-key': 2, - 'vue/require-valid-default-prop': 2, - 'vue/return-in-computed-property': 2, - 'vue/valid-template-root': 2, - 'vue/valid-v-bind': 2, - 'vue/valid-v-cloak': 2, - 'vue/valid-v-else-if': 2, - 'vue/valid-v-else': 2, - 'vue/valid-v-for': 2, - 'vue/valid-v-html': 2, - 'vue/valid-v-if': 2, - 'vue/valid-v-model': 2, - 'vue/valid-v-on': 2, - 'vue/valid-v-once': 2, - 'vue/valid-v-pre': 2, - 'vue/valid-v-show': 2, - 'vue/valid-v-text': 2, - 'vue/no-unused-components': 1, - 'vue/require-prop-type-constructor': 2, - 'vue/first-attribute-linebreak': [ - 2, - { singleline: 'ignore', multiline: 'below' } - ], - 'vue/require-explicit-emits': 2, - 'vue/one-component-per-file': 2, - 'vue/component-definition-name-casing': [2, 'PascalCase'], - 'vue/attribute-hyphenation': [2, 'never'], - 'vue/require-default-prop': 1, - 'vue/require-prop-types': 1, - 'vue/v-bind-style': [2, 'shorthand'], - 'vue/v-on-style': [2, 'shorthand'], - 'vue/no-template-shadow': 2, - 'vue/no-multiple-slot-args': 2, - 'vue/no-lone-template': 1, - 'vue/component-tags-order': [ - 2, - { 'order': ['template', 'script', 'style'] } - ], - 'vue/attributes-order': 2, - 'vue/order-in-components': 2, - 'vue/this-in-template': [1, 'never'], - 'vue/no-use-v-if-with-v-for': 2, - 'vue/no-v-html': 1, - 'vue/prefer-separate-static-class': 0, - 'vue/no-v-text': 2, - 'vue/no-use-computed-property-like-method': 1, - 'vue/no-undef-properties': 1, - 'vue/no-restricted-class': 0, - 'vue/v-for-delimiter-style': [2, 'in'], - 'vue/static-class-names-order': 0, - 'vue/sort-keys': 0, - 'vue/require-name-property': 0, - 'vue/padding-line-between-blocks': [1, 'never'], - 'vue/no-useless-v-bind': 1, - 'vue/no-useless-mustaches': 2, - 'vue/no-unused-properties': 1, - 'vue/no-unsupported-features': 0, - 'vue/no-template-target-blank': 2, - 'vue/no-static-inline-styles': 2, - 'vue/no-reserved-component-names': 2, - 'vue/no-restricted-component-options': 0, - 'vue/no-restricted-static-attribute': 0, - 'vue/no-restricted-v-bind': 0, - 'vue/no-potential-component-option-typo': 0, - 'vue/no-multiple-objects-in-class': 1, - 'vue/no-duplicate-attr-inheritance': 2, - 'vue/no-empty-component-block': 1, - 'vue/no-bare-strings-in-template': 0, - 'vue/html-comment-content-newline': 0, - 'vue/html-comment-content-spacing': 0, - 'vue/html-comment-indent': 0, - 'vue/valid-v-slot': 2, - 'vue/v-slot-style': [ - 2, - { - atComponent: 'v-slot', - default: 'v-slot', - named: 'longform' - } - ], - 'vue/no-deprecated-scope-attribute': 2, - 'vue/no-empty-pattern': 2, - 'vue/prop-name-casing': [2, 'camelCase'], - 'vue/component-name-in-template-casing': [ - 2, - 'PascalCase', - { - ignores: [ - 'svg', - 'rect', - 'router-view', - 'router-link', - 'component', - 'transition', - 'transition-group', - 'keep-alive', - 'slot' - ] - } - ], - 'vue/html-button-has-type': 2, - 'vue/new-line-between-multi-line-property': 1, - 'vue/next-tick-style': [2, 'promise'], - 'vue/no-export-in-script-setup': 2, - 'vue/no-restricted-block': 0, - 'vue/no-restricted-call-after-await': 0, - 'vue/no-restricted-custom-event': 0, - 'vue/no-restricted-props': 0, - 'vue/no-this-in-before-route-enter': 2, - 'vue/no-unused-refs': 1, - 'vue/require-emit-validator': 1, - 'vue/v-on-event-hyphenation': [2, 'never'], - 'vue/valid-next-tick': 2, - 'vue/match-component-file-name': 0, - 'vue/no-boolean-default': 0, - 'vue/require-direct-export': 2, - 'vue/v-on-function-call': [2, 'never'], - 'vue/block-lang': 0, - 'vue/component-api-style': 0, - 'vue/component-options-name-casing': [2, 'PascalCase'], - 'vue/no-child-content': 2, - 'vue/define-emits-declaration': 0, - 'vue/define-macros-order': 1, - 'vue/define-props-declaration': 0, - 'vue/match-component-import-name': 0, - 'vue/no-ref-object-destructure': 2, - 'vue/no-required-prop-with-default': 0, - 'vue/no-restricted-html-elements': 0, - 'vue/no-undef-components': 2, - 'vue/padding-line-between-tags': 0, - 'vue/prefer-prop-type-boolean-first': 2, - 'vue/prefer-true-attribute-shorthand': 0, - 'vue/v-on-handler-style': 0, - 'vue/block-order': [1, { 'order': ['template', 'script', 'style'] }], - 'vue/enforce-style-attribute': 0, - 'vue/max-lines-per-block': 0, - 'vue/no-deprecated-model-definition': 2, - 'vue/no-ref-object-reactivity-loss': 2, - 'vue/no-restricted-component-names': 0, - 'vue/no-restricted-v-on': 0, - 'vue/no-root-v-if': 0, - 'vue/no-setup-props-reactivity-loss': 2, - 'vue/no-unused-emit-declarations': 1, - 'vue/no-use-v-else-with-v-for': 2, - 'vue/padding-lines-in-component-definition': 0, - 'vue/prefer-define-options': 1, - 'vue/require-explicit-slots': 1, - 'vue/require-macro-variable-name': 1, - 'vue/require-prop-comment': 0, - 'vue/require-typed-object-prop': 0, - 'vue/require-typed-ref': 1, - 'vue/v-if-else-key': 2, - 'vue/valid-define-options': 1, - 'vue/no-console': 2, +export default [ + { + languageOptions: { + parser: parserVueEslint + }, + plugins: { + vue: pluginVue + }, + rules: { + 'no-param-reassign': [ + 1, + { + props: true, + ignorePropertyModificationsFor: ['state'] + } + ], + 'vue/comment-directive': 2, + 'vue/jsx-uses-vars': 2, + 'vue/no-loss-of-precision': 1, + 'vue/dot-notation': 1, + 'vue/no-irregular-whitespace': 2, + 'vue/no-sparse-arrays': 2, + 'vue/no-useless-concat': 1, + 'vue/prefer-template': 1, + 'vue/no-constant-condition': 2, + 'vue/camelcase': 0, + 'vue/eqeqeq': 0, + 'vue/no-restricted-syntax': 0, + 'vue/object-shorthand': [1, 'consistent-as-needed'], + 'vue/no-useless-template-attributes': 2, + 'vue/no-reserved-props': 2, + 'vue/no-computed-properties-in-data': 2, + 'vue/multi-word-component-names': 0, + 'vue/valid-v-bind-sync': 2, + 'vue/no-setup-props-destructure': 2, + 'vue/no-ref-as-operand': 2, + 'vue/no-mutating-props': 2, + 'vue/no-multiple-template-root': 2, + 'vue/no-custom-modifiers-on-v-model': 2, + 'vue/no-deprecated-data-object-declaration': 2, + 'vue/no-deprecated-filter': 2, + 'vue/no-deprecated-html-element-is': 2, + 'vue/no-deprecated-inline-template': 2, + 'vue/no-deprecated-slot-attribute': 2, + 'vue/no-deprecated-slot-scope-attribute': 2, + 'vue/no-deprecated-v-bind-sync': 2, + 'vue/no-deprecated-vue-config-keycodes': 2, + 'vue/no-dupe-v-else-if': 2, + 'vue/no-lifecycle-after-await': 2, + 'vue/no-watch-after-await': 2, + 'vue/no-v-for-template-key': 2, + 'vue/no-v-model-argument': 2, + 'vue/return-in-emits-validator': 2, + 'vue/use-v-on-exact': 2, + 'vue/no-v-text-v-html-on-component': 2, + 'vue/valid-attribute-name': 2, + 'vue/valid-model-definition': 2, + 'vue/valid-v-memo': 2, + 'vue/no-deprecated-destroyed-lifecycle': 2, + 'vue/no-deprecated-dollar-listeners-api': 2, + 'vue/no-deprecated-dollar-scopedslots-api': 2, + 'vue/no-deprecated-events-api': 2, + 'vue/no-deprecated-functional-template': 2, + 'vue/no-deprecated-props-default-this': 2, + 'vue/no-deprecated-v-on-native-modifier': 2, + 'vue/no-deprecated-v-on-number-modifiers': 2, + 'vue/no-v-for-template-key-on-child': 2, + 'vue/require-slots-as-functions': 2, + 'vue/require-toggle-inside-transition': 2, + 'vue/valid-v-is': 2, + 'vue/no-deprecated-v-is': 2, + 'vue/require-expose': 0, + 'vue/valid-define-emits': 1, + 'vue/valid-define-props': 1, + 'vue/no-deprecated-router-link-tag-prop': 2, + 'vue/no-expose-after-await': 2, + 'vue/prefer-import-from-vue': 2, + 'vue/no-arrow-functions-in-watch': 2, + 'vue/custom-event-name-casing': [2, 'camelCase'], + 'vue/no-async-in-computed-properties': 2, + 'vue/no-dupe-keys': 2, + 'vue/no-duplicate-attributes': [ + 2, + { allowCoexistClass: true, allowCoexistStyle: true } + ], + 'vue/no-parsing-error': 2, + 'vue/no-reserved-keys': 2, + 'vue/no-shared-component-data': 2, + 'vue/no-side-effects-in-computed-properties': 2, + 'vue/no-template-key': 2, + 'vue/no-textarea-mustache': 2, + 'vue/no-unused-vars': 1, + 'vue/require-component-is': 2, + 'vue/require-render-return': 2, + 'vue/require-v-for-key': 2, + 'vue/require-valid-default-prop': 2, + 'vue/return-in-computed-property': 2, + 'vue/valid-template-root': 2, + 'vue/valid-v-bind': 2, + 'vue/valid-v-cloak': 2, + 'vue/valid-v-else-if': 2, + 'vue/valid-v-else': 2, + 'vue/valid-v-for': 2, + 'vue/valid-v-html': 2, + 'vue/valid-v-if': 2, + 'vue/valid-v-model': 2, + 'vue/valid-v-on': 2, + 'vue/valid-v-once': 2, + 'vue/valid-v-pre': 2, + 'vue/valid-v-show': 2, + 'vue/valid-v-text': 2, + 'vue/no-unused-components': 1, + 'vue/require-prop-type-constructor': 2, + 'vue/first-attribute-linebreak': [ + 2, + { singleline: 'ignore', multiline: 'below' } + ], + 'vue/require-explicit-emits': 2, + 'vue/one-component-per-file': 2, + 'vue/component-definition-name-casing': [2, 'PascalCase'], + 'vue/attribute-hyphenation': [2, 'never'], + 'vue/require-default-prop': 1, + 'vue/require-prop-types': 1, + 'vue/v-bind-style': [2, 'shorthand'], + 'vue/v-on-style': [2, 'shorthand'], + 'vue/no-template-shadow': 2, + 'vue/no-multiple-slot-args': 2, + 'vue/no-lone-template': 1, + 'vue/component-tags-order': [ + 2, + { 'order': ['template', 'script', 'style'] } + ], + 'vue/attributes-order': 2, + 'vue/order-in-components': 2, + 'vue/this-in-template': [1, 'never'], + 'vue/no-use-v-if-with-v-for': 2, + 'vue/no-v-html': 1, + 'vue/prefer-separate-static-class': 0, + 'vue/no-v-text': 2, + 'vue/no-use-computed-property-like-method': 1, + 'vue/no-undef-properties': 1, + 'vue/no-restricted-class': 0, + 'vue/v-for-delimiter-style': [2, 'in'], + 'vue/static-class-names-order': 0, + 'vue/sort-keys': 0, + 'vue/require-name-property': 0, + 'vue/padding-line-between-blocks': [1, 'never'], + 'vue/no-useless-v-bind': 1, + 'vue/no-useless-mustaches': 2, + 'vue/no-unused-properties': 1, + 'vue/no-unsupported-features': 0, + 'vue/no-template-target-blank': 2, + 'vue/no-static-inline-styles': 2, + 'vue/no-reserved-component-names': 2, + 'vue/no-restricted-component-options': 0, + 'vue/no-restricted-static-attribute': 0, + 'vue/no-restricted-v-bind': 0, + 'vue/no-potential-component-option-typo': 0, + 'vue/no-multiple-objects-in-class': 1, + 'vue/no-duplicate-attr-inheritance': 2, + 'vue/no-empty-component-block': 1, + 'vue/no-bare-strings-in-template': 0, + 'vue/html-comment-content-newline': 0, + 'vue/html-comment-content-spacing': 0, + 'vue/html-comment-indent': 0, + 'vue/valid-v-slot': 2, + 'vue/v-slot-style': [ + 2, + { + atComponent: 'v-slot', + default: 'v-slot', + named: 'longform' + } + ], + 'vue/no-deprecated-scope-attribute': 2, + 'vue/no-empty-pattern': 2, + 'vue/prop-name-casing': [2, 'camelCase'], + 'vue/component-name-in-template-casing': [ + 2, + 'PascalCase', + { + ignores: [ + 'svg', + 'rect', + 'router-view', + 'router-link', + 'component', + 'transition', + 'transition-group', + 'keep-alive', + 'slot' + ] + } + ], + 'vue/html-button-has-type': 2, + 'vue/new-line-between-multi-line-property': 1, + 'vue/next-tick-style': [2, 'promise'], + 'vue/no-export-in-script-setup': 2, + 'vue/no-restricted-block': 0, + 'vue/no-restricted-call-after-await': 0, + 'vue/no-restricted-custom-event': 0, + 'vue/no-restricted-props': 0, + 'vue/no-this-in-before-route-enter': 2, + 'vue/no-unused-refs': 1, + 'vue/require-emit-validator': 1, + 'vue/v-on-event-hyphenation': [2, 'never'], + 'vue/valid-next-tick': 2, + 'vue/match-component-file-name': 0, + 'vue/no-boolean-default': 0, + 'vue/require-direct-export': 2, + 'vue/v-on-function-call': [2, 'never'], + 'vue/block-lang': 0, + 'vue/component-api-style': 0, + 'vue/component-options-name-casing': [2, 'PascalCase'], + 'vue/no-child-content': 2, + 'vue/define-emits-declaration': 0, + 'vue/define-macros-order': 1, + 'vue/define-props-declaration': 0, + 'vue/match-component-import-name': 0, + 'vue/no-ref-object-destructure': 2, + 'vue/no-required-prop-with-default': 0, + 'vue/no-restricted-html-elements': 0, + 'vue/no-undef-components': 2, + 'vue/padding-line-between-tags': 0, + 'vue/prefer-prop-type-boolean-first': 2, + 'vue/prefer-true-attribute-shorthand': 0, + 'vue/v-on-handler-style': 0, + 'vue/block-order': [ + 1, + { 'order': ['template', 'script', 'style'] } + ], + 'vue/enforce-style-attribute': 0, + 'vue/max-lines-per-block': 0, + 'vue/no-deprecated-model-definition': 2, + 'vue/no-ref-object-reactivity-loss': 2, + 'vue/no-restricted-component-names': 0, + 'vue/no-restricted-v-on': 0, + 'vue/no-root-v-if': 0, + 'vue/no-setup-props-reactivity-loss': 2, + 'vue/no-unused-emit-declarations': 1, + 'vue/no-use-v-else-with-v-for': 2, + 'vue/padding-lines-in-component-definition': 0, + 'vue/prefer-define-options': 1, + 'vue/require-explicit-slots': 1, + 'vue/require-macro-variable-name': 1, + 'vue/require-prop-comment': 0, + 'vue/require-typed-object-prop': 0, + 'vue/require-typed-ref': 1, + 'vue/v-if-else-key': 2, + 'vue/valid-define-options': 1, + 'vue/no-console': 2, - // Stylistic rules - 'vue/array-bracket-newline': [1, 'consistent'], - 'vue/array-bracket-spacing': 0, - 'vue/array-element-newline': [1, 'consistent'], - 'vue/arrow-spacing': 0, - 'vue/block-spacing': 0, - 'vue/brace-style': 0, - 'vue/comma-dangle': 0, - 'vue/comma-spacing': [ - 2, - { - before: false, - after: true - } - ], - 'vue/comma-style': [2, 'last'], - 'vue/dot-location': [1, 'property'], - 'vue/func-call-spacing': [2, 'never'], - 'vue/key-spacing': 0, - 'vue/keyword-spacing': [ - 2, - { - before: true, - after: true - } - ], - 'vue/max-len': 0, - 'vue/multiline-ternary': 0, - 'vue/no-extra-parens': 0, - 'vue/no-multi-spaces': 2, - 'vue/object-curly-newline': [ - 1, - { - consistent: true - } - ], - 'vue/object-curly-spacing': 0, - 'vue/object-property-newline': [ - 1, - { allowAllPropertiesOnSameLine: true } - ], - 'vue/operator-linebreak': [2, 'after'], - 'vue/quote-props': [ - 1, - 'consistent-as-needed', - { - keywords: true - } - ], - 'vue/space-in-parens': 0, - 'vue/space-infix-ops': 0, - 'vue/space-unary-ops': 0, - 'vue/template-curly-spacing': [2, 'never'], - 'vue/block-tag-newline': 0, - 'vue/html-closing-bracket-newline': [ - 2, - { - singleline: 'never', - multiline: 'always' - } - ], - 'vue/html-closing-bracket-spacing': [ - 2, - { - startTag: 'never', - endTag: 'never', - selfClosingTag: 'always' - } - ], - 'vue/html-end-tags': 2, - 'vue/html-indent': [2, 'tab'], - 'vue/html-quotes': [2, 'double'], - 'vue/max-attributes-per-line': [ - 2, - { - singleline: 3, - multiline: 1 - } - ], - 'vue/multiline-html-element-content-newline': 1, - 'vue/mustache-interpolation-spacing': [2, 'always'], - 'vue/no-spaces-around-equal-signs-in-attribute': 2, - 'vue/script-indent': [ - 2, - 'tab', - { - baseIndent: 1, - switchCase: 1 - } - ], - 'vue/singleline-html-element-content-newline': 0, - 'vue/html-self-closing': [ - 2, - { - html: { - void: 'always', - normal: 'never', - component: 'always' - }, - svg: 'always', - math: 'always' - } - ], - 'vue/max-props': 0, - 'vue/max-template-depth': 0, - 'vue/no-deprecated-delete-set': 2, - 'vue/prefer-use-template-ref': 1, - 'vue/require-default-export': 1 + // Stylistic rules + 'vue/array-bracket-newline': [1, 'consistent'], + 'vue/array-bracket-spacing': 0, + 'vue/array-element-newline': [1, 'consistent'], + 'vue/arrow-spacing': 0, + 'vue/block-spacing': 0, + 'vue/brace-style': 0, + 'vue/comma-dangle': 0, + 'vue/comma-spacing': [ + 2, + { + before: false, + after: true + } + ], + 'vue/comma-style': [2, 'last'], + 'vue/dot-location': [1, 'property'], + 'vue/func-call-spacing': [2, 'never'], + 'vue/key-spacing': 0, + 'vue/keyword-spacing': [ + 2, + { + before: true, + after: true + } + ], + 'vue/max-len': 0, + 'vue/multiline-ternary': 0, + 'vue/no-extra-parens': 0, + 'vue/no-multi-spaces': 2, + 'vue/object-curly-newline': [ + 1, + { + consistent: true + } + ], + 'vue/object-curly-spacing': 0, + 'vue/object-property-newline': [ + 1, + { allowAllPropertiesOnSameLine: true } + ], + 'vue/operator-linebreak': [2, 'after'], + 'vue/quote-props': [ + 1, + 'consistent-as-needed', + { + keywords: true + } + ], + 'vue/space-in-parens': 0, + 'vue/space-infix-ops': 0, + 'vue/space-unary-ops': 0, + 'vue/template-curly-spacing': [2, 'never'], + 'vue/block-tag-newline': 0, + 'vue/html-closing-bracket-newline': [ + 2, + { + singleline: 'never', + multiline: 'always' + } + ], + 'vue/html-closing-bracket-spacing': [ + 2, + { + startTag: 'never', + endTag: 'never', + selfClosingTag: 'always' + } + ], + 'vue/html-end-tags': 2, + 'vue/html-indent': [2, 'tab'], + 'vue/html-quotes': [2, 'double'], + 'vue/max-attributes-per-line': [ + 2, + { + singleline: 3, + multiline: 1 + } + ], + 'vue/multiline-html-element-content-newline': 1, + 'vue/mustache-interpolation-spacing': [2, 'always'], + 'vue/no-spaces-around-equal-signs-in-attribute': 2, + 'vue/singleline-html-element-content-newline': 0, + 'vue/html-self-closing': [ + 2, + { + html: { + void: 'always', + normal: 'never', + component: 'always' + }, + svg: 'always', + math: 'always' + } + ], + 'vue/max-props': 0, + 'vue/max-template-depth': 0, + 'vue/no-deprecated-delete-set': 2, + 'vue/prefer-use-template-ref': 1, + 'vue/require-default-export': 1, + 'vue/script-indent': 0 + } }, - overrides: [ - { - files: ['*.vue'], - rules: { - indent: 0 - } + { + files: ['**/*.vue'], + plugins: { + vue: pluginVue }, - { - files: ['!*.vue'], - rules: { - 'vue/script-indent': 0 - } + rules: { + indent: 0, + 'vue/script-indent': [ + 2, + 'tab', + { + baseIndent: 1, + switchCase: 1 + } + ] } - ] -}; + } +]; From 934cd3804f8fe25998d37174dcf0e47c30eab16f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ivan=20Nikoli=C4=87?= Date: Fri, 15 Nov 2024 19:37:28 +0100 Subject: [PATCH 3/3] Upgrade to ESLint 9 compatible version of eslint-find-rules Closes #70. --- package.json | 3 ++- test/fixtures/all-rules.js | 13 +++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 test/fixtures/all-rules.js diff --git a/package.json b/package.json index 662f728..2c77d76 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,7 @@ "scripts": { "lint": "eslint '{index,browser,tests,vue,typescript,test/index}.js'", "release": "np --no-release-draft", - "test": "npm run lint && mocha 'test/index.js'", + "test": "npm run lint && eslint-find-rules --flatConfig -u ./test/fixtures/all-rules.js && mocha 'test/index.js'", "test:watch": "npm test -- --watch", "version": "if [ $(git rev-parse --abbrev-ref HEAD) == 'master' ]; then sed -i '' '/\\[unreleased\\]:/d' CHANGELOG.md && version-changelog CHANGELOG.md && changelog-verify CHANGELOG.md && git add CHANGELOG.md; else echo; fi", "postpublish": "GITHUB_TOKEN=$GITHUB_RELEASE_TOKEN github-release-from-changelog", @@ -46,6 +46,7 @@ "changelog-verify": "^1.1.2", "eslint": "^9.15.0", "eslint-config-prettier": "^9.1.0", + "eslint-find-rules": "file:../eslint-find-rules", "eslint-plugin-prettier": "^5.2.1", "github-release-from-changelog": "^2.1.1", "husky": "^4.3.8", diff --git a/test/fixtures/all-rules.js b/test/fixtures/all-rules.js new file mode 100644 index 0000000..41055e6 --- /dev/null +++ b/test/fixtures/all-rules.js @@ -0,0 +1,13 @@ +import configBase from '../../index.js'; +import configBrowser from '../../browser.js'; +import configTest from '../../tests.js'; +import configVue from '../../vue.js'; +import configTypescript from '../../typescript.js'; + +export default [ + configBase, + configBrowser, + configTest, + ...configVue, + configTypescript +];