-
Notifications
You must be signed in to change notification settings - Fork 131
/
Copy pathon-watch.js
85 lines (74 loc) · 2.92 KB
/
on-watch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
* require `$on` and `$watch` deregistration callbacks to be saved in a variable
*
* Watch and On methods on the scope object should be assigned to a variable, in order to be deleted in a $destroy event handler
* @version 0.1.0
* @category bestPractice
* @sinceAngularVersion 1.x
*/
'use strict';
module.exports = {
meta: {
docs: {
url: 'https://github.com/Gillespie59/eslint-plugin-angular/blob/master/docs/rules/on-watch.md'
},
schema: []
},
create: function(context) {
function report(node, method) {
context.report(node, 'The "{{method}}" call should be assigned to a variable, in order to be destroyed during the $destroy event', {
method: method
});
}
/**
* Return true if the given node is a call expression calling a function
* named '$on' or '$watch' on an object named '$scope', '$rootScope' or
* 'scope'.
*/
function isScopeOnOrWatch(node, scopes) {
if (node.type !== 'CallExpression') {
return false;
}
var calledFunction = node.callee;
if (calledFunction.type !== 'MemberExpression') {
return false;
}
// can only easily tell what name was used if a simple
// identifiers were used to access it.
var parentObject = calledFunction.object;
var accessedFunction = calledFunction.property;
// cannot check name of the parent object if it is returned from a
// complex expression.
if (parentObject.type !== 'Identifier' ||
accessedFunction.type !== 'Identifier') {
return false;
}
var objectName = parentObject.name;
var functionName = accessedFunction.name;
return scopes.indexOf(objectName) >= 0 && (functionName === '$on' ||
functionName === '$watch');
}
/**
* Return true if the given node is a call expression that has a first
* argument of the string '$destroy'.
*/
function isFirstArgDestroy(node) {
var args = node.arguments;
return (args.length >= 1 &&
args[0].type === 'Literal' &&
args[0].value === '$destroy');
}
return {
CallExpression: function(node) {
if (isScopeOnOrWatch(node, ['$rootScope']) && !isFirstArgDestroy(node)) {
if (node.parent.type !== 'VariableDeclarator' &&
node.parent.type !== 'AssignmentExpression' &&
!(isScopeOnOrWatch(node.parent, ['$rootScope', '$scope', 'scope']) &&
isFirstArgDestroy(node.parent))) {
report(node, node.callee.property.name);
}
}
}
};
}
};