From 22dfebf164e289c8b6a5ec43d7dd845245140636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Thu, 15 Jun 2017 13:24:45 +0200 Subject: [PATCH 0001/1448] Add "attention" section about beta release --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aa7a9bfee..83de73b8c 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,15 @@ > Official ESLint plugin for Vue.js -## :exclamation: Requirements +## :exclamation: Attention - this is documentation for beta `3.0.0` :exclamation: + +This branch contains `eslint-plugin-vue@beta` which is pre-released `3.0.0`, but it's not an official version that you get by `npm install eslint-plugin-vue`. In order to install this you need to specify either `3.0.0` in `package.json` or do `npm install eslint-plugin-vue@beta`. + +Please try it and report any issues that you might experience. + +If you want to check previous releases [go here](https://github.com/vuejs/eslint-plugin-vue/releases). + +## :grey_exclamation: Requirements - [ESLint](http://eslint.org/) `>=3.18.0`. - Node.js `>=4.0.0` @@ -14,7 +22,7 @@ ## :cd: Installation ``` -npm install --save-dev eslint eslint-plugin-vue +npm install --save-dev eslint eslint-plugin-vue@beta ``` ## :rocket: Usage From 5da884108a7d94433fe5e9fdf19adc10ed90277e Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Fri, 16 Jun 2017 07:07:08 +0900 Subject: [PATCH 0002/1448] Fix: move index.js and configs (#23) --- .eslintrc.js | 1 - {config => lib/config}/base.js | 0 {config => lib/config}/recommended.js | 2 +- index.js => lib/index.js | 2 +- 4 files changed, 2 insertions(+), 3 deletions(-) rename {config => lib/config}/base.js (100%) rename {config => lib/config}/recommended.js (56%) rename index.js => lib/index.js (76%) diff --git a/.eslintrc.js b/.eslintrc.js index 906fd952a..0d0779434 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -15,7 +15,6 @@ module.exports = { 'eslint-plugin' ], rules: { - 'complexity': 'off', 'eslint-plugin/report-message-format': ['error', '^[A-Z].*\\.$'], 'eslint-plugin/prefer-placeholders': 'error', 'eslint-plugin/consistent-output': 'error' diff --git a/config/base.js b/lib/config/base.js similarity index 100% rename from config/base.js rename to lib/config/base.js diff --git a/config/recommended.js b/lib/config/recommended.js similarity index 56% rename from config/recommended.js rename to lib/config/recommended.js index 5c5f596d1..a3b7f7f3c 100644 --- a/config/recommended.js +++ b/lib/config/recommended.js @@ -1,4 +1,4 @@ module.exports = { extends: require.resolve('./base.js'), - rules: require('../lib/recommended-rules.js') + rules: require('../recommended-rules.js') } diff --git a/index.js b/lib/index.js similarity index 76% rename from index.js rename to lib/index.js index 985c9341b..4c563f27f 100644 --- a/index.js +++ b/lib/index.js @@ -3,7 +3,7 @@ const resolve = require('path').resolve const requireIndex = require('requireindex') -const rules = requireIndex(resolve(__dirname, 'lib/rules')) +const rules = requireIndex(resolve(__dirname, 'rules')) const configs = requireIndex(resolve(__dirname, 'config')) module.exports = { From 55583c3be30e6264ad6c757adbe4ca3da35c92e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Fri, 16 Jun 2017 00:11:59 +0200 Subject: [PATCH 0003/1448] 3.0.1 --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3598aaddf..9bbf5b436 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "3.0.0", + "version": "3.0.1", "lockfileVersion": 1, "dependencies": { "@types/node": { diff --git a/package.json b/package.json index f2fc70edc..968de1392 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "3.0.0", + "version": "3.0.1", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "scripts": { From f35fb11a9e9b480d1cd54fcc7be50764ec1b75d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Fri, 16 Jun 2017 00:23:50 +0200 Subject: [PATCH 0004/1448] Update plugin version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83de73b8c..5134a45ac 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ## :exclamation: Attention - this is documentation for beta `3.0.0` :exclamation: -This branch contains `eslint-plugin-vue@beta` which is pre-released `3.0.0`, but it's not an official version that you get by `npm install eslint-plugin-vue`. In order to install this you need to specify either `3.0.0` in `package.json` or do `npm install eslint-plugin-vue@beta`. +This branch contains `eslint-plugin-vue@beta` which is pre-released `3.0.0`, but it's not an official version that you get by `npm install eslint-plugin-vue`. In order to install this you need to specify either `3.0.1` in `package.json` or do `npm install eslint-plugin-vue@beta`. Please try it and report any issues that you might experience. From 948a9ed4eed16eb8ee1fca982bad4decae8f4869 Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 16 Jun 2017 11:09:41 +0800 Subject: [PATCH 0005/1448] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5134a45ac..bd50cf3e7 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ ## :exclamation: Attention - this is documentation for beta `3.0.0` :exclamation: -This branch contains `eslint-plugin-vue@beta` which is pre-released `3.0.0`, but it's not an official version that you get by `npm install eslint-plugin-vue`. In order to install this you need to specify either `3.0.1` in `package.json` or do `npm install eslint-plugin-vue@beta`. +This branch contains `eslint-plugin-vue@beta` which is pre-released `3.0`, but it's not the default version that you get with `npm install eslint-plugin-vue`. In order to install this you need to specify either `"eslint-plugin-vue": "beta"` in `package.json` or do `npm install eslint-plugin-vue@beta`. Please try it and report any issues that you might experience. From 1dc567b5c8fdbd8b15b275f88a71ebeac4943e9f Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Sat, 17 Jun 2017 00:57:53 +0200 Subject: [PATCH 0006/1448] Add sync modifier to v-bind (#28) --- lib/rules/no-invalid-v-bind.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/no-invalid-v-bind.js b/lib/rules/no-invalid-v-bind.js index a8ae24a61..6563df56b 100644 --- a/lib/rules/no-invalid-v-bind.js +++ b/lib/rules/no-invalid-v-bind.js @@ -15,7 +15,7 @@ const utils = require('../utils') // Helpers // ------------------------------------------------------------------------------ -const VALID_MODIFIERS = new Set(['prop', 'camel']) +const VALID_MODIFIERS = new Set(['prop', 'camel', 'sync']) /** * Creates AST event handlers for no-invalid-v-bind. From bfb4015eedc05a2e37b7dadec6f43387dfbf3057 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Sat, 17 Jun 2017 01:00:48 +0200 Subject: [PATCH 0007/1448] 3.1.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 968de1392..0a9138d4f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "3.0.1", + "version": "3.1.0", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "scripts": { From 6b69437bdbdb15168e9967bc75b540dd5010ff64 Mon Sep 17 00:00:00 2001 From: Gabriel Oliveira Date: Sat, 17 Jun 2017 16:06:41 -0300 Subject: [PATCH 0008/1448] Fix should typo (#33) --- lib/rules/html-no-self-closing.js | 2 +- tests/lib/rules/html-no-self-closing.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/rules/html-no-self-closing.js b/lib/rules/html-no-self-closing.js index 19848cb95..0a9a3678c 100644 --- a/lib/rules/html-no-self-closing.js +++ b/lib/rules/html-no-self-closing.js @@ -29,7 +29,7 @@ function create (context) { context.report({ node, loc: node.loc, - message: 'Self-closing shuld not be used.', + message: 'Self-closing should not be used.', fix: (fixer) => fixer.removeRange([pos, pos + 1]) }) } diff --git a/tests/lib/rules/html-no-self-closing.js b/tests/lib/rules/html-no-self-closing.js index 3f298fb46..26f8edb84 100644 --- a/tests/lib/rules/html-no-self-closing.js +++ b/tests/lib/rules/html-no-self-closing.js @@ -45,19 +45,19 @@ tester.run('html-no-self-closing', rule, { filename: 'test.vue', code: '', output: '', - errors: ['Self-closing shuld not be used.'] + errors: ['Self-closing should not be used.'] }, { filename: 'test.vue', code: '', output: '', - errors: ['Self-closing shuld not be used.'] + errors: ['Self-closing should not be used.'] }, { filename: 'test.vue', code: '', output: '', - errors: ['Self-closing shuld not be used.'] + errors: ['Self-closing should not be used.'] } ] }) From e8e67cc5eede0e674571552b559c5138e9642363 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Sun, 18 Jun 2017 18:01:30 +0900 Subject: [PATCH 0009/1448] Fix: more robust parser setting (fixes #30) (#32) --- lib/config/base.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/config/base.js b/lib/config/base.js index 5b3797d58..d7bc8d7d8 100644 --- a/lib/config/base.js +++ b/lib/config/base.js @@ -1,7 +1,7 @@ module.exports = { root: true, - parser: 'vue-eslint-parser', + parser: require.resolve('vue-eslint-parser'), parserOptions: { ecmaVersion: 6, From 22aeca5c3ad2a5f5775b7a6134b56236de00b217 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Mon, 19 Jun 2017 06:41:18 +0900 Subject: [PATCH 0010/1448] Fix: upgrade vue-eslint-parser (#34) * Fix: upgrade vue-eslint-parser - Make correct ASTs about self-closing elements (fixes #29) - Improve the integration with eslint-plugin-import (refs #21) * add comments to integration test --- .gitignore | 1 + .vscode/settings.json | 3 ++ package-lock.json | 4 +- package.json | 4 +- tests/.eslintrc.json | 5 +++ tests/integrations/eslint-plugin-import.js | 39 +++++++++++++++++++ .../eslint-plugin-import/.eslintrc.json | 22 +++++++++++ tests/integrations/eslint-plugin-import/a.vue | 10 +++++ tests/integrations/eslint-plugin-import/b.vue | 7 ++++ .../eslint-plugin-import/package.json | 15 +++++++ tests/lib/rules/no-invalid-template-root.js | 4 ++ tests/lib/rules/no-invalid-v-else-if.js | 4 ++ tests/lib/rules/no-invalid-v-else.js | 4 ++ 13 files changed, 119 insertions(+), 3 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 tests/.eslintrc.json create mode 100644 tests/integrations/eslint-plugin-import.js create mode 100644 tests/integrations/eslint-plugin-import/.eslintrc.json create mode 100644 tests/integrations/eslint-plugin-import/a.vue create mode 100644 tests/integrations/eslint-plugin-import/b.vue create mode 100644 tests/integrations/eslint-plugin-import/package.json diff --git a/.gitignore b/.gitignore index 0f23426ce..f5ee9df9b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /.nyc_output /coverage +/tests/integrations/*/node_modules /node_modules /test.* diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..ce072c82c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "editor.tabSize": 2 +} diff --git a/package-lock.json b/package-lock.json index 9bbf5b436..89fa33c39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1974,7 +1974,9 @@ "dev": true }, "vue-eslint-parser": { - "version": "github:mysticatea/vue-eslint-parser#1250373ccff349c7617abc1feee6608ca251cd32" + "version": "1.1.0-6", + "resolved": "https://registry.npmjs.org/vue-eslint-parser/-/vue-eslint-parser-1.1.0-6.tgz", + "integrity": "sha512-HKaWwqfPOUSR3lMX1/2fQkgNoVnmhQtHyeGzE3kyf1j6BgAw4fzaHeoNLPLCLvq7c/SoxY2VXRxFCxq+1mB3JQ==" }, "wordwrap": { "version": "1.0.0", diff --git a/package.json b/package.json index 0a9138d4f..24b8bf3f0 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "main": "lib/index.js", "scripts": { "start": "npm run test:simple -- --watch --growl", - "test:base": "mocha tests --recursive", + "test:base": "mocha \"tests/lib/**/*.js\" \"tests/integrations/*.js\" --timeout 60000", "test:simple": "npm run test:base -- --reporter nyan", "test": "nyc npm run test:base", "lint": "eslint .", @@ -45,7 +45,7 @@ }, "dependencies": { "requireindex": "^1.1.0", - "vue-eslint-parser": "mysticatea/vue-eslint-parser#v1.1.0-4" + "vue-eslint-parser": "^1.1.0-6" }, "devDependencies": { "@types/node": "^4.2.6", diff --git a/tests/.eslintrc.json b/tests/.eslintrc.json new file mode 100644 index 000000000..4668ae79f --- /dev/null +++ b/tests/.eslintrc.json @@ -0,0 +1,5 @@ +{ + "env": { + "mocha": true + } +} diff --git a/tests/integrations/eslint-plugin-import.js b/tests/integrations/eslint-plugin-import.js new file mode 100644 index 000000000..e1908a636 --- /dev/null +++ b/tests/integrations/eslint-plugin-import.js @@ -0,0 +1,39 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ----------------------------------------------------------------------------- +// Requirements +// ----------------------------------------------------------------------------- + +const cp = require('child_process') +const path = require('path') + +// ----------------------------------------------------------------------------- +// Tests +// ----------------------------------------------------------------------------- + +const ESLINT = `.${path.sep}node_modules${path.sep}.bin${path.sep}eslint` + +describe('Integration with eslint-plugin-import', () => { + let originalCwd + + before(() => { + originalCwd = process.cwd() + process.chdir(path.join(__dirname, 'eslint-plugin-import')) + cp.execSync('npm i', { stdio: 'inherit', env: { npm_config_package_lock: 'false' }}) + }) + after(() => { + process.chdir(originalCwd) + }) + + // https://github.com/vuejs/eslint-plugin-vue/issues/21#issuecomment-308957697 + // eslint-plugin-vue had been breaking eslint-plugin-import if people use both at the same time. + // This test is in order to prevent the regression. + it('should lint without errors', () => { + cp.execSync(`${ESLINT} a.vue`, { stdio: 'inherit' }) + }) +}) diff --git a/tests/integrations/eslint-plugin-import/.eslintrc.json b/tests/integrations/eslint-plugin-import/.eslintrc.json new file mode 100644 index 000000000..bd240b24b --- /dev/null +++ b/tests/integrations/eslint-plugin-import/.eslintrc.json @@ -0,0 +1,22 @@ +{ + "root": true, + "parserOptions": { + "sourceType": "module", + "ecmaVersion": 2015 + }, + "parser": "vue-eslint-parser", + "plugins": [ + "import", + "vue" + ], + "rules": { + "import/default": "warn", + "import/namespace": "warn" + }, + "settings": { + "import/extensions": [ + ".js", + ".vue" + ] + } +} diff --git a/tests/integrations/eslint-plugin-import/a.vue b/tests/integrations/eslint-plugin-import/a.vue new file mode 100644 index 000000000..ce4b66e14 --- /dev/null +++ b/tests/integrations/eslint-plugin-import/a.vue @@ -0,0 +1,10 @@ + + + diff --git a/tests/integrations/eslint-plugin-import/b.vue b/tests/integrations/eslint-plugin-import/b.vue new file mode 100644 index 000000000..488aa4466 --- /dev/null +++ b/tests/integrations/eslint-plugin-import/b.vue @@ -0,0 +1,7 @@ + + + diff --git a/tests/integrations/eslint-plugin-import/package.json b/tests/integrations/eslint-plugin-import/package.json new file mode 100644 index 000000000..957cd9081 --- /dev/null +++ b/tests/integrations/eslint-plugin-import/package.json @@ -0,0 +1,15 @@ +{ + "private": true, + "name": "integration-test-for-eslint-plugin-import", + "version": "1.0.0", + "description": "Integration test for eslint-plugin-import", + "scripts": {}, + "keywords": [], + "author": "Toru Nagashima (https://github.com/mysticatea)", + "license": "MIT", + "dependencies": { + "eslint": "~3.19.0", + "eslint-plugin-import": "~2.3.0", + "eslint-plugin-vue": "file:../../.." + } +} diff --git a/tests/lib/rules/no-invalid-template-root.js b/tests/lib/rules/no-invalid-template-root.js index 6b7dbfd76..89a38c7b8 100644 --- a/tests/lib/rules/no-invalid-template-root.js +++ b/tests/lib/rules/no-invalid-template-root.js @@ -46,6 +46,10 @@ tester.run('no-invalid-template-root', rule, { { filename: 'test.vue', code: '' + }, + { + filename: 'test.vue', + code: `` } ], invalid: [ diff --git a/tests/lib/rules/no-invalid-v-else-if.js b/tests/lib/rules/no-invalid-v-else-if.js index 165fd3908..3763a8dcc 100644 --- a/tests/lib/rules/no-invalid-v-else-if.js +++ b/tests/lib/rules/no-invalid-v-else-if.js @@ -34,6 +34,10 @@ tester.run('no-invalid-v-else-if', rule, { { filename: 'test.vue', code: '' + }, + { + filename: 'test.vue', + code: `` } ], invalid: [ diff --git a/tests/lib/rules/no-invalid-v-else.js b/tests/lib/rules/no-invalid-v-else.js index b49667dce..30a2dc2b6 100644 --- a/tests/lib/rules/no-invalid-v-else.js +++ b/tests/lib/rules/no-invalid-v-else.js @@ -34,6 +34,10 @@ tester.run('no-invalid-v-else', rule, { { filename: 'test.vue', code: '' + }, + { + filename: 'test.vue', + code: `` } ], invalid: [ From 47532e2e07169e7c0b9237f40fd2db37b5473ef5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Mon, 19 Jun 2017 11:38:40 +0200 Subject: [PATCH 0011/1448] 3.1.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 24b8bf3f0..37602fdda 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "3.1.0", + "version": "3.1.1", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "scripts": { From 8da7f030d55d95fae61ada6f02a3cfb3d71c77a3 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Wed, 21 Jun 2017 00:26:36 +0900 Subject: [PATCH 0012/1448] Fix: crash `no-v-invalid-v-for` on `:key` (fixes #37) (#39) --- lib/rules/no-invalid-v-for.js | 3 +++ tests/lib/rules/no-invalid-v-for.js | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/lib/rules/no-invalid-v-for.js b/lib/rules/no-invalid-v-for.js index b9852b576..9b19599a3 100644 --- a/lib/rules/no-invalid-v-for.js +++ b/lib/rules/no-invalid-v-for.js @@ -21,6 +21,9 @@ const utils = require('../utils') * @returns {boolean} `true` if the node is using the variables which are defined by `v-for` directives. */ function isUsingIterationVar (node) { + if (node.value == null) { + return false + } const references = node.value.references const variables = node.parent.parent.variables diff --git a/tests/lib/rules/no-invalid-v-for.js b/tests/lib/rules/no-invalid-v-for.js index 861197737..f465b567c 100644 --- a/tests/lib/rules/no-invalid-v-for.js +++ b/tests/lib/rules/no-invalid-v-for.js @@ -144,6 +144,11 @@ tester.run('no-invalid-v-for', rule, { filename: 'test.vue', code: '', errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] + }, + { + filename: 'test.vue', + code: '', + errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] } ] }) From 92583d2d2719c881fdaa30b1a9c997903664976d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Tue, 20 Jun 2017 17:27:20 +0200 Subject: [PATCH 0013/1448] 3.1.2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 37602fdda..d58481b77 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "3.1.1", + "version": "3.1.2", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "scripts": { From 547e82418f8860a3a3707a480dafe196c0b23238 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Wed, 21 Jun 2017 00:31:44 +0900 Subject: [PATCH 0014/1448] Chore: add issue template (#38) * Chore: add issue template * Use vue template --- .github/ISSUE_TEMPLATE.md | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE.md diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..9a3407f13 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,39 @@ + + +**Tell us about your environment** + +* **ESLint Version:** +* **eslint-plugin-vue Version:** +* **Node Version:** + +**Please show your full configuration:** + + +``` + + + + +``` + +**What did you do? Please include the actual source code causing the issue.** + + +```vue + + + + + +``` + +**What did you expect to happen?** + +**What actually happened? Please include the actual, raw output from ESLint.** From b71c7a3ea1da6116136275c703e52f69963bfbcf Mon Sep 17 00:00:00 2001 From: Gabriel Oliveira Date: Tue, 20 Jun 2017 18:00:23 -0300 Subject: [PATCH 0015/1448] Changing console.assert to node assert (#40) --- lib/utils/index.js | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/utils/index.js b/lib/utils/index.js index aa411b94c..cd01df744 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -12,6 +12,7 @@ const HTML_ELEMENT_NAMES = new Set(require('./html-elements.json')) const SVG_ELEMENT_NAMES = new Set(require('./svg-elements.json')) const VOID_ELEMENT_NAMES = new Set(require('./void-elements.json')) +const assert = require('assert') // ------------------------------------------------------------------------------ // Exports @@ -63,7 +64,7 @@ module.exports = { * @returns {boolean} `true` if the node is the root element. */ isRootElement (node) { - console.assert(node && node.type === 'VElement') + assert(node && node.type === 'VElement') return ( node.parent.type === 'Program' || @@ -77,7 +78,7 @@ module.exports = { * @returns {ASTNode|null} The previous sibling element. */ prevSibling (node) { - console.assert(node && node.type === 'VElement') + assert(node && node.type === 'VElement') let prevElement = null for (const siblingNode of (node.parent && node.parent.children) || []) { @@ -100,7 +101,7 @@ module.exports = { * @returns {boolean} `true` if the start tag has the directive. */ hasAttribute (node, name, value) { - console.assert(node && node.type === 'VStartTag') + assert(node && node.type === 'VStartTag') return node.attributes.some(a => !a.directive && a.key.name === name && @@ -119,7 +120,7 @@ module.exports = { * @returns {boolean} `true` if the start tag has the directive. */ hasDirective (node, name, argument) { - console.assert(node && node.type === 'VStartTag') + assert(node && node.type === 'VStartTag') return node.attributes.some(a => a.directive && a.key.name === name && @@ -133,7 +134,7 @@ module.exports = { * @returns {boolean} `true` if the attribute has their value. */ hasAttributeValue (node) { - console.assert(node && node.type === 'VAttribute') + assert(node && node.type === 'VAttribute') return ( node.value != null && (node.value.expression != null || node.value.syntaxError != null) @@ -148,7 +149,7 @@ module.exports = { * @returns {ASTNode} The found attribute. */ getAttribute (node, name, value) { - console.assert(node && node.type === 'VStartTag') + assert(node && node.type === 'VStartTag') return node.attributes.find(a => !a.directive && a.key.name === name && @@ -167,7 +168,7 @@ module.exports = { * @returns {ASTNode} The found directive. */ getDirective (node, name, argument) { - console.assert(node && node.type === 'VStartTag') + assert(node && node.type === 'VStartTag') return node.attributes.find(a => a.directive && a.key.name === name && @@ -181,7 +182,7 @@ module.exports = { * @returns {boolean} `true` if the previous sibling element has `if` or `else-if` directive. */ prevElementHasIf (node) { - console.assert(node && node.type === 'VElement') + assert(node && node.type === 'VElement') const prev = this.prevSibling(node) return ( @@ -199,7 +200,7 @@ module.exports = { * @returns {boolean} `true` if the node is a custom component. */ isCustomComponent (node) { - console.assert(node && node.type === 'VStartTag') + assert(node && node.type === 'VStartTag') const name = node.id.name return ( @@ -215,7 +216,7 @@ module.exports = { * @returns {boolean} `true` if the name is a HTML element name. */ isHtmlElementName (name) { - console.assert(typeof name === 'string') + assert(typeof name === 'string') return HTML_ELEMENT_NAMES.has(name.toLowerCase()) }, @@ -226,7 +227,7 @@ module.exports = { * @returns {boolean} `true` if the name is a SVG element name. */ isSvgElementName (name) { - console.assert(typeof name === 'string') + assert(typeof name === 'string') return SVG_ELEMENT_NAMES.has(name.toLowerCase()) }, @@ -237,7 +238,7 @@ module.exports = { * @returns {boolean} `true` if the name is a void element name. */ isVoidElementName (name) { - console.assert(typeof name === 'string') + assert(typeof name === 'string') return VOID_ELEMENT_NAMES.has(name.toLowerCase()) } From a800d96205bfc380ccfefcff5abb83c2df826855 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Tue, 20 Jun 2017 23:16:48 +0200 Subject: [PATCH 0016/1448] 3.1.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index d58481b77..745c6c776 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "3.1.2", + "version": "3.1.3", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "scripts": { From 9fff64d1119f4df4ddf867b0a3a0fe92e7bb8d97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Mon, 26 Jun 2017 23:00:21 +0200 Subject: [PATCH 0017/1448] New rule `order-in-components` (#42) * Add new rule "order-in-components" * Add initial implementation of `order-in-components` rule * Update test scripts * Improve order-in-components rule, add more test scenarios * Update readme * Update order-in-components docs * Update rule logic and fix tests * Fix order logic * Check for arguments existance * Apply order-in-components rule only to exported ObjectExpressions in .vue and .jsx files * Disable recommended setting in `order-in-components` rule --- README.md | 1 + docs/rules/order-in-components.md | 87 ++++++++ lib/recommended-rules.js | 1 + lib/rules/order-in-components.js | 148 +++++++++++++ package-lock.json | 2 +- package.json | 4 +- tests/lib/rules/order-in-components.js | 278 +++++++++++++++++++++++++ 7 files changed, 518 insertions(+), 3 deletions(-) create mode 100644 docs/rules/order-in-components.md create mode 100644 lib/rules/order-in-components.js create mode 100644 tests/lib/rules/order-in-components.js diff --git a/README.md b/README.md index bd50cf3e7..f9fb1eae9 100644 --- a/README.md +++ b/README.md @@ -69,6 +69,7 @@ The `--fix` option on the command line automatically fixes problems reported by | :white_check_mark: | [no-confusing-v-for-v-if](./docs/rules/no-confusing-v-for-v-if.md) | disallow confusing `v-for` and `v-if` on the same element. | | | [no-duplicate-attributes](./docs/rules/no-duplicate-attributes.md) | disallow duplicate arguments. | | :white_check_mark: | [no-textarea-mustache](./docs/rules/no-textarea-mustache.md) | disallow mustaches in ` + +
+ +
+ + +``` + +## :wrench: Options + +Nothing. + +## :couple: Related rules + +- [no-parsing-error] + + +[no-parsing-error]: no-parsing-error.md diff --git a/docs/rules/valid-v-on.md b/docs/rules/valid-v-on.md new file mode 100644 index 000000000..e88a4d675 --- /dev/null +++ b/docs/rules/valid-v-on.md @@ -0,0 +1,50 @@ +# Enforce valid `v-on` directives (valid-v-on) + +This rule checks whether every `v-on` directive is valid. + +## :book: Rule Details + +This rule reports `v-on` directives in the following cases: + +- The directive does not have that event name. E.g. `
` +- The directive has invalid modifiers. E.g. `
` +- The directive does not have that attribute value and any verb modifiers. E.g. `
` + +This rule does not check syntax errors in directives because it's checked by [no-parsing-error] rule. + +:-1: Examples of **incorrect** code for this rule: + +```html + +``` + +:+1: Examples of **correct** code for this rule: + +```html + +``` + +## :wrench: Options + +Nothing. + +## :couple: Related rules + +- [no-parsing-error] + + +[no-parsing-error]: no-parsing-error.md diff --git a/docs/rules/valid-v-once.md b/docs/rules/valid-v-once.md new file mode 100644 index 000000000..0f367555d --- /dev/null +++ b/docs/rules/valid-v-once.md @@ -0,0 +1,37 @@ +# Enforce valid `v-once` directives (valid-v-once) + +This rule checks whether every `v-once` directive is valid. + +## :book: Rule Details + +This rule reports `v-once` directives in the following cases: + +- The directive has that argument. E.g. `
` +- The directive has that modifier. E.g. `
` +- The directive has that attribute value. E.g. `
` + +:-1: Examples of **incorrect** code for this rule: + +```html + +``` + +:+1: Examples of **correct** code for this rule: + +```html + +``` + +## :wrench: Options + +Nothing. diff --git a/docs/rules/valid-v-pre.md b/docs/rules/valid-v-pre.md new file mode 100644 index 000000000..7dba0ebc5 --- /dev/null +++ b/docs/rules/valid-v-pre.md @@ -0,0 +1,37 @@ +# Enforce valid `v-pre` directives (valid-v-pre) + +This rule checks whether every `v-pre` directive is valid. + +## :book: Rule Details + +This rule reports `v-pre` directives in the following cases: + +- The directive has that argument. E.g. `
` +- The directive has that modifier. E.g. `
` +- The directive has that attribute value. E.g. `
` + +:-1: Examples of **incorrect** code for this rule: + +```html + +``` + +:+1: Examples of **correct** code for this rule: + +```html + +``` + +## :wrench: Options + +Nothing. diff --git a/docs/rules/valid-v-show.md b/docs/rules/valid-v-show.md new file mode 100644 index 000000000..1e2175993 --- /dev/null +++ b/docs/rules/valid-v-show.md @@ -0,0 +1,46 @@ +# Enforce valid `v-show` directives (valid-v-show) + +This rule checks whether every `v-show` directive is valid. + +## :book: Rule Details + +This rule reports `v-show` directives in the following cases: + +- The directive has that argument. E.g. `
` +- The directive has that modifier. E.g. `
` +- The directive does not have that attribute value. E.g. `
` + +This rule does not check syntax errors in directives because it's checked by [no-parsing-error] rule. + +:-1: Examples of **incorrect** code for this rule: + +```html + +``` + +:+1: Examples of **correct** code for this rule: + +```html + +``` + +## :wrench: Options + +Nothing. + +## :couple: Related rules + +- [no-parsing-error] + + +[no-parsing-error]: no-parsing-error.md diff --git a/docs/rules/valid-v-text.md b/docs/rules/valid-v-text.md new file mode 100644 index 000000000..c808e6413 --- /dev/null +++ b/docs/rules/valid-v-text.md @@ -0,0 +1,46 @@ +# Enforce valid `v-text` directives (valid-v-text) + +This rule checks whether every `v-text` directive is valid. + +## :book: Rule Details + +This rule reports `v-text` directives in the following cases: + +- The directive has that argument. E.g. `
` +- The directive has that modifier. E.g. `
` +- The directive does not have that attribute value. E.g. `
` + +This rule does not check syntax errors in directives because it's checked by [no-parsing-error] rule. + +:-1: Examples of **incorrect** code for this rule: + +```html + +``` + +:+1: Examples of **correct** code for this rule: + +```html + +``` + +## :wrench: Options + +Nothing. + +## :couple: Related rules + +- [no-parsing-error] + + +[no-parsing-error]: no-parsing-error.md diff --git a/lib/recommended-rules.js b/lib/recommended-rules.js index c4eab5baf..fe3d3e174 100644 --- a/lib/recommended-rules.js +++ b/lib/recommended-rules.js @@ -14,20 +14,20 @@ module.exports = { "vue/no-confusing-v-for-v-if": "error", "vue/no-dupe-keys": "off", "vue/no-duplicate-attributes": "off", - "vue/no-invalid-template-root": "error", - "vue/no-invalid-v-bind": "error", - "vue/no-invalid-v-cloak": "error", - "vue/no-invalid-v-else-if": "error", - "vue/no-invalid-v-else": "error", - "vue/no-invalid-v-for": "error", - "vue/no-invalid-v-html": "error", - "vue/no-invalid-v-if": "error", - "vue/no-invalid-v-model": "error", - "vue/no-invalid-v-on": "error", - "vue/no-invalid-v-once": "error", - "vue/no-invalid-v-pre": "error", - "vue/no-invalid-v-show": "error", - "vue/no-invalid-v-text": "error", + "vue/no-invalid-template-root": "off", + "vue/no-invalid-v-bind": "off", + "vue/no-invalid-v-cloak": "off", + "vue/no-invalid-v-else-if": "off", + "vue/no-invalid-v-else": "off", + "vue/no-invalid-v-for": "off", + "vue/no-invalid-v-html": "off", + "vue/no-invalid-v-if": "off", + "vue/no-invalid-v-model": "off", + "vue/no-invalid-v-on": "off", + "vue/no-invalid-v-once": "off", + "vue/no-invalid-v-pre": "off", + "vue/no-invalid-v-show": "off", + "vue/no-invalid-v-text": "off", "vue/no-parsing-error": "error", "vue/no-reservered-keys": "off", "vue/no-shared-component-data": "off", @@ -39,7 +39,22 @@ module.exports = { "vue/require-prop-types": "off", "vue/require-render-return": "off", "vue/require-v-for-key": "error", + "vue/require-valid-default-prop": "off", "vue/return-in-computed-property": "off", "vue/v-bind-style": "off", - "vue/v-on-style": "off" + "vue/v-on-style": "off", + "vue/valid-template-root": "error", + "vue/valid-v-bind": "error", + "vue/valid-v-cloak": "error", + "vue/valid-v-else-if": "error", + "vue/valid-v-else": "error", + "vue/valid-v-for": "error", + "vue/valid-v-html": "error", + "vue/valid-v-if": "error", + "vue/valid-v-model": "error", + "vue/valid-v-on": "error", + "vue/valid-v-once": "error", + "vue/valid-v-pre": "error", + "vue/valid-v-show": "error", + "vue/valid-v-text": "error" } \ No newline at end of file diff --git a/lib/rules/no-invalid-template-root.js b/lib/rules/no-invalid-template-root.js index 78d55ecef..887ebd2ca 100644 --- a/lib/rules/no-invalid-template-root.js +++ b/lib/rules/no-invalid-template-root.js @@ -114,8 +114,10 @@ module.exports = { docs: { description: 'disallow invalid template root.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-template-root'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-bind.js b/lib/rules/no-invalid-v-bind.js index cd9ddc600..081452e92 100644 --- a/lib/rules/no-invalid-v-bind.js +++ b/lib/rules/no-invalid-v-bind.js @@ -60,8 +60,10 @@ module.exports = { docs: { description: 'disallow invalid `v-bind` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-bind'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-cloak.js b/lib/rules/no-invalid-v-cloak.js index 55757d122..d292d9f78 100644 --- a/lib/rules/no-invalid-v-cloak.js +++ b/lib/rules/no-invalid-v-cloak.js @@ -61,8 +61,10 @@ module.exports = { docs: { description: 'disallow invalid `v-cloak` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-cloak'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-else-if.js b/lib/rules/no-invalid-v-else-if.js index e9f007458..21ec073da 100644 --- a/lib/rules/no-invalid-v-else-if.js +++ b/lib/rules/no-invalid-v-else-if.js @@ -84,8 +84,10 @@ module.exports = { docs: { description: 'disallow invalid `v-else-if` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-else-if'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-else.js b/lib/rules/no-invalid-v-else.js index 58eb6e763..1455bed0e 100644 --- a/lib/rules/no-invalid-v-else.js +++ b/lib/rules/no-invalid-v-else.js @@ -84,8 +84,10 @@ module.exports = { docs: { description: 'disallow invalid `v-else` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-else'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-for.js b/lib/rules/no-invalid-v-for.js index aced1b81d..1cb022f94 100644 --- a/lib/rules/no-invalid-v-for.js +++ b/lib/rules/no-invalid-v-for.js @@ -165,8 +165,10 @@ module.exports = { docs: { description: 'disallow invalid `v-for` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-for'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-html.js b/lib/rules/no-invalid-v-html.js index 8d179da0a..b0606b574 100644 --- a/lib/rules/no-invalid-v-html.js +++ b/lib/rules/no-invalid-v-html.js @@ -61,8 +61,10 @@ module.exports = { docs: { description: 'disallow invalid `v-html` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-html'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-if.js b/lib/rules/no-invalid-v-if.js index e77b15c46..89a5a6ade 100644 --- a/lib/rules/no-invalid-v-if.js +++ b/lib/rules/no-invalid-v-if.js @@ -77,8 +77,10 @@ module.exports = { docs: { description: 'disallow invalid `v-if` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-if'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-model.js b/lib/rules/no-invalid-v-model.js index 59deadf5b..cd75bf10f 100644 --- a/lib/rules/no-invalid-v-model.js +++ b/lib/rules/no-invalid-v-model.js @@ -178,8 +178,10 @@ module.exports = { docs: { description: 'disallow invalid `v-model` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-model'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-on.js b/lib/rules/no-invalid-v-on.js index 142d849aa..ef54544f3 100644 --- a/lib/rules/no-invalid-v-on.js +++ b/lib/rules/no-invalid-v-on.js @@ -66,8 +66,10 @@ module.exports = { docs: { description: 'disallow invalid `v-on` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-on'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-once.js b/lib/rules/no-invalid-v-once.js index 36f73afb7..f8c67b8b1 100644 --- a/lib/rules/no-invalid-v-once.js +++ b/lib/rules/no-invalid-v-once.js @@ -61,8 +61,10 @@ module.exports = { docs: { description: 'disallow invalid `v-once` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-once'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-pre.js b/lib/rules/no-invalid-v-pre.js index 07f2e401b..76e640250 100644 --- a/lib/rules/no-invalid-v-pre.js +++ b/lib/rules/no-invalid-v-pre.js @@ -61,8 +61,10 @@ module.exports = { docs: { description: 'disallow invalid `v-pre` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-pre'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-show.js b/lib/rules/no-invalid-v-show.js index f2812f167..e7ea46d04 100644 --- a/lib/rules/no-invalid-v-show.js +++ b/lib/rules/no-invalid-v-show.js @@ -61,8 +61,10 @@ module.exports = { docs: { description: 'disallow invalid `v-show` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-show'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/no-invalid-v-text.js b/lib/rules/no-invalid-v-text.js index 6284f90a2..7ebda73e0 100644 --- a/lib/rules/no-invalid-v-text.js +++ b/lib/rules/no-invalid-v-text.js @@ -61,8 +61,10 @@ module.exports = { docs: { description: 'disallow invalid `v-text` directives.', category: 'Possible Errors', - recommended: true + recommended: false, + replacedBy: ['valid-v-text'] }, + deprecated: true, fixable: false, schema: [] } diff --git a/lib/rules/valid-template-root.js b/lib/rules/valid-template-root.js new file mode 100644 index 000000000..2f511d31e --- /dev/null +++ b/lib/rules/valid-template-root.js @@ -0,0 +1,122 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-template-root. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + const sourceCode = context.getSourceCode() + + return { + Program (program) { + const element = program.templateBody + if (element == null) { + return + } + + const hasSrc = utils.hasAttribute(element, 'src') + const rootElements = [] + let extraText = null + let extraElement = null + let vIf = false + for (const child of element.children) { + if (child.type === 'VElement') { + if (rootElements.length === 0 && !hasSrc) { + rootElements.push(child) + vIf = utils.hasDirective(child, 'if') + } else if (vIf && utils.hasDirective(child, 'else-if')) { + rootElements.push(child) + } else if (vIf && utils.hasDirective(child, 'else')) { + rootElements.push(child) + vIf = false + } else { + extraElement = child + } + } else if (sourceCode.getText(child).trim() !== '') { + extraText = child + } + } + + if (hasSrc && (extraText != null || extraElement != null)) { + context.report({ + node: extraText || extraElement, + loc: (extraText || extraElement).loc, + message: "The template root with 'src' attribute is required to be empty." + }) + } else if (extraText != null) { + context.report({ + node: extraText, + loc: extraText.loc, + message: 'The template root requires an element rather than texts.' + }) + } else if (extraElement != null) { + context.report({ + node: extraElement, + loc: extraElement.loc, + message: 'The template root requires exactly one element.' + }) + } else if (rootElements.length === 0 && !hasSrc) { + context.report({ + node: element, + loc: element.loc, + message: 'The template root requires exactly one element.' + }) + } else { + for (const element of rootElements) { + const tag = element.startTag + const name = element.name + + if (name === 'template' || name === 'slot') { + context.report({ + node: tag, + loc: tag.loc, + message: "The template root disallows '<{{name}}>' elements.", + data: { name } + }) + } + if (utils.hasDirective(element, 'for')) { + context.report({ + node: tag, + loc: tag.loc, + message: "The template root disallows 'v-for' directives." + }) + } + } + } + } + } +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid template root.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-bind.js b/lib/rules/valid-v-bind.js new file mode 100644 index 000000000..699bedaaf --- /dev/null +++ b/lib/rules/valid-v-bind.js @@ -0,0 +1,68 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +const VALID_MODIFIERS = new Set(['prop', 'camel', 'sync']) + +/** + * Creates AST event handlers for valid-v-bind. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='bind']" (node) { + for (const modifier of node.key.modifiers) { + if (!VALID_MODIFIERS.has(modifier)) { + context.report({ + node, + loc: node.key.loc, + message: "'v-bind' directives don't support the modifier '{{name}}'.", + data: { name: modifier } + }) + } + } + + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-bind' directives require an attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-bind` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-cloak.js b/lib/rules/valid-v-cloak.js new file mode 100644 index 000000000..b567f3a44 --- /dev/null +++ b/lib/rules/valid-v-cloak.js @@ -0,0 +1,69 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-cloak. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='cloak']" (node) { + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-cloak' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-cloak' directives require no modifier." + }) + } + if (node.value) { + context.report({ + node, + loc: node.loc, + message: "'v-cloak' directives require no attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-cloak` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-else-if.js b/lib/rules/valid-v-else-if.js new file mode 100644 index 000000000..1889728a4 --- /dev/null +++ b/lib/rules/valid-v-else-if.js @@ -0,0 +1,92 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-else-if. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='else-if']" (node) { + const element = node.parent.parent + + if (!utils.prevElementHasIf(element)) { + context.report({ + node, + loc: node.loc, + message: "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + }) + } + if (utils.hasDirective(element, 'if')) { + context.report({ + node, + loc: node.loc, + message: "'v-else-if' and 'v-if' directives can't exist on the same element." + }) + } + if (utils.hasDirective(element, 'else')) { + context.report({ + node, + loc: node.loc, + message: "'v-else-if' and 'v-else' directives can't exist on the same element." + }) + } + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-else-if' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-else-if' directives require no modifier." + }) + } + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-else-if' directives require that attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-else-if` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-else.js b/lib/rules/valid-v-else.js new file mode 100644 index 000000000..a5d80d53d --- /dev/null +++ b/lib/rules/valid-v-else.js @@ -0,0 +1,92 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-else. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='else']" (node) { + const element = node.parent.parent + + if (!utils.prevElementHasIf(element)) { + context.report({ + node, + loc: node.loc, + message: "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else' directive." + }) + } + if (utils.hasDirective(element, 'if')) { + context.report({ + node, + loc: node.loc, + message: "'v-else' and 'v-if' directives can't exist on the same element. You may want 'v-else-if' directives." + }) + } + if (utils.hasDirective(element, 'else-if')) { + context.report({ + node, + loc: node.loc, + message: "'v-else' and 'v-else-if' directives can't exist on the same element." + }) + } + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-else' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-else' directives require no modifier." + }) + } + if (utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-else' directives require no attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-else` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-for.js b/lib/rules/valid-v-for.js new file mode 100644 index 000000000..47d8f5029 --- /dev/null +++ b/lib/rules/valid-v-for.js @@ -0,0 +1,173 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Check whether the given attribute is using the variables which are defined by `v-for` directives. + * @param {ASTNode} vFor The attribute node of `v-for` to check. + * @param {ASTNode} vBindKey The attribute node of `v-bind:key` to check. + * @returns {boolean} `true` if the node is using the variables which are defined by `v-for` directives. + */ +function isUsingIterationVar (vFor, vBindKey) { + if (vBindKey.value == null) { + return false + } + const references = vBindKey.value.references + const variables = vFor.parent.parent.variables + + return references.some(reference => + variables.some(variable => + variable.id.name === reference.id.name && + variable.kind === 'v-for' + ) + ) +} + +/** + * Check the given element about `v-bind:key` attributes. + * @param {RuleContext} context The rule context to report. + * @param {ASTNode} vFor The attribute node of `v-for` to check. + * @param {ASTNode} element The element node to check. + */ +function checkKey (context, vFor, element) { + if (element.name === 'template') { + for (const child of element.children) { + if (child.type === 'VElement') { + checkKey(context, vFor, child) + } + } + return + } + + const vBindKey = utils.getDirective(element, 'bind', 'key') + + if (utils.isCustomComponent(element) && vBindKey == null) { + context.report({ + node: element.startTag, + loc: element.startTag.loc, + message: "Custom elements in iteration require 'v-bind:key' directives." + }) + } + if (vBindKey != null && !isUsingIterationVar(vFor, vBindKey)) { + context.report({ + node: vBindKey, + loc: vBindKey.loc, + message: "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + }) + } +} + +/** + * Creates AST event handlers for valid-v-for. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + const sourceCode = context.getSourceCode() + + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='for']" (node) { + const element = node.parent.parent + + checkKey(context, node, element) + + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-for' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-for' directives require no modifier." + }) + } + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-for' directives require that attribute value." + }) + return + } + + const expr = node.value.expression + if (expr == null) { + return + } + if (expr.type !== 'VForExpression') { + context.report({ + node: node.value, + loc: node.value.loc, + message: "'v-for' directives require the special syntax ' in '." + }) + return + } + + const lhs = expr.left + const value = lhs[0] + const key = lhs[1] + const index = lhs[2] + + if (value === null) { + context.report({ + node: value || expr, + loc: value && value.loc, + message: "Invalid alias ''." + }) + } + if (key !== undefined && (!key || key.type !== 'Identifier')) { + context.report({ + node: key || expr, + loc: key && key.loc, + message: "Invalid alias '{{text}}'.", + data: { text: key ? sourceCode.getText(key) : '' } + }) + } + if (index !== undefined && (!index || index.type !== 'Identifier')) { + context.report({ + node: index || expr, + loc: index && index.loc, + message: "Invalid alias '{{text}}'.", + data: { text: index ? sourceCode.getText(index) : '' } + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-for` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-html.js b/lib/rules/valid-v-html.js new file mode 100644 index 000000000..fdb5f6657 --- /dev/null +++ b/lib/rules/valid-v-html.js @@ -0,0 +1,69 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-html. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='html']" (node) { + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-html' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-html' directives require no modifier." + }) + } + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-html' directives require that attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-html` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-if.js b/lib/rules/valid-v-if.js new file mode 100644 index 000000000..090026ff2 --- /dev/null +++ b/lib/rules/valid-v-if.js @@ -0,0 +1,85 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-if. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='if']" (node) { + const element = node.parent.parent + + if (utils.hasDirective(element, 'else')) { + context.report({ + node, + loc: node.loc, + message: "'v-if' and 'v-else' directives can't exist on the same element. You may want 'v-else-if' directives." + }) + } + if (utils.hasDirective(element, 'else-if')) { + context.report({ + node, + loc: node.loc, + message: "'v-if' and 'v-else-if' directives can't exist on the same element." + }) + } + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-if' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-if' directives require no modifier." + }) + } + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-if' directives require that attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-if` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-model.js b/lib/rules/valid-v-model.js new file mode 100644 index 000000000..406ac8734 --- /dev/null +++ b/lib/rules/valid-v-model.js @@ -0,0 +1,186 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +const VALID_MODIFIERS = new Set(['lazy', 'number', 'trim']) + +/** + * Check whether the given node is valid or not. + * @param {ASTNode} node The element node to check. + * @returns {boolean} `true` if the node is valid. + */ +function isValidElement (node) { + const name = node.name + return ( + name === 'input' || + name === 'select' || + name === 'textarea' || + ( + name !== 'keep-alive' && + name !== 'slot' && + name !== 'transition' && + name !== 'transition-group' && + utils.isCustomComponent(node) + ) + ) +} + +/** + * Check whether the given node can be LHS. + * @param {ASTNode} node The node to check. + * @returns {boolean} `true` if the node can be LHS. + */ +function isLhs (node) { + return node != null && ( + node.type === 'Identifier' || + node.type === 'MemberExpression' + ) +} + +/** + * Get the variable by names. + * @param {string} name The variable name to find. + * @param {ASTNode} leafNode The node to look up. + * @returns {Variable|null} The found variable or null. + */ +function getVariable (name, leafNode) { + let node = leafNode + + while (node != null) { + const variables = node.variables + const variable = variables && variables.find(v => v.id.name === name) + + if (variable != null) { + return variable + } + + node = node.parent + } + + return null +} + +/** + * Creates AST event handlers for valid-v-model. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='model']" (node) { + const element = node.parent.parent + const name = element.name + + if (!isValidElement(element)) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives aren't supported on <{{name}}> elements.", + data: { name } + }) + } + if (name === 'input') { + if (utils.hasDirective(element, 'bind', 'type')) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives don't support dynamic input types.", + data: { name } + }) + } + if (utils.hasAttribute(element, 'type', 'file')) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives don't support 'file' input type.", + data: { name } + }) + } + } + + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives require no argument." + }) + } + + for (const modifier of node.key.modifiers) { + if (!VALID_MODIFIERS.has(modifier)) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives don't support the modifier '{{name}}'.", + data: { name: modifier } + }) + } + } + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives require that attribute value." + }) + } + if (node.value) { + if (!isLhs(node.value.expression)) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives require the attribute value which is valid as LHS." + }) + } + + for (const reference of node.value.references) { + const id = reference.id + if (id.parent.type === 'MemberExpression') { + continue + } + + const variable = getVariable(id.name, element) + if (variable != null) { + context.report({ + node, + loc: node.loc, + message: "'v-model' directives cannot update the iteration variable 'x' itself." + }) + } + } + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-model` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-on.js b/lib/rules/valid-v-on.js new file mode 100644 index 000000000..d590ef95b --- /dev/null +++ b/lib/rules/valid-v-on.js @@ -0,0 +1,74 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +const VALID_MODIFIERS = new Set([ + 'stop', 'prevent', 'capture', 'self', 'ctrl', 'shift', 'alt', 'meta', + 'native', 'once', 'left', 'right', 'middle', 'passive', 'esc', 'tab', + 'enter', 'space', 'up', 'left', 'right', 'down', 'delete' +]) +const VERB_MODIFIERS = new Set([ + 'stop', 'prevent' +]) + +/** + * Creates AST event handlers for valid-v-on. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='on']" (node) { + for (const modifier of node.key.modifiers) { + if (!VALID_MODIFIERS.has(modifier) && !Number.isInteger(parseInt(modifier, 10))) { + context.report({ + node, + loc: node.loc, + message: "'v-on' directives don't support the modifier '{{modifier}}'.", + data: { modifier } + }) + } + } + if (!utils.hasAttributeValue(node) && !node.key.modifiers.some(VERB_MODIFIERS.has, VERB_MODIFIERS)) { + context.report({ + node, + loc: node.loc, + message: "'v-on' directives require that attribute value or verb modifiers." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-on` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-once.js b/lib/rules/valid-v-once.js new file mode 100644 index 000000000..eefc4a30b --- /dev/null +++ b/lib/rules/valid-v-once.js @@ -0,0 +1,69 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-once. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='once']" (node) { + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-once' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-once' directives require no modifier." + }) + } + if (node.value) { + context.report({ + node, + loc: node.loc, + message: "'v-once' directives require no attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-once` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-pre.js b/lib/rules/valid-v-pre.js new file mode 100644 index 000000000..e3e42d083 --- /dev/null +++ b/lib/rules/valid-v-pre.js @@ -0,0 +1,69 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-pre. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='pre']" (node) { + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-pre' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-pre' directives require no modifier." + }) + } + if (node.value) { + context.report({ + node, + loc: node.loc, + message: "'v-pre' directives require no attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-pre` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-show.js b/lib/rules/valid-v-show.js new file mode 100644 index 000000000..b724a9bd4 --- /dev/null +++ b/lib/rules/valid-v-show.js @@ -0,0 +1,69 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-show. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='show']" (node) { + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-show' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-show' directives require no modifier." + }) + } + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-show' directives require that attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-show` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/lib/rules/valid-v-text.js b/lib/rules/valid-v-text.js new file mode 100644 index 000000000..0fe20cbfd --- /dev/null +++ b/lib/rules/valid-v-text.js @@ -0,0 +1,69 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Creates AST event handlers for valid-v-text. + * + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ +function create (context) { + utils.registerTemplateBodyVisitor(context, { + "VAttribute[directive=true][key.name='text']" (node) { + if (node.key.argument) { + context.report({ + node, + loc: node.loc, + message: "'v-text' directives require no argument." + }) + } + if (node.key.modifiers.length > 0) { + context.report({ + node, + loc: node.loc, + message: "'v-text' directives require no modifier." + }) + } + if (!utils.hasAttributeValue(node)) { + context.report({ + node, + loc: node.loc, + message: "'v-text' directives require that attribute value." + }) + } + } + }) + + return {} +} + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + create, + meta: { + docs: { + description: 'enforce valid `v-text` directives.', + category: 'Possible Errors', + recommended: true + }, + fixable: false, + schema: [] + } +} diff --git a/tests/lib/rules/valid-template-root.js b/tests/lib/rules/valid-template-root.js new file mode 100644 index 000000000..0aef8cbc5 --- /dev/null +++ b/tests/lib/rules/valid-template-root.js @@ -0,0 +1,132 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/valid-template-root') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('valid-template-root', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: `` + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives aren't supported on
elements."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives require no argument."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives don't support the modifier 'aaa'."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives require that attribute value."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives require the attribute value which is valid as LHS."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives don't support dynamic input types."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives don't support dynamic input types."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives don't support 'file' input type."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-model' directives cannot update the iteration variable 'x' itself."] + } + ] +}) diff --git a/tests/lib/rules/valid-v-on.js b/tests/lib/rules/valid-v-on.js new file mode 100644 index 000000000..e7179c109 --- /dev/null +++ b/tests/lib/rules/valid-v-on.js @@ -0,0 +1,80 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/valid-v-on') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('valid-v-on', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ["'v-on' directives don't support the modifier 'aaa'."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-on' directives require that attribute value or verb modifiers."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-on' directives require that attribute value or verb modifiers."] + } + ] +}) diff --git a/tests/lib/rules/valid-v-once.js b/tests/lib/rules/valid-v-once.js new file mode 100644 index 000000000..30ecbbcee --- /dev/null +++ b/tests/lib/rules/valid-v-once.js @@ -0,0 +1,52 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/valid-v-once') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('valid-v-once', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ["'v-once' directives require no argument."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-once' directives require no modifier."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-once' directives require no attribute value."] + } + ] +}) diff --git a/tests/lib/rules/valid-v-pre.js b/tests/lib/rules/valid-v-pre.js new file mode 100644 index 000000000..a943baeae --- /dev/null +++ b/tests/lib/rules/valid-v-pre.js @@ -0,0 +1,52 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/valid-v-pre') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('valid-v-pre', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ["'v-pre' directives require no argument."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-pre' directives require no modifier."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-pre' directives require no attribute value."] + } + ] +}) diff --git a/tests/lib/rules/valid-v-show.js b/tests/lib/rules/valid-v-show.js new file mode 100644 index 000000000..03f7f7694 --- /dev/null +++ b/tests/lib/rules/valid-v-show.js @@ -0,0 +1,52 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/valid-v-show') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('valid-v-show', rule, { + valid: [ + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ["'v-show' directives require no argument."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-show' directives require no modifier."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-show' directives require that attribute value."] + } + ] +}) diff --git a/tests/lib/rules/valid-v-text.js b/tests/lib/rules/valid-v-text.js new file mode 100644 index 000000000..714833cb8 --- /dev/null +++ b/tests/lib/rules/valid-v-text.js @@ -0,0 +1,56 @@ +/** + * @author Toru Nagashima + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/valid-v-text') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +tester.run('valid-v-text', rule, { + valid: [ + { + filename: 'test.js', + code: 'test' + }, + { + filename: 'test.vue', + code: '' + }, + { + filename: 'test.vue', + code: '' + } + ], + invalid: [ + { + filename: 'test.vue', + code: '', + errors: ["'v-text' directives require no argument."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-text' directives require no modifier."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-text' directives require that attribute value."] + } + ] +}) diff --git a/tools/update-rules.js b/tools/update-rules.js index 937948692..65410bf08 100644 --- a/tools/update-rules.js +++ b/tools/update-rules.js @@ -41,7 +41,7 @@ const categories = rules arr.push(category) } return arr - }, []) + }, ['Possible Errors', 'Best Practices', 'Stylistic Issues']) const rulesTableContent = categories.map(category => ` ### ${category} @@ -50,18 +50,38 @@ const rulesTableContent = categories.map(category => ` |:---|:--------|:------------| ${ rules - .filter(entry => entry[1].meta.docs.category === category) + .filter(entry => entry[1].meta.docs.category === category && !entry[1].meta.deprecated) .map(entry => { const name = entry[0] const meta = entry[1].meta const mark = `${meta.docs.recommended ? STAR : ''}${meta.fixable ? PEN : ''}${meta.deprecated ? WARN : ''}` const link = `[${name}](./docs/rules/${name}.md)` - const description = (meta.docs.description || '(no description)') + (meta.deprecated ? ' - (deprecated)' : '') + const description = meta.docs.description || '(no description)' return `| ${mark} | ${link} | ${description} |` }) .join('\n') } -`).join('\n') +`).join('\n') + ` +### Deprecated + +> - :warning: We're going to remove deprecated rules in the next major release. Please migrate to successor/new rules. +> - :innocent: We don't fix bugs which are in deprecated rules since we don't have enough resources. + +| Rule ID | Replaced by | +|:--------|:------------| +${ + rules + .filter(entry => entry[1].meta.deprecated) + .map(entry => { + const name = entry[0] + const meta = entry[1].meta + const link = `[${name}](./rules/${name}.md)` + const replacedBy = (meta.docs.replacedBy || []).map(id => `[${id}](./rules/${id}.md)`).join(', ') || '(no replacement)' + return `| ${link} | ${replacedBy} |` + }) + .join('\n') +} +` const recommendedRules = rules.reduce((obj, entry) => { const name = `vue/${entry[0]}` From 8761bdeb74dab5551639634a75af84ce29cfb520 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Tue, 8 Aug 2017 23:46:03 +0900 Subject: [PATCH 0071/1448] Fix: support ESLint 4.4.0 (fixes #134) (#139) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 867d03aaa..6ebff6e25 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ }, "dependencies": { "requireindex": "^1.1.0", - "vue-eslint-parser": "2.0.0-beta.5" + "vue-eslint-parser": "2.0.0-beta.6" }, "devDependencies": { "@types/node": "^4.2.16", From a1fd26be58b657af9aa3f11acb191a172df0e233 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Wed, 9 Aug 2017 02:15:54 +0200 Subject: [PATCH 0072/1448] v3.11.0 --- README.md | 3 ++- lib/recommended-rules.js | 1 + package.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 111afae7e..a6d61292a 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ The `--fix` option on the command line automatically fixes problems reported by |:---|:--------|:------------| | :wrench: | [attribute-hyphenation](./docs/rules/attribute-hyphenation.md) | Define a style for the props casing in templates. | | | [html-quotes](./docs/rules/html-quotes.md) | enforce quotes style of HTML attributes. | +| :wrench: | [html-self-closing](./docs/rules/html-self-closing.md) | enforce self-closing style. | | :wrench: | [name-property-casing](./docs/rules/name-property-casing.md) | Requires specific casing for the name property in Vue components | | :wrench: | [v-bind-style](./docs/rules/v-bind-style.md) | enforce `v-bind` directive style. | | :wrench: | [v-on-style](./docs/rules/v-on-style.md) | enforce `v-on` directive style. | @@ -156,7 +157,7 @@ The `--fix` option on the command line automatically fixes problems reported by | Rule ID | Replaced by | |:--------|:------------| -| [html-no-self-closing](./rules/html-no-self-closing.md) | (no replacement) | +| [html-no-self-closing](./rules/html-no-self-closing.md) | [html-self-closing-style](./rules/html-self-closing-style.md) | | [no-invalid-template-root](./rules/no-invalid-template-root.md) | [valid-template-root](./rules/valid-template-root.md) | | [no-invalid-v-bind](./rules/no-invalid-v-bind.md) | [valid-v-bind](./rules/valid-v-bind.md) | | [no-invalid-v-cloak](./rules/no-invalid-v-cloak.md) | [valid-v-cloak](./rules/valid-v-cloak.md) | diff --git a/lib/recommended-rules.js b/lib/recommended-rules.js index fe3d3e174..02c13c1b8 100644 --- a/lib/recommended-rules.js +++ b/lib/recommended-rules.js @@ -8,6 +8,7 @@ module.exports = { "vue/html-end-tags": "off", "vue/html-no-self-closing": "off", "vue/html-quotes": "off", + "vue/html-self-closing": "off", "vue/jsx-uses-vars": "error", "vue/name-property-casing": "off", "vue/no-async-in-computed-properties": "off", diff --git a/package.json b/package.json index 6ebff6e25..643b95ff9 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eslint-plugin-vue", - "version": "3.10.0", + "version": "3.11.0", "description": "Official ESLint plugin for Vue.js", "main": "lib/index.js", "scripts": { From 164b2aea7b19d30b37ec1b58d809b558da2042d9 Mon Sep 17 00:00:00 2001 From: Armano Date: Wed, 9 Aug 2017 14:52:00 +0200 Subject: [PATCH 0073/1448] Fix small mistake in `require-valid-default-prop` (#143) * Fix small mistakes in `require-valid-default-prop` - Improve coverage for FunctionExpression and ArrowFunctionExpression - Fix traversing over many types (return -> continue) * Cleanup code --- lib/rules/require-valid-default-prop.js | 13 +++++-------- tests/lib/rules/require-valid-default-prop.js | 1 + 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lib/rules/require-valid-default-prop.js b/lib/rules/require-valid-default-prop.js index 22dbe5b4d..659df0183 100644 --- a/lib/rules/require-valid-default-prop.js +++ b/lib/rules/require-valid-default-prop.js @@ -102,23 +102,20 @@ module.exports = { for (const prop of properties) { const type = getPropertyNode(prop.value, 'type') - if (!type) { - return - } + if (!type) continue const typeNames = new Set(getTypes(type.value) .map(item => item === 'Object' || item === 'Array' ? 'Function' : item) // Object and Array require function .filter(item => NATIVE_TYPES.has(item))) - if (typeNames.size === 0) { // There is no native types detected - return - } + // There is no native types detected + if (typeNames.size === 0) continue const def = getPropertyNode(prop.value, 'default') - if (!def) return + if (!def) continue const defType = getValueType(def.value) - if (typeNames.has(defType)) return + if (!defType || typeNames.has(defType)) continue context.report({ node: def, diff --git a/tests/lib/rules/require-valid-default-prop.js b/tests/lib/rules/require-valid-default-prop.js index 8c4a84abf..b95fa71ae 100644 --- a/tests/lib/rules/require-valid-default-prop.js +++ b/tests/lib/rules/require-valid-default-prop.js @@ -65,6 +65,7 @@ ruleTester.run('require-valid-default-prop', rule, { foo: null, foo: Number, foo: [String, Number], + foo: { type: Number, default: VAR_BAR }, foo: { type: Number, default: 100 }, foo: { type: [String, Number], default: '' }, foo: { type: [String, Number], default: 0 }, From 140a276e191c311155c0d82ca14d4a7bb0045dcd Mon Sep 17 00:00:00 2001 From: Armano Date: Mon, 14 Aug 2017 07:27:21 +0200 Subject: [PATCH 0074/1448] New: add "no-multi-spaces" rule (fixes #133) (#138) --- docs/rules/no-multi-spaces.md | 31 +++++ lib/rules/no-multi-spaces.js | 66 +++++++++++ package.json | 2 +- tests/lib/rules/no-multi-spaces.js | 177 +++++++++++++++++++++++++++++ 4 files changed, 275 insertions(+), 1 deletion(-) create mode 100644 docs/rules/no-multi-spaces.md create mode 100644 lib/rules/no-multi-spaces.js create mode 100644 tests/lib/rules/no-multi-spaces.js diff --git a/docs/rules/no-multi-spaces.md b/docs/rules/no-multi-spaces.md new file mode 100644 index 000000000..b93254dab --- /dev/null +++ b/docs/rules/no-multi-spaces.md @@ -0,0 +1,31 @@ +# This rule warns about the usage of extra whitespaces between attributes (no-multi-spaces) + +The `--fix` option on the command line can automatically fix some of the problems reported by this rule. + +This rule aims to remove multiple spaces in a row between attributes witch are not used for indentation. + +## Rule Details + +Examples of **incorrect** code for this rule: + +```html + +``` + +Examples of **correct** code for this rule: + +```html + +``` + +### Options + +Nothing diff --git a/lib/rules/no-multi-spaces.js b/lib/rules/no-multi-spaces.js new file mode 100644 index 000000000..c9d6369f4 --- /dev/null +++ b/lib/rules/no-multi-spaces.js @@ -0,0 +1,66 @@ +/** + * @fileoverview This rule warns about the usage of extra whitespaces between attributes + * @author Armano + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + docs: { + description: 'This rule warns about the usage of extra whitespaces between attributes', + category: 'Stylistic Issues', + recommended: false + }, + fixable: 'whitespace', // or "code" or "whitespace" + schema: [] + }, + + /** + * @param {RuleContext} context - The rule context. + * @returns {Object} AST event handlers. + */ + create (context) { + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + return { + Program (node) { + if (context.parserServices.getTemplateBodyTokenStore == null) { + context.report({ + loc: { line: 1, column: 0 }, + message: 'Use the latest vue-eslint-parser. See also https://github.com/vuejs/eslint-plugin-vue#what-is-the-use-the-latest-vue-eslint-parser-error.' + }) + return + } + const sourceCode = context.getSourceCode() + const tokenStore = context.parserServices.getTemplateBodyTokenStore() + const tokens = tokenStore.getTokens(node.templateBody, { includeComments: true }) + + let prevToken = tokens.shift() + for (const token of tokens) { + const spaces = token.range[0] - prevToken.range[1] + if (spaces > 1 && token.loc.start.line === prevToken.loc.start.line) { + context.report({ + node: token, + loc: { + start: prevToken.loc.end, + end: token.loc.start + }, + message: "Multiple spaces found before '{{displayValue}}'.", + fix: (fixer) => fixer.replaceTextRange([prevToken.range[1], token.range[0]], ' '), + data: { + displayValue: sourceCode.getText(token) + } + }) + } + prevToken = token + } + } + } + } +} diff --git a/package.json b/package.json index 643b95ff9..12917f314 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ }, "dependencies": { "requireindex": "^1.1.0", - "vue-eslint-parser": "2.0.0-beta.6" + "vue-eslint-parser": "2.0.0-beta.7" }, "devDependencies": { "@types/node": "^4.2.16", diff --git a/tests/lib/rules/no-multi-spaces.js b/tests/lib/rules/no-multi-spaces.js new file mode 100644 index 000000000..afb93cf07 --- /dev/null +++ b/tests/lib/rules/no-multi-spaces.js @@ -0,0 +1,177 @@ +/** + * @fileoverview This rule warns about the usage of extra whitespaces between attributes + * @author Armano + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/no-multi-spaces') +const RuleTester = require('eslint').RuleTester + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +ruleTester.run('no-multi-spaces', rule, { + valid: [ + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '', + '' + ], + invalid: [ + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'class'.", + type: 'HTMLIdentifier' + }, + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'class'.", + type: 'HTMLIdentifier' + }, + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before ':class'.", + type: 'HTMLIdentifier' + }, + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [{ + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + }] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before '/>'.", + type: 'HTMLSelfClosingTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'test'.", + type: 'Identifier' + }, + { + message: "Multiple spaces found before '}}'.", + type: 'VExpressionEnd' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before '>'.", + type: 'HTMLTagClose' + } + ] + }, + { + code: '', + output: '', + errors: [ + { + message: "Multiple spaces found before 'i'.", + type: 'Identifier' + }, + { + message: "Multiple spaces found before 'in'.", + type: 'Keyword' + }, + { + message: "Multiple spaces found before 'b'.", + type: 'Identifier' + }, + { + message: "Multiple spaces found before '\"'.", + type: 'Punctuator' + } + ] + } + ] +}) From df84d9bf48b20cceb91776f889d65359f8891326 Mon Sep 17 00:00:00 2001 From: Armano Date: Mon, 14 Aug 2017 07:33:02 +0200 Subject: [PATCH 0075/1448] Fix: improve support for spread operator (#146) * Fix exceptions in iterateFunctionExpression and iterateProperties: * Cannot read property 'type' of null * Improve support for spread operator * Add more unit tests to match all possible cases --- lib/rules/order-in-components.js | 4 ++- lib/utils/index.js | 5 ++- tests/lib/rules/html-end-tags.js | 33 ++++++++++--------- tests/lib/rules/name-property-casing.js | 13 +++++++- .../rules/no-async-in-computed-properties.js | 1 + tests/lib/rules/no-dupe-keys.js | 10 +++++- tests/lib/rules/no-reservered-keys.js | 8 ++++- tests/lib/rules/no-shared-component-data.js | 18 ++++++++++ .../no-side-effects-in-computed-properties.js | 1 + tests/lib/rules/order-in-components.js | 21 ++++++++---- tests/lib/rules/require-prop-types.js | 1 + tests/lib/rules/require-render-return.js | 1 + tests/lib/rules/require-valid-default-prop.js | 18 +++++++++- tests/lib/rules/valid-v-for.js | 9 +++++ 14 files changed, 115 insertions(+), 28 deletions(-) diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js index d35d6458a..e6a131f7c 100644 --- a/lib/rules/order-in-components.js +++ b/lib/rules/order-in-components.js @@ -53,7 +53,9 @@ function getOrderMap (order) { } function checkOrder (propertiesNodes, orderMap, context) { - const properties = propertiesNodes.map(property => property.key) + const properties = propertiesNodes + .filter(property => property.type === 'Property') + .map(property => property.key) properties.forEach((property, i) => { const propertiesAbove = properties.slice(0, i) diff --git a/lib/utils/index.js b/lib/utils/index.js index b2a5bacbf..e40c0935e 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -323,6 +323,7 @@ module.exports = { getComputedProperties (componentObject) { const computedPropertiesNode = componentObject.properties .find(p => + p.type === 'Property' && p.key.type === 'Identifier' && p.key.name === 'computed' && p.value.type === 'ObjectExpression' @@ -480,6 +481,8 @@ module.exports = { const nodes = node.properties.filter(p => p.type === 'Property' && groups.has(this.getStaticPropertyName(p.key))) for (const item of nodes) { const name = this.getStaticPropertyName(item.key) + if (!name) continue + if (item.value.type === 'ArrayExpression') { yield * this.iterateArrayExpression(item.value, name) } else if (item.value.type === 'ObjectExpression') { @@ -531,7 +534,7 @@ module.exports = { assert(node.type === 'FunctionExpression') if (node.body.type === 'BlockStatement') { for (const item of node.body.body) { - if (item.type === 'ReturnStatement' && item.argument.type === 'ObjectExpression') { + if (item.type === 'ReturnStatement' && item.argument && item.argument.type === 'ObjectExpression') { yield * this.iterateObjectExpression(item.argument, groupName) } } diff --git a/tests/lib/rules/html-end-tags.js b/tests/lib/rules/html-end-tags.js index e470e62b3..b4d648d56 100644 --- a/tests/lib/rules/html-end-tags.js +++ b/tests/lib/rules/html-end-tags.js @@ -49,21 +49,24 @@ tester.run('html-end-tags', rule, { } ], invalid: [ - // { - // filename: "test.vue", - // code: "", - // errors: ["'
' should not have end tag."], - // }, - // { - // filename: "test.vue", - // code: "", - // errors: ["'' should not have end tag."], - // }, - // { - // filename: "test.vue", - // code: "", - // errors: ["'' should not have end tag."], - // }, + // { + // filename: 'test.vue', + // code: '', + // output: '', + // errors: ["'
' should not have end tag."] + // }, + // { + // filename: 'test.vue', + // code: '', + // output: '', + // errors: ["'' should not have end tag."] + // }, + // { + // filename: 'test.vue', + // code: '', + // output: '', + // errors: ["'' should not have end tag."] + // }, { filename: 'test.vue', code: '', diff --git a/tests/lib/rules/name-property-casing.js b/tests/lib/rules/name-property-casing.js index 88ede6d6d..3c09f23f0 100644 --- a/tests/lib/rules/name-property-casing.js +++ b/tests/lib/rules/name-property-casing.js @@ -17,7 +17,8 @@ const RuleTester = require('eslint').RuleTester const parserOptions = { ecmaVersion: 6, - sourceType: 'module' + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } } const ruleTester = new RuleTester() @@ -33,6 +34,16 @@ ruleTester.run('name-property-casing', rule, { options: ['camelCase'], parserOptions }, + { + filename: 'test.vue', + code: ` + export default { + ...name + } + `, + options: ['camelCase'], + parserOptions + }, { filename: 'test.vue', code: ` diff --git a/tests/lib/rules/no-async-in-computed-properties.js b/tests/lib/rules/no-async-in-computed-properties.js index 34c57e75f..e7cd02694 100644 --- a/tests/lib/rules/no-async-in-computed-properties.js +++ b/tests/lib/rules/no-async-in-computed-properties.js @@ -36,6 +36,7 @@ ruleTester.run('no-async-in-computed-properties', rule, { filename: 'test.vue', code: ` export default { + ...foo, computed: { ...mapGetters({ test: 'getTest' diff --git a/tests/lib/rules/no-dupe-keys.js b/tests/lib/rules/no-dupe-keys.js index fbb314c90..fb23ff8ab 100644 --- a/tests/lib/rules/no-dupe-keys.js +++ b/tests/lib/rules/no-dupe-keys.js @@ -32,6 +32,9 @@ ruleTester.run('no-dupe-keys', rule, { dat: null } }, + data () { + return + }, methods: { _foo () {}, test () { @@ -68,7 +71,12 @@ ruleTester.run('no-dupe-keys', rule, { ...foo(), test () { } - } + }, + data () { + return { + ...dat + } + }, } `, parserOptions: { ecmaVersion: 8, sourceType: 'module', ecmaFeatures: { experimentalObjectRestSpread: true }} diff --git a/tests/lib/rules/no-reservered-keys.js b/tests/lib/rules/no-reservered-keys.js index 378a840c2..46744a266 100644 --- a/tests/lib/rules/no-reservered-keys.js +++ b/tests/lib/rules/no-reservered-keys.js @@ -11,6 +11,12 @@ const rule = require('../../../lib/rules/no-reservered-keys') const RuleTester = require('eslint').RuleTester +const parserOptions = { + ecmaVersion: 7, + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } +} + // ------------------------------------------------------------------------------ // Tests // ------------------------------------------------------------------------------ @@ -39,7 +45,7 @@ ruleTester.run('no-reservered-keys', rule, { } } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions } ], diff --git a/tests/lib/rules/no-shared-component-data.js b/tests/lib/rules/no-shared-component-data.js index aad6b3049..2a54ad07f 100644 --- a/tests/lib/rules/no-shared-component-data.js +++ b/tests/lib/rules/no-shared-component-data.js @@ -32,6 +32,24 @@ ruleTester.run('no-shared-component-data', rule, { }) ` }, + { + filename: 'test.js', + code: ` + new Vue({ + ...data, + data () { + return { + foo: 'bar' + } + } + }) + `, + parserOptions: { + ecmaVersion: 7, + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } + } + }, { filename: 'test.js', code: ` diff --git a/tests/lib/rules/no-side-effects-in-computed-properties.js b/tests/lib/rules/no-side-effects-in-computed-properties.js index c6f95f15d..a84e6fae8 100644 --- a/tests/lib/rules/no-side-effects-in-computed-properties.js +++ b/tests/lib/rules/no-side-effects-in-computed-properties.js @@ -26,6 +26,7 @@ ruleTester.run('no-side-effects-in-computed-properties', rule, { valid: [ { code: `Vue.component('test', { + ...foo, computed: { ...test0({}), test1() { diff --git a/tests/lib/rules/order-in-components.js b/tests/lib/rules/order-in-components.js index 4470e895a..4886e88bf 100644 --- a/tests/lib/rules/order-in-components.js +++ b/tests/lib/rules/order-in-components.js @@ -9,6 +9,12 @@ const RuleTester = require('eslint').RuleTester const ruleTester = new RuleTester() +const parserOptions = { + ecmaVersion: 6, + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } +} + ruleTester.run('order-in-components', rule, { valid: [ @@ -20,6 +26,7 @@ ruleTester.run('order-in-components', rule, { props: { propA: Number, }, + ...a, data () { return { msg: 'Welcome to Your Vue.js App' @@ -27,21 +34,21 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.vue', code: ` export default {} `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.vue', code: ` export default 'example-text' `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.jsx', @@ -55,7 +62,7 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' } + parserOptions }, { filename: 'test.js', @@ -136,7 +143,7 @@ ruleTester.run('order-in-components', rule, { }, } `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + parserOptions, errors: [{ message: 'The "props" property should be above the "data" property on line 4.', line: 9 @@ -268,7 +275,7 @@ ruleTester.run('order-in-components', rule, { name: 'burger', }; `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + parserOptions, errors: [{ message: 'The "name" property should be above the "data" property on line 3.', line: 16 @@ -284,7 +291,7 @@ ruleTester.run('order-in-components', rule, { test: 'ok' }; `, - parserOptions: { ecmaVersion: 6, sourceType: 'module' }, + parserOptions, options: [{ order: ['data', 'test', 'name'] }], errors: [{ message: 'The "test" property should be above the "name" property on line 5.', diff --git a/tests/lib/rules/require-prop-types.js b/tests/lib/rules/require-prop-types.js index 835d2552e..f630354c7 100644 --- a/tests/lib/rules/require-prop-types.js +++ b/tests/lib/rules/require-prop-types.js @@ -24,6 +24,7 @@ ruleTester.run('require-prop-types', rule, { filename: 'test.vue', code: ` export default { + ...foo, props: { ...test(), foo: String diff --git a/tests/lib/rules/require-render-return.js b/tests/lib/rules/require-render-return.js index 5aebda6eb..c12910ff7 100644 --- a/tests/lib/rules/require-render-return.js +++ b/tests/lib/rules/require-render-return.js @@ -26,6 +26,7 @@ ruleTester.run('require-render-return', rule, { valid: [ { code: `Vue.component('test', { + ...foo, render() { return {} } diff --git a/tests/lib/rules/require-valid-default-prop.js b/tests/lib/rules/require-valid-default-prop.js index b95fa71ae..b8794fbfb 100644 --- a/tests/lib/rules/require-valid-default-prop.js +++ b/tests/lib/rules/require-valid-default-prop.js @@ -13,7 +13,8 @@ const RuleTester = require('eslint').RuleTester const parserOptions = { ecmaVersion: 6, - sourceType: 'module' + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true, jsx: true } } function errorMessage (type) { @@ -32,6 +33,14 @@ const ruleTester = new RuleTester() ruleTester.run('require-valid-default-prop', rule, { valid: [ + { + filename: 'test.vue', + code: `export default { + ...foo, + props: { ...foo } + }`, + parserOptions + }, { filename: 'test.vue', code: `export default { @@ -65,8 +74,13 @@ ruleTester.run('require-valid-default-prop', rule, { foo: null, foo: Number, foo: [String, Number], + foo: { }, + foo: { type: String }, foo: { type: Number, default: VAR_BAR }, foo: { type: Number, default: 100 }, + foo: { type: Number, default: Number.MAX_VALUE }, + foo: { type: Number, default: Foo.BAR }, + foo: { type: {}, default: '' }, foo: { type: [String, Number], default: '' }, foo: { type: [String, Number], default: 0 }, foo: { type: String, default: '' }, @@ -80,6 +94,8 @@ ruleTester.run('require-valid-default-prop', rule, { foo: { type: Symbol, default () { } }, foo: { type: Array, default () { } }, foo: { type: Symbol, default: Symbol('a') }, + foo: { type: String, default: \`Foo\` }, + foo: { type: Foo, default: Foo('a') }, foo: { type: String, default: \`Foo\` } } })`, diff --git a/tests/lib/rules/valid-v-for.js b/tests/lib/rules/valid-v-for.js index 80da18187..e3da7c5ed 100644 --- a/tests/lib/rules/valid-v-for.js +++ b/tests/lib/rules/valid-v-for.js @@ -78,6 +78,10 @@ tester.run('valid-v-for', rule, { { filename: 'test.vue', code: '' + }, + { + filename: 'test.vue', + code: '' } ], invalid: [ @@ -170,6 +174,11 @@ tester.run('valid-v-for', rule, { filename: 'test.vue', code: '', errors: ["Custom elements in iteration require 'v-bind:key' directives."] + }, + { + filename: 'test.vue', + code: '', + errors: ["'v-for' directives require that attribute value."] } ] }) From 85558dc8c89a1f6b860cf42a248e797076d8eaf1 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Tue, 15 Aug 2017 10:35:46 +0100 Subject: [PATCH 0076/1448] Add rule `max-attributes-per-line` (resolves #47) (#60) * Inits new rule. Adds documentation. * Improves rule definition * Update docs to match review * Adds rule to check for number of attributes per line * Updates per code review: - Adds defaults values - Adds tests for the default values * Updates single line max attributes error as per code review * Changes schema to allow a different config Changes options parser to allow to redifine only one prop Changes error thrown for singleline errors Updates tests and docs accordingly * Moves function into utils Uses arrow function Improves readability * Fix eslint error * Improves code coverage * Update docs as per code review * reports the violated attributes instead of elements --- docs/rules/max-attributes-per-line.md | 122 +++++++++++++ lib/rules/max-attributes-per-line.js | 161 +++++++++++++++++ lib/utils/index.js | 9 + tests/lib/rules/max-attributes-per-line.js | 191 +++++++++++++++++++++ 4 files changed, 483 insertions(+) create mode 100644 docs/rules/max-attributes-per-line.md create mode 100644 lib/rules/max-attributes-per-line.js create mode 100644 tests/lib/rules/max-attributes-per-line.js diff --git a/docs/rules/max-attributes-per-line.md b/docs/rules/max-attributes-per-line.md new file mode 100644 index 000000000..8493465b6 --- /dev/null +++ b/docs/rules/max-attributes-per-line.md @@ -0,0 +1,122 @@ +# Define the number of attributes allows per line (max-attributes-per-line) + +Limits the maximum number of attributes/properties per line to improve readability. + + +## :book: Rule Details + +This rule aims to enforce a number of attributes per line in templates. +It checks all the elements in a template and verifies that the number of attributes per line does not exceed the defined maximum. +An attribute is considered to be in a new line when there is a line break between two attributes. + +There is a configurable number of attributes that are acceptable in one-line case (default 3), as well as how many attributes are acceptable per line in multi-line case (default 1). + +:-1: Examples of **incorrect** code for this rule: + +```html + + + + + +``` + +:+1: Examples of **correct** code for this rule: + +```html + + + + + + +``` + +### :wrench: Options + +``` +{ + "vue/max-attributes-per-line": [{ + "singleline": 3, + "multiline": { + max: 1, + allowFirstLine: false + } + }] +} +``` + +#### `allowFirstLine` +For multi-line declarations, defines if allows attributes to be put in the first line. (Default false) + +:-1: Example of **incorrect** code for this setting: +```html +// [{ "multiline": { "allowFirstLine": false }}] + +; +``` + +:+1: Example of **correct** code for this setting: +```html +// [{ "multiline": { "allowFirstLine": false }}] + +; +``` + + +#### `singleline` +Number of maximum attributes per line when the opening tag is in a single line. (Default is 3) + +:-1: Example of **incorrect** code for this setting: +```html +// [{"singleline": 2,}] +; +``` + +:+1: Example of **correct** code for this setting: +```html +// [{"singleline": 3,}] +; +``` + + +#### `multiline` +Number of maximum attributes per line when a tag is in multiple lines. (Default is 1) + +:-1: Example of **incorrect** code for this setting: +```html +// [{"multiline": 1}] + +; +``` + +:+1: Example of **correct** code for this setting: +```html +// [{"multiline": 1}] + +; +``` + +## When Not To Use It + +If you do not want to check the number of attributes declared per line you can disable this rule. + diff --git a/lib/rules/max-attributes-per-line.js b/lib/rules/max-attributes-per-line.js new file mode 100644 index 000000000..f5309e4a1 --- /dev/null +++ b/lib/rules/max-attributes-per-line.js @@ -0,0 +1,161 @@ +/** + * @fileoverview Define the number of attributes allows per line + * @author Filipa Lacerda + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ +const utils = require('../utils') + +module.exports = { + meta: { + docs: { + description: 'Define the number of attributes allows per line', + category: 'Stylistic Issues', + recommended: false + }, + fixable: null, + schema: [ + { + type: 'object', + properties: { + singleline: { + anyOf: [ + { + type: 'number', + minimum: 1 + }, + { + type: 'object', + properties: { + max: { + type: 'number', + minimum: 1 + } + }, + additionalProperties: false + } + ] + }, + multiline: { + anyOf: [ + { + type: 'number', + minimum: 1 + }, + { + type: 'object', + properties: { + max: { + type: 'number', + minimum: 1 + }, + allowFirstLine: { + type: 'boolean' + } + }, + additionalProperties: false + } + ] + } + } + } + ] + }, + + create: function (context) { + const configuration = parseOptions(context.options[0]) + const multilineMaximum = configuration.multiline + const singlelinemMaximum = configuration.singleline + const canHaveFirstLine = configuration.allowFirstLine + + utils.registerTemplateBodyVisitor(context, { + 'VStartTag' (node) { + const numberOfAttributes = node.attributes.length + + if (!numberOfAttributes) return + + if (utils.isSingleLine(node) && numberOfAttributes > singlelinemMaximum) { + showErrors(node.attributes.slice(singlelinemMaximum), node) + } + + if (!utils.isSingleLine(node)) { + if (!canHaveFirstLine && node.attributes[0].loc.start.line === node.loc.start.line) { + showErrors([node.attributes[0]], node) + } + + groupAttrsByLine(node.attributes) + .filter(attrs => attrs.length > multilineMaximum) + .forEach(attrs => showErrors(attrs.splice(multilineMaximum), node)) + } + } + }) + + // ---------------------------------------------------------------------- + // Helpers + // ---------------------------------------------------------------------- + function parseOptions (options) { + const defaults = { + singleline: 3, + multiline: 1, + allowFirstLine: false + } + + if (options) { + if (typeof options.singleline === 'number') { + defaults.singleline = options.singleline + } else if (options.singleline && options.singleline.max) { + defaults.singleline = options.singleline.max + } + + if (options.multiline) { + if (typeof options.multiline === 'number') { + defaults.multiline = options.multiline + } else if (typeof options.multiline === 'object') { + if (options.multiline.max) { + defaults.multiline = options.multiline.max + } + + if (options.multiline.allowFirstLine) { + defaults.allowFirstLine = options.multiline.allowFirstLine + } + } + } + } + + return defaults + } + + function showErrors (attributes, node) { + attributes.forEach((prop) => { + context.report({ + node: prop, + loc: prop.loc, + message: 'Attribute "{{propName}}" should be on a new line.', + data: { + propName: prop.key.name + } + }) + }) + } + + function groupAttrsByLine (attributes) { + const propsPerLine = [[attributes[0]]] + + attributes.reduce((previous, current) => { + if (previous.loc.end.line === current.loc.start.line) { + propsPerLine[propsPerLine.length - 1].push(current) + } else { + propsPerLine.push([current]) + } + return current + }) + + return propsPerLine + } + + return {} + } +} diff --git a/lib/utils/index.js b/lib/utils/index.js index e40c0935e..e61ca1a17 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -590,5 +590,14 @@ module.exports = { } } } + }, + + /** + * Check whether the component is declared in a single line or not. + * @param {ASTNode} node + * @returns {boolean} + */ + isSingleLine (node) { + return node.loc.start.line === node.loc.end.line } } diff --git a/tests/lib/rules/max-attributes-per-line.js b/tests/lib/rules/max-attributes-per-line.js new file mode 100644 index 000000000..07d24197c --- /dev/null +++ b/tests/lib/rules/max-attributes-per-line.js @@ -0,0 +1,191 @@ +/** + * @fileoverview Define the number of attributes allows per line + * @author Filipa Lacerda + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../lib/rules/max-attributes-per-line') + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + parser: 'vue-eslint-parser', + parserOptions: { ecmaVersion: 2015 } +}) + +ruleTester.run('max-attributes-per-line', rule, { + valid: [ + { + code: `` + }, + { + code: `` + }, + { + code: ``, + options: [{ multiline: { allowFirstLine: true }}] + }, + { + code: `` + }, + { + code: ``, + options: [{ singleline: 1 }] + }, + { + code: ``, + options: [{ singleline: 1, multiline: { max: 1, allowFirstLine: false }}] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 1, allowFirstLine: false }}] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 1, allowFirstLine: true }}] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 1, allowFirstLine: false }}] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 2, allowFirstLine: false }}] + } + ], + + invalid: [ + { + code: ``, + errors: ['Attribute "petname" should be on a new line.'] + }, + { + code: ``, + errors: [{ + message: 'Attribute "job" should be on a new line.', + type: 'VAttribute', + line: 1 + }] + }, + { + code: ``, + options: [{ singleline: { max: 1 }}], + errors: [{ + message: 'Attribute "age" should be on a new line.', + type: 'VAttribute', + line: 1 + }] + }, + { + code: ``, + options: [{ singleline: 1, multiline: { max: 1, allowFirstLine: false }}], + errors: [{ + message: 'Attribute "age" should be on a new line.', + type: 'VAttribute', + line: 1 + }, { + message: 'Attribute "job" should be on a new line.', + type: 'VAttribute', + line: 1 + }] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 1, allowFirstLine: false }}], + errors: [{ + message: 'Attribute "name" should be on a new line.', + type: 'VAttribute', + line: 1 + }] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 1, allowFirstLine: false }}], + errors: [{ + message: 'Attribute "age" should be on a new line.', + type: 'VAttribute', + line: 2 + }] + }, + { + code: ``, + options: [{ singleline: 3, multiline: 1 }], + errors: [{ + message: 'Attribute "age" should be on a new line.', + type: 'VAttribute', + line: 2 + }] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 2, allowFirstLine: false }}], + errors: [{ + message: 'Attribute "petname" should be on a new line.', + type: 'VAttribute', + line: 3 + }] + }, + { + code: ``, + options: [{ singleline: 3, multiline: { max: 2, allowFirstLine: false }}], + errors: [{ + message: 'Attribute "petname" should be on a new line.', + type: 'VAttribute', + line: 3 + }, { + message: 'Attribute "extra" should be on a new line.', + type: 'VAttribute', + line: 3 + }] + } + ] +}) From becfb8a75acbe3bec52ccade2f696f718efa0f89 Mon Sep 17 00:00:00 2001 From: Armano Date: Tue, 15 Aug 2017 12:08:53 +0200 Subject: [PATCH 0077/1448] Treat Vue.mixin as components (#137) * Treat Vue.mixin as components * Add unit test for `Vue.mixin` --- lib/utils/index.js | 2 +- tests/lib/utils/vue-component.js | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/utils/index.js b/lib/utils/index.js index e61ca1a17..08c8c34cf 100644 --- a/lib/utils/index.js +++ b/lib/utils/index.js @@ -382,7 +382,7 @@ module.exports = { callee.object.type === 'Identifier' && callee.object.name === 'Vue' && callee.property.type === 'Identifier' && - callee.property.name === 'component' && + (callee.property.name === 'component' || callee.property.name === 'mixin') && node.arguments.length && node.arguments.slice(-1)[0].type === 'ObjectExpression' diff --git a/tests/lib/utils/vue-component.js b/tests/lib/utils/vue-component.js index 38b696333..0dd2d0cf3 100644 --- a/tests/lib/utils/vue-component.js +++ b/tests/lib/utils/vue-component.js @@ -120,6 +120,12 @@ function invalidTests (ext) { parserOptions, errors: [makeError(1)] }, + { + filename: `test.${ext}`, + code: `Vue.mixin({})`, + parserOptions, + errors: [makeError(1)] + }, { filename: `test.${ext}`, code: ` From 23d360ca0b5209b0fe70c10ee72a5314b358e92c Mon Sep 17 00:00:00 2001 From: Armano Date: Tue, 15 Aug 2017 12:59:16 +0200 Subject: [PATCH 0078/1448] Rename rule `no-reservered-keys` to `no-reserved-keys`. (#157) fixes #155 --- docs/rules/no-reserved-keys.md | 58 ++++++++++++++++ lib/rules/no-reserved-keys.js | 74 ++++++++++++++++++++ lib/rules/no-reservered-keys.js | 6 +- tests/lib/rules/no-reserved-keys.js | 100 ++++++++++++++++++++++++++++ 4 files changed, 236 insertions(+), 2 deletions(-) create mode 100644 docs/rules/no-reserved-keys.md create mode 100644 lib/rules/no-reserved-keys.js create mode 100644 tests/lib/rules/no-reserved-keys.js diff --git a/docs/rules/no-reserved-keys.md b/docs/rules/no-reserved-keys.md new file mode 100644 index 000000000..baf54a6a4 --- /dev/null +++ b/docs/rules/no-reserved-keys.md @@ -0,0 +1,58 @@ +# Prevent overwrite reserved keys (no-reserved-keys) + +This rule prevents to use reserved names from to avoid conflicts and unexpected behavior. + +## Rule Details + +:-1: Examples of **incorrect** code for this rule: + +```js +export default { + props: { + $el: String + }, + computed: { + $on: { + get () { + } + } + }, + data: { + _foo: null + }, + methods: { + $nextTick () { + } + } +} +``` + +## :wrench: Options + +This rule has an object option: + +`"reserved"`: [] (default) array of dissalowed names inside `groups`. + +`"groups"`: [] (default) array of additional groups to search for duplicates. + +### Example: + +``` +vue/no-reserved-keys: [2, { + reserved: ['foo', 'foo2'], + groups: ['asyncComputed'] +}] +``` + +:-1: Examples of **incorrect** code for this configuration + +```js +export default { + asyncComputed: { + foo2 () {} + }, + computed: { + foo () {} + } +} +``` diff --git a/lib/rules/no-reserved-keys.js b/lib/rules/no-reserved-keys.js new file mode 100644 index 000000000..bc4a89004 --- /dev/null +++ b/lib/rules/no-reserved-keys.js @@ -0,0 +1,74 @@ +/** + * @fileoverview Prevent overwrite reserved keys + * @author Armano + */ +'use strict' + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +const RESERVED_KEYS = require('../utils/vue-reserved.json') +const GROUP_NAMES = ['props', 'computed', 'data', 'methods'] + +function create (context) { + const options = context.options[0] || {} + const reservedKeys = new Set(RESERVED_KEYS.concat(options.reserved || [])) + const groups = new Set(GROUP_NAMES.concat(options.groups || [])) + + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + + return utils.executeOnVue(context, (obj) => { + const properties = utils.iterateProperties(obj, groups) + for (const o of properties) { + if (o.groupName === 'data' && o.name[0] === '_') { + context.report({ + node: o.node, + message: "Keys starting with with '_' are reserved in '{{name}}' group.", + data: { + name: o.name + } + }) + } else if (reservedKeys.has(o.name)) { + context.report({ + node: o.node, + message: "Key '{{name}}' is reserved.", + data: { + name: o.name + } + }) + } + } + }) +} + +module.exports = { + meta: { + docs: { + description: 'Prevent overwrite reserved keys.', + category: 'Possible Errors', + recommended: false + }, + fixable: null, + schema: [ + { + type: 'object', + properties: { + reserved: { + type: 'array' + }, + groups: { + type: 'array' + } + }, + additionalProperties: false + } + ] + }, + + create +} diff --git a/lib/rules/no-reservered-keys.js b/lib/rules/no-reservered-keys.js index c0ba613f2..e31fe710d 100644 --- a/lib/rules/no-reservered-keys.js +++ b/lib/rules/no-reservered-keys.js @@ -51,9 +51,11 @@ module.exports = { docs: { description: 'Prevent overwrite reserved keys.', category: 'Possible Errors', - recommended: false + recommended: false, + replacedBy: ['no-reserved-keys'] }, - fixable: null, // or "code" or "whitespace" + deprecated: true, + fixable: null, schema: [ { type: 'object', diff --git a/tests/lib/rules/no-reserved-keys.js b/tests/lib/rules/no-reserved-keys.js new file mode 100644 index 000000000..cc116f1dc --- /dev/null +++ b/tests/lib/rules/no-reserved-keys.js @@ -0,0 +1,100 @@ +/** + * @fileoverview Prevent overwrite reserved keys + * @author Armano + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/no-reserved-keys') +const RuleTester = require('eslint').RuleTester + +const parserOptions = { + ecmaVersion: 7, + sourceType: 'module', + ecmaFeatures: { experimentalObjectRestSpread: true } +} + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const ruleTester = new RuleTester() +ruleTester.run('no-reserved-keys', rule, { + valid: [ + { + filename: 'test.vue', + code: ` + export default { + props: ['foo'], + computed: { + bar () { + } + }, + data () { + return { + dat: null + } + }, + methods: { + _foo () {}, + test () { + } + } + } + `, + parserOptions + } + ], + + invalid: [ + { + filename: 'test.js', + code: ` + new Vue({ + props: { + $el: String + } + }) + `, + parserOptions: { ecmaVersion: 6 }, + errors: [{ + message: "Key '$el' is reserved.", + line: 4 + }] + }, + { + filename: 'test.js', + code: ` + new Vue({ + data: { + _foo: String + } + }) + `, + parserOptions: { ecmaVersion: 6 }, + errors: [{ + message: "Keys starting with with '_' are reserved in '_foo' group.", + line: 4 + }] + }, + { + filename: 'test.js', + code: ` + new Vue({ + foo: { + bar: String + } + }) + `, + options: [{ reserved: ['bar'], groups: ['foo'] }], + parserOptions: { ecmaVersion: 6 }, + errors: [{ + message: "Key 'bar' is reserved.", + line: 4 + }] + } + ] +}) From 541c2385dd33fb2bb23674dbe5e9ebbcb4cdb6f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Sajn=C3=B3g?= Date: Tue, 15 Aug 2017 16:45:12 +0200 Subject: [PATCH 0079/1448] v3.12.0 --- README.md | 5 ++++- lib/recommended-rules.js | 3 +++ package.json | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a6d61292a..8fda2f0d8 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ The `--fix` option on the command line automatically fixes problems reported by |:---|:--------|:------------| | | [no-dupe-keys](./docs/rules/no-dupe-keys.md) | Prevents duplication of field names. | | :white_check_mark: | [no-parsing-error](./docs/rules/no-parsing-error.md) | disallow parsing errors in ` `, - errors: [{ messageId: 'expectedVSlot', data: { actual: 'v-slot:default', argument: 'default' }}], + errors: [ + { + messageId: 'expectedVSlot', + data: { actual: 'v-slot:default', argument: 'default' } + } + ], options: [{ default: 'v-slot' }] }, @@ -383,7 +443,12 @@ tester.run('v-slot-style', rule, { `, - errors: [{ messageId: 'expectedShorthand', data: { actual: 'v-slot:foo', argument: 'foo' }}] + errors: [ + { + messageId: 'expectedShorthand', + data: { actual: 'v-slot:foo', argument: 'foo' } + } + ] }, { code: ` @@ -400,7 +465,12 @@ tester.run('v-slot-style', rule, { `, - errors: [{ messageId: 'expectedLongform', data: { actual: '#foo', argument: 'foo' }}], + errors: [ + { + messageId: 'expectedLongform', + data: { actual: '#foo', argument: 'foo' } + } + ], options: [{ named: 'longform' }] }, @@ -419,7 +489,12 @@ tester.run('v-slot-style', rule, { `, - errors: [{ messageId: 'expectedShorthand', data: { actual: 'v-slot:[foo]', argument: '[foo]' }}] + errors: [ + { + messageId: 'expectedShorthand', + data: { actual: 'v-slot:[foo]', argument: '[foo]' } + } + ] }, { code: ` @@ -436,7 +511,12 @@ tester.run('v-slot-style', rule, { `, - errors: [{ messageId: 'expectedLongform', data: { actual: '#[foo]', argument: '[foo]' }}], + errors: [ + { + messageId: 'expectedLongform', + data: { actual: '#[foo]', argument: '[foo]' } + } + ], options: [{ named: 'longform' }] } ] diff --git a/tests/lib/rules/valid-template-root.js b/tests/lib/rules/valid-template-root.js index 033188cca..212fefc8d 100644 --- a/tests/lib/rules/valid-template-root.js +++ b/tests/lib/rules/valid-template-root.js @@ -41,11 +41,13 @@ tester.run('valid-template-root', rule, { }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', @@ -57,7 +59,8 @@ tester.run('valid-template-root', rule, { }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', @@ -117,12 +120,16 @@ tester.run('valid-template-root', rule, { { filename: 'test.vue', code: '', - errors: ["The template root with 'src' attribute is required to be empty."] + errors: [ + "The template root with 'src' attribute is required to be empty." + ] }, { filename: 'test.vue', code: '', - errors: ["The template root with 'src' attribute is required to be empty."] + errors: [ + "The template root with 'src' attribute is required to be empty." + ] } ] }) diff --git a/tests/lib/rules/valid-v-bind-sync.js b/tests/lib/rules/valid-v-bind-sync.js index 4f939aa16..385f5d991 100644 --- a/tests/lib/rules/valid-v-bind-sync.js +++ b/tests/lib/rules/valid-v-bind-sync.js @@ -51,51 +51,63 @@ tester.run('valid-v-bind-sync', rule, { }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, // not .sync { @@ -128,12 +140,15 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers require the attribute value which is valid as LHS.", - line: 3, - column: 24, - endColumn: 41 - }] + errors: [ + { + message: + "'.sync' modifiers require the attribute value which is valid as LHS.", + line: 3, + column: 24, + endColumn: 41 + } + ] }, { filename: 'test.vue', @@ -142,12 +157,15 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers require the attribute value which is valid as LHS.", - line: 3, - column: 24, - endColumn: 47 - }] + errors: [ + { + message: + "'.sync' modifiers require the attribute value which is valid as LHS.", + line: 3, + column: 24, + endColumn: 47 + } + ] }, { filename: 'test.vue', @@ -156,12 +174,15 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers aren't supported on non Vue-components.", - line: 3, - column: 18, - endColumn: 33 - }] + errors: [ + { + message: + "'.sync' modifiers aren't supported on non Vue-components.", + line: 3, + column: 18, + endColumn: 33 + } + ] }, { filename: 'test.vue', @@ -170,12 +191,15 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers require the attribute value which is valid as LHS.", - line: 3, - column: 24, - endColumn: 41 - }] + errors: [ + { + message: + "'.sync' modifiers require the attribute value which is valid as LHS.", + line: 3, + column: 24, + endColumn: 41 + } + ] }, { filename: 'test.vue', @@ -184,12 +208,15 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers require the attribute value which is valid as LHS.", - line: 3, - column: 24, - endColumn: 46 - }] + errors: [ + { + message: + "'.sync' modifiers require the attribute value which is valid as LHS.", + line: 3, + column: 24, + endColumn: 46 + } + ] }, { filename: 'test.vue', @@ -198,12 +225,15 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers aren't supported on non Vue-components.", - line: 3, - column: 18, - endColumn: 39 - }] + errors: [ + { + message: + "'.sync' modifiers aren't supported on non Vue-components.", + line: 3, + column: 18, + endColumn: 39 + } + ] }, { filename: 'test.vue', @@ -214,12 +244,15 @@ tester.run('valid-v-bind-sync', rule, {
`, - errors: [{ - message: "'.sync' modifiers cannot update the iteration variable 'x' itself.", - line: 4, - column: 26, - endColumn: 39 - }] + errors: [ + { + message: + "'.sync' modifiers cannot update the iteration variable 'x' itself.", + line: 4, + column: 26, + endColumn: 39 + } + ] }, { filename: 'test.vue', @@ -230,12 +263,15 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers cannot update the iteration variable 'e' itself.", - line: 4, - column: 26, - endColumn: 45 - }] + errors: [ + { + message: + "'.sync' modifiers cannot update the iteration variable 'e' itself.", + line: 4, + column: 26, + endColumn: 45 + } + ] }, { filename: 'test.vue', @@ -250,10 +286,13 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers cannot update the iteration variable 'e1' itself.", - line: 6 - }] + errors: [ + { + message: + "'.sync' modifiers cannot update the iteration variable 'e1' itself.", + line: 6 + } + ] }, { filename: 'test.vue', @@ -264,10 +303,13 @@ tester.run('valid-v-bind-sync', rule, { `, - errors: [{ - message: "'.sync' modifiers cannot update the iteration variable 'index' itself.", - line: 4 - }] + errors: [ + { + message: + "'.sync' modifiers cannot update the iteration variable 'index' itself.", + line: 4 + } + ] }, { filename: 'test.vue', @@ -276,17 +318,23 @@ tester.run('valid-v-bind-sync', rule, {
`, - errors: ["'.sync' modifiers aren't supported on
non Vue-components."] + errors: [ + "'.sync' modifiers aren't supported on
non Vue-components." + ] }, { filename: 'test.vue', code: '', - errors: ["'.sync' modifiers require the attribute value which is valid as LHS."] + errors: [ + "'.sync' modifiers require the attribute value which is valid as LHS." + ] }, { filename: 'test.vue', code: '', - errors: ["'.sync' modifiers require the attribute value which is valid as LHS."] + errors: [ + "'.sync' modifiers require the attribute value which is valid as LHS." + ] } ] }) diff --git a/tests/lib/rules/valid-v-else-if.js b/tests/lib/rules/valid-v-else-if.js index b0c18093f..778d07339 100644 --- a/tests/lib/rules/valid-v-else-if.js +++ b/tests/lib/rules/valid-v-else-if.js @@ -29,11 +29,13 @@ tester.run('valid-v-else-if', rule, { }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', @@ -43,57 +45,82 @@ tester.run('valid-v-else-if', rule, { invalid: [ { filename: 'test.vue', - code: '', - errors: ["'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + code: + '', + errors: [ + "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', code: '', - errors: ["'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + errors: [ + "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', code: '', - errors: ["'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + errors: [ + "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + code: + '', + errors: [ + "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + code: + '', + errors: [ + "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + code: + '', + errors: [ + "'v-else-if' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else-if' and 'v-if' directives can't exist on the same element."] + code: + '', + errors: [ + "'v-else-if' and 'v-if' directives can't exist on the same element." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else-if' and 'v-else' directives can't exist on the same element."] + code: + '', + errors: [ + "'v-else-if' and 'v-else' directives can't exist on the same element." + ] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["'v-else-if' directives require no argument."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["'v-else-if' directives require no modifier."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["'v-else-if' directives require that attribute value."] } ] diff --git a/tests/lib/rules/valid-v-else.js b/tests/lib/rules/valid-v-else.js index 7825e4dfb..1e235f9b5 100644 --- a/tests/lib/rules/valid-v-else.js +++ b/tests/lib/rules/valid-v-else.js @@ -29,11 +29,13 @@ tester.run('valid-v-else', rule, { }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', @@ -44,56 +46,79 @@ tester.run('valid-v-else', rule, { { filename: 'test.vue', code: '', - errors: ["'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + errors: [ + "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', code: '', - errors: ["'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + errors: [ + "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', code: '', - errors: ["'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + errors: [ + "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', code: '', - errors: ["'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + errors: [ + "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + code: + '', + errors: [ + "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] + code: + '', + errors: [ + "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else' and 'v-if' directives can't exist on the same element. You may want 'v-else-if' directives."] + code: + '', + errors: [ + "'v-else' and 'v-if' directives can't exist on the same element. You may want 'v-else-if' directives." + ] }, { filename: 'test.vue', - code: '', - errors: ["'v-else' and 'v-else-if' directives can't exist on the same element."] + code: + '', + errors: [ + "'v-else' and 'v-else-if' directives can't exist on the same element." + ] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["'v-else' directives require no argument."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["'v-else' directives require no modifier."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["'v-else' directives require no attribute value."] } ] diff --git a/tests/lib/rules/valid-v-for.js b/tests/lib/rules/valid-v-for.js index d83b634a3..74a1ea614 100644 --- a/tests/lib/rules/valid-v-for.js +++ b/tests/lib/rules/valid-v-for.js @@ -37,55 +37,68 @@ tester.run('valid-v-for', rule, { }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', - code: '' + code: + '' }, { filename: 'test.vue', @@ -134,92 +147,123 @@ tester.run('valid-v-for', rule, { }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Invalid alias ''."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Invalid alias ''."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Invalid alias ''."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Invalid alias '{b,c}'."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Invalid alias '{c,d}'."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Custom elements in iteration require 'v-bind:key' directives."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Custom elements in iteration require 'v-bind:key' directives."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Custom elements in iteration require 'v-bind:key' directives."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Custom elements in iteration require 'v-bind:key' directives."] }, { filename: 'test.vue', - code: '', - errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] + code: + '', + errors: [ + "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] + code: + '', + errors: [ + "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] + code: + '', + errors: [ + "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] + code: + '', + errors: [ + "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + ] }, { filename: 'test.vue', - code: '', - errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] + code: + '', + errors: [ + "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + ] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["Custom elements in iteration require 'v-bind:key' directives."] }, { filename: 'test.vue', - code: '', + code: + '', errors: ["'v-for' directives require that attribute value."] }, { filename: 'test.vue', - code: '', - errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."] + code: + '', + errors: [ + "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + ] }, { filename: 'test.vue', - errors: ["Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive."], + errors: [ + "Expected 'v-bind:key' directive to use the variables which are defined by the 'v-for' directive." + ], code: ` ` + }, + // empty value + { + filename: 'empty-value.vue', + code: '', + errors: ["'v-for' directives require that attribute value."] } ] }) diff --git a/tests/lib/rules/valid-v-html.js b/tests/lib/rules/valid-v-html.js index 9a30bcf48..afb312f74 100644 --- a/tests/lib/rules/valid-v-html.js +++ b/tests/lib/rules/valid-v-html.js @@ -30,6 +30,16 @@ tester.run('valid-v-html', rule, { { filename: 'test.vue', code: '' + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '' + }, + // comment value (parsing error) + { + filename: 'comment-value.vue', + code: '' } ], invalid: [ @@ -47,6 +57,12 @@ tester.run('valid-v-html', rule, { filename: 'test.vue', code: '', errors: ["'v-html' directives require that attribute value."] + }, + // empty value + { + filename: 'empty-value.vue', + code: '', + errors: ["'v-html' directives require that attribute value."] } ] }) diff --git a/tests/lib/rules/valid-v-if.js b/tests/lib/rules/valid-v-if.js index effe04836..d3afe5780 100644 --- a/tests/lib/rules/valid-v-if.js +++ b/tests/lib/rules/valid-v-if.js @@ -30,6 +30,16 @@ tester.run('valid-v-if', rule, { { filename: 'test.vue', code: '' + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '' + }, + // comment value (parsing error) + { + filename: 'comment-value.vue', + code: '' } ], invalid: [ @@ -62,6 +72,12 @@ tester.run('valid-v-if', rule, { filename: 'test.vue', code: '', errors: ["'v-if' directives require that attribute value."] + }, + // empty value + { + filename: 'empty-value.vue', + code: '', + errors: ["'v-if' directives require that attribute value."] } ] }) diff --git a/tests/lib/rules/valid-v-model.js b/tests/lib/rules/valid-v-model.js index c9c28585a..9e78ef47a 100644 --- a/tests/lib/rules/valid-v-model.js +++ b/tests/lib/rules/valid-v-model.js @@ -150,6 +150,16 @@ tester.run('valid-v-model', rule, { filename: 'test.vue', code: '' + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '' + }, + // comment value (parsing error) + { + filename: 'comment-value.vue', + code: '' } ], invalid: [ @@ -216,6 +226,12 @@ tester.run('valid-v-model', rule, { errors: [ "'v-model' directives cannot update the iteration variable 'e' itself." ] + }, + // empty value + { + filename: 'empty-value.vue', + code: '', + errors: ["'v-model' directives require that attribute value."] } ] }) diff --git a/tests/lib/rules/valid-v-on.js b/tests/lib/rules/valid-v-on.js index 911039ea5..6f162e1df 100644 --- a/tests/lib/rules/valid-v-on.js +++ b/tests/lib/rules/valid-v-on.js @@ -96,6 +96,33 @@ tester.run('valid-v-on', rule, { filename: 'test.vue', code: '', options: [{ modifiers: ['bar', 'aaa'] }] + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '' + }, + // comment value (valid) + { + filename: 'comment-value.vue', + code: '' + }, + { + filename: 'comment-value.vue', + code: '' + }, + { + filename: 'comment-value.vue', + code: '' + }, + { + filename: 'comment-value.vue', + code: '' + }, + // empty value + { + filename: 'empty-value.vue', + code: '' } ], invalid: [ @@ -139,6 +166,14 @@ tester.run('valid-v-on', rule, { filename: 'test.vue', code: '', errors: ['Avoid using JavaScript keyword as "v-on" value: "delete".'] + }, + // empty value + { + filename: 'empty-value.vue', + code: '', + errors: [ + "'v-on' directives require a value or verb modifier (like 'stop' or 'prevent')." + ] } ] }) diff --git a/tests/lib/rules/valid-v-once.js b/tests/lib/rules/valid-v-once.js index 0c6a71a20..c9f3750c3 100644 --- a/tests/lib/rules/valid-v-once.js +++ b/tests/lib/rules/valid-v-once.js @@ -47,6 +47,24 @@ tester.run('valid-v-once', rule, { filename: 'test.vue', code: '', errors: ["'v-once' directives require no attribute value."] + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '', + errors: ["'v-once' directives require no attribute value."] + }, + // comment value + { + filename: 'comment-value.vue', + code: '', + errors: ["'v-once' directives require no attribute value."] + }, + // empty value + { + filename: 'comment-value.vue', + code: '', + errors: ["'v-once' directives require no attribute value."] } ] }) diff --git a/tests/lib/rules/valid-v-pre.js b/tests/lib/rules/valid-v-pre.js index ae9d38e6f..3d9c9d883 100644 --- a/tests/lib/rules/valid-v-pre.js +++ b/tests/lib/rules/valid-v-pre.js @@ -47,6 +47,24 @@ tester.run('valid-v-pre', rule, { filename: 'test.vue', code: '', errors: ["'v-pre' directives require no attribute value."] + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '', + errors: ["'v-pre' directives require no attribute value."] + }, + // comment value + { + filename: 'comment-value.vue', + code: '', + errors: ["'v-pre' directives require no attribute value."] + }, + // empty value + { + filename: 'empty-value.vue', + code: '', + errors: ["'v-pre' directives require no attribute value."] } ] }) diff --git a/tests/lib/rules/valid-v-show.js b/tests/lib/rules/valid-v-show.js index 0471ccd9f..4220e8749 100644 --- a/tests/lib/rules/valid-v-show.js +++ b/tests/lib/rules/valid-v-show.js @@ -30,6 +30,16 @@ tester.run('valid-v-show', rule, { { filename: 'test.vue', code: '' + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '' + }, + // comment value (parsing error) + { + filename: 'comment-value.vue', + code: '' } ], invalid: [ @@ -48,8 +58,9 @@ tester.run('valid-v-show', rule, { code: '', errors: ["'v-show' directives require that attribute value."] }, + // empty value { - filename: 'test.vue', + filename: 'empty-value.vue', code: '', errors: ["'v-show' directives require that attribute value."] } diff --git a/tests/lib/rules/valid-v-slot.js b/tests/lib/rules/valid-v-slot.js index ab8307fed..0043756f1 100644 --- a/tests/lib/rules/valid-v-slot.js +++ b/tests/lib/rules/valid-v-slot.js @@ -83,7 +83,13 @@ tester.run('valid-v-slot', rule, { - ` + `, + // parsing error + { + filename: 'parsing-error.vue', + code: + '' + } ], invalid: [ // Verify location. @@ -294,6 +300,26 @@ tester.run('valid-v-slot', rule, { `, errors: [{ messageId: 'requireAttributeValue' }] + }, + // comment value + { + filename: 'comment-value1.vue', + code: + '', + errors: [{ messageId: 'requireAttributeValue' }] + }, + { + filename: 'comment-value2.vue', + code: + '', + errors: [{ messageId: 'requireAttributeValue' }] + }, + // empty value + { + filename: 'empty-value.vue', + code: + '', + errors: [{ messageId: 'requireAttributeValue' }] } ] }) diff --git a/tests/lib/rules/valid-v-text.js b/tests/lib/rules/valid-v-text.js index 3956462ce..611b1a31a 100644 --- a/tests/lib/rules/valid-v-text.js +++ b/tests/lib/rules/valid-v-text.js @@ -34,6 +34,16 @@ tester.run('valid-v-text', rule, { { filename: 'test.vue', code: '' + }, + // parsing error + { + filename: 'parsing-error.vue', + code: '' + }, + // comment value (parsing error) + { + filename: 'parsing-error.vue', + code: '' } ], invalid: [ @@ -51,6 +61,12 @@ tester.run('valid-v-text', rule, { filename: 'test.vue', code: '', errors: ["'v-text' directives require that attribute value."] + }, + // empty value + { + filename: 'empty-value.vue', + code: '', + errors: ["'v-text' directives require that attribute value."] } ] }) From e5c835eb957340b153ea2047e3ba274b88ba01bb Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Fri, 5 Jun 2020 14:29:35 +0900 Subject: [PATCH 0546/1448] Add `vue/no-bare-strings-in-template` rule (#1185) --- docs/rules/README.md | 1 + docs/rules/no-bare-strings-in-template.md | 88 ++++++ lib/index.js | 1 + lib/rules/no-bare-strings-in-template.js | 279 +++++++++++++++++ lib/utils/regexp.js | 14 +- package.json | 2 + .../lib/rules/no-bare-strings-in-template.js | 290 ++++++++++++++++++ 7 files changed, 673 insertions(+), 2 deletions(-) create mode 100644 docs/rules/no-bare-strings-in-template.md create mode 100644 lib/rules/no-bare-strings-in-template.js create mode 100644 tests/lib/rules/no-bare-strings-in-template.js diff --git a/docs/rules/README.md b/docs/rules/README.md index f3e2bfdf6..55b3c4e0d 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -282,6 +282,7 @@ For example: | [vue/html-comment-content-spacing](./html-comment-content-spacing.md) | enforce unified spacing in HTML comments | :wrench: | | [vue/html-comment-indent](./html-comment-indent.md) | enforce consistent indentation in HTML comments | :wrench: | | [vue/match-component-file-name](./match-component-file-name.md) | require component name property to match its file name | | +| [vue/no-bare-strings-in-template](./no-bare-strings-in-template.md) | disallow the use of bare strings in ` `, - options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.' ] @@ -473,13 +473,13 @@ singleline element
`, - options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], output: ` `, + options: [{ ignoreWhenEmpty: false, ignoreWhenNoAttributes: false }], errors: [ 'Expected 1 line break after opening tag (`
`), but no line breaks found.' ] diff --git a/tests/lib/rules/space-in-parens.js b/tests/lib/rules/space-in-parens.js index 8791652ed..ef6fe628e 100644 --- a/tests/lib/rules/space-in-parens.js +++ b/tests/lib/rules/space-in-parens.js @@ -94,13 +94,13 @@ tester.run('space-in-parens', rule, { @click="foo(arg)" /> `, - options: ['always'], output: ` `, + options: ['always'], errors: [ errorMessage({ messageId: 'missingOpeningSpace', @@ -143,13 +143,13 @@ tester.run('space-in-parens', rule, { :value="(1 + 2) + 3" > `, - options: ['always'], output: ` `, + options: ['always'], errors: [ errorMessage({ messageId: 'missingOpeningSpace', @@ -192,13 +192,13 @@ tester.run('space-in-parens', rule, { :[(1+2)]="(1 + 2) + 3" > `, - options: ['always'], output: ` `, + options: ['always'], errors: [ errorMessage({ messageId: 'missingOpeningSpace', diff --git a/tests/lib/rules/space-unary-ops.js b/tests/lib/rules/space-unary-ops.js index 6b3e7c25f..63539a5a7 100644 --- a/tests/lib/rules/space-unary-ops.js +++ b/tests/lib/rules/space-unary-ops.js @@ -50,8 +50,8 @@ tester.run('space-unary-ops', rule, { }, { code: '', - options: [{ nonwords: true }], output: '', + options: [{ nonwords: true }], errors: ["Unary operator '!' must be followed by whitespace."] }, diff --git a/tests/lib/rules/template-curly-spacing.js b/tests/lib/rules/template-curly-spacing.js index 6c4376969..0fe530511 100644 --- a/tests/lib/rules/template-curly-spacing.js +++ b/tests/lib/rules/template-curly-spacing.js @@ -41,14 +41,13 @@ tester.run('template-curly-spacing', rule, { }, // CSS vars injection - { - code: ` + ` ` - } + + ` ], invalid: [ { @@ -79,12 +78,12 @@ tester.run('template-curly-spacing', rule, {
`, - options: ['always'], output: ` `, + options: ['always'], errors: [ { message: "Expected space(s) after '${'.", diff --git a/tests/lib/rules/this-in-template.js b/tests/lib/rules/this-in-template.js index 904aa00c4..5686bf137 100644 --- a/tests/lib/rules/this-in-template.js +++ b/tests/lib/rules/this-in-template.js @@ -248,14 +248,14 @@ ruleTester.run('this-in-template', rule, { { code: ``, output: ``, - errors: ["Unexpected usage of 'this'."], - options: ['never'] + options: ['never'], + errors: ["Unexpected usage of 'this'."] }, { code: ``, output: ``, - errors: ["Unexpected usage of 'this'."], - options: ['never'] + options: ['never'], + errors: ["Unexpected usage of 'this'."] } ] }) diff --git a/tests/lib/rules/use-v-on-exact.js b/tests/lib/rules/use-v-on-exact.js index 73ac2408b..929fd746a 100644 --- a/tests/lib/rules/use-v-on-exact.js +++ b/tests/lib/rules/use-v-on-exact.js @@ -15,92 +15,48 @@ const ruleTester = new RuleTester({ ruleTester.run('use-v-on-exact', rule, { valid: [ - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: `` - }, - { - code: ` + ` ], invalid: [ diff --git a/tests/lib/rules/v-bind-style.js b/tests/lib/rules/v-bind-style.js index 2fd1ce7c2..0cb67f62f 100644 --- a/tests/lib/rules/v-bind-style.js +++ b/tests/lib/rules/v-bind-style.js @@ -67,44 +67,44 @@ tester.run('v-bind-style', rule, { }, { filename: 'test.vue', - options: ['shorthand'], code: '', output: '', + options: ['shorthand'], errors: ["Unexpected 'v-bind' before ':'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind' before ':'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] }, { filename: 'test.vue', - options: ['longform'], code: '', output: '', + options: ['longform'], errors: ["Expected 'v-bind:' instead of '.'."] } ] diff --git a/tests/lib/rules/v-for-delimiter-style.js b/tests/lib/rules/v-for-delimiter-style.js index b1500af50..23665a32c 100644 --- a/tests/lib/rules/v-for-delimiter-style.js +++ b/tests/lib/rules/v-for-delimiter-style.js @@ -94,9 +94,9 @@ tester.run('v-for-delimiter-style', rule, { }, { filename: 'test.vue', - options: ['in'], code: '', output: '', + options: ['in'], errors: [ { message: "Expected 'in' instead of 'of' in 'v-for'.", @@ -106,9 +106,9 @@ tester.run('v-for-delimiter-style', rule, { }, { filename: 'test.vue', - options: ['of'], code: '', output: '', + options: ['of'], errors: [ { message: "Expected 'of' instead of 'in' in 'v-for'.", diff --git a/tests/lib/rules/v-on-event-hyphenation.js b/tests/lib/rules/v-on-event-hyphenation.js index 087e5d00a..beaa5e3fa 100644 --- a/tests/lib/rules/v-on-event-hyphenation.js +++ b/tests/lib/rules/v-on-event-hyphenation.js @@ -73,12 +73,12 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['always', { autofix: true }], output: ` `, + options: ['always', { autofix: true }], errors: [ { message: "v-on event '@customEvent' must be hyphenated.", @@ -95,12 +95,12 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['never', { autofix: true }], output: ` `, + options: ['never', { autofix: true }], errors: ["v-on event 'v-on:custom-event' can't be hyphenated."] }, { @@ -110,13 +110,13 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['always', { autofix: true }], output: ` `, + options: ['always', { autofix: true }], errors: ["v-on event '@update:modelValue' must be hyphenated."] }, { @@ -126,13 +126,13 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['never', { autofix: true }], output: ` `, + options: ['never', { autofix: true }], errors: ["v-on event '@update:model-value' can't be hyphenated."] }, { @@ -144,7 +144,6 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['always', { autofix: true }], output: ` `, + options: ['always', { autofix: true }], errors: [ "v-on event '@upDate:modelValue' must be hyphenated.", "v-on event '@up-date:modelValue' must be hyphenated.", @@ -168,7 +168,6 @@ tester.run('v-on-event-hyphenation', rule, { `, - options: ['never', { autofix: true }], output: ` `, + options: ['never', { autofix: true }], errors: [ "v-on event '@up-date:modelValue' can't be hyphenated.", "v-on event '@upDate:model-value' can't be hyphenated.", diff --git a/tests/lib/rules/v-on-function-call.js b/tests/lib/rules/v-on-function-call.js index d8486a448..d06bbe231 100644 --- a/tests/lib/rules/v-on-function-call.js +++ b/tests/lib/rules/v-on-function-call.js @@ -161,37 +161,37 @@ tester.run('v-on-function-call', rule, { filename: 'test.vue', code: '', output: null, + options: ['always'], errors: [ "Method calls inside of 'v-on' directives must have parentheses." - ], - options: ['always'] + ] }, { filename: 'test.vue', code: '', output: ``, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', code: '', output: ``, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', code: '', output: null, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -204,13 +204,13 @@ tester.run('v-on-function-call', rule, { ">
`, output: null, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -222,10 +222,10 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -237,10 +237,10 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -254,11 +254,11 @@ tester.run('v-on-function-call', rule, {
`, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses.", "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -270,10 +270,10 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -285,19 +285,19 @@ tester.run('v-on-function-call', rule, { `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', code: '', output: '', + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -319,10 +319,10 @@ tester.run('v-on-function-call', rule, { } } `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] }, { filename: 'test.vue', @@ -344,10 +344,10 @@ tester.run('v-on-function-call', rule, { } } `, + options: ['never'], errors: [ "Method calls without arguments inside of 'v-on' directives must not have parentheses." - ], - options: ['never'] + ] } ] }) diff --git a/tests/lib/rules/v-on-handler-style.js b/tests/lib/rules/v-on-handler-style.js index e3afd05d5..314bbf8c8 100644 --- a/tests/lib/rules/v-on-handler-style.js +++ b/tests/lib/rules/v-on-handler-style.js @@ -78,12 +78,12 @@ tester.run('v-on-handler-style', rule, {