From c42935879d5edc63834e2a4ab66087a84b0b54d5 Mon Sep 17 00:00:00 2001 From: Rohan Talip Date: Thu, 15 Aug 2019 21:39:00 -0700 Subject: [PATCH 0001/1063] Updated attributes-order.md: "ex:" --> "e.g." (#941) "ex" is far less common an abbreviation for "example" than "e.g." I also deleted some trailing whitespace. --- docs/rules/attributes-order.md | 36 +++++++++++++++++----------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/docs/rules/attributes-order.md b/docs/rules/attributes-order.md index 2f41dfa63..8c61d3688 100644 --- a/docs/rules/attributes-order.md +++ b/docs/rules/attributes-order.md @@ -15,27 +15,27 @@ description: enforce order of attributes This rule aims to enforce ordering of component attributes. The default order is specified in the [Vue styleguide](https://vuejs.org/v2/style-guide/#Element-attribute-order-recommended) and is: - `DEFINITION` - ex: 'is' + e.g. 'is' - `LIST_RENDERING` - ex: 'v-for item in items' + e.g. 'v-for item in items' - `CONDITIONALS` - ex: 'v-if', 'v-else-if', 'v-else', 'v-show', 'v-cloak' + e.g. 'v-if', 'v-else-if', 'v-else', 'v-show', 'v-cloak' - `RENDER_MODIFIERS` - ex: 'v-once', 'v-pre' + e.g. 'v-once', 'v-pre' - `GLOBAL` - ex: 'id' + e.g. 'id' - `UNIQUE` - ex: 'ref', 'key', 'v-slot', 'slot' + e.g. 'ref', 'key', 'v-slot', 'slot' - `TWO_WAY_BINDING` - ex: 'v-model' + e.g. 'v-model' - `OTHER_DIRECTIVES` - ex: 'v-custom-directive' + e.g. 'v-custom-directive' - `OTHER_ATTR` - ex: 'custom-prop="foo"', 'v-bind:prop="foo"', ':prop="foo"' + e.g. 'custom-prop="foo"', 'v-bind:prop="foo"', ':prop="foo"' - `EVENTS` - ex: '@click="functionCall"', 'v-on="event"' + e.g. '@click="functionCall"', 'v-on="event"' - `CONTENT` - ex: 'v-text', 'v-html' + e.g. 'v-text', 'v-html' ### the default order @@ -96,14 +96,14 @@ This rule aims to enforce ordering of component attributes. The default order is "order": [ "DEFINITION", "LIST_RENDERING", - "CONDITIONALS", + "CONDITIONALS", "RENDER_MODIFIERS", - "GLOBAL", - "UNIQUE", - "TWO_WAY_BINDING", - "OTHER_DIRECTIVES", - "OTHER_ATTR", - "EVENTS", + "GLOBAL", + "UNIQUE", + "TWO_WAY_BINDING", + "OTHER_DIRECTIVES", + "OTHER_ATTR", + "EVENTS", "CONTENT" ] }] From ba68ae74d74b1b7a09c9d75d2b725d0c37aa5cbd Mon Sep 17 00:00:00 2001 From: Connor Pearson Date: Fri, 16 Aug 2019 06:40:03 +0200 Subject: [PATCH 0002/1063] fix(use-v-on-exact): Don't flag events with different key codes (#904) --- lib/rules/use-v-on-exact.js | 37 +++++++++++++++++++++++++++---- tests/lib/rules/use-v-on-exact.js | 21 ++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/lib/rules/use-v-on-exact.js b/lib/rules/use-v-on-exact.js index bf194fd8e..29862b845 100644 --- a/lib/rules/use-v-on-exact.js +++ b/lib/rules/use-v-on-exact.js @@ -11,6 +11,7 @@ const utils = require('../utils') const SYSTEM_MODIFIERS = new Set(['ctrl', 'shift', 'alt', 'meta']) +const GLOBAL_MODIFIERS = new Set(['stop', 'prevent', 'capture', 'self', 'once', 'passive', 'native']) // ------------------------------------------------------------------------------ // Helpers @@ -36,6 +37,16 @@ function getEventDirectives (attributes, sourceCode) { })) } +/** + * Checks whether given modifier is key modifier + * + * @param {string} modifier + * @returns {boolean} + */ +function isKeyModifier (modifier) { + return !GLOBAL_MODIFIERS.has(modifier) && !SYSTEM_MODIFIERS.has(modifier) +} + /** * Checks whether given modifier is system one * @@ -86,6 +97,16 @@ function getSystemModifiersString (modifiers) { return modifiers.filter(isSystemModifier).sort().join(',') } +/** + * Creates alphabetically sorted string with key modifiers + * + * @param {array[string]} modifiers + * @returns {string} e.g. "enter,tab" + */ +function getKeyModifiersString (modifiers) { + return modifiers.filter(isKeyModifier).sort().join(',') +} + /** * Compares two events based on their modifiers * to detect possible event leakeage @@ -100,13 +121,21 @@ function hasConflictedModifiers (baseEvent, event) { event.modifiers.includes('exact') ) return false - const eventModifiers = getSystemModifiersString(event.modifiers) - const baseEventModifiers = getSystemModifiersString(baseEvent.modifiers) + const eventKeyModifiers = getKeyModifiersString(event.modifiers) + const baseEventKeyModifiers = getKeyModifiersString(baseEvent.modifiers) + + if ( + eventKeyModifiers && baseEventKeyModifiers && + eventKeyModifiers !== baseEventKeyModifiers + ) return false + + const eventSystemModifiers = getSystemModifiersString(event.modifiers) + const baseEventSystemModifiers = getSystemModifiersString(baseEvent.modifiers) return ( baseEvent.modifiers.length >= 1 && - baseEventModifiers !== eventModifiers && - baseEventModifiers.indexOf(eventModifiers) > -1 + baseEventSystemModifiers !== eventSystemModifiers && + baseEventSystemModifiers.indexOf(eventSystemModifiers) > -1 ) } diff --git a/tests/lib/rules/use-v-on-exact.js b/tests/lib/rules/use-v-on-exact.js index 6d9948266..726662ca8 100644 --- a/tests/lib/rules/use-v-on-exact.js +++ b/tests/lib/rules/use-v-on-exact.js @@ -158,6 +158,27 @@ ruleTester.run('use-v-on-exact', rule, { }, { code: `` + }, + { + code: `` + }, + { + code: `` + }, + { + code: `` } ], From 6a00fa8d0ff0d94eaa985ed3b4d4b02c67ec9574 Mon Sep 17 00:00:00 2001 From: Philipp Bosch Date: Fri, 16 Aug 2019 06:40:25 +0200 Subject: [PATCH 0003/1063] Fix: typo in valid-v-else rule (#937) * Fix: typo in valid-v-else rule * Fix: typo in valid-v-else rule --- lib/rules/valid-v-else.js | 2 +- tests/lib/rules/valid-v-else.js | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/rules/valid-v-else.js b/lib/rules/valid-v-else.js index e54122377..b0a09cb28 100644 --- a/lib/rules/valid-v-else.js +++ b/lib/rules/valid-v-else.js @@ -36,7 +36,7 @@ module.exports = { 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." + message: "'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive." }) } if (utils.hasDirective(element, 'if')) { diff --git a/tests/lib/rules/valid-v-else.js b/tests/lib/rules/valid-v-else.js index 7d112a8c2..7825e4dfb 100644 --- a/tests/lib/rules/valid-v-else.js +++ b/tests/lib/rules/valid-v-else.js @@ -44,32 +44,32 @@ 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' 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' 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' 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' 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' 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' directive."] + errors: ["'v-else' directives require being preceded by the element which has a 'v-if' or 'v-else-if' directive."] }, { filename: 'test.vue', From a6177067224d72994f9419c467909aa4ec2d9e57 Mon Sep 17 00:00:00 2001 From: Preom Rahman Date: Thu, 15 Aug 2019 23:51:54 -0500 Subject: [PATCH 0004/1063] Update README.md (#936) --- docs/user-guide/README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/user-guide/README.md b/docs/user-guide/README.md index 2c7bcfdb6..abf2390c9 100644 --- a/docs/user-guide/README.md +++ b/docs/user-guide/README.md @@ -71,6 +71,7 @@ If you want to use custom parsers such as [babel-eslint](https://www.npmjs.com/p ```diff - "parser": "babel-eslint", ++ "parser": "vue-eslint-parser", "parserOptions": { + "parser": "babel-eslint", "sourceType": "module" From cb2e367ce7b869ba34ec7bec3a9b6adafb6ea48c Mon Sep 17 00:00:00 2001 From: Takayoshi Sawada Date: Fri, 16 Aug 2019 13:54:00 +0900 Subject: [PATCH 0005/1063] fix: update vue-eslint-parser (#895) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e55bf568e..3f6573ea6 100755 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "eslint": "^5.0.0 || ^6.0.0" }, "dependencies": { - "vue-eslint-parser": "^6.0.2" + "vue-eslint-parser": "^6.0.4" }, "devDependencies": { "@types/node": "^4.2.16", From d822a0313016c52db82f88c73a7b6a6fe8539cd6 Mon Sep 17 00:00:00 2001 From: fisker Cheung Date: Fri, 16 Aug 2019 12:54:27 +0800 Subject: [PATCH 0006/1063] pref: improve traverse (#912) * pref: improve traverse * ci: trigger build * Remove throw trick --- lib/rules/order-in-components.js | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js index 5702c22e5..db057143b 100644 --- a/lib/rules/order-in-components.js +++ b/lib/rules/order-in-components.js @@ -97,11 +97,14 @@ function isNotSideEffectsNode (node, visitorKeys) { traverseNodes(node, { visitorKeys, enterNode (node, parent) { - if (!result || noSideEffectsNodes.has(node)) { + if (!result) { return } if ( + // parent has no side effects + noSideEffectsNodes.has(parent) || + // no side effects node node.type === 'FunctionExpression' || node.type === 'Identifier' || node.type === 'Literal' || @@ -109,15 +112,7 @@ function isNotSideEffectsNode (node, visitorKeys) { node.type === 'ArrowFunctionExpression' || node.type === 'TemplateElement' ) { - // no side effects node noSideEffectsNodes.add(node) - traverseNodes(node, { - visitorKeys, - enterNode (node) { - noSideEffectsNodes.add(node) - }, - leaveNode () {} - }) } else if ( node.type !== 'Property' && node.type !== 'ObjectExpression' && @@ -137,6 +132,7 @@ function isNotSideEffectsNode (node, visitorKeys) { }, leaveNode () {} }) + return result } From 27fc35c8323cfceeafd3129f03129998f9ddd424 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20Ch=C5=82odnicki?= Date: Sat, 17 Aug 2019 03:02:34 +0200 Subject: [PATCH 0007/1063] chore: Keep Nuxt's 'asyncData' and 'fetch' with 'data' (#823) * chore: Keep Nuxt's 'asyncData' and 'fetch' with 'data' Change the order of asyncData and fetch properties to be next to data property. All those are function-wise more or less equivalent so IMO it makes sense to keep them together. asyncData and fetch are primarily for setting up component's data. * Update order per review * Add also 'head' property * Change order of 'head' --- docs/rules/order-in-components.md | 3 +++ lib/rules/order-in-components.js | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/docs/rules/order-in-components.md b/docs/rules/order-in-components.md index c28e283b4..d215cf1ee 100644 --- a/docs/rules/order-in-components.md +++ b/docs/rules/order-in-components.md @@ -74,11 +74,14 @@ export default { "inheritAttrs", "model", ["props", "propsData"], + "fetch", + "asyncData", "data", "computed", "watch", "LIFECYCLE_HOOKS", "methods", + "head", ["template", "render"], "renderError" ] diff --git a/lib/rules/order-in-components.js b/lib/rules/order-in-components.js index db057143b..5f2c4ecd8 100644 --- a/lib/rules/order-in-components.js +++ b/lib/rules/order-in-components.js @@ -19,13 +19,14 @@ const defaultOrder = [ 'inheritAttrs', 'model', ['props', 'propsData'], + 'fetch', + 'asyncData', 'data', 'computed', 'watch', - 'asyncData', - 'fetch', 'LIFECYCLE_HOOKS', 'methods', + 'head', ['template', 'render'], 'renderError' ] From 1d12b93e510c475433ec61ef9257bec2cd467c3c Mon Sep 17 00:00:00 2001 From: gebeuhler Date: Mon, 26 Aug 2019 09:42:55 -0500 Subject: [PATCH 0008/1063] typo (#947) --- docs/rules/no-dupe-keys.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/rules/no-dupe-keys.md b/docs/rules/no-dupe-keys.md index 2cbed8ebb..f139792d2 100644 --- a/docs/rules/no-dupe-keys.md +++ b/docs/rules/no-dupe-keys.md @@ -51,7 +51,7 @@ export default { } ``` -- `"groups"` (`string[]`) Array of additional groups to search for duplicates. Defailt is empty. +- `"groups"` (`string[]`) Array of additional groups to search for duplicates. Default is empty. ### `"groups": ["firebase"]` From e59eb0986e54bf9e03d09d5c1c0368d63912af9e Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 18 Sep 2019 21:31:53 +0900 Subject: [PATCH 0009/1063] Fixed jsx parsing error (#961) * Fixed jsx parsing error refs https://github.com/eslint/eslint/issues/11018 * Fixed parsing error in eslint@5. * Changed the definition of JOB. --- .circleci/config.yml | 12 ++++++------ package.json | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2da27550d..c60601bce 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -58,17 +58,17 @@ jobs: - run: name: Install dependencies command: npm install + - save_cache: + key: v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }} + paths: + - node_modules - run: name: Install eslint 5 command: | # We need to execute this command twice because of npm's bug. # See also: https://npm.community/t/error-node-modules-staging-eslint-e7cf6846-node-modules-eslint - npm install eslint@5.0.0 --no-save - npm install eslint@5.0.0 --no-save + npm install eslint@5.0.0 acorn@6.0.7 --no-save + npm install eslint@5.0.0 acorn@6.0.7 --no-save - run: name: Test command: npm test - - save_cache: - key: v2-npm-lock-{{ .Branch }}-{{ .Environment.CIRCLE_JOB }}-{{ checksum "package.json" }} - paths: - - node_modules diff --git a/package.json b/package.json index 3f6573ea6..8246a88b8 100755 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "devDependencies": { "@types/node": "^4.2.16", "@typescript-eslint/parser": "^1.11.0", + "acorn": "^7.0.0", "babel-eslint": "^10.0.2", "chai": "^4.1.0", "eslint": "^6.0.0", From 3836af4cac1db79a5e33c8a6464b2bd9670a9494 Mon Sep 17 00:00:00 2001 From: Chris Fritz Date: Sun, 22 Sep 2019 03:27:13 -0400 Subject: [PATCH 0010/1063] Fix: register v-slot-style and valid-v-slot (#880) --- lib/index.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/index.js b/lib/index.js index 6c727f241..d2d3d0e15 100644 --- a/lib/index.js +++ b/lib/index.js @@ -75,6 +75,7 @@ module.exports = { 'v-bind-style': require('./rules/v-bind-style'), 'v-on-function-call': require('./rules/v-on-function-call'), 'v-on-style': require('./rules/v-on-style'), + 'v-slot-style': require('./rules/v-slot-style'), 'valid-template-root': require('./rules/valid-template-root'), 'valid-v-bind': require('./rules/valid-v-bind'), 'valid-v-cloak': require('./rules/valid-v-cloak'), @@ -88,6 +89,7 @@ module.exports = { 'valid-v-once': require('./rules/valid-v-once'), 'valid-v-pre': require('./rules/valid-v-pre'), 'valid-v-show': require('./rules/valid-v-show'), + 'valid-v-slot': require('./rules/valid-v-slot'), 'valid-v-text': require('./rules/valid-v-text') }, configs: { From edf43ffe1c56db99c81d8eaa62de36b2fa47604e Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Thu, 26 Sep 2019 08:30:12 +0900 Subject: [PATCH 0011/1063] Drop autofix of prop-name-casing. (#940) * Drop autofix of prop-name-casing. * Fixed eslint error --- docs/rules/README.md | 2 +- docs/rules/prop-name-casing.md | 5 +-- lib/rules/prop-name-casing.js | 23 +---------- tests/lib/rules/prop-name-casing.js | 59 ----------------------------- 4 files changed, 5 insertions(+), 84 deletions(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 97117319f..a47600386 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -98,7 +98,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi | [vue/no-multi-spaces](./no-multi-spaces.md) | disallow multiple spaces | :wrench: | | [vue/no-spaces-around-equal-signs-in-attribute](./no-spaces-around-equal-signs-in-attribute.md) | disallow spaces around equal signs in attribute | :wrench: | | [vue/no-template-shadow](./no-template-shadow.md) | disallow variable declarations from shadowing variables declared in the outer scope | | -| [vue/prop-name-casing](./prop-name-casing.md) | enforce specific casing for the Prop name in Vue components | :wrench: | +| [vue/prop-name-casing](./prop-name-casing.md) | enforce specific casing for the Prop name in Vue components | | | [vue/require-default-prop](./require-default-prop.md) | require default value for props | | | [vue/require-prop-types](./require-prop-types.md) | require type definitions in props | | | [vue/singleline-html-element-content-newline](./singleline-html-element-content-newline.md) | require a line break before and after the contents of a singleline element | :wrench: | diff --git a/docs/rules/prop-name-casing.md b/docs/rules/prop-name-casing.md index 846766c66..def33cd5e 100644 --- a/docs/rules/prop-name-casing.md +++ b/docs/rules/prop-name-casing.md @@ -8,13 +8,12 @@ description: enforce specific casing for the Prop name in Vue components > enforce specific casing for the Prop name in Vue components - :gear: This rule is included in `"plugin:vue/strongly-recommended"` and `"plugin:vue/recommended"`. -- :wrench: The `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the problems reported by this rule. ## :book: Rule Details This rule enforce proper casing of props in vue components(camelCase). - + ```vue +``` + + + +## :wrench: Options + +Nothing. + +## :mag: Implementation + +- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/require-name-property.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/require-name-property.js) diff --git a/lib/rules/require-name-property.js b/lib/rules/require-name-property.js new file mode 100644 index 000000000..126c1bfe6 --- /dev/null +++ b/lib/rules/require-name-property.js @@ -0,0 +1,37 @@ +/** + * @fileoverview Require a name property in Vue components + * @author LukeeeeBennett + */ +'use strict' + +const utils = require('../utils') + +function isNameProperty (node) { + return node.type === 'Property' && + node.key.name === 'name' && + !node.computed +} + +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'require a name property in Vue components', + category: undefined, + url: 'https://eslint.vuejs.org/rules/require-name-property.html' + }, + fixable: null, + schema: [] + }, + + create (context) { + return utils.executeOnVue(context, component => { + if (component.properties.some(isNameProperty)) return + + context.report({ + node: component, + message: 'Required name property is not set.' + }) + }) + } +} diff --git a/tests/lib/rules/require-name-property.js b/tests/lib/rules/require-name-property.js new file mode 100644 index 000000000..7b55e2400 --- /dev/null +++ b/tests/lib/rules/require-name-property.js @@ -0,0 +1,102 @@ +/** + * @fileoverview Require a name property in Vue components + * @author LukeeeeBennett + */ +'use strict' + +const rule = require('../../../lib/rules/require-name-property') +const RuleTester = require('eslint').RuleTester + +const parserOptions = { + ecmaVersion: 2018, + sourceType: 'module' +} + +const ruleTester = new RuleTester() +ruleTester.run('require-name-property', rule, { + valid: [ + { + filename: 'ValidComponent.vue', + code: ` + export default { + name: 'IssaName' + } + `, + parserOptions + }, + { + filename: 'ValidComponent.vue', + code: ` + export default { + name: undefined + } + `, + parserOptions + }, + { + filename: 'ValidComponent.vue', + code: ` + export default { + name: '' + } + `, + parserOptions + } + ], + + invalid: [ + { + filename: 'InvalidComponent.vue', + code: ` + export default { + } + `, + parserOptions, + errors: [{ + message: 'Required name property is not set.', + type: 'ObjectExpression' + }] + }, + { + filename: 'InvalidComponent.vue', + code: ` + export default { + nameNot: 'IssaNameNot' + } + `, + parserOptions, + errors: [{ + message: 'Required name property is not set.', + type: 'ObjectExpression' + }] + }, + { + filename: 'InvalidComponent.vue', + code: ` + export default { + computed: { + name() { return 'name' } + } + } + `, + parserOptions, + errors: [{ + message: 'Required name property is not set.', + type: 'ObjectExpression' + }] + }, + { + filename: 'InvalidComponent.vue', + code: ` + export default { + [name]: 'IssaName' + } + `, + parserOptions, + errors: [{ + message: 'Required name property is not set.', + type: 'ObjectExpression' + }] + } + ] +}) From b19843c698110d9dfb08fe8dffdbd0aaffbcce36 Mon Sep 17 00:00:00 2001 From: Jake Date: Wed, 25 Dec 2019 22:27:37 -0500 Subject: [PATCH 0026/1063] =?UTF-8?q?=20=E2=AD=90=EF=B8=8F=20New:=20Add=20?= =?UTF-8?q?rule=20`no-reserved-component-names`=20(#757)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :star: add rule no-reserved-component-names * Increase test coverage * Checking elements against element lists * :hammer: Update PR with ota-meshi suggestions * :hammer: Lint locally registered components * :ok_hand: Adding tests to validate slot and template * :hammer: Linting for deprecated elements --- docs/rules/no-reserved-component-names.md | 28 ++ lib/rules/no-reserved-component-names.js | 125 ++++++ lib/utils/deprecated-html-elements.json | 1 + .../lib/rules/no-reserved-component-names.js | 375 ++++++++++++++++++ 4 files changed, 529 insertions(+) create mode 100644 docs/rules/no-reserved-component-names.md create mode 100644 lib/rules/no-reserved-component-names.js create mode 100644 lib/utils/deprecated-html-elements.json create mode 100644 tests/lib/rules/no-reserved-component-names.js diff --git a/docs/rules/no-reserved-component-names.md b/docs/rules/no-reserved-component-names.md new file mode 100644 index 000000000..57a008592 --- /dev/null +++ b/docs/rules/no-reserved-component-names.md @@ -0,0 +1,28 @@ +# vue/no-reserved-component-names +> disallow the use of reserved names in component definitions + +- :gear: This rule is included in all of `"plugin:vue/essential"`, `"plugin:vue/recommended"`, and `"plugin:vue/strongly-recommended"`. + +## :book: Rule Details + +This rule prevents name collisions between vue components and standard html elements. + + + +```vue + +``` + + + +## :books: Further reading + +- [List of html elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element) +- [List of SVG elements](https://developer.mozilla.org/en-US/docs/Web/SVG/Element) +- [Kebab case elements](https://stackoverflow.com/questions/22545621/do-custom-elements-require-a-dash-in-their-name/22545622#22545622) +- [Valid custom element name](https://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name) \ No newline at end of file diff --git a/lib/rules/no-reserved-component-names.js b/lib/rules/no-reserved-component-names.js new file mode 100644 index 000000000..c08b34f5d --- /dev/null +++ b/lib/rules/no-reserved-component-names.js @@ -0,0 +1,125 @@ +/** + * @fileoverview disallow the use of reserved names in component definitions + * @author Jake Hassel + */ +'use strict' + +const utils = require('../utils') +const casing = require('../utils/casing') + +const htmlElements = require('../utils/html-elements.json') +const deprecatedHtmlElements = require('../utils/deprecated-html-elements.json') +const svgElements = require('../utils/svg-elements.json') + +const kebabCaseElements = [ + 'annotation-xml', + 'color-profile', + 'font-face', + 'font-face-src', + 'font-face-uri', + 'font-face-format', + 'font-face-name', + 'missing-glyph' +] + +const isLowercase = (word) => /^[a-z]*$/.test(word) +const capitalizeFirstLetter = (word) => word[0].toUpperCase() + word.substring(1, word.length) + +const RESERVED_NAMES = new Set( + [ + ...kebabCaseElements, + ...kebabCaseElements.map(casing.pascalCase), + ...htmlElements, + ...htmlElements.map(capitalizeFirstLetter), + ...deprecatedHtmlElements, + ...deprecatedHtmlElements.map(capitalizeFirstLetter), + ...svgElements, + ...svgElements.filter(isLowercase).map(capitalizeFirstLetter) + ]) + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'disallow the use of reserved names in component definitions', + category: undefined, // 'essential' + url: 'https://eslint.vuejs.org/rules/no-reserved-component-names.html' + }, + fixable: null, + schema: [] + }, + + create (context) { + function canVerify (node) { + return node.type === 'Literal' || ( + node.type === 'TemplateLiteral' && + node.expressions.length === 0 && + node.quasis.length === 1 + ) + } + + function reportIfInvalid (node) { + let name + if (node.type === 'TemplateLiteral') { + const quasis = node.quasis[0] + name = quasis.value.cooked + } else { + name = node.value + } + if (RESERVED_NAMES.has(name)) { + report(node, name) + } + } + + function report (node, name) { + context.report({ + node: node, + message: 'Name "{{name}}" is reserved.', + data: { + name: name + } + }) + } + + return Object.assign({}, + { + "CallExpression > MemberExpression > Identifier[name='component']" (node) { + const parent = node.parent.parent + const calleeObject = utils.unwrapTypes(parent.callee.object) + + if (calleeObject.type === 'Identifier' && + calleeObject.name === 'Vue' && + parent.arguments && + parent.arguments.length === 2 + ) { + const argument = parent.arguments[0] + + if (canVerify(argument)) { + reportIfInvalid(argument) + } + } + } + }, + utils.executeOnVue(context, (obj) => { + // Report if a component has been registered locally with a reserved name. + utils.getRegisteredComponents(obj) + .filter(({ name }) => RESERVED_NAMES.has(name)) + .forEach(({ node, name }) => report(node, name)) + + const node = obj.properties + .find(item => ( + item.type === 'Property' && + item.key.name === 'name' && + canVerify(item.value) + )) + + if (!node) return + reportIfInvalid(node.value) + }) + ) + } +} diff --git a/lib/utils/deprecated-html-elements.json b/lib/utils/deprecated-html-elements.json new file mode 100644 index 000000000..daf23f512 --- /dev/null +++ b/lib/utils/deprecated-html-elements.json @@ -0,0 +1 @@ +["acronym","applet","basefont","bgsound","big","blink","center","command","content","dir","element","font","frame","frameset","image","isindex","keygen","listing","marquee","menuitem","multicol","nextid","nobr","noembed","noframes","plaintext","shadow","spacer","strike","tt","xmp"] \ No newline at end of file diff --git a/tests/lib/rules/no-reserved-component-names.js b/tests/lib/rules/no-reserved-component-names.js new file mode 100644 index 000000000..6d592396d --- /dev/null +++ b/tests/lib/rules/no-reserved-component-names.js @@ -0,0 +1,375 @@ +/** + * @fileoverview disallow the use of reserved names in component definitions + * @author Jake Hassel + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/no-reserved-component-names') +const RuleTester = require('eslint').RuleTester + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const invalidElements = [ + 'annotation-xml', 'AnnotationXml', + 'color-profile', 'ColorProfile', + 'font-face', 'FontFace', + 'font-face-src', 'FontFaceSrc', + 'font-face-uri', 'FontFaceUri', + 'font-face-format', 'FontFaceFormat', + 'font-face-name', 'FontFaceName', + 'missing-glyph', 'MissingGlyph', + 'html', 'Html', + 'body', 'Body', + 'base', 'Base', + 'head', 'Head', + 'link', 'Link', + 'meta', 'Meta', + 'style', 'Style', + 'title', 'Title', + 'address', 'Address', + 'article', 'Article', + 'aside', 'Aside', + 'footer', 'Footer', + 'header', 'Header', + 'h1', 'H1', + 'h2', 'H2', + 'h3', 'H3', + 'h4', 'H4', + 'h5', 'H5', + 'h6', 'H6', + 'hgroup', 'Hgroup', + 'nav', 'Nav', + 'section', 'Section', + 'div', 'Div', + 'dd', 'Dd', + 'dl', 'Dl', + 'dt', 'Dt', + 'figcaption', 'Figcaption', + 'figure', 'Figure', + 'hr', 'Hr', + 'img', 'Img', + 'li', 'Li', + 'main', 'Main', + 'ol', 'Ol', + 'p', 'P', + 'pre', 'Pre', + 'ul', 'Ul', + 'a', 'A', + 'b', 'B', + 'abbr', 'Abbr', + 'bdi', 'Bdi', + 'bdo', 'Bdo', + 'br', 'Br', + 'cite', 'Cite', + 'code', 'Code', + 'data', 'Data', + 'dfn', 'Dfn', + 'em', 'Em', + 'i', 'I', + 'kbd', 'Kbd', + 'mark', 'Mark', + 'q', 'Q', + 'rp', 'Rp', + 'rt', 'Rt', + 'rtc', 'Rtc', + 'ruby', 'Ruby', + 's', 'S', + 'samp', 'Samp', + 'small', 'Small', + 'span', 'Span', + 'strong', 'Strong', + 'sub', 'Sub', + 'sup', 'Sup', + 'time', 'Time', + 'u', 'U', + 'var', 'Var', + 'wbr', 'Wbr', + 'area', 'Area', + 'audio', 'Audio', + 'map', 'Map', + 'track', 'Track', + 'video', 'Video', + 'embed', 'Embed', + 'object', 'Object', + 'param', 'Param', + 'source', 'Source', + 'canvas', 'Canvas', + 'script', 'Script', + 'noscript', 'Noscript', + 'del', 'Del', + 'ins', 'Ins', + 'caption', 'Caption', + 'col', 'Col', + 'colgroup', 'Colgroup', + 'table', 'Table', + 'thead', 'Thead', + 'tbody', 'Tbody', + 'tfoot', 'Tfoot', + 'td', 'Td', + 'th', 'Th', + 'tr', 'Tr', + 'button', 'Button', + 'datalist', 'Datalist', + 'fieldset', 'Fieldset', + 'form', 'Form', + 'input', 'Input', + 'label', 'Label', + 'legend', 'Legend', + 'meter', 'Meter', + 'optgroup', 'Optgroup', + 'option', 'Option', + 'output', 'Output', + 'progress', 'Progress', + 'select', 'Select', + 'textarea', 'Textarea', + 'details', 'Details', + 'dialog', 'Dialog', + 'menu', 'Menu', + 'menuitem', 'menuitem', + 'summary', 'Summary', + 'content', 'Content', + 'element', 'Element', + 'shadow', 'Shadow', + 'template', 'Template', + 'slot', 'Slot', + 'blockquote', 'Blockquote', + 'iframe', 'Iframe', + 'noframes', 'Noframes', + 'picture', 'Picture', + + // SVG elements + 'animate', 'Animate', + 'animateMotion', + 'animateTransform', + 'circle', 'Circle', + 'clipPath', + 'defs', 'Defs', + 'desc', 'Desc', + 'discard', 'Discard', + 'ellipse', 'Ellipse', + 'feBlend', + 'feColorMatrix', + 'feComponentTransfer', + 'feComposite', + 'feConvolveMatrix', + 'feDiffuseLighting', + 'feDisplacementMap', + 'feDistantLight', + 'feDropShadow', + 'feFlood', + 'feFuncA', + 'feFuncB', + 'feFuncG', + 'feFuncR', + 'feGaussianBlur', + 'feImage', + 'feMerge', + 'feMergeNode', + 'feMorphology', + 'feOffset', + 'fePointLight', + 'feSpecularLighting', + 'feSpotLight', + 'feTile', + 'feTurbulence', + 'filter', 'Filter', + 'foreignObject', + 'g', 'G', + 'image', 'Image', + 'line', 'Line', + 'linearGradient', + 'marker', 'Marker', + 'mask', 'Mask', + 'metadata', 'Metadata', + 'mpath', 'Mpath', + 'path', 'Path', + 'pattern', 'Pattern', + 'polygon', 'Polygon', + 'polyline', 'Polyline', + 'radialGradient', + 'rect', 'Rect', + 'set', 'Set', + 'stop', 'Stop', + 'svg', 'Svg', + 'switch', 'Switch', + 'symbol', 'Symbol', + 'text', 'Text', + 'textPath', + 'tspan', 'Tspan', + 'unknown', 'Unknown', + 'use', 'Use', + 'view', 'View', + + // Deprecated + 'acronym', 'Acronym', + 'applet', 'Applet', + 'basefont', 'Basefont', + 'bgsound', 'Bgsound', + 'big', 'Big', + 'blink', 'Blink', + 'center', 'Center', + 'command', 'Command', + 'dir', 'Dir', + 'font', 'Font', + 'frame', 'Frame', + 'frameset', 'Frameset', + 'isindex', 'Isindex', + 'keygen', 'Keygen', + 'listing', 'Listing', + 'marquee', 'Marquee', + 'multicol', 'Multicol', + 'nextid', 'Nextid', + 'nobr', 'Nobr', + 'noembed', 'Noembed', + 'plaintext', 'Plaintext', + 'spacer', 'Spacer', + 'strike', 'Strike', + 'tt', 'Tt', + 'xmp', 'Xmp' +] + +const parserOptions = { + ecmaVersion: 2018, + sourceType: 'module' +} + +const ruleTester = new RuleTester() +ruleTester.run('no-reserved-component-names', rule, { + + valid: [ + { + filename: 'test.vue', + code: ` + export default { + } + `, + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + ...name + } + `, + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + name: 'FooBar' + } + `, + parserOptions + }, + { + filename: 'test.vue', + code: `Vue.component('FooBar', {})`, + parserOptions + }, + { + filename: 'test.js', + code: ` + new Vue({ + name: 'foo!bar' + }) + `, + parserOptions + }, + { + filename: 'test.vue', + code: `Vue.component(\`fooBar\${foo}\`, component)`, + parserOptions + }, + { + filename: 'test.vue', + code: ` + + `, + parser: 'vue-eslint-parser', + parserOptions + }, + { + filename: 'test.vue', + code: ` + + `, + parser: 'vue-eslint-parser', + parserOptions + } + ], + + invalid: [ + ...invalidElements.map(name => { + return { + filename: `${name}.vue`, + code: ` + export default { + name: '${name}' + } + `, + parserOptions, + errors: [{ + message: `Name "${name}" is reserved.`, + type: 'Literal', + line: 3 + }] + } + }), + ...invalidElements.map(name => { + return { + filename: 'test.vue', + code: `Vue.component('${name}', component)`, + parserOptions, + errors: [{ + message: `Name "${name}" is reserved.`, + type: 'Literal', + line: 1 + }] + } + }), + ...invalidElements.map(name => { + return { + filename: 'test.vue', + code: `Vue.component(\`${name}\`, {})`, + parserOptions, + errors: [{ + message: `Name "${name}" is reserved.`, + type: 'TemplateLiteral', + line: 1 + }] + } + }), + ...invalidElements.map(name => { + return { + filename: 'test.vue', + code: `export default { + components: { + '${name}': {}, + } + }`, + parserOptions, + errors: [{ + message: `Name "${name}" is reserved.`, + type: 'Property', + line: 3 + }] + } + }) + ] +}) From 8d7cadf0344b24787a30477f243c0292fa4ca512 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Thu, 26 Dec 2019 12:55:47 +0900 Subject: [PATCH 0027/1063] Change document style for new rules added & Fixed new rule test cases to work with eslint v6 (#1011) --- docs/rules/README.md | 2 ++ docs/rules/no-reserved-component-names.md | 15 +++++++++++--- docs/rules/require-name-property.md | 20 +++++++++++++++++-- docs/rules/static-class-names-order.md | 10 +++++----- lib/index.js | 2 ++ .../lib/rules/no-reserved-component-names.js | 4 ++-- 6 files changed, 41 insertions(+), 12 deletions(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 520e84fcb..b77661eb0 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -154,9 +154,11 @@ For example: | [vue/no-boolean-default](./no-boolean-default.md) | disallow boolean defaults | :wrench: | | [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: | | [vue/no-empty-pattern](./no-empty-pattern.md) | disallow empty destructuring patterns | | +| [vue/no-reserved-component-names](./no-reserved-component-names.md) | disallow the use of reserved names in component definitions | | | [vue/no-restricted-syntax](./no-restricted-syntax.md) | disallow specified syntax | | | [vue/object-curly-spacing](./object-curly-spacing.md) | enforce consistent spacing inside braces | :wrench: | | [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | | +| [vue/require-name-property](./require-name-property.md) | require a name property in Vue components | | | [vue/script-indent](./script-indent.md) | enforce consistent indentation in ` +``` + + + + +```vue + +``` + + + + +```vue + `, - parser: 'vue-eslint-parser', + parser: require.resolve('vue-eslint-parser'), parserOptions }, { @@ -309,7 +309,7 @@ ruleTester.run('no-reserved-component-names', rule, { } `, - parser: 'vue-eslint-parser', + parser: require.resolve('vue-eslint-parser'), parserOptions } ], From c360057d4e6fce2375d0e2b9ca353ce733073b60 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Thu, 26 Dec 2019 12:58:12 +0900 Subject: [PATCH 0028/1063] =?UTF-8?q?=E2=AD=90=EF=B8=8FNew:=20Add=20`vue/c?= =?UTF-8?q?omponent-tags-order`=20rule=20(#763)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * ⭐️New: Add `vue/component-tags-order` rule * Upgrade vue-eslint-parser@^7.0.0 * Use parserServices.getDocumentFragment --- docs/rules/README.md | 1 + docs/rules/component-tags-order.md | 96 +++++++++++ lib/index.js | 1 + lib/rules/component-tags-order.js | 93 ++++++++++ tests/lib/rules/component-tags-order.js | 217 ++++++++++++++++++++++++ 5 files changed, 408 insertions(+) create mode 100644 docs/rules/component-tags-order.md create mode 100644 lib/rules/component-tags-order.js create mode 100644 tests/lib/rules/component-tags-order.js diff --git a/docs/rules/README.md b/docs/rules/README.md index b77661eb0..481f39099 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -146,6 +146,7 @@ For example: | [vue/camelcase](./camelcase.md) | enforce camelcase naming convention | | | [vue/comma-dangle](./comma-dangle.md) | require or disallow trailing commas | :wrench: | | [vue/component-name-in-template-casing](./component-name-in-template-casing.md) | enforce specific casing for the component naming style in template | :wrench: | +| [vue/component-tags-order](./component-tags-order.md) | enforce order of component top-level elements | | | [vue/dot-location](./dot-location.md) | enforce consistent newlines before and after dots | :wrench: | | [vue/eqeqeq](./eqeqeq.md) | require the use of `===` and `!==` | :wrench: | | [vue/key-spacing](./key-spacing.md) | enforce consistent spacing between keys and values in object literal properties | :wrench: | diff --git a/docs/rules/component-tags-order.md b/docs/rules/component-tags-order.md new file mode 100644 index 000000000..d8c45447b --- /dev/null +++ b/docs/rules/component-tags-order.md @@ -0,0 +1,96 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/component-tags-order +description: enforce order of component top-level elements +--- +# vue/component-tags-order +> enforce order of component top-level elements + +## :book: Rule Details + +This rule warns about the order of the ` + + +``` + + + + + +```vue + + + + +``` + + + +### `{ "order": ["template", "script", "style"] }` + + + +```vue + + + + +``` + + + +### `{ "order": ["docs", "template", "script", "style"] }` + + + +```vue + + documents + + + +``` + + + + + +```vue + + + + documents + +``` + + + +## :books: Further reading + +- [Style guide - Single-file component top-level element order](https://vuejs.org/v2/style-guide/#Single-file-component-top-level-element-order-recommended) + +## :mag: Implementation + +- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/component-tags-order.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/component-tags-order.js) diff --git a/lib/index.js b/lib/index.js index 8a2fd8033..28343da6d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -17,6 +17,7 @@ module.exports = { 'comma-dangle': require('./rules/comma-dangle'), 'comment-directive': require('./rules/comment-directive'), 'component-name-in-template-casing': require('./rules/component-name-in-template-casing'), + 'component-tags-order': require('./rules/component-tags-order'), 'dot-location': require('./rules/dot-location'), 'eqeqeq': require('./rules/eqeqeq'), 'html-closing-bracket-newline': require('./rules/html-closing-bracket-newline'), diff --git a/lib/rules/component-tags-order.js b/lib/rules/component-tags-order.js new file mode 100644 index 000000000..6f63c2cf0 --- /dev/null +++ b/lib/rules/component-tags-order.js @@ -0,0 +1,93 @@ +/** + * @author Yosuke Ota + * issue https://github.com/vuejs/eslint-plugin-vue/issues/140 + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +const DEFAULT_ORDER = Object.freeze(['script', 'template', 'style']) + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: 'suggestion', + docs: { + description: 'enforce order of component top-level elements', + category: undefined, + url: 'https://eslint.vuejs.org/rules/component-tags-order.html' + }, + fixable: null, + schema: { + type: 'array', + properties: { + order: { + type: 'array' + } + } + }, + messages: { + unexpected: 'The <{{name}}> should be above the <{{firstUnorderedName}}> on line {{line}}.' + } + }, + create (context) { + const order = (context.options[0] && context.options[0].order) || DEFAULT_ORDER + const documentFragment = context.parserServices.getDocumentFragment && context.parserServices.getDocumentFragment() + + function getTopLevelHTMLElements () { + if (documentFragment) { + return documentFragment.children + } + return [] + } + + function report (element, firstUnorderedElement) { + context.report({ + node: element, + loc: element.loc, + messageId: 'unexpected', + data: { + name: element.name, + firstUnorderedName: firstUnorderedElement.name, + line: firstUnorderedElement.loc.start.line + } + }) + } + + return utils.defineTemplateBodyVisitor( + context, + {}, + { + Program (node) { + if (utils.hasInvalidEOF(node)) { + return + } + const elements = getTopLevelHTMLElements() + + elements.forEach((element, index) => { + const expectedIndex = order.indexOf(element.name) + if (expectedIndex < 0) { + return + } + const firstUnordered = elements + .slice(0, index) + .filter(e => expectedIndex < order.indexOf(e.name)) + .sort( + (e1, e2) => order.indexOf(e1.name) - order.indexOf(e2.name) + )[0] + if (firstUnordered) { + report(element, firstUnordered) + } + }) + } + } + ) + } +} diff --git a/tests/lib/rules/component-tags-order.js b/tests/lib/rules/component-tags-order.js new file mode 100644 index 000000000..a9108fb76 --- /dev/null +++ b/tests/lib/rules/component-tags-order.js @@ -0,0 +1,217 @@ +/** + * @author Yosuke Ota + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/component-tags-order') +const RuleTester = require('eslint').RuleTester + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +const tester = new RuleTester({ + parser: require.resolve('vue-eslint-parser') +}) + +tester.run('component-tags-order', rule, { + valid: [ + // default + '', + '', + '', + '', + '', + ` + + + + + + `, + + // order + { + code: '', + output: null, + options: [{ order: ['template', 'script', 'style'] }] + }, + { + code: '', + output: null, + options: [{ order: ['style', 'template', 'script'] }] + }, + { + code: '', + output: null, + options: [{ order: ['template', 'docs', 'script', 'style'] }] + }, + { + code: '', + output: null, + options: [{ order: ['template', 'script', 'style'] }] + }, + { + code: '
text

', + output: null, + options: [{ order: ['docs', 'script', 'template', 'style'] }] + }, + + ``, + + // Invalid EOF + ' `, - 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 0161/1063] 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, {