32136a352393c4b87e4e3af9af109143fb805807
[platform/framework/web/crosswalk-tizen.git] /
1 /**
2  * @fileoverview Comma spacing - validates spacing before and after comma
3  * @author Vignesh Anand aka vegetableman.
4  * @copyright 2014 Vignesh Anand. All rights reserved.
5  */
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = function(context) {
13
14     var options = {
15         before: context.options[0] ? !!context.options[0].before : false,
16         after: context.options[0] ? !!context.options[0].after : true
17     };
18
19     //--------------------------------------------------------------------------
20     // Helpers
21     //--------------------------------------------------------------------------
22
23     // the index of the last comment that was checked
24     var lastCommentIndex = 0;
25
26     /**
27      * Determines whether two adjacent tokens have whitespace between them.
28      * @param {Object} left - The left token object.
29      * @param {Object} right - The right token object.
30      * @returns {boolean} Whether or not there is space between the tokens.
31      */
32     function isSpaced(left, right) {
33         var punctuationLength = context.getTokensBetween(left, right).length; // the length of any parenthesis
34         return (left.range[1] + punctuationLength) < right.range[0];
35     }
36
37     /**
38      * Checks whether two tokens are on the same line.
39      * @param {ASTNode} left The leftmost token.
40      * @param {ASTNode} right The rightmost token.
41      * @returns {boolean} True if the tokens are on the same line, false if not.
42      * @private
43      */
44     function isSameLine(left, right) {
45         return left.loc.end.line === right.loc.start.line;
46     }
47
48     /**
49      * Determines if a given token is a comma operator.
50      * @param {ASTNode} token The token to check.
51      * @returns {boolean} True if the token is a comma, false if not.
52      * @private
53      */
54     function isComma(token) {
55         return !!token && (token.type === "Punctuator") && (token.value === ",");
56     }
57
58     /**
59      * Reports a spacing error with an appropriate message.
60      * @param {ASTNode} node The binary expression node to report.
61      * @param {string} dir Is the error "before" or "after" the comma?
62      * @returns {void}
63      * @private
64      */
65     function report(node, dir) {
66         context.report(node, options[dir] ?
67             "A space is required " + dir + " ','." :
68             "There should be no space " + dir + " ','.");
69     }
70
71     /**
72      * Validates the spacing around a comma token.
73      * @param {Object} tokens - The tokens to be validated.
74      * @param {Token} tokens.comma The token representing the comma.
75      * @param {Token} [tokens.left] The last token before the comma.
76      * @param {Token} [tokens.right] The first token after the comma.
77      * @param {Token|ASTNode} reportItem The item to use when reporting an error.
78      * @returns {void}
79      * @private
80      */
81     function validateCommaItemSpacing(tokens, reportItem) {
82         if (tokens.left && isSameLine(tokens.left, tokens.comma) &&
83                 (options.before !== isSpaced(tokens.left, tokens.comma))
84         ) {
85             report(reportItem, "before");
86         }
87         if (tokens.right && isSameLine(tokens.comma, tokens.right) &&
88                 (options.after !== isSpaced(tokens.comma, tokens.right))
89         ) {
90             report(reportItem, "after");
91         }
92     }
93
94     /**
95      * Determines if a given source index is in a comment or not by checking
96      * the index against the comment range. Since the check goes straight
97      * through the file, once an index is passed a certain comment, we can
98      * go to the next comment to check that.
99      * @param {int} index The source index to check.
100      * @param {ASTNode[]} comments An array of comment nodes.
101      * @returns {boolean} True if the index is within a comment, false if not.
102      * @private
103      */
104     function isIndexInComment(index, comments) {
105
106         var comment;
107
108         while (lastCommentIndex < comments.length) {
109
110             comment = comments[lastCommentIndex];
111
112             if (comment.range[0] <= index && index < comment.range[1]) {
113                 return true;
114             } else if (index > comment.range[1]) {
115                 lastCommentIndex++;
116             } else {
117                 break;
118             }
119
120         }
121
122         return false;
123     }
124
125     //--------------------------------------------------------------------------
126     // Public
127     //--------------------------------------------------------------------------
128
129     return {
130         "Program": function() {
131
132             var source = context.getSource(),
133                 allComments = context.getAllComments(),
134                 pattern = /,/g,
135                 commaToken,
136                 previousToken,
137                 nextToken;
138
139             while (pattern.test(source)) {
140
141                 // do not flag anything inside of comments
142                 if (!isIndexInComment(pattern.lastIndex, allComments)) {
143                     commaToken = context.getTokenByRangeStart(pattern.lastIndex - 1);
144
145                     if (commaToken && commaToken.type !== "JSXText") {
146                         previousToken = context.getTokenBefore(commaToken);
147                         nextToken = context.getTokenAfter(commaToken);
148                         validateCommaItemSpacing({
149                             comma: commaToken,
150                             left: isComma(previousToken) ? null : previousToken,
151                             right: isComma(nextToken) ? null : nextToken
152                         }, commaToken);
153                     }
154                 }
155             }
156         }
157     };
158
159 };