diff --git a/lib/rules/__test__/no-this-in-async-data.test.js b/lib/rules/__test__/no-this-in-async-data.test.js new file mode 100644 index 0000000..a42ed66 --- /dev/null +++ b/lib/rules/__test__/no-this-in-async-data.test.js @@ -0,0 +1,107 @@ +/** + * @fileoverview Prevent using this in asyncData + * @author Clark Du + */ +'use strict' + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +var rule = require('../no-this-in-async-data') + +var RuleTester = require('eslint').RuleTester + +const parserOptions = { + ecmaVersion: 2018, + sourceType: 'module' +} + +// ------------------------------------------------------------------------------ +// Tests +// ------------------------------------------------------------------------------ + +var ruleTester = new RuleTester() +ruleTester.run('no-this-in-async-data', rule, { + + valid: [ + { + filename: 'test.vue', + code: ` + export default { + ...foo, + asyncData() { + } + } + `, + parserOptions + } + ], + + invalid: [ + { + filename: 'test.vue', + code: ` + export default { + ...foo, + asyncData() { + if(this.$route.path === 'foo') {} + } + } + `, + errors: [{ + message: 'Unexpected this in asyncData.', + type: 'Identifier' + }], + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + ...foo, + async asyncData() { + if(this.$route.path === 'foo') {} + } + } + `, + errors: [{ + message: 'Unexpected this in asyncData.', + type: 'Identifier' + }], + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + ...foo, + asyncData: () => { + if(this.$route.path === 'foo') {} + } + } + `, + errors: [{ + message: 'Unexpected this in asyncData.', + type: 'Identifier' + }], + parserOptions + }, + { + filename: 'test.vue', + code: ` + export default { + ...foo, + asyncData: function test() { + if(this.$route.path === 'foo') {} + } + } + `, + errors: [{ + message: 'Unexpected this in asyncData.', + type: 'Identifier' + }], + parserOptions + } + ] +}) diff --git a/lib/rules/no-this-in-async-data.js b/lib/rules/no-this-in-async-data.js index a5acc40..87d4ac3 100644 --- a/lib/rules/no-this-in-async-data.js +++ b/lib/rules/no-this-in-async-data.js @@ -4,6 +4,8 @@ */ 'use strict' +const utils = require('../utils') + // ------------------------------------------------------------------------------ // Rule Definition // ------------------------------------------------------------------------------ @@ -11,9 +13,8 @@ module.exports = { meta: { docs: { - description: 'Prevent using this in asyncData', - category: 'Fill me in', - recommended: false + description: 'disallow `this` in asyncData', + category: 'base' }, fixable: null, // or "code" or "whitespace" schema: [ @@ -26,20 +27,58 @@ module.exports = { create: function (context) { // variables should be defined here + const forbiddenNodes = [] + let isThisUsed // ---------------------------------------------------------------------- // Helpers // ---------------------------------------------------------------------- + function enterFunction () { + isThisUsed = false + } + + function exitFunction (node) { + if (isThisUsed) { + forbiddenNodes.push(node) + } + } + + function markThisUsed () { + isThisUsed = true + } + + function getFuncNodeWithName (node, name) { + return node.properties.find(item => item.type === 'Property' && + utils.getStaticPropertyName(item) === name && + (item.value.type === 'ArrowFunctionExpression' || item.value.type === 'FunctionExpression') + ) + } + // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return { - 'FunctionExpression:exit' (node) { + FunctionExpression: enterFunction, + 'FunctionExpression:exit': exitFunction, + ArrowFunctionExpression: enterFunction, + 'ArrowFunctionExpression:exit': exitFunction, + ThisExpression: markThisUsed, + Super: markThisUsed, + ...utils.executeOnVue(context, obj => { + const node = getFuncNodeWithName(obj, 'asyncData') + if (!node) return - // give me methods - } + forbiddenNodes.forEach(el => { + if (node.value === el) { + context.report({ + node: node.key, + messageId: 'noThis' + }) + } + }) + }) } } } diff --git a/lib/rules/no-this-in-fetch.js b/lib/rules/no-this-in-fetch.js index c9fac50..c8a8528 100644 --- a/lib/rules/no-this-in-fetch.js +++ b/lib/rules/no-this-in-fetch.js @@ -11,9 +11,8 @@ module.exports = { meta: { docs: { - description: 'Prevent using this in fetch', - category: 'Fill me in', - recommended: false + description: 'disallow `this` in fetch', + category: 'base' }, fixable: null, // or "code" or "whitespace" schema: [ diff --git a/lib/utils/index.js b/lib/utils/index.js new file mode 100644 index 0000000..778e72a --- /dev/null +++ b/lib/utils/index.js @@ -0,0 +1 @@ +module.exports = require('eslint-plugin-vue/lib/utils')