eslint 1.8.0 → 1.9.0
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/conf/eslint.json +1 -0
- package/lib/cli-engine.js +7 -74
- package/lib/eslint.js +1 -12
- package/lib/rules/linebreak-style.js +45 -10
- package/lib/rules/max-nested-callbacks.js +1 -1
- package/lib/rules/no-case-declarations.js +47 -0
- package/lib/rules/no-multiple-empty-lines.js +2 -2
- package/lib/rules/no-shadow.js +1 -1
- package/lib/rules/no-use-before-define.js +1 -1
- package/lib/rules/no-warning-comments.js +1 -1
- package/lib/rules/radix.js +36 -6
- package/lib/rules/space-in-parens.js +6 -2
- package/lib/rules/spaced-comment.js +3 -3
- package/lib/rules.js +13 -9
- package/lib/util/estraverse.js +54 -0
- package/lib/util/glob-util.js +149 -0
- package/lib/util/source-code-fixer.js +1 -1
- package/lib/util/source-code.js +5 -1
- package/lib/util.js +15 -9
- package/package.json +21 -21
package/conf/eslint.json
CHANGED
package/lib/cli-engine.js
CHANGED
@@ -22,7 +22,6 @@ var fs = require("fs"),
|
|
22
22
|
|
23
23
|
assign = require("object-assign"),
|
24
24
|
debug = require("debug"),
|
25
|
-
glob = require("glob"),
|
26
25
|
shell = require("shelljs"),
|
27
26
|
|
28
27
|
rules = require("./rules"),
|
@@ -31,6 +30,7 @@ var fs = require("fs"),
|
|
31
30
|
Config = require("./config"),
|
32
31
|
util = require("./util"),
|
33
32
|
fileEntryCache = require("file-entry-cache"),
|
33
|
+
globUtil = require("./util/glob-util"),
|
34
34
|
SourceCodeFixer = require("./util/source-code-fixer"),
|
35
35
|
validator = require("./config-validator"),
|
36
36
|
stringify = require("json-stable-stringify"),
|
@@ -297,51 +297,6 @@ function isErrorMessage(message) {
|
|
297
297
|
return message.severity === 2;
|
298
298
|
}
|
299
299
|
|
300
|
-
|
301
|
-
/**
|
302
|
-
* Checks if a provided path is a directory and returns a glob string matching
|
303
|
-
* all files under that directory if so, the path itself otherwise.
|
304
|
-
*
|
305
|
-
* Reason for this is that `glob` needs `/**` to collect all the files under a
|
306
|
-
* directory where as our previous implementation without `glob` simply walked
|
307
|
-
* a directory that is passed. So this is to maintain backwards compatibility.
|
308
|
-
*
|
309
|
-
* Also makes sure all path separators are POSIX style for `glob` compatibility.
|
310
|
-
*
|
311
|
-
* @param {string[]} [extensions] An array of accepted extensions
|
312
|
-
* @returns {Function} A function that takes a pathname and returns a glob that
|
313
|
-
* matches all files with the provided extensions if
|
314
|
-
* pathname is a directory.
|
315
|
-
*/
|
316
|
-
function processPath(extensions) {
|
317
|
-
var suffix = "/**";
|
318
|
-
|
319
|
-
if (extensions) {
|
320
|
-
if (extensions.length === 1) {
|
321
|
-
suffix += "/*." + extensions[0];
|
322
|
-
} else {
|
323
|
-
suffix += "/*.{" + extensions.join(",") + "}";
|
324
|
-
}
|
325
|
-
}
|
326
|
-
|
327
|
-
/**
|
328
|
-
* A function that converts a directory name to a glob pattern
|
329
|
-
*
|
330
|
-
* @param {string} pathname The directory path to be modified
|
331
|
-
* @returns {string} The glob path or the file path itself
|
332
|
-
* @private
|
333
|
-
*/
|
334
|
-
return function(pathname) {
|
335
|
-
var newPath = pathname;
|
336
|
-
|
337
|
-
if (shell.test("-d", pathname)) {
|
338
|
-
newPath = pathname.replace(/[\/\\]$/, "") + suffix;
|
339
|
-
}
|
340
|
-
|
341
|
-
return newPath.replace(/\\/g, "/").replace(/^\.\//, "");
|
342
|
-
};
|
343
|
-
}
|
344
|
-
|
345
300
|
/**
|
346
301
|
* create a md5Hash of a given string
|
347
302
|
* @param {string} str the string to calculate the hash for
|
@@ -557,11 +512,7 @@ CLIEngine.prototype = {
|
|
557
512
|
* @returns {string[]} The equivalent glob patterns.
|
558
513
|
*/
|
559
514
|
resolveFileGlobPatterns: function(patterns) {
|
560
|
-
|
561
|
-
return ext.charAt(0) === "." ? ext.substr(1) : ext;
|
562
|
-
});
|
563
|
-
|
564
|
-
return patterns.map(processPath(extensions));
|
515
|
+
return globUtil.resolveFileGlobPatterns(patterns, this.options.extensions);
|
565
516
|
},
|
566
517
|
|
567
518
|
/**
|
@@ -575,20 +526,13 @@ CLIEngine.prototype = {
|
|
575
526
|
options = this.options,
|
576
527
|
fileCache = this._fileCache, // eslint-disable-line no-underscore-dangle
|
577
528
|
configHelper = new Config(options),
|
578
|
-
ignoredPaths = IgnoredPaths.load(options),
|
579
|
-
ignoredPathsList = ignoredPaths.patterns || [],
|
580
|
-
globOptions,
|
581
529
|
stats,
|
582
530
|
startTime,
|
583
531
|
prevConfig; // the previous configuration used
|
584
532
|
|
585
533
|
startTime = Date.now();
|
586
|
-
patterns = this.resolveFileGlobPatterns(patterns);
|
587
534
|
|
588
|
-
|
589
|
-
nodir: true,
|
590
|
-
ignore: ignoredPathsList
|
591
|
-
};
|
535
|
+
patterns = this.resolveFileGlobPatterns(patterns);
|
592
536
|
|
593
537
|
/**
|
594
538
|
* Calculates the hash of the config file used to validate a given file
|
@@ -619,22 +563,16 @@ CLIEngine.prototype = {
|
|
619
563
|
/**
|
620
564
|
* Executes the linter on a file defined by the `filename`. Skips
|
621
565
|
* unsupported file extensions and any files that are already linted.
|
622
|
-
* @param {string} filename The file to be linted
|
566
|
+
* @param {string} filename The resolved filename of the file to be linted
|
623
567
|
* @returns {void}
|
624
568
|
*/
|
625
569
|
function executeOnFile(filename) {
|
626
|
-
var
|
627
|
-
if (shouldIgnore) {
|
628
|
-
return;
|
629
|
-
}
|
570
|
+
var hashOfConfig;
|
630
571
|
|
631
|
-
filename = fs.realpathSync(filename);
|
632
572
|
if (processed[filename]) {
|
633
573
|
return;
|
634
574
|
}
|
635
575
|
|
636
|
-
var hashOfConfig;
|
637
|
-
|
638
576
|
if (options.cache) {
|
639
577
|
// get the descriptor for this file
|
640
578
|
// with the metadata and the flag that determines if
|
@@ -690,13 +628,8 @@ CLIEngine.prototype = {
|
|
690
628
|
results.push(res);
|
691
629
|
}
|
692
630
|
|
693
|
-
|
694
|
-
|
695
|
-
executeOnFile(pattern);
|
696
|
-
} else {
|
697
|
-
glob.sync(pattern, globOptions).forEach(executeOnFile);
|
698
|
-
}
|
699
|
-
});
|
631
|
+
// Lint each desired file
|
632
|
+
globUtil.listFilesToProcess(patterns, options).forEach(executeOnFile);
|
700
633
|
|
701
634
|
// only warn for files explicitly passed on the command line
|
702
635
|
if (options.ignore) {
|
package/lib/eslint.js
CHANGED
@@ -10,7 +10,7 @@
|
|
10
10
|
// Requirements
|
11
11
|
//------------------------------------------------------------------------------
|
12
12
|
|
13
|
-
var estraverse = require("estraverse
|
13
|
+
var estraverse = require("./util/estraverse"),
|
14
14
|
escope = require("escope"),
|
15
15
|
environments = require("../conf/environments"),
|
16
16
|
blankScriptAST = require("../conf/blank-script.json"),
|
@@ -32,17 +32,6 @@ var DEFAULT_PARSER = require("../conf/eslint.json").parser;
|
|
32
32
|
// Helpers
|
33
33
|
//------------------------------------------------------------------------------
|
34
34
|
|
35
|
-
// additional changes to make estraverse happy
|
36
|
-
estraverse.Syntax.ExperimentalSpreadProperty = "ExperimentalSpreadProperty";
|
37
|
-
estraverse.Syntax.ExperimentalRestProperty = "ExperimentalRestProperty";
|
38
|
-
|
39
|
-
estraverse.VisitorKeys.ExperimentalSpreadProperty = ["argument"];
|
40
|
-
estraverse.VisitorKeys.ExperimentalRestProperty = ["argument"];
|
41
|
-
|
42
|
-
// All nodes in ObjectExpression.properties and ObjectPattern.properties are visited as `Property`.
|
43
|
-
// See Also: https://github.com/estools/estraverse/blob/master/estraverse.js#L687-L688
|
44
|
-
estraverse.VisitorKeys.Property.push("argument");
|
45
|
-
|
46
35
|
/**
|
47
36
|
* Parses a list of "name:boolean_value" or/and "name" options divided by comma or
|
48
37
|
* whitespace.
|
@@ -13,25 +13,60 @@
|
|
13
13
|
//------------------------------------------------------------------------------
|
14
14
|
|
15
15
|
module.exports = function(context) {
|
16
|
+
|
16
17
|
var EXPECTED_LF_MSG = "Expected linebreaks to be 'LF' but found 'CRLF'.",
|
17
18
|
EXPECTED_CRLF_MSG = "Expected linebreaks to be 'CRLF' but found 'LF'.";
|
18
19
|
|
20
|
+
//--------------------------------------------------------------------------
|
21
|
+
// Helpers
|
22
|
+
//--------------------------------------------------------------------------
|
23
|
+
|
24
|
+
/**
|
25
|
+
* Builds a fix function that replaces text at the specified range in the source text.
|
26
|
+
* @param {int[]} range The range to replace
|
27
|
+
* @param {string} text The text to insert.
|
28
|
+
* @returns {function} Fixer function
|
29
|
+
* @private
|
30
|
+
*/
|
31
|
+
function createFix(range, text) {
|
32
|
+
return function(fixer) {
|
33
|
+
return fixer.replaceTextRange(range, text);
|
34
|
+
};
|
35
|
+
}
|
36
|
+
|
37
|
+
//--------------------------------------------------------------------------
|
38
|
+
// Public
|
39
|
+
//--------------------------------------------------------------------------
|
40
|
+
|
19
41
|
return {
|
20
42
|
"Program": function checkForlinebreakStyle(node) {
|
21
43
|
var linebreakStyle = context.options[0] || "unix",
|
22
44
|
expectedLF = linebreakStyle === "unix",
|
23
|
-
|
24
|
-
|
45
|
+
expectedLFChars = expectedLF ? "\n" : "\r\n",
|
46
|
+
source = context.getSource(),
|
47
|
+
pattern = /\r\n|\r|\n|\u2028|\u2029/g,
|
48
|
+
match,
|
49
|
+
index,
|
50
|
+
range;
|
25
51
|
|
26
|
-
|
27
|
-
|
28
|
-
|
52
|
+
var i = 0;
|
53
|
+
while ((match = pattern.exec(source)) !== null) {
|
54
|
+
i++;
|
55
|
+
if (match[0] === expectedLFChars) {
|
56
|
+
continue;
|
57
|
+
}
|
29
58
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
59
|
+
index = match.index;
|
60
|
+
range = [index, index + match[0].length];
|
61
|
+
context.report({
|
62
|
+
node: node,
|
63
|
+
loc: {
|
64
|
+
line: i,
|
65
|
+
column: context.getSourceLines()[i - 1].length
|
66
|
+
},
|
67
|
+
message: expectedLF ? EXPECTED_LF_MSG : EXPECTED_CRLF_MSG,
|
68
|
+
fix: createFix(range, expectedLFChars)
|
69
|
+
});
|
35
70
|
}
|
36
71
|
}
|
37
72
|
};
|
@@ -16,7 +16,7 @@ module.exports = function(context) {
|
|
16
16
|
// Constants
|
17
17
|
//--------------------------------------------------------------------------
|
18
18
|
|
19
|
-
var THRESHOLD = context.options[0];
|
19
|
+
var THRESHOLD = context.options[0] || 10;
|
20
20
|
|
21
21
|
//--------------------------------------------------------------------------
|
22
22
|
// Helpers
|
@@ -0,0 +1,47 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Rule to flag use of an lexical declarations inside a case clause
|
3
|
+
* @author Erik Arvidsson
|
4
|
+
* @copyright 2015 Erik Arvidsson. All rights reserved.
|
5
|
+
*/
|
6
|
+
"use strict";
|
7
|
+
|
8
|
+
//------------------------------------------------------------------------------
|
9
|
+
// Rule Definition
|
10
|
+
//------------------------------------------------------------------------------
|
11
|
+
|
12
|
+
module.exports = function(context) {
|
13
|
+
|
14
|
+
/**
|
15
|
+
* Checks whether or not a node is a lexical declaration.
|
16
|
+
* @param {ASTNode} node A direct child statement of a switch case.
|
17
|
+
* @returns {boolean} Whether or not the node is a lexical declaration.
|
18
|
+
*/
|
19
|
+
function isLexicalDeclaration(node) {
|
20
|
+
switch (node.type) {
|
21
|
+
case "FunctionDeclaration":
|
22
|
+
case "ClassDeclaration":
|
23
|
+
return true;
|
24
|
+
case "VariableDeclaration":
|
25
|
+
return node.kind !== "var";
|
26
|
+
default:
|
27
|
+
return false;
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
return {
|
32
|
+
"SwitchCase": function(node) {
|
33
|
+
for (var i = 0; i < node.consequent.length; i++) {
|
34
|
+
var statement = node.consequent[i];
|
35
|
+
if (isLexicalDeclaration(statement)) {
|
36
|
+
context.report({
|
37
|
+
node: node,
|
38
|
+
message: "Unexpected lexical declaration in case block."
|
39
|
+
});
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
};
|
44
|
+
|
45
|
+
};
|
46
|
+
|
47
|
+
module.exports.schema = [];
|
@@ -88,13 +88,13 @@ module.exports = function(context) {
|
|
88
88
|
// within the file, not at the end
|
89
89
|
if (blankCounter >= max) {
|
90
90
|
context.report(node, location,
|
91
|
-
"
|
91
|
+
"More than " + max + " blank lines not allowed.");
|
92
92
|
}
|
93
93
|
} else {
|
94
94
|
// inside the last blank lines
|
95
95
|
if (blankCounter >= maxEOF) {
|
96
96
|
context.report(node, location,
|
97
|
-
"Too many blank lines at the end of file.");
|
97
|
+
"Too many blank lines at the end of file. Max of " + maxEOF + " allowed.");
|
98
98
|
}
|
99
99
|
}
|
100
100
|
|
package/lib/rules/no-shadow.js
CHANGED
@@ -132,7 +132,7 @@ module.exports = function(context) {
|
|
132
132
|
if (variable.identifiers.length > 0 && isContainedInScopeVars(variable, scope.variables)) {
|
133
133
|
context.report(
|
134
134
|
variable.identifiers[0],
|
135
|
-
"{{name}} is already declared in the upper scope.",
|
135
|
+
"\"{{name}}\" is already declared in the upper scope.",
|
136
136
|
{name: variable.name});
|
137
137
|
} else {
|
138
138
|
passedVars.push(variable);
|
@@ -57,7 +57,7 @@ module.exports = function(context) {
|
|
57
57
|
function checkLocationAndReport(reference, declaration) {
|
58
58
|
if (typeOption !== NO_FUNC || declaration.defs[0].type !== "FunctionName") {
|
59
59
|
if (declaration.identifiers[0].range[1] > reference.identifier.range[1]) {
|
60
|
-
context.report(reference.identifier, "{{a}} was used before it was defined", {a: reference.identifier.name});
|
60
|
+
context.report(reference.identifier, "\"{{a}}\" was used before it was defined", {a: reference.identifier.name});
|
61
61
|
}
|
62
62
|
}
|
63
63
|
}
|
@@ -79,7 +79,7 @@ module.exports = function(context) {
|
|
79
79
|
var matches = commentContainsWarningTerm(node.value);
|
80
80
|
|
81
81
|
matches.forEach(function(matchedTerm) {
|
82
|
-
context.report(node, "Unexpected " + matchedTerm + " comment.");
|
82
|
+
context.report(node, "Unexpected \"" + matchedTerm + "\" comment.");
|
83
83
|
});
|
84
84
|
}
|
85
85
|
|
package/lib/rules/radix.js
CHANGED
@@ -11,6 +11,11 @@
|
|
11
11
|
|
12
12
|
module.exports = function(context) {
|
13
13
|
|
14
|
+
var MODE_ALWAYS = "always",
|
15
|
+
MODE_AS_NEEDED = "as-needed";
|
16
|
+
|
17
|
+
var mode = context.options[0] || MODE_ALWAYS;
|
18
|
+
|
14
19
|
return {
|
15
20
|
"CallExpression": function(node) {
|
16
21
|
|
@@ -25,17 +30,37 @@ module.exports = function(context) {
|
|
25
30
|
return;
|
26
31
|
}
|
27
32
|
|
28
|
-
if (node.arguments.length
|
29
|
-
context.report(
|
33
|
+
if (node.arguments.length === 0) {
|
34
|
+
context.report({
|
35
|
+
node: node,
|
36
|
+
message: "Missing parameters."
|
37
|
+
});
|
38
|
+
} else if (node.arguments.length < 2 && mode === MODE_ALWAYS) {
|
39
|
+
context.report({
|
40
|
+
node: node,
|
41
|
+
message: "Missing radix parameter."
|
42
|
+
});
|
43
|
+
} else if (node.arguments.length > 1 && mode === MODE_AS_NEEDED &&
|
44
|
+
(node.arguments[1] && node.arguments[1].type === "Literal" &&
|
45
|
+
node.arguments[1].value === 10)
|
46
|
+
) {
|
47
|
+
context.report({
|
48
|
+
node: node,
|
49
|
+
message: "Redundant radix parameter."
|
50
|
+
});
|
30
51
|
} else {
|
31
52
|
|
32
53
|
radix = node.arguments[1];
|
33
54
|
|
34
55
|
// don't allow non-numeric literals or undefined
|
35
|
-
if (
|
36
|
-
(radix.type === "
|
56
|
+
if (radix &&
|
57
|
+
((radix.type === "Literal" && typeof radix.value !== "number") ||
|
58
|
+
(radix.type === "Identifier" && radix.name === "undefined"))
|
37
59
|
) {
|
38
|
-
context.report(
|
60
|
+
context.report({
|
61
|
+
node: node,
|
62
|
+
message: "Invalid radix parameter."
|
63
|
+
});
|
39
64
|
}
|
40
65
|
}
|
41
66
|
|
@@ -44,4 +69,9 @@ module.exports = function(context) {
|
|
44
69
|
|
45
70
|
};
|
46
71
|
|
47
|
-
module.exports.schema = [
|
72
|
+
module.exports.schema = [
|
73
|
+
{
|
74
|
+
"enum": ["always", "as-needed"]
|
75
|
+
}
|
76
|
+
];
|
77
|
+
|
@@ -137,6 +137,10 @@ module.exports = function(context) {
|
|
137
137
|
* @returns {boolean} True if the paren should reject the space
|
138
138
|
*/
|
139
139
|
function shouldOpenerRejectSpace(left, right) {
|
140
|
+
if (right.type === "Line") {
|
141
|
+
return false;
|
142
|
+
}
|
143
|
+
|
140
144
|
if (!astUtils.isTokenOnSameLine(left, right)) {
|
141
145
|
return false;
|
142
146
|
}
|
@@ -184,9 +188,9 @@ module.exports = function(context) {
|
|
184
188
|
|
185
189
|
return {
|
186
190
|
"Program": function checkParenSpaces(node) {
|
187
|
-
var tokens
|
188
|
-
var prevToken, nextToken;
|
191
|
+
var tokens, prevToken, nextToken;
|
189
192
|
exceptions = getExceptions();
|
193
|
+
tokens = sourceCode.tokensAndComments;
|
190
194
|
|
191
195
|
tokens.forEach(function(token, i) {
|
192
196
|
prevToken = tokens[i - 1];
|
@@ -165,16 +165,16 @@ module.exports = function(context) {
|
|
165
165
|
if (requireSpace) {
|
166
166
|
if (!rule.regex.test(node.value)) {
|
167
167
|
if (rule.hasExceptions) {
|
168
|
-
context.report(node, "Expected exception block, space or tab after " + commentIdentifier + " in comment.");
|
168
|
+
context.report(node, "Expected exception block, space or tab after \"" + commentIdentifier + "\" in comment.");
|
169
169
|
} else {
|
170
|
-
context.report(node, "Expected space or tab after " + commentIdentifier + " in comment.");
|
170
|
+
context.report(node, "Expected space or tab after \"" + commentIdentifier + "\" in comment.");
|
171
171
|
}
|
172
172
|
}
|
173
173
|
} else {
|
174
174
|
var matched = rule.regex.exec(node.value);
|
175
175
|
if (matched) {
|
176
176
|
if (!matched[1]) {
|
177
|
-
context.report(node, "Unexpected space or tab after " + commentIdentifier + " in comment.");
|
177
|
+
context.report(node, "Unexpected space or tab after \"" + commentIdentifier + "\" in comment.");
|
178
178
|
} else {
|
179
179
|
context.report(node, "Unexpected space or tab after marker (" + matched[1] + ") in comment.");
|
180
180
|
}
|
package/lib/rules.js
CHANGED
@@ -31,8 +31,6 @@ function define(ruleId, ruleModule) {
|
|
31
31
|
rules[ruleId] = ruleModule;
|
32
32
|
}
|
33
33
|
|
34
|
-
exports.define = define;
|
35
|
-
|
36
34
|
/**
|
37
35
|
* Loads and registers all rules from passed rules directory.
|
38
36
|
* @param {String} [rulesDir] Path to rules directory, may be relative. Defaults to `lib/rules`.
|
@@ -45,43 +43,49 @@ function load(rulesDir) {
|
|
45
43
|
});
|
46
44
|
}
|
47
45
|
|
48
|
-
exports.load = load;
|
49
|
-
|
50
46
|
/**
|
51
47
|
* Registers all given rules of a plugin.
|
52
48
|
* @param {Object} pluginRules A key/value map of rule definitions.
|
53
49
|
* @param {String} pluginName The name of the plugin without prefix (`eslint-plugin-`).
|
54
50
|
* @returns {void}
|
55
51
|
*/
|
56
|
-
|
52
|
+
function importPlugin(pluginRules, pluginName) {
|
57
53
|
Object.keys(pluginRules).forEach(function(ruleId) {
|
58
54
|
var qualifiedRuleId = pluginName + "/" + ruleId,
|
59
55
|
rule = pluginRules[ruleId];
|
60
56
|
|
61
57
|
define(qualifiedRuleId, rule);
|
62
58
|
});
|
63
|
-
}
|
59
|
+
}
|
64
60
|
|
65
61
|
/**
|
66
62
|
* Access rule handler by id (file name).
|
67
63
|
* @param {String} ruleId Rule id (file name).
|
68
64
|
* @returns {Function} Rule handler.
|
69
65
|
*/
|
70
|
-
|
66
|
+
function get(ruleId) {
|
71
67
|
if (typeof rules[ruleId] === "string") {
|
72
68
|
return require(rules[ruleId]);
|
73
69
|
} else {
|
74
70
|
return rules[ruleId];
|
75
71
|
}
|
76
|
-
}
|
72
|
+
}
|
77
73
|
|
78
74
|
/**
|
79
75
|
* Reset rules storage.
|
80
76
|
* Should be used only in tests.
|
81
77
|
* @returns {void}
|
82
78
|
*/
|
83
|
-
|
79
|
+
function testClear() {
|
84
80
|
rules = Object.create(null);
|
81
|
+
}
|
82
|
+
|
83
|
+
module.exports = {
|
84
|
+
define: define,
|
85
|
+
load: load,
|
86
|
+
import: importPlugin,
|
87
|
+
get: get,
|
88
|
+
testClear: testClear
|
85
89
|
};
|
86
90
|
|
87
91
|
//------------------------------------------------------------------------------
|
@@ -0,0 +1,54 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Patch for estraverse
|
3
|
+
* @author Toru Nagashima
|
4
|
+
* @copyright 2015 Toru Nagashima. All rights reserved.
|
5
|
+
* See LICENSE file in root directory for full license.
|
6
|
+
*/
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
// Requirements
|
11
|
+
//------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
var estraverse = require("estraverse"),
|
14
|
+
jsxKeys = require("estraverse-fb/keys");
|
15
|
+
|
16
|
+
//------------------------------------------------------------------------------
|
17
|
+
// Helers
|
18
|
+
//------------------------------------------------------------------------------
|
19
|
+
|
20
|
+
var experimentalKeys = {
|
21
|
+
ExperimentalRestProperty: ["argument"],
|
22
|
+
ExperimentalSpreadProperty: ["argument"]
|
23
|
+
};
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Adds a given keys to Syntax and VisitorKeys of estraverse.
|
27
|
+
*
|
28
|
+
* @param {object} keys - Key definitions to add.
|
29
|
+
* This is an object as map.
|
30
|
+
* Keys are the node type.
|
31
|
+
* Values are an array of property names to visit.
|
32
|
+
* @returns {void}
|
33
|
+
*/
|
34
|
+
function installKeys(keys) {
|
35
|
+
for (var key in keys) {
|
36
|
+
if (keys.hasOwnProperty(key)) {
|
37
|
+
estraverse.Syntax[key] = key;
|
38
|
+
if (keys[key]) {
|
39
|
+
estraverse.VisitorKeys[key] = keys[key];
|
40
|
+
}
|
41
|
+
}
|
42
|
+
}
|
43
|
+
}
|
44
|
+
|
45
|
+
// Add JSX node types.
|
46
|
+
installKeys(jsxKeys);
|
47
|
+
// Add Experimental node types.
|
48
|
+
installKeys(experimentalKeys);
|
49
|
+
|
50
|
+
//------------------------------------------------------------------------------
|
51
|
+
// Public Interface
|
52
|
+
//------------------------------------------------------------------------------
|
53
|
+
|
54
|
+
module.exports = estraverse;
|
@@ -0,0 +1,149 @@
|
|
1
|
+
/**
|
2
|
+
* @fileoverview Utilities for working with globs and the filesystem.
|
3
|
+
* @author Ian VanSchooten
|
4
|
+
* @copyright 2015 Ian VanSchooten. All rights reserved.
|
5
|
+
* See LICENSE in root directory for full license.
|
6
|
+
*/
|
7
|
+
"use strict";
|
8
|
+
|
9
|
+
//------------------------------------------------------------------------------
|
10
|
+
// Requirements
|
11
|
+
//------------------------------------------------------------------------------
|
12
|
+
|
13
|
+
var debug = require("debug"),
|
14
|
+
fs = require("fs"),
|
15
|
+
glob = require("glob"),
|
16
|
+
shell = require("shelljs"),
|
17
|
+
|
18
|
+
IgnoredPaths = require("../ignored-paths");
|
19
|
+
|
20
|
+
debug = debug("eslint:glob-util");
|
21
|
+
|
22
|
+
//------------------------------------------------------------------------------
|
23
|
+
// Helpers
|
24
|
+
//------------------------------------------------------------------------------
|
25
|
+
|
26
|
+
/**
|
27
|
+
* Checks if a provided path is a directory and returns a glob string matching
|
28
|
+
* all files under that directory if so, the path itself otherwise.
|
29
|
+
*
|
30
|
+
* Reason for this is that `glob` needs `/**` to collect all the files under a
|
31
|
+
* directory where as our previous implementation without `glob` simply walked
|
32
|
+
* a directory that is passed. So this is to maintain backwards compatibility.
|
33
|
+
*
|
34
|
+
* Also makes sure all path separators are POSIX style for `glob` compatibility.
|
35
|
+
*
|
36
|
+
* @param {string[]} [extensions] An array of accepted extensions
|
37
|
+
* @returns {Function} A function that takes a pathname and returns a glob that
|
38
|
+
* matches all files with the provided extensions if
|
39
|
+
* pathname is a directory.
|
40
|
+
*/
|
41
|
+
function processPath(extensions) {
|
42
|
+
var suffix = "/**";
|
43
|
+
|
44
|
+
if (extensions) {
|
45
|
+
if (extensions.length === 1) {
|
46
|
+
suffix += "/*." + extensions[0];
|
47
|
+
} else {
|
48
|
+
suffix += "/*.{" + extensions.join(",") + "}";
|
49
|
+
}
|
50
|
+
}
|
51
|
+
|
52
|
+
/**
|
53
|
+
* A function that converts a directory name to a glob pattern
|
54
|
+
*
|
55
|
+
* @param {string} pathname The directory path to be modified
|
56
|
+
* @returns {string} The glob path or the file path itself
|
57
|
+
* @private
|
58
|
+
*/
|
59
|
+
return function(pathname) {
|
60
|
+
var newPath = pathname;
|
61
|
+
|
62
|
+
if (shell.test("-d", pathname)) {
|
63
|
+
newPath = pathname.replace(/[\/\\]$/, "") + suffix;
|
64
|
+
}
|
65
|
+
|
66
|
+
return newPath.replace(/\\/g, "/").replace(/^\.\//, "");
|
67
|
+
};
|
68
|
+
}
|
69
|
+
|
70
|
+
//------------------------------------------------------------------------------
|
71
|
+
// Public Interface
|
72
|
+
//------------------------------------------------------------------------------
|
73
|
+
|
74
|
+
/**
|
75
|
+
* Resolves the patterns into glob-based patterns for easier handling.
|
76
|
+
* @param {string[]} patterns File patterns (such as passed on the command line).
|
77
|
+
* @param {string[]} extensions List of valid file extensions.
|
78
|
+
* @returns {string[]} The equivalent glob patterns.
|
79
|
+
*/
|
80
|
+
function resolveFileGlobPatterns(patterns, extensions) {
|
81
|
+
extensions = extensions || [".js"];
|
82
|
+
|
83
|
+
extensions = extensions.map(function(ext) {
|
84
|
+
return ext.charAt(0) === "." ? ext.substr(1) : ext;
|
85
|
+
});
|
86
|
+
|
87
|
+
return patterns.map(processPath(extensions));
|
88
|
+
}
|
89
|
+
|
90
|
+
/**
|
91
|
+
* Build a list of absolute filesnames on which ESLint will act.
|
92
|
+
* Ignored files are excluded from the results, as are duplicates.
|
93
|
+
*
|
94
|
+
* @param {string[]} globPatterns Glob patterns.
|
95
|
+
* @param {Object} [options] An options object.
|
96
|
+
* @param {boolean} [options.ignore] False disables use of .eslintignore.
|
97
|
+
* @param {string} [options.ignorePath] The ignore file to use instead of .eslintignore.
|
98
|
+
* @param {string} [options.ignorePattern] A pattern of files to ignore.
|
99
|
+
* @returns {string[]} Resolved absolute filenames.
|
100
|
+
*/
|
101
|
+
function listFilesToProcess(globPatterns, options) {
|
102
|
+
var ignoredPaths,
|
103
|
+
ignoredPathsList,
|
104
|
+
files = [],
|
105
|
+
added = {},
|
106
|
+
globOptions;
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Executes the linter on a file defined by the `filename`. Skips
|
110
|
+
* unsupported file extensions and any files that are already linted.
|
111
|
+
* @param {string} filename The file to be processed
|
112
|
+
* @returns {void}
|
113
|
+
*/
|
114
|
+
function addFile(filename) {
|
115
|
+
if (ignoredPaths.contains(filename)) {
|
116
|
+
return;
|
117
|
+
}
|
118
|
+
filename = fs.realpathSync(filename);
|
119
|
+
if (added[filename]) {
|
120
|
+
return;
|
121
|
+
}
|
122
|
+
files.push(filename);
|
123
|
+
added[filename] = true;
|
124
|
+
}
|
125
|
+
|
126
|
+
options = options || { ignore: true };
|
127
|
+
ignoredPaths = IgnoredPaths.load(options);
|
128
|
+
ignoredPathsList = ignoredPaths.patterns || [];
|
129
|
+
globOptions = {
|
130
|
+
nodir: true,
|
131
|
+
ignore: ignoredPathsList
|
132
|
+
};
|
133
|
+
|
134
|
+
debug("Creating list of files to process.");
|
135
|
+
globPatterns.forEach(function(pattern) {
|
136
|
+
if (shell.test("-f", pattern)) {
|
137
|
+
addFile(pattern);
|
138
|
+
} else {
|
139
|
+
glob.sync(pattern, globOptions).forEach(addFile);
|
140
|
+
}
|
141
|
+
});
|
142
|
+
|
143
|
+
return files;
|
144
|
+
}
|
145
|
+
|
146
|
+
module.exports = {
|
147
|
+
resolveFileGlobPatterns: resolveFileGlobPatterns,
|
148
|
+
listFilesToProcess: listFilesToProcess
|
149
|
+
};
|
@@ -97,7 +97,7 @@ SourceCodeFixer.applyFixes = function(sourceCode, messages) {
|
|
97
97
|
fixes.forEach(function(problem) {
|
98
98
|
var fix = problem.fix;
|
99
99
|
|
100
|
-
if (fix.range[1]
|
100
|
+
if (fix.range[1] < lastFixPos) {
|
101
101
|
chars.splice(fix.range[0], fix.range[1] - fix.range[0], fix.text);
|
102
102
|
lastFixPos = fix.range[0];
|
103
103
|
} else {
|
package/lib/util/source-code.js
CHANGED
@@ -12,7 +12,7 @@
|
|
12
12
|
//------------------------------------------------------------------------------
|
13
13
|
|
14
14
|
var createTokenStore = require("../token-store.js"),
|
15
|
-
estraverse = require("estraverse"),
|
15
|
+
estraverse = require("./estraverse"),
|
16
16
|
assign = require("object-assign");
|
17
17
|
|
18
18
|
//------------------------------------------------------------------------------
|
@@ -115,6 +115,10 @@ function SourceCode(text, ast) {
|
|
115
115
|
*/
|
116
116
|
this.lines = text.split(/\r\n|\r|\n|\u2028|\u2029/g);
|
117
117
|
|
118
|
+
this.tokensAndComments = ast.tokens.concat(ast.comments).sort(function(left, right) {
|
119
|
+
return left.range[0] - right.range[0];
|
120
|
+
});
|
121
|
+
|
118
122
|
// create token store methods
|
119
123
|
var tokenStore = createTokenStore(ast.tokens);
|
120
124
|
Object.keys(tokenStore).forEach(function(methodName) {
|
package/lib/util.js
CHANGED
@@ -22,7 +22,7 @@ var PLUGIN_NAME_PREFIX = "eslint-plugin-",
|
|
22
22
|
* @param {boolean} [isRule] Whether its a rule
|
23
23
|
* @returns {Object} merged config object.
|
24
24
|
*/
|
25
|
-
|
25
|
+
function deepmerge(target, src, combine, isRule) {
|
26
26
|
/*
|
27
27
|
The MIT License (MIT)
|
28
28
|
|
@@ -104,32 +104,38 @@ exports.mergeConfigs = function deepmerge(target, src, combine, isRule) {
|
|
104
104
|
}
|
105
105
|
|
106
106
|
return dst;
|
107
|
-
}
|
107
|
+
}
|
108
108
|
|
109
109
|
/**
|
110
110
|
* Removes the prefix `eslint-plugin-` from a plugin name.
|
111
111
|
* @param {string} pluginName The name of the plugin which may have the prefix.
|
112
112
|
* @returns {string} The name of the plugin without prefix.
|
113
113
|
*/
|
114
|
-
|
114
|
+
function removePluginPrefix(pluginName) {
|
115
115
|
return pluginName.indexOf(PLUGIN_NAME_PREFIX) === 0 ? pluginName.substring(PLUGIN_NAME_PREFIX.length) : pluginName;
|
116
|
-
}
|
116
|
+
}
|
117
117
|
|
118
118
|
/**
|
119
119
|
* @param {string} pluginName The name of the plugin which may have the prefix.
|
120
120
|
* @returns {string} The name of the plugins namepace if it has one.
|
121
121
|
*/
|
122
|
-
|
122
|
+
function getNamespace(pluginName) {
|
123
123
|
return pluginName.match(NAMESPACE_REGEX) ? pluginName.match(NAMESPACE_REGEX)[0] : "";
|
124
|
-
}
|
124
|
+
}
|
125
125
|
|
126
126
|
/**
|
127
127
|
* Removes the namespace from a plugin name.
|
128
128
|
* @param {string} pluginName The name of the plugin which may have the prefix.
|
129
129
|
* @returns {string} The name of the plugin without the namespace.
|
130
130
|
*/
|
131
|
-
|
131
|
+
function removeNameSpace(pluginName) {
|
132
132
|
return pluginName.replace(NAMESPACE_REGEX, "");
|
133
|
-
}
|
133
|
+
}
|
134
134
|
|
135
|
-
exports
|
135
|
+
module.exports = {
|
136
|
+
mergeConfigs: deepmerge,
|
137
|
+
removePluginPrefix: removePluginPrefix,
|
138
|
+
getNamespace: getNamespace,
|
139
|
+
removeNameSpace: removeNameSpace,
|
140
|
+
"PLUGIN_NAME_PREFIX": PLUGIN_NAME_PREFIX
|
141
|
+
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.9.0",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -42,14 +42,14 @@
|
|
42
42
|
"escape-string-regexp": "^1.0.2",
|
43
43
|
"escope": "^3.2.0",
|
44
44
|
"espree": "^2.2.4",
|
45
|
-
"estraverse": "^4.1.
|
45
|
+
"estraverse": "^4.1.1",
|
46
46
|
"estraverse-fb": "^1.3.1",
|
47
47
|
"esutils": "^2.0.2",
|
48
48
|
"file-entry-cache": "^1.1.1",
|
49
49
|
"glob": "^5.0.14",
|
50
50
|
"globals": "^8.11.0",
|
51
51
|
"handlebars": "^4.0.0",
|
52
|
-
"inquirer": "^0.
|
52
|
+
"inquirer": "^0.11.0",
|
53
53
|
"is-my-json-valid": "^2.10.0",
|
54
54
|
"is-resolvable": "^1.0.0",
|
55
55
|
"js-yaml": "^3.2.5",
|
@@ -57,33 +57,33 @@
|
|
57
57
|
"lodash.clonedeep": "^3.0.1",
|
58
58
|
"lodash.merge": "^3.3.2",
|
59
59
|
"lodash.omit": "^3.1.0",
|
60
|
-
"minimatch": "^
|
60
|
+
"minimatch": "^3.0.0",
|
61
61
|
"mkdirp": "^0.5.0",
|
62
|
-
"object-assign": "^
|
63
|
-
"optionator": "^0.
|
62
|
+
"object-assign": "^4.0.1",
|
63
|
+
"optionator": "^0.6.0",
|
64
64
|
"path-is-absolute": "^1.0.0",
|
65
65
|
"path-is-inside": "^1.0.1",
|
66
|
-
"shelljs": "^0.3
|
66
|
+
"shelljs": "^0.5.3",
|
67
67
|
"strip-json-comments": "~1.0.1",
|
68
68
|
"text-table": "~0.2.0",
|
69
|
-
"to-double-quotes": "^
|
70
|
-
"to-single-quotes": "^
|
71
|
-
"user-home": "^
|
69
|
+
"to-double-quotes": "^2.0.0",
|
70
|
+
"to-single-quotes": "^2.0.0",
|
71
|
+
"user-home": "^2.0.0",
|
72
72
|
"xml-escape": "~1.0.0"
|
73
73
|
},
|
74
74
|
"devDependencies": {
|
75
75
|
"beefy": "^1.0.0",
|
76
76
|
"brfs": "0.0.9",
|
77
|
-
"browserify": "^
|
78
|
-
"chai": "^
|
77
|
+
"browserify": "^12.0.1",
|
78
|
+
"chai": "^3.4.0",
|
79
79
|
"cheerio": "^0.19.0",
|
80
|
-
"coveralls": "2.11.
|
80
|
+
"coveralls": "2.11.4",
|
81
81
|
"dateformat": "^1.0.8",
|
82
82
|
"ejs": "^2.3.3",
|
83
83
|
"esprima": "^2.4.1",
|
84
|
-
"esprima-fb": "^
|
85
|
-
"gh-got": "^
|
86
|
-
"istanbul": "^0.
|
84
|
+
"esprima-fb": "^15001.1001.0-dev-harmony-fb",
|
85
|
+
"gh-got": "^2.2.0",
|
86
|
+
"istanbul": "^0.4.0",
|
87
87
|
"jsdoc": "^3.3.0-beta1",
|
88
88
|
"jsonlint": "^1.6.2",
|
89
89
|
"leche": "^2.1.1",
|
@@ -91,14 +91,14 @@
|
|
91
91
|
"load-perf": "^0.2.0",
|
92
92
|
"markdownlint": "^0.0.8",
|
93
93
|
"mocha": "^2.1.0",
|
94
|
-
"mocha-phantomjs": "
|
95
|
-
"npm-license": "^0.
|
96
|
-
"phantomjs": "1.9.
|
94
|
+
"mocha-phantomjs": "4.0.1",
|
95
|
+
"npm-license": "^0.3.1",
|
96
|
+
"phantomjs": "1.9.18",
|
97
97
|
"proxyquire": "^1.0.0",
|
98
98
|
"rewire": "^2.3.4",
|
99
|
-
"semver": "^
|
99
|
+
"semver": "^5.0.3",
|
100
100
|
"shelljs-nodecli": "~0.1.0",
|
101
|
-
"sinon": "1.
|
101
|
+
"sinon": "1.17.2",
|
102
102
|
"through": "^2.3.6"
|
103
103
|
},
|
104
104
|
"keywords": [
|