UNPKG

6.96 kBJavaScriptView Raw
1'use strict'
2
3/**
4 * @fileoverview Disallows or enforces spaces inside of array brackets.
5 * @author Jamund Ferguson
6 * @copyright 2015 Jamund Ferguson. All rights reserved.
7 * @copyright 2014 Brandyn Bennett. All rights reserved.
8 * @copyright 2014 Michael Ficarra. No rights reserved.
9 * @copyright 2014 Vignesh Anand. All rights reserved.
10 */
11// ------------------------------------------------------------------------------
12// Rule Definition
13// ------------------------------------------------------------------------------
14
15module.exports = {
16 meta: {
17 docs: {
18 url: 'https://github.com/standard/eslint-plugin-standard#rules-explanations'
19 }
20 },
21
22 create: function (context) {
23 var spaced = context.options[0] === 'always'
24 var either = context.options[0] === 'either'
25
26 /**
27 * Determines whether an option is set, relative to the spacing option.
28 * If spaced is "always", then check whether option is set to false.
29 * If spaced is "never", then check whether option is set to true.
30 * @param {Object} option - The option to exclude.
31 * @returns {boolean} Whether or not the property is excluded.
32 */
33 function isOptionSet (option) {
34 return context.options[1] != null ? context.options[1][option] === !spaced : false
35 }
36
37 var options = {
38 either: either,
39 spaced: spaced,
40 singleElementException: isOptionSet('singleValue'),
41 objectsInArraysException: isOptionSet('objectsInArrays'),
42 arraysInArraysException: isOptionSet('arraysInArrays')
43 }
44
45 // --------------------------------------------------------------------------
46 // Helpers
47 // --------------------------------------------------------------------------
48
49 /**
50 * Determines whether two adjacent tokens are have whitespace between them.
51 * @param {Object} left - The left token object.
52 * @param {Object} right - The right token object.
53 * @returns {boolean} Whether or not there is space between the tokens.
54 */
55 function isSpaced (left, right) {
56 return left.range[1] < right.range[0]
57 }
58
59 /**
60 * Determines whether two adjacent tokens are on the same line.
61 * @param {Object} left - The left token object.
62 * @param {Object} right - The right token object.
63 * @returns {boolean} Whether or not the tokens are on the same line.
64 */
65 function isSameLine (left, right) {
66 return left.loc.start.line === right.loc.start.line
67 }
68
69 /**
70 * Reports that there shouldn't be a space after the first token
71 * @param {ASTNode} node - The node to report in the event of an error.
72 * @param {Token} token - The token to use for the report.
73 * @returns {void}
74 */
75 function reportNoBeginningSpace (node, token) {
76 context.report(node, token.loc.start,
77 "There should be no space after '" + token.value + "'")
78 }
79
80 /**
81 * Reports that there shouldn't be a space before the last token
82 * @param {ASTNode} node - The node to report in the event of an error.
83 * @param {Token} token - The token to use for the report.
84 * @returns {void}
85 */
86 function reportNoEndingSpace (node, token) {
87 context.report(node, token.loc.start,
88 "There should be no space before '" + token.value + "'")
89 }
90
91 /**
92 * Reports that there should be a space after the first token
93 * @param {ASTNode} node - The node to report in the event of an error.
94 * @param {Token} token - The token to use for the report.
95 * @returns {void}
96 */
97 function reportRequiredBeginningSpace (node, token) {
98 context.report(node, token.loc.start,
99 "A space is required after '" + token.value + "'")
100 }
101
102 /**
103 * Reports that there should be a space before the last token
104 * @param {ASTNode} node - The node to report in the event of an error.
105 * @param {Token} token - The token to use for the report.
106 * @returns {void}
107 */
108 function reportRequiredEndingSpace (node, token) {
109 context.report(node, token.loc.start,
110 "A space is required before '" + token.value + "'")
111 }
112
113 /**
114 * Checks if a start and end brace in a node are spaced evenly
115 * and not too long (>1 space)
116 * @param node
117 * @param start
118 * @param end
119 * @returns {boolean}
120 */
121 function isEvenlySpacedAndNotTooLong (node, start, end) {
122 var expectedSpace = start[1].range[0] - start[0].range[1]
123 var endSpace = end[1].range[0] - end[0].range[1]
124 return endSpace === expectedSpace && endSpace <= 1
125 }
126
127 /**
128 * Validates the spacing around array brackets
129 * @param {ASTNode} node - The node we're checking for spacing
130 * @returns {void}
131 */
132 function validateArraySpacing (node) {
133 if (node.elements.length === 0) {
134 return
135 }
136
137 var first = context.getFirstToken(node)
138 var second = context.getFirstToken(node, 1)
139 var penultimate = context.getLastToken(node, 1)
140 var last = context.getLastToken(node)
141
142 var openingBracketMustBeSpaced =
143 (options.objectsInArraysException && second.value === '{') ||
144 (options.arraysInArraysException && second.value === '[') ||
145 (options.singleElementException && node.elements.length === 1)
146 ? !options.spaced : options.spaced
147
148 var closingBracketMustBeSpaced =
149 (options.objectsInArraysException && penultimate.value === '}') ||
150 (options.arraysInArraysException && penultimate.value === ']') ||
151 (options.singleElementException && node.elements.length === 1)
152 ? !options.spaced : options.spaced
153
154 // we only care about evenly spaced things
155 if (options.either) {
156 // newlines at any point means return
157 if (!isSameLine(first, last)) {
158 return
159 }
160
161 // confirm that the object expression/literal is spaced evenly
162 if (!isEvenlySpacedAndNotTooLong(node, [first, second], [penultimate, last])) {
163 context.report(node, 'Expected consistent spacing')
164 }
165
166 return
167 }
168
169 if (isSameLine(first, second)) {
170 if (openingBracketMustBeSpaced && !isSpaced(first, second)) {
171 reportRequiredBeginningSpace(node, first)
172 }
173 if (!openingBracketMustBeSpaced && isSpaced(first, second)) {
174 reportNoBeginningSpace(node, first)
175 }
176 }
177
178 if (isSameLine(penultimate, last)) {
179 if (closingBracketMustBeSpaced && !isSpaced(penultimate, last)) {
180 reportRequiredEndingSpace(node, last)
181 }
182 if (!closingBracketMustBeSpaced && isSpaced(penultimate, last)) {
183 reportNoEndingSpace(node, last)
184 }
185 }
186 }
187
188 // --------------------------------------------------------------------------
189 // Public
190 // --------------------------------------------------------------------------
191
192 return {
193 ArrayPattern: validateArraySpacing,
194 ArrayExpression: validateArraySpacing
195 }
196 }
197}