e39f3a591b3b9b0ddbd8e65daa0185d59c84dd6f
[platform/framework/web/crosswalk-tizen.git] /
1 /**
2  * @fileoverview Disallows or enforces spaces inside of brackets.
3  * @author Ian Christian Myers
4  * @copyright 2014 Brandyn Bennett. All rights reserved.
5  * @copyright 2014 Michael Ficarra. No rights reserved.
6  * @copyright 2014 Vignesh Anand. All rights reserved.
7  */
8 "use strict";
9
10 //------------------------------------------------------------------------------
11 // Rule Definition
12 //------------------------------------------------------------------------------
13
14 module.exports = function(context) {
15     var spaced = context.options[0] === "always";
16
17     /**
18      * Determines whether an option is set, relative to the spacing option.
19      * If spaced is "always", then check whether option is set to false.
20      * If spaced is "never", then check whether option is set to true.
21      * @param {Object} option - The option to exclude.
22      * @returns {boolean} Whether or not the property is excluded.
23      */
24     function isOptionSet(option) {
25         return context.options[1] != null ? context.options[1][option] === !spaced : false;
26     }
27
28     var options = {
29         spaced: spaced,
30         singleElementException: isOptionSet("singleValue"),
31         objectsInArraysException: isOptionSet("objectsInArrays"),
32         arraysInArraysException: isOptionSet("arraysInArrays"),
33         arraysInObjectsException: isOptionSet("arraysInObjects"),
34         objectsInObjectsException: isOptionSet("objectsInObjects"),
35         propertyNameException: isOptionSet("propertyName")
36     };
37
38     //--------------------------------------------------------------------------
39     // Helpers
40     //--------------------------------------------------------------------------
41
42     /**
43      * Determines whether two adjacent tokens are have whitespace between them.
44      * @param {Object} left - The left token object.
45      * @param {Object} right - The right token object.
46      * @returns {boolean} Whether or not there is space between the tokens.
47      */
48     function isSpaced(left, right) {
49         return left.range[1] < right.range[0];
50     }
51
52     /**
53      * Determines whether two adjacent tokens are on the same line.
54      * @param {Object} left - The left token object.
55      * @param {Object} right - The right token object.
56      * @returns {boolean} Whether or not the tokens are on the same line.
57      */
58     function isSameLine(left, right) {
59         return left.loc.start.line === right.loc.start.line;
60     }
61
62     /**
63     * Reports that there shouldn't be a space after the first token
64     * @param {ASTNode} node - The node to report in the event of an error.
65     * @param {Token} token - The token to use for the report.
66     * @returns {void}
67     */
68     function reportNoBeginningSpace(node, token) {
69         context.report(node, token.loc.start,
70             "There should be no space after '" + token.value + "'");
71     }
72
73     /**
74     * Reports that there shouldn't be a space before the last token
75     * @param {ASTNode} node - The node to report in the event of an error.
76     * @param {Token} token - The token to use for the report.
77     * @returns {void}
78     */
79     function reportNoEndingSpace(node, token) {
80         context.report(node, token.loc.start,
81             "There should be no space before '" + token.value + "'");
82     }
83
84     /**
85     * Reports that there should be a space after the first token
86     * @param {ASTNode} node - The node to report in the event of an error.
87     * @param {Token} token - The token to use for the report.
88     * @returns {void}
89     */
90     function reportRequiredBeginningSpace(node, token) {
91         context.report(node, token.loc.start,
92             "A space is required after '" + token.value + "'");
93     }
94
95     /**
96     * Reports that there should be a space before the last token
97     * @param {ASTNode} node - The node to report in the event of an error.
98     * @param {Token} token - The token to use for the report.
99     * @returns {void}
100     */
101     function reportRequiredEndingSpace(node, token) {
102         context.report(node, token.loc.start,
103                     "A space is required before '" + token.value + "'");
104     }
105
106
107     //--------------------------------------------------------------------------
108     // Public
109     //--------------------------------------------------------------------------
110
111     return {
112
113         MemberExpression: function(node) {
114             if (!node.computed) {
115                 return;
116             }
117
118             var property = node.property,
119                 before = context.getTokenBefore(property),
120                 first = context.getFirstToken(property),
121                 last = context.getLastToken(property),
122                 after = context.getTokenAfter(property);
123
124             var propertyNameMustBeSpaced = options.propertyNameException ?
125                                     !options.spaced : options.spaced;
126
127             if (isSameLine(before, first)) {
128                 if (propertyNameMustBeSpaced) {
129                     if (!isSpaced(before, first) && isSameLine(before, first)) {
130                         reportRequiredBeginningSpace(node, before);
131                     }
132                 } else {
133                     if (isSpaced(before, first)) {
134                         reportNoBeginningSpace(node, before);
135                     }
136                 }
137             }
138
139             if (isSameLine(last, after)) {
140                 if (propertyNameMustBeSpaced) {
141                     if (!isSpaced(last, after) && isSameLine(last, after)) {
142                         reportRequiredEndingSpace(node, after);
143                     }
144                 } else {
145                     if (isSpaced(last, after)) {
146                         reportNoEndingSpace(node, after);
147                     }
148                 }
149             }
150         },
151
152         ArrayExpression: function(node) {
153             if (node.elements.length === 0) {
154                 return;
155             }
156
157             var first = context.getFirstToken(node),
158                 second = context.getFirstToken(node, 1),
159                 penultimate = context.getLastToken(node, 1),
160                 last = context.getLastToken(node);
161
162             var openingBracketMustBeSpaced =
163                 options.objectsInArraysException && second.value === "{" ||
164                 options.arraysInArraysException && second.value === "[" ||
165                 options.singleElementException && node.elements.length === 1
166                 ? !options.spaced : options.spaced;
167
168             var closingBracketMustBeSpaced =
169                 options.objectsInArraysException && penultimate.value === "}" ||
170                 options.arraysInArraysException && penultimate.value === "]" ||
171                 options.singleElementException && node.elements.length === 1
172                 ? !options.spaced : options.spaced;
173
174             if (isSameLine(first, second)) {
175                 if (openingBracketMustBeSpaced && !isSpaced(first, second)) {
176                     reportRequiredBeginningSpace(node, first);
177                 }
178                 if (!openingBracketMustBeSpaced && isSpaced(first, second)) {
179                     reportNoBeginningSpace(node, first);
180                 }
181             }
182
183             if (isSameLine(penultimate, last)) {
184                 if (closingBracketMustBeSpaced && !isSpaced(penultimate, last)) {
185                     reportRequiredEndingSpace(node, last);
186                 }
187                 if (!closingBracketMustBeSpaced && isSpaced(penultimate, last)) {
188                     reportNoEndingSpace(node, last);
189                 }
190             }
191         },
192
193         ObjectExpression: function(node) {
194             if (node.properties.length === 0) {
195                 return;
196             }
197
198             var first = context.getFirstToken(node),
199                 second = context.getFirstToken(node, 1),
200                 penultimate = context.getLastToken(node, 1),
201                 last = context.getLastToken(node);
202
203             var closingCurlyBraceMustBeSpaced =
204                 options.arraysInObjectsException && penultimate.value === "]" ||
205                 options.objectsInObjectsException && penultimate.value === "}"
206                 ? !options.spaced : options.spaced;
207
208             if (isSameLine(first, second)) {
209                 if (options.spaced && !isSpaced(first, second)) {
210                     reportRequiredBeginningSpace(node, first);
211                 }
212                 if (!options.spaced && isSpaced(first, second)) {
213                     reportNoBeginningSpace(node, first);
214                 }
215             }
216
217             if (isSameLine(penultimate, last)) {
218                 if (closingCurlyBraceMustBeSpaced && !isSpaced(penultimate, last)) {
219                     reportRequiredEndingSpace(node, last);
220                 }
221                 if (!closingCurlyBraceMustBeSpaced && isSpaced(penultimate, last)) {
222                     reportNoEndingSpace(node, last);
223                 }
224             }
225         }
226
227     };
228
229 };