1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 | 'use strict'
|
8 |
|
9 | const getDocsUrl = require('./lib/get-docs-url')
|
10 | const isPromise = require('./lib/is-promise')
|
11 |
|
12 | module.exports = {
|
13 | meta: {
|
14 | type: 'problem',
|
15 | docs: {
|
16 | url: getDocsUrl('catch-or-return'),
|
17 | },
|
18 | messages: {
|
19 | terminationMethod: 'Expected {{ terminationMethod }}() or return',
|
20 | },
|
21 | schema: [
|
22 | {
|
23 | type: 'object',
|
24 | properties: {
|
25 | allowFinally: {
|
26 | type: 'boolean',
|
27 | },
|
28 | allowThen: {
|
29 | type: 'boolean',
|
30 | },
|
31 | terminationMethod: {
|
32 | oneOf: [
|
33 | { type: 'string' },
|
34 | {
|
35 | type: 'array',
|
36 | items: {
|
37 | type: 'string',
|
38 | },
|
39 | },
|
40 | ],
|
41 | },
|
42 | },
|
43 | additionalProperties: false,
|
44 | },
|
45 | ],
|
46 | },
|
47 | create(context) {
|
48 | const options = context.options[0] || {}
|
49 | const allowThen = options.allowThen
|
50 | const allowFinally = options.allowFinally
|
51 | let terminationMethod = options.terminationMethod || 'catch'
|
52 |
|
53 | if (typeof terminationMethod === 'string') {
|
54 | terminationMethod = [terminationMethod]
|
55 | }
|
56 |
|
57 | function isAllowedPromiseTermination(expression) {
|
58 |
|
59 | if (
|
60 | allowThen &&
|
61 | expression.type === 'CallExpression' &&
|
62 | expression.callee.type === 'MemberExpression' &&
|
63 | expression.callee.property.name === 'then' &&
|
64 | expression.arguments.length === 2
|
65 | ) {
|
66 | return true
|
67 | }
|
68 |
|
69 |
|
70 | if (
|
71 | allowFinally &&
|
72 | expression.type === 'CallExpression' &&
|
73 | expression.callee.type === 'MemberExpression' &&
|
74 | expression.callee.property.name === 'finally' &&
|
75 | isPromise(expression.callee.object) &&
|
76 | isAllowedPromiseTermination(expression.callee.object)
|
77 | ) {
|
78 | return true
|
79 | }
|
80 |
|
81 |
|
82 | if (
|
83 | expression.type === 'CallExpression' &&
|
84 | expression.callee.type === 'MemberExpression' &&
|
85 | terminationMethod.indexOf(expression.callee.property.name) !== -1
|
86 | ) {
|
87 | return true
|
88 | }
|
89 |
|
90 |
|
91 | if (
|
92 | expression.type === 'CallExpression' &&
|
93 | expression.callee.type === 'MemberExpression' &&
|
94 | expression.callee.property.type === 'Literal' &&
|
95 | expression.callee.property.value === 'catch'
|
96 | ) {
|
97 | return true
|
98 | }
|
99 |
|
100 | return false
|
101 | }
|
102 |
|
103 | return {
|
104 | ExpressionStatement(node) {
|
105 | if (!isPromise(node.expression)) {
|
106 | return
|
107 | }
|
108 |
|
109 | if (isAllowedPromiseTermination(node.expression)) {
|
110 | return
|
111 | }
|
112 |
|
113 | context.report({
|
114 | node,
|
115 | messageId: 'terminationMethod',
|
116 | data: { terminationMethod },
|
117 | })
|
118 | },
|
119 | }
|
120 | },
|
121 | }
|