Skip to content

Commit f9522d2

Browse files
authored
Merge pull request #159 from mikegreiling/add-allow-finally
Add allowFinally option to catch-or-return rule
2 parents c159832 + 0a953ca commit f9522d2

File tree

4 files changed

+143
-40
lines changed

4 files changed

+143
-40
lines changed

__tests__/catch-or-return.js

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,21 @@ ruleTester.run('catch-or-return', rule, {
8989
options: [{ allowThen: true }]
9090
},
9191

92+
// allowFinally - .finally(fn)
93+
{
94+
code: 'frank().then(go).catch(doIt).finally(fn)',
95+
options: [{ allowFinally: true }]
96+
},
97+
{
98+
code: 'frank().then(go).then().then().then().catch(doIt).finally(fn)',
99+
options: [{ allowFinally: true }]
100+
},
101+
{
102+
code:
103+
'frank().then(go).then().catch(function() { /* why bother */ }).finally(fn)',
104+
options: [{ allowFinally: true }]
105+
},
106+
92107
// terminationMethod=done - .done(null, fn)
93108
{
94109
code: 'frank().then(go).done()',
@@ -129,7 +144,28 @@ ruleTester.run('catch-or-return', rule, {
129144
errors: [{ message: catchMessage }]
130145
},
131146
{
132-
code: 'frank.then(to).finally(fn)',
147+
code: 'frank().then(to).catch(fn).then(foo)',
148+
errors: [{ message: catchMessage }]
149+
},
150+
{
151+
code: 'frank().finally(fn)',
152+
errors: [{ message: catchMessage }]
153+
},
154+
{
155+
code: 'frank().then(to).finally(fn)',
156+
errors: [{ message: catchMessage }]
157+
},
158+
{
159+
code: 'frank().then(go).catch(doIt).finally(fn)',
160+
errors: [{ message: catchMessage }]
161+
},
162+
{
163+
code: 'frank().then(go).then().then().then().catch(doIt).finally(fn)',
164+
errors: [{ message: catchMessage }]
165+
},
166+
{
167+
code:
168+
'frank().then(go).then().catch(function() { /* why bother */ }).finally(fn)',
133169
errors: [{ message: catchMessage }]
134170
},
135171

@@ -151,6 +187,18 @@ ruleTester.run('catch-or-return', rule, {
151187
errors: [{ message: catchMessage }]
152188
},
153189

190+
// allowFinally=true failures
191+
{
192+
code: 'frank().then(go).catch(doIt).finally(fn).then(foo)',
193+
options: [{ allowFinally: true }],
194+
errors: [{ message: catchMessage }]
195+
},
196+
{
197+
code: 'frank().then(go).catch(doIt).finally(fn).foobar(foo)',
198+
options: [{ allowFinally: true }],
199+
errors: [{ message: catchMessage }]
200+
},
201+
154202
// terminationMethod=done - .done(null, fn)
155203
{
156204
code: 'frank().then(go)',
@@ -161,6 +209,12 @@ ruleTester.run('catch-or-return', rule, {
161209
code: 'frank().catch(go)',
162210
options: [{ terminationMethod: 'done' }],
163211
errors: [{ message: doneMessage }]
212+
},
213+
214+
// assume somePromise.ANYTHING() is a new promise
215+
{
216+
code: 'frank().catch(go).someOtherMethod()',
217+
errors: [{ message: catchMessage }]
164218
}
165219
]
166220
})

docs/rules/catch-or-return.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ You can pass an `{ allowThen: true }` as an option to this rule to allow for
3434
`.then(null, fn)` to be used instead of `catch()` at the end of the promise
3535
chain.
3636

37+
##### `allowFinally`
38+
39+
You can pass an `{ allowFinally: true }` as an option to this rule to allow for
40+
`.finally(fn)` to be used after `catch()` at the end of the promise chain. This
41+
is different from adding `'finally'` as a `terminationMethod` because it will
42+
still require the Promise chain to be "caught" beforehand.
43+
3744
##### `terminationMethod`
3845

3946
You can pass a `{ terminationMethod: 'done' }` as an option to this rule to

package-lock.json

Lines changed: 33 additions & 12 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rules/catch-or-return.js

Lines changed: 48 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -21,45 +21,66 @@ module.exports = {
2121
create(context) {
2222
const options = context.options[0] || {}
2323
const allowThen = options.allowThen
24+
const allowFinally = options.allowFinally
2425
let terminationMethod = options.terminationMethod || 'catch'
2526

2627
if (typeof terminationMethod === 'string') {
2728
terminationMethod = [terminationMethod]
2829
}
2930

31+
function isAllowedPromiseTermination(expression) {
32+
// somePromise.then(a, b)
33+
if (
34+
allowThen &&
35+
expression.type === 'CallExpression' &&
36+
expression.callee.type === 'MemberExpression' &&
37+
expression.callee.property.name === 'then' &&
38+
expression.arguments.length === 2
39+
) {
40+
return true
41+
}
42+
43+
// somePromise.catch().finally(fn)
44+
if (
45+
allowFinally &&
46+
expression.type === 'CallExpression' &&
47+
expression.callee.type === 'MemberExpression' &&
48+
expression.callee.property.name === 'finally' &&
49+
isPromise(expression.callee.object) &&
50+
isAllowedPromiseTermination(expression.callee.object)
51+
) {
52+
return true
53+
}
54+
55+
// somePromise.catch()
56+
if (
57+
expression.type === 'CallExpression' &&
58+
expression.callee.type === 'MemberExpression' &&
59+
terminationMethod.indexOf(expression.callee.property.name) !== -1
60+
) {
61+
return true
62+
}
63+
64+
// somePromise['catch']()
65+
if (
66+
expression.type === 'CallExpression' &&
67+
expression.callee.type === 'MemberExpression' &&
68+
expression.callee.property.type === 'Literal' &&
69+
expression.callee.property.value === 'catch'
70+
) {
71+
return true
72+
}
73+
74+
return false
75+
}
76+
3077
return {
3178
ExpressionStatement(node) {
3279
if (!isPromise(node.expression)) {
3380
return
3481
}
3582

36-
// somePromise.then(a, b)
37-
if (
38-
allowThen &&
39-
node.expression.type === 'CallExpression' &&
40-
node.expression.callee.type === 'MemberExpression' &&
41-
node.expression.callee.property.name === 'then' &&
42-
node.expression.arguments.length === 2
43-
) {
44-
return
45-
}
46-
47-
// somePromise.catch()
48-
if (
49-
node.expression.type === 'CallExpression' &&
50-
node.expression.callee.type === 'MemberExpression' &&
51-
terminationMethod.indexOf(node.expression.callee.property.name) !== -1
52-
) {
53-
return
54-
}
55-
56-
// somePromise['catch']()
57-
if (
58-
node.expression.type === 'CallExpression' &&
59-
node.expression.callee.type === 'MemberExpression' &&
60-
node.expression.callee.property.type === 'Literal' &&
61-
node.expression.callee.property.value === 'catch'
62-
) {
83+
if (isAllowedPromiseTermination(node.expression)) {
6384
return
6485
}
6586

0 commit comments

Comments
 (0)