Socket
Socket
Sign inDemoInstall

eslint-plugin-angular

Package Overview
Dependencies
Maintainers
1
Versions
74
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

eslint-plugin-angular - npm Package Compare versions

Comparing version 1.6.1 to 1.6.2

rules/utils/false-values.js

6

package.json
{
"name": "eslint-plugin-angular",
"version": "1.6.1",
"version": "1.6.2",
"description": "ESLint rules for AngularJS projects",

@@ -32,6 +32,6 @@ "main": "index.js",

"gulp-istanbul": "^1.0.0",
"gulp-mocha": "^2.2.0",
"gulp-mocha": "^3.0.1",
"istanbul": "^0.4.2",
"lodash": "^4.13.1",
"mocha": "^2.4.5",
"mocha": "^3.2.0",
"parse-comments": "^0.4.3",

@@ -38,0 +38,0 @@ "shelljs": "^0.7.1",

@@ -13,12 +13,15 @@ /**

module.exports = function(context) {
return {
CallExpression: function(node) {
if (node.callee.name === '$' || node.callee.name === 'jQuery') {
context.report(node, 'You should use angular.element instead of the jQuery $ object', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
CallExpression: function(node) {
if (node.callee.name === '$' || node.callee.name === 'jQuery') {
context.report(node, 'You should use angular.element instead of the jQuery $ object', {});
}
}
}
};
};
}
};
module.exports.schema = [];

@@ -21,34 +21,37 @@ /**

module.exports = angularRule(function(context) {
var limit = context.options[0] || 1;
var count = 0;
var msg = 'There may be at most {{limit}} AngularJS {{component}} per file, but found {{number}}';
module.exports = {
meta: {
schema: [{
type: 'integer'
}]
},
create: angularRule(function(context) {
var limit = context.options[0] || 1;
var count = 0;
var msg = 'There may be at most {{limit}} AngularJS {{component}} per file, but found {{number}}';
function checkLimit(callee) {
count++;
if (count > limit) {
context.report(callee, msg, {
limit: limit,
component: limit === 1 ? 'component' : 'components',
number: count
});
function checkLimit(callee) {
count++;
if (count > limit) {
context.report(callee, msg, {
limit: limit,
component: limit === 1 ? 'component' : 'components',
number: count
});
}
}
}
return {
'angular:animation': checkLimit,
'angular:config': checkLimit,
'angular:controller': checkLimit,
'angular:directive': checkLimit,
'angular:factory': checkLimit,
'angular:filter': checkLimit,
'angular:provider': checkLimit,
'angular:run': checkLimit,
'angular:service': checkLimit,
'angular:component': checkLimit
};
});
module.exports.schema = [{
type: 'integer'
}];
return {
'angular:animation': checkLimit,
'angular:config': checkLimit,
'angular:controller': checkLimit,
'angular:directive': checkLimit,
'angular:factory': checkLimit,
'angular:filter': checkLimit,
'angular:provider': checkLimit,
'angular:run': checkLimit,
'angular:service': checkLimit,
'angular:component': checkLimit
};
})
};

@@ -16,42 +16,49 @@ /**

module.exports = function(context) {
if (context.settings.angular === 2) {
return {};
}
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}]
},
create: function(context) {
if (context.settings.angular === 2) {
return {};
}
return {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
convertedPrefix = utils.convertPrefixToRegex(prefix);
if (utils.isAngularComponentDeclaration(node)) {
var name = node.arguments[0].value;
if (utils.isAngularComponentDeclaration(node)) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('ng') === 0) {
context.report(node, 'The {{component}} component should not start with "ng". This is reserved for AngularJS components', {
component: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{component}} component should be prefixed by {{prefix}}', {
component: name,
prefix: prefix
if (name !== undefined && name.indexOf('ng') === 0) {
context.report(node, 'The {{component}} component should not start with "ng". This is reserved for AngularJS components', {
component: name
});
} else {
context.report(node, 'The {{component}} component should follow this pattern: {{prefix}}', {
component: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{component}} component should be prefixed by {{prefix}}', {
component: name,
prefix: prefix
});
} else {
context.report(node, 'The {{component}} component should follow this pattern: {{prefix}}', {
component: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -18,40 +18,49 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}, {
type: 'object'
}]
},
create: function(context) {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isConstant;
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isConstant;
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
isConstant = utils.isAngularConstantDeclaration(node);
convertedPrefix = utils.convertPrefixToRegex(prefix);
isConstant = utils.isAngularConstantDeclaration(node);
if (isConstant) {
var name = node.arguments[0].value;
if (isConstant) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{constant}} constant should not start with "$". This is reserved for AngularJS services', {
constant: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{constant}} constant should be prefixed by {{prefix}}', {
constant: name,
prefix: prefix
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{constant}} constant should not start with "$". This is reserved for AngularJS services', {
constant: name
});
} else {
context.report(node, 'The {{constant}} constant should follow this pattern: {{prefix}}', {
constant: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{constant}} constant should be prefixed by {{prefix}}', {
constant: name,
prefix: prefix
});
} else {
context.report(node, 'The {{constant}} constant should follow this pattern: {{prefix}}', {
constant: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -15,74 +15,79 @@ /**

module.exports = function(context) {
return {
CallExpression: function(node) {
var routeObject = null;
var stateObject = null;
var hasControllerAs = false;
var controllerProp = null;
var stateName = null;
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
CallExpression: function(node) {
var routeObject = null;
var stateObject = null;
var hasControllerAs = false;
var controllerProp = null;
var stateName = null;
if (utils.isRouteDefinition(node)) {
// second argument in $routeProvider.when('route', {...})
routeObject = node.arguments[1];
if (utils.isRouteDefinition(node)) {
// second argument in $routeProvider.when('route', {...})
routeObject = node.arguments[1];
if (routeObject.properties) {
routeObject.properties.forEach(function(prop) {
if (prop.key.name === 'controller') {
controllerProp = prop;
if (routeObject.properties) {
routeObject.properties.forEach(function(prop) {
if (prop.key.name === 'controller') {
controllerProp = prop;
if (new RegExp('\\sas\\s').test(prop.value.value)) {
hasControllerAs = true;
if (new RegExp('\\sas\\s').test(prop.value.value)) {
hasControllerAs = true;
}
}
}
if (prop.key.name === 'controllerAs') {
if (hasControllerAs) {
context.report(node, 'The controllerAs syntax is defined twice for the route "{{route}}"', {
route: node.arguments[0].value
});
if (prop.key.name === 'controllerAs') {
if (hasControllerAs) {
context.report(node, 'The controllerAs syntax is defined twice for the route "{{route}}"', {
route: node.arguments[0].value
});
}
hasControllerAs = true;
}
});
hasControllerAs = true;
// if it's a route without a controller, we shouldn't warn about controllerAs
if (controllerProp && !hasControllerAs) {
context.report(node, 'Route "{{route}}" should use controllerAs syntax', {
route: node.arguments[0].value
});
}
});
}
} else if (utils.isUIRouterStateDefinition(node)) {
// state can be defined like .state({...}) or .state('name', {...})
var isObjectState = node.arguments.length === 1;
stateObject = isObjectState ? node.arguments[0] : node.arguments[1];
// if it's a route without a controller, we shouldn't warn about controllerAs
if (controllerProp && !hasControllerAs) {
context.report(node, 'Route "{{route}}" should use controllerAs syntax', {
route: node.arguments[0].value
if (stateObject && stateObject.properties) {
stateObject.properties.forEach(function(prop) {
if (prop.key.name === 'controller') {
controllerProp = prop;
}
if (prop.key.name === 'controllerAs') {
hasControllerAs = true;
}
// grab the name from the object for when they aren't using .state('name',...)
if (prop.key.name === 'name') {
stateName = prop.value.value;
}
});
}
}
} else if (utils.isUIRouterStateDefinition(node)) {
// state can be defined like .state({...}) or .state('name', {...})
var isObjectState = node.arguments.length === 1;
stateObject = isObjectState ? node.arguments[0] : node.arguments[1];
if (stateObject && stateObject.properties) {
stateObject.properties.forEach(function(prop) {
if (prop.key.name === 'controller') {
controllerProp = prop;
if (!hasControllerAs && controllerProp) {
// if the controller is a string, controllerAs can be set like 'controller as vm'
if (controllerProp.value.type !== 'Literal' || controllerProp.value.value.indexOf(' as ') < 0) {
context.report(node, 'State "{{state}}" should use controllerAs syntax', {
state: isObjectState ? stateName : node.arguments[0].value
});
}
}
if (prop.key.name === 'controllerAs') {
hasControllerAs = true;
}
// grab the name from the object for when they aren't using .state('name',...)
if (prop.key.name === 'name') {
stateName = prop.value.value;
}
});
if (!hasControllerAs && controllerProp) {
// if the controller is a string, controllerAs can be set like 'controller as vm'
if (controllerProp.value.type !== 'Literal' || controllerProp.value.value.indexOf(' as ') < 0) {
context.report(node, 'State "{{state}}" should use controllerAs syntax', {
state: isObjectState ? stateName : node.arguments[0].value
});
}
}
}
}
}
};
};
}
};

@@ -21,82 +21,85 @@ /**

module.exports = function(context) {
var badStatements = [];
var badCaptureStatements = [];
var controllerFunctions = [];
module.exports = {
meta: {
schema: [{
type: 'string'
}, {
type: 'string'
}]
},
create: function(context) {
var badStatements = [];
var badCaptureStatements = [];
var controllerFunctions = [];
var viewModelName = context.options[0] || 'vm';
// If your Angular code is written so that controller functions are in
// separate files from your .controller() calls, you can specify a regex for your controller function names
var controllerNameMatcher = context.options[1];
if (controllerNameMatcher && utils.isStringRegexp(controllerNameMatcher)) {
controllerNameMatcher = utils.convertStringToRegex(controllerNameMatcher);
}
var viewModelName = context.options[0] || 'vm';
// If your Angular code is written so that controller functions are in
// separate files from your .controller() calls, you can specify a regex for your controller function names
var controllerNameMatcher = context.options[1];
if (controllerNameMatcher && utils.isStringRegexp(controllerNameMatcher)) {
controllerNameMatcher = utils.convertStringToRegex(controllerNameMatcher);
}
// check node against known controller functions or pattern if specified
function isControllerFunction(node) {
return controllerFunctions.indexOf(node) >= 0 ||
(controllerNameMatcher && (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') &&
node.id && controllerNameMatcher.test(node.id.name));
}
// check node against known controller functions or pattern if specified
function isControllerFunction(node) {
return controllerFunctions.indexOf(node) >= 0 ||
(controllerNameMatcher && (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') &&
node.id && controllerNameMatcher.test(node.id.name));
}
// for each of the bad uses, find any parent nodes that are controller functions
function reportBadUses() {
if (controllerFunctions.length > 0 || controllerNameMatcher) {
badCaptureStatements.forEach(function(item) {
item.parents.filter(isControllerFunction).forEach(function() {
context.report(item.stmt, 'You should assign "this" to a consistent variable across your project: {{capture}}',
{
capture: viewModelName
}
);
// for each of the bad uses, find any parent nodes that are controller functions
function reportBadUses() {
if (controllerFunctions.length > 0 || controllerNameMatcher) {
badCaptureStatements.forEach(function(item) {
item.parents.filter(isControllerFunction).forEach(function() {
context.report(item.stmt, 'You should assign "this" to a consistent variable across your project: {{capture}}',
{
capture: viewModelName
}
);
});
});
});
badStatements.forEach(function(item) {
item.parents.filter(isControllerFunction).forEach(function() {
context.report(item.stmt, 'You should not use "this" directly. Instead, assign it to a variable called "{{capture}}"',
{
capture: viewModelName
}
);
badStatements.forEach(function(item) {
item.parents.filter(isControllerFunction).forEach(function() {
context.report(item.stmt, 'You should not use "this" directly. Instead, assign it to a variable called "{{capture}}"',
{
capture: viewModelName
}
);
});
});
});
}
}
}
function isClassDeclaration(ancestors) {
return ancestors.findIndex(function(ancestor) {
return ancestor.type === 'ClassDeclaration';
}) > -1;
}
function isClassDeclaration(ancestors) {
return ancestors.findIndex(function(ancestor) {
return ancestor.type === 'ClassDeclaration';
}) > -1;
}
return {
// Looking for .controller() calls here and getting the associated controller function
'CallExpression:exit': function(node) {
if (utils.isAngularControllerDeclaration(node)) {
controllerFunctions.push(utils.getControllerDefinition(context, node));
}
},
// statements are checked here for bad uses of $scope
ThisExpression: function(stmt) {
var parents = context.getAncestors();
if (!isClassDeclaration(parents)) {
if (stmt.parent.type === 'VariableDeclarator') {
if (!stmt.parent.id || stmt.parent.id.name !== viewModelName) {
badCaptureStatements.push({parents: parents, stmt: stmt});
return {
// Looking for .controller() calls here and getting the associated controller function
'CallExpression:exit': function(node) {
if (utils.isAngularControllerDeclaration(node)) {
controllerFunctions.push(utils.getControllerDefinition(context, node));
}
},
// statements are checked here for bad uses of $scope
ThisExpression: function(stmt) {
var parents = context.getAncestors();
if (!isClassDeclaration(parents)) {
if (stmt.parent.type === 'VariableDeclarator') {
if (!stmt.parent.id || stmt.parent.id.name !== viewModelName) {
badCaptureStatements.push({parents: parents, stmt: stmt});
}
} else {
badStatements.push({parents: parents, stmt: stmt});
}
} else {
badStatements.push({parents: parents, stmt: stmt});
}
},
'Program:exit': function() {
reportBadUses();
}
},
'Program:exit': function() {
reportBadUses();
}
};
};
}
};
module.exports.schema = [{
type: 'string'
}, {
type: 'string'
}];

@@ -17,62 +17,65 @@ /**

module.exports = function(context) {
var badStatements = [];
var controllerFunctions = [];
module.exports = {
meta: {
schema: [{
type: ['object', 'string']
}]
},
create: function(context) {
var badStatements = [];
var controllerFunctions = [];
// If your Angular code is written so that controller functions are in
// separate files from your .controller() calls, you can specify a regex for your controller function names
var controllerNameMatcher = context.options[0];
if (controllerNameMatcher && utils.isStringRegexp(controllerNameMatcher)) {
controllerNameMatcher = utils.convertStringToRegex(controllerNameMatcher);
}
// If your Angular code is written so that controller functions are in
// separate files from your .controller() calls, you can specify a regex for your controller function names
var controllerNameMatcher = context.options[0];
if (controllerNameMatcher && utils.isStringRegexp(controllerNameMatcher)) {
controllerNameMatcher = utils.convertStringToRegex(controllerNameMatcher);
}
// check node against known controller functions or pattern if specified
function isControllerFunction(node) {
return controllerFunctions.indexOf(node) >= 0 ||
(controllerNameMatcher && (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') &&
node.id && controllerNameMatcher.test(node.id.name));
}
// check node against known controller functions or pattern if specified
function isControllerFunction(node) {
return controllerFunctions.indexOf(node) >= 0 ||
(controllerNameMatcher && (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') &&
node.id && controllerNameMatcher.test(node.id.name));
}
// for each of the bad uses, find any parent nodes that are controller functions
function reportBadUses() {
if (controllerFunctions.length > 0 || controllerNameMatcher) {
badStatements.forEach(function(item) {
item.parents.forEach(function(parent) {
if (isControllerFunction(parent)) {
context.report(item.stmt, 'You should not set properties on $scope in controllers. Use controllerAs syntax and add data to "this"');
}
// for each of the bad uses, find any parent nodes that are controller functions
function reportBadUses() {
if (controllerFunctions.length > 0 || controllerNameMatcher) {
badStatements.forEach(function(item) {
item.parents.forEach(function(parent) {
if (isControllerFunction(parent)) {
context.report(item.stmt, 'You should not set properties on $scope in controllers. Use controllerAs syntax and add data to "this"');
}
});
});
});
}
}
}
return {
// Looking for .controller() calls here and getting the associated controller function
'CallExpression:exit': function(node) {
if (utils.isAngularControllerDeclaration(node)) {
controllerFunctions.push(utils.getControllerDefinition(context, node));
return {
// Looking for .controller() calls here and getting the associated controller function
'CallExpression:exit': function(node) {
if (utils.isAngularControllerDeclaration(node)) {
controllerFunctions.push(utils.getControllerDefinition(context, node));
}
},
// statements are checked here for bad uses of $scope
ExpressionStatement: function(stmt) {
if (stmt.expression.type === 'AssignmentExpression' &&
stmt.expression.left.object &&
stmt.expression.left.object.name === '$scope' &&
utils.scopeProperties.indexOf(stmt.expression.left.property.name) < 0) {
badStatements.push({parents: context.getAncestors(), stmt: stmt});
} else if (stmt.expression.type === 'CallExpression' &&
stmt.expression.callee.object &&
stmt.expression.callee.object.name === '$scope' &&
utils.scopeProperties.indexOf(stmt.expression.callee.property.name) < 0) {
badStatements.push({parents: context.getAncestors(), stmt: stmt});
}
},
'Program:exit': function() {
reportBadUses();
}
},
// statements are checked here for bad uses of $scope
ExpressionStatement: function(stmt) {
if (stmt.expression.type === 'AssignmentExpression' &&
stmt.expression.left.object &&
stmt.expression.left.object.name === '$scope' &&
utils.scopeProperties.indexOf(stmt.expression.left.property.name) < 0) {
badStatements.push({parents: context.getAncestors(), stmt: stmt});
} else if (stmt.expression.type === 'CallExpression' &&
stmt.expression.callee.object &&
stmt.expression.callee.object.name === '$scope' &&
utils.scopeProperties.indexOf(stmt.expression.callee.property.name) < 0) {
badStatements.push({parents: context.getAncestors(), stmt: stmt});
}
},
'Program:exit': function() {
reportBadUses();
}
};
};
}
};
module.exports.schema = [{
type: ['object', 'string']
}];

@@ -18,44 +18,47 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [
{
type: 'string'
}
]
},
create: function(context) {
return {
CallExpression: function(node) {
var prefix = context.options[0] || '/^[A-Z][a-zA-Z0-9]*Controller$/';
var convertedPrefix; // convert string from JSON .eslintrc to regex
CallExpression: function(node) {
var prefix = context.options[0] || '/^[A-Z][a-zA-Z0-9]*Controller$/';
var convertedPrefix; // convert string from JSON .eslintrc to regex
convertedPrefix = utils.convertPrefixToRegex(prefix);
convertedPrefix = utils.convertPrefixToRegex(prefix);
var callee = node.callee;
if (callee.type === 'MemberExpression' && callee.property.name === 'controller') {
/**
* Allow the usage of element.controller() and element.controller('directiveName') in unittests
*/
if (node.arguments.length < 2) {
return;
}
var callee = node.callee;
if (callee.type === 'MemberExpression' && callee.property.name === 'controller') {
/**
* Allow the usage of element.controller() and element.controller('directiveName') in unittests
*/
if (node.arguments.length < 2) {
return;
}
var name = node.arguments[0].value;
var name = node.arguments[0].value;
if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{controller}} controller should be prefixed by {{prefix}}', {
controller: name,
prefix: prefix
});
} else {
context.report(node, 'The {{controller}} controller should follow this pattern: {{prefix}}', {
controller: name,
prefix: prefix.toString()
});
if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{controller}} controller should be prefixed by {{prefix}}', {
controller: name,
prefix: prefix
});
} else {
context.report(node, 'The {{controller}} controller should follow this pattern: {{prefix}}', {
controller: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};
module.exports.schema = [
{
type: 'string'
}
];

@@ -14,15 +14,18 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
MemberExpression: function(node) {
if (node.object.type === 'Identifier' && utils.isAngularServiceImport(node.object.name, '$q')) {
if (node.property.type === 'Identifier' && node.property.name === 'defer') {
context.report(node, 'You should not create a new promise with this syntax. Use the $q(function(resolve, reject) {}) syntax.', {});
MemberExpression: function(node) {
if (node.object.type === 'Identifier' && utils.isAngularServiceImport(node.object.name, '$q')) {
if (node.property.type === 'Identifier' && node.property.name === 'defer') {
context.report(node, 'You should not create a new promise with this syntax. Use the $q(function(resolve, reject) {}) syntax.', {});
}
}
}
}
};
};
}
};
module.exports.schema = [];

