86 lines
2.9 KiB
JavaScript
86 lines
2.9 KiB
JavaScript
/**
|
|
* 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);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
}
|
|
};
|