eslint 0.22.0 → 0.24.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +20 -20
- package/README.md +111 -95
- package/bin/eslint.js +41 -41
- package/conf/environments.js +87 -81
- package/conf/eslint.json +186 -179
- package/lib/api.js +13 -12
- package/lib/cli-engine.js +441 -451
- package/lib/cli.js +196 -196
- package/lib/config-initializer.js +145 -145
- package/lib/config-validator.js +110 -110
- package/lib/config.js +428 -416
- package/lib/eslint.js +1072 -1073
- package/lib/file-finder.js +167 -167
- package/lib/formatters/checkstyle.js +68 -68
- package/lib/formatters/compact.js +53 -53
- package/lib/formatters/jslint-xml.js +40 -40
- package/lib/formatters/junit.js +63 -63
- package/lib/formatters/stylish.js +90 -90
- package/lib/formatters/tap.js +86 -86
- package/lib/ignored-paths.js +137 -137
- package/lib/load-rules.js +39 -39
- package/lib/options.js +132 -126
- package/lib/rule-context.js +107 -107
- package/lib/rules/accessor-pairs.js +65 -65
- package/lib/rules/array-bracket-spacing.js +180 -0
- package/lib/rules/block-scoped-var.js +339 -320
- package/lib/rules/brace-style.js +228 -228
- package/lib/rules/camelcase.js +111 -111
- package/lib/rules/comma-dangle.js +67 -64
- package/lib/rules/comma-spacing.js +191 -191
- package/lib/rules/comma-style.js +195 -195
- package/lib/rules/complexity.js +94 -94
- package/lib/rules/computed-property-spacing.js +144 -0
- package/lib/rules/consistent-return.js +75 -75
- package/lib/rules/consistent-this.js +119 -119
- package/lib/rules/constructor-super.js +108 -0
- package/lib/rules/curly.js +109 -109
- package/lib/rules/default-case.js +66 -66
- package/lib/rules/dot-location.js +63 -63
- package/lib/rules/dot-notation.js +119 -119
- package/lib/rules/eol-last.js +38 -38
- package/lib/rules/eqeqeq.js +96 -96
- package/lib/rules/func-names.js +45 -45
- package/lib/rules/func-style.js +49 -49
- package/lib/rules/generator-star-spacing.js +104 -87
- package/lib/rules/generator-star.js +76 -76
- package/lib/rules/global-strict.js +49 -49
- package/lib/rules/guard-for-in.js +32 -32
- package/lib/rules/handle-callback-err.js +81 -124
- package/lib/rules/indent.js +486 -486
- package/lib/rules/key-spacing.js +325 -325
- package/lib/rules/linebreak-style.js +44 -44
- package/lib/rules/lines-around-comment.js +228 -160
- package/lib/rules/max-depth.js +89 -89
- package/lib/rules/max-len.js +76 -76
- package/lib/rules/max-nested-callbacks.js +73 -73
- package/lib/rules/max-params.js +45 -45
- package/lib/rules/max-statements.js +61 -61
- package/lib/rules/new-cap.js +224 -224
- package/lib/rules/new-parens.js +29 -29
- package/lib/rules/newline-after-var.js +127 -127
- package/lib/rules/no-alert.js +153 -153
- package/lib/rules/no-array-constructor.js +31 -31
- package/lib/rules/no-bitwise.js +57 -57
- package/lib/rules/no-caller.js +29 -29
- package/lib/rules/no-catch-shadow.js +52 -52
- package/lib/rules/no-comma-dangle.js +45 -45
- package/lib/rules/no-cond-assign.js +123 -123
- package/lib/rules/no-console.js +27 -27
- package/lib/rules/no-constant-condition.js +73 -73
- package/lib/rules/no-continue.js +23 -23
- package/lib/rules/no-control-regex.js +58 -58
- package/lib/rules/no-debugger.js +22 -22
- package/lib/rules/no-delete-var.js +25 -25
- package/lib/rules/no-div-regex.js +27 -27
- package/lib/rules/no-dupe-args.js +89 -85
- package/lib/rules/no-dupe-keys.js +43 -43
- package/lib/rules/no-duplicate-case.js +67 -67
- package/lib/rules/no-else-return.js +125 -125
- package/lib/rules/no-empty-character-class.js +43 -43
- package/lib/rules/no-empty-class.js +45 -45
- package/lib/rules/no-empty-label.js +27 -27
- package/lib/rules/no-empty.js +49 -49
- package/lib/rules/no-eq-null.js +29 -29
- package/lib/rules/no-eval.js +26 -26
- package/lib/rules/no-ex-assign.js +42 -42
- package/lib/rules/no-extend-native.js +103 -103
- package/lib/rules/no-extra-bind.js +81 -81
- package/lib/rules/no-extra-boolean-cast.js +71 -71
- package/lib/rules/no-extra-parens.js +368 -355
- package/lib/rules/no-extra-semi.js +70 -23
- package/lib/rules/no-extra-strict.js +86 -86
- package/lib/rules/no-fallthrough.js +97 -97
- package/lib/rules/no-floating-decimal.js +30 -30
- package/lib/rules/no-func-assign.js +83 -83
- package/lib/rules/no-implied-eval.js +76 -76
- package/lib/rules/no-inline-comments.js +49 -49
- package/lib/rules/no-inner-declarations.js +78 -78
- package/lib/rules/no-invalid-regexp.js +53 -53
- package/lib/rules/no-irregular-whitespace.js +135 -135
- package/lib/rules/no-iterator.js +28 -28
- package/lib/rules/no-label-var.js +64 -64
- package/lib/rules/no-labels.js +44 -44
- package/lib/rules/no-lone-blocks.js +106 -27
- package/lib/rules/no-lonely-if.js +30 -30
- package/lib/rules/no-loop-func.js +58 -58
- package/lib/rules/no-mixed-requires.js +165 -165
- package/lib/rules/no-mixed-spaces-and-tabs.js +74 -74
- package/lib/rules/no-multi-spaces.js +119 -119
- package/lib/rules/no-multi-str.js +43 -43
- package/lib/rules/no-multiple-empty-lines.js +98 -98
- package/lib/rules/no-native-reassign.js +62 -62
- package/lib/rules/no-negated-in-lhs.js +25 -25
- package/lib/rules/no-nested-ternary.js +24 -24
- package/lib/rules/no-new-func.js +25 -25
- package/lib/rules/no-new-object.js +25 -25
- package/lib/rules/no-new-require.js +25 -25
- package/lib/rules/no-new-wrappers.js +26 -26
- package/lib/rules/no-new.js +27 -27
- package/lib/rules/no-obj-calls.js +28 -28
- package/lib/rules/no-octal-escape.js +39 -39
- package/lib/rules/no-octal.js +25 -25
- package/lib/rules/no-param-reassign.js +87 -87
- package/lib/rules/no-path-concat.js +39 -39
- package/lib/rules/no-plusplus.js +24 -24
- package/lib/rules/no-process-env.js +30 -30
- package/lib/rules/no-process-exit.js +33 -33
- package/lib/rules/no-proto.js +28 -28
- package/lib/rules/no-redeclare.js +68 -68
- package/lib/rules/no-regex-spaces.js +35 -35
- package/lib/rules/no-reserved-keys.js +56 -56
- package/lib/rules/no-restricted-modules.js +85 -85
- package/lib/rules/no-return-assign.js +53 -24
- package/lib/rules/no-script-url.js +34 -34
- package/lib/rules/no-self-compare.js +29 -29
- package/lib/rules/no-sequences.js +94 -94
- package/lib/rules/no-shadow-restricted-names.js +51 -51
- package/lib/rules/no-shadow.js +181 -136
- package/lib/rules/no-space-before-semi.js +98 -98
- package/lib/rules/no-spaced-func.js +37 -37
- package/lib/rules/no-sparse-arrays.js +33 -33
- package/lib/rules/no-sync.js +30 -30
- package/lib/rules/no-ternary.js +24 -24
- package/lib/rules/no-this-before-super.js +144 -0
- package/lib/rules/no-throw-literal.js +33 -33
- package/lib/rules/no-trailing-spaces.js +74 -63
- package/lib/rules/no-undef-init.js +28 -28
- package/lib/rules/no-undef.js +92 -92
- package/lib/rules/no-undefined.js +27 -27
- package/lib/rules/no-underscore-dangle.js +73 -73
- package/lib/rules/no-unexpected-multiline.js +58 -0
- package/lib/rules/no-unneeded-ternary.js +48 -48
- package/lib/rules/no-unreachable.js +98 -98
- package/lib/rules/no-unused-expressions.js +76 -76
- package/lib/rules/no-unused-vars.js +252 -250
- package/lib/rules/no-use-before-define.js +105 -105
- package/lib/rules/no-var.js +26 -26
- package/lib/rules/no-void.js +28 -28
- package/lib/rules/no-warning-comments.js +102 -102
- package/lib/rules/no-with.js +22 -22
- package/lib/rules/no-wrap-func.js +65 -65
- package/lib/rules/object-curly-spacing.js +231 -206
- package/lib/rules/object-shorthand.js +74 -73
- package/lib/rules/one-var.js +311 -304
- package/lib/rules/operator-assignment.js +118 -118
- package/lib/rules/operator-linebreak.js +114 -114
- package/lib/rules/padded-blocks.js +98 -98
- package/lib/rules/prefer-const.js +91 -0
- package/lib/rules/quote-props.js +72 -72
- package/lib/rules/quotes.js +92 -92
- package/lib/rules/radix.js +41 -41
- package/lib/rules/semi-spacing.js +167 -167
- package/lib/rules/semi.js +136 -136
- package/lib/rules/sort-vars.js +49 -49
- package/lib/rules/space-after-function-name.js +49 -49
- package/lib/rules/space-after-keywords.js +82 -82
- package/lib/rules/space-before-blocks.js +91 -91
- package/lib/rules/space-before-function-paren.js +139 -139
- package/lib/rules/space-before-function-parentheses.js +139 -139
- package/lib/rules/space-in-brackets.js +305 -305
- package/lib/rules/space-in-parens.js +281 -281
- package/lib/rules/space-infix-ops.js +106 -106
- package/lib/rules/space-return-throw-case.js +38 -38
- package/lib/rules/space-unary-ops.js +124 -133
- package/lib/rules/spaced-comment.js +143 -0
- package/lib/rules/spaced-line-comment.js +89 -89
- package/lib/rules/strict.js +242 -242
- package/lib/rules/use-isnan.js +26 -26
- package/lib/rules/valid-jsdoc.js +215 -215
- package/lib/rules/valid-typeof.js +42 -42
- package/lib/rules/vars-on-top.js +115 -115
- package/lib/rules/wrap-iife.js +48 -48
- package/lib/rules/wrap-regex.js +38 -38
- package/lib/rules/yoda.js +242 -225
- package/lib/rules.js +88 -88
- package/lib/timing.js +109 -109
- package/lib/token-store.js +201 -201
- package/lib/util/traverse.js +105 -105
- package/lib/util.js +125 -85
- package/package.json +6 -6
- package/CHANGELOG.md +0 -1638
@@ -1,281 +1,281 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Disallows or enforces spaces inside of parentheses.
|
3
|
-
* @author Jonathan Rajavuori
|
4
|
-
* @copyright 2014 David Clark. All rights reserved.
|
5
|
-
* @copyright 2014 Jonathan Rajavuori. All rights reserved.
|
6
|
-
*/
|
7
|
-
"use strict";
|
8
|
-
|
9
|
-
//------------------------------------------------------------------------------
|
10
|
-
// Rule Definition
|
11
|
-
//------------------------------------------------------------------------------
|
12
|
-
|
13
|
-
module.exports = function(context) {
|
14
|
-
|
15
|
-
var MISSING_SPACE_MESSAGE = "There must be a space inside this paren.",
|
16
|
-
REJECTED_SPACE_MESSAGE = "There should be no spaces inside this paren.",
|
17
|
-
exceptionsArray = (context.options.length === 2) ? context.options[1].exceptions : [],
|
18
|
-
options = {},
|
19
|
-
rejectedSpaceRegExp,
|
20
|
-
missingSpaceRegExp,
|
21
|
-
spaceChecks;
|
22
|
-
|
23
|
-
if (exceptionsArray && exceptionsArray.length) {
|
24
|
-
options.braceException = exceptionsArray.indexOf("{}") !== -1 || false;
|
25
|
-
options.bracketException = exceptionsArray.indexOf("[]") !== -1 || false;
|
26
|
-
options.parenException = exceptionsArray.indexOf("()") !== -1 || false;
|
27
|
-
options.empty = exceptionsArray.indexOf("empty") !== -1 || false;
|
28
|
-
}
|
29
|
-
|
30
|
-
/**
|
31
|
-
* Used with the `never` option to produce, given the exception options,
|
32
|
-
* two regular expressions to check for missing and rejected spaces.
|
33
|
-
* @param {Object} opts The exception options
|
34
|
-
* @returns {Object} `missingSpace` and `rejectedSpace` regular expressions
|
35
|
-
* @private
|
36
|
-
*/
|
37
|
-
function getNeverChecks(opts) {
|
38
|
-
var missingSpaceOpeners = [],
|
39
|
-
missingSpaceClosers = [],
|
40
|
-
rejectedSpaceOpeners = ["\\s"],
|
41
|
-
rejectedSpaceClosers = ["\\s"],
|
42
|
-
missingSpaceCheck,
|
43
|
-
rejectedSpaceCheck;
|
44
|
-
|
45
|
-
// Populate openers and closers
|
46
|
-
if (opts.braceException) {
|
47
|
-
missingSpaceOpeners.push("\\{");
|
48
|
-
missingSpaceClosers.push("\\}");
|
49
|
-
rejectedSpaceOpeners.push("\\{");
|
50
|
-
rejectedSpaceClosers.push("\\}");
|
51
|
-
}
|
52
|
-
if (opts.bracketException) {
|
53
|
-
missingSpaceOpeners.push("\\[");
|
54
|
-
missingSpaceClosers.push("\\]");
|
55
|
-
rejectedSpaceOpeners.push("\\[");
|
56
|
-
rejectedSpaceClosers.push("\\]");
|
57
|
-
}
|
58
|
-
if (opts.parenException) {
|
59
|
-
missingSpaceOpeners.push("\\(");
|
60
|
-
missingSpaceClosers.push("\\)");
|
61
|
-
rejectedSpaceOpeners.push("\\(");
|
62
|
-
rejectedSpaceClosers.push("\\)");
|
63
|
-
}
|
64
|
-
if (opts.empty) {
|
65
|
-
missingSpaceOpeners.push("\\)");
|
66
|
-
missingSpaceClosers.push("\\(");
|
67
|
-
rejectedSpaceOpeners.push("\\)");
|
68
|
-
rejectedSpaceClosers.push("\\(");
|
69
|
-
}
|
70
|
-
|
71
|
-
if (missingSpaceOpeners.length) {
|
72
|
-
missingSpaceCheck = "\\((" + missingSpaceOpeners.join("|") + ")";
|
73
|
-
if (missingSpaceClosers.length) {
|
74
|
-
missingSpaceCheck += "|";
|
75
|
-
}
|
76
|
-
}
|
77
|
-
if (missingSpaceClosers.length) {
|
78
|
-
missingSpaceCheck += "(" + missingSpaceClosers.join("|") + ")\\)";
|
79
|
-
}
|
80
|
-
|
81
|
-
// compose the rejected regexp
|
82
|
-
rejectedSpaceCheck = "\\( +[^" + rejectedSpaceOpeners.join("") + "]";
|
83
|
-
rejectedSpaceCheck += "|[^" + rejectedSpaceClosers.join("") + "] +\\)";
|
84
|
-
|
85
|
-
return {
|
86
|
-
// e.g. \((\{)|(\})\) --- where {} is an exception
|
87
|
-
missingSpace: missingSpaceCheck || ".^",
|
88
|
-
// e.g. \( +[^ \n\r\{]|[^ \n\r\}] +\) --- where {} is an exception
|
89
|
-
rejectedSpace: rejectedSpaceCheck
|
90
|
-
};
|
91
|
-
}
|
92
|
-
|
93
|
-
/**
|
94
|
-
* Used with the `always` option to produce, given the exception options,
|
95
|
-
* two regular expressions to check for missing and rejected spaces.
|
96
|
-
* @param {Object} opts The exception options
|
97
|
-
* @returns {Object} `missingSpace` and `rejectedSpace` regular expressions
|
98
|
-
* @private
|
99
|
-
*/
|
100
|
-
function getAlwaysChecks(opts) {
|
101
|
-
var missingSpaceOpeners = ["\\s", "\\)"],
|
102
|
-
missingSpaceClosers = ["\\s", "\\("],
|
103
|
-
rejectedSpaceOpeners = [],
|
104
|
-
rejectedSpaceClosers = [],
|
105
|
-
missingSpaceCheck,
|
106
|
-
rejectedSpaceCheck;
|
107
|
-
|
108
|
-
// Populate openers and closers
|
109
|
-
if (opts.braceException) {
|
110
|
-
missingSpaceOpeners.push("\\{");
|
111
|
-
missingSpaceClosers.push("\\}");
|
112
|
-
rejectedSpaceOpeners.push(" \\{");
|
113
|
-
rejectedSpaceClosers.push("\\} ");
|
114
|
-
}
|
115
|
-
if (opts.bracketException) {
|
116
|
-
missingSpaceOpeners.push("\\[");
|
117
|
-
missingSpaceClosers.push("\\]");
|
118
|
-
rejectedSpaceOpeners.push(" \\[");
|
119
|
-
rejectedSpaceClosers.push("\\] ");
|
120
|
-
}
|
121
|
-
if (opts.parenException) {
|
122
|
-
missingSpaceOpeners.push("\\(");
|
123
|
-
missingSpaceClosers.push("\\)");
|
124
|
-
rejectedSpaceOpeners.push(" \\(");
|
125
|
-
rejectedSpaceClosers.push("\\) ");
|
126
|
-
}
|
127
|
-
if (opts.empty) {
|
128
|
-
rejectedSpaceOpeners.push(" \\)");
|
129
|
-
rejectedSpaceClosers.push("\\( ");
|
130
|
-
}
|
131
|
-
|
132
|
-
// compose the allowed regexp
|
133
|
-
missingSpaceCheck = "\\([^" + missingSpaceOpeners.join("") + "]";
|
134
|
-
missingSpaceCheck += "|[^" + missingSpaceClosers.join("") + "]\\)";
|
135
|
-
|
136
|
-
// compose the rejected regexp
|
137
|
-
if (rejectedSpaceOpeners.length) {
|
138
|
-
rejectedSpaceCheck = "\\((" + rejectedSpaceOpeners.join("|") + ")";
|
139
|
-
if (rejectedSpaceClosers.length) {
|
140
|
-
rejectedSpaceCheck += "|";
|
141
|
-
}
|
142
|
-
}
|
143
|
-
if (rejectedSpaceClosers.length) {
|
144
|
-
rejectedSpaceCheck += "(" + rejectedSpaceClosers.join("|") + ")\\)";
|
145
|
-
}
|
146
|
-
|
147
|
-
return {
|
148
|
-
// e.g. \([^ \)\r\n\{]|[^ \(\r\n\}]\) --- where {} is an exception
|
149
|
-
missingSpace: missingSpaceCheck,
|
150
|
-
// e.g. \(( \{})|(\} )\) --- where {} is an excpetion
|
151
|
-
rejectedSpace: rejectedSpaceCheck || ".^"
|
152
|
-
};
|
153
|
-
}
|
154
|
-
|
155
|
-
spaceChecks = (context.options[0] === "always") ? getAlwaysChecks(options) : getNeverChecks(options);
|
156
|
-
missingSpaceRegExp = new RegExp(spaceChecks.missingSpace, "mg");
|
157
|
-
rejectedSpaceRegExp = new RegExp(spaceChecks.rejectedSpace, "mg");
|
158
|
-
|
159
|
-
|
160
|
-
//--------------------------------------------------------------------------
|
161
|
-
// Helpers
|
162
|
-
//--------------------------------------------------------------------------
|
163
|
-
|
164
|
-
var skipRanges = [];
|
165
|
-
|
166
|
-
/**
|
167
|
-
* Adds the range of a node to the set to be skipped when checking parens
|
168
|
-
* @param {ASTNode} node The node to skip
|
169
|
-
* @returns {void}
|
170
|
-
* @private
|
171
|
-
*/
|
172
|
-
function addSkipRange(node) {
|
173
|
-
skipRanges.push(node.range);
|
174
|
-
}
|
175
|
-
|
176
|
-
/**
|
177
|
-
* Sorts the skipRanges array. Must be called before shouldSkip
|
178
|
-
* @returns {void}
|
179
|
-
* @private
|
180
|
-
*/
|
181
|
-
function sortSkipRanges() {
|
182
|
-
skipRanges.sort(function (a, b) {
|
183
|
-
return a[0] - b[0];
|
184
|
-
});
|
185
|
-
}
|
186
|
-
|
187
|
-
/**
|
188
|
-
* Checks if a certain position in the source should be skipped
|
189
|
-
* @param {Number} pos The 0-based index in the source
|
190
|
-
* @returns {boolean} whether the position should be skipped
|
191
|
-
* @private
|
192
|
-
*/
|
193
|
-
function shouldSkip(pos) {
|
194
|
-
var i, len, range;
|
195
|
-
for (i = 0, len = skipRanges.length; i < len; i += 1) {
|
196
|
-
range = skipRanges[i];
|
197
|
-
if (pos < range[0]) {
|
198
|
-
break;
|
199
|
-
} else if (pos < range[1]) {
|
200
|
-
return true;
|
201
|
-
}
|
202
|
-
}
|
203
|
-
return false;
|
204
|
-
}
|
205
|
-
|
206
|
-
|
207
|
-
//--------------------------------------------------------------------------
|
208
|
-
// Public
|
209
|
-
//--------------------------------------------------------------------------
|
210
|
-
|
211
|
-
return {
|
212
|
-
|
213
|
-
"Program:exit": function checkParenSpaces(node) {
|
214
|
-
|
215
|
-
var nextMatch,
|
216
|
-
nextLine,
|
217
|
-
column,
|
218
|
-
line = 1,
|
219
|
-
source = context.getSource(),
|
220
|
-
pos = 0;
|
221
|
-
|
222
|
-
function checkMatch(match, message) {
|
223
|
-
if (source.charAt(match.index) !== "(") {
|
224
|
-
// Matched a closing paren pattern
|
225
|
-
match.index += 1;
|
226
|
-
}
|
227
|
-
|
228
|
-
if (!shouldSkip(match.index)) {
|
229
|
-
while ((nextLine = source.indexOf("\n", pos)) !== -1 && nextLine < match.index) {
|
230
|
-
pos = nextLine + 1;
|
231
|
-
line += 1;
|
232
|
-
}
|
233
|
-
column = match.index - pos;
|
234
|
-
|
235
|
-
context.report(node, { line: line, column: column }, message);
|
236
|
-
}
|
237
|
-
}
|
238
|
-
|
239
|
-
sortSkipRanges();
|
240
|
-
|
241
|
-
while ((nextMatch = rejectedSpaceRegExp.exec(source)) !== null) {
|
242
|
-
checkMatch(nextMatch, REJECTED_SPACE_MESSAGE);
|
243
|
-
}
|
244
|
-
|
245
|
-
while ((nextMatch = missingSpaceRegExp.exec(source)) !== null) {
|
246
|
-
checkMatch(nextMatch, MISSING_SPACE_MESSAGE);
|
247
|
-
}
|
248
|
-
|
249
|
-
},
|
250
|
-
|
251
|
-
|
252
|
-
// These nodes can contain parentheses that this rule doesn't care about
|
253
|
-
|
254
|
-
LineComment: addSkipRange,
|
255
|
-
|
256
|
-
BlockComment: addSkipRange,
|
257
|
-
|
258
|
-
Literal: addSkipRange
|
259
|
-
|
260
|
-
};
|
261
|
-
|
262
|
-
};
|
263
|
-
|
264
|
-
module.exports.schema = [
|
265
|
-
{
|
266
|
-
"enum": ["always", "never"]
|
267
|
-
},
|
268
|
-
{
|
269
|
-
"type": "object",
|
270
|
-
"properties": {
|
271
|
-
"exceptions": {
|
272
|
-
"type": "array",
|
273
|
-
"items": {
|
274
|
-
"enum": ["{}", "[]", "()", "empty"]
|
275
|
-
},
|
276
|
-
"uniqueItems": true
|
277
|
-
}
|
278
|
-
},
|
279
|
-
"additionalProperties": false
|
280
|
-
}
|
281
|
-
];
|
1
|
+
/**
|
2
|
+
* @fileoverview Disallows or enforces spaces inside of parentheses.
|
3
|
+
* @author Jonathan Rajavuori
|
4
|
+
* @copyright 2014 David Clark. All rights reserved.
|
5
|
+
* @copyright 2014 Jonathan Rajavuori. All rights reserved.
|
6
|
+
*/
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
// Rule Definition
|
11
|
+
//------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
module.exports = function(context) {
|
14
|
+
|
15
|
+
var MISSING_SPACE_MESSAGE = "There must be a space inside this paren.",
|
16
|
+
REJECTED_SPACE_MESSAGE = "There should be no spaces inside this paren.",
|
17
|
+
exceptionsArray = (context.options.length === 2) ? context.options[1].exceptions : [],
|
18
|
+
options = {},
|
19
|
+
rejectedSpaceRegExp,
|
20
|
+
missingSpaceRegExp,
|
21
|
+
spaceChecks;
|
22
|
+
|
23
|
+
if (exceptionsArray && exceptionsArray.length) {
|
24
|
+
options.braceException = exceptionsArray.indexOf("{}") !== -1 || false;
|
25
|
+
options.bracketException = exceptionsArray.indexOf("[]") !== -1 || false;
|
26
|
+
options.parenException = exceptionsArray.indexOf("()") !== -1 || false;
|
27
|
+
options.empty = exceptionsArray.indexOf("empty") !== -1 || false;
|
28
|
+
}
|
29
|
+
|
30
|
+
/**
|
31
|
+
* Used with the `never` option to produce, given the exception options,
|
32
|
+
* two regular expressions to check for missing and rejected spaces.
|
33
|
+
* @param {Object} opts The exception options
|
34
|
+
* @returns {Object} `missingSpace` and `rejectedSpace` regular expressions
|
35
|
+
* @private
|
36
|
+
*/
|
37
|
+
function getNeverChecks(opts) {
|
38
|
+
var missingSpaceOpeners = [],
|
39
|
+
missingSpaceClosers = [],
|
40
|
+
rejectedSpaceOpeners = ["\\s"],
|
41
|
+
rejectedSpaceClosers = ["\\s"],
|
42
|
+
missingSpaceCheck,
|
43
|
+
rejectedSpaceCheck;
|
44
|
+
|
45
|
+
// Populate openers and closers
|
46
|
+
if (opts.braceException) {
|
47
|
+
missingSpaceOpeners.push("\\{");
|
48
|
+
missingSpaceClosers.push("\\}");
|
49
|
+
rejectedSpaceOpeners.push("\\{");
|
50
|
+
rejectedSpaceClosers.push("\\}");
|
51
|
+
}
|
52
|
+
if (opts.bracketException) {
|
53
|
+
missingSpaceOpeners.push("\\[");
|
54
|
+
missingSpaceClosers.push("\\]");
|
55
|
+
rejectedSpaceOpeners.push("\\[");
|
56
|
+
rejectedSpaceClosers.push("\\]");
|
57
|
+
}
|
58
|
+
if (opts.parenException) {
|
59
|
+
missingSpaceOpeners.push("\\(");
|
60
|
+
missingSpaceClosers.push("\\)");
|
61
|
+
rejectedSpaceOpeners.push("\\(");
|
62
|
+
rejectedSpaceClosers.push("\\)");
|
63
|
+
}
|
64
|
+
if (opts.empty) {
|
65
|
+
missingSpaceOpeners.push("\\)");
|
66
|
+
missingSpaceClosers.push("\\(");
|
67
|
+
rejectedSpaceOpeners.push("\\)");
|
68
|
+
rejectedSpaceClosers.push("\\(");
|
69
|
+
}
|
70
|
+
|
71
|
+
if (missingSpaceOpeners.length) {
|
72
|
+
missingSpaceCheck = "\\((" + missingSpaceOpeners.join("|") + ")";
|
73
|
+
if (missingSpaceClosers.length) {
|
74
|
+
missingSpaceCheck += "|";
|
75
|
+
}
|
76
|
+
}
|
77
|
+
if (missingSpaceClosers.length) {
|
78
|
+
missingSpaceCheck += "(" + missingSpaceClosers.join("|") + ")\\)";
|
79
|
+
}
|
80
|
+
|
81
|
+
// compose the rejected regexp
|
82
|
+
rejectedSpaceCheck = "\\( +[^" + rejectedSpaceOpeners.join("") + "]";
|
83
|
+
rejectedSpaceCheck += "|[^" + rejectedSpaceClosers.join("") + "] +\\)";
|
84
|
+
|
85
|
+
return {
|
86
|
+
// e.g. \((\{)|(\})\) --- where {} is an exception
|
87
|
+
missingSpace: missingSpaceCheck || ".^",
|
88
|
+
// e.g. \( +[^ \n\r\{]|[^ \n\r\}] +\) --- where {} is an exception
|
89
|
+
rejectedSpace: rejectedSpaceCheck
|
90
|
+
};
|
91
|
+
}
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Used with the `always` option to produce, given the exception options,
|
95
|
+
* two regular expressions to check for missing and rejected spaces.
|
96
|
+
* @param {Object} opts The exception options
|
97
|
+
* @returns {Object} `missingSpace` and `rejectedSpace` regular expressions
|
98
|
+
* @private
|
99
|
+
*/
|
100
|
+
function getAlwaysChecks(opts) {
|
101
|
+
var missingSpaceOpeners = ["\\s", "\\)"],
|
102
|
+
missingSpaceClosers = ["\\s", "\\("],
|
103
|
+
rejectedSpaceOpeners = [],
|
104
|
+
rejectedSpaceClosers = [],
|
105
|
+
missingSpaceCheck,
|
106
|
+
rejectedSpaceCheck;
|
107
|
+
|
108
|
+
// Populate openers and closers
|
109
|
+
if (opts.braceException) {
|
110
|
+
missingSpaceOpeners.push("\\{");
|
111
|
+
missingSpaceClosers.push("\\}");
|
112
|
+
rejectedSpaceOpeners.push(" \\{");
|
113
|
+
rejectedSpaceClosers.push("\\} ");
|
114
|
+
}
|
115
|
+
if (opts.bracketException) {
|
116
|
+
missingSpaceOpeners.push("\\[");
|
117
|
+
missingSpaceClosers.push("\\]");
|
118
|
+
rejectedSpaceOpeners.push(" \\[");
|
119
|
+
rejectedSpaceClosers.push("\\] ");
|
120
|
+
}
|
121
|
+
if (opts.parenException) {
|
122
|
+
missingSpaceOpeners.push("\\(");
|
123
|
+
missingSpaceClosers.push("\\)");
|
124
|
+
rejectedSpaceOpeners.push(" \\(");
|
125
|
+
rejectedSpaceClosers.push("\\) ");
|
126
|
+
}
|
127
|
+
if (opts.empty) {
|
128
|
+
rejectedSpaceOpeners.push(" \\)");
|
129
|
+
rejectedSpaceClosers.push("\\( ");
|
130
|
+
}
|
131
|
+
|
132
|
+
// compose the allowed regexp
|
133
|
+
missingSpaceCheck = "\\([^" + missingSpaceOpeners.join("") + "]";
|
134
|
+
missingSpaceCheck += "|[^" + missingSpaceClosers.join("") + "]\\)";
|
135
|
+
|
136
|
+
// compose the rejected regexp
|
137
|
+
if (rejectedSpaceOpeners.length) {
|
138
|
+
rejectedSpaceCheck = "\\((" + rejectedSpaceOpeners.join("|") + ")";
|
139
|
+
if (rejectedSpaceClosers.length) {
|
140
|
+
rejectedSpaceCheck += "|";
|
141
|
+
}
|
142
|
+
}
|
143
|
+
if (rejectedSpaceClosers.length) {
|
144
|
+
rejectedSpaceCheck += "(" + rejectedSpaceClosers.join("|") + ")\\)";
|
145
|
+
}
|
146
|
+
|
147
|
+
return {
|
148
|
+
// e.g. \([^ \)\r\n\{]|[^ \(\r\n\}]\) --- where {} is an exception
|
149
|
+
missingSpace: missingSpaceCheck,
|
150
|
+
// e.g. \(( \{})|(\} )\) --- where {} is an excpetion
|
151
|
+
rejectedSpace: rejectedSpaceCheck || ".^"
|
152
|
+
};
|
153
|
+
}
|
154
|
+
|
155
|
+
spaceChecks = (context.options[0] === "always") ? getAlwaysChecks(options) : getNeverChecks(options);
|
156
|
+
missingSpaceRegExp = new RegExp(spaceChecks.missingSpace, "mg");
|
157
|
+
rejectedSpaceRegExp = new RegExp(spaceChecks.rejectedSpace, "mg");
|
158
|
+
|
159
|
+
|
160
|
+
//--------------------------------------------------------------------------
|
161
|
+
// Helpers
|
162
|
+
//--------------------------------------------------------------------------
|
163
|
+
|
164
|
+
var skipRanges = [];
|
165
|
+
|
166
|
+
/**
|
167
|
+
* Adds the range of a node to the set to be skipped when checking parens
|
168
|
+
* @param {ASTNode} node The node to skip
|
169
|
+
* @returns {void}
|
170
|
+
* @private
|
171
|
+
*/
|
172
|
+
function addSkipRange(node) {
|
173
|
+
skipRanges.push(node.range);
|
174
|
+
}
|
175
|
+
|
176
|
+
/**
|
177
|
+
* Sorts the skipRanges array. Must be called before shouldSkip
|
178
|
+
* @returns {void}
|
179
|
+
* @private
|
180
|
+
*/
|
181
|
+
function sortSkipRanges() {
|
182
|
+
skipRanges.sort(function (a, b) {
|
183
|
+
return a[0] - b[0];
|
184
|
+
});
|
185
|
+
}
|
186
|
+
|
187
|
+
/**
|
188
|
+
* Checks if a certain position in the source should be skipped
|
189
|
+
* @param {Number} pos The 0-based index in the source
|
190
|
+
* @returns {boolean} whether the position should be skipped
|
191
|
+
* @private
|
192
|
+
*/
|
193
|
+
function shouldSkip(pos) {
|
194
|
+
var i, len, range;
|
195
|
+
for (i = 0, len = skipRanges.length; i < len; i += 1) {
|
196
|
+
range = skipRanges[i];
|
197
|
+
if (pos < range[0]) {
|
198
|
+
break;
|
199
|
+
} else if (pos < range[1]) {
|
200
|
+
return true;
|
201
|
+
}
|
202
|
+
}
|
203
|
+
return false;
|
204
|
+
}
|
205
|
+
|
206
|
+
|
207
|
+
//--------------------------------------------------------------------------
|
208
|
+
// Public
|
209
|
+
//--------------------------------------------------------------------------
|
210
|
+
|
211
|
+
return {
|
212
|
+
|
213
|
+
"Program:exit": function checkParenSpaces(node) {
|
214
|
+
|
215
|
+
var nextMatch,
|
216
|
+
nextLine,
|
217
|
+
column,
|
218
|
+
line = 1,
|
219
|
+
source = context.getSource(),
|
220
|
+
pos = 0;
|
221
|
+
|
222
|
+
function checkMatch(match, message) {
|
223
|
+
if (source.charAt(match.index) !== "(") {
|
224
|
+
// Matched a closing paren pattern
|
225
|
+
match.index += 1;
|
226
|
+
}
|
227
|
+
|
228
|
+
if (!shouldSkip(match.index)) {
|
229
|
+
while ((nextLine = source.indexOf("\n", pos)) !== -1 && nextLine < match.index) {
|
230
|
+
pos = nextLine + 1;
|
231
|
+
line += 1;
|
232
|
+
}
|
233
|
+
column = match.index - pos;
|
234
|
+
|
235
|
+
context.report(node, { line: line, column: column }, message);
|
236
|
+
}
|
237
|
+
}
|
238
|
+
|
239
|
+
sortSkipRanges();
|
240
|
+
|
241
|
+
while ((nextMatch = rejectedSpaceRegExp.exec(source)) !== null) {
|
242
|
+
checkMatch(nextMatch, REJECTED_SPACE_MESSAGE);
|
243
|
+
}
|
244
|
+
|
245
|
+
while ((nextMatch = missingSpaceRegExp.exec(source)) !== null) {
|
246
|
+
checkMatch(nextMatch, MISSING_SPACE_MESSAGE);
|
247
|
+
}
|
248
|
+
|
249
|
+
},
|
250
|
+
|
251
|
+
|
252
|
+
// These nodes can contain parentheses that this rule doesn't care about
|
253
|
+
|
254
|
+
LineComment: addSkipRange,
|
255
|
+
|
256
|
+
BlockComment: addSkipRange,
|
257
|
+
|
258
|
+
Literal: addSkipRange
|
259
|
+
|
260
|
+
};
|
261
|
+
|
262
|
+
};
|
263
|
+
|
264
|
+
module.exports.schema = [
|
265
|
+
{
|
266
|
+
"enum": ["always", "never"]
|
267
|
+
},
|
268
|
+
{
|
269
|
+
"type": "object",
|
270
|
+
"properties": {
|
271
|
+
"exceptions": {
|
272
|
+
"type": "array",
|
273
|
+
"items": {
|
274
|
+
"enum": ["{}", "[]", "()", "empty"]
|
275
|
+
},
|
276
|
+
"uniqueItems": true
|
277
|
+
}
|
278
|
+
},
|
279
|
+
"additionalProperties": false
|
280
|
+
}
|
281
|
+
];
|