eslint 1.7.1 → 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.
Files changed (38) hide show
  1. package/README.md +1 -0
  2. package/conf/eslint.json +3 -0
  3. package/lib/cli-engine.js +74 -74
  4. package/lib/cli.js +12 -10
  5. package/lib/eslint.js +15 -26
  6. package/lib/logging.js +25 -0
  7. package/lib/options.js +7 -2
  8. package/lib/rules/array-bracket-spacing.js +2 -2
  9. package/lib/rules/arrow-body-style.js +71 -0
  10. package/lib/rules/comma-dangle.js +26 -10
  11. package/lib/rules/comma-spacing.js +72 -36
  12. package/lib/rules/eol-last.js +10 -4
  13. package/lib/rules/indent.js +8 -7
  14. package/lib/rules/key-spacing.js +13 -25
  15. package/lib/rules/linebreak-style.js +45 -10
  16. package/lib/rules/max-nested-callbacks.js +1 -1
  17. package/lib/rules/no-arrow-condition.js +88 -0
  18. package/lib/rules/no-case-declarations.js +47 -0
  19. package/lib/rules/no-extend-native.js +3 -3
  20. package/lib/rules/no-magic-numbers.js +22 -5
  21. package/lib/rules/no-mixed-spaces-and-tabs.js +23 -19
  22. package/lib/rules/no-multiple-empty-lines.js +39 -13
  23. package/lib/rules/no-plusplus.js +22 -1
  24. package/lib/rules/no-shadow.js +22 -4
  25. package/lib/rules/no-use-before-define.js +1 -1
  26. package/lib/rules/no-warning-comments.js +1 -1
  27. package/lib/rules/radix.js +36 -6
  28. package/lib/rules/space-in-parens.js +148 -199
  29. package/lib/rules/spaced-comment.js +3 -3
  30. package/lib/rules/valid-jsdoc.js +36 -19
  31. package/lib/rules.js +13 -9
  32. package/lib/testers/rule-tester.js +62 -7
  33. package/lib/util/estraverse.js +54 -0
  34. package/lib/util/glob-util.js +149 -0
  35. package/lib/util/source-code-fixer.js +1 -1
  36. package/lib/util/source-code.js +11 -1
  37. package/lib/util.js +15 -9
  38. package/package.json +21 -21
@@ -78,6 +78,34 @@ var RuleTesterParameters = [
78
78
 
79
79
  var validateSchema = validate(metaSchema, { verbose: true });
80
80
 
81
+ var hasOwnProperty = Function.call.bind(Object.hasOwnProperty);
82
+
83
+ /**
84
+ * Clones a given value deeply.
85
+ * Note: This ignores `parent` property.
86
+ *
87
+ * @param {any} x - A value to clone.
88
+ * @returns {any} A cloned value.
89
+ */
90
+ function cloneDeeplyExcludesParent(x) {
91
+ if (typeof x === "object" && x !== null) {
92
+ if (Array.isArray(x)) {
93
+ return x.map(cloneDeeplyExcludesParent);
94
+ }
95
+
96
+ var retv = {};
97
+ for (var key in x) {
98
+ if (key !== "parent" && hasOwnProperty(x, key)) {
99
+ retv[key] = cloneDeeplyExcludesParent(x[key]);
100
+ }
101
+ }
102
+
103
+ return retv;
104
+ }
105
+
106
+ return x;
107
+ }
108
+
81
109
  //------------------------------------------------------------------------------
82
110
  // Public Interface
83
111
  //------------------------------------------------------------------------------
@@ -178,7 +206,7 @@ RuleTester.prototype = {
178
206
  */
179
207
  function runRuleForItem(ruleName, item) {
180
208
  var config = clone(testerConfig),
181
- code, filename, schema;
209
+ code, filename, schema, beforeAST, afterAST;
182
210
 
183
211
  if (typeof item === "string") {
184
212
  code = item;
@@ -223,7 +251,21 @@ RuleTester.prototype = {
223
251
 
224
252
  validator.validate(config, "rule-tester");
225
253
 
226
- return eslint.verify(code, config, filename);
254
+ // To cache AST.
255
+ eslint.reset();
256
+ eslint.on("Program", function(node) {
257
+ beforeAST = cloneDeeplyExcludesParent(node);
258
+
259
+ eslint.on("Program:exit", function(node) {
260
+ afterAST = cloneDeeplyExcludesParent(node);
261
+ });
262
+ });
263
+
264
+ return {
265
+ messages: eslint.verify(code, config, filename, true),
266
+ beforeAST: beforeAST,
267
+ afterAST: afterAST
268
+ };
227
269
  }
228
270
 
229
271
  /**
@@ -235,10 +277,17 @@ RuleTester.prototype = {
235
277
  * @private
236
278
  */
237
279
  function testValidTemplate(ruleName, item) {
238
- var messages = runRuleForItem(ruleName, item);
280
+ var result = runRuleForItem(ruleName, item);
281
+ var messages = result.messages;
239
282
 
240
283
  assert.equal(messages.length, 0, util.format("Should have no errors but had %d: %s",
241
284
  messages.length, util.inspect(messages)));
285
+
286
+ assert.deepEqual(
287
+ result.beforeAST,
288
+ result.afterAST,
289
+ "Rule should not modify AST."
290
+ );
242
291
  }
243
292
 
244
293
  /**
@@ -250,7 +299,8 @@ RuleTester.prototype = {
250
299
  * @private
251
300
  */
252
301
  function testInvalidTemplate(ruleName, item) {
253
- var messages = runRuleForItem(ruleName, item);
302
+ var result = runRuleForItem(ruleName, item);
303
+ var messages = result.messages;
254
304
 
255
305
  if (typeof item.errors === "number") {
256
306
  assert.equal(messages.length, item.errors, util.format("Should have %d errors but had %d: %s",
@@ -261,11 +311,10 @@ RuleTester.prototype = {
261
311
  item.errors.length, messages.length, util.inspect(messages)));
262
312
 
263
313
  if (item.hasOwnProperty("output")) {
264
- var result = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
265
- assert.equal(result.output, item.output, "Output is incorrect.");
314
+ var fixResult = SourceCodeFixer.applyFixes(eslint.getSourceCode(), messages);
315
+ assert.equal(fixResult.output, item.output, "Output is incorrect.");
266
316
  }
267
317
 
268
-
269
318
  for (var i = 0, l = item.errors.length; i < l; i++) {
270
319
  assert.ok(!("fatal" in messages[i]), "A fatal parsing error occurred: " + messages[i].message);
271
320
  assert.equal(messages[i].ruleId, ruleName, "Error rule name should be the same as the name of the rule being tested");
@@ -299,6 +348,12 @@ RuleTester.prototype = {
299
348
  }
300
349
  }
301
350
  }
351
+
352
+ assert.deepEqual(
353
+ result.beforeAST,
354
+ result.afterAST,
355
+ "Rule should not modify AST."
356
+ );
302
357
  }
303
358
 
304
359
  // this creates a mocha test suite and pipes all supplied info
@@ -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) {
@@ -211,6 +215,12 @@ SourceCode.prototype = {
211
215
  }
212
216
  break;
213
217
 
218
+ case "ClassDeclaration":
219
+ return findJSDocComment(node.leadingComments, line);
220
+
221
+ case "ClassExpression":
222
+ return findJSDocComment(parent.parent.leadingComments, line);
223
+
214
224
  case "ArrowFunctionExpression":
215
225
  case "FunctionExpression":
216
226
 
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.7.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.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": [