UNPKG

2.97 kBJavaScriptView Raw
1'use strict'
2
3const getDocsUrl = require('./lib/get-docs-url')
4
5module.exports = {
6 meta: {
7 type: 'suggestion',
8 docs: {
9 url: getDocsUrl('prefer-await-to-callbacks'),
10 },
11 messages: {
12 error: 'Avoid callbacks. Prefer Async/Await.',
13 },
14 schema: [],
15 },
16 create(context) {
17 function checkLastParamsForCallback(node) {
18 const lastParam = node.params[node.params.length - 1] || {}
19 if (lastParam.name === 'callback' || lastParam.name === 'cb') {
20 context.report({ node: lastParam, messageId: 'error' })
21 }
22 }
23 function isInsideYieldOrAwait() {
24 return context.getAncestors().some((parent) => {
25 return (
26 parent.type === 'AwaitExpression' || parent.type === 'YieldExpression'
27 )
28 })
29 }
30 return {
31 CallExpression(node) {
32 // Callbacks aren't allowed.
33 if (node.callee.name === 'cb' || node.callee.name === 'callback') {
34 context.report({ node, messageId: 'error' })
35 return
36 }
37
38 // Then-ables aren't allowed either.
39 const args = node.arguments
40 const lastArgIndex = args.length - 1
41 const arg = lastArgIndex > -1 && node.arguments[lastArgIndex]
42 if (
43 (arg && arg.type === 'FunctionExpression') ||
44 arg.type === 'ArrowFunctionExpression'
45 ) {
46 // Ignore event listener callbacks.
47 if (
48 node.callee.property &&
49 (node.callee.property.name === 'on' ||
50 node.callee.property.name === 'once')
51 ) {
52 return
53 }
54
55 // carve out exemption for map/filter/etc
56 const arrayMethods = [
57 'map',
58 'every',
59 'forEach',
60 'some',
61 'find',
62 'filter',
63 ]
64 const isLodash =
65 node.callee.object &&
66 ['lodash', 'underscore', '_'].includes(node.callee.object.name)
67 const callsArrayMethod =
68 node.callee.property &&
69 arrayMethods.includes(node.callee.property.name) &&
70 (node.arguments.length === 1 ||
71 (node.arguments.length === 2 && isLodash))
72 const isArrayMethod =
73 node.callee.name &&
74 arrayMethods.includes(node.callee.name) &&
75 node.arguments.length === 2
76 if (callsArrayMethod || isArrayMethod) return
77
78 // actually check for callbacks (I know this is the worst)
79 if (
80 arg.params &&
81 arg.params[0] &&
82 (arg.params[0].name === 'err' || arg.params[0].name === 'error')
83 ) {
84 if (!isInsideYieldOrAwait()) {
85 context.report({ node: arg, messageId: 'error' })
86 }
87 }
88 }
89 },
90 FunctionDeclaration: checkLastParamsForCallback,
91 FunctionExpression: checkLastParamsForCallback,
92 ArrowFunctionExpression: checkLastParamsForCallback,
93 }
94 },
95}