diff --git a/docs/rules/no-angular-mock.md b/docs/rules/no-angular-mock.md index f808ebc5..54740409 100644 --- a/docs/rules/no-angular-mock.md +++ b/docs/rules/no-angular-mock.md @@ -9,7 +9,7 @@ So you can remove angular.mock from your code ## Examples -The following patterns are considered problems; +The following patterns are considered problems with default config; /*eslint angular/no-angular-mock: 2*/ @@ -24,7 +24,7 @@ The following patterns are considered problems; // invalid angular.mock.module('myModule'); // error: You should use the "module" method available in the window object. -The following patterns are **not** considered problems; +The following patterns are **not** considered problems with default config; /*eslint angular/no-angular-mock: 2*/ @@ -39,6 +39,26 @@ The following patterns are **not** considered problems; // valid module('myModule'); +The following patterns are considered problems when configured `"webpack-module-support"`: + + /*eslint angular/no-angular-mock: [2,"webpack-module-support"]*/ + + // invalid + module('myModule'); // error: You should use the "angular.mock.module" method directly. + +The following patterns are **not** considered problems when configured `"webpack-module-support"`: + + /*eslint angular/no-angular-mock: [2,"webpack-module-support"]*/ + + // valid + inject(); + + // valid + dump(); + + // valid + angular.mock.module('myModule'); + ## Version This rule was introduced in eslint-plugin-angular 0.2.0 diff --git a/examples/no-angular-mock.js b/examples/no-angular-mock.js index de844ab1..62575450 100644 --- a/examples/no-angular-mock.js +++ b/examples/no-angular-mock.js @@ -19,3 +19,15 @@ angular.mock.inject(function (someService) { // example - valid: false, errorMessage: "You should use the \"module\" method available in the window object." angular.mock.module('myModule'); + +// example - valid: true, options: ["webpack-module-support"] +inject(); + +// example - valid: true, options: ["webpack-module-support"] +dump(); + +// example - valid: true, options: ["webpack-module-support"] +angular.mock.module('myModule'); + +// example - valid: false, options: ["webpack-module-support"], errorMessage: "You should use the \"angular.mock.module\" method directly." +module('myModule'); diff --git a/rules/no-angular-mock.js b/rules/no-angular-mock.js index 2f268101..94796c50 100644 --- a/rules/no-angular-mock.js +++ b/rules/no-angular-mock.js @@ -30,24 +30,106 @@ */ 'use strict'; +const WEBPACK_OPTION = 'webpack-module-support'; +const WEBPACK_OPTION_REPLACEMENT = 'angular.mock.module'; + +function argumentIsModuleInvocation(arg) { + return arg.type === 'CallExpression' && arg.callee.name === 'module'; +} + +function getWebpackFixer(node) { + return function(fixer) { + return fixer.replaceText(node.callee, WEBPACK_OPTION_REPLACEMENT); + }; +} + +function getCallExpressionHandler(context) { + return function(node) { + const moduleCalls = node.arguments.filter(arg => argumentIsModuleInvocation(arg)); + + return moduleCalls.map(problem => { + return context.report({ + node: problem, + messageId: 'useMockModule', + fix: getWebpackFixer(problem) + }); + }); + }; +} + +function getExpressionStatmentHandler(context) { + return function(node) { + const isModuleCall = argumentIsModuleInvocation(node.expression); + + if (!isModuleCall) { + return; + } + + return context.report({ + node: node, + messageId: 'useMockModule', + fix: getWebpackFixer(node.expression) + }); + }; +} + module.exports = { meta: { docs: { url: 'https://github.com/Gillespie59/eslint-plugin-angular/blob/master/docs/rules/no-angular-mock.md' }, - schema: [] + schema: [{ + type: 'string' + }], + fixable: 'code', + messages: { + useMockModule: 'You should use the "angular.mock.module" method directly.' + } }, create: function(context) { + const webpackRuleEnabled = context.options && context.options[0] === WEBPACK_OPTION; + const sourceCode = context.getSourceCode(); + return { + CallExpression: webpackRuleEnabled ? getCallExpressionHandler(context) : function() {}, + + ExpressionStatement: webpackRuleEnabled ? getExpressionStatmentHandler(context) : function() {}, 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.', { + const isAngularMock = + node.object.type === 'Identifier' && + node.object.name === 'angular' && + node.property.type === 'Identifier' && + node.property.name === 'mock' && + node.parent.type === 'MemberExpression' && + node.parent.property.type === 'Identifier' && + + // If the webpack option is turned on, we only need to check + // for non-"module" mock properties + (webpackRuleEnabled ? node.parent.property.name !== 'module' : true); + + if (isAngularMock) { + context.report({ + node: node, + message: 'You should use the "{{method}}" method available in the window object.', + data: { method: node.parent.property.name - }); - } + }, + fix: (fixer) => { + if (webpackRuleEnabled && node.parent.property.name === 'module') { + return; + } + + let angularPeriod = sourceCode.getTokenAfter(node.object); + let mockPeriod = sourceCode.getTokenAfter(node.property); + return [ + fixer.remove(angularPeriod), + fixer.remove(mockPeriod), + fixer.remove(node.object), + fixer.remove(node.property) + ]; + } + }); } } }; diff --git a/test/no-angular-mock.js b/test/no-angular-mock.js index 32d96877..368d3d25 100644 --- a/test/no-angular-mock.js +++ b/test/no-angular-mock.js @@ -17,17 +17,61 @@ eslintTester.run('no-angular-mock', rule, { valid: [ 'dump();', 'inject();', - 'module();' + 'module();', + 'module', + 'module.exports', + 'module.exports = {}', + { + code: 'dump()', + options: ['webpack-module-support'] + } ].concat(commonFalsePositives), invalid: [{ code: 'angular.mock.dump();', - errors: [{message: 'You should use the "dump" method available in the window object.'}] + errors: [{message: 'You should use the "dump" method available in the window object.'}], + output: 'dump();' }, { code: 'angular.mock.inject();', - errors: [{message: 'You should use the "inject" method available in the window object.'}] + errors: [{message: 'You should use the "inject" method available in the window object.'}], + output: 'inject();' }, { code: 'angular.mock.module();', - errors: [{message: 'You should use the "module" method available in the window object.'}] + errors: [{message: 'You should use the "module" method available in the window object.'}], + output: 'module();' + }, { + code: 'beforeEach(angular.mock.module("exampleModule"))', + errors: [{message: 'You should use the "module" method available in the window object.'}], + output: 'beforeEach(module("exampleModule"))' + }, { + code: 'angular.mock.dump();', + options: ['webpack-module-support'], + errors: [{message: 'You should use the "dump" method available in the window object.'}], + output: 'dump();' + }, { + code: 'angular.mock.inject();', + options: ['webpack-module-support'], + errors: [{message: 'You should use the "inject" method available in the window object.'}], + output: 'inject();' + }, { + code: 'module();', + options: ['webpack-module-support'], + errors: [{message: 'You should use the "angular.mock.module" method directly.'}], + output: 'angular.mock.module();' + }, { + code: 'module("exampleModule");', + options: ['webpack-module-support'], + errors: [{message: 'You should use the "angular.mock.module" method directly.'}], + output: 'angular.mock.module("exampleModule");' + }, { + code: 'beforeEach(module("exampleModule"))', + options: ['webpack-module-support'], + errors: [{message: 'You should use the "angular.mock.module" method directly.'}], + output: 'beforeEach(angular.mock.module("exampleModule"))' + }, { + code: 'angular.mock.module("exampleModule"); module("anotherModule")', + options: ['webpack-module-support'], + errors: [{message: 'You should use the "angular.mock.module" method directly.'}], + output: 'angular.mock.module("exampleModule"); angular.mock.module("anotherModule")' } ] });