@@ -16,42 +16,45 @@ /**

module.exports = function(context) {
function isCompareOperator(operator) {
return operator === '===' || operator === '!==' || operator === '==' || operator === '!=';
}
function reportError(node) {
context.report(node, 'You should not use directly the "undefined" keyword. Prefer ' +
'angular.isUndefined or angular.isDefined', {});
}
/**
* Rule that check if we use angular.is(Un)defined() instead of the undefined keyword
*/
return {
MemberExpression: function(node) {
if (node.object.name === 'angular' &&
module.exports = {
meta: {
schema: []
},
create: function(context) {
function isCompareOperator(operator) {
return operator === '===' || operator === '!==' || operator === '==' || operator === '!=';
}
function reportError(node) {
context.report(node, 'You should not use directly the "undefined" keyword. Prefer ' +
'angular.isUndefined or angular.isDefined', {});
}
/**
* Rule that check if we use angular.is(Un)defined() instead of the undefined keyword
*/
return {
MemberExpression: function(node) {
if (node.object.name === 'angular' &&
node.parent !== undefined &&
node.parent.parent !== undefined &&
node.parent.parent.operator === '!') {
if (node.property.name === 'isDefined') {
context.report(node, 'Instead of !angular.isDefined, you can use the out-of-box angular.isUndefined method', {});
} else if (node.property.name === 'isUndefined') {
context.report(node, 'Instead of !angular.isUndefined, you can use the out-of-box angular.isDefined method', {});
if (node.property.name === 'isDefined') {
context.report(node, 'Instead of !angular.isDefined, you can use the out-of-box angular.isUndefined method', {});
} else if (node.property.name === 'isUndefined') {
context.report(node, 'Instead of !angular.isUndefined, you can use the out-of-box angular.isDefined method', {});
}
}
}
},
BinaryExpression: function(node) {
if (isCompareOperator(node.operator)) {
if (utils.isTypeOfStatement(node.left) && node.right.value === 'undefined') {
reportError(node);
} else if (utils.isTypeOfStatement(node.right) && node.left.value === 'undefined') {
reportError(node);
} else if (node.left.type === 'Identifier' && node.left.name === 'undefined') {
reportError(node);
} else if (node.right.type === 'Identifier' && node.right.name === 'undefined') {
reportError(node);
},
BinaryExpression: function(node) {
if (isCompareOperator(node.operator)) {
if (utils.isTypeOfStatement(node.left) && node.right.value === 'undefined') {
reportError(node);
} else if (utils.isTypeOfStatement(node.right) && node.left.value === 'undefined') {
reportError(node);
} else if (node.left.type === 'Identifier' && node.left.name === 'undefined') {
reportError(node);
} else if (node.right.type === 'Identifier' && node.right.name === 'undefined') {
reportError(node);
}
}
}
}
};
};
}
};
module.exports.schema = [];

@@ -17,41 +17,50 @@ /**

module.exports = angularRule(function(context) {
var stripUnderscores = context.options[0] !== false;
var caseSensitiveOpt = (context.options[1] || caseSensitive) === caseSensitive;
module.exports = {
meta: {
schema: [{
type: 'boolean'
}, {
type: 'string'
}]
},
create: angularRule(function(context) {
var stripUnderscores = context.options[0] !== false;
var caseSensitiveOpt = (context.options[1] || caseSensitive) === caseSensitive;
function checkOrder(callee, fn) {
if (!fn || !fn.params) {
return;
function checkOrder(callee, fn) {
if (!fn || !fn.params) {
return;
}
var args = fn.params.map(function(arg) {
var formattedArg = arg.name;
if (stripUnderscores) {
formattedArg = formattedArg.replace(/^_(.+)_$/, '$1');
}
return caseSensitiveOpt ? formattedArg : formattedArg.toLowerCase();
});
var sortedArgs = args.slice().sort();
sortedArgs.some(function(value, index) {
if (args.indexOf(value) !== index) {
context.report(fn, 'Injected values should be sorted alphabetically');
return true;
}
});
}
var args = fn.params.map(function(arg) {
var formattedArg = arg.name;
if (stripUnderscores) {
formattedArg = formattedArg.replace(/^_(.+)_$/, '$1');
return {
'angular:animation': checkOrder,
'angular:config': checkOrder,
'angular:controller': checkOrder,
'angular:directive': checkOrder,
'angular:factory': checkOrder,
'angular:filter': checkOrder,
'angular:inject': checkOrder,
'angular:run': checkOrder,
'angular:service': checkOrder,
'angular:provider': function(callee, providerFn, $get) {
checkOrder(null, providerFn);
checkOrder(null, $get);
}
return caseSensitiveOpt ? formattedArg : formattedArg.toLowerCase();
});
var sortedArgs = args.slice().sort();
sortedArgs.some(function(value, index) {
if (args.indexOf(value) !== index) {
context.report(fn, 'Injected values should be sorted alphabetically');
return true;
}
});
}
return {
'angular:animation': checkOrder,
'angular:config': checkOrder,
'angular:controller': checkOrder,
'angular:directive': checkOrder,
'angular:factory': checkOrder,
'angular:filter': checkOrder,
'angular:inject': checkOrder,
'angular:run': checkOrder,
'angular:service': checkOrder,
'angular:provider': function(callee, providerFn, $get) {
checkOrder(null, providerFn);
checkOrder(null, $get);
}
};
});
};
})
};

@@ -15,60 +15,65 @@ /**

module.exports = angularRule(function(context) {
// Keeps track of visited scopes in the collectAngularScopes function to prevent infinite recursion on circular references.
var visitedScopes = [];
module.exports = {
meta: {
schema: []
},
create: angularRule(function(context) {
// Keeps track of visited scopes in the collectAngularScopes function to prevent infinite recursion on circular references.
var visitedScopes = [];
// This collects the variable scopes for the injectible functions which have been collected.
function collectAngularScopes(scope) {
if (visitedScopes.indexOf(scope) === -1) {
visitedScopes.push(scope);
scope.childScopes.forEach(function(child) {
collectAngularScopes(child);
});
// This collects the variable scopes for the injectible functions which have been collected.
function collectAngularScopes(scope) {
if (visitedScopes.indexOf(scope) === -1) {
visitedScopes.push(scope);
scope.childScopes.forEach(function(child) {
collectAngularScopes(child);
});
}
}
}
function reportUnusedVariables(callee, fn) {
if (!fn) {
return;
}
visitedScopes.some(function(scope) {
if (scope.block !== fn) {
function reportUnusedVariables(callee, fn) {
if (!fn) {
return;
}
scope.variables.forEach(function(variable) {
if (variable.name === 'arguments') {
visitedScopes.some(function(scope) {
if (scope.block !== fn) {
return;
}
if (fn.params.indexOf(variable.identifiers[0]) === -1) {
return;
}
if (variable.references.length === 0) {
context.report(fn, 'Unused injected value {{name}}', variable);
}
scope.variables.forEach(function(variable) {
if (variable.name === 'arguments') {
return;
}
if (fn.params.indexOf(variable.identifiers[0]) === -1) {
return;
}
if (variable.references.length === 0) {
context.report(fn, 'Unused injected value {{name}}', variable);
}
});
return true;
});
return true;
});
}
}
return {
'angular:animation': reportUnusedVariables,
'angular:config': reportUnusedVariables,
'angular:controller': reportUnusedVariables,
'angular:directive': reportUnusedVariables,
'angular:factory': reportUnusedVariables,
'angular:filter': reportUnusedVariables,
'angular:inject': reportUnusedVariables,
'angular:run': reportUnusedVariables,
'angular:service': reportUnusedVariables,
'angular:provider': function(callee, providerFn, $get) {
reportUnusedVariables(null, providerFn);
reportUnusedVariables(null, $get);
},
return {
'angular:animation': reportUnusedVariables,
'angular:config': reportUnusedVariables,
'angular:controller': reportUnusedVariables,
'angular:directive': reportUnusedVariables,
'angular:factory': reportUnusedVariables,
'angular:filter': reportUnusedVariables,
'angular:inject': reportUnusedVariables,
'angular:run': reportUnusedVariables,
'angular:service': reportUnusedVariables,
'angular:provider': function(callee, providerFn, $get) {
reportUnusedVariables(null, providerFn);
reportUnusedVariables(null, $get);
},
// Actually find and report unused injected variables.
'Program:exit': function() {
var globalScope = context.getScope();
collectAngularScopes(globalScope);
}
};
});
// Actually find and report unused injected variables.
'Program:exit': function() {
var globalScope = context.getScope();
collectAngularScopes(globalScope);
}
};
})
};

@@ -17,65 +17,49 @@ /**

module.exports = angularRule(function(context) {
var syntax = context.options[0] || 'function';
module.exports = {
meta: {
schema: [{
enum: [
'function',
'array',
'$inject'
]
}, {
type: 'object',
properties: {
matchNames: {
type: 'boolean'
}
}
}]
},
create: angularRule(function(context) {
var syntax = context.options[0] || 'function';
var extra = context.options[1] || {};
var matchNames = extra.matchNames !== false;
var extra = context.options[1] || {};
var matchNames = extra.matchNames !== false;
function report(node) {
context.report(node, 'You should use the {{syntax}} syntax for DI', {
syntax: syntax
});
}
var $injectProperties = {};
function maybeNoteInjection(node) {
if (syntax === '$inject' && node.left && node.left.property &&
((utils.isLiteralType(node.left.property) && node.left.property.value === '$inject') ||
(utils.isIdentifierType(node.left.property) && node.left.property.name === '$inject'))) {
$injectProperties[node.left.object.name] = node.right;
function report(node) {
context.report(node, 'You should use the {{syntax}} syntax for DI', {
syntax: syntax
});
}
}
function checkDi(callee, fn) {
if (!fn) {
return;
}
var $injectProperties = {};
if (syntax === 'array') {
if (utils.isArrayType(fn.parent)) {
if (fn.parent.elements.length - 1 !== fn.params.length) {
context.report(fn, 'The signature of the method is incorrect', {});
return;
}
if (matchNames) {
var invalidArray = fn.params.filter(function(e, i) {
return e.name !== fn.parent.elements[i].value;
});
if (invalidArray.length > 0) {
context.report(fn, 'You have an error in your DI configuration. Each items of the array should match exactly one function parameter', {});
return;
}
}
} else {
if (fn.params.length === 0) {
return;
}
report(fn);
function maybeNoteInjection(node) {
if (syntax === '$inject' && node.left && node.left.property &&
((utils.isLiteralType(node.left.property) && node.left.property.value === '$inject') ||
(utils.isIdentifierType(node.left.property) && node.left.property.name === '$inject'))) {
$injectProperties[node.left.object.name] = node.right;
}
}
if (syntax === 'function') {
if (utils.isArrayType(fn.parent)) {
report(fn);
function checkDi(callee, fn) {
if (!fn) {
return;
}
}
if (syntax === '$inject') {
if (fn && fn.id && utils.isIdentifierType(fn.id)) {
var $injectArray = $injectProperties[fn.id.name];
if ($injectArray && utils.isArrayType($injectArray)) {
if ($injectArray.elements.length !== fn.params.length) {
if (syntax === 'array') {
if (utils.isArrayType(fn.parent)) {
if (fn.parent.elements.length - 1 !== fn.params.length) {
context.report(fn, 'The signature of the method is incorrect', {});

@@ -86,6 +70,6 @@ return;

if (matchNames) {
var invalidInjectArray = fn.params.filter(function(e, i) {
return e.name !== $injectArray.elements[i].value;
var invalidArray = fn.params.filter(function(e, i) {
return e.name !== fn.parent.elements[i].value;
});
if (invalidInjectArray.length > 0) {
if (invalidArray.length > 0) {
context.report(fn, 'You have an error in your DI configuration. Each items of the array should match exactly one function parameter', {});

@@ -96,43 +80,62 @@ return;

} else {
if (fn.params.length === 0) {
return;
}
report(fn);
}
} else if (fn.params && fn.params.length !== 0) {
report(fn);
}
}
}
return {
'angular:animation': checkDi,
'angular:config': checkDi,
'angular:controller': checkDi,
'angular:directive': checkDi,
'angular:factory': checkDi,
'angular:filter': checkDi,
'angular:inject': checkDi,
'angular:run': checkDi,
'angular:service': checkDi,
'angular:provider': function(callee, providerFn, $get) {
checkDi(null, providerFn);
checkDi(null, $get);
},
AssignmentExpression: function(node) {
maybeNoteInjection(node);
if (syntax === 'function') {
if (utils.isArrayType(fn.parent)) {
report(fn);
}
}
if (syntax === '$inject') {
if (fn && fn.id && utils.isIdentifierType(fn.id)) {
var $injectArray = $injectProperties[fn.id.name];
if ($injectArray && utils.isArrayType($injectArray)) {
if ($injectArray.elements.length !== fn.params.length) {
context.report(fn, 'The signature of the method is incorrect', {});
return;
}
if (matchNames) {
var invalidInjectArray = fn.params.filter(function(e, i) {
return e.name !== $injectArray.elements[i].value;
});
if (invalidInjectArray.length > 0) {
context.report(fn, 'You have an error in your DI configuration. Each items of the array should match exactly one function parameter', {});
return;
}
}
} else {
report(fn);
}
} else if (fn.params && fn.params.length !== 0) {
report(fn);
}
}
}
};
});
module.exports.schema = [{
enum: [
'function',
'array',
'$inject'
]
}, {
type: 'object',
properties: {
matchNames: {
type: 'boolean'
}
}
}];
return {
'angular:animation': checkDi,
'angular:config': checkDi,
'angular:controller': checkDi,
'angular:directive': checkDi,
'angular:factory': checkDi,
'angular:filter': checkDi,
'angular:inject': checkDi,
'angular:run': checkDi,
'angular:service': checkDi,
'angular:provider': function(callee, providerFn, $get) {
checkDi(null, providerFn);
checkDi(null, $get);
},
AssignmentExpression: function(node) {
maybeNoteInjection(node);
}
};
})
};

@@ -18,42 +18,49 @@ /**

module.exports = function(context) {
if (context.settings.angular === 2) {
return {};
}
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}]
},
create: function(context) {
if (context.settings.angular === 2) {
return {};
}
return {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
convertedPrefix = utils.convertPrefixToRegex(prefix);
if (utils.isAngularDirectiveDeclaration(node)) {
var name = node.arguments[0].value;
if (utils.isAngularDirectiveDeclaration(node)) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('ng') === 0) {
context.report(node, 'The {{directive}} directive should not start with "ng". This is reserved for AngularJS directives', {
directive: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{directive}} directive should be prefixed by {{prefix}}', {
directive: name,
prefix: prefix
if (name !== undefined && name.indexOf('ng') === 0) {
context.report(node, 'The {{directive}} directive should not start with "ng". This is reserved for AngularJS directives', {
directive: name
});
} else {
context.report(node, 'The {{directive}} directive should follow this pattern: {{prefix}}', {
directive: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{directive}} directive should be prefixed by {{prefix}}', {
directive: name,
prefix: prefix
});
} else {
context.report(node, 'The {{directive}} directive should follow this pattern: {{prefix}}', {
directive: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -18,90 +18,93 @@ /**

module.exports = function(context) {
var options = context.options[0] || {};
var restrictOpt = options.restrict || 'AE';
var explicitRestrict = options.explicit === 'always';
var restrictChars = restrictOpt.split('');
// Example RegExp for AE: /^A?E?$/
var restrictRegExp = new RegExp('^' + restrictChars.join('?') + '?$');
var foundDirectives = [];
var checkedDirectives = [];
var defaultRestrictions = ['AE', 'EA'];
function checkLiteralNode(node) {
if (node.type !== 'Literal') {
return;
}
var directiveNode;
context.getAncestors().some(function(ancestor) {
if (utils.isAngularDirectiveDeclaration(ancestor)) {
directiveNode = ancestor;
return true;
module.exports = {
meta: {
schema: [{
type: 'object',
properties: {
restrict: {
type: 'string',
pattern: '^A|C|E|(AC)|(CA)|(AE)|(EA)|(EC)|(CE)|(AEC)|(ACE)|(EAC)|(CAE)|(ACE)|(AEC)|(CAE)|(ACE)|(AEC)$'
},
explicit: {
enum: ['always', 'never']
}
}
});
// The restrict property was not defined inside of a directive.
if (!directiveNode) {
return;
}
if (!explicitRestrict && defaultRestrictions.indexOf(node.value) !== -1) {
context.report(node, 'No need to explicitly specify a default directive restriction');
return;
}
}]
},
create: function(context) {
var options = context.options[0] || {};
var restrictOpt = options.restrict || 'AE';
var explicitRestrict = options.explicit === 'always';
var restrictChars = restrictOpt.split('');
if (!restrictRegExp.test(node.value)) {
context.report(directiveNode, 'Disallowed directive restriction. It must be one of {{allowed}} in that order', {
allowed: restrictOpt
});
}
// Example RegExp for AE: /^A?E?$/
var restrictRegExp = new RegExp('^' + restrictChars.join('?') + '?$');
var foundDirectives = [];
var checkedDirectives = [];
var defaultRestrictions = ['AE', 'EA'];
checkedDirectives.push(directiveNode);
}
return {
CallExpression: function(node) {
if (utils.isAngularDirectiveDeclaration(node)) {
foundDirectives.push(node);
}
},
AssignmentExpression: function(node) {
// Only check for literal member property assignments.
if (node.left.type !== 'MemberExpression') {
function checkLiteralNode(node) {
if (node.type !== 'Literal') {
return;
}
// Only check setting properties named 'restrict'.
if (node.left.property.name !== 'restrict') {
var directiveNode;
context.getAncestors().some(function(ancestor) {
if (utils.isAngularDirectiveDeclaration(ancestor)) {
directiveNode = ancestor;
return true;
}
});
// The restrict property was not defined inside of a directive.
if (!directiveNode) {
return;
}
checkLiteralNode(node.right);
},
Property: function(node) {
// This only checks for objects which have defined a literal restrict property.
if (node.key.name !== 'restrict') {
if (!explicitRestrict && defaultRestrictions.indexOf(node.value) !== -1) {
context.report(node, 'No need to explicitly specify a default directive restriction');
return;
}
checkLiteralNode(node.value);
},
'Program:exit': function() {
if (explicitRestrict) {
foundDirectives.filter(function(directive) {
return checkedDirectives.indexOf(directive) < 0;
}).forEach(function(directiveNode) {
context.report(directiveNode, 'Missing directive restriction');
if (!restrictRegExp.test(node.value)) {
context.report(directiveNode, 'Disallowed directive restriction. It must be one of {{allowed}} in that order', {
allowed: restrictOpt
});
}
checkedDirectives.push(directiveNode);
}
};
};
module.exports.schema = [{
type: 'object',
properties: {
restrict: {
type: 'string',
pattern: '^A|C|E|(AC)|(CA)|(AE)|(EA)|(EC)|(CE)|(AEC)|(ACE)|(EAC)|(CAE)|(ACE)|(AEC)|(CAE)|(ACE)|(AEC)$'
},
explicit: {
enum: ['always', 'never']
}
return {
CallExpression: function(node) {
if (utils.isAngularDirectiveDeclaration(node)) {
foundDirectives.push(node);
}
},
AssignmentExpression: function(node) {
// Only check for literal member property assignments.
if (node.left.type !== 'MemberExpression') {
return;
}
// Only check setting properties named 'restrict'.
if (node.left.property.name !== 'restrict') {
return;
}
checkLiteralNode(node.right);
},
Property: function(node) {
// This only checks for objects which have defined a literal restrict property.
if (node.key.name !== 'restrict') {
return;
}
checkLiteralNode(node.value);
},
'Program:exit': function() {
if (explicitRestrict) {
foundDirectives.filter(function(directive) {
return checkedDirectives.indexOf(directive) < 0;
}).forEach(function(directiveNode) {
context.report(directiveNode, 'Missing directive restriction');
});
}
}
};
}
}];
};

@@ -13,14 +13,15 @@ /**

module.exports = function(context) {
return {
MemberExpression: function(node) {
if (node.object.name === 'document' || (node.object.name === 'window' && node.property.name === 'document')) {
context.report(node, 'You should use the $document service instead of the default document object', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
MemberExpression: function(node) {
if (node.object.name === 'document' || (node.object.name === 'window' && node.property.name === 'document')) {
context.report(node, 'You should use the $document service instead of the default document object', {});
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -16,58 +16,63 @@ /**

module.exports = angularRule(function(context) {
function report(node, name) {
context.report(node, 'inject functions may only consist of assignments in the form {{name}} = _{{name}}_', {
name: name || 'myService'
});
}
module.exports = {
meta: {
schema: []
},
create: angularRule(function(context) {
function report(node, name) {
context.report(node, 'inject functions may only consist of assignments in the form {{name}} = _{{name}}_', {
name: name || 'myService'
});
}
return {
'angular:inject': function(callExpression, fn) {
if (!fn) {
return;
}
var valid = [];
// Report bad statement types
fn.body.body.forEach(function(statement) {
if (statement.type !== 'ExpressionStatement') {
return report(statement);
}
if (statement.expression.type !== 'AssignmentExpression') {
return report(statement);
}
if (statement.expression.right.type !== 'Identifier') {
return report(statement);
}
// From this point there is more context on what to report.
var name = statement.expression.right.name.replace(/^_(.+)_$/, '$1');
if (statement.expression.left.type !== 'Identifier') {
return report(statement, name);
}
if (statement.expression.right.name !== '_' + name + '_') {
return report(statement, name);
}
if (statement.expression.left.name !== name) {
return report(statement, name);
}
// Register valid statements for sort order validation
valid.push(statement);
});
// Validate the sorting order
var lastValid;
valid.forEach(function(statement) {
if (!lastValid) {
lastValid = statement.expression.left.name;
return {
'angular:inject': function(callExpression, fn) {
if (!fn) {
return;
}
if (statement.expression.left.name.localeCompare(lastValid) !== -1) {
lastValid = statement.expression.left.name;
return;
}
context.report(statement, "'{{current}}' must be sorted before '{{previous}}'", {
current: statement.expression.left.name,
previous: lastValid
var valid = [];
// Report bad statement types
fn.body.body.forEach(function(statement) {
if (statement.type !== 'ExpressionStatement') {
return report(statement);
}
if (statement.expression.type !== 'AssignmentExpression') {
return report(statement);
}
if (statement.expression.right.type !== 'Identifier') {
return report(statement);
}
// From this point there is more context on what to report.
var name = statement.expression.right.name.replace(/^_(.+)_$/, '$1');
if (statement.expression.left.type !== 'Identifier') {
return report(statement, name);
}
if (statement.expression.right.name !== '_' + name + '_') {
return report(statement, name);
}
if (statement.expression.left.name !== name) {
return report(statement, name);
}
// Register valid statements for sort order validation
valid.push(statement);
});
});
}
};
});
// Validate the sorting order
var lastValid;
valid.forEach(function(statement) {
if (!lastValid) {
lastValid = statement.expression.left.name;
return;
}
if (statement.expression.left.name.localeCompare(lastValid) !== -1) {
lastValid = statement.expression.left.name;
return;
}
context.report(statement, "'{{current}}' must be sorted before '{{previous}}'", {
current: statement.expression.left.name,
previous: lastValid
});
});
}
};
})
};

@@ -15,29 +15,30 @@ /**

module.exports = function(context) {
function report(node, name) {
context.report(node, 'The {{ctrl}} controller is useless because empty. You can remove it from your Router configuration or in one of your view', {
ctrl: name
});
}
module.exports = {
meta: {
schema: []
},
create: function(context) {
function report(node, name) {
context.report(node, 'The {{ctrl}} controller is useless because empty. You can remove it from your Router configuration or in one of your view', {
ctrl: name
});
}
return {
return {
CallExpression: function(node) {
if (utils.isAngularControllerDeclaration(node)) {
var name = node.arguments[0].value;
CallExpression: function(node) {
if (utils.isAngularControllerDeclaration(node)) {
var name = node.arguments[0].value;
var fn = node.arguments[1];
if (utils.isArrayType(node.arguments[1])) {
fn = node.arguments[1].elements[node.arguments[1].elements.length - 1];
var fn = node.arguments[1];
if (utils.isArrayType(node.arguments[1])) {
fn = node.arguments[1].elements[node.arguments[1].elements.length - 1];
}
if (utils.isFunctionType(fn) && utils.isEmptyFunction(fn)) {
report(node, name);
}
}
if (utils.isFunctionType(fn) && utils.isEmptyFunction(fn)) {
report(node, name);
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -18,40 +18,49 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}, {
type: 'object'
}]
},
create: function(context) {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isFactory;
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isFactory;
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
isFactory = utils.isAngularFactoryDeclaration(node);
convertedPrefix = utils.convertPrefixToRegex(prefix);
isFactory = utils.isAngularFactoryDeclaration(node);
if (isFactory) {
var name = node.arguments[0].value;
if (isFactory) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{factory}} factory should not start with "$". This is reserved for AngularJS services', {
factory: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{factory}} factory should be prefixed by {{prefix}}', {
factory: name,
prefix: prefix
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{factory}} factory should not start with "$". This is reserved for AngularJS services', {
factory: name
});
} else {
context.report(node, 'The {{factory}} factory should follow this pattern: {{prefix}}', {
factory: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{factory}} factory should be prefixed by {{prefix}}', {
factory: name,
prefix: prefix
});
} else {
context.report(node, 'The {{factory}} factory should follow this pattern: {{prefix}}', {
factory: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -26,109 +26,116 @@ /**

module.exports = (function() {
var fileEnding = '.js';
module.exports = {
meta: {
schema: [{
type: ['object']
}]
},
create: (function() {
var fileEnding = '.js';
var separators = {
dot: '.',
dash: '-',
underscore: '_'
};
var separators = {
dot: '.',
dash: '-',
underscore: '_'
};
function createComponentTypeMappings(options) {
var componentTypeMappingOptions = options.componentTypeMappings || {};
function createComponentTypeMappings(options) {
var componentTypeMappingOptions = options.componentTypeMappings || {};
return {
module: componentTypeMappingOptions.module || 'module',
controller: componentTypeMappingOptions.controller || 'controller',
directive: componentTypeMappingOptions.directive || 'directive',
filter: componentTypeMappingOptions.filter || 'filter',
service: componentTypeMappingOptions.service || 'service',
factory: componentTypeMappingOptions.factory || 'service',
provider: componentTypeMappingOptions.provider || 'service',
value: componentTypeMappingOptions.value || 'service',
constant: componentTypeMappingOptions.constant || 'constant',
component: componentTypeMappingOptions.component || 'component'
};
}
return {
module: componentTypeMappingOptions.module || 'module',
controller: componentTypeMappingOptions.controller || 'controller',
directive: componentTypeMappingOptions.directive || 'directive',
filter: componentTypeMappingOptions.filter || 'filter',
service: componentTypeMappingOptions.service || 'service',
factory: componentTypeMappingOptions.factory || 'service',
provider: componentTypeMappingOptions.provider || 'service',
value: componentTypeMappingOptions.value || 'service',
constant: componentTypeMappingOptions.constant || 'constant',
component: componentTypeMappingOptions.component || 'component'
};
}
var filenameUtil = {
firstToUpper: function(value) {
return value[0].toUpperCase() + value.slice(1);
},
firstToLower: function(value) {
return value[0].toLowerCase() + value.slice(1);
},
removeTypeSuffix: function(name, type) {
var nameTypeLengthDiff = name.length - type.length;
if (nameTypeLengthDiff <= 0) {
var filenameUtil = {
firstToUpper: function(value) {
return value[0].toUpperCase() + value.slice(1);
},
firstToLower: function(value) {
return value[0].toLowerCase() + value.slice(1);
},
removeTypeSuffix: function(name, type) {
var nameTypeLengthDiff = name.length - type.length;
if (nameTypeLengthDiff <= 0) {
return name;
}
var typeCamelCase = this.firstToUpper(type);
if (name.indexOf(typeCamelCase) === nameTypeLengthDiff) {
return name.slice(0, nameTypeLengthDiff);
}
return name;
}
var typeCamelCase = this.firstToUpper(type);
if (name.indexOf(typeCamelCase) === nameTypeLengthDiff) {
return name.slice(0, nameTypeLengthDiff);
}
return name;
},
removePrefix: function(name, options) {
var regName = '^' + options.ignorePrefix.replace(/[\.]/g, '\\$&');
regName += options.ignorePrefix.indexOf('\.') === -1 ? '[A-Z]' : '[a-zA-z]';
if (new RegExp(regName).test(name)) {
return this.firstToLower(name.slice(options.ignorePrefix.length));
}
return name;
},
transformComponentName: function(name, options) {
var nameStyle = options.nameStyle;
var nameSeparator = separators[nameStyle];
if (nameSeparator) {
var replacement = '$1' + nameSeparator + '$2';
name = name.replace(/([a-z0-9])([A-Z])/g, replacement).toLowerCase();
}
return name;
},
createExpectedName: function(name, type, options) {
var typeSeparator = separators[options.typeSeparator];
},
removePrefix: function(name, options) {
var regName = '^' + options.ignorePrefix.replace(/[\.]/g, '\\$&');
regName += options.ignorePrefix.indexOf('\.') === -1 ? '[A-Z]' : '[a-zA-z]';
if (new RegExp(regName).test(name)) {
return this.firstToLower(name.slice(options.ignorePrefix.length));
}
return name;
},
transformComponentName: function(name, options) {
var nameStyle = options.nameStyle;
var nameSeparator = separators[nameStyle];
if (nameSeparator) {
var replacement = '$1' + nameSeparator + '$2';
name = name.replace(/([a-z0-9])([A-Z])/g, replacement).toLowerCase();
}
return name;
},
createExpectedName: function(name, type, options) {
var typeSeparator = separators[options.typeSeparator];
if (options.ignoreTypeSuffix) {
name = filenameUtil.removeTypeSuffix(name, type);
if (options.ignoreTypeSuffix) {
name = filenameUtil.removeTypeSuffix(name, type);
}
if (options.ignorePrefix && options.ignorePrefix.length > 0) {
name = filenameUtil.removePrefix(name, options);
}
if (options.nameStyle) {
name = filenameUtil.transformComponentName(name, options);
}
if (typeSeparator !== undefined) {
name = name + typeSeparator + type;
}
return name + fileEnding;
}
if (options.ignorePrefix && options.ignorePrefix.length > 0) {
name = filenameUtil.removePrefix(name, options);
}
if (options.nameStyle) {
name = filenameUtil.transformComponentName(name, options);
}
if (typeSeparator !== undefined) {
name = name + typeSeparator + type;
}
return name + fileEnding;
}
};
};
return function(context) {
var options = context.options[0] || {};
var filename = path.basename(context.getFilename());
var componentTypeMappings = createComponentTypeMappings(options);
return function(context) {
var options = context.options[0] || {};
var filename = path.basename(context.getFilename());
var componentTypeMappings = createComponentTypeMappings(options);
return {
CallExpression: function(node) {
if (utils.isAngularComponent(node) && utils.isMemberExpression(node.callee)) {
var name = node.arguments[0].value;
var type = componentTypeMappings[node.callee.property.name];
var expectedName;
return {
CallExpression: function(node) {
if (utils.isAngularComponent(node) && utils.isMemberExpression(node.callee)) {
var name = node.arguments[0].value;
var type = componentTypeMappings[node.callee.property.name];
var expectedName;
if (type === undefined || (type === 'service' && node.callee.object.name === '$provide')) {
return;
}
if (type === undefined || (type === 'service' && node.callee.object.name === '$provide')) {
return;
}
expectedName = filenameUtil.createExpectedName(name, type, options);
expectedName = filenameUtil.createExpectedName(name, type, options);
if (expectedName !== filename) {
context.report(node, 'Filename must be "{{expectedName}}"', {
expectedName: expectedName
});
if (expectedName !== filename) {
context.report(node, 'Filename must be "{{expectedName}}"', {
expectedName: expectedName
});
}
}
}
}
};
};
};
}());
}())
};

@@ -16,33 +16,41 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}]
},
create: function(context) {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex;
if (prefix === undefined) {
return;
}
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex;
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
convertedPrefix = utils.convertPrefixToRegex(prefix);
if (utils.isAngularFilterDeclaration(node)) {
var name = node.arguments[0].value;
if (utils.isAngularFilterDeclaration(node)) {
var name = node.arguments[0].value;
if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{filter}} filter should be prefixed by {{prefix}}', {
filter: name,
prefix: prefix
});
} else {
context.report(node, 'The {{filter}} filter should follow this pattern: {{prefix}}', {
filter: name,
prefix: prefix.toString()
});
if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{filter}} filter should be prefixed by {{prefix}}', {
filter: name,
prefix: prefix
});
} else {
context.report(node, 'The {{filter}} filter should follow this pattern: {{prefix}}', {
filter: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -12,14 +12,15 @@ /**

module.exports = function(context) {
return {
MemberExpression: function(node) {
if (node.object.type === 'Identifier' && node.object.name !== 'angular' && node.property.name === 'forEach') {
context.report(node, 'You should use the angular.forEach method', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
MemberExpression: function(node) {
if (node.object.type === 'Identifier' && node.object.name !== 'angular' && node.property.name === 'forEach') {
context.report(node, 'You should use the angular.forEach method', {});
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -18,56 +18,59 @@ /**

module.exports = function(context) {
var angularObjectList = ['animation', 'config', 'constant', 'controller', 'directive', 'factory', 'filter', 'provider', 'service', 'value', 'decorator'];
var configType = context.options[0] || 'anonymous';
var messageByConfigType = {
anonymous: 'Use anonymous functions instead of named function',
named: 'Use named functions instead of anonymous function'
};
var message = messageByConfigType[configType];
module.exports = {
meta: {
schema: [{
enum: [
'named',
'anonymous'
]
}, {
type: 'array',
items: {
type: 'string'
}
}]
},
create: function(context) {
var angularObjectList = ['animation', 'config', 'constant', 'controller', 'directive', 'factory', 'filter', 'provider', 'service', 'value', 'decorator'];
var configType = context.options[0] || 'anonymous';
var messageByConfigType = {
anonymous: 'Use anonymous functions instead of named function',
named: 'Use named functions instead of anonymous function'
};
var message = messageByConfigType[configType];
if (context.options[1]) {
angularObjectList = context.options[1];
}
if (context.options[1]) {
angularObjectList = context.options[1];
}
function checkType(arg) {
return utils.isCallExpression(arg) ||
(configType === 'named' && (utils.isIdentifierType(arg) || utils.isNamedInlineFunction(arg))) ||
(configType === 'anonymous' && utils.isFunctionType(arg) && !utils.isNamedInlineFunction(arg));
}
function checkType(arg) {
return utils.isCallExpression(arg) ||
(configType === 'named' && (utils.isIdentifierType(arg) || utils.isNamedInlineFunction(arg))) ||
(configType === 'anonymous' && utils.isFunctionType(arg) && !utils.isNamedInlineFunction(arg));
}
return {
return {
CallExpression: function(node) {
var callee = node.callee;
var angularObjectName = callee.property && callee.property.name;
var firstArgument = node.arguments[1];
CallExpression: function(node) {
var callee = node.callee;
var angularObjectName = callee.property && callee.property.name;
var firstArgument = node.arguments[1];
if (utils.isAngularComponent(node) && callee.type === 'MemberExpression' && angularObjectList.indexOf(angularObjectName) >= 0) {
if (checkType(firstArgument)) {
return;
}
if (utils.isArrayType(firstArgument)) {
var last = firstArgument.elements[firstArgument.elements.length - 1];
if (checkType(last) || (!utils.isFunctionType(last) && !utils.isIdentifierType(last))) {
if (utils.isAngularComponent(node) && callee.type === 'MemberExpression' && angularObjectList.indexOf(angularObjectName) >= 0) {
if (checkType(firstArgument)) {
return;
}
if (utils.isArrayType(firstArgument)) {
var last = firstArgument.elements[firstArgument.elements.length - 1];
if (checkType(last) || (!utils.isFunctionType(last) && !utils.isIdentifierType(last))) {
return;
}
}
context.report(node, message, {});
}
context.report(node, message, {});
}
}
};
};
}
};
module.exports.schema = [{
enum: [
'named',
'anonymous'
]
}, {
type: 'array',
items: {
type: 'string'
}
}];

@@ -13,23 +13,24 @@ /**

module.exports = function(context) {
var message = 'You should use the $interval service instead of the default window.setInterval method';
module.exports = {
meta: {
schema: []
},
create: function(context) {
var message = 'You should use the $interval service instead of the default window.setInterval method';
return {
return {
MemberExpression: function(node) {
if (node.object.name === 'window' && node.property.name === 'setInterval') {
context.report(node, message, {});
}
},
MemberExpression: function(node) {
if (node.object.name === 'window' && node.property.name === 'setInterval') {
context.report(node, message, {});
}
},
CallExpression: function(node) {
if (node.callee.name === 'setInterval') {
context.report(node, message, {});
CallExpression: function(node) {
if (node.callee.name === 'setInterval') {
context.report(node, message, {});
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -13,19 +13,20 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
MemberExpression: function(node) {
if (node.object.name === 'JSON') {
if (node.property.name === 'stringify') {
context.report(node, 'You should use the angular.toJson method instead of JSON.stringify', {});
} else if (node.property.name === 'parse') {
context.report(node, 'You should use the angular.fromJson method instead of JSON.parse', {});
MemberExpression: function(node) {
if (node.object.name === 'JSON') {
if (node.property.name === 'stringify') {
context.report(node, 'You should use the angular.toJson method instead of JSON.stringify', {});
} else if (node.property.name === 'parse') {
context.report(node, 'You should use the angular.fromJson method instead of JSON.parse', {});
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -11,17 +11,18 @@ /**

module.exports = function(context) {
var method = ['log', 'debug', 'error', 'info', 'warn'];
module.exports = {
meta: {
schema: []
},
create: function(context) {
var method = ['log', 'debug', 'error', 'info', 'warn'];
return {
return {
MemberExpression: function(node) {
if (node.object.name === 'console' && method.indexOf(node.property.name) >= 0) {
context.report(node, 'You should use the "' + node.property.name + '" method of the AngularJS Service $log instead of the console object');
MemberExpression: function(node) {
if (node.object.name === 'console' && method.indexOf(node.property.name) >= 0) {
context.report(node, 'You should use the "' + node.property.name + '" method of the AngularJS Service $log instead of the console object');
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -20,87 +20,127 @@ /**

module.exports = function(context) {
var options = context.options[0] || {};
var groupedMode = options.grouped !== false;
var moduleRegex;
if (groupedMode) {
moduleRegex = utils.convertPrefixToRegex(options.prefix);
}
module.exports = {
meta: {
schema: [{
type: 'object',
properties: {
grouped: {
type: 'boolean'
},
prefix: {
type: ['string', 'null']
}
}
}]
},
create: function(context) {
var options = context.options[0] || {};
var groupedMode = options.grouped !== false;
var moduleRegex;
if (groupedMode) {
moduleRegex = utils.convertPrefixToRegex(options.prefix);
}
var standard = [
// Libraries in the angular.js repository
'ng',
'ngAnimate',
'ngAria',
'ngCookies',
'ngLocale',
'ngMessageFormat',
'ngMessages',
'ngMock',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
var standard = [
// Libraries in the angular.js repository
'ng',
'ngAnimate',
'ngAria',
'ngCookies',
'ngLocale',
'ngMessageFormat',
'ngMessages',
'ngMock',
'ngResource',
'ngRoute',
'ngSanitize',
'ngTouch',
// Libraries maintained by the angular team, but in another repository
'ngMaterial',
'ngNewRouter'
];
// Libraries maintained by the angular team, but in another repository
'ngMaterial',
'ngNewRouter'
];
function checkLiteral(node) {
if (node && node.type !== 'Literal') {
context.report(node, 'Unexpected non-literal value');
return false;
function checkLiteral(node) {
if (node && node.type !== 'Literal') {
context.report(node, 'Unexpected non-literal value');
return false;
}
if (!node) {
return false;
}
return true;
}
if (!node) {
return false;
function checkCombined(deps) {
var lastCorrect;
deps.elements.forEach(function(node) {
if (!checkLiteral(node)) {
return;
}
var value = node.value;
if (lastCorrect === undefined || lastCorrect.localeCompare(value) < 0) {
lastCorrect = value;
} else {
context.report(node, '{{current}} should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
}
});
}
return true;
}
function checkCombined(deps) {
var lastCorrect;
deps.elements.forEach(function(node) {
if (!checkLiteral(node)) {
return;
}
var value = node.value;
if (lastCorrect === undefined || lastCorrect.localeCompare(value) < 0) {
lastCorrect = value;
} else {
context.report(node, '{{current}} should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
}
});
}
function isStandardModule(value) {
return standard.indexOf(value) !== -1;
}
function isStandardModule(value) {
return standard.indexOf(value) !== -1;
}
function isCustomModule(value) {
return moduleRegex && moduleRegex.test(value);
}
function isCustomModule(value) {
return moduleRegex && moduleRegex.test(value);
}
function checkGrouped(deps) {
var lastCorrect;
var group = 'standard';
deps.elements.forEach(function loop(node) {
if (!checkLiteral(node)) {
return;
}
var value = node.value;
if (lastCorrect === undefined) {
lastCorrect = value;
if (isCustomModule(value)) {
group = 'custom';
} else if (standard.indexOf(value) === -1) {
group = 'third party';
function checkGrouped(deps) {
var lastCorrect;
var group = 'standard';
deps.elements.forEach(function loop(node) {
if (!checkLiteral(node)) {
return;
}
return;
}
if (group === 'standard') {
if (isStandardModule(value)) {
if (lastCorrect.localeCompare(value) > 0) {
var value = node.value;
if (lastCorrect === undefined) {
lastCorrect = value;
if (isCustomModule(value)) {
group = 'custom';
} else if (standard.indexOf(value) === -1) {
group = 'third party';
}
return;
}
if (group === 'standard') {
if (isStandardModule(value)) {
if (lastCorrect.localeCompare(value) > 0) {
context.report(node, '{{current}} should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
} else {
lastCorrect = value;
}
} else {
if (isCustomModule(value)) {
group = 'custom';
} else {
group = 'third party';
}
lastCorrect = value;
}
}
if (group === 'third party') {
if (isStandardModule(value)) {
context.report(node, '{{current}} is a standard module and should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
} else if (isCustomModule(value)) {
group = 'custom';
lastCorrect = value;
} else if (lastCorrect.localeCompare(value) > 0) {
context.report(node, '{{current}} should be sorted before {{last}}', {

@@ -113,74 +153,37 @@ current: value,

}
} else {
if (isCustomModule(value)) {
group = 'custom';
} else {
group = 'third party';
}
if (group === 'custom') {
if (isStandardModule(value)) {
context.report(node, '{{current}} is a standard module and should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
} else if (!isCustomModule(value)) {
context.report(node, '{{current}} is a third party module and should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
}
lastCorrect = value;
}
}
if (group === 'third party') {
if (isStandardModule(value)) {
context.report(node, '{{current}} is a standard module and should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
} else if (isCustomModule(value)) {
group = 'custom';
lastCorrect = value;
} else if (lastCorrect.localeCompare(value) > 0) {
context.report(node, '{{current}} should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
});
}
return {
CallExpression: function(node) {
if (!utils.isAngularModuleDeclaration(node)) {
return;
}
var deps = node.arguments[1];
if (deps.type !== 'ArrayExpression') {
context.report(deps, 'Dependencies should be a literal array');
return;
}
if (groupedMode) {
checkGrouped(deps);
} else {
lastCorrect = value;
checkCombined(deps);
}
}
if (group === 'custom') {
if (isStandardModule(value)) {
context.report(node, '{{current}} is a standard module and should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
} else if (!isCustomModule(value)) {
context.report(node, '{{current}} is a third party module and should be sorted before {{last}}', {
current: value,
last: lastCorrect
});
}
}
});
};
}
return {
CallExpression: function(node) {
if (!utils.isAngularModuleDeclaration(node)) {
return;
}
var deps = node.arguments[1];
if (deps.type !== 'ArrayExpression') {
context.report(deps, 'Dependencies should be a literal array');
return;
}
if (groupedMode) {
checkGrouped(deps);
} else {
checkCombined(deps);
}
}
};
};
module.exports.schema = [{
type: 'object',
properties: {
grouped: {
type: 'boolean'
},
prefix: {
type: ['string', 'null']
}
}
}];

@@ -16,7 +16,11 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
ExpressionStatement: function(node) {
if ((utils.isAngularControllerDeclaration(node.expression) ||
ExpressionStatement: function(node) {
if ((utils.isAngularControllerDeclaration(node.expression) ||
utils.isAngularFilterDeclaration(node.expression) ||

@@ -32,17 +36,14 @@ utils.isAngularServiceDeclaration(node.expression) ||

!utils.isAngularModuleDeclaration(node.expression)) {
var calleeObject = node.expression.callee.object;
while (calleeObject !== undefined && calleeObject.type === 'CallExpression' && !utils.isAngularModuleGetter(calleeObject)) {
calleeObject = calleeObject.callee.object;
}
var calleeObject = node.expression.callee.object;
if (!(calleeObject !== undefined && calleeObject.type === 'CallExpression' && utils.isAngularModuleGetter(calleeObject))) {
context.report(node, 'Avoid using a variable and instead use chaining with the getter syntax.');
while (calleeObject !== undefined && calleeObject.type === 'CallExpression' && !utils.isAngularModuleGetter(calleeObject)) {
calleeObject = calleeObject.callee.object;
}
if (!(calleeObject !== undefined && calleeObject.type === 'CallExpression' && utils.isAngularModuleGetter(calleeObject))) {
context.report(node, 'Avoid using a variable and instead use chaining with the getter syntax.');
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -17,38 +17,45 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}]
},
create: function(context) {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
convertedPrefix = utils.convertPrefixToRegex(prefix);
if (utils.isAngularModuleDeclaration(node)) {
var name = node.arguments[0].value;
if (utils.isAngularModuleDeclaration(node)) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('ng') === 0) {
context.report(node, 'The {{module}} module should not start with "ng". This is reserved for AngularJS modules', {
module: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{module}} module should be prefixed by {{prefix}}', {
module: name,
prefix: prefix
if (name !== undefined && name.indexOf('ng') === 0) {
context.report(node, 'The {{module}} module should not start with "ng". This is reserved for AngularJS modules', {
module: name
});
} else {
context.report(node, 'The {{module}} module should follow this pattern: {{prefix}}', {
module: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{module}} module should be prefixed by {{prefix}}', {
module: name,
prefix: prefix
});
} else {
context.report(node, 'The {{module}} module should follow this pattern: {{prefix}}', {
module: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -16,27 +16,28 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
VariableDeclaration: function(node) {
var variableDeclarator = node.declarations[0];
var rightExpression;
VariableDeclaration: function(node) {
var variableDeclarator = node.declarations[0];
var rightExpression;
if (variableDeclarator.init) {
rightExpression = variableDeclarator.init;
if (variableDeclarator.init) {
rightExpression = variableDeclarator.init;
if (rightExpression.arguments && utils.isAngularModuleDeclaration(rightExpression)) {
context.report(rightExpression, 'Declare modules without a variable using the setter syntax.');
if (rightExpression.arguments && utils.isAngularModuleDeclaration(rightExpression)) {
context.report(rightExpression, 'Declare modules without a variable using the setter syntax.');
}
}
},
AssignmentExpression: function(node) {
if (node.right.arguments && utils.isAngularModuleDeclaration(node.right)) {
context.report(node.right, 'Declare modules without a variable using the setter syntax.');
}
}
},
AssignmentExpression: function(node) {
if (node.right.arguments && utils.isAngularModuleDeclaration(node.right)) {
context.report(node.right, 'Declare modules without a variable using the setter syntax.');
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -33,20 +33,21 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
MemberExpression: function(node) {
if (node.object.type === 'Identifier' && node.object.name === 'angular' &&
MemberExpression: function(node) {
if (node.object.type === 'Identifier' && node.object.name === 'angular' &&
node.property.type === 'Identifier' && node.property.name === 'mock') {
if (node.parent.type === 'MemberExpression' && node.parent.property.type === 'Identifier') {
context.report(node, 'You should use the "{{method}}" method available in the window object.', {
method: node.parent.property.name
});
if (node.parent.type === 'MemberExpression' && node.parent.property.type === 'Identifier') {
context.report(node, 'You should use the "{{method}}" method available in the window object.', {
method: node.parent.property.name
});
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,15 +14,16 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
CallExpression: function(node) {
if (utils.isAngularControllerDeclaration(node)) {
context.report(node, 'Based on the Component-First Pattern, you should avoid the use of controllers', {});
CallExpression: function(node) {
if (utils.isAngularControllerDeclaration(node)) {
context.report(node, 'Based on the Component-First Pattern, you should avoid the use of controllers', {});
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -13,15 +13,16 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
MemberExpression: function(node) {
if (node.object && node.object.name === '$cookieStore') {
context.report(node, 'Since Angular 1.4, the $cookieStore service is deprecated. Please use now the $cookies service.', {});
MemberExpression: function(node) {
if (node.object && node.object.name === '$cookieStore') {
context.report(node, 'Since Angular 1.4, the $cookieStore service is deprecated. Please use now the $cookies service.', {});
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -17,87 +17,90 @@ /**

module.exports = angularRule(function(context) {
var options = context.options[0] || {};
var ignoreReplaceFalse = !!options.ignoreReplaceFalse;
module.exports = {
meta: {
schema: [{
type: 'object',
properties: {
ignoreReplaceFalse: {
type: 'boolean'
}
}
}]
},
create: angularRule(function(context) {
var options = context.options[0] || {};
var ignoreReplaceFalse = !!options.ignoreReplaceFalse;
var potentialReplaceNodes = {};
var potentialReplaceNodes = {};
function addPotentialReplaceNode(variableName, node) {
var nodeList = potentialReplaceNodes[variableName] || [];
function addPotentialReplaceNode(variableName, node) {
var nodeList = potentialReplaceNodes[variableName] || [];
nodeList.push({
name: variableName,
node: node,
block: context.getScope().block.body
});
nodeList.push({
name: variableName,
node: node,
block: context.getScope().block.body
});
potentialReplaceNodes[variableName] = nodeList;
}
potentialReplaceNodes[variableName] = nodeList;
}
return {
'angular:directive': function(callExpressionNode, fnNode) {
if (!fnNode || !fnNode.body) {
return;
}
fnNode.body.body.forEach(function(statement) {
if (statement.type === 'ReturnStatement') {
// get potential replace node by argument name of empty string for object expressions
var potentialNodes = potentialReplaceNodes[statement.argument.name || ''];
if (!potentialNodes) {
return;
return {
'angular:directive': function(callExpressionNode, fnNode) {
if (!fnNode || !fnNode.body) {
return;
}
fnNode.body.body.forEach(function(statement) {
if (statement.type === 'ReturnStatement') {
// get potential replace node by argument name of empty string for object expressions
var potentialNodes = potentialReplaceNodes[statement.argument.name || ''];
if (!potentialNodes) {
return;
}
potentialNodes.forEach(function(report) {
// only reports nodes that belong to the same expression
if (report.block === statement.parent) {
context.report(report.node, 'Directive definition property replace is deprecated.');
}
});
}
potentialNodes.forEach(function(report) {
// only reports nodes that belong to the same expression
if (report.block === statement.parent) {
context.report(report.node, 'Directive definition property replace is deprecated.');
}
});
});
},
AssignmentExpression: function(node) {
// Only check for literal member property assignments.
if (node.left.type !== 'MemberExpression') {
return;
}
});
},
AssignmentExpression: function(node) {
// Only check for literal member property assignments.
if (node.left.type !== 'MemberExpression') {
return;
}
// Only check setting properties named 'replace'.
if (node.left.property.name !== 'replace') {
return;
}
if (ignoreReplaceFalse && node.right.value === false) {
return;
}
addPotentialReplaceNode(node.left.object.name, node);
},
Property: function(node) {
// This only checks for objects which have defined a literal restrict property.
if (node.key.name !== 'replace') {
return;
}
if (ignoreReplaceFalse === true && node.value.value === false) {
return;
}
// Only check setting properties named 'replace'.
if (node.left.property.name !== 'replace') {
return;
}
if (ignoreReplaceFalse && node.right.value === false) {
return;
}
addPotentialReplaceNode(node.left.object.name, node);
},
Property: function(node) {
// This only checks for objects which have defined a literal restrict property.
if (node.key.name !== 'replace') {
return;
}
if (ignoreReplaceFalse === true && node.value.value === false) {
return;
}
// assumption: Property always belongs to a ObjectExpression
var objectExpressionParent = node.parent.parent;
// assumption: Property always belongs to a ObjectExpression
var objectExpressionParent = node.parent.parent;
// add to potential replace nodes if the object is defined in a variable
if (objectExpressionParent.type === 'VariableDeclarator') {
addPotentialReplaceNode(objectExpressionParent.id.name, node);
}
// add to potential replace nodes if the object is defined in a variable
if (objectExpressionParent.type === 'VariableDeclarator') {
addPotentialReplaceNode(objectExpressionParent.id.name, node);
}
// report directly if object is part of a return statement and inside a directive body
if (objectExpressionParent.type === 'ReturnStatement') {
addPotentialReplaceNode('', node);
// report directly if object is part of a return statement and inside a directive body
if (objectExpressionParent.type === 'ReturnStatement') {
addPotentialReplaceNode('', node);
}
}
}
};
});
module.exports.schema = [{
type: 'object',
properties: {
ignoreReplaceFalse: {
type: 'boolean'
}
}
}];
};
})
};

@@ -13,36 +13,41 @@ /**

module.exports = function(context) {
var httpMethods = [
'delete',
'get',
'head',
'jsonp',
'patch',
'post',
'put'
];
module.exports = {
meta: {
schema: []
},
create: function(context) {
var httpMethods = [
'delete',
'get',
'head',
'jsonp',
'patch',
'post',
'put'
];
function isHttpCall(node) {
if (node.callee.type === 'MemberExpression') {
return httpMethods.indexOf(node.callee.property.name) !== -1 ||
(node.callee.object.type === 'CallExpression' && isHttpCall(node.callee.object));
function isHttpCall(node) {
if (node.callee.type === 'MemberExpression') {
return httpMethods.indexOf(node.callee.property.name) !== -1 ||
(node.callee.object.type === 'CallExpression' && isHttpCall(node.callee.object));
}
if (node.callee.type === 'Identifier') {
return node.callee.name === '$http';
}
}
if (node.callee.type === 'Identifier') {
return node.callee.name === '$http';
}
}
return {
CallExpression: function(node) {
if (node.callee.type !== 'MemberExpression') {
return;
return {
CallExpression: function(node) {
if (node.callee.type !== 'MemberExpression') {
return;
}
if (node.callee.property.name === 'success' && isHttpCall(node)) {
return context.report(node, '$http success is deprecated. Use then instead');
}
if (node.callee.property.name === 'error' && isHttpCall(node)) {
context.report(node, '$http error is deprecated. Use then or catch instead');
}
}
if (node.callee.property.name === 'success' && isHttpCall(node)) {
return context.report(node, '$http success is deprecated. Use then instead');
}
if (node.callee.property.name === 'error' && isHttpCall(node)) {
context.report(node, '$http error is deprecated. Use then or catch instead');
}
}
};
};
}
};

@@ -14,39 +14,42 @@ /**

module.exports = function(context) {
// Extracts any HTML tags.
var regularTagPattern = /<(.+?)>/g;
// Extracts self closing HTML tags.
var selfClosingTagPattern = /<(.+?)\/>/g;
module.exports = {
meta: {
schema: [{
allowSimple: {
type: 'boolean'
}
}]
},
create: function(context) {
// Extracts any HTML tags.
var regularTagPattern = /<(.+?)>/g;
// Extracts self closing HTML tags.
var selfClosingTagPattern = /<(.+?)\/>/g;
var allowSimple = (context.options[0] && context.options[0].allowSimple) !== false;
var allowSimple = (context.options[0] && context.options[0].allowSimple) !== false;
function reportComplex(node) {
context.report(node, 'Inline template is too complex. Use an external template instead');
}
function reportComplex(node) {
context.report(node, 'Inline template is too complex. Use an external template instead');
}
return {
Property: function(node) {
if (node.key.name !== 'template' || node.value.type !== 'Literal') {
return;
return {
Property: function(node) {
if (node.key.name !== 'template' || node.value.type !== 'Literal') {
return;
}
if (!allowSimple) {
context.report(node, 'Inline templates are not allowed. Use an external template instead');
}
if ((node.value.value && node.value.value.match(regularTagPattern) || []).length > 2) {
return reportComplex(node);
}
if ((node.value.value && node.value.value.match(selfClosingTagPattern) || []).length > 1) {
return reportComplex(node);
}
if (node.value && node.value.raw.indexOf('\\') !== -1) {
reportComplex(node);
}
}
if (!allowSimple) {
context.report(node, 'Inline templates are not allowed. Use an external template instead');
}
if ((node.value.value && node.value.value.match(regularTagPattern) || []).length > 2) {
return reportComplex(node);
}
if ((node.value.value && node.value.value.match(selfClosingTagPattern) || []).length > 1) {
return reportComplex(node);
}
if (node.value && node.value.raw.indexOf('\\') !== -1) {
reportComplex(node);
}
}
};
};
}
};
module.exports.schema = [{
allowSimple: {
type: 'boolean'
}
}];

@@ -11,20 +11,21 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
MemberExpression: function(node) {
if (node.object.name === 'angular' && node.property.name === 'element') {
if (node.parent !== undefined && node.parent.parent !== undefined &&
MemberExpression: function(node) {
if (node.object.name === 'angular' && node.property.name === 'element') {
if (node.parent !== undefined && node.parent.parent !== undefined &&
node.parent.parent.type === 'CallExpression' &&
node.parent.parent.callee.type === 'Identifier' &&
(node.parent.parent.callee.name === 'jQuery' || node.parent.parent.callee.name === '$')) {
context.report(node, 'angular.element returns already a jQLite element. No need to wrap with the jQuery object', {});
context.report(node, 'angular.element returns already a jQLite element. No need to wrap with the jQuery object', {});
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,32 +14,35 @@ /**

module.exports = function(context) {
var options = context.options[0] || {};
var allowed = options.allow || [];
module.exports = {
meta: {
schema: [
{
type: 'object',
properties: {
allow: {
type: 'array',
items: {
type: 'string'
}
}
},
additionalProperties: false
}
]
},
create: function(context) {
var options = context.options[0] || {};
var allowed = options.allow || [];
function check(node, name) {
if (name.slice(0, 2) === '$$' && allowed.indexOf(name) < 0) {
context.report(node, 'Using $$-prefixed Angular objects/methods are not recommended', {});
function check(node, name) {
if (name.slice(0, 2) === '$$' && allowed.indexOf(name) < 0) {
context.report(node, 'Using $$-prefixed Angular objects/methods are not recommended', {});
}
}
}
return {
return {
Identifier: function(node) {
check(node, node.name);
}
};
};
module.exports.schema = [
{
type: 'object',
properties: {
allow: {
type: 'array',
items: {
type: 'string'
}
Identifier: function(node) {
check(node, node.name);
}
},
additionalProperties: false
};
}
];
};

@@ -16,46 +16,49 @@ /**

module.exports = angularRule(function(context) {
var options = context.options[0] || {};
var allowParams = options.allowParams !== false;
module.exports = {
meta: {
schema: [{
type: 'object',
properties: {
allowParams: {
type: 'boolean'
}
}
}]
},
create: angularRule(function(context) {
var options = context.options[0] || {};
var allowParams = options.allowParams !== false;
function report(node) {
context.report(node, 'The run function may only contain call expressions');
}
function report(node) {
context.report(node, 'The run function may only contain call expressions');
}
return {
'angular:run': function(callExpression, fn) {
if (!fn) {
return;
}
fn.body.body.forEach(function(statement) {
if (statement.type !== 'ExpressionStatement') {
return report(statement);
return {
'angular:run': function(callExpression, fn) {
if (!fn) {
return;
}
var expression = statement.expression;
if (expression.type !== 'CallExpression') {
return report(statement);
}
if (expression.callee.type === 'MemberExpression' && expression.callee.object.type !== 'Identifier') {
return report(statement);
}
if (!allowParams && expression.arguments.length) {
return context.report(expression, 'Run function call expressions may not take any arguments');
}
expression.arguments.forEach(function(argument) {
if (argument.type !== 'Literal' && argument.type !== 'Identifier') {
context.report(argument, 'Run function call expressions may only take simple arguments');
fn.body.body.forEach(function(statement) {
if (statement.type !== 'ExpressionStatement') {
return report(statement);
}
var expression = statement.expression;
if (expression.type !== 'CallExpression') {
return report(statement);
}
if (expression.callee.type === 'MemberExpression' && expression.callee.object.type !== 'Identifier') {
return report(statement);
}
if (!allowParams && expression.arguments.length) {
return context.report(expression, 'Run function call expressions may not take any arguments');
}
expression.arguments.forEach(function(argument) {
if (argument.type !== 'Literal' && argument.type !== 'Identifier') {
context.report(argument, 'Run function call expressions may only take simple arguments');
}
});
});
});
}
};
});
module.exports.schema = [{
type: 'object',
properties: {
allowParams: {
type: 'boolean'
}
}
}];
}
};
})
};

@@ -15,11 +15,16 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
return {
CallExpression: function(node) {
if (utils.isAngularComponent(node) && node.callee.property && node.callee.property.name === 'service') {
context.report(node, 'You should prefer the factory() method instead of service()', {});
CallExpression: function(node) {
if (utils.isAngularComponent(node) && node.callee.property && node.callee.property.name === 'service') {
context.report(node, 'You should prefer the factory() method instead of service()', {});
}
}
}
};
};
}
};

@@ -18,80 +18,82 @@ /**

module.exports = function(context) {
var angularObjectList = ['controller', 'filter', 'directive'];
var badServices;
var map;
var message = 'REST API calls should be implemented in a specific service';
module.exports = {
meta: {
schema: [{
type: ['array', 'object']
}, {
type: 'array'
}]
},
create: function(context) {
var angularObjectList = ['controller', 'filter', 'directive'];
var badServices;
var map;
var message = 'REST API calls should be implemented in a specific service';
function isArray(item) {
return Object.prototype.toString.call(item) === '[object Array]';
}
function isArray(item) {
return Object.prototype.toString.call(item) === '[object Array]';
}
function isObject(item) {
return Object.prototype.toString.call(item) === '[object Object]';
}
function isObject(item) {
return Object.prototype.toString.call(item) === '[object Object]';
}
if (context.options[0] === undefined) {
badServices = ['$http', '$resource', 'Restangular', '$q', '$filter'];
}
if (context.options[0] === undefined) {
badServices = ['$http', '$resource', 'Restangular', '$q', '$filter'];
}
if (isArray(context.options[0])) {
badServices = context.options[0];
}
if (isArray(context.options[0])) {
badServices = context.options[0];
}
if (isArray(context.options[1])) {
angularObjectList = context.options[1];
}
if (isArray(context.options[1])) {
angularObjectList = context.options[1];
}
if (isObject(context.options[0])) {
map = context.options[0];
var result = [];
var prop;
if (isObject(context.options[0])) {
map = context.options[0];
var result = [];
var prop;
for (prop in map) {
if (map.hasOwnProperty(prop)) {
result.push(prop);
for (prop in map) {
if (map.hasOwnProperty(prop)) {
result.push(prop);
}
}
angularObjectList = result;
}
angularObjectList = result;
}
function isSetBedService(serviceName, angularObjectName) {
if (map) {
return map[angularObjectName].indexOf(serviceName) >= 0;
function isSetBedService(serviceName, angularObjectName) {
if (map) {
return map[angularObjectName].indexOf(serviceName) >= 0;
}
return badServices.indexOf(serviceName) >= 0;
}
return badServices.indexOf(serviceName) >= 0;
}
return {
return {
CallExpression: function(node) {
var callee = node.callee;
CallExpression: function(node) {
var callee = node.callee;
if (utils.isAngularComponent(node) && callee.type === 'MemberExpression' && angularObjectList.indexOf(callee.property.name) >= 0) {
if (utils.isFunctionType(node.arguments[1])) {
node.arguments[1].params.forEach(function(service) {
if (service.type === 'Identifier' && isSetBedService(service.name, callee.property.name)) {
context.report(node, message + ' (' + service.name + ' in ' + callee.property.name + ')', {});
}
});
}
if (utils.isAngularComponent(node) && callee.type === 'MemberExpression' && angularObjectList.indexOf(callee.property.name) >= 0) {
if (utils.isFunctionType(node.arguments[1])) {
node.arguments[1].params.forEach(function(service) {
if (service.type === 'Identifier' && isSetBedService(service.name, callee.property.name)) {
context.report(node, message + ' (' + service.name + ' in ' + callee.property.name + ')', {});
}
});
}
if (utils.isArrayType(node.arguments[1])) {
node.arguments[1].elements.forEach(function(service) {
if (service.type === 'Literal' && isSetBedService(service.value, callee.property.name)) {
context.report(node, message + ' (' + service.value + ' in ' + callee.property.name + ')', {});
}
});
if (utils.isArrayType(node.arguments[1])) {
node.arguments[1].elements.forEach(function(service) {
if (service.type === 'Literal' && isSetBedService(service.value, callee.property.name)) {
context.report(node, message + ' (' + service.value + ' in ' + callee.property.name + ')', {});
}
});
}
}
}
}
};
};
}
};
module.exports.schema = [{
type: ['array', 'object']
}, {
type: 'array'
}];

@@ -11,52 +11,53 @@ /**

module.exports = function(context) {
function report(node) {
context.report(node, 'You probably misspelled $on("$destroy").');
}
/**
* Return true if the given node is a call expression calling a function
* named '$on'.
*/
function isOn(node) {
var calledFunction = node.callee;
if (calledFunction.type !== 'MemberExpression') {
return false;
module.exports = {
meta: {
schema: []
},
create: function(context) {
function report(node) {
context.report(node, 'You probably misspelled $on("$destroy").');
}
// can only easily tell what name was used if a simple
// identifiers were used to access it.
var accessedFunction = calledFunction.property;
if (accessedFunction.type !== 'Identifier') {
return false;
}
/**
* Return true if the given node is a call expression calling a function
* named '$on'.
*/
function isOn(node) {
var calledFunction = node.callee;
if (calledFunction.type !== 'MemberExpression') {
return false;
}
var functionName = accessedFunction.name;
// can only easily tell what name was used if a simple
// identifiers were used to access it.
var accessedFunction = calledFunction.property;
if (accessedFunction.type !== 'Identifier') {
return false;
}
return functionName === '$on';
}
var functionName = accessedFunction.name;
/**
* 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 functionName === '$on';
}
return (args.length >= 1 &&
/**
* 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 (isOn(node) && isFirstArgDestroy(node)) {
report(node);
return {
CallExpression: function(node) {
if (isOn(node) && isFirstArgDestroy(node)) {
report(node);
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -11,72 +11,73 @@ /**

module.exports = 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;
module.exports = {
meta: {
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
});
}
var calledFunction = node.callee;
if (calledFunction.type !== 'MemberExpression') {
return false;
}
/**
* 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;
}
// 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;
var calledFunction = node.callee;
if (calledFunction.type !== 'MemberExpression') {
return false;
}
// cannot check name of the parent object if it is returned from a
// complex expression.
if (parentObject.type !== 'Identifier' ||
accessedFunction.type !== 'Identifier') {
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;
var objectName = parentObject.name;
var functionName = accessedFunction.name;
// cannot check name of the parent object if it is returned from a
// complex expression.
if (parentObject.type !== 'Identifier' ||
accessedFunction.type !== 'Identifier') {
return false;
}
return scopes.indexOf(objectName) >= 0 && (functionName === '$on' ||
functionName === '$watch');
}
var objectName = parentObject.name;
var functionName = accessedFunction.name;
/**
* 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 scopes.indexOf(objectName) >= 0 && (functionName === '$on' ||
functionName === '$watch');
}
return (args.length >= 1 &&
/**
* 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 {
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);
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);
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,118 +14,123 @@ /**

module.exports = function(context) {
var angularObjectList = ['animation', 'config', 'constant', 'controller', 'directive', 'factory', 'filter', 'provider', 'service', 'value', 'decorator'];
module.exports = {
meta: {
schema: []
},
create: function(context) {
var angularObjectList = ['animation', 'config', 'constant', 'controller', 'directive', 'factory', 'filter', 'provider', 'service', 'value', 'decorator'];
function checkArgumentPositionInFunction(node) {
if (!node.params || node.params.length < 2) {
return;
function checkArgumentPositionInFunction(node) {
if (!node.params || node.params.length < 2) {
return;
}
var linesFound = [];
node.params.forEach(reportMultipleItemsInOneLine.bind(null, node, linesFound));
}
var linesFound = [];
node.params.forEach(reportMultipleItemsInOneLine.bind(null, node, linesFound));
}
function reportMultipleItemsInOneLine(node, linesFound, item) {
var currentLine = item.loc.start.line;
if (linesFound.indexOf(currentLine) !== -1) {
context.report({
node: node,
message: 'Do not use multiple dependencies in one line',
loc: item.loc.start
});
}
linesFound.push(currentLine);
}
function reportMultipleItemsInOneLine(node, linesFound, item) {
var currentLine = item.loc.start.line;
if (linesFound.indexOf(currentLine) !== -1) {
context.report({
node: node,
message: 'Do not use multiple dependencies in one line',
loc: item.loc.start
function checkArgumentPositionArrayExpression(angularComponentNode, arrayNode) {
var linesFound = [];
arrayNode.elements.forEach(function(element) {
if (element.type === 'Literal') {
reportMultipleItemsInOneLine(arrayNode, linesFound, element);
}
if (element.type === 'FunctionExpression') {
checkArgumentPositionInFunction(element);
}
if (element.type === 'Identifier') {
var fn = getFunctionDeclaration(angularComponentNode, element.name);
checkArgumentPositionInFunction(fn);
}
});
}
linesFound.push(currentLine);
}
function checkArgumentPositionArrayExpression(angularComponentNode, arrayNode) {
var linesFound = [];
function findFunctionDeclarationByDeclaration(body, fName) {
return body.find(function(item) {
return item.type === 'FunctionDeclaration' && item.id.name === fName;
});
}
arrayNode.elements.forEach(function(element) {
if (element.type === 'Literal') {
reportMultipleItemsInOneLine(arrayNode, linesFound, element);
}
if (element.type === 'FunctionExpression') {
checkArgumentPositionInFunction(element);
}
if (element.type === 'Identifier') {
var fn = getFunctionDeclaration(angularComponentNode, element.name);
checkArgumentPositionInFunction(fn);
}
});
}
function findFunctionDeclarationByVariableDeclaration(body, fName) {
var fn;
body.forEach(function(item) {
if (fn) {
return;
}
if (item.type === 'VariableDeclaration') {
item.declarations.forEach(function(declaration) {
if (declaration.type === 'VariableDeclarator' &&
declaration.id &&
declaration.id.name === fName &&
declaration.init &&
declaration.init.type === 'FunctionExpression'
) {
fn = declaration.init;
}
});
}
});
return fn;
}
function findFunctionDeclarationByDeclaration(body, fName) {
return body.find(function(item) {
return item.type === 'FunctionDeclaration' && item.id.name === fName;
});
}
function findFunctionDeclarationByVariableDeclaration(body, fName) {
var fn;
body.forEach(function(item) {
if (fn) {
return;
}
if (item.type === 'VariableDeclaration') {
item.declarations.forEach(function(declaration) {
if (declaration.type === 'VariableDeclarator' &&
declaration.id &&
declaration.id.name === fName &&
declaration.init &&
declaration.init.type === 'FunctionExpression'
) {
fn = declaration.init;
function getFunctionDeclaration(node, fName) {
if (node.type === 'BlockStatement' || node.type === 'Program') {
if (node.body) {
var fn = findFunctionDeclarationByDeclaration(node.body, fName);
if (fn) {
return fn;
}
});
}
});
return fn;
}
function getFunctionDeclaration(node, fName) {
if (node.type === 'BlockStatement' || node.type === 'Program') {
if (node.body) {
var fn = findFunctionDeclarationByDeclaration(node.body, fName);
if (fn) {
return fn;
fn = findFunctionDeclarationByVariableDeclaration(node.body, fName);
if (fn) {
return fn;
}
}
fn = findFunctionDeclarationByVariableDeclaration(node.body, fName);
if (fn) {
return fn;
}
}
if (node.parent) {
return getFunctionDeclaration(node.parent, fName);
}
}
if (node.parent) {
return getFunctionDeclaration(node.parent, fName);
}
}
return {
return {
CallExpression: function(node) {
var fn;
if (utils.isAngularComponent(node) &&
node.callee.type === 'MemberExpression' &&
node.arguments[1].type === 'FunctionExpression' &&
angularObjectList.indexOf(node.callee.property.name) >= 0) {
fn = node.arguments[1];
return checkArgumentPositionInFunction(fn);
}
if (utils.isAngularComponent(node) &&
node.callee.type === 'MemberExpression' &&
node.arguments[1].type === 'Identifier' &&
angularObjectList.indexOf(node.callee.property.name) >= 0) {
var fName = node.arguments[1].name;
fn = getFunctionDeclaration(node, fName);
if (fn) {
CallExpression: function(node) {
var fn;
if (utils.isAngularComponent(node) &&
node.callee.type === 'MemberExpression' &&
node.arguments[1].type === 'FunctionExpression' &&
angularObjectList.indexOf(node.callee.property.name) >= 0) {
fn = node.arguments[1];
return checkArgumentPositionInFunction(fn);
}
if (utils.isAngularComponent(node) &&
node.callee.type === 'MemberExpression' &&
node.arguments[1].type === 'Identifier' &&
angularObjectList.indexOf(node.callee.property.name) >= 0) {
var fName = node.arguments[1].name;
fn = getFunctionDeclaration(node, fName);
if (fn) {
return checkArgumentPositionInFunction(fn);
}
}
if (utils.isAngularComponent(node) &&
node.callee.type === 'MemberExpression' &&
node.arguments[1].type === 'ArrayExpression' &&
angularObjectList.indexOf(node.callee.property.name) >= 0) {
return checkArgumentPositionArrayExpression(node, node.arguments[1]);
}
}
if (utils.isAngularComponent(node) &&
node.callee.type === 'MemberExpression' &&
node.arguments[1].type === 'ArrayExpression' &&
angularObjectList.indexOf(node.callee.property.name) >= 0) {
return checkArgumentPositionArrayExpression(node, node.arguments[1]);
}
}
};
};
}
};

@@ -14,65 +14,68 @@ /*

module.exports = angularRule(function(context) {
var potentialReplaceNodes = {};
module.exports = {
meta: {
schema: []
},
create: angularRule(function(context) {
var potentialReplaceNodes = {};
function addPotentialLinkNode(variableName, node) {
var nodeList = potentialReplaceNodes[variableName] || [];
function addPotentialLinkNode(variableName, node) {
var nodeList = potentialReplaceNodes[variableName] || [];
nodeList.push({
name: variableName,
node: node,
block: context.getScope().block.body
});
nodeList.push({
name: variableName,
node: node,
block: context.getScope().block.body
});
potentialReplaceNodes[variableName] = nodeList;
}
potentialReplaceNodes[variableName] = nodeList;
}
return {
'angular:directive': function(callExpressionNode, fnNode) {
if (!fnNode || !fnNode.body) {
return;
}
fnNode.body.body.forEach(function(statement) {
if (statement.type === 'ReturnStatement' && !potentialReplaceNodes[statement.argument.name || '']) {
context.report(statement, 'Directive should be implemented with the component method.');
return {
'angular:directive': function(callExpressionNode, fnNode) {
if (!fnNode || !fnNode.body) {
return;
}
});
},
AssignmentExpression: function(node) {
// Only check for literal member property assignments.
if (node.left.type !== 'MemberExpression') {
return;
}
fnNode.body.body.forEach(function(statement) {
if (statement.type === 'ReturnStatement' && !potentialReplaceNodes[statement.argument.name || '']) {
context.report(statement, 'Directive should be implemented with the component method.');
}
});
},
AssignmentExpression: function(node) {
// Only check for literal member property assignments.
if (node.left.type !== 'MemberExpression') {
return;
}
if (allowedProperties.indexOf(node.left.property.name) < 0) {
return;
}
if (allowedProperties.indexOf(node.left.property.name) < 0) {
return;
}
addPotentialLinkNode(node.left.object.name, node);
},
Property: function(node) {
if (node.key.name === 'restrict') {
if (node.value.raw && node.value.raw.indexOf('C') < 0 && node.value.raw.indexOf('A') < 0) {
addPotentialLinkNode(node.left.object.name, node);
},
Property: function(node) {
if (node.key.name === 'restrict') {
if (node.value.raw && node.value.raw.indexOf('C') < 0 && node.value.raw.indexOf('A') < 0) {
return;
}
} else if (allowedProperties.indexOf(node.key.name) < 0) {
return;
}
} else if (allowedProperties.indexOf(node.key.name) < 0) {
return;
}
// assumption: Property always belongs to a ObjectExpression
var objectExpressionParent = node.parent.parent;
// assumption: Property always belongs to a ObjectExpression
var objectExpressionParent = node.parent.parent;
// add to potential link nodes if the object is defined in a variable
if (objectExpressionParent.type === 'VariableDeclarator') {
addPotentialLinkNode(objectExpressionParent.id.name, node);
}
// add to potential link nodes if the object is defined in a variable
if (objectExpressionParent.type === 'VariableDeclarator') {
addPotentialLinkNode(objectExpressionParent.id.name, node);
}
// report directly if object is part of a return statement and inside a directive body
if (objectExpressionParent.type === 'ReturnStatement') {
addPotentialLinkNode('', node);
// report directly if object is part of a return statement and inside a directive body
if (objectExpressionParent.type === 'ReturnStatement') {
addPotentialLinkNode('', node);
}
}
}
};
});
module.exports.schema = [];
};
})
};

@@ -18,40 +18,49 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}, {
type: 'object'
}]
},
create: function(context) {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isProvider;
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isProvider;
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
isProvider = utils.isAngularProviderDeclaration(node);
convertedPrefix = utils.convertPrefixToRegex(prefix);
isProvider = utils.isAngularProviderDeclaration(node);
if (isProvider) {
var name = node.arguments[0].value;
if (isProvider) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{provider}} provider should not start with "$". This is reserved for AngularJS services', {
provider: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{provider}} provider should be prefixed by {{prefix}}', {
provider: name,
prefix: prefix
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{provider}} provider should not start with "$". This is reserved for AngularJS services', {
provider: name
});
} else {
context.report(node, 'The {{provider}} provider should follow this pattern: {{prefix}}', {
provider: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{provider}} provider should be prefixed by {{prefix}}', {
provider: name,
prefix: prefix
});
} else {
context.report(node, 'The {{provider}} provider should follow this pattern: {{prefix}}', {
provider: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -15,44 +15,47 @@ /**

module.exports = function(context) {
var angularObjectList = ['controller', 'filter', 'directive', 'service', 'factory', 'provider'];
var services = ['$http', '$resource', 'Restangular'];
var message = 'You should use the same service ({{method}}) for REST API calls';
module.exports = {
meta: {
schema: [{
type: 'string'
}]
},
create: function(context) {
var angularObjectList = ['controller', 'filter', 'directive', 'service', 'factory', 'provider'];
var services = ['$http', '$resource', 'Restangular'];
var message = 'You should use the same service ({{method}}) for REST API calls';
return {
return {
CallExpression: function(node) {
function checkElement(element) {
if (element.type === 'Identifier' && services.indexOf(element.name) >= 0 && context.options[0] !== element.name) {
context.report(node, message, {
method: context.options[0]
});
} else if (element.type === 'Literal' && services.indexOf(element.value) >= 0 && context.options[0] !== element.value) {
context.report(node, message, {
method: context.options[0]
});
CallExpression: function(node) {
function checkElement(element) {
if (element.type === 'Identifier' && services.indexOf(element.name) >= 0 && context.options[0] !== element.name) {
context.report(node, message, {
method: context.options[0]
});
} else if (element.type === 'Literal' && services.indexOf(element.value) >= 0 && context.options[0] !== element.value) {
context.report(node, message, {
method: context.options[0]
});
}
}
}
function checkAllElements(elements) {
elements.forEach(checkElement);
}
function checkAllElements(elements) {
elements.forEach(checkElement);
}
var callee = node.callee;
var callee = node.callee;
if (utils.isAngularComponent(node) && callee.type === 'MemberExpression' && angularObjectList.indexOf(callee.property.name) >= 0) {
if (utils.isFunctionType(node.arguments[1])) {
checkAllElements(node.arguments[1].params);
}
if (utils.isAngularComponent(node) && callee.type === 'MemberExpression' && angularObjectList.indexOf(callee.property.name) >= 0) {
if (utils.isFunctionType(node.arguments[1])) {
checkAllElements(node.arguments[1].params);
}
if (utils.isArrayType(node.arguments[1])) {
checkAllElements(node.arguments[1].elements);
if (utils.isArrayType(node.arguments[1])) {
checkAllElements(node.arguments[1].elements);
}
}
}
}
};
};
}
};
module.exports.schema = [{
type: 'string'
}];

@@ -47,49 +47,58 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}, {
type: 'object'
}]
},
create: function(context) {
return {
CallExpression: function(node) {
var config = getConfig(context.options);
var prefix = getPrefixFromOptions(context.options);
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isService;
CallExpression: function(node) {
var config = getConfig(context.options);
var prefix = getPrefixFromOptions(context.options);
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isService;
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
convertedPrefix = utils.convertPrefixToRegex(prefix);
if (config.oldBehavior) {
isService = utils.isAngularServiceDeclarationDeprecated(node);
// Warning that the API is deprecated
// eslint-disable-next-line
console.warn('The rule `angular/service-name` will be split up to different rules in the next version. Please read the docs for more information');
} else {
isService = utils.isAngularServiceDeclaration(node);
}
if (config.oldBehavior) {
isService = utils.isAngularServiceDeclarationDeprecated(node);
// Warning that the API is deprecated
// eslint-disable-next-line
console.warn('The rule `angular/service-name` will be split up to different rules in the next version. Please read the docs for more information');
} else {
isService = utils.isAngularServiceDeclaration(node);
}
if (isService) {
var name = node.arguments[0].value;
if (isService) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{service}} service should not start with "$". This is reserved for AngularJS services', {
service: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{service}} service should be prefixed by {{prefix}}', {
service: name,
prefix: prefix
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{service}} service should not start with "$". This is reserved for AngularJS services', {
service: name
});
} else {
context.report(node, 'The {{service}} service should follow this pattern: {{prefix}}', {
service: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{service}} service should be prefixed by {{prefix}}', {
service: name,
prefix: prefix
});
} else {
context.report(node, 'The {{service}} service should follow this pattern: {{prefix}}', {
service: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -13,23 +13,39 @@ /**

module.exports = function(context) {
var message = 'You should use the $timeout service instead of the default window.setTimeout method';
module.exports = {
meta: {
schema: []
},
create: function(context) {
var message = 'You should use the $timeout service instead of the default window.setTimeout method';
return {
return {
MemberExpression: function(node) {
if (node.object.name === 'window' && node.property.name === 'setTimeout') {
context.report(node, message, {});
}
},
MemberExpression: function(node) {
if (node.property.name !== 'setTimeout') {
return;
}
CallExpression: function(node) {
if (node.callee.name === 'setTimeout') {
context.report(node, message, {});
if (node.object.type === 'Identifier') {
if ((node.object.name === 'window' || node.object.name === '$window')) {
context.report(node, message, {});
}
return;
}
// Detect expression this.$window.setTimeout which is what we would see in ES6 code when using classes
var parentNode = node.object;
if (parentNode.object.type === 'ThisExpression' && parentNode.property.name === '$window') {
context.report(node, message, {});
}
},
CallExpression: function(node) {
if (node.callee.name === 'setTimeout') {
context.report(node, message, {});
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,29 +14,30 @@ /**

module.exports = function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && node.value === '[object Array]') {
context.report(origin, 'You should use the angular.isArray method', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && node.value === '[object Array]') {
context.report(origin, 'You should use the angular.isArray method', {});
}
}
}
return {
MemberExpression: function(node) {
if (node.object.name === 'Array' && node.property.name === 'isArray') {
context.report(node, 'You should use the angular.isArray method', {});
}
},
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
return {
MemberExpression: function(node) {
if (node.object.name === 'Array' && node.property.name === 'isArray') {
context.report(node, 'You should use the angular.isArray method', {});
}
},
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,25 +14,26 @@ /**

module.exports = function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && node.value === '[object Date]') {
context.report(origin, 'You should use the angular.isDate method', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && node.value === '[object Date]') {
context.report(origin, 'You should use the angular.isDate method', {});
}
}
}
return {
return {
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,25 +14,26 @@ /**

module.exports = function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'function' || node.value === '[object Function]')) {
context.report(origin, 'You should use the angular.isFunction method', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'function' || node.value === '[object Function]')) {
context.report(origin, 'You should use the angular.isFunction method', {});
}
}
}
return {
return {
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,26 +14,27 @@ /**

module.exports = function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'number' || node.value === '[object Number]')) {
context.report(origin, 'You should use the angular.isNumber method', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'number' || node.value === '[object Number]')) {
context.report(origin, 'You should use the angular.isNumber method', {});
}
}
}
return {
return {
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,24 +14,25 @@ /**

module.exports = function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'object' || node.value === '[object Object]')) {
context.report(origin, 'You should use the angular.isObject method', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'object' || node.value === '[object Object]')) {
context.report(origin, 'You should use the angular.isObject method', {});
}
}
}
return {
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
return {
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -14,25 +14,26 @@ /**

module.exports = function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'string' || node.value === '[object String]')) {
context.report(origin, 'You should use the angular.isString method', {});
module.exports = {
meta: {
schema: []
},
create: function(context) {
function recordError(node, origin) {
if (node.type === 'Literal' && (node.value === 'string' || node.value === '[object String]')) {
context.report(origin, 'You should use the angular.isString method', {});
}
}
}
return {
return {
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
BinaryExpression: function(node) {
if (node.operator === '===' || node.operator === '!==') {
if (utils.isTypeOfStatement(node.left) || utils.isToStringStatement(node.left)) {
recordError(node.right, node);
} else if (utils.isTypeOfStatement(node.right) || utils.isToStringStatement(node.right)) {
recordError(node.left, node);
}
}
}
}
};
};
}
};
module.exports.schema = [
// JSON Schema for rule options goes here
];

@@ -200,3 +200,3 @@ 'use strict';

if (node.type === 'ArrayExpression') {
node = node.elements[node.elements.length - 1];
node = node.elements[node.elements.length - 1] || {};
}

@@ -209,2 +209,3 @@ if (node.type === 'FunctionExpression' || node.type === 'FunctionDeclaration') {

}
var func;

@@ -211,0 +212,0 @@ scope.variables.some(function(variable) {

'use strict';
var falseConfigValues = require('./false-values').config;
var scopeProperties = [

@@ -258,3 +258,3 @@ '$id',

node.arguments.length === 2 &&
isLiteralType(node.arguments[0]) &&
(isLiteralType(node.arguments[0]) || isIdentifierType(node.arguments[0])) &&
(isIdentifierType(node.arguments[1]) ||

@@ -491,3 +491,4 @@ isFunctionType(node.arguments[1]) ||

node.callee.property.type === 'Identifier' &&
node.callee.property.name === 'config';
node.callee.property.name === 'config' &&
falseConfigValues.indexOf(node.callee.object.name) < 0;
}

@@ -494,0 +495,0 @@

@@ -18,40 +18,47 @@ /**

module.exports = function(context) {
return {
module.exports = {
meta: {
schema: [{
type: ['string', 'object']
}]
},
create: function(context) {
return {
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isValue;
CallExpression: function(node) {
var prefix = context.options[0];
var convertedPrefix; // convert string from JSON .eslintrc to regex
var isValue;
if (prefix === undefined) {
return;
}
if (prefix === undefined) {
return;
}
convertedPrefix = utils.convertPrefixToRegex(prefix);
isValue = utils.isAngularValueDeclaration(node);
convertedPrefix = utils.convertPrefixToRegex(prefix);
isValue = utils.isAngularValueDeclaration(node);
if (isValue) {
var name = node.arguments[0].value;
if (isValue) {
var name = node.arguments[0].value;
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{value}} value should not start with "$". This is reserved for AngularJS services', {
value: name
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{value}} value should be prefixed by {{prefix}}', {
value: name,
prefix: prefix
if (name !== undefined && name.indexOf('$') === 0) {
context.report(node, 'The {{value}} value should not start with "$". This is reserved for AngularJS services', {
value: name
});
} else {
context.report(node, 'The {{value}} value should follow this pattern: {{prefix}}', {
value: name,
prefix: prefix.toString()
});
} else if (name !== undefined && !convertedPrefix.test(name)) {
if (typeof prefix === 'string' && !utils.isStringRegexp(prefix)) {
context.report(node, 'The {{value}} value should be prefixed by {{prefix}}', {
value: name,
prefix: prefix
});
} else {
context.report(node, 'The {{value}} value should follow this pattern: {{prefix}}', {
value: name,
prefix: prefix.toString()
});
}
}
}
}
}
};
};
}
};

@@ -13,23 +13,26 @@ /**

module.exports = function(context) {
var method = context.options[0] || '$digest';
var methods = ['$apply', '$digest'];
return {
module.exports = {
meta: {
schema: [{
enum: ['$apply', '$digest']
}]
},
create: function(context) {
var method = context.options[0] || '$digest';
var methods = ['$apply', '$digest'];
return {
MemberExpression: function(node) {
var forbiddenMethod = methods.filter(function(m) {
return m !== method;
});
if (forbiddenMethod.length > 0 && node.property.type === 'Identifier' && forbiddenMethod.indexOf(node.property.name) >= 0) {
context.report(node, 'Instead of using the {{forbidden}}() method, you should prefer {{method}}()', {
forbidden: node.property.name,
method: method
MemberExpression: function(node) {
var forbiddenMethod = methods.filter(function(m) {
return m !== method;
});
if (forbiddenMethod.length > 0 && node.property.type === 'Identifier' && forbiddenMethod.indexOf(node.property.name) >= 0) {
context.report(node, 'Instead of using the {{forbidden}}() method, you should prefer {{method}}()', {
forbidden: node.property.name,
method: method
});
}
}
}
};
};
}
};
module.exports.schema = [{
enum: ['$apply', '$digest']
}];

@@ -13,14 +13,17 @@ /**

module.exports = function(context) {
var restrict = ['document', 'setInterval', 'setTimeout'];
return {
module.exports = {
meta: {
schema: []
},
create: function(context) {
var restrict = ['document', 'setInterval', 'setTimeout'];
return {
MemberExpression: function(node) {
if (node.object.name === 'window' && restrict.indexOf(node.property.name) < 0) {
context.report(node, 'You should use the $window service instead of the default window object', {});
MemberExpression: function(node) {
if (node.object.name === 'window' && restrict.indexOf(node.property.name) < 0) {
context.report(node, 'You should use the $window service instead of the default window object', {});
}
}
}
};
};
}
};
module.exports.schema = [];

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc