eslint 2.11.0 → 2.13.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/CHANGELOG.md +77 -0
- package/README.md +24 -0
- package/conf/eslint-all.js +29 -0
- package/conf/eslint.json +10 -6
- package/lib/ast-utils.js +91 -0
- package/lib/config/config-file.js +9 -4
- package/lib/config/config-ops.js +27 -2
- package/lib/eslint.js +34 -15
- package/lib/file-finder.js +3 -59
- package/lib/ignored-paths.js +38 -4
- package/lib/options.js +1 -1
- package/lib/rules/accessor-pairs.js +1 -1
- package/lib/rules/array-bracket-spacing.js +1 -1
- package/lib/rules/arrow-body-style.js +57 -15
- package/lib/rules/callback-return.js +25 -3
- package/lib/rules/default-case.js +1 -1
- package/lib/rules/eqeqeq.js +1 -1
- package/lib/rules/func-names.js +15 -4
- package/lib/rules/max-len.js +3 -2
- package/lib/rules/max-lines.js +148 -0
- package/lib/rules/max-statements-per-line.js +1 -1
- package/lib/rules/newline-per-chained-call.js +16 -1
- package/lib/rules/no-extra-parens.js +1 -92
- package/lib/rules/no-extra-semi.js +10 -1
- package/lib/rules/no-mixed-operators.js +212 -0
- package/lib/rules/no-multiple-empty-lines.js +40 -9
- package/lib/rules/no-prototype-builtins.js +1 -1
- package/lib/rules/no-script-url.js +1 -1
- package/lib/rules/no-unsafe-finally.js +1 -1
- package/lib/rules/no-useless-rename.js +11 -3
- package/lib/rules/object-curly-newline.js +209 -0
- package/lib/rules/object-shorthand.js +75 -5
- package/lib/rules/one-var.js +3 -0
- package/lib/rules/padded-blocks.js +19 -1
- package/lib/rules/rest-spread-spacing.js +107 -0
- package/lib/rules/unicode-bom.js +1 -1
- package/lib/util/glob-util.js +2 -1
- package/package.json +4 -2
@@ -16,16 +16,45 @@ module.exports = {
|
|
16
16
|
recommended: false
|
17
17
|
},
|
18
18
|
|
19
|
-
schema:
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
schema: {
|
20
|
+
anyOf: [
|
21
|
+
{
|
22
|
+
type: "array",
|
23
|
+
items: [
|
24
|
+
{
|
25
|
+
enum: ["always", "never"]
|
26
|
+
}
|
27
|
+
],
|
28
|
+
minItems: 0,
|
29
|
+
maxItems: 1
|
30
|
+
},
|
31
|
+
{
|
32
|
+
type: "array",
|
33
|
+
items: [
|
34
|
+
{
|
35
|
+
enum: ["as-needed"]
|
36
|
+
},
|
37
|
+
{
|
38
|
+
type: "object",
|
39
|
+
properties: {
|
40
|
+
requireReturnForObjectLiteral: {type: "boolean"}
|
41
|
+
},
|
42
|
+
additionalProperties: false
|
43
|
+
}
|
44
|
+
],
|
45
|
+
minItems: 0,
|
46
|
+
maxItems: 2
|
47
|
+
}
|
48
|
+
]
|
49
|
+
}
|
24
50
|
},
|
25
51
|
|
26
52
|
create: function(context) {
|
27
|
-
var
|
28
|
-
var
|
53
|
+
var options = context.options;
|
54
|
+
var always = options[0] === "always";
|
55
|
+
var asNeeded = !options[0] || options[0] === "as-needed";
|
56
|
+
var never = options[0] === "never";
|
57
|
+
var requireReturnForObjectLiteral = options[1] && options[1].requireReturnForObjectLiteral;
|
29
58
|
|
30
59
|
/**
|
31
60
|
* Determines whether a arrow function body needs braces
|
@@ -36,21 +65,34 @@ module.exports = {
|
|
36
65
|
var arrowBody = node.body;
|
37
66
|
|
38
67
|
if (arrowBody.type === "BlockStatement") {
|
39
|
-
|
40
|
-
|
41
|
-
if (blockBody.length !== 1) {
|
42
|
-
return;
|
43
|
-
}
|
44
|
-
|
45
|
-
if (asNeeded && blockBody[0].type === "ReturnStatement") {
|
68
|
+
if (never) {
|
46
69
|
context.report({
|
47
70
|
node: node,
|
48
71
|
loc: arrowBody.loc.start,
|
49
72
|
message: "Unexpected block statement surrounding arrow body."
|
50
73
|
});
|
74
|
+
} else {
|
75
|
+
var blockBody = arrowBody.body;
|
76
|
+
|
77
|
+
if (blockBody.length !== 1) {
|
78
|
+
return;
|
79
|
+
}
|
80
|
+
|
81
|
+
if (asNeeded && requireReturnForObjectLiteral && blockBody[0].type === "ReturnStatement" &&
|
82
|
+
blockBody[0].argument.type === "ObjectExpression") {
|
83
|
+
return;
|
84
|
+
}
|
85
|
+
|
86
|
+
if (asNeeded && blockBody[0].type === "ReturnStatement") {
|
87
|
+
context.report({
|
88
|
+
node: node,
|
89
|
+
loc: arrowBody.loc.start,
|
90
|
+
message: "Unexpected block statement surrounding arrow body."
|
91
|
+
});
|
92
|
+
}
|
51
93
|
}
|
52
94
|
} else {
|
53
|
-
if (always) {
|
95
|
+
if (always || (asNeeded && requireReturnForObjectLiteral && arrowBody.type === "ObjectExpression")) {
|
54
96
|
context.report({
|
55
97
|
node: node,
|
56
98
|
loc: arrowBody.loc.start,
|
@@ -24,7 +24,8 @@ module.exports = {
|
|
24
24
|
|
25
25
|
create: function(context) {
|
26
26
|
|
27
|
-
var callbacks = context.options[0] || ["callback", "cb", "next"]
|
27
|
+
var callbacks = context.options[0] || ["callback", "cb", "next"],
|
28
|
+
sourceCode = context.getSourceCode();
|
28
29
|
|
29
30
|
//--------------------------------------------------------------------------
|
30
31
|
// Helpers
|
@@ -46,13 +47,34 @@ module.exports = {
|
|
46
47
|
return node.parent;
|
47
48
|
}
|
48
49
|
|
50
|
+
/**
|
51
|
+
* Check to see if a node contains only identifers
|
52
|
+
* @param {ASTNode} node The node to check
|
53
|
+
* @returns {Boolean} Whether or not the node contains only identifers
|
54
|
+
*/
|
55
|
+
function containsOnlyIdentifiers(node) {
|
56
|
+
if (node.type === "Identifier") {
|
57
|
+
return true;
|
58
|
+
}
|
59
|
+
|
60
|
+
if (node.type === "MemberExpression") {
|
61
|
+
if (node.object.type === "Identifier") {
|
62
|
+
return true;
|
63
|
+
} else if (node.object.type === "MemberExpression") {
|
64
|
+
return containsOnlyIdentifiers(node.object);
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
return false;
|
69
|
+
}
|
70
|
+
|
49
71
|
/**
|
50
72
|
* Check to see if a CallExpression is in our callback list.
|
51
73
|
* @param {ASTNode} node The node to check against our callback names list.
|
52
74
|
* @returns {Boolean} Whether or not this function matches our callback name.
|
53
75
|
*/
|
54
76
|
function isCallback(node) {
|
55
|
-
return node.callee
|
77
|
+
return containsOnlyIdentifiers(node.callee) && callbacks.indexOf(sourceCode.getText(node.callee)) > -1;
|
56
78
|
}
|
57
79
|
|
58
80
|
/**
|
@@ -90,7 +112,7 @@ module.exports = {
|
|
90
112
|
return {
|
91
113
|
CallExpression: function(node) {
|
92
114
|
|
93
|
-
// if we
|
115
|
+
// if we're not a callback we can return
|
94
116
|
if (!isCallback(node)) {
|
95
117
|
return;
|
96
118
|
}
|
@@ -13,7 +13,7 @@ var DEFAULT_COMMENT_PATTERN = /^no default$/;
|
|
13
13
|
module.exports = {
|
14
14
|
meta: {
|
15
15
|
docs: {
|
16
|
-
description: "require `default` cases in
|
16
|
+
description: "require `default` cases in `switch` statements",
|
17
17
|
category: "Best Practices",
|
18
18
|
recommended: false
|
19
19
|
},
|
package/lib/rules/eqeqeq.js
CHANGED
package/lib/rules/func-names.js
CHANGED
@@ -12,15 +12,20 @@
|
|
12
12
|
module.exports = {
|
13
13
|
meta: {
|
14
14
|
docs: {
|
15
|
-
description: "
|
15
|
+
description: "require or disallow named `function` expressions",
|
16
16
|
category: "Stylistic Issues",
|
17
17
|
recommended: false
|
18
18
|
},
|
19
19
|
|
20
|
-
schema: [
|
20
|
+
schema: [
|
21
|
+
{
|
22
|
+
enum: ["always", "never"]
|
23
|
+
}
|
24
|
+
]
|
21
25
|
},
|
22
26
|
|
23
27
|
create: function(context) {
|
28
|
+
var never = context.options[0] === "never";
|
24
29
|
|
25
30
|
/**
|
26
31
|
* Determines whether the current FunctionExpression node is a get, set, or
|
@@ -44,8 +49,14 @@ module.exports = {
|
|
44
49
|
|
45
50
|
var name = node.id && node.id.name;
|
46
51
|
|
47
|
-
if (
|
48
|
-
|
52
|
+
if (never) {
|
53
|
+
if (name) {
|
54
|
+
context.report(node, "Unexpected function expression name.");
|
55
|
+
}
|
56
|
+
} else {
|
57
|
+
if (!name && !isObjectOrClassMethod()) {
|
58
|
+
context.report(node, "Missing function expression name.");
|
59
|
+
}
|
49
60
|
}
|
50
61
|
}
|
51
62
|
};
|
package/lib/rules/max-len.js
CHANGED
@@ -157,10 +157,11 @@ module.exports = {
|
|
157
157
|
*/
|
158
158
|
function isFullLineComment(line, lineNumber, comment) {
|
159
159
|
var start = comment.loc.start,
|
160
|
-
end = comment.loc.end
|
160
|
+
end = comment.loc.end,
|
161
|
+
isFirstTokenOnLine = !line.slice(0, comment.loc.start.column).trim();
|
161
162
|
|
162
163
|
return comment &&
|
163
|
-
(start.line < lineNumber || (start.line === lineNumber &&
|
164
|
+
(start.line < lineNumber || (start.line === lineNumber && isFirstTokenOnLine)) &&
|
164
165
|
(end.line > lineNumber || end.column === line.length);
|
165
166
|
}
|
166
167
|
|
@@ -0,0 +1,148 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview enforce a maximum file length
|
3
|
+
* @author Alberto Rodríguez
|
4
|
+
*/
|
5
|
+
"use strict";
|
6
|
+
|
7
|
+
//------------------------------------------------------------------------------
|
8
|
+
// Requirements
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
|
11
|
+
var lodash = require("lodash");
|
12
|
+
var astUtils = require("../ast-utils");
|
13
|
+
|
14
|
+
//------------------------------------------------------------------------------
|
15
|
+
// Rule Definition
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
module.exports = {
|
19
|
+
meta: {
|
20
|
+
docs: {
|
21
|
+
description: "enforce a maximum number of lines per file",
|
22
|
+
category: "Stylistic Issues",
|
23
|
+
recommended: false
|
24
|
+
},
|
25
|
+
|
26
|
+
schema: [
|
27
|
+
{
|
28
|
+
oneOf: [
|
29
|
+
{
|
30
|
+
type: "integer",
|
31
|
+
minimum: 0
|
32
|
+
},
|
33
|
+
{
|
34
|
+
type: "object",
|
35
|
+
properties: {
|
36
|
+
max: {
|
37
|
+
type: "integer",
|
38
|
+
minimum: 0
|
39
|
+
},
|
40
|
+
skipComments: {
|
41
|
+
type: "boolean"
|
42
|
+
},
|
43
|
+
skipBlankLines: {
|
44
|
+
type: "boolean"
|
45
|
+
}
|
46
|
+
},
|
47
|
+
additionalProperties: false
|
48
|
+
}
|
49
|
+
]
|
50
|
+
}
|
51
|
+
]
|
52
|
+
},
|
53
|
+
|
54
|
+
create: function(context) {
|
55
|
+
var option = context.options[0],
|
56
|
+
max = 300;
|
57
|
+
|
58
|
+
if (typeof option === "object" && option.hasOwnProperty("max") && typeof option.max === "number") {
|
59
|
+
max = option.max;
|
60
|
+
}
|
61
|
+
|
62
|
+
if (typeof option === "number") {
|
63
|
+
max = option;
|
64
|
+
}
|
65
|
+
|
66
|
+
var skipComments = option && option.skipComments;
|
67
|
+
var skipBlankLines = option && option.skipBlankLines;
|
68
|
+
|
69
|
+
var sourceCode = context.getSourceCode();
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Returns whether or not a token is a comment node type
|
73
|
+
* @param {Token} token The token to check
|
74
|
+
* @returns {boolean} True if the token is a comment node
|
75
|
+
*/
|
76
|
+
function isCommentNodeType(token) {
|
77
|
+
return token && (token.type === "Block" || token.type === "Line");
|
78
|
+
}
|
79
|
+
|
80
|
+
/**
|
81
|
+
* Returns the line numbers of a comment that don't have any code on the same line
|
82
|
+
* @param {Node} comment The comment node to check
|
83
|
+
* @returns {int[]} The line numbers
|
84
|
+
*/
|
85
|
+
function getLinesWithoutCode(comment) {
|
86
|
+
var start = comment.loc.start.line;
|
87
|
+
var end = comment.loc.end.line;
|
88
|
+
|
89
|
+
var token;
|
90
|
+
|
91
|
+
token = comment;
|
92
|
+
do {
|
93
|
+
token = sourceCode.getTokenOrCommentBefore(token);
|
94
|
+
} while (isCommentNodeType(token));
|
95
|
+
|
96
|
+
if (token && astUtils.isTokenOnSameLine(token, comment)) {
|
97
|
+
start += 1;
|
98
|
+
}
|
99
|
+
|
100
|
+
token = comment;
|
101
|
+
do {
|
102
|
+
token = sourceCode.getTokenOrCommentAfter(token);
|
103
|
+
} while (isCommentNodeType(token));
|
104
|
+
|
105
|
+
if (token && astUtils.isTokenOnSameLine(comment, token)) {
|
106
|
+
end -= 1;
|
107
|
+
}
|
108
|
+
|
109
|
+
if (start <= end) {
|
110
|
+
return lodash.range(start, end + 1);
|
111
|
+
}
|
112
|
+
return [];
|
113
|
+
}
|
114
|
+
|
115
|
+
return {
|
116
|
+
"Program:exit": function() {
|
117
|
+
var lines = sourceCode.lines.map(function(text, i) {
|
118
|
+
return { lineNumber: i + 1, text: text };
|
119
|
+
});
|
120
|
+
|
121
|
+
if (skipBlankLines) {
|
122
|
+
lines = lines.filter(function(l) {
|
123
|
+
return l.text.trim() !== "";
|
124
|
+
});
|
125
|
+
}
|
126
|
+
|
127
|
+
if (skipComments) {
|
128
|
+
var comments = sourceCode.getAllComments();
|
129
|
+
|
130
|
+
var commentLines = lodash.flatten(comments.map(function(comment) {
|
131
|
+
return getLinesWithoutCode(comment);
|
132
|
+
}));
|
133
|
+
|
134
|
+
lines = lines.filter(function(l) {
|
135
|
+
return !lodash.includes(commentLines, l.lineNumber);
|
136
|
+
});
|
137
|
+
}
|
138
|
+
|
139
|
+
if (lines.length > max) {
|
140
|
+
context.report({
|
141
|
+
loc: { line: 1, column: 0 },
|
142
|
+
message: "File must be at most " + max + " lines long"
|
143
|
+
});
|
144
|
+
}
|
145
|
+
}
|
146
|
+
};
|
147
|
+
}
|
148
|
+
};
|
@@ -43,7 +43,7 @@ module.exports = {
|
|
43
43
|
// Helpers
|
44
44
|
//--------------------------------------------------------------------------
|
45
45
|
|
46
|
-
var SINGLE_CHILD_ALLOWED = /^(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement$/;
|
46
|
+
var SINGLE_CHILD_ALLOWED = /^(?:(?:DoWhile|For|ForIn|ForOf|If|Labeled|While)Statement|Export(?:Default|Named)Declaration)$/;
|
47
47
|
|
48
48
|
/**
|
49
49
|
* Gets the actual last token of a given node.
|
@@ -38,6 +38,21 @@ module.exports = {
|
|
38
38
|
|
39
39
|
var sourceCode = context.getSourceCode();
|
40
40
|
|
41
|
+
/**
|
42
|
+
* Gets the property text of a given MemberExpression node.
|
43
|
+
* If the text is multiline, this returns only the first line.
|
44
|
+
*
|
45
|
+
* @param {ASTNode} node - A MemberExpression node to get.
|
46
|
+
* @returns {string} The property text of the node.
|
47
|
+
*/
|
48
|
+
function getPropertyText(node) {
|
49
|
+
var prefix = node.computed ? "[" : ".";
|
50
|
+
var lines = sourceCode.getText(node.property).split(/\r\n|\r|\n/g);
|
51
|
+
var suffix = node.computed && lines.length === 1 ? "]" : "";
|
52
|
+
|
53
|
+
return prefix + lines[0] + suffix;
|
54
|
+
}
|
55
|
+
|
41
56
|
return {
|
42
57
|
"CallExpression:exit": function(node) {
|
43
58
|
if (!node.callee || node.callee.type !== "MemberExpression") {
|
@@ -57,7 +72,7 @@ module.exports = {
|
|
57
72
|
context.report(
|
58
73
|
callee.property,
|
59
74
|
callee.property.loc.start,
|
60
|
-
"Expected line break
|
75
|
+
"Expected line break before `" + getPropertyText(callee) + "`."
|
61
76
|
);
|
62
77
|
}
|
63
78
|
}
|
@@ -57,6 +57,7 @@ module.exports = {
|
|
57
57
|
var sourceCode = context.getSourceCode();
|
58
58
|
|
59
59
|
var isParenthesised = astUtils.isParenthesised.bind(astUtils, sourceCode);
|
60
|
+
var precedence = astUtils.getPrecedence;
|
60
61
|
var ALL_NODES = context.options[0] !== "functions";
|
61
62
|
var EXCEPT_COND_ASSIGN = ALL_NODES && context.options[1] && context.options[1].conditionalAssign === false;
|
62
63
|
var NESTED_BINARY = ALL_NODES && context.options[1] && context.options[1].nestedBinaryExpressions === false;
|
@@ -255,98 +256,6 @@ module.exports = {
|
|
255
256
|
throw new Error("unreachable");
|
256
257
|
}
|
257
258
|
|
258
|
-
/**
|
259
|
-
* Get the precedence level based on the node type
|
260
|
-
* @param {ASTNode} node node to evaluate
|
261
|
-
* @returns {int} precedence level
|
262
|
-
* @private
|
263
|
-
*/
|
264
|
-
function precedence(node) {
|
265
|
-
|
266
|
-
switch (node.type) {
|
267
|
-
case "SequenceExpression":
|
268
|
-
return 0;
|
269
|
-
|
270
|
-
case "AssignmentExpression":
|
271
|
-
case "ArrowFunctionExpression":
|
272
|
-
case "YieldExpression":
|
273
|
-
return 1;
|
274
|
-
|
275
|
-
case "ConditionalExpression":
|
276
|
-
return 3;
|
277
|
-
|
278
|
-
case "LogicalExpression":
|
279
|
-
switch (node.operator) {
|
280
|
-
case "||":
|
281
|
-
return 4;
|
282
|
-
case "&&":
|
283
|
-
return 5;
|
284
|
-
|
285
|
-
// no default
|
286
|
-
}
|
287
|
-
|
288
|
-
/* falls through */
|
289
|
-
|
290
|
-
case "BinaryExpression":
|
291
|
-
|
292
|
-
switch (node.operator) {
|
293
|
-
case "|":
|
294
|
-
return 6;
|
295
|
-
case "^":
|
296
|
-
return 7;
|
297
|
-
case "&":
|
298
|
-
return 8;
|
299
|
-
case "==":
|
300
|
-
case "!=":
|
301
|
-
case "===":
|
302
|
-
case "!==":
|
303
|
-
return 9;
|
304
|
-
case "<":
|
305
|
-
case "<=":
|
306
|
-
case ">":
|
307
|
-
case ">=":
|
308
|
-
case "in":
|
309
|
-
case "instanceof":
|
310
|
-
return 10;
|
311
|
-
case "<<":
|
312
|
-
case ">>":
|
313
|
-
case ">>>":
|
314
|
-
return 11;
|
315
|
-
case "+":
|
316
|
-
case "-":
|
317
|
-
return 12;
|
318
|
-
case "*":
|
319
|
-
case "/":
|
320
|
-
case "%":
|
321
|
-
return 13;
|
322
|
-
|
323
|
-
// no default
|
324
|
-
}
|
325
|
-
|
326
|
-
/* falls through */
|
327
|
-
|
328
|
-
case "UnaryExpression":
|
329
|
-
return 14;
|
330
|
-
|
331
|
-
case "UpdateExpression":
|
332
|
-
return 15;
|
333
|
-
|
334
|
-
case "CallExpression":
|
335
|
-
|
336
|
-
// IIFE is allowed to have parens in any position (#655)
|
337
|
-
if (node.callee.type === "FunctionExpression") {
|
338
|
-
return -1;
|
339
|
-
}
|
340
|
-
return 16;
|
341
|
-
|
342
|
-
case "NewExpression":
|
343
|
-
return 17;
|
344
|
-
|
345
|
-
// no default
|
346
|
-
}
|
347
|
-
return 18;
|
348
|
-
}
|
349
|
-
|
350
259
|
/**
|
351
260
|
* Report the node
|
352
261
|
* @param {ASTNode} node node to evaluate
|
@@ -66,7 +66,16 @@ module.exports = {
|
|
66
66
|
*/
|
67
67
|
EmptyStatement: function(node) {
|
68
68
|
var parent = node.parent,
|
69
|
-
allowedParentTypes = [
|
69
|
+
allowedParentTypes = [
|
70
|
+
"ForStatement",
|
71
|
+
"ForInStatement",
|
72
|
+
"ForOfStatement",
|
73
|
+
"WhileStatement",
|
74
|
+
"DoWhileStatement",
|
75
|
+
"IfStatement",
|
76
|
+
"LabeledStatement",
|
77
|
+
"WithStatement"
|
78
|
+
];
|
70
79
|
|
71
80
|
if (allowedParentTypes.indexOf(parent.type) === -1) {
|
72
81
|
report(node);
|