From 9c53407c4120033d3bc4a17fe95e86334fa7f30a Mon Sep 17 00:00:00 2001 From: Pig Fang Date: Wed, 2 Jun 2021 08:34:12 +0800 Subject: [PATCH 1/8] Fix rules index for `require-emit-validator` (#1505) --- lib/rules/require-emit-validator.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rules/require-emit-validator.js b/lib/rules/require-emit-validator.js index c85ee42ad..9d6e5d7f1 100644 --- a/lib/rules/require-emit-validator.js +++ b/lib/rules/require-emit-validator.js @@ -20,7 +20,7 @@ module.exports = { type: 'suggestion', docs: { description: 'require type definitions in emits', - categories: [], + categories: undefined, url: 'https://eslint.vuejs.org/rules/require-emit-validator.html' }, fixable: null, From e1815cdce18fcba4a96ae1077a73d2e79ad5e3f1 Mon Sep 17 00:00:00 2001 From: yosuke ota Date: Wed, 2 Jun 2021 09:35:12 +0900 Subject: [PATCH 2/8] Update docs --- docs/rules/README.md | 1 + docs/rules/require-emit-validator.md | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 9717d49ae..d38c44a2b 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -321,6 +321,7 @@ For example: | [vue/no-useless-v-bind](./no-useless-v-bind.md) | disallow unnecessary `v-bind` directives | :wrench: | | [vue/padding-line-between-blocks](./padding-line-between-blocks.md) | require or disallow padding lines between blocks | :wrench: | | [vue/require-direct-export](./require-direct-export.md) | require the component to be directly exported | | +| [vue/require-emit-validator](./require-emit-validator.md) | require type definitions in emits | | | [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 ` `, - errors: [ - { - message: - 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', - line: 4, - suggestions: [ - { - desc: 'Instead, change to `beforeUnmount`.', - output: ` + output: ` - ` - } - ] + `, + errors: [ + { + message: + 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', + line: 4 }, { message: 'The `destroyed` lifecycle hook is deprecated. Use `unmounted` instead.', - line: 5, - suggestions: [ - { - desc: 'Instead, change to `unmounted`.', - output: ` - - ` - } - ] + line: 5 } ] }, @@ -160,42 +142,24 @@ ruleTester.run('no-deprecated-destroyed-lifecycle', rule, { } `, - errors: [ - { - message: - 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', - line: 4, - suggestions: [ - { - desc: 'Instead, change to `beforeUnmount`.', - output: ` + output: ` - ` - } - ] + `, + errors: [ + { + message: + 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', + line: 4 }, { message: 'The `destroyed` lifecycle hook is deprecated. Use `unmounted` instead.', - line: 5, - suggestions: [ - { - desc: 'Instead, change to `unmounted`.', - output: ` - - ` - } - ] + line: 5 } ] }, @@ -218,15 +182,7 @@ ruleTester.run('no-deprecated-destroyed-lifecycle', rule, { } `, - errors: [ - { - message: - 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', - line: 12, - suggestions: [ - { - desc: 'Instead, change to `beforeUnmount`.', - output: ` + output: ` - ` - } - ] + `, + errors: [ + { + message: + 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', + line: 12 }, { message: 'The `destroyed` lifecycle hook is deprecated. Use `unmounted` instead.', - line: 13, - suggestions: [ - { - desc: 'Instead, change to `unmounted`.', - output: ` - - ` - } - ] + line: 13 } ] }, @@ -285,42 +222,24 @@ ruleTester.run('no-deprecated-destroyed-lifecycle', rule, { } `, - errors: [ - { - message: - 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', - line: 4, - suggestions: [ - { - desc: 'Instead, change to `beforeUnmount`.', - output: ` + output: ` - ` - } - ] + `, + errors: [ + { + message: + 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', + line: 4 }, { message: 'The `destroyed` lifecycle hook is deprecated. Use `unmounted` instead.', - line: 5, - suggestions: [ - { - desc: 'Instead, change to `unmounted`.', - output: ` - - ` - } - ] + line: 5 } ] }, @@ -334,42 +253,24 @@ ruleTester.run('no-deprecated-destroyed-lifecycle', rule, { } `, - errors: [ - { - message: - 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', - line: 4, - suggestions: [ - { - desc: 'Instead, change to `beforeUnmount`.', - output: ` + output: ` - ` - } - ] + `, + errors: [ + { + message: + 'The `beforeDestroy` lifecycle hook is deprecated. Use `beforeUnmount` instead.', + line: 4 }, { message: 'The `destroyed` lifecycle hook is deprecated. Use `unmounted` instead.', - line: 5, - suggestions: [ - { - desc: 'Instead, change to `unmounted`.', - output: ` - - ` - } - ] + line: 5 } ] } From 76f835ac3f794218954131d3c4b4625da7a8e5aa Mon Sep 17 00:00:00 2001 From: Przemyslaw Jan Beigert Date: Wed, 9 Jun 2021 09:38:51 +0200 Subject: [PATCH 4/8] feat(no-this-in-before-router-enter): create rule (#1506) * feat(no-this-in-before-router-enter): create rule * Update lib/rules/no-this-in-before-route-enter.js Co-authored-by: Yosuke Ota * Update docs/rules/no-this-in-before-route-enter.md Co-authored-by: Yosuke Ota * feat(no-this-in-before-router-enter): create rule Update lib/rules/no-this-in-before-route-enter.js Co-authored-by: Yosuke Ota Update docs/rules/no-this-in-before-route-enter.md Co-authored-by: Yosuke Ota * (feat): update test assertions for no-this-in-before-route-enter rule * (feat): update docs for no-this-in-before-route-enter Co-authored-by: Yosuke Ota --- docs/rules/README.md | 1 + docs/rules/no-this-in-before-route-enter.md | 115 +++++++++++ lib/index.js | 1 + lib/rules/no-this-in-before-route-enter.js | 91 +++++++++ .../rules/no-this-in-before-route-enter.js | 190 ++++++++++++++++++ 5 files changed, 398 insertions(+) create mode 100644 docs/rules/no-this-in-before-route-enter.md create mode 100644 lib/rules/no-this-in-before-route-enter.js create mode 100644 tests/lib/rules/no-this-in-before-route-enter.js diff --git a/docs/rules/README.md b/docs/rules/README.md index d38c44a2b..16185b231 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -313,6 +313,7 @@ For example: | [vue/no-restricted-v-bind](./no-restricted-v-bind.md) | disallow specific argument in `v-bind` | | | [vue/no-static-inline-styles](./no-static-inline-styles.md) | disallow static inline `style` attributes | | | [vue/no-template-target-blank](./no-template-target-blank.md) | disallow target="_blank" attribute without rel="noopener noreferrer" | | +| [vue/no-this-in-before-route-enter](./no-this-in-before-route-enter.md) | disallow this usage in a beforeRouteEnter method | | | [vue/no-unregistered-components](./no-unregistered-components.md) | disallow using components that are not registered inside templates | | | [vue/no-unsupported-features](./no-unsupported-features.md) | disallow unsupported Vue.js syntax on the specified version | :wrench: | | [vue/no-unused-properties](./no-unused-properties.md) | disallow unused properties | | diff --git a/docs/rules/no-this-in-before-route-enter.md b/docs/rules/no-this-in-before-route-enter.md new file mode 100644 index 000000000..7409b48ea --- /dev/null +++ b/docs/rules/no-this-in-before-route-enter.md @@ -0,0 +1,115 @@ +--- +pageClass: rule-details +sidebarDepth: 0 +title: vue/no-this-in-before-route-enter +description: disallow this usage in a beforeRouteEnter method +--- +# vue/no-this-in-before-route-enter + +> disallow this usage in a beforeRouteEnter method + +- :exclamation: ***This rule has not been released yet.*** + +## Rule Details + +Because lack of `this` in the `beforeRouteEnter` [(docs)](https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards). This behavior isn't obvious, so it's pretty easy to make a `TypeError`. Especially during some refactor. + +Bad: + + + +```vue + +``` + + + +Bad: + + + +```vue + +``` + + + +Bad: + + + +```vue + +``` + + + + +Bad: + + + +```vue + +``` + + + +Good: + + + +```vue + +``` + + + +### Options + +Nothing. + +## When Not To Use It + +When [vue-router](https://router.vuejs.org/) is not installed. + +## Further Reading + +[vue-router - in-component-guards](https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards) + +## :mag: Implementation + +- [Rule source](https://github.com/vuejs/eslint-plugin-vue/blob/master/lib/rules/no-this-in-before-route-enter.js) +- [Test source](https://github.com/vuejs/eslint-plugin-vue/blob/master/tests/lib/rules/no-this-in-before-route-enter.js) diff --git a/lib/index.js b/lib/index.js index 1379e284e..20ecde959 100644 --- a/lib/index.js +++ b/lib/index.js @@ -113,6 +113,7 @@ module.exports = { 'no-template-shadow': require('./rules/no-template-shadow'), 'no-template-target-blank': require('./rules/no-template-target-blank'), 'no-textarea-mustache': require('./rules/no-textarea-mustache'), + 'no-this-in-before-route-enter': require('./rules/no-this-in-before-route-enter'), 'no-unregistered-components': require('./rules/no-unregistered-components'), 'no-unsupported-features': require('./rules/no-unsupported-features'), 'no-unused-components': require('./rules/no-unused-components'), diff --git a/lib/rules/no-this-in-before-route-enter.js b/lib/rules/no-this-in-before-route-enter.js new file mode 100644 index 000000000..968f45c18 --- /dev/null +++ b/lib/rules/no-this-in-before-route-enter.js @@ -0,0 +1,91 @@ +/** + * @fileoverview Don't use this in a beforeRouteEnter method + * @author Przemyslaw Jan Beigert + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +const utils = require('../utils') + +// ------------------------------------------------------------------------------ +// Rule Definition +// ------------------------------------------------------------------------------ + +module.exports = { + meta: { + type: 'problem', + docs: { + description: 'disallow this usage in a beforeRouteEnter method', + categories: null, + url: 'https://eslint.vuejs.org/rules/no-this-in-before-route-enter.html' + }, + fixable: null, + schema: [], + messages: { + disallow: + "'beforeRouteEnter' does NOT have access to `this` component instance. https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards." + } + }, + /** @param {RuleContext} context */ + create(context) { + /** + * @typedef {object} ScopeStack + * @property {ScopeStack | null} upper + * @property {FunctionExpression | FunctionDeclaration} node + * @property {boolean} beforeRouteEnter + */ + /** @type {Set} */ + const beforeRouteEnterFunctions = new Set() + /** @type {ScopeStack | null} */ + let scopeStack = null + + /** + * @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node + */ + function onFunctionEnter(node) { + if (node.type === 'ArrowFunctionExpression') { + return + } + scopeStack = { + upper: scopeStack, + node, + beforeRouteEnter: beforeRouteEnterFunctions.has( + /** @type {never} */ (node) + ) + } + } + + /** + * @param {FunctionExpression | FunctionDeclaration | ArrowFunctionExpression} node + */ + function onFunctionExit(node) { + if (scopeStack && scopeStack.node === node) { + scopeStack = scopeStack.upper + } + } + return utils.defineVueVisitor(context, { + onVueObjectEnter(node) { + const beforeRouteEnter = utils.findProperty(node, 'beforeRouteEnter') + if ( + beforeRouteEnter && + beforeRouteEnter.value.type === 'FunctionExpression' + ) { + beforeRouteEnterFunctions.add(beforeRouteEnter.value) + } + }, + ':function': onFunctionEnter, + ':function:exit': onFunctionExit, + ThisExpression(node) { + if (scopeStack && scopeStack.beforeRouteEnter) { + context.report({ + node, + messageId: 'disallow' + }) + } + } + }) + } +} diff --git a/tests/lib/rules/no-this-in-before-route-enter.js b/tests/lib/rules/no-this-in-before-route-enter.js new file mode 100644 index 000000000..1171959ae --- /dev/null +++ b/tests/lib/rules/no-this-in-before-route-enter.js @@ -0,0 +1,190 @@ +/** + * @fileoverview Don't use "this" i a beforeRouteEnter method + * @author Przemyslaw Jan Beigert + */ +'use strict' + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const rule = require('../../../lib/rules/no-this-in-before-route-enter') +const RuleTester = require('eslint').RuleTester + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const template = (beforeRouteEnter) => ` + + + + +` + +const functionTemplate = (beforeRouteEnter) => ` + + +` + +const ruleTester = new RuleTester({ + parser: require.resolve('vue-eslint-parser'), + parserOptions: { ecmaVersion: 2020, sourceType: 'module' } +}) +ruleTester.run('no-this-in-before-route-enter', rule, { + valid: [ + template(''), + template('const variable = 42;'), + template('someFunction(42)'), + ` + + + ` }, + { + filename: 'test.vue', + code: ` + + + ` + }, { filename: 'test.vue', code: ` @@ -706,6 +719,48 @@ tester.run('no-unregistered-components', rule, { line: 3 } ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: 'The "foo" component has been used but not registered.', + line: 3 + } + ] + }, + { + filename: 'test.vue', + code: ` + + + `, + errors: [ + { + message: 'The "foo" component has been used but not registered.', + line: 3 + } + ] } ] }) diff --git a/tests/lib/rules/no-unsupported-features/is-attribute-with-vue-prefix.js b/tests/lib/rules/no-unsupported-features/is-attribute-with-vue-prefix.js new file mode 100644 index 000000000..adcc64835 --- /dev/null +++ b/tests/lib/rules/no-unsupported-features/is-attribute-with-vue-prefix.js @@ -0,0 +1,64 @@ +/** + * @author Yosuke Ota + * See LICENSE file in root directory for full license. + */ +'use strict' + +const RuleTester = require('eslint').RuleTester +const rule = require('../../../../lib/rules/no-unsupported-features') +const utils = require('./utils') + +const buildOptions = utils.optionsBuilder( + 'is-attribute-with-vue-prefix', + '^3.1.0' +) +const tester = new RuleTester({ + parser: require.resolve('vue-eslint-parser'), + parserOptions: { + ecmaVersion: 2019 + } +}) + +tester.run('no-unsupported-features/is-attribute-with-vue-prefix', rule, { + valid: [ + { + code: ` + `, + options: buildOptions() + }, + { + code: ` + `, + options: buildOptions({ version: '^2.5.0' }) + }, + { + code: ` + `, + options: buildOptions({ + version: '^2.5.0', + ignores: ['is-attribute-with-vue-prefix'] + }) + } + ], + invalid: [ + { + code: ` + `, + options: buildOptions({ version: '^3.0.0' }), + errors: [ + { + message: '`is="vue:"` are not supported until Vue.js "3.1.0".', + line: 3 + } + ] + } + ] +}) diff --git a/tests/lib/rules/no-unused-components.js b/tests/lib/rules/no-unused-components.js index 02cb1a3cf..f63b75f13 100644 --- a/tests/lib/rules/no-unused-components.js +++ b/tests/lib/rules/no-unused-components.js @@ -486,6 +486,21 @@ tester.run('no-unused-components', rule, { } ` + }, + { + filename: 'test.vue', + code: ` + + + ` } ], invalid: [ From a4ac565521d416ba8aff25223fd639ff91285e23 Mon Sep 17 00:00:00 2001 From: Yosuke Ota Date: Wed, 9 Jun 2021 18:10:15 +0900 Subject: [PATCH 7/8] Format documents (#1511) --- docs/rules/README.md | 6 +- .../no-deprecated-destroyed-lifecycle.md | 3 +- .../rules/no-deprecated-props-default-this.md | 4 +- docs/rules/no-deprecated-v-is.md | 9 ++- docs/rules/no-this-in-before-route-enter.md | 67 +++---------------- docs/rules/no-unsupported-features.md | 1 + docs/rules/valid-v-is.md | 3 + lib/rules/no-deprecated-props-default-this.js | 3 +- lib/rules/no-this-in-before-route-enter.js | 2 +- lib/rules/valid-v-is.js | 2 + 10 files changed, 33 insertions(+), 67 deletions(-) diff --git a/docs/rules/README.md b/docs/rules/README.md index 914242d1c..a93d5a640 100644 --- a/docs/rules/README.md +++ b/docs/rules/README.md @@ -42,7 +42,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi | [vue/no-arrow-functions-in-watch](./no-arrow-functions-in-watch.md) | disallow using arrow functions to define watcher | | | [vue/no-async-in-computed-properties](./no-async-in-computed-properties.md) | disallow asynchronous actions in computed properties | | | [vue/no-deprecated-data-object-declaration](./no-deprecated-data-object-declaration.md) | disallow using deprecated object declaration on data (in Vue.js 3.0.0+) | :wrench: | -| [vue/no-deprecated-destroyed-lifecycle](./no-deprecated-destroyed-lifecycle.md) | disallow using deprecated `destroyed` and `beforeDestroy` lifecycle hooks (in Vue.js 3.0.0+) | | +| [vue/no-deprecated-destroyed-lifecycle](./no-deprecated-destroyed-lifecycle.md) | disallow using deprecated `destroyed` and `beforeDestroy` lifecycle hooks (in Vue.js 3.0.0+) | :wrench: | | [vue/no-deprecated-dollar-listeners-api](./no-deprecated-dollar-listeners-api.md) | disallow using deprecated `$listeners` (in Vue.js 3.0.0+) | | | [vue/no-deprecated-dollar-scopedslots-api](./no-deprecated-dollar-scopedslots-api.md) | disallow using deprecated `$scopedSlots` (in Vue.js 3.0.0+) | :wrench: | | [vue/no-deprecated-events-api](./no-deprecated-events-api.md) | disallow using deprecated events api (in Vue.js 3.0.0+) | | @@ -50,7 +50,7 @@ Enforce all the rules in this category, as well as all higher priority rules, wi | [vue/no-deprecated-functional-template](./no-deprecated-functional-template.md) | disallow using deprecated the `functional` template (in Vue.js 3.0.0+) | | | [vue/no-deprecated-html-element-is](./no-deprecated-html-element-is.md) | disallow using deprecated the `is` attribute on HTML elements (in Vue.js 3.0.0+) | | | [vue/no-deprecated-inline-template](./no-deprecated-inline-template.md) | disallow using deprecated `inline-template` attribute (in Vue.js 3.0.0+) | | -| [vue/no-deprecated-props-default-this](./no-deprecated-props-default-this.md) | disallow props default function `this` access | | +| [vue/no-deprecated-props-default-this](./no-deprecated-props-default-this.md) | disallow deprecated `this` access in props default function (in Vue.js 3.0.0+) | | | [vue/no-deprecated-scope-attribute](./no-deprecated-scope-attribute.md) | disallow deprecated `scope` attribute (in Vue.js 2.5.0+) | :wrench: | | [vue/no-deprecated-slot-attribute](./no-deprecated-slot-attribute.md) | disallow deprecated `slot` attribute (in Vue.js 2.6.0+) | :wrench: | | [vue/no-deprecated-slot-scope-attribute](./no-deprecated-slot-scope-attribute.md) | disallow deprecated `slot-scope` attribute (in Vue.js 2.6.0+) | :wrench: | @@ -314,7 +314,7 @@ For example: | [vue/no-restricted-v-bind](./no-restricted-v-bind.md) | disallow specific argument in `v-bind` | | | [vue/no-static-inline-styles](./no-static-inline-styles.md) | disallow static inline `style` attributes | | | [vue/no-template-target-blank](./no-template-target-blank.md) | disallow target="_blank" attribute without rel="noopener noreferrer" | | -| [vue/no-this-in-before-route-enter](./no-this-in-before-route-enter.md) | disallow this usage in a beforeRouteEnter method | | +| [vue/no-this-in-before-route-enter](./no-this-in-before-route-enter.md) | disallow `this` usage in a `beforeRouteEnter` method | | | [vue/no-unregistered-components](./no-unregistered-components.md) | disallow using components that are not registered inside templates | | | [vue/no-unsupported-features](./no-unsupported-features.md) | disallow unsupported Vue.js syntax on the specified version | :wrench: | | [vue/no-unused-properties](./no-unused-properties.md) | disallow unused properties | | diff --git a/docs/rules/no-deprecated-destroyed-lifecycle.md b/docs/rules/no-deprecated-destroyed-lifecycle.md index 37f8c0fe1..c99a7670a 100644 --- a/docs/rules/no-deprecated-destroyed-lifecycle.md +++ b/docs/rules/no-deprecated-destroyed-lifecycle.md @@ -10,12 +10,13 @@ since: v7.0.0 > disallow using deprecated `destroyed` and `beforeDestroy` lifecycle hooks (in Vue.js 3.0.0+) - :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `"plugin:vue/vue3-strongly-recommended"` and `"plugin:vue/vue3-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 reports use of deprecated `destroyed` and `beforeDestroy` lifecycle hooks. (in Vue.js 3.0.0+). - + ```vue -``` - - - -Bad: - ```vue -``` - - - -Bad: - - - -```vue - -``` - - - - -Bad: - - - -```vue -