all files / eslint-plugin-angular/rules/ prefer-component.js

100% Statements 30/30
100% Branches 28/28
100% Functions 6/6
100% Lines 30/30
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78                      30×   16×   16×           16×     30×   21×   19× 31×                       16×   12×       14×     14×       14× 12×            
/*
 * Since AngularJS 1.5, we can use a new API when creating directives.
 * This new API should be use when creating directive without DOM manipulation.
 *
 * @version 0.16.0
 * @category bestPractice
 * @sinceAngularVersion 1.5
 */
'use strict';
 
var angularRule = require('./utils/angular-rule');
var allowedProperties = ['compile', 'link', 'multiElement', 'priority', 'templateNamespace', 'terminal'];
 
module.exports = angularRule(function(context) {
    var potentialReplaceNodes = {};
 
    function addPotentialLinkNode(variableName, node) {
        var nodeList = potentialReplaceNodes[variableName] || [];
 
        nodeList.push({
            name: variableName,
            node: node,
            block: context.getScope().block.body
        });
 
        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.');
                }
            });
        },
        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;
            }
 
            addPotentialLinkNode(node.left.object.name, node);
        },
        Property: function(node) {
            if (node.key.name === 'restrict') {
                if (node.value.raw.indexOf('C') < 0 && node.value.raw.indexOf('A') < 0) {
                    return;
                }
            } else if (allowedProperties.indexOf(node.key.name) < 0) {
                return;
            }
 
            // 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);
            }
 
            // report directly if object is part of a return statement and inside a directive body
            if (objectExpressionParent.type === 'ReturnStatement') {
                addPotentialLinkNode('', node);
            }
        }
    };
});
 
module.exports.schema = [];