eslint 4.15.0 → 4.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/CHANGELOG.md +56 -0
  2. package/lib/config/config-validator.js +9 -2
  3. package/lib/linter.js +38 -19
  4. package/lib/options.js +7 -7
  5. package/lib/report-translator.js +28 -37
  6. package/lib/rules/accessor-pairs.js +7 -3
  7. package/lib/rules/array-bracket-newline.js +11 -5
  8. package/lib/rules/array-bracket-spacing.js +11 -5
  9. package/lib/rules/array-callback-return.js +11 -5
  10. package/lib/rules/array-element-newline.js +8 -3
  11. package/lib/rules/arrow-body-style.js +16 -8
  12. package/lib/rules/arrow-parens.js +13 -9
  13. package/lib/rules/arrow-spacing.js +13 -5
  14. package/lib/rules/block-scoped-var.js +6 -2
  15. package/lib/rules/block-spacing.js +13 -6
  16. package/lib/rules/brace-style.js +16 -14
  17. package/lib/rules/callback-return.js +6 -2
  18. package/lib/rules/camelcase.js +6 -2
  19. package/lib/rules/capitalized-comments.js +11 -8
  20. package/lib/rules/class-methods-use-this.js +7 -3
  21. package/lib/rules/comma-dangle.js +7 -4
  22. package/lib/rules/comma-spacing.js +13 -10
  23. package/lib/rules/comma-style.js +16 -5
  24. package/lib/rules/complexity.js +6 -2
  25. package/lib/rules/computed-property-spacing.js +13 -5
  26. package/lib/rules/consistent-return.js +12 -7
  27. package/lib/rules/consistent-this.js +9 -4
  28. package/lib/rules/constructor-super.js +17 -8
  29. package/lib/rules/curly.js +59 -80
  30. package/lib/rules/default-case.js +6 -2
  31. package/lib/rules/dot-location.js +8 -3
  32. package/lib/rules/dot-notation.js +10 -5
  33. package/lib/rules/eol-last.js +7 -3
  34. package/lib/rules/eqeqeq.js +6 -2
  35. package/lib/rules/guard-for-in.js +35 -7
  36. package/lib/rules/indent.js +4 -4
  37. package/lib/rules/key-spacing.js +3 -2
  38. package/lib/rules/keyword-spacing.js +6 -1
  39. package/lib/rules/no-alert.js +19 -18
  40. package/lib/rules/no-array-constructor.js +6 -2
  41. package/lib/rules/no-await-in-loop.js +75 -57
  42. package/lib/rules/no-bitwise.js +6 -2
  43. package/lib/rules/no-buffer-constructor.js +6 -3
  44. package/lib/rules/no-caller.js +6 -2
  45. package/lib/rules/no-case-declarations.js +6 -2
  46. package/lib/rules/no-catch-shadow.js +6 -2
  47. package/lib/rules/no-class-assign.js +6 -2
  48. package/lib/rules/no-compare-neg-zero.js +5 -2
  49. package/lib/rules/no-cond-assign.js +10 -4
  50. package/lib/rules/no-confusing-arrow.js +6 -2
  51. package/lib/rules/no-console.js +6 -2
  52. package/lib/rules/no-const-assign.js +6 -2
  53. package/lib/rules/no-constant-condition.js +6 -3
  54. package/lib/rules/no-continue.js +6 -2
  55. package/lib/rules/no-control-regex.js +7 -3
  56. package/lib/rules/no-debugger.js +5 -2
  57. package/lib/rules/no-delete-var.js +6 -2
  58. package/lib/rules/no-div-regex.js +6 -2
  59. package/lib/rules/no-dupe-args.js +6 -2
  60. package/lib/rules/no-dupe-class-members.js +6 -2
  61. package/lib/rules/no-dupe-keys.js +6 -2
  62. package/lib/rules/no-duplicate-case.js +6 -2
  63. package/lib/rules/no-else-return.js +7 -2
  64. package/lib/rules/no-empty-character-class.js +6 -2
  65. package/lib/rules/no-empty-function.js +6 -2
  66. package/lib/rules/no-empty-pattern.js +7 -3
  67. package/lib/rules/no-empty.js +7 -3
  68. package/lib/rules/no-eq-null.js +6 -2
  69. package/lib/rules/no-eval.js +6 -2
  70. package/lib/rules/no-ex-assign.js +6 -2
  71. package/lib/rules/no-extend-native.js +6 -2
  72. package/lib/rules/no-extra-bind.js +6 -2
  73. package/lib/rules/no-extra-boolean-cast.js +8 -3
  74. package/lib/rules/no-extra-label.js +6 -2
  75. package/lib/rules/no-extra-parens.js +5 -1
  76. package/lib/rules/no-extra-semi.js +6 -2
  77. package/lib/rules/no-self-assign.js +3 -1
  78. package/lib/rules/no-unused-vars.js +1 -1
  79. package/lib/rules/object-curly-newline.js +67 -19
  80. package/lib/rules/object-property-newline.js +8 -2
  81. package/lib/rules/object-shorthand.js +9 -7
  82. package/lib/rules/padding-line-between-statements.js +6 -0
  83. package/lib/rules/prefer-destructuring.js +4 -2
  84. package/lib/rules/require-await.js +5 -0
  85. package/lib/rules/rest-spread-spacing.js +6 -0
  86. package/lib/rules/space-unary-ops.js +1 -10
  87. package/lib/rules/valid-jsdoc.js +89 -28
  88. package/lib/util/glob-util.js +17 -4
  89. package/lib/util/npm-util.js +1 -1
  90. package/package.json +2 -2
