From 7dfeb5cf7d09fdc7ae6f8e99e83716d7284d8079 Mon Sep 17 00:00:00 2001 From: David Raynes Date: Thu, 1 Oct 2015 22:07:36 -0400 Subject: [PATCH 1/2] Added a function.$inject option for the di rule --- README.md | 2 +- rules/di.js | 44 ++++++++++++++++++++++++++++++++++----- test/di.js | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 47421fbe..85df3f1d 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Users may use the shareable [eslint-config-angular](https://github.com/dustinspe | controller-name | All your controllers should have a name starting with the parameter you can define in your config object. The second parameter can be a Regexp wrapped in quotes. ("controller-name": [2, "ng"]) [Y123](https://github.com/johnpapa/angular-styleguide#style-y123), [Y124](https://github.com/johnpapa/angular-styleguide#style-y124)| | deferred | When you want to create a new promise, you should not use the $q.deferred anymore. Prefer the new syntax : $q(function(resolve, reject){}) | | definedundefined | You should use the angular.isUndefined or angular.isDefined methods instead of using the keyword undefined. We also check the use of !angular.isUndefined and !angular.isDefined (should prefer the reverse function)| -| di | All your DI should use the same syntax : the Array or function syntaxes ("di": [2, "function or array"])| +| di | All your DI should use the same syntax : the Array, function, or function.$inject syntaxes ("di": [2, "array, function, or function.$inject"])| | di-order | Injected dependencies should be sorted alphabetically. If the second parameter is set to false, values which start and end with an underscore those underscores are stripped. This means for example that `_$httpBackend_` goes before `_$http_`. | | directive-name | All your directives should have a name starting with the parameter you can define in your config object. The second parameter can be a Regexp wrapped in quotes. You can not prefix your directives by "ng" (reserved keyword for AngularJS directives) ("directive-name": [2, "ng"]) [Y073](https://github.com/johnpapa/angular-styleguide#style-y073), [Y126](https://github.com/johnpapa/angular-styleguide#style-y126) | | directive-restrict | Not all directive restrictions may be desirable. Also it might be desirable to define default restrictions, or explicitly not. The default configuration limits the restrictions `AE` [Y074](https://github.com/johnpapa/angular-styleguide#style-y074) and disallows explicitly specifying a default. ("directive-restrict": [0, {"restrict": "AE", "explicit": "never"}]) | diff --git a/rules/di.js b/rules/di.js index dfa06c04..4980283a 100644 --- a/rules/di.js +++ b/rules/di.js @@ -11,18 +11,46 @@ module.exports = function(context) { }); } + var noninjectedFunctions = {}; + var injectedFunctions = []; + function checkDi(syntax, node, param) { if (syntax === 'function' && (!utils.isFunctionType(param) && !utils.isIdentifierType(param))) { report(node, syntax); - } - if (syntax === 'array') { - if (!utils.isArrayType(param)) { - report(node, syntax); - } else { + } else if (syntax === 'array') { + if (utils.isArrayType(param)) { var fn = param.elements[param.elements.length - 1]; if (utils.isFunctionType(fn) && fn.params.length !== param.elements.length - 1) { context.report(fn, 'The signature of the method is incorrect', {}); } + } else { + report(node, syntax); + } + } else if (syntax === 'function.$inject') { + if (utils.isIdentifierType(param)) { + noninjectedFunctions[param.name] = node; + } else { + report(node, syntax); + } + } + } + + function maybeNoteInjection(syntax, node) { + if (syntax === 'function.$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'))) { + injectedFunctions.push(node.left.object.name); + } + } + + function verifyInjections(syntax) { + if (syntax === 'function.$inject') { + injectedFunctions.forEach(function(f) { + delete noninjectedFunctions[f]; + }); + + for (var func in noninjectedFunctions) { + report(noninjectedFunctions[func], syntax); } } } @@ -41,6 +69,12 @@ module.exports = function(context) { */ checkDi(context.options[0], node, node.arguments[0]); } + }, + AssignmentExpression: function(node) { + maybeNoteInjection(context.options[0], node); + }, + 'Program:exit': function() { + verifyInjections(context.options[0]); } }; }; diff --git a/test/di.js b/test/di.js index 823858b0..138fb8c6 100644 --- a/test/di.js +++ b/test/di.js @@ -28,6 +28,21 @@ angularObjectList.forEach(function(object) { }, { code: 'angular.' + object + '(myFunction);function MyFunction() {}', options: ['function'] + }, { + code: 'angular.' + object + '(myFunction);myFunction.$inject=[];function myFunction() {}', + options: ['function.$inject'] + }, { + code: 'angular.' + object + '(myFunction);myFunction["$inject"]=[];function myFunction() {}', + options: ['function.$inject'] + }, { + code: 'myFunction.$inject=[];function myFunction() {} angular.' + object + '(myFunction);', + options: ['function.$inject'] + }, { + code: 'function myFunction() {} myFunction.$inject=[];angular.' + object + '(myFunction);', + options: ['function.$inject'] + }, { + code: 'var myFunction = function() {}; myFunction.$inject=[];angular.' + object + '(myFunction);', + options: ['function.$inject'] }); invalid.push({ @@ -46,6 +61,22 @@ angularObjectList.forEach(function(object) { code: 'angular.' + object + '([function(Service1) {}]);', options: ['array'], errors: [{message: 'The signature of the method is incorrect'}] + }, { + code: 'angular.' + object + '(myFunction); function myFunction() {}', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] + }, { + code: 'function myFunction() {} angular.' + object + '(myFunction);', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] + }, { + code: 'var myFunction = function() {};angular.' + object + '(myFunction);', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] + }, { + code: 'angular.' + object + '(function() {});', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] }); }); @@ -62,6 +93,18 @@ angularNamedObjectList.forEach(function(object) { }, { code: 'angular.' + object + '("name", myFunction);function MyFunction() {}', options: ['function'] + }, { + code: 'angular.' + object + '("name", myFunction);myFunction.$inject=[];function myFunction() {}', + options: ['function.$inject'] + }, { + code: 'myFunction.$inject=[];function myFunction() {} angular.' + object + '("name", myFunction);', + options: ['function.$inject'] + }, { + code: 'function myFunction() {} myFunction.$inject=[];angular.' + object + '("name", myFunction);', + options: ['function.$inject'] + }, { + code: 'var myFunction = function() {}; myFunction.$inject=[];angular.' + object + '("name", myFunction);', + options: ['function.$inject'] }); invalid.push({ @@ -80,6 +123,22 @@ angularNamedObjectList.forEach(function(object) { code: 'angular.' + object + '("name", [function(Service1) {}]);', options: ['array'], errors: [{message: 'The signature of the method is incorrect'}] + }, { + code: 'angular.' + object + '("name", myFunction); function myFunction() {}', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] + }, { + code: 'function myFunction() {} angular.' + object + '("name", myFunction);', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] + }, { + code: 'var myFunction = function () {};angular.' + object + '("name", myFunction);', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] + }, { + code: 'angular.' + object + '("name", function() {});', + options: ['function.$inject'], + errors: [{message: 'You should use the function.$inject syntax for DI'}] }); }); From 4b4ce8260eb529b93b6ef22beb62a55e17516456 Mon Sep 17 00:00:00 2001 From: David Raynes Date: Thu, 15 Oct 2015 09:39:44 -0400 Subject: [PATCH 2/2] function.$inject -> $inject --- README.md | 2 +- rules/di.js | 6 +++--- test/di.js | 50 +++++++++++++++++++++++++------------------------- 3 files changed, 29 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 85df3f1d..1d5a9339 100644 --- a/README.md +++ b/README.md @@ -172,7 +172,7 @@ Users may use the shareable [eslint-config-angular](https://github.com/dustinspe | controller-name | All your controllers should have a name starting with the parameter you can define in your config object. The second parameter can be a Regexp wrapped in quotes. ("controller-name": [2, "ng"]) [Y123](https://github.com/johnpapa/angular-styleguide#style-y123), [Y124](https://github.com/johnpapa/angular-styleguide#style-y124)| | deferred | When you want to create a new promise, you should not use the $q.deferred anymore. Prefer the new syntax : $q(function(resolve, reject){}) | | definedundefined | You should use the angular.isUndefined or angular.isDefined methods instead of using the keyword undefined. We also check the use of !angular.isUndefined and !angular.isDefined (should prefer the reverse function)| -| di | All your DI should use the same syntax : the Array, function, or function.$inject syntaxes ("di": [2, "array, function, or function.$inject"])| +| di | All your DI should use the same syntax : the Array, function, or $inject syntaxes ("di": [2, "array, function, or $inject"])| | di-order | Injected dependencies should be sorted alphabetically. If the second parameter is set to false, values which start and end with an underscore those underscores are stripped. This means for example that `_$httpBackend_` goes before `_$http_`. | | directive-name | All your directives should have a name starting with the parameter you can define in your config object. The second parameter can be a Regexp wrapped in quotes. You can not prefix your directives by "ng" (reserved keyword for AngularJS directives) ("directive-name": [2, "ng"]) [Y073](https://github.com/johnpapa/angular-styleguide#style-y073), [Y126](https://github.com/johnpapa/angular-styleguide#style-y126) | | directive-restrict | Not all directive restrictions may be desirable. Also it might be desirable to define default restrictions, or explicitly not. The default configuration limits the restrictions `AE` [Y074](https://github.com/johnpapa/angular-styleguide#style-y074) and disallows explicitly specifying a default. ("directive-restrict": [0, {"restrict": "AE", "explicit": "never"}]) | diff --git a/rules/di.js b/rules/di.js index 4980283a..042313cf 100644 --- a/rules/di.js +++ b/rules/di.js @@ -26,7 +26,7 @@ module.exports = function(context) { } else { report(node, syntax); } - } else if (syntax === 'function.$inject') { + } else if (syntax === '$inject') { if (utils.isIdentifierType(param)) { noninjectedFunctions[param.name] = node; } else { @@ -36,7 +36,7 @@ module.exports = function(context) { } function maybeNoteInjection(syntax, node) { - if (syntax === 'function.$inject' && node.left && node.left.property && + 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'))) { injectedFunctions.push(node.left.object.name); @@ -44,7 +44,7 @@ module.exports = function(context) { } function verifyInjections(syntax) { - if (syntax === 'function.$inject') { + if (syntax === '$inject') { injectedFunctions.forEach(function(f) { delete noninjectedFunctions[f]; }); diff --git a/test/di.js b/test/di.js index 138fb8c6..2683019b 100644 --- a/test/di.js +++ b/test/di.js @@ -30,19 +30,19 @@ angularObjectList.forEach(function(object) { options: ['function'] }, { code: 'angular.' + object + '(myFunction);myFunction.$inject=[];function myFunction() {}', - options: ['function.$inject'] + options: ['$inject'] }, { code: 'angular.' + object + '(myFunction);myFunction["$inject"]=[];function myFunction() {}', - options: ['function.$inject'] + options: ['$inject'] }, { code: 'myFunction.$inject=[];function myFunction() {} angular.' + object + '(myFunction);', - options: ['function.$inject'] + options: ['$inject'] }, { code: 'function myFunction() {} myFunction.$inject=[];angular.' + object + '(myFunction);', - options: ['function.$inject'] + options: ['$inject'] }, { code: 'var myFunction = function() {}; myFunction.$inject=[];angular.' + object + '(myFunction);', - options: ['function.$inject'] + options: ['$inject'] }); invalid.push({ @@ -63,20 +63,20 @@ angularObjectList.forEach(function(object) { errors: [{message: 'The signature of the method is incorrect'}] }, { code: 'angular.' + object + '(myFunction); function myFunction() {}', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }, { code: 'function myFunction() {} angular.' + object + '(myFunction);', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }, { code: 'var myFunction = function() {};angular.' + object + '(myFunction);', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }, { code: 'angular.' + object + '(function() {});', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }); }); @@ -95,16 +95,16 @@ angularNamedObjectList.forEach(function(object) { options: ['function'] }, { code: 'angular.' + object + '("name", myFunction);myFunction.$inject=[];function myFunction() {}', - options: ['function.$inject'] + options: ['$inject'] }, { code: 'myFunction.$inject=[];function myFunction() {} angular.' + object + '("name", myFunction);', - options: ['function.$inject'] + options: ['$inject'] }, { code: 'function myFunction() {} myFunction.$inject=[];angular.' + object + '("name", myFunction);', - options: ['function.$inject'] + options: ['$inject'] }, { code: 'var myFunction = function() {}; myFunction.$inject=[];angular.' + object + '("name", myFunction);', - options: ['function.$inject'] + options: ['$inject'] }); invalid.push({ @@ -125,20 +125,20 @@ angularNamedObjectList.forEach(function(object) { errors: [{message: 'The signature of the method is incorrect'}] }, { code: 'angular.' + object + '("name", myFunction); function myFunction() {}', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }, { code: 'function myFunction() {} angular.' + object + '("name", myFunction);', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }, { code: 'var myFunction = function () {};angular.' + object + '("name", myFunction);', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }, { code: 'angular.' + object + '("name", function() {});', - options: ['function.$inject'], - errors: [{message: 'You should use the function.$inject syntax for DI'}] + options: ['$inject'], + errors: [{message: 'You should use the $inject syntax for DI'}] }); });