Skip to content

Commit d5805cf

Browse files
committed
feat: enhance member expression handling and add TypeScript support
1 parent 86eec3c commit d5805cf

File tree

2 files changed

+55
-15
lines changed

2 files changed

+55
-15
lines changed

lib/rules/no-async-in-computed-properties.js

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -38,24 +38,35 @@ function isTimedFunction(node) {
3838
)
3939
}
4040

41+
/**
42+
* @param {*} node
43+
* @returns {*}
44+
*/
45+
function skipWrapper(node) {
46+
while (node && node.expression) {
47+
node = node.expression
48+
}
49+
return node
50+
}
51+
4152
/**
4253
* Get the root object name from a member expression chain
4354
* @param {MemberExpression} memberExpr
4455
* @returns {string|null}
4556
*/
4657
function getRootObjectName(memberExpr) {
47-
let current = memberExpr.object
58+
let current = skipWrapper(memberExpr.object)
4859

4960
while (current) {
5061
switch (current.type) {
5162
case 'MemberExpression': {
52-
current = utils.skipChainExpression(current.object)
63+
current = skipWrapper(current.object)
5364
break
5465
}
5566
case 'CallExpression': {
56-
const calleeExpr = utils.skipChainExpression(current.callee)
67+
const calleeExpr = skipWrapper(current.callee)
5768
if (calleeExpr.type === 'MemberExpression') {
58-
current = calleeExpr.object
69+
current = skipWrapper(calleeExpr.object)
5970
} else if (calleeExpr.type === 'Identifier') {
6071
return calleeExpr.name
6172
} else {
@@ -75,6 +86,22 @@ function getRootObjectName(memberExpr) {
7586
return null
7687
}
7788

89+
/**
90+
* @param {string} name
91+
* @param {*} callee
92+
* @returns {boolean}
93+
*/
94+
function isPromiseMethod(name, callee) {
95+
return (
96+
// hello.PROMISE_FUNCTION()
97+
PROMISE_FUNCTIONS.has(name) ||
98+
// Promise.PROMISE_METHOD()
99+
(callee.object.type === 'Identifier' &&
100+
callee.object.name === 'Promise' &&
101+
PROMISE_METHODS.has(name))
102+
)
103+
}
104+
78105
/**
79106
* @param {CallExpression} node
80107
* @param {Set<string>} ignoredObjectNames
@@ -83,15 +110,7 @@ function isPromise(node, ignoredObjectNames) {
83110
const callee = utils.skipChainExpression(node.callee)
84111
if (callee.type === 'MemberExpression') {
85112
const name = utils.getStaticPropertyName(callee)
86-
if (
87-
!name ||
88-
(!PROMISE_FUNCTIONS.has(name) &&
89-
!(
90-
callee.object.type === 'Identifier' &&
91-
callee.object.name === 'Promise' &&
92-
PROMISE_METHODS.has(name)
93-
))
94-
) {
113+
if (!name || !isPromiseMethod(name, callee)) {
95114
return false
96115
}
97116

tests/lib/rules/no-async-in-computed-properties.js

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -363,13 +363,34 @@ ruleTester.run('no-async-in-computed-properties', rule, {
363363
export default {
364364
computed: {
365365
foo: function () {
366-
return z.a.b.c.d.e.f.method().catch(err => err).finally(() => {})
366+
return z.a?.['b'].[c].d.method().catch(err => err).finally(() => {})
367367
}
368368
}
369369
}
370370
`,
371371
options: [{ ignoredObjectNames: ['z'] }],
372-
languageOptions
372+
languageOptions: {
373+
parser,
374+
sourceType: 'module',
375+
ecmaVersion: 2020
376+
}
377+
},
378+
{
379+
filename: 'test.vue',
380+
code: `
381+
<script setup lang="ts">
382+
import { computed } from 'vue'
383+
import { z } from 'zod'
384+
385+
const foo = computed(() => z.a?.['b'].c!.d.method().catch(err => err).finally(() => {}))
386+
</script>`,
387+
options: [{ ignoredObjectNames: ['z'] }],
388+
languageOptions: {
389+
parser: require('vue-eslint-parser'),
390+
parserOptions: {
391+
parser: require.resolve('@typescript-eslint/parser')
392+
}
393+
}
373394
}
374395
],
375396

0 commit comments

Comments
 (0)