UNPKG

3.52 kBJavaScriptView Raw
1/**
2 * disallow assignments to `$scope` in controllers
3 *
4 * You should not set properties on $scope in controllers.
5 * Use controllerAs syntax and add data to 'this'.
6 * The second parameter can be a Regexp for identifying controller functions (when using something like Browserify)
7 *
8 * @styleguideReference {johnpapa} `y031` controllerAs Controller Syntax
9 * @version 0.1.0
10 * @category bestPractice
11 * @sinceAngularVersion 1.x
12 */
13'use strict';
14
15var utils = require('./utils/utils');
16
17module.exports = {
18 meta: {
19 schema: [{
20 type: ['object', 'string']
21 }]
22 },
23 create: function(context) {
24 var badStatements = [];
25 var controllerFunctions = [];
26
27 // If your Angular code is written so that controller functions are in
28 // separate files from your .controller() calls, you can specify a regex for your controller function names
29 var controllerNameMatcher = context.options[0];
30 if (controllerNameMatcher && utils.isStringRegexp(controllerNameMatcher)) {
31 controllerNameMatcher = utils.convertStringToRegex(controllerNameMatcher);
32 }
33
34 // check node against known controller functions or pattern if specified
35 function isControllerFunction(node) {
36 return controllerFunctions.indexOf(node) >= 0 ||
37 (controllerNameMatcher && (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') &&
38 node.id && controllerNameMatcher.test(node.id.name));
39 }
40
41 // for each of the bad uses, find any parent nodes that are controller functions
42 function reportBadUses() {
43 if (controllerFunctions.length > 0 || controllerNameMatcher) {
44 badStatements.forEach(function(item) {
45 item.parents.forEach(function(parent) {
46 if (isControllerFunction(parent)) {
47 context.report(item.stmt, 'You should not set properties on $scope in controllers. Use controllerAs syntax and add data to "this"');
48 }
49 });
50 });
51 }
52 }
53
54 return {
55 // Looking for .controller() calls here and getting the associated controller function
56 'CallExpression:exit': function(node) {
57 if (utils.isAngularControllerDeclaration(node)) {
58 controllerFunctions.push(utils.getControllerDefinition(context, node));
59 }
60 },
61 // statements are checked here for bad uses of $scope
62 ExpressionStatement: function(stmt) {
63 if (stmt.expression.type === 'AssignmentExpression' &&
64 stmt.expression.left.object &&
65 stmt.expression.left.object.name === '$scope' &&
66 utils.scopeProperties.indexOf(stmt.expression.left.property.name) < 0) {
67 badStatements.push({parents: context.getAncestors(), stmt: stmt});
68 } else if (stmt.expression.type === 'CallExpression' &&
69 stmt.expression.callee.object &&
70 stmt.expression.callee.object.name === '$scope' &&
71 utils.scopeProperties.indexOf(stmt.expression.callee.property.name) < 0) {
72 badStatements.push({parents: context.getAncestors(), stmt: stmt});
73 }
74 },
75 'Program:exit': function() {
76 reportBadUses();
77 }
78 };
79 }
80};