UNPKG

4.61 kBJavaScriptView Raw
1/**
2 * Disallows space before and/or after `?` or `:` in conditional expressions.
3 *
4 * Types: `Object` or `Boolean`
5 *
6 * Values: `"afterTest"`, `"beforeConsequent"`, `"afterConsequent"`, `"beforeAlternate"` as child properties,
7 * or `true` to set all properties to true. Child properties must be set to `true`. These token names correspond to:
8 *
9 * ```
10 * var a = b ? c : d;
11 * ^ ^ ^ ^
12 * | | | |
13 * | | | └- beforeAlternate
14 * | | └--- afterConsequent
15 * | └-------- beforeConsequent
16 * └---------- afterTest
17 * ```
18 *
19 * #### Example
20 *
21 * ```js
22 * "disallowSpacesInConditionalExpression": {
23 * "afterTest": true,
24 * "beforeConsequent": true,
25 * "afterConsequent": true,
26 * "beforeAlternate": true
27 * }
28 * ```
29 *
30 * ##### Valid
31 *
32 * ```js
33 * var a = b?c:d;
34 * var a= b?c:d;
35 * ```
36 *
37 * ##### Invalid
38 *
39 * ```js
40 * var a = b ?c:d;
41 * var a = b? c:d;
42 * var a = b?c :d;
43 * var a = b?c: d;
44 * ```
45 */
46
47var assert = require('assert');
48
49module.exports = function() {};
50
51module.exports.prototype = {
52 configure: function(options) {
53 var validProperties = [
54 'afterTest',
55 'beforeConsequent',
56 'afterConsequent',
57 'beforeAlternate'
58 ];
59 var optionName = this.getOptionName();
60
61 if (options === true) {
62 options = {
63 'afterTest': true,
64 'beforeConsequent': true,
65 'afterConsequent': true,
66 'beforeAlternate': true
67 };
68 }
69
70 assert(
71 typeof options === 'object',
72 optionName + ' option requires a true value or an object'
73 );
74
75 var isProperlyConfigured = validProperties.some(function(key) {
76 var isPresent = key in options;
77
78 if (isPresent) {
79 assert(
80 options[key] === true,
81 optionName + '.' + key + ' property requires true value or should be removed'
82 );
83 }
84
85 return isPresent;
86 });
87
88 assert(
89 isProperlyConfigured,
90 optionName + ' must have at least 1 of the following properties: ' + validProperties.join(', ')
91 );
92
93 validProperties.forEach(function(property) {
94 this['_' + property] = Boolean(options[property]);
95 }.bind(this));
96 },
97
98 getOptionName: function() {
99 return 'disallowSpacesInConditionalExpression';
100 },
101
102 check: function(file, errors) {
103 file.iterateNodesByType(['ConditionalExpression'], function(node) {
104
105 var test = node.test;
106 var consequent = node.consequent;
107 var consequentToken = file.getFirstNodeToken(consequent);
108 var alternate = node.alternate;
109 var alternateToken = file.getFirstNodeToken(alternate);
110 var questionMarkToken = file.findPrevOperatorToken(consequentToken, '?');
111 var colonToken = file.findPrevOperatorToken(alternateToken, ':');
112 var token;
113
114 if (this._afterTest && file.isOnTheSameLine(test, questionMarkToken)) {
115 token = file.getPrevToken(questionMarkToken);
116
117 errors.assert.noWhitespaceBetween({
118 token: token,
119 nextToken: questionMarkToken,
120 message: 'Illegal space after test'
121 });
122 }
123
124 if (this._beforeConsequent && file.isOnTheSameLine(questionMarkToken, consequent)) {
125 token = file.getNextToken(questionMarkToken);
126
127 errors.assert.noWhitespaceBetween({
128 token: questionMarkToken,
129 nextToken: token,
130 message: 'Illegal space before consequent'
131 });
132 }
133
134 if (this._afterConsequent && file.isOnTheSameLine(consequent, colonToken)) {
135 token = file.getPrevToken(colonToken);
136
137 errors.assert.noWhitespaceBetween({
138 token: token,
139 nextToken: colonToken,
140 message: 'Illegal space after consequent'
141 });
142 }
143
144 if (this._beforeAlternate && file.isOnTheSameLine(colonToken, alternate)) {
145 token = file.getNextToken(colonToken);
146 errors.assert.noWhitespaceBetween({
147 token: colonToken,
148 nextToken: token,
149 message: 'Illegal space before alternate'
150 });
151 }
152 }.bind(this));
153 }
154
155};