2fe8a3f40637ffb08f38a94a1f0dee4e20d9f9c3
[platform/framework/web/crosswalk-tizen.git] /
1 /**
2  * @fileoverview This rule shoud require or disallow spaces before or after unary operations.
3  * @author Marcin Kumorek
4  * @copyright 2014 Marcin Kumorek. All rights reserved.
5  */
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = function(context) {
13     var options = context.options && Array.isArray(context.options) && context.options[0] || { words: true, nonwords: false };
14
15     //--------------------------------------------------------------------------
16     // Helpers
17     //--------------------------------------------------------------------------
18
19     /**
20     * Check if the parent unary operator is "!" in order to know if it's "!!" convert to Boolean or just "!" negation
21     * @param {ASTnode} node AST node
22     * @returns {boolean} Whether or not the parent is unary "!" operator
23     */
24     function isParentUnaryBangExpression(node) {
25         return node && node.parent && node.parent.type === "UnaryExpression" && node.parent.operator === "!";
26     }
27
28     /**
29     * Checks if the type is a unary word expression
30     * @param {string} type value of AST token
31     * @returns {boolean} Whether the word is in the list of known words
32     */
33     function isWordExpression(type) {
34         return ["delete", "new", "typeof", "void"].indexOf(type) !== -1;
35     }
36
37     /**
38     * Check if the node's child argument is an "ObjectExpression"
39     * @param {ASTnode} node AST node
40     * @returns {boolean} Whether or not the argument's type is "ObjectExpression"
41     */
42     function isArgumentObjectExpression(node) {
43         return node.argument && node.argument.type && node.argument.type === "ObjectExpression";
44     }
45
46     /**
47     * Check Unary Word Operators for spaces after the word operator
48     * @param {ASTnode} node AST node
49     * @param {object} firstToken first token from the AST node
50     * @param {object} secondToken second token from the AST node
51     * @returns {void}
52     */
53     function checkUnaryWordOperatorForSpaces(node, firstToken, secondToken) {
54         if (options.words) {
55             if (secondToken.range[0] === firstToken.range[1]) {
56                 context.report(node, "Unary word operator \"" + firstToken.value + "\" must be followed by whitespace.");
57             }
58         }
59
60         if (!options.words && isArgumentObjectExpression(node)) {
61             if (secondToken.range[0] > firstToken.range[1]) {
62                 context.report(node, "Unexpected space after unary word operator \"" + firstToken.value + "\".");
63             }
64         }
65     }
66
67     /**
68     * Checks UnaryExpression, UpdateExpression and NewExpression for spaces before and after the operator
69     * @param {ASTnode} node AST node
70     * @returns {void}
71     */
72     function checkForSpaces(node) {
73         var tokens = context.getFirstTokens(node, 2),
74             firstToken = tokens[0],
75             secondToken = tokens[1];
76
77         if (isWordExpression(firstToken.value)) {
78             checkUnaryWordOperatorForSpaces(node, firstToken, secondToken);
79             return void 0;
80         }
81
82         if (options.nonwords) {
83             if (node.prefix) {
84                 if (isParentUnaryBangExpression(node)) {
85                     return void 0;
86                 }
87                 if (firstToken.range[1] === secondToken.range[0]) {
88                     context.report(node, "Unary operator \"" + firstToken.value + "\" must be followed by whitespace.");
89                 }
90             } else {
91                 if (firstToken.range[1] === secondToken.range[0]) {
92                     context.report(node, "Space is required before unary expressions \"" + secondToken.value + "\".");
93                 }
94             }
95         } else {
96             if (node.prefix) {
97                 if (secondToken.range[0] > firstToken.range[1]) {
98                     context.report(node, "Unexpected space after unary operator \"" + firstToken.value + "\".");
99                 }
100             } else {
101                 if (secondToken.range[0] > firstToken.range[1]) {
102                     context.report(node, "Unexpected space before unary operator \"" + secondToken.value + "\".");
103                 }
104             }
105         }
106     }
107
108     //--------------------------------------------------------------------------
109     // Public
110     //--------------------------------------------------------------------------
111
112     return {
113         "UnaryExpression": checkForSpaces,
114         "UpdateExpression": checkForSpaces,
115         "NewExpression": checkForSpaces
116     };
117
118 };