From e349989f6007a2d0ee1ab2ec0ac9702e823a0019 Mon Sep 17 00:00:00 2001 From: sapphi-red Date: Sun, 3 Jan 2021 17:30:29 +0900 Subject: [PATCH] Add composition api's computed function support to vue/return-in-computed-property refs #1393 --- docs/rules/return-in-computed-property.md | 39 +++++- lib/rules/return-in-computed-property.js | 35 ++++- .../lib/rules/return-in-computed-property.js | 122 ++++++++++++++++++ 3 files changed, 191 insertions(+), 5 deletions(-) diff --git a/docs/rules/return-in-computed-property.md b/docs/rules/return-in-computed-property.md index d25225798..0ade8e5ae 100644 --- a/docs/rules/return-in-computed-property.md +++ b/docs/rules/return-in-computed-property.md @@ -2,18 +2,18 @@ pageClass: rule-details sidebarDepth: 0 title: vue/return-in-computed-property -description: enforce that a return statement is present in computed property +description: enforce that a return statement is present in computed property and function since: v3.7.0 --- # vue/return-in-computed-property -> enforce that a return statement is present in computed property +> enforce that a return statement is present in computed property and function - :gear: This rule is included in all of `"plugin:vue/vue3-essential"`, `"plugin:vue/essential"`, `"plugin:vue/vue3-strongly-recommended"`, `"plugin:vue/strongly-recommended"`, `"plugin:vue/vue3-recommended"` and `"plugin:vue/recommended"`. ## :book: Rule Details -This rule enforces that a `return` statement is present in `computed` properties. +This rule enforces that a `return` statement is present in `computed` properties and functions. @@ -46,6 +46,39 @@ export default { + + +```vue + +``` + + + ## :wrench: Options ```json diff --git a/lib/rules/return-in-computed-property.js b/lib/rules/return-in-computed-property.js index 770e0c597..9908fe4fe 100644 --- a/lib/rules/return-in-computed-property.js +++ b/lib/rules/return-in-computed-property.js @@ -3,7 +3,7 @@ * @author Armano */ 'use strict' - +const { ReferenceTracker } = require('eslint-utils') const utils = require('../utils') /** @@ -47,13 +47,36 @@ module.exports = { * @type {Set} */ const computedProperties = new Set() + /** @type {(FunctionExpression | ArrowFunctionExpression)[]} */ + const computedFunctionNodes = [] // ---------------------------------------------------------------------- // Public // ---------------------------------------------------------------------- return Object.assign( - {}, + { + Program() { + const tracker = new ReferenceTracker(context.getScope()) + const traceMap = utils.createCompositionApiTraceMap({ + [ReferenceTracker.ESM]: true, + computed: { + [ReferenceTracker.CALL]: true + } + }) + + for (const { node } of tracker.iterateEsmReferences(traceMap)) { + if (node.type !== 'CallExpression') { + continue + } + + const getter = utils.getGetterBodyFromComputedFunction(node) + if (getter) { + computedFunctionNodes.push(getter) + } + } + } + }, utils.defineVueVisitor(context, { onVueObjectEnter(obj) { for (const computedProperty of utils.getComputedProperties(obj)) { @@ -76,6 +99,14 @@ module.exports = { }) } }) + computedFunctionNodes.forEach((cf) => { + if (cf === node) { + context.report({ + node, + message: 'Expected to return a value in computed function.' + }) + } + }) } ) ) diff --git a/tests/lib/rules/return-in-computed-property.js b/tests/lib/rules/return-in-computed-property.js index a7c14a51f..df6b1b680 100644 --- a/tests/lib/rules/return-in-computed-property.js +++ b/tests/lib/rules/return-in-computed-property.js @@ -104,6 +104,56 @@ ruleTester.run('return-in-computed-property', rule, { `, parserOptions, options: [{ treatUndefinedAsUnspecified: false }] + }, + { + filename: 'test.vue', + code: ` + import {computed} from 'vue' + export default { + setup() { + const foo = computed(() => true) + const bar = computed(function() { + return false + }) + const bar3 = computed({ + set: () => true, + get: () => true + }) + const bar4 = computed(() => { + if (foo) { + return true + } else { + return false + } + }) + const foo2 = computed(() => { + const options = [] + this.matches.forEach((match) => { + options.push(match) + }) + return options + }) + } + } + `, + parserOptions + }, + { + filename: 'test.vue', + code: ` + import {computed} from 'vue' + export default { + setup() { + const foo = computed({ + get: () => { + return + } + }) + } + } + `, + parserOptions, + options: [{ treatUndefinedAsUnspecified: false }] } ], @@ -272,6 +322,78 @@ ruleTester.run('return-in-computed-property', rule, { line: 5 } ] + }, + { + filename: 'test.vue', + code: ` + import {computed} from 'vue' + export default { + setup() { + const foo = computed(() => {}) + const foo2 = computed(function() {}) + const foo3 = computed(() => { + if (a) { + return + } + }) + const foo4 = computed({ + set: () => {}, + get: () => {} + }) + const foo5 = computed(() => { + const bar = () => { + return this.baz * 2 + } + bar() + }) + } + } + `, + parserOptions, + errors: [ + { + message: 'Expected to return a value in computed function.', + line: 5 + }, + { + message: 'Expected to return a value in computed function.', + line: 6 + }, + { + message: 'Expected to return a value in computed function.', + line: 7 + }, + { + message: 'Expected to return a value in computed function.', + line: 14 + }, + { + message: 'Expected to return a value in computed function.', + line: 16 + } + ] + }, + { + filename: 'test.vue', + code: ` + import {computed} from 'vue' + export default { + setup() { + const foo = computed(() => {}) + const baz = computed(() => { + return + }) + } + } + `, + parserOptions, + options: [{ treatUndefinedAsUnspecified: false }], + errors: [ + { + message: 'Expected to return a value in computed function.', + line: 5 + } + ] } ] })