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.
10 //------------------------------------------------------------------------------
12 //------------------------------------------------------------------------------
14 module.exports = function(context) {
15 var spaced = context.options[0] === "always";
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.
24 function isOptionSet(option) {
25 return context.options[1] != null ? context.options[1][option] === !spaced : false;
30 singleElementException: isOptionSet("singleValue"),
31 objectsInArraysException: isOptionSet("objectsInArrays"),
32 arraysInArraysException: isOptionSet("arraysInArrays"),
33 arraysInObjectsException: isOptionSet("arraysInObjects"),
34 objectsInObjectsException: isOptionSet("objectsInObjects"),
35 propertyNameException: isOptionSet("propertyName")
38 //--------------------------------------------------------------------------
40 //--------------------------------------------------------------------------
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.
48 function isSpaced(left, right) {
49 return left.range[1] < right.range[0];
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.
58 function isSameLine(left, right) {
59 return left.loc.start.line === right.loc.start.line;
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.
68 function reportNoBeginningSpace(node, token) {
69 context.report(node, token.loc.start,
70 "There should be no space after '" + token.value + "'");
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.
79 function reportNoEndingSpace(node, token) {
80 context.report(node, token.loc.start,
81 "There should be no space before '" + token.value + "'");
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.
90 function reportRequiredBeginningSpace(node, token) {
91 context.report(node, token.loc.start,
92 "A space is required after '" + token.value + "'");
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.
101 function reportRequiredEndingSpace(node, token) {
102 context.report(node, token.loc.start,
103 "A space is required before '" + token.value + "'");
107 //--------------------------------------------------------------------------
109 //--------------------------------------------------------------------------
113 MemberExpression: function(node) {
114 if (!node.computed) {
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);
124 var propertyNameMustBeSpaced = options.propertyNameException ?
125 !options.spaced : options.spaced;
127 if (isSameLine(before, first)) {
128 if (propertyNameMustBeSpaced) {
129 if (!isSpaced(before, first) && isSameLine(before, first)) {
130 reportRequiredBeginningSpace(node, before);
133 if (isSpaced(before, first)) {
134 reportNoBeginningSpace(node, before);
139 if (isSameLine(last, after)) {
140 if (propertyNameMustBeSpaced) {
141 if (!isSpaced(last, after) && isSameLine(last, after)) {
142 reportRequiredEndingSpace(node, after);
145 if (isSpaced(last, after)) {
146 reportNoEndingSpace(node, after);
152 ArrayExpression: function(node) {
153 if (node.elements.length === 0) {
157 var first = context.getFirstToken(node),
158 second = context.getFirstToken(node, 1),
159 penultimate = context.getLastToken(node, 1),
160 last = context.getLastToken(node);
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;
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;
174 if (isSameLine(first, second)) {
175 if (openingBracketMustBeSpaced && !isSpaced(first, second)) {
176 reportRequiredBeginningSpace(node, first);
178 if (!openingBracketMustBeSpaced && isSpaced(first, second)) {
179 reportNoBeginningSpace(node, first);
183 if (isSameLine(penultimate, last)) {
184 if (closingBracketMustBeSpaced && !isSpaced(penultimate, last)) {
185 reportRequiredEndingSpace(node, last);
187 if (!closingBracketMustBeSpaced && isSpaced(penultimate, last)) {
188 reportNoEndingSpace(node, last);
193 ObjectExpression: function(node) {
194 if (node.properties.length === 0) {
198 var first = context.getFirstToken(node),
199 second = context.getFirstToken(node, 1),
200 penultimate = context.getLastToken(node, 1),
201 last = context.getLastToken(node);
203 var closingCurlyBraceMustBeSpaced =
204 options.arraysInObjectsException && penultimate.value === "]" ||
205 options.objectsInObjectsException && penultimate.value === "}"
206 ? !options.spaced : options.spaced;
208 if (isSameLine(first, second)) {
209 if (options.spaced && !isSpaced(first, second)) {
210 reportRequiredBeginningSpace(node, first);
212 if (!options.spaced && isSpaced(first, second)) {
213 reportNoBeginningSpace(node, first);
217 if (isSameLine(penultimate, last)) {
218 if (closingCurlyBraceMustBeSpaced && !isSpaced(penultimate, last)) {
219 reportRequiredEndingSpace(node, last);
221 if (!closingCurlyBraceMustBeSpaced && isSpaced(penultimate, last)) {
222 reportNoEndingSpace(node, last);