eslint 1.4.1 → 1.5.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/README.md +1 -1
- package/bin/eslint.js +32 -3
- package/lib/ast-utils.js +17 -11
- package/lib/cli-engine.js +72 -11
- package/lib/config.js +54 -55
- package/lib/eslint.js +7 -56
- package/lib/options.js +7 -0
- package/lib/rules/array-bracket-spacing.js +6 -5
- package/lib/rules/block-spacing.js +4 -3
- package/lib/rules/comma-dangle.js +25 -10
- package/lib/rules/comma-spacing.js +4 -29
- package/lib/rules/computed-property-spacing.js +5 -4
- package/lib/rules/eol-last.js +8 -1
- package/lib/rules/func-style.js +29 -9
- package/lib/rules/id-length.js +3 -3
- package/lib/rules/indent.js +100 -47
- package/lib/rules/jsx-quotes.js +1 -1
- package/lib/rules/key-spacing.js +7 -1
- package/lib/rules/no-dupe-args.js +30 -46
- package/lib/rules/no-extra-semi.js +7 -1
- package/lib/rules/no-inline-comments.js +3 -1
- package/lib/rules/no-spaced-func.js +18 -5
- package/lib/rules/no-trailing-spaces.js +34 -6
- package/lib/rules/no-unused-vars.js +4 -4
- package/lib/rules/no-warning-comments.js +7 -0
- package/lib/rules/object-curly-spacing.js +7 -9
- package/lib/rules/semi-spacing.js +29 -4
- package/lib/rules/space-after-keywords.js +27 -5
- package/lib/rules/space-before-blocks.js +64 -7
- package/lib/rules/space-before-function-paren.js +19 -13
- package/lib/rules/space-before-keywords.js +45 -17
- package/lib/rules/space-infix-ops.js +22 -1
- package/lib/rules/space-return-throw-case.js +7 -1
- package/lib/testers/event-generator-tester.js +63 -0
- package/lib/util/comment-event-generator.js +116 -0
- package/lib/util/node-event-generator.js +55 -0
- package/lib/util/source-code.js +14 -7
- package/package.json +2 -2
@@ -13,6 +13,8 @@ var astUtils = require("../ast-utils");
|
|
13
13
|
|
14
14
|
module.exports = function(context) {
|
15
15
|
|
16
|
+
var sourceCode = context.getSourceCode();
|
17
|
+
|
16
18
|
var options = {
|
17
19
|
before: context.options[0] ? !!context.options[0].before : false,
|
18
20
|
after: context.options[0] ? !!context.options[0].after : true
|
@@ -29,33 +31,6 @@ module.exports = function(context) {
|
|
29
31
|
// list of comma tokens to ignore for the check of leading whitespace
|
30
32
|
var commaTokensToIgnore = [];
|
31
33
|
|
32
|
-
/**
|
33
|
-
* Determines the length of comment between 2 tokens
|
34
|
-
* @param {Object} left - The left token object.
|
35
|
-
* @param {Object} right - The right token object.
|
36
|
-
* @returns {number} Length of comment in between tokens
|
37
|
-
*/
|
38
|
-
function getCommentLengthBetweenTokens(left, right) {
|
39
|
-
return allComments.reduce(function(val, comment) {
|
40
|
-
if (left.range[1] <= comment.range[0] && comment.range[1] <= right.range[0]) {
|
41
|
-
val = val + comment.range[1] - comment.range[0];
|
42
|
-
}
|
43
|
-
return val;
|
44
|
-
}, 0);
|
45
|
-
}
|
46
|
-
|
47
|
-
/**
|
48
|
-
* Determines whether two adjacent tokens have whitespace between them.
|
49
|
-
* @param {Object} left - The left token object.
|
50
|
-
* @param {Object} right - The right token object.
|
51
|
-
* @returns {boolean} Whether or not there is space between the tokens.
|
52
|
-
*/
|
53
|
-
function isSpaced(left, right) {
|
54
|
-
var punctuationLength = context.getTokensBetween(left, right).length; // the length of any parenthesis
|
55
|
-
var commentLenth = getCommentLengthBetweenTokens(left, right);
|
56
|
-
return (left.range[1] + punctuationLength + commentLenth) < right.range[0];
|
57
|
-
}
|
58
|
-
|
59
34
|
/**
|
60
35
|
* Determines if a given token is a comma operator.
|
61
36
|
* @param {ASTNode} token The token to check.
|
@@ -91,12 +66,12 @@ module.exports = function(context) {
|
|
91
66
|
*/
|
92
67
|
function validateCommaItemSpacing(tokens, reportItem) {
|
93
68
|
if (tokens.left && astUtils.isTokenOnSameLine(tokens.left, tokens.comma) &&
|
94
|
-
(options.before !==
|
69
|
+
(options.before !== sourceCode.isSpaceBetweenTokens(tokens.left, tokens.comma))
|
95
70
|
) {
|
96
71
|
report(reportItem, "before");
|
97
72
|
}
|
98
73
|
if (tokens.right && astUtils.isTokenOnSameLine(tokens.comma, tokens.right) &&
|
99
|
-
(options.after !==
|
74
|
+
(options.after !== sourceCode.isSpaceBetweenTokens(tokens.comma, tokens.right))
|
100
75
|
) {
|
101
76
|
report(reportItem, "after");
|
102
77
|
}
|
@@ -12,6 +12,7 @@ var astUtils = require("../ast-utils");
|
|
12
12
|
//------------------------------------------------------------------------------
|
13
13
|
|
14
14
|
module.exports = function(context) {
|
15
|
+
var sourceCode = context.getSourceCode();
|
15
16
|
var propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
|
16
17
|
|
17
18
|
//--------------------------------------------------------------------------
|
@@ -83,11 +84,11 @@ module.exports = function(context) {
|
|
83
84
|
|
84
85
|
if (astUtils.isTokenOnSameLine(before, first)) {
|
85
86
|
if (propertyNameMustBeSpaced) {
|
86
|
-
if (!
|
87
|
+
if (!sourceCode.isSpaceBetweenTokens(before, first) && astUtils.isTokenOnSameLine(before, first)) {
|
87
88
|
reportRequiredBeginningSpace(node, before);
|
88
89
|
}
|
89
90
|
} else {
|
90
|
-
if (
|
91
|
+
if (sourceCode.isSpaceBetweenTokens(before, first)) {
|
91
92
|
reportNoBeginningSpace(node, before);
|
92
93
|
}
|
93
94
|
}
|
@@ -95,11 +96,11 @@ module.exports = function(context) {
|
|
95
96
|
|
96
97
|
if (astUtils.isTokenOnSameLine(last, after)) {
|
97
98
|
if (propertyNameMustBeSpaced) {
|
98
|
-
if (!
|
99
|
+
if (!sourceCode.isSpaceBetweenTokens(last, after) && astUtils.isTokenOnSameLine(last, after)) {
|
99
100
|
reportRequiredEndingSpace(node, after);
|
100
101
|
}
|
101
102
|
} else {
|
102
|
-
if (
|
103
|
+
if (sourceCode.isSpaceBetweenTokens(last, after)) {
|
103
104
|
reportNoEndingSpace(node, after);
|
104
105
|
}
|
105
106
|
}
|
package/lib/rules/eol-last.js
CHANGED
@@ -27,7 +27,14 @@ module.exports = function(context) {
|
|
27
27
|
if (src[src.length - 1] !== "\n") {
|
28
28
|
// file is not newline-terminated
|
29
29
|
location.line = src.split(/\n/g).length;
|
30
|
-
context.report(
|
30
|
+
context.report({
|
31
|
+
node: node,
|
32
|
+
loc: location,
|
33
|
+
message: "Newline required at end of file but not found.",
|
34
|
+
fix: function(fixer) {
|
35
|
+
return fixer.insertTextAfterRange([0, src.length], "\n");
|
36
|
+
}
|
37
|
+
});
|
31
38
|
}
|
32
39
|
}
|
33
40
|
|
package/lib/rules/func-style.js
CHANGED
@@ -12,32 +12,52 @@
|
|
12
12
|
module.exports = function(context) {
|
13
13
|
|
14
14
|
var style = context.options[0],
|
15
|
-
enforceDeclarations = (style === "declaration")
|
15
|
+
enforceDeclarations = (style === "declaration"),
|
16
|
+
stack = [];
|
16
17
|
|
17
18
|
return {
|
19
|
+
"Program": function() {
|
20
|
+
stack = [];
|
21
|
+
},
|
18
22
|
|
19
23
|
"FunctionDeclaration": function(node) {
|
24
|
+
stack.push(false);
|
25
|
+
|
20
26
|
if (!enforceDeclarations) {
|
21
27
|
context.report(node, "Expected a function expression.");
|
22
28
|
}
|
23
29
|
},
|
30
|
+
"FunctionDeclaration:exit": function() {
|
31
|
+
stack.pop();
|
32
|
+
},
|
24
33
|
|
25
|
-
"FunctionExpression": function() {
|
26
|
-
|
34
|
+
"FunctionExpression": function(node) {
|
35
|
+
stack.push(false);
|
27
36
|
|
28
|
-
if (enforceDeclarations && parent.type === "VariableDeclarator") {
|
29
|
-
context.report(parent, "Expected a function declaration.");
|
37
|
+
if (enforceDeclarations && node.parent.type === "VariableDeclarator") {
|
38
|
+
context.report(node.parent, "Expected a function declaration.");
|
30
39
|
}
|
31
40
|
},
|
41
|
+
"FunctionExpression:exit": function() {
|
42
|
+
stack.pop();
|
43
|
+
},
|
32
44
|
|
33
45
|
"ArrowFunctionExpression": function() {
|
34
|
-
|
46
|
+
stack.push(false);
|
47
|
+
},
|
48
|
+
"ArrowFunctionExpression:exit": function(node) {
|
49
|
+
var hasThisExpr = stack.pop();
|
35
50
|
|
36
|
-
if (enforceDeclarations && parent.type === "VariableDeclarator") {
|
37
|
-
context.report(parent, "Expected a function declaration.");
|
51
|
+
if (enforceDeclarations && !hasThisExpr && node.parent.type === "VariableDeclarator") {
|
52
|
+
context.report(node.parent, "Expected a function declaration.");
|
38
53
|
}
|
39
|
-
}
|
54
|
+
},
|
40
55
|
|
56
|
+
"ThisExpression": function() {
|
57
|
+
if (stack.length > 0) {
|
58
|
+
stack[stack.length - 1] = true;
|
59
|
+
}
|
60
|
+
}
|
41
61
|
};
|
42
62
|
|
43
63
|
};
|
package/lib/rules/id-length.js
CHANGED
@@ -19,10 +19,10 @@ module.exports = function(context) {
|
|
19
19
|
var properties = options.properties !== "never";
|
20
20
|
var exceptions = (options.exceptions ? options.exceptions : [])
|
21
21
|
.reduce(function(obj, item) {
|
22
|
-
|
22
|
+
obj[item] = true;
|
23
23
|
|
24
|
-
|
25
|
-
|
24
|
+
return obj;
|
25
|
+
}, {});
|
26
26
|
|
27
27
|
var SUPPORTED_EXPRESSIONS = {
|
28
28
|
"MemberExpression": function(parent) {
|
package/lib/rules/indent.js
CHANGED
@@ -83,20 +83,78 @@ module.exports = function(context) {
|
|
83
83
|
* @param {int} needed Expected indentation character count
|
84
84
|
* @param {int} gotten Indentation character count in the actual node/code
|
85
85
|
* @param {Object=} loc Error line and column location
|
86
|
+
* @param {boolean} isLastNodeCheck Is the error for last node check
|
86
87
|
* @returns {void}
|
87
88
|
*/
|
88
|
-
function report(node, needed, gotten, loc) {
|
89
|
+
function report(node, needed, gotten, loc, isLastNodeCheck) {
|
89
90
|
var msgContext = {
|
90
91
|
needed: needed,
|
91
92
|
type: indentType,
|
92
93
|
characters: needed === 1 ? "character" : "characters",
|
93
94
|
gotten: gotten
|
94
95
|
};
|
96
|
+
var indentChar = indentType === "space" ? " " : "\t";
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Responsible for fixing the indentation issue fix
|
100
|
+
* @returns {Function} function to be executed by the fixer
|
101
|
+
* @private
|
102
|
+
*/
|
103
|
+
function getFixerFunction() {
|
104
|
+
var rangeToFix = [];
|
105
|
+
|
106
|
+
if (needed > gotten) {
|
107
|
+
var spaces = "" + new Array(needed - gotten + 1).join(indentChar); // replace with repeat in future
|
108
|
+
|
109
|
+
if (isLastNodeCheck === true) {
|
110
|
+
rangeToFix = [
|
111
|
+
node.range[1] - 1,
|
112
|
+
node.range[1] - 1
|
113
|
+
];
|
114
|
+
} else {
|
115
|
+
rangeToFix = [
|
116
|
+
node.range[0],
|
117
|
+
node.range[0]
|
118
|
+
];
|
119
|
+
}
|
120
|
+
|
121
|
+
return function(fixer) {
|
122
|
+
return fixer.insertTextBeforeRange(rangeToFix, spaces);
|
123
|
+
};
|
124
|
+
} else {
|
125
|
+
if (isLastNodeCheck === true) {
|
126
|
+
rangeToFix = [
|
127
|
+
node.range[1] - (gotten - needed) - 1,
|
128
|
+
node.range[1] - 1
|
129
|
+
];
|
130
|
+
} else {
|
131
|
+
rangeToFix = [
|
132
|
+
node.range[0] - (gotten - needed),
|
133
|
+
node.range[0]
|
134
|
+
];
|
135
|
+
}
|
136
|
+
|
137
|
+
return function(fixer) {
|
138
|
+
return fixer.removeRange(rangeToFix);
|
139
|
+
};
|
140
|
+
}
|
141
|
+
}
|
95
142
|
|
96
143
|
if (loc) {
|
97
|
-
context.report(
|
144
|
+
context.report({
|
145
|
+
node: node,
|
146
|
+
loc: loc,
|
147
|
+
message: MESSAGE,
|
148
|
+
data: msgContext,
|
149
|
+
fix: getFixerFunction()
|
150
|
+
});
|
98
151
|
} else {
|
99
|
-
context.report(
|
152
|
+
context.report({
|
153
|
+
node: node,
|
154
|
+
message: MESSAGE,
|
155
|
+
data: msgContext,
|
156
|
+
fix: getFixerFunction()
|
157
|
+
});
|
100
158
|
}
|
101
159
|
}
|
102
160
|
|
@@ -172,7 +230,8 @@ module.exports = function(context) {
|
|
172
230
|
node,
|
173
231
|
lastLineIndent,
|
174
232
|
endIndent,
|
175
|
-
{ line: lastToken.loc.start.line, column: lastToken.loc.start.column }
|
233
|
+
{ line: lastToken.loc.start.line, column: lastToken.loc.start.column },
|
234
|
+
true
|
176
235
|
);
|
177
236
|
}
|
178
237
|
}
|
@@ -195,6 +254,35 @@ module.exports = function(context) {
|
|
195
254
|
}
|
196
255
|
}
|
197
256
|
|
257
|
+
/**
|
258
|
+
* Returns the VariableDeclarator based on the current node
|
259
|
+
* if not present then return null
|
260
|
+
* @param {ASTNode} node node to examine
|
261
|
+
* @returns {ASTNode|void} if found then node otherwise null
|
262
|
+
*/
|
263
|
+
function getVariableDeclaratorNode(node) {
|
264
|
+
var parent = node.parent;
|
265
|
+
|
266
|
+
while (parent.type !== "VariableDeclarator" && parent.type !== "Program") {
|
267
|
+
parent = parent.parent;
|
268
|
+
}
|
269
|
+
|
270
|
+
return parent.type === "VariableDeclarator" ? parent : null;
|
271
|
+
}
|
272
|
+
|
273
|
+
/**
|
274
|
+
* Check to see if the node is part of the multi-line variable declaration.
|
275
|
+
* Also if its on the same line as the varNode
|
276
|
+
* @param {ASTNode} node node to check
|
277
|
+
* @param {ASTNode} varNode variable declaration node to check against
|
278
|
+
* @returns {boolean} True if all the above condition satisfy
|
279
|
+
*/
|
280
|
+
function isNodeInVarOnTop(node, varNode) {
|
281
|
+
return varNode &&
|
282
|
+
varNode.parent.loc.start.line === node.loc.start.line &&
|
283
|
+
varNode.parent.declarations.length > 1;
|
284
|
+
}
|
285
|
+
|
198
286
|
/**
|
199
287
|
* Check indent for function block content
|
200
288
|
* @param {ASTNode} node node to examine
|
@@ -214,11 +302,6 @@ module.exports = function(context) {
|
|
214
302
|
//
|
215
303
|
// Looks for 'Models'
|
216
304
|
var calleeNode = node.parent; // FunctionExpression
|
217
|
-
while (calleeNode.parent &&
|
218
|
-
calleeNode.parent.type === "CallExpression") {
|
219
|
-
calleeNode = calleeNode.parent;
|
220
|
-
}
|
221
|
-
|
222
305
|
var indent;
|
223
306
|
|
224
307
|
if (calleeNode.parent &&
|
@@ -244,17 +327,16 @@ module.exports = function(context) {
|
|
244
327
|
indent += indentSize;
|
245
328
|
}
|
246
329
|
|
330
|
+
// function body indent should be indent + indent size
|
247
331
|
indent += indentSize;
|
248
|
-
// If function content is not empty
|
249
|
-
var bodyIndent;
|
250
|
-
if (node.body.length > 0) {
|
251
|
-
bodyIndent = getNodeIndent(node.body[0]);
|
252
|
-
// Calculate left shift position don't require strict indent
|
253
|
-
// allow function body align to (indentSize * X)
|
254
|
-
while (bodyIndent > indent) {
|
255
|
-
indent += indentSize;
|
256
|
-
}
|
257
332
|
|
333
|
+
// check if the node is inside a variable
|
334
|
+
var parentVarNode = getVariableDeclaratorNode(node);
|
335
|
+
if (parentVarNode && isNodeInVarOnTop(node, parentVarNode)) {
|
336
|
+
indent += indentSize * options.VariableDeclarator[parentVarNode.parent.kind];
|
337
|
+
}
|
338
|
+
|
339
|
+
if (node.body.length > 0) {
|
258
340
|
checkNodesIndent(node.body, indent);
|
259
341
|
}
|
260
342
|
|
@@ -275,35 +357,6 @@ module.exports = function(context) {
|
|
275
357
|
return startLine === endLine;
|
276
358
|
}
|
277
359
|
|
278
|
-
/**
|
279
|
-
* Returns the VariableDeclarator based on the current node
|
280
|
-
* if not present then return null
|
281
|
-
* @param {ASTNode} node node to examine
|
282
|
-
* @returns {ASTNode|void} if found then node otherwise null
|
283
|
-
*/
|
284
|
-
function getVariableDeclaratorNode(node) {
|
285
|
-
var parent = node.parent;
|
286
|
-
|
287
|
-
while (parent.type !== "VariableDeclarator" && parent.type !== "Program") {
|
288
|
-
parent = parent.parent;
|
289
|
-
}
|
290
|
-
|
291
|
-
return parent.type === "VariableDeclarator" ? parent : null;
|
292
|
-
}
|
293
|
-
|
294
|
-
/**
|
295
|
-
* Check to see if the node is part of the multi-line variable declaration.
|
296
|
-
* Also if its on the same line as the varNode
|
297
|
-
* @param {ASTNode} node node to check
|
298
|
-
* @param {ASTNode} varNode variable declaration node to check against
|
299
|
-
* @returns {boolean} True if all the above condition satisfy
|
300
|
-
*/
|
301
|
-
function isNodeInVarOnTop(node, varNode) {
|
302
|
-
return varNode &&
|
303
|
-
varNode.parent.loc.start.line === node.loc.start.line &&
|
304
|
-
varNode.parent.declarations.length > 1;
|
305
|
-
}
|
306
|
-
|
307
360
|
/**
|
308
361
|
* Check to see if the first element inside an array is an object and on the same line as the node
|
309
362
|
* If the node is not an array then it will return false.
|
package/lib/rules/jsx-quotes.js
CHANGED
@@ -49,7 +49,7 @@ module.exports = function(context) {
|
|
49
49
|
"JSXAttribute": function(node) {
|
50
50
|
var attributeValue = node.value;
|
51
51
|
|
52
|
-
if (astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) {
|
52
|
+
if (attributeValue && astUtils.isStringLiteral(attributeValue) && !usesExpectedQuotes(attributeValue)) {
|
53
53
|
context.report(attributeValue, "Unexpected usage of {{description}}.", setting);
|
54
54
|
}
|
55
55
|
}
|
package/lib/rules/key-spacing.js
CHANGED
@@ -94,6 +94,7 @@ module.exports = function(context) {
|
|
94
94
|
|
95
95
|
var options = context.options[0] || {},
|
96
96
|
align = options.align,
|
97
|
+
mode = options.mode || "strict",
|
97
98
|
beforeColon = +!!options.beforeColon, // Defaults to false
|
98
99
|
afterColon = +!(options.afterColon === false); // Defaults to true
|
99
100
|
|
@@ -162,7 +163,9 @@ module.exports = function(context) {
|
|
162
163
|
firstTokenAfterColon = context.getTokenAfter(key, 1),
|
163
164
|
location = side === "key" ? key.loc.start : firstTokenAfterColon.loc.start;
|
164
165
|
|
165
|
-
if (diff &&
|
166
|
+
if ((diff && mode === "strict" || diff < 0 && mode === "minimum") &&
|
167
|
+
!(expected && containsLineTerminator(whitespace))
|
168
|
+
) {
|
166
169
|
context.report(property[side], location, messages[side], {
|
167
170
|
error: diff > 0 ? "Extra" : "Missing",
|
168
171
|
computed: property.computed ? "computed " : "",
|
@@ -333,6 +336,9 @@ module.exports.schema = [
|
|
333
336
|
"align": {
|
334
337
|
"enum": ["colon", "value"]
|
335
338
|
},
|
339
|
+
"mode": {
|
340
|
+
"enum": ["strict", "minimum"]
|
341
|
+
},
|
336
342
|
"beforeColon": {
|
337
343
|
"type": "boolean"
|
338
344
|
},
|
@@ -2,6 +2,8 @@
|
|
2
2
|
* @fileoverview Rule to flag duplicate arguments
|
3
3
|
* @author Jamund Ferguson
|
4
4
|
* @copyright 2015 Jamund Ferguson. All rights reserved.
|
5
|
+
* @copyright 2015 Toru Nagashima. All rights reserved.
|
6
|
+
* See LICENSE file in root directory for full license.
|
5
7
|
*/
|
6
8
|
|
7
9
|
"use strict";
|
@@ -16,6 +18,15 @@ module.exports = function(context) {
|
|
16
18
|
// Helpers
|
17
19
|
//--------------------------------------------------------------------------
|
18
20
|
|
21
|
+
/**
|
22
|
+
* Checks whether or not a given definition is a parameter's.
|
23
|
+
* @param {escope.DefEntry} def - A definition to check.
|
24
|
+
* @returns {boolean} `true` if the definition is a parameter's.
|
25
|
+
*/
|
26
|
+
function isParameter(def) {
|
27
|
+
return def.type === "Parameter";
|
28
|
+
}
|
29
|
+
|
19
30
|
/**
|
20
31
|
* Determines if a given node has duplicate parameters.
|
21
32
|
* @param {ASTNode} node The node to check.
|
@@ -23,56 +34,29 @@ module.exports = function(context) {
|
|
23
34
|
* @private
|
24
35
|
*/
|
25
36
|
function checkParams(node) {
|
26
|
-
var
|
27
|
-
|
37
|
+
var variables = context.getDeclaredVariables(node);
|
38
|
+
var keyMap = Object.create(null);
|
28
39
|
|
40
|
+
for (var i = 0; i < variables.length; ++i) {
|
41
|
+
var variable = variables[i];
|
29
42
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
* @private
|
35
|
-
*/
|
36
|
-
function markParam(name) {
|
37
|
-
if (params.hasOwnProperty(name)) {
|
38
|
-
dups[name] = 1;
|
39
|
-
} else {
|
40
|
-
params[name] = 1;
|
43
|
+
// TODO(nagashima): Remove this duplication check after https://github.com/estools/escope/pull/79
|
44
|
+
var key = "$" + variable.name; // to avoid __proto__.
|
45
|
+
if (!isParameter(variable.defs[0]) || keyMap[key]) {
|
46
|
+
continue;
|
41
47
|
}
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
case "ObjectPattern":
|
53
|
-
param.properties.forEach(function(property) {
|
54
|
-
markParam(property.key.name);
|
55
|
-
});
|
56
|
-
break;
|
57
|
-
|
58
|
-
case "ArrayPattern":
|
59
|
-
param.elements.forEach(function(element) {
|
60
|
-
|
61
|
-
// Arrays can be sparse (unwanted arguments)
|
62
|
-
if (element !== null) {
|
63
|
-
markParam(element.name);
|
64
|
-
}
|
65
|
-
});
|
66
|
-
break;
|
67
|
-
|
68
|
-
// no default
|
48
|
+
keyMap[key] = true;
|
49
|
+
|
50
|
+
// Checks and reports duplications.
|
51
|
+
var defs = variable.defs.filter(isParameter);
|
52
|
+
if (defs.length >= 2) {
|
53
|
+
context.report({
|
54
|
+
node: node,
|
55
|
+
message: "Duplicate param '{{name}}'.",
|
56
|
+
data: {name: variable.name}
|
57
|
+
});
|
69
58
|
}
|
70
|
-
}
|
71
|
-
|
72
|
-
// log an error for each duplicate (not 2 for each)
|
73
|
-
Object.keys(dups).forEach(function(currentParam) {
|
74
|
-
context.report(node, "Duplicate param '{{key}}'.", { key: currentParam });
|
75
|
-
});
|
59
|
+
}
|
76
60
|
}
|
77
61
|
|
78
62
|
//--------------------------------------------------------------------------
|
@@ -17,7 +17,13 @@ module.exports = function(context) {
|
|
17
17
|
* @returns {void}
|
18
18
|
*/
|
19
19
|
function report(nodeOrToken) {
|
20
|
-
context.report(
|
20
|
+
context.report({
|
21
|
+
node: nodeOrToken,
|
22
|
+
message: "Unnecessary semicolon.",
|
23
|
+
fix: function(fixer) {
|
24
|
+
return fixer.remove(nodeOrToken);
|
25
|
+
}
|
26
|
+
});
|
21
27
|
}
|
22
28
|
|
23
29
|
/**
|
@@ -5,6 +5,8 @@
|
|
5
5
|
*/
|
6
6
|
"use strict";
|
7
7
|
|
8
|
+
var astUtils = require("../ast-utils");
|
9
|
+
|
8
10
|
//------------------------------------------------------------------------------
|
9
11
|
// Rule Definition
|
10
12
|
//------------------------------------------------------------------------------
|
@@ -29,7 +31,7 @@ module.exports = function(context) {
|
|
29
31
|
var postamble = endLine.slice(node.loc.end.column).trim();
|
30
32
|
|
31
33
|
// Check that this comment isn't an ESLint directive
|
32
|
-
var isDirective =
|
34
|
+
var isDirective = astUtils.isDirectiveComment(node);
|
33
35
|
|
34
36
|
// Should be empty if there was only whitespace around the comment
|
35
37
|
if (!isDirective && (preamble || postamble)) {
|
@@ -11,6 +11,8 @@
|
|
11
11
|
|
12
12
|
module.exports = function(context) {
|
13
13
|
|
14
|
+
var sourceCode = context.getSourceCode();
|
15
|
+
|
14
16
|
/**
|
15
17
|
* Check if open space is present in a function name
|
16
18
|
* @param {ASTNode} node node to evaluate
|
@@ -18,18 +20,29 @@ module.exports = function(context) {
|
|
18
20
|
* @private
|
19
21
|
*/
|
20
22
|
function detectOpenSpaces(node) {
|
21
|
-
var lastCalleeToken =
|
22
|
-
|
23
|
-
|
23
|
+
var lastCalleeToken = sourceCode.getLastToken(node.callee),
|
24
|
+
tokens = sourceCode.getTokens(node),
|
25
|
+
i = tokens.indexOf(lastCalleeToken),
|
26
|
+
l = tokens.length;
|
27
|
+
|
24
28
|
while (i < l && tokens[i].value !== "(") {
|
25
29
|
++i;
|
26
30
|
}
|
31
|
+
|
27
32
|
if (i >= l) {
|
28
33
|
return;
|
29
34
|
}
|
35
|
+
|
30
36
|
// look for a space between the callee and the open paren
|
31
|
-
if (tokens[i - 1]
|
32
|
-
context.report(
|
37
|
+
if (sourceCode.isSpaceBetweenTokens(tokens[i - 1], tokens[i])) {
|
38
|
+
context.report({
|
39
|
+
node: node,
|
40
|
+
loc: lastCalleeToken.loc.start,
|
41
|
+
message: "Unexpected space between function name and paren.",
|
42
|
+
fix: function(fixer) {
|
43
|
+
return fixer.removeRange([tokens[i - 1].range[1], tokens[i].range[0]]);
|
44
|
+
}
|
45
|
+
});
|
33
46
|
}
|
34
47
|
}
|
35
48
|
|
@@ -18,6 +18,27 @@ module.exports = function(context) {
|
|
18
18
|
var options = context.options[0] || {},
|
19
19
|
skipBlankLines = options.skipBlankLines || false;
|
20
20
|
|
21
|
+
/**
|
22
|
+
* Report the error message
|
23
|
+
* @param {ASTNode} node node to report
|
24
|
+
* @param {int[]} location range information
|
25
|
+
* @param {int[]} fixRange Range based on the whole program
|
26
|
+
* @returns {void}
|
27
|
+
*/
|
28
|
+
function report(node, location, fixRange) {
|
29
|
+
// Passing node is a bit dirty, because message data will contain
|
30
|
+
// big text in `source`. But... who cares :) ?
|
31
|
+
// One more kludge will not make worse the bloody wizardry of this plugin.
|
32
|
+
context.report({
|
33
|
+
node: node,
|
34
|
+
loc: location,
|
35
|
+
message: "Trailing spaces not allowed.",
|
36
|
+
fix: function(fixer) {
|
37
|
+
return fixer.removeRange(fixRange);
|
38
|
+
}
|
39
|
+
});
|
40
|
+
}
|
41
|
+
|
21
42
|
|
22
43
|
//--------------------------------------------------------------------------
|
23
44
|
// Public
|
@@ -33,10 +54,12 @@ module.exports = function(context) {
|
|
33
54
|
var src = context.getSource(),
|
34
55
|
re = new RegExp(NONBLANK),
|
35
56
|
skipMatch = new RegExp(SKIP_BLANK),
|
36
|
-
matches, lines = src.split(/\r?\n/),
|
57
|
+
matches, lines = src.split(/\r?\n/),
|
58
|
+
location,
|
59
|
+
totalLength = 0,
|
60
|
+
fixRange = [];
|
37
61
|
|
38
62
|
for (var i = 0, ii = lines.length; i < ii; i++) {
|
39
|
-
|
40
63
|
matches = re.exec(lines[i]);
|
41
64
|
if (matches) {
|
42
65
|
|
@@ -50,11 +73,16 @@ module.exports = function(context) {
|
|
50
73
|
column: matches.index
|
51
74
|
};
|
52
75
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
76
|
+
if (i === ii - 1) {
|
77
|
+
fixRange = [totalLength + location.column + 1, totalLength + lines[i].length + 1];
|
78
|
+
} else {
|
79
|
+
fixRange = [totalLength + location.column, totalLength + lines[i].length];
|
80
|
+
}
|
81
|
+
|
82
|
+
report(node, location, fixRange);
|
57
83
|
}
|
84
|
+
|
85
|
+
totalLength += lines[i].length;
|
58
86
|
}
|
59
87
|
}
|
60
88
|
|