From c283697d824c84759ae78a7d60235c4663b782a8 Mon Sep 17 00:00:00 2001 From: Przemyslaw Jan Beigert Date: Wed, 2 Jun 2021 19:51:26 +0200 Subject: [PATCH] feat(no-this-in-before-router-enter): create rule --- docs/rules/no-this-in-before-route-enter.md | 72 ++++++++++ lib/index.js | 1 + lib/rules/no-this-in-before-route-enter.js | 88 ++++++++++++ .../rules/no-this-in-before-route-enter.js | 132 ++++++++++++++++++ 4 files changed, 293 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/no-this-in-before-route-enter.md b/docs/rules/no-this-in-before-route-enter.md new file mode 100644 index 000000000..6bfd82321 --- /dev/null +++ b/docs/rules/no-this-in-before-route-enter.md @@ -0,0 +1,72 @@ +# vue/no-this-in-before-route-enter + +> This rule prevents usage this in the "beforeRouteEnter" because this is undefined there. https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards + +## Rule Details + +Bad: +```js + +``` + +Bad: +```js + +``` + +Bad: +```js + +``` + +Good: +```js + +``` + +### Options + +If there are any options, describe them here. Otherwise, delete this section. + +## When Not To Use It + +Give a short description of when it would be appropriate to turn off this rule. + +## Further Reading + +[vue-router - in-component-guards](https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards) + +## :rocket: Version + +This rule was introduced in eslint-plugin-vue 7.11.0 + +## :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 d38cff322..090cd395b 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': 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..feb7753d9 --- /dev/null +++ b/lib/rules/no-this-in-before-route-enter.js @@ -0,0 +1,88 @@ +/** + * @fileoverview Don't use this in a beforeRouteEnter method + * @author Przemyslaw Jan Beigert + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Rule Definition +//------------------------------------------------------------------------------ + +const utils = require('../utils'); + +"use strict"; +/** + * @param {FunctionExpression | BlockStatement | Property | ThisExpression} obj + * @returns {boolean} + */ +function deepFindThisExpression(obj) { + if (typeof obj !== 'object' || !obj) { + return false; + } + if (obj.type === 'ThisExpression') { + return true; + } + + /** @param {typeof obj} key */ + return Object.entries(obj).some(([key, value]) => { + if (key === 'parent') { + return false; + } + if (Array.isArray(value)) { + return value.some(item => deepFindThisExpression(item)); + } + if (typeof value === 'object') { + return deepFindThisExpression(value); + } + + return false; + }) +} + +/** + * @param {Property | SpreadElement} property + * @returns {property is Property} + */ +function isPropertyBeforeRouteMethod(property) { + if (property.type !== 'Property') { + return false; + } + + return property.key.type === 'Identifier' && property.key.name === 'beforeRouteEnter'; +} + +const errorMessage = 'beforeRouteEnter does NOT have access to `this` component instance. https://router.vuejs.org/guide/advanced/navigation-guards.html#in-component-guards' + +module.exports = { + errorMessage: errorMessage, + meta: { + type: 'suggestion', + docs: { + description: 'Do not this in beforeRouteEnter', + categories: null, + url: 'https://eslint.vuejs.org/rules/no-this-in-before-route-enter.html' + }, + }, + + /** @param {RuleContext} context */ + create: function (context) { + // ---------------------------------------------------------------------- + // Public + // ---------------------------------------------------------------------- + return utils.executeOnVue(context, (obj) => { + const beforeRouteProperty = obj.properties.find(isPropertyBeforeRouteMethod); + if (!beforeRouteProperty) { + return; + } + if (beforeRouteProperty.value.type !== 'FunctionExpression') { + return; + } + if (deepFindThisExpression(beforeRouteProperty.value.body)) { + context.report({ + node: beforeRouteProperty, + message: errorMessage, + }); + } + }); + } +}; 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..0f11327ce --- /dev/null +++ b/tests/lib/rules/no-this-in-before-route-enter.js @@ -0,0 +1,132 @@ +/** + * @fileoverview Don't use "this" i a beforeRouteEnter method + * @author Przemyslaw Jan Beigert + */ +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +var rule = require("../../../lib/rules/no-this-in-before-route-enter"); +var 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)'), + ` + + +