Skip to content

Commit d7eacd6

Browse files
authored
Add composition api's computed function support to vue/return-in-computed-property refs #1393 (#1406)
1 parent 10824ec commit d7eacd6

File tree

3 files changed

+191
-5
lines changed

3 files changed

+191
-5
lines changed

docs/rules/return-in-computed-property.md

+36-3
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22
pageClass: rule-details
33
sidebarDepth: 0
44
title: vue/return-in-computed-property
5-
description: enforce that a return statement is present in computed property
5+
description: enforce that a return statement is present in computed property and function
66
since: v3.7.0
77
---
88
# vue/return-in-computed-property
99

10-
> enforce that a return statement is present in computed property
10+
> enforce that a return statement is present in computed property and function
1111
1212
- :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"`.
1313

1414
## :book: Rule Details
1515

16-
This rule enforces that a `return` statement is present in `computed` properties.
16+
This rule enforces that a `return` statement is present in `computed` properties and functions.
1717

1818
<eslint-code-block :rules="{'vue/return-in-computed-property': ['error']}">
1919

@@ -46,6 +46,39 @@ export default {
4646

4747
</eslint-code-block>
4848

49+
<eslint-code-block :rules="{'vue/return-in-computed-property': ['error']}">
50+
51+
```vue
52+
<script>
53+
import {computed} from 'vue'
54+
export default {
55+
setup() {
56+
const foobar = useFoobar()
57+
58+
/* ✓ GOOD */
59+
const foo = computed(() => {
60+
if (foobar.bar) {
61+
return foobar.baz
62+
} else {
63+
return foobar.baf
64+
}
65+
})
66+
const bar = computed(() => false)
67+
68+
/* ✗ BAD */
69+
const baz = computed(() => {
70+
if (foobar.baf) {
71+
return foobar.baf
72+
}
73+
})
74+
const baf = computed(() => {})
75+
}
76+
}
77+
</script>
78+
```
79+
80+
</eslint-code-block>
81+
4982
## :wrench: Options
5083

5184
```json

lib/rules/return-in-computed-property.js

+33-2
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* @author Armano
44
*/
55
'use strict'
6-
6+
const { ReferenceTracker } = require('eslint-utils')
77
const utils = require('../utils')
88

99
/**
@@ -47,13 +47,36 @@ module.exports = {
4747
* @type {Set<ComponentComputedProperty>}
4848
*/
4949
const computedProperties = new Set()
50+
/** @type {(FunctionExpression | ArrowFunctionExpression)[]} */
51+
const computedFunctionNodes = []
5052

5153
// ----------------------------------------------------------------------
5254
// Public
5355
// ----------------------------------------------------------------------
5456

5557
return Object.assign(
56-
{},
58+
{
59+
Program() {
60+
const tracker = new ReferenceTracker(context.getScope())
61+
const traceMap = utils.createCompositionApiTraceMap({
62+
[ReferenceTracker.ESM]: true,
63+
computed: {
64+
[ReferenceTracker.CALL]: true
65+
}
66+
})
67+
68+
for (const { node } of tracker.iterateEsmReferences(traceMap)) {
69+
if (node.type !== 'CallExpression') {
70+
continue
71+
}
72+
73+
const getter = utils.getGetterBodyFromComputedFunction(node)
74+
if (getter) {
75+
computedFunctionNodes.push(getter)
76+
}
77+
}
78+
}
79+
},
5780
utils.defineVueVisitor(context, {
5881
onVueObjectEnter(obj) {
5982
for (const computedProperty of utils.getComputedProperties(obj)) {
@@ -76,6 +99,14 @@ module.exports = {
7699
})
77100
}
78101
})
102+
computedFunctionNodes.forEach((cf) => {
103+
if (cf === node) {
104+
context.report({
105+
node,
106+
message: 'Expected to return a value in computed function.'
107+
})
108+
}
109+
})
79110
}
80111
)
81112
)

tests/lib/rules/return-in-computed-property.js

+122
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,56 @@ ruleTester.run('return-in-computed-property', rule, {
104104
`,
105105
parserOptions,
106106
options: [{ treatUndefinedAsUnspecified: false }]
107+
},
108+
{
109+
filename: 'test.vue',
110+
code: `
111+
import {computed} from 'vue'
112+
export default {
113+
setup() {
114+
const foo = computed(() => true)
115+
const bar = computed(function() {
116+
return false
117+
})
118+
const bar3 = computed({
119+
set: () => true,
120+
get: () => true
121+
})
122+
const bar4 = computed(() => {
123+
if (foo) {
124+
return true
125+
} else {
126+
return false
127+
}
128+
})
129+
const foo2 = computed(() => {
130+
const options = []
131+
this.matches.forEach((match) => {
132+
options.push(match)
133+
})
134+
return options
135+
})
136+
}
137+
}
138+
`,
139+
parserOptions
140+
},
141+
{
142+
filename: 'test.vue',
143+
code: `
144+
import {computed} from 'vue'
145+
export default {
146+
setup() {
147+
const foo = computed({
148+
get: () => {
149+
return
150+
}
151+
})
152+
}
153+
}
154+
`,
155+
parserOptions,
156+
options: [{ treatUndefinedAsUnspecified: false }]
107157
}
108158
],
109159

@@ -272,6 +322,78 @@ ruleTester.run('return-in-computed-property', rule, {
272322
line: 5
273323
}
274324
]
325+
},
326+
{
327+
filename: 'test.vue',
328+
code: `
329+
import {computed} from 'vue'
330+
export default {
331+
setup() {
332+
const foo = computed(() => {})
333+
const foo2 = computed(function() {})
334+
const foo3 = computed(() => {
335+
if (a) {
336+
return
337+
}
338+
})
339+
const foo4 = computed({
340+
set: () => {},
341+
get: () => {}
342+
})
343+
const foo5 = computed(() => {
344+
const bar = () => {
345+
return this.baz * 2
346+
}
347+
bar()
348+
})
349+
}
350+
}
351+
`,
352+
parserOptions,
353+
errors: [
354+
{
355+
message: 'Expected to return a value in computed function.',
356+
line: 5
357+
},
358+
{
359+
message: 'Expected to return a value in computed function.',
360+
line: 6
361+
},
362+
{
363+
message: 'Expected to return a value in computed function.',
364+
line: 7
365+
},
366+
{
367+
message: 'Expected to return a value in computed function.',
368+
line: 14
369+
},
370+
{
371+
message: 'Expected to return a value in computed function.',
372+
line: 16
373+
}
374+
]
375+
},
376+
{
377+
filename: 'test.vue',
378+
code: `
379+
import {computed} from 'vue'
380+
export default {
381+
setup() {
382+
const foo = computed(() => {})
383+
const baz = computed(() => {
384+
return
385+
})
386+
}
387+
}
388+
`,
389+
parserOptions,
390+
options: [{ treatUndefinedAsUnspecified: false }],
391+
errors: [
392+
{
393+
message: 'Expected to return a value in computed function.',
394+
line: 5
395+
}
396+
]
275397
}
276398
]
277399
})

0 commit comments

Comments
 (0)