eslint 3.16.0 → 3.18.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 (59) hide show
  1. package/CHANGELOG.md +73 -0
  2. package/conf/eslint-recommended.js +2 -0
  3. package/lib/ast-utils.js +3 -67
  4. package/lib/code-path-analysis/code-path-analyzer.js +2 -7
  5. package/lib/code-path-analysis/debug-helpers.js +17 -16
  6. package/lib/config/config-file.js +68 -38
  7. package/lib/eslint.js +5 -5
  8. package/lib/formatters/stylish.js +5 -4
  9. package/lib/ignored-paths.js +6 -0
  10. package/lib/internal-rules/internal-no-invalid-meta.js +2 -40
  11. package/lib/rules/array-callback-return.js +15 -5
  12. package/lib/rules/capitalized-comments.js +2 -1
  13. package/lib/rules/complexity.js +14 -8
  14. package/lib/rules/consistent-return.js +17 -10
  15. package/lib/rules/func-name-matching.js +18 -7
  16. package/lib/rules/func-names.js +20 -5
  17. package/lib/rules/keyword-spacing.js +19 -4
  18. package/lib/rules/line-comment-position.js +15 -5
  19. package/lib/rules/lines-around-comment.js +19 -0
  20. package/lib/rules/max-params.js +17 -4
  21. package/lib/rules/max-statements.js +11 -10
  22. package/lib/rules/no-compare-neg-zero.js +53 -0
  23. package/lib/rules/no-else-return.js +13 -1
  24. package/lib/rules/no-empty-function.js +9 -16
  25. package/lib/rules/no-extra-parens.js +64 -19
  26. package/lib/rules/no-extra-semi.js +13 -1
  27. package/lib/rules/no-global-assign.js +1 -1
  28. package/lib/rules/no-invalid-regexp.js +2 -1
  29. package/lib/rules/no-multiple-empty-lines.js +2 -4
  30. package/lib/rules/no-new-func.js +6 -8
  31. package/lib/rules/no-new.js +2 -6
  32. package/lib/rules/no-param-reassign.js +29 -6
  33. package/lib/rules/no-process-exit.js +2 -10
  34. package/lib/rules/no-restricted-properties.js +2 -0
  35. package/lib/rules/no-restricted-syntax.js +6 -22
  36. package/lib/rules/no-return-await.js +1 -1
  37. package/lib/rules/no-sync.js +8 -13
  38. package/lib/rules/no-unused-expressions.js +10 -1
  39. package/lib/rules/no-unused-vars.js +12 -12
  40. package/lib/rules/no-use-before-define.js +1 -1
  41. package/lib/rules/no-useless-escape.js +8 -2
  42. package/lib/rules/no-useless-return.js +13 -2
  43. package/lib/rules/nonblock-statement-body-position.js +114 -0
  44. package/lib/rules/object-shorthand.js +2 -1
  45. package/lib/rules/operator-assignment.js +1 -1
  46. package/lib/rules/padded-blocks.js +37 -28
  47. package/lib/rules/prefer-destructuring.js +1 -1
  48. package/lib/rules/semi.js +13 -1
  49. package/lib/rules/sort-vars.js +3 -5
  50. package/lib/rules/space-unary-ops.js +19 -1
  51. package/lib/rules/strict.js +8 -2
  52. package/lib/rules/yoda.js +2 -2
  53. package/lib/testers/rule-tester.js +44 -13
  54. package/lib/util/fix-tracker.js +121 -0
  55. package/lib/util/node-event-generator.js +274 -4
  56. package/lib/util/source-code-fixer.js +2 -2
  57. package/lib/util/source-code.js +99 -2
  58. package/lib/util/traverser.js +16 -25
  59. package/package.json +8 -8
package/CHANGELOG.md CHANGED
@@ -1,3 +1,76 @@
1
+ v3.18.0 - March 17, 2017
2
+
3
+ * 85f74ca Fix: broken code path of direct nested loops (fixes #8248) (#8274) (Toru Nagashima)
4
+ * a61c359 Fix: Ignore hidden folders when resolving globs (fixes #8259) (#8270) (Ian VanSchooten)
5
+ * 6f05546 Chore: convert StubModuleResolver in config tests to ES6 class (#8265) (Teddy Katz)
6
+ * 0c0fc31 Fix: false positive of no-extra-parens about spread and sequense (#8275) (Toru Nagashima)
7
+ * e104973 Docs: remove self-reference in no-restricted-syntax docs (#8277) (Vitor Balocco)
8
+ * 23eca51 Update: Add allowTaggedTemplates to no-unused-expressions (fixes #7632) (#8253) (Kevin Partington)
9
+ * f9ede3f Upgrade: doctrine to 2.0.0 (#8269) (alberto)
10
+ * 1b678a6 New: allow rules to listen for AST selectors (fixes #5407) (#7833) (Teddy Katz)
11
+ * 63ca0c5 Chore: use precalculated counts in stylish formatter (#8251) (alberto)
12
+ * 47c3171 Fix: typo in console.error (#8258) (Jan Peer Stöcklmair)
13
+ * e74ed6d Chore: convert Traverser to ES6 class (refs #7849) (#8232) (Teddy Katz)
14
+ * 13eead9 Fix: sort-vars crash on mixed destructuring declarations (#8245) (Teddy Katz)
15
+ * 133f489 Fix: func-name-matching crash on destructuring assignment to functions (#8247) (Teddy Katz)
16
+ * a34b9c4 Fix: func-name-matching crash on non-string literal computed keys (#8246) (Teddy Katz)
17
+ * 7276e6d Docs: remove unneeded semicolons in arrow-parens.md (#8249) (Dmitry Gershun)
18
+ * 8c40a25 concat-stream known to be vulnerable prior 1.5.2 (#8228) (Samuel)
19
+ * 149c055 Upgrade: mock-fs to v4.2.0 (fixes #8194) (#8243) (Teddy Katz)
20
+ * a83bff9 Build: remove unneeded json config in demo (fixes #8237) (#8242) (alberto)
21
+ * df12137 Docs: fix typos (#8235) (Gyandeep Singh)
22
+ * b5e9788 Chore: rename no-extra-parens methods (#8225) (Vitor Balocco)
23
+ * 7f8afe6 Update: no-extra-parens overlooked spread and superClass (fixes #8175) (#8209) (Toru Nagashima)
24
+ * ce6ff56 Docs: set recommended true for no-global-assign (fixes #8215) (#8218) (BinYi LIU)
25
+ * 5b5c236 Fix: wrong comment when module not found in config (fixes #8192) (#8196) (alberto)
26
+
27
+ v3.17.1 - March 6, 2017
28
+
29
+ * f8c8e6e Build: change mock-fs path without SSH (fixes #8207) (#8208) (Toru Nagashima)
30
+ * f713f11 Fix: nonblock-statement-body-position multiline error (fixes #8202) (#8203) (Teddy Katz)
31
+ * 41e3d9c Fix: `operator-assignment` with parenthesized expression (fixes #8190) (#8197) (alberto)
32
+ * 5e3bca7 Chore: add eslint-plugin-eslint-plugin (#8198) (Teddy Katz)
33
+ * 580da36 Chore: add missing `output` property to tests (#8195) (alberto)
34
+
35
+ v3.17.0 - March 3, 2017
36
+
37
+ * 4fdf6d7 Update: deprecate `applyDefaultPatterns` in `line-comment-position` (#8183) (alberto)
38
+ * 25e5817 Fix: Don't autofix `+ +a` to `++a` in space-unary-ops (#8176) (Alan Pierce)
39
+ * a6ce8f9 Build: Sort rules before dumping them to doc files (#8154) (Danny Andrews)
40
+ * 0af9057 Chore: Upgrade to a patched version of mock-fs (fixes #8177) (#8188) (Teddy Katz)
41
+ * bf4d8cf Update: ignore eslint comments in lines-arount-comment (fixes #4345) (#8155) (alberto)
42
+ * dad20ad New: add SourceCode#getLocFromIndex and #getIndexFromLoc (fixes #8073) (#8158) (Teddy Katz)
43
+ * 18a519f Update: let RuleTester cases assert that no autofix occurs (fixes #8157) (#8163) (Teddy Katz)
44
+ * a30eb8d Docs: improve documentation for RuleTester cases (#8162) (Teddy Katz)
45
+ * a78ec9f Chore: upgrade `coveralls` to ^2.11.16 (#8161) (alberto)
46
+ * d02bd11 Fix: padded-blocks autofix problems with comments (#8149) (alberto)
47
+ * 9994889 Docs: Add missing space to `create` in `no-use-before-define` (#8166) (Justin Anastos)
48
+ * 4d542ba Docs: Remove unneeded statement about autofix (#8164) (alberto)
49
+ * 20daea5 New: no-compare-neg-zero rule (#8091) (薛定谔的猫)
50
+ * 4d35a81 Fix: Add a utility to avoid autofix conflicts (fixes #7928, fixes #8026) (#8067) (Alan Pierce)
51
+ * 287e882 New: nonblock-statement-body-position rule (fixes #6067) (#8108) (Teddy Katz)
52
+ * 7f1f4e5 Chore: remove unneeded devDeps `linefix` and `gh-got` (#8160) (alberto)
53
+ * ca1694b Update: ignore negative ranges in fixes (#8133) (alberto)
54
+ * 163d751 Docs: `lines-around-comment` doesn't disallow empty lines (#8151) (alberto)
55
+ * 1c84922 Chore: upgrade eslint-plugin-node (#8156) (alberto)
56
+ * 1ee5c27 Fix: Make RuleTester handle empty-string cases gracefully (fixes #8142) (#8143) (Teddy Katz)
57
+ * 044bc10 Docs: Add details about "--fix" option for "sort-imports" rule (#8077) (Olivier Audard)
58
+ * 3fec54a Add option to ignore property in no-param-reassign (#8087) (Christian Bundy)
59
+ * 4e52cfc Fix: Improve keyword-spacing typescript support (fixes #8110) (#8111) (Reyad Attiyat)
60
+ * 7ff42e8 New: Allow regexes in RuleTester (fixes #7837) (#8115) (Daniel Lo Nigro)
61
+ * cbd7ded Build: display rules’ meta data in their docs (fixes #5774) (#8127) (Wilson Kurniawan)
62
+ * da8e8af Update: include function name in report message if possible (fixes #7260) (#8058) (Dieter Luypaert)
63
+ * 8f91e32 Fix: `ignoreRestSiblings` option didn't cover arguments (fixes #8119) (#8120) (Toru Nagashima)
64
+
65
+ v3.16.1 - February 22, 2017
66
+
67
+ * ff8a80c Fix: duplicated autofix output for inverted fix ranges (fixes #8116) (#8117) (Teddy Katz)
68
+ * a421897 Docs: fix typo in arrow-parens.md (#8132) (Will Chen)
69
+ * 22d7fbf Chore: fix invalid redeclared variables in tests (#8130) (Teddy Katz)
70
+ * 8d95598 Chore: fix output assertion typos in rule tests (#8129) (Teddy Katz)
71
+ * 9fa2559 Docs: Add missing quotes in key-spacing rule (#8121) (Glenn Reyes)
72
+ * f3a6ced Build: package.json update for eslint-config-eslint release (ESLint Jenkins)
73
+
1
74
  v3.16.0 - February 20, 2017
2
75
 
3
76
  * d89d0b4 Update: fix quotes false negative for string literals as template tags (#8107) (Teddy Katz)
@@ -84,6 +84,7 @@ module.exports = {
84
84
  "no-case-declarations": "error",
85
85
  "no-catch-shadow": "off",
86
86
  "no-class-assign": "error",
87
+ "no-compare-neg-zero": "off",
87
88
  "no-cond-assign": "error",
88
89
  "no-confusing-arrow": "off",
89
90
  "no-console": "error",
@@ -209,6 +210,7 @@ module.exports = {
209
210
  "no-warning-comments": "off",
210
211
  "no-whitespace-before-property": "off",
211
212
  "no-with": "off",
213
+ "nonblock-statement-body-position": "off",
212
214
  "object-curly-newline": "off",
213
215
  "object-curly-spacing": ["off", "never"],
214
216
  "object-property-newline": "off",
package/lib/ast-utils.js CHANGED
@@ -10,7 +10,6 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const esutils = require("esutils");
13
- const lodash = require("lodash");
14
13
 
15
14
  //------------------------------------------------------------------------------
16
15
  // Helpers
@@ -24,6 +23,8 @@ const bindOrCallOrApplyPattern = /^(?:bind|call|apply)$/;
24
23
  const breakableTypePattern = /^(?:(?:Do)?While|For(?:In|Of)?|Switch)Statement$/;
25
24
  const thisTagPattern = /^[\s*]*@this/m;
26
25
 
26
+
27
+ const COMMENTS_IGNORE_PATTERN = /^\s*(?:eslint|jshint\s+|jslint\s+|istanbul\s+|globals?\s+|exported\s+|jscs)/;
27
28
  const LINEBREAKS = new Set(["\r\n", "\r", "\n", "\u2028", "\u2029"]);
28
29
  const LINEBREAK_MATCHER = /\r\n|[\r\n\u2028\u2029]/;
29
30
 
@@ -403,45 +404,12 @@ function createGlobalLinebreakMatcher() {
403
404
  return new RegExp(LINEBREAK_MATCHER.source, "g");
404
405
  }
405
406
 
406
- const lineIndexCache = new WeakMap();
407
-
408
- /**
409
- * Gets the range index for the first character in each of the lines of `sourceCode`.
410
- * @param {SourceCode} sourceCode A sourceCode object
411
- * @returns {number[]} The indices of the first characters in the each of the lines of the code
412
- */
413
- function getLineIndices(sourceCode) {
414
-
415
- if (!lineIndexCache.has(sourceCode)) {
416
- const lineIndices = [0];
417
- const lineEndingPattern = createGlobalLinebreakMatcher();
418
- let match;
419
-
420
- /*
421
- * Previously, this function was implemented using a regex that
422
- * matched a sequence of non-linebreak characters followed by a
423
- * linebreak, then adding the lengths of the matches. However,
424
- * this caused a catastrophic backtracking issue when the end
425
- * of a file contained a large number of non-newline characters.
426
- * To avoid this, the current implementation just matches newlines
427
- * and uses match.index to get the correct line start indices.
428
- */
429
-
430
- while ((match = lineEndingPattern.exec(sourceCode.text))) {
431
- lineIndices.push(match.index + match[0].length);
432
- }
433
-
434
- // Store the sourceCode object in a WeakMap to avoid iterating over all of the lines every time a sourceCode object is passed in.
435
- lineIndexCache.set(sourceCode, lineIndices);
436
- }
437
- return lineIndexCache.get(sourceCode);
438
- }
439
-
440
407
  //------------------------------------------------------------------------------
441
408
  // Public Interface
442
409
  //------------------------------------------------------------------------------
443
410
 
444
411
  module.exports = {
412
+ COMMENTS_IGNORE_PATTERN,
445
413
  LINEBREAKS,
446
414
  LINEBREAK_MATCHER,
447
415
  STATEMENT_LIST_PARENTS,
@@ -1207,38 +1175,6 @@ module.exports = {
1207
1175
  };
1208
1176
  },
1209
1177
 
1210
- /*
1211
- * Converts a range index into a (line, column) pair.
1212
- * @param {SourceCode} sourceCode A SourceCode object
1213
- * @param {number} rangeIndex The range index of a character in a file
1214
- * @returns {Object} A {line, column} location object with a 0-indexed column
1215
- */
1216
- getLocationFromRangeIndex(sourceCode, rangeIndex) {
1217
- const lineIndices = getLineIndices(sourceCode);
1218
-
1219
- /*
1220
- * lineIndices is a sorted list of indices of the first character of each line.
1221
- * To figure out which line rangeIndex is on, determine the last index at which rangeIndex could
1222
- * be inserted into lineIndices to keep the list sorted.
1223
- */
1224
- const lineNumber = lodash.sortedLastIndex(lineIndices, rangeIndex);
1225
-
1226
- return { line: lineNumber, column: rangeIndex - lineIndices[lineNumber - 1] };
1227
-
1228
- },
1229
-
1230
- /**
1231
- * Converts a (line, column) pair into a range index.
1232
- * @param {SourceCode} sourceCode A SourceCode object
1233
- * @param {Object} loc A line/column location
1234
- * @param {number} loc.line The line number of the location (1-indexed)
1235
- * @param {number} loc.column The column number of the location (0-indexed)
1236
- * @returns {number} The range index of the location in the file.
1237
- */
1238
- getRangeIndexFromLocation(sourceCode, loc) {
1239
- return getLineIndices(sourceCode)[loc.line - 1] + loc.column;
1240
- },
1241
-
1242
1178
  /**
1243
1179
  * Gets the parenthesized text of a node. This is similar to sourceCode.getText(node), but it also includes any parentheses
1244
1180
  * surrounding the node.
@@ -512,13 +512,8 @@ function processCodePathToExit(analyzer, node) {
512
512
  break;
513
513
  }
514
514
 
515
- /*
516
- * Skip updating the current segment to avoid creating useless segments if
517
- * the node type is the same as the parent node type.
518
- */
519
- if (!dontForward && (!node.parent || node.type !== node.parent.type)) {
520
-
521
- // Emits onCodePathSegmentStart events if updated.
515
+ // Emits onCodePathSegmentStart events if updated.
516
+ if (!dontForward) {
522
517
  forwardCurrentToHead(analyzer, node);
523
518
  }
524
519
  debug.dumpState(node, state, true);
@@ -107,22 +107,23 @@ module.exports = {
107
107
  text += "style=\"rounded,dashed,filled\",fillcolor=\"#FF9800\",label=\"<<unreachable>>\\n";
108
108
  }
109
109
 
110
- if (segment.internal.nodes.length > 0) {
111
- text += segment.internal.nodes.map(node => {
112
- switch (node.type) {
113
- case "Identifier": return `${node.type} (${node.name})`;
114
- case "Literal": return `${node.type} (${node.value})`;
115
- default: return node.type;
116
- }
117
- }).join("\\n");
118
- } else if (segment.internal.exitNodes.length > 0) {
119
- text += segment.internal.exitNodes.map(node => {
120
- switch (node.type) {
121
- case "Identifier": return `${node.type}:exit (${node.name})`;
122
- case "Literal": return `${node.type}:exit (${node.value})`;
123
- default: return `${node.type}:exit`;
124
- }
125
- }).join("\\n");
110
+ if (segment.internal.nodes.length > 0 || segment.internal.exitNodes.length > 0) {
111
+ text += [].concat(
112
+ segment.internal.nodes.map(node => {
113
+ switch (node.type) {
114
+ case "Identifier": return `${node.type} (${node.name})`;
115
+ case "Literal": return `${node.type} (${node.value})`;
116
+ default: return node.type;
117
+ }
118
+ }),
119
+ segment.internal.exitNodes.map(node => {
120
+ switch (node.type) {
121
+ case "Identifier": return `${node.type}:exit (${node.name})`;
122
+ case "Literal": return `${node.type}:exit (${node.value})`;
123
+ default: return `${node.type}:exit`;
124
+ }
125
+ })
126
+ ).join("\\n");
126
127
  } else {
127
128
  text += "????";
128
129
  }
@@ -183,6 +183,22 @@ function loadPackageJSONConfigFile(filePath) {
183
183
  }
184
184
  }
185
185
 
186
+ /**
187
+ * Creates an error to notify about a missing config to extend from.
188
+ * @param {string} configName The name of the missing config.
189
+ * @returns {Error} The error object to throw
190
+ * @private
191
+ */
192
+ function configMissingError(configName) {
193
+ const error = new Error(`Failed to load config "${configName}" to extend from.`);
194
+
195
+ error.messageTemplate = "extend-config-missing";
196
+ error.messageData = {
197
+ configName
198
+ };
199
+ return error;
200
+ }
201
+
186
202
  /**
187
203
  * Loads a configuration file regardless of the source. Inspects the file path
188
204
  * to determine the correctly way to load the config file.
@@ -199,6 +215,9 @@ function loadConfigFile(file) {
199
215
  config = loadJSConfigFile(filePath);
200
216
  if (file.configName) {
201
217
  config = config.configs[file.configName];
218
+ if (!config) {
219
+ throw configMissingError(file.configFullName);
220
+ }
202
221
  }
203
222
  break;
204
223
 
@@ -340,6 +359,33 @@ function getLookupPath(configFilePath) {
340
359
  return path.join(basedir, "node_modules");
341
360
  }
342
361
 
362
+ /**
363
+ * Resolves a eslint core config path
364
+ * @param {string} name The eslint config name.
365
+ * @returns {string} The resolved path of the config.
366
+ * @private
367
+ */
368
+ function getEslintCoreConfigPath(name) {
369
+ if (name === "eslint:recommended") {
370
+
371
+ /*
372
+ * Add an explicit substitution for eslint:recommended to
373
+ * conf/eslint-recommended.js.
374
+ */
375
+ return path.resolve(__dirname, "../../conf/eslint-recommended.js");
376
+ }
377
+
378
+ if (name === "eslint:all") {
379
+
380
+ /*
381
+ * Add an explicit substitution for eslint:all to conf/eslint-all.js
382
+ */
383
+ return path.resolve(__dirname, "../../conf/eslint-all.js");
384
+ }
385
+
386
+ throw configMissingError(name);
387
+ }
388
+
343
389
  /**
344
390
  * Applies values from the "extends" field in a configuration file.
345
391
  * @param {Object} config The configuration information.
@@ -360,43 +406,23 @@ function applyExtends(config, filePath, relativeTo) {
360
406
 
361
407
  // Make the last element in an array take the highest precedence
362
408
  config = configExtends.reduceRight((previousValue, parentPath) => {
363
-
364
- if (parentPath === "eslint:recommended") {
365
-
366
- /*
367
- * Add an explicit substitution for eslint:recommended to
368
- * conf/eslint-recommended.js.
369
- */
370
- parentPath = path.resolve(__dirname, "../../conf/eslint-recommended.js");
371
- } else if (parentPath === "eslint:all") {
372
-
373
- /*
374
- * Add an explicit substitution for eslint:all to conf/eslint-all.js
375
- */
376
- parentPath = path.resolve(__dirname, "../../conf/eslint-all.js");
377
- } else if (isFilePath(parentPath)) {
378
-
379
- /*
380
- * If the `extends` path is relative, use the directory of the current configuration
381
- * file as the reference point. Otherwise, use as-is.
382
- */
383
- parentPath = (!path.isAbsolute(parentPath)
384
- ? path.join(relativeTo || path.dirname(filePath), parentPath)
385
- : parentPath
386
- );
387
- }
388
-
389
409
  try {
410
+ if (parentPath.startsWith("eslint:")) {
411
+ parentPath = getEslintCoreConfigPath(parentPath);
412
+ } else if (isFilePath(parentPath)) {
413
+
414
+ /*
415
+ * If the `extends` path is relative, use the directory of the current configuration
416
+ * file as the reference point. Otherwise, use as-is.
417
+ */
418
+ parentPath = (path.isAbsolute(parentPath)
419
+ ? parentPath
420
+ : path.join(relativeTo || path.dirname(filePath), parentPath)
421
+ );
422
+ }
390
423
  debug(`Loading ${parentPath}`);
391
424
  return ConfigOps.merge(load(parentPath, false, relativeTo), previousValue);
392
425
  } catch (e) {
393
- if (parentPath.indexOf("plugin:") === 0 || parentPath.indexOf("eslint:") === 0) {
394
- e.message = `Failed to load config "${parentPath}" to extend from.`;
395
- e.messageTemplate = "extend-config-missing";
396
- e.messageData = {
397
- configName: parentPath
398
- };
399
- }
400
426
 
401
427
  /*
402
428
  * If the file referenced by `extends` failed to load, add the path
@@ -462,7 +488,10 @@ function normalizePackageName(name, prefix) {
462
488
  * or package name.
463
489
  * @param {string} filePath The filepath to resolve.
464
490
  * @param {string} [relativeTo] The path to resolve relative to.
465
- * @returns {Object} A path that can be used directly to load the configuration.
491
+ * @returns {Object} An object containing 3 properties:
492
+ * - 'filePath' (required) the resolved path that can be used directly to load the configuration.
493
+ * - 'configName' the name of the configuration inside the plugin.
494
+ * - 'configFullName' the name of the configuration as used in the eslint config (e.g. 'plugin:node/recommended').
466
495
  * @private
467
496
  */
468
497
  function resolve(filePath, relativeTo) {
@@ -471,14 +500,15 @@ function resolve(filePath, relativeTo) {
471
500
  }
472
501
  let normalizedPackageName;
473
502
 
474
- if (filePath.indexOf("plugin:") === 0) {
475
- const packagePath = filePath.substr(7, filePath.lastIndexOf("/") - 7);
503
+ if (filePath.startsWith("plugin:")) {
504
+ const configFullName = filePath;
505
+ const pluginName = filePath.substr(7, filePath.lastIndexOf("/") - 7);
476
506
  const configName = filePath.substr(filePath.lastIndexOf("/") + 1, filePath.length - filePath.lastIndexOf("/") - 1);
477
507
 
478
- normalizedPackageName = normalizePackageName(packagePath, "eslint-plugin");
508
+ normalizedPackageName = normalizePackageName(pluginName, "eslint-plugin");
479
509
  debug(`Attempting to resolve ${normalizedPackageName}`);
480
510
  filePath = resolver.resolve(normalizedPackageName, getLookupPath(relativeTo));
481
- return { filePath, configName };
511
+ return { filePath, configName, configFullName };
482
512
  }
483
513
  normalizedPackageName = normalizePackageName(filePath, "eslint-config");
484
514
  debug(`Attempting to resolve ${normalizedPackageName}`);
package/lib/eslint.js CHANGED
@@ -867,11 +867,11 @@ module.exports = (function() {
867
867
  const rule = ruleCreator.create ? ruleCreator.create(ruleContext)
868
868
  : ruleCreator(ruleContext);
869
869
 
870
- // add all the node types as listeners
871
- Object.keys(rule).forEach(nodeType => {
872
- api.on(nodeType, timing.enabled
873
- ? timing.time(key, rule[nodeType])
874
- : rule[nodeType]
870
+ // add all the selectors from the rule as listeners
871
+ Object.keys(rule).forEach(selector => {
872
+ api.on(selector, timing.enabled
873
+ ? timing.time(key, rule[selector])
874
+ : rule[selector]
875
875
  );
876
876
  });
877
877
  } catch (ex) {
@@ -28,7 +28,6 @@ function pluralize(word, count) {
28
28
  module.exports = function(results) {
29
29
 
30
30
  let output = "\n",
31
- total = 0,
32
31
  errors = 0,
33
32
  warnings = 0,
34
33
  summaryColor = "yellow";
@@ -40,7 +39,9 @@ module.exports = function(results) {
40
39
  return;
41
40
  }
42
41
 
43
- total += messages.length;
42
+ errors += result.errorCount;
43
+ warnings += result.warningCount;
44
+
44
45
  output += `${chalk.underline(result.filePath)}\n`;
45
46
 
46
47
  output += `${table(
@@ -50,10 +51,8 @@ module.exports = function(results) {
50
51
  if (message.fatal || message.severity === 2) {
51
52
  messageType = chalk.red("error");
52
53
  summaryColor = "red";
53
- errors++;
54
54
  } else {
55
55
  messageType = chalk.yellow("warning");
56
- warnings++;
57
56
  }
58
57
 
59
58
  return [
@@ -74,6 +73,8 @@ module.exports = function(results) {
74
73
  ).split("\n").map(el => el.replace(/(\d+)\s+(\d+)/, (m, p1, p2) => chalk.dim(`${p1}:${p2}`))).join("\n")}\n\n`;
75
74
  });
76
75
 
76
+ const total = errors + warnings;
77
+
77
78
  if (total > 0) {
78
79
  output += chalk[summaryColor].bold([
79
80
  "\u2716 ", total, pluralize(" problem", total),
@@ -201,6 +201,12 @@ class IgnoredPaths {
201
201
 
202
202
  const ig = ignore().add(DEFAULT_IGNORE_DIRS);
203
203
 
204
+ if (this.options.dotfiles !== true) {
205
+
206
+ // Ignore hidden folders. (This cannot be ".*", or else it's not possible to unignore hidden files)
207
+ ig.add([".*/*", "!../"]);
208
+ }
209
+
204
210
  if (this.options.ignore) {
205
211
  ig.add(this.ig.custom);
206
212
  }
@@ -94,16 +94,6 @@ function hasMetaSchema(metaPropertyNode) {
94
94
  return getPropertyFromObject("schema", metaPropertyNode.value);
95
95
  }
96
96
 
97
- /**
98
- * Whether this `meta` ObjectExpression has a `fixable` property defined or not.
99
- *
100
- * @param {ASTNode} metaPropertyNode The `meta` ObjectExpression for this rule.
101
- * @returns {boolean} `true` if a `fixable` property exists.
102
- */
103
- function hasMetaFixable(metaPropertyNode) {
104
- return getPropertyFromObject("fixable", metaPropertyNode.value);
105
- }
106
-
107
97
  /**
108
98
  * Checks the validity of the meta definition of this rule and reports any errors found.
109
99
  *
@@ -112,7 +102,7 @@ function hasMetaFixable(metaPropertyNode) {
112
102
  * @param {boolean} ruleIsFixable whether the rule is fixable or not.
113
103
  * @returns {void}
114
104
  */
115
- function checkMetaValidity(context, exportsNode, ruleIsFixable) {
105
+ function checkMetaValidity(context, exportsNode) {
116
106
  const metaProperty = getMetaPropertyFromExportsNode(exportsNode);
117
107
 
118
108
  if (!metaProperty) {
@@ -142,11 +132,6 @@ function checkMetaValidity(context, exportsNode, ruleIsFixable) {
142
132
 
143
133
  if (!hasMetaSchema(metaProperty)) {
144
134
  context.report(metaProperty, "Rule is missing a meta.schema property.");
145
- return;
146
- }
147
-
148
- if (ruleIsFixable && !hasMetaFixable(metaProperty)) {
149
- context.report(metaProperty, "Rule is fixable, but is missing a meta.fixable property.");
150
135
  }
151
136
  }
152
137
 
@@ -177,7 +162,6 @@ module.exports = {
177
162
 
178
163
  create(context) {
179
164
  let exportsNode;
180
- let ruleIsFixable = false;
181
165
 
182
166
  return {
183
167
  AssignmentExpression(node) {
@@ -191,35 +175,13 @@ module.exports = {
191
175
  }
192
176
  },
193
177
 
194
- CallExpression(node) {
195
-
196
- // If the rule has a call for `context.report` and a property `fix`
197
- // is being passed in, then we consider that the rule is fixable.
198
- //
199
- // Note that we only look for context.report() calls in the new
200
- // style (with single MessageDescriptor argument), because only
201
- // calls in the new style can specify a fix.
202
- if (node.callee.type === "MemberExpression" &&
203
- node.callee.object.type === "Identifier" &&
204
- node.callee.object.name === "context" &&
205
- node.callee.property.type === "Identifier" &&
206
- node.callee.property.name === "report" &&
207
- node.arguments.length === 1 &&
208
- node.arguments[0].type === "ObjectExpression") {
209
-
210
- if (getPropertyFromObject("fix", node.arguments[0])) {
211
- ruleIsFixable = true;
212
- }
213
- }
214
- },
215
-
216
178
  "Program:exit"() {
217
179
  if (!isCorrectExportsFormat(exportsNode)) {
218
180
  context.report({ node: exportsNode, message: "Rule does not export an Object. Make sure the rule follows the new rule format." });
219
181
  return;
220
182
  }
221
183
 
222
- checkMetaValidity(context, exportsNode, ruleIsFixable);
184
+ checkMetaValidity(context, exportsNode);
223
185
  }
224
186
  };
225
187
  }
@@ -9,6 +9,8 @@
9
9
  // Requirements
10
10
  //------------------------------------------------------------------------------
11
11
 
12
+ const lodash = require("lodash");
13
+
12
14
  const astUtils = require("../ast-utils");
13
15
 
14
16
  //------------------------------------------------------------------------------
@@ -147,7 +149,8 @@ module.exports = {
147
149
  upper: null,
148
150
  codePath: null,
149
151
  hasReturn: false,
150
- shouldCheck: false
152
+ shouldCheck: false,
153
+ node: null
151
154
  };
152
155
 
153
156
  /**
@@ -168,8 +171,11 @@ module.exports = {
168
171
  node,
169
172
  loc: getLocation(node, context.getSourceCode()).loc.start,
170
173
  message: funcInfo.hasReturn
171
- ? "Expected to return a value at the end of this function."
172
- : "Expected to return a value in this function."
174
+ ? "Expected to return a value at the end of {{name}}."
175
+ : "Expected to return a value in {{name}}.",
176
+ data: {
177
+ name: astUtils.getFunctionNameWithKind(funcInfo.node)
178
+ }
173
179
  });
174
180
  }
175
181
  }
@@ -187,7 +193,8 @@ module.exports = {
187
193
  node.body.type === "BlockStatement" &&
188
194
  isCallbackOfArrayMethod(node) &&
189
195
  !node.async &&
190
- !node.generator
196
+ !node.generator,
197
+ node
191
198
  };
192
199
  },
193
200
 
@@ -204,7 +211,10 @@ module.exports = {
204
211
  if (!node.argument) {
205
212
  context.report({
206
213
  node,
207
- message: "Expected a return value."
214
+ message: "{{name}} expected a return value.",
215
+ data: {
216
+ name: lodash.upperFirst(astUtils.getFunctionNameWithKind(funcInfo.node))
217
+ }
208
218
  });
209
219
  }
210
220
  }
@@ -9,6 +9,7 @@
9
9
  //------------------------------------------------------------------------------
10
10
 
11
11
  const LETTER_PATTERN = require("../util/patterns/letters");
12
+ const astUtils = require("../ast-utils");
12
13
 
13
14
  //------------------------------------------------------------------------------
14
15
  // Helpers
@@ -16,7 +17,7 @@ const LETTER_PATTERN = require("../util/patterns/letters");
16
17
 
17
18
  const ALWAYS_MESSAGE = "Comments should not begin with a lowercase character",
18
19
  NEVER_MESSAGE = "Comments should not begin with an uppercase character",
19
- DEFAULT_IGNORE_PATTERN = /^\s*(?:eslint|istanbul|jscs|jshint|globals?|exported)\b/,
20
+ DEFAULT_IGNORE_PATTERN = astUtils.COMMENTS_IGNORE_PATTERN,
20
21
  WHITESPACE = /\s/g,
21
22
  MAYBE_URL = /^\s*[^:/?#\s]+:\/\/[^?#]/, // TODO: Combine w/ max-len pattern?
22
23
  DEFAULTS = {