@@ -57,7 +57,9 @@ module.exports = {
57
57
  },
58
58
  additionalProperties: false
59
59
  }
60
- ]
60
+ ],
61
+
62
+ fixable: "code"
61
63
  },
62
64
 
63
65
  create(context) {
@@ -145,23 +147,35 @@ module.exports = {
145
147
  /**
146
148
  * Extract the current and expected type based on the input type object
147
149
  * @param {Object} type JSDoc tag
148
- * @returns {Object} current and expected type object
150
+ * @returns {{currentType: Doctrine.Type, expectedTypeName: string}} The current type annotation and
151
+ * the expected name of the annotation
149
152
  * @private
150
153
  */
151
154
  function getCurrentExpectedTypes(type) {
152
155
  let currentType;
153
156
 
154
157
  if (type.name) {
155
- currentType = type.name;
158
+ currentType = type;
156
159
  } else if (type.expression) {
157
- currentType = type.expression.name;
160
+ currentType = type.expression;
158
161
  }
159
162
 
160
- const expectedType = currentType && preferType[currentType];
161
-
162
163
  return {
163
164
  currentType,
164
- expectedType
165
+ expectedTypeName: currentType && preferType[currentType.name]
166
+ };
167
+ }
168
+
169
+ /**
170
+ * Gets the location of a JSDoc node in a file
171
+ * @param {Token} jsdocComment The comment that this node is parsed from
172
+ * @param {{range: number[]}} parsedJsdocNode A tag or other node which was parsed from this comment
173
+ * @returns {{start: SourceLocation, end: SourceLocation}} The 0-based source location for the tag
174
+ */
175
+ function getAbsoluteRange(jsdocComment, parsedJsdocNode) {
176
+ return {
177
+ start: sourceCode.getLocFromIndex(jsdocComment.range[0] + 2 + parsedJsdocNode.range[0]),
178
+ end: sourceCode.getLocFromIndex(jsdocComment.range[0] + 2 + parsedJsdocNode.range[1])
165
179
  };
166
180
  }
167
181
 
@@ -204,14 +218,21 @@ module.exports = {
204
218
  elements.forEach(validateType.bind(null, jsdocNode));
205
219
 
206
220
  typesToCheck.forEach(typeToCheck => {
207
- if (typeToCheck.expectedType &&
208
- typeToCheck.expectedType !== typeToCheck.currentType) {
221
+ if (typeToCheck.expectedTypeName &&
222
+ typeToCheck.expectedTypeName !== typeToCheck.currentType.name) {
209
223
  context.report({
210
224
  node: jsdocNode,
211
- message: "Use '{{expectedType}}' instead of '{{currentType}}'.",
225
+ message: "Use '{{expectedTypeName}}' instead of '{{currentTypeName}}'.",
226
+ loc: getAbsoluteRange(jsdocNode, typeToCheck.currentType),
212
227
  data: {
213
- currentType: typeToCheck.currentType,
214
- expectedType: typeToCheck.expectedType
228
+ currentTypeName: typeToCheck.currentType.name,
229
+ expectedTypeName: typeToCheck.expectedTypeName
230
+ },
231
+ fix(fixer) {
232
+ return fixer.replaceTextRange(
233
+ typeToCheck.currentType.range.map(indexInComment => jsdocNode.range[0] + 2 + indexInComment),
234
+ typeToCheck.expectedTypeName
235
+ );
215
236
  }
216
237
  });
217
238
  }
@@ -227,8 +248,8 @@ module.exports = {
227
248
  function checkJSDoc(node) {
228
249
  const jsdocNode = sourceCode.getJSDocComment(node),
229
250
  functionData = fns.pop(),
230
- params = Object.create(null),
231
- paramsTags = [];
251
+ paramTagsByName = Object.create(null),
252
+ paramTags = [];
232
253
  let hasReturns = false,
233
254
  returnsTag,
234
255
  hasConstructor = false,
@@ -244,7 +265,8 @@ module.exports = {
244
265
  jsdoc = doctrine.parse(jsdocNode.value, {
245
266
  strict: true,
246
267
  unwrap: true,
247
- sloppy: true
268
+ sloppy: true,
269
+ range: true
248
270
  });
249
271
  } catch (ex) {
250
272
 
@@ -264,7 +286,7 @@ module.exports = {
264
286
  case "param":
265
287
  case "arg":
266
288
  case "argument":
267
- paramsTags.push(tag);
289
+ paramTags.push(tag);
268
290
  break;
269
291
 
270
292
  case "return":
@@ -297,7 +319,29 @@ module.exports = {
297
319
 
298
320
  // check tag preferences
299
321
  if (prefer.hasOwnProperty(tag.title) && tag.title !== prefer[tag.title]) {
300
- context.report({ node: jsdocNode, message: "Use @{{name}} instead.", data: { name: prefer[tag.title] } });
322
+ const entireTagRange = getAbsoluteRange(jsdocNode, tag);
323
+
324
+ context.report({
325
+ node: jsdocNode,
326
+ message: "Use @{{name}} instead.",
327
+ loc: {
328
+ start: entireTagRange.start,
329
+ end: {
330
+ line: entireTagRange.start.line,
331
+ column: entireTagRange.start.column + `@${tag.title}`.length
332
+ }
333
+ },
334
+ data: { name: prefer[tag.title] },
335
+ fix(fixer) {
336
+ return fixer.replaceTextRange(
337
+ [
338
+ jsdocNode.range[0] + tag.range[0] + 3,
339
+ jsdocNode.range[0] + tag.range[0] + tag.title.length + 3
340
+ ],
341
+ prefer[tag.title]
342
+ );
343
+ }
344
+ });
301
345
  }
302
346
 
303
347
  // validate the types
@@ -306,17 +350,32 @@ module.exports = {
306
350
  }
307
351
  });
308
352
 
309
- paramsTags.forEach(param => {
353
+ paramTags.forEach(param => {
310
354
  if (!param.type) {
311
- context.report({ node: jsdocNode, message: "Missing JSDoc parameter type for '{{name}}'.", data: { name: param.name } });
355
+ context.report({
356
+ node: jsdocNode,
357
+ message: "Missing JSDoc parameter type for '{{name}}'.",
358
+ loc: getAbsoluteRange(jsdocNode, param),
359
+ data: { name: param.name }
360
+ });
312
361
  }
313
362
  if (!param.description && requireParamDescription) {
314
- context.report({ node: jsdocNode, message: "Missing JSDoc parameter description for '{{name}}'.", data: { name: param.name } });
363
+ context.report({
364
+ node: jsdocNode,
365
+ message: "Missing JSDoc parameter description for '{{name}}'.",
366
+ loc: getAbsoluteRange(jsdocNode, param),
367
+ data: { name: param.name }
368
+ });
315
369
  }
316
- if (params[param.name]) {
317
- context.report({ node: jsdocNode, message: "Duplicate JSDoc parameter '{{name}}'.", data: { name: param.name } });
370
+ if (paramTagsByName[param.name]) {
371
+ context.report({
372
+ node: jsdocNode,
373
+ message: "Duplicate JSDoc parameter '{{name}}'.",
374
+ loc: getAbsoluteRange(jsdocNode, param),
375
+ data: { name: param.name }
376
+ });
318
377
  } else if (param.name.indexOf(".") === -1) {
319
- params[param.name] = 1;
378
+ paramTagsByName[param.name] = param;
320
379
  }
321
380
  });
322
381
 
@@ -325,6 +384,7 @@ module.exports = {
325
384
  context.report({
326
385
  node: jsdocNode,
327
386
  message: "Unexpected @{{title}} tag; function has no return statement.",
387
+ loc: getAbsoluteRange(jsdocNode, returnsTag),
328
388
  data: {
329
389
  title: returnsTag.title
330
390
  }
@@ -356,10 +416,10 @@ module.exports = {
356
416
  }
357
417
 
358
418
  // check the parameters
359
- const jsdocParams = Object.keys(params);
419
+ const jsdocParamNames = Object.keys(paramTagsByName);
360
420
 
361
421
  if (node.params) {
362
- node.params.forEach((param, i) => {
422
+ node.params.forEach((param, paramsIndex) => {
363
423
  if (param.type === "AssignmentPattern") {
364
424
  param = param.left;
365
425
  }
@@ -368,16 +428,17 @@ module.exports = {
368
428
 
369
429
  // TODO(nzakas): Figure out logical things to do with destructured, default, rest params
370
430
  if (param.type === "Identifier") {
371
- if (jsdocParams[i] && (name !== jsdocParams[i])) {
431
+ if (jsdocParamNames[paramsIndex] && (name !== jsdocParamNames[paramsIndex])) {
372
432
  context.report({
373
433
  node: jsdocNode,
374
434
  message: "Expected JSDoc for '{{name}}' but found '{{jsdocName}}'.",
435
+ loc: getAbsoluteRange(jsdocNode, paramTagsByName[jsdocParamNames[paramsIndex]]),
375
436
  data: {
376
437
  name,
377
- jsdocName: jsdocParams[i]
438
+ jsdocName: jsdocParamNames[paramsIndex]
378
439
  }
379
440
  });
380
- } else if (!params[name] && !isOverride) {
441
+ } else if (!paramTagsByName[name] && !isOverride) {
381
442
  context.report({
382
443
  node: jsdocNode,
383
444
  message: "Missing JSDoc for parameter '{{name}}'.",
@@ -8,7 +8,8 @@
8
8
  // Requirements
9
9
  //------------------------------------------------------------------------------
10
10
 
11
- const fs = require("fs"),
11
+ const lodash = require("lodash"),
12
+ fs = require("fs"),
12
13
  path = require("path"),
13
14
  GlobSync = require("./glob"),
14
15
 
@@ -88,6 +89,8 @@ function resolveFileGlobPatterns(patterns, options) {
88
89
  return patterns.filter(p => p.length).map(processPathExtensions);
89
90
  }
90
91
 
92
+ const dotfilesPattern = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/;
93
+
91
94
  /**
92
95
  * Build a list of absolute filesnames on which ESLint will act.
93
96
  * Ignored files are excluded from the results, as are duplicates.
@@ -107,6 +110,11 @@ function listFilesToProcess(globPatterns, options) {
107
110
 
108
111
  const cwd = (options && options.cwd) || process.cwd();
109
112
 
113
+ const getIgnorePaths = lodash.memoize(
114
+ optionsObj =>
115
+ new IgnoredPaths(optionsObj)
116
+ );
117
+
110
118
  /**
111
119
  * Executes the linter on a file defined by the `filename`. Skips
112
120
  * unsupported file extensions and any files that are already linted.
@@ -151,15 +159,20 @@ function listFilesToProcess(globPatterns, options) {
151
159
  const file = path.resolve(cwd, pattern);
152
160
 
153
161
  if (fs.existsSync(file) && fs.statSync(file).isFile()) {
154
- const ignoredPaths = new IgnoredPaths(options);
162
+ const ignoredPaths = getIgnorePaths(options);
155
163
 
156
164
  addFile(fs.realpathSync(file), true, ignoredPaths);
157
165
  } else {
158
166
 
159
167
  // regex to find .hidden or /.hidden patterns, but not ./relative or ../relative
160
- const globIncludesDotfiles = /(?:(?:^\.)|(?:[/\\]\.))[^/\\.].*/.test(pattern);
168
+ const globIncludesDotfiles = dotfilesPattern.test(pattern);
169
+ let newOptions = options;
170
+
171
+ if (!options.dotfiles) {
172
+ newOptions = Object.assign({}, options, { dotfiles: globIncludesDotfiles });
173
+ }
161
174
 
162
- const ignoredPaths = new IgnoredPaths(Object.assign({}, options, { dotfiles: options.dotfiles || globIncludesDotfiles }));
175
+ const ignoredPaths = getIgnorePaths(newOptions);
163
176
  const shouldIgnore = ignoredPaths.getIgnoredFoldersGlobChecker();
164
177
  const globOptions = {
165
178
  nodir: true,
@@ -60,7 +60,7 @@ function installSyncSaveDev(packages) {
60
60
  if (error && error.code === "ENOENT") {
61
61
  const pluralS = packages.length > 1 ? "s" : "";
62
62
 
63
- log.error(`Could not execute npm. Please install the following package${pluralS} with your package manager of choice: ${packages.join(", ")}`);
63
+ log.error(`Could not execute npm. Please install the following package${pluralS} with a package manager of your choice: ${packages.join(", ")}`);
64
64
  }
65
65
  }
66
66
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "4.15.0",
3
+ "version": "4.18.1",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {
@@ -40,7 +40,7 @@
40
40
  "concat-stream": "^1.6.0",
41
41
  "cross-spawn": "^5.1.0",
42
42
  "debug": "^3.1.0",
43
- "doctrine": "^2.0.2",
43
+ "doctrine": "^2.1.0",
44
44
  "eslint-scope": "^3.7.1",
45
45
  "eslint-visitor-keys": "^1.0.0",
46
46
  "espree": "^3.5.2",