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 CHANGED
@@ -7,6 +7,7 @@
7
7
  "no-arrow-condition": 0,
8
8
  "no-bitwise": 0,
9
9
  "no-caller": 0,
10
+ "no-case-declarations": 0,
10
11
  "no-catch-shadow": 0,
11
12
  "no-class-assign": 0,
12
13
  "no-cond-assign": 2,
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
- var extensions = this.options.extensions.map(function(ext) {
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
- globOptions = {
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 shouldIgnore = ignoredPaths.contains(filename);
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
- patterns.forEach(function(pattern) {
694
- if (shell.test("-f", pattern) && !ignoredPaths.contains(pattern)) {
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-fb"),
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
- linebreaks = context.getSource().match(/\r\n|\r|\n|\u2028|\u2029/g),
24
- lineOfError = -1;
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
- if (linebreaks !== null) {
27
- lineOfError = linebreaks.indexOf(expectedLF ? "\r\n" : "\n");
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
- if (lineOfError !== -1) {
31
- context.report(node, {
32
- line: lineOfError + 1,
33
- column: context.getSourceLines()[lineOfError].length
34
- }, expectedLF ? EXPECTED_LF_MSG : EXPECTED_CRLF_MSG);
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
- "Multiple blank lines not allowed.");
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
 
@@ -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
 
@@ -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 < 2) {
29
- context.report(node, "Missing radix parameter.");
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 ((radix.type === "Literal" && typeof radix.value !== "number") ||
36
- (radix.type === "Identifier" && radix.name === "undefined")
56
+ if (radix &&
57
+ ((radix.type === "Literal" && typeof radix.value !== "number") ||
58
+ (radix.type === "Identifier" && radix.name === "undefined"))
37
59
  ) {
38
- context.report(node, "Invalid radix parameter.");
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 = node.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
- exports.import = function(pluginRules, pluginName) {
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
- exports.get = function(ruleId) {
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
- exports.testClear = function() {
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] <= lastFixPos) {
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 {
@@ -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
- exports.mergeConfigs = function deepmerge(target, src, combine, isRule) {
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
- exports.removePluginPrefix = function removePluginPrefix(pluginName) {
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
- exports.getNamespace = function getNamespace(pluginName) {
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
- exports.removeNameSpace = function removeNameSpace(pluginName) {
131
+ function removeNameSpace(pluginName) {
132
132
  return pluginName.replace(NAMESPACE_REGEX, "");
133
- };
133
+ }
134
134
 
135
- exports.PLUGIN_NAME_PREFIX = PLUGIN_NAME_PREFIX;
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.8.0",
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.0",
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.9.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": "^2.0.1",
60
+ "minimatch": "^3.0.0",
61
61
  "mkdirp": "^0.5.0",
62
- "object-assign": "^2.0.0",
63
- "optionator": "^0.5.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.0",
66
+ "shelljs": "^0.5.3",
67
67
  "strip-json-comments": "~1.0.1",
68
68
  "text-table": "~0.2.0",
69
- "to-double-quotes": "^1.0.1",
70
- "to-single-quotes": "^1.0.3",
71
- "user-home": "^1.0.0",
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": "^8.1.3",
78
- "chai": "^1.9.1",
77
+ "browserify": "^12.0.1",
78
+ "chai": "^3.4.0",
79
79
  "cheerio": "^0.19.0",
80
- "coveralls": "2.11.2",
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": "^10001.1.0-dev-harmony-fb",
85
- "gh-got": "^1.0.3",
86
- "istanbul": "^0.3.5",
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": "3.6.0",
95
- "npm-license": "^0.2.3",
96
- "phantomjs": "1.9.7-15",
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": "^4.1.0",
99
+ "semver": "^5.0.3",
100
100
  "shelljs-nodecli": "~0.1.0",
101
- "sinon": "1.14.1",
101
+ "sinon": "1.17.2",
102
102
  "through": "^2.3.6"
103
103
  },
104
104
  "keywords": [