eslint 5.10.0 → 5.11.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/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ v5.11.0 - December 22, 2018
2
+
3
+ * [`b4395f6`](https://github.com/eslint/eslint/commit/b4395f671442a7e0be956382c24cce38025a6df6) New: add option `first` for VariableDeclarator in indent (fixes #8976) (#11193) (Pig Fang)
4
+ * [`2b5a602`](https://github.com/eslint/eslint/commit/2b5a60284670a3ab1281b206941ed38faf2ea10c) New: no-useless-catch rule (fixes #11174) (#11198) (Alexander Grasley)
5
+ * [`06b3b5b`](https://github.com/eslint/eslint/commit/06b3b5bfcf0429c5078d4f4af3c03bb777e4f022) Fix: Account for comments in implicit-arrow-linebreak (#10545) (Mark de Dios)
6
+ * [`4242314`](https://github.com/eslint/eslint/commit/4242314215a6f35e432860433906f47af1a29724) Update: handle computed properties in camelcase (fixes #11084) (#11113) (Bence Dányi)
7
+ * [`1009304`](https://github.com/eslint/eslint/commit/100930493d9ab802a94dac5c761515b12241ddd2) Docs: add a note for no-unused-expressions (fixes #11169) (#11192) (Pig Fang)
8
+ * [`88f99d3`](https://github.com/eslint/eslint/commit/88f99d31b88a4cde4563bc4a6f4c41f0cc557885) Docs: clarify how to use configs in plugins (#11199) (Kai Cataldo)
9
+ * [`bcf558b`](https://github.com/eslint/eslint/commit/bcf558b2f7036f487af2bdb2b2d34b6cdf7fc174) Docs: Clarify the no-unused-vars docs (#11195) (Jed Fox)
10
+ * [`a470eb7`](https://github.com/eslint/eslint/commit/a470eb73d52fae0f0bc48de5a487e23cf78fcfa9) Docs: Fix no-irregular-whitespace description (#11196) (Jed Fox)
11
+ * [`8abc8af`](https://github.com/eslint/eslint/commit/8abc8afe71691b747cbd1819a13d896e8aa5b92a) Docs: Remove a misleading example (#11204) (Bogdan Gradinariu)
12
+ * [`733d936`](https://github.com/eslint/eslint/commit/733d93618a99758a05453ab94505a9f1330950e0) Docs: link to JSDoc EOL blogpost in valid-jsdoc and require-jsdoc (#11191) (Nathan Diddle)
13
+ * [`d5eb108`](https://github.com/eslint/eslint/commit/d5eb108e17f676d0e4fcddeb1211b4bdfac760c1) Docs: Ensure `triage` label is added to new issues (#11182) (Teddy Katz)
14
+ * [`617a287`](https://github.com/eslint/eslint/commit/617a2874ed085bca36ca289aac55e3b7f7ce937e) Docs: add missing deprecation notices for jsdoc rules (#11171) (Teddy Katz)
15
+
1
16
  v5.10.0 - December 8, 2018
2
17
 
3
18
  * [`4b0f517`](https://github.com/eslint/eslint/commit/4b0f517cd317e5f1b99a1e8a0392332bd8a2e231) Upgrade: single- and multiline const, let, var statements (fixes #10721) (#10919) (Tom Panier)
@@ -207,6 +207,7 @@ module.exports = {
207
207
  "no-unused-vars": "error",
208
208
  "no-use-before-define": "off",
209
209
  "no-useless-call": "off",
210
+ "no-useless-catch": "off",
210
211
  "no-useless-computed-key": "off",
211
212
  "no-useless-concat": "off",
212
213
  "no-useless-constructor": "off",
@@ -100,14 +100,20 @@ module.exports = {
100
100
  * @private
101
101
  */
102
102
  function isInsideObjectPattern(node) {
103
- let { parent } = node;
103
+ let current = node;
104
104
 
105
- while (parent) {
106
- if (parent.type === "ObjectPattern") {
105
+ while (current) {
106
+ const parent = current.parent;
107
+
108
+ if (parent && parent.type === "Property" && parent.computed && parent.key === current) {
109
+ return false;
110
+ }
111
+
112
+ if (current.type === "ObjectPattern") {
107
113
  return true;
108
114
  }
109
115
 
110
- parent = parent.parent;
116
+ current = parent;
111
117
  }
112
118
 
113
119
  return false;
@@ -169,12 +175,15 @@ module.exports = {
169
175
 
170
176
  if (node.parent.parent && node.parent.parent.type === "ObjectPattern") {
171
177
  if (node.parent.shorthand && node.parent.value.left && nameIsUnderscored) {
172
-
173
178
  report(node);
174
179
  }
175
180
 
176
181
  const assignmentKeyEqualsValue = node.parent.key.name === node.parent.value.name;
177
182
 
183
+ if (isUnderscored(name) && node.parent.computed) {
184
+ report(node);
185
+ }
186
+
178
187
  // prevent checking righthand side of destructured object
179
188
  if (node.parent.key === node && node.parent.value !== node) {
180
189
  return;
@@ -4,6 +4,12 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ const {
8
+ isArrowToken,
9
+ isParenthesised,
10
+ isOpeningParenToken
11
+ } = require("../util/ast-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Rule Definition
9
15
  //------------------------------------------------------------------------------
@@ -41,6 +47,142 @@ module.exports = {
41
47
  return context.options[0] || "beside";
42
48
  }
43
49
 
50
+ /**
51
+ * Formats the comments depending on whether it's a line or block comment.
52
+ * @param {Comment[]} comments The array of comments between the arrow and body
53
+ * @param {Integer} column The column number of the first token
54
+ * @returns {string} A string of comment text joined by line breaks
55
+ */
56
+ function formatComments(comments, column) {
57
+ const whiteSpaces = " ".repeat(column);
58
+
59
+ return `${comments.map(comment => {
60
+
61
+ if (comment.type === "Line") {
62
+ return `//${comment.value}`;
63
+ }
64
+
65
+ return `/*${comment.value}*/`;
66
+ }).join(`\n${whiteSpaces}`)}\n${whiteSpaces}`;
67
+ }
68
+
69
+ /**
70
+ * Finds the first token to prepend comments to depending on the parent type
71
+ * @param {Node} node The validated node
72
+ * @returns {Token|Node} The node to prepend comments to
73
+ */
74
+ function findFirstToken(node) {
75
+ switch (node.parent.type) {
76
+ case "VariableDeclarator":
77
+
78
+ // If the parent is first or only declarator, return the declaration, else, declarator
79
+ return sourceCode.getFirstToken(
80
+ node.parent.parent.declarations.length === 1 ||
81
+ node.parent.parent.declarations[0].id.name === node.parent.id.name
82
+ ? node.parent.parent : node.parent
83
+ );
84
+ case "CallExpression":
85
+ case "Property":
86
+
87
+ // find the object key
88
+ return sourceCode.getFirstToken(node.parent);
89
+ default:
90
+ return node;
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Helper function for adding parentheses fixes for nodes containing nested arrow functions
96
+ * @param {Fixer} fixer Fixer
97
+ * @param {Token} arrow - The arrow token
98
+ * @param {ASTNode} arrowBody - The arrow function body
99
+ * @returns {Function[]} autofixer -- wraps function bodies with parentheses
100
+ */
101
+ function addParentheses(fixer, arrow, arrowBody) {
102
+ const parenthesesFixes = [];
103
+ let closingParentheses = "";
104
+
105
+ let followingBody = arrowBody;
106
+ let currentArrow = arrow;
107
+
108
+ while (currentArrow) {
109
+ if (!isParenthesised(sourceCode, followingBody)) {
110
+ parenthesesFixes.push(
111
+ fixer.insertTextAfter(currentArrow, " (")
112
+ );
113
+
114
+ const paramsToken = sourceCode.getTokenBefore(currentArrow, token =>
115
+ isOpeningParenToken(token) || token.type === "Identifier");
116
+
117
+ const whiteSpaces = " ".repeat(paramsToken.loc.start.column);
118
+
119
+ closingParentheses = `\n${whiteSpaces})${closingParentheses}`;
120
+ }
121
+
122
+ currentArrow = sourceCode.getTokenAfter(currentArrow, isArrowToken);
123
+
124
+ if (currentArrow) {
125
+ followingBody = sourceCode.getTokenAfter(currentArrow, token => !isOpeningParenToken(token));
126
+ }
127
+ }
128
+
129
+ return [...parenthesesFixes,
130
+ fixer.insertTextAfter(arrowBody, closingParentheses)
131
+ ];
132
+ }
133
+
134
+ /**
135
+ * Autofixes the function body to collapse onto the same line as the arrow.
136
+ * If comments exist, prepends the comments before the arrow function.
137
+ * If the function body contains arrow functions, appends the function bodies with parentheses.
138
+ * @param {Token} arrowToken The arrow token.
139
+ * @param {ASTNode} arrowBody the function body
140
+ * @param {ASTNode} node The evaluated node
141
+ * @returns {Function} autofixer -- validates the node to adhere to besides
142
+ */
143
+ function autoFixBesides(arrowToken, arrowBody, node) {
144
+ return fixer => {
145
+ const placeBesides = fixer.replaceTextRange([arrowToken.range[1], arrowBody.range[0]], " ");
146
+
147
+ const comments = sourceCode.getCommentsInside(node).filter(comment =>
148
+ comment.loc.start.line < arrowBody.loc.start.line);
149
+
150
+ if (comments.length) {
151
+
152
+ // If the grandparent is not a variable declarator
153
+ if (
154
+ arrowBody.parent &&
155
+ arrowBody.parent.parent &&
156
+ arrowBody.parent.parent.type !== "VariableDeclarator"
157
+ ) {
158
+
159
+ // If any arrow functions follow, return the necessary parens fixes.
160
+ if (sourceCode.getTokenAfter(arrowToken, isArrowToken) && arrowBody.parent.parent.type !== "VariableDeclarator") {
161
+ return addParentheses(fixer, arrowToken, arrowBody);
162
+ }
163
+
164
+ // If any arrow functions precede, the necessary fixes have already been returned, so return null.
165
+ if (sourceCode.getTokenBefore(arrowToken, isArrowToken) && arrowBody.parent.parent.type !== "VariableDeclarator") {
166
+ return null;
167
+ }
168
+ }
169
+
170
+ const firstToken = findFirstToken(node);
171
+
172
+ const commentText = formatComments(comments, firstToken.loc.start.column);
173
+
174
+ const commentBeforeExpression = fixer.insertTextBeforeRange(
175
+ firstToken.range,
176
+ commentText
177
+ );
178
+
179
+ return [placeBesides, commentBeforeExpression];
180
+ }
181
+
182
+ return placeBesides;
183
+ };
184
+ }
185
+
44
186
  /**
45
187
  * Validates the location of an arrow function body
46
188
  * @param {ASTNode} node The arrow function body
@@ -75,7 +217,7 @@ module.exports = {
75
217
  context.report({
76
218
  node: fixerTarget,
77
219
  message: "Expected no linebreak before this expression.",
78
- fix: fixer => fixer.replaceTextRange([tokenBefore.range[1], fixerTarget.range[0]], " ")
220
+ fix: autoFixBesides(tokenBefore, fixerTarget, node)
79
221
  });
80
222
  }
81
223
  }
@@ -522,25 +522,13 @@ module.exports = {
522
522
  },
523
523
  VariableDeclarator: {
524
524
  oneOf: [
525
- {
526
- type: "integer",
527
- minimum: 0
528
- },
525
+ ELEMENT_LIST_SCHEMA,
529
526
  {
530
527
  type: "object",
531
528
  properties: {
532
- var: {
533
- type: "integer",
534
- minimum: 0
535
- },
536
- let: {
537
- type: "integer",
538
- minimum: 0
539
- },
540
- const: {
541
- type: "integer",
542
- minimum: 0
543
- }
529
+ var: ELEMENT_LIST_SCHEMA,
530
+ let: ELEMENT_LIST_SCHEMA,
531
+ const: ELEMENT_LIST_SCHEMA
544
532
  },
545
533
  additionalProperties: false
546
534
  }
@@ -661,7 +649,7 @@ module.exports = {
661
649
  if (context.options[1]) {
662
650
  lodash.merge(options, context.options[1]);
663
651
 
664
- if (typeof options.VariableDeclarator === "number") {
652
+ if (typeof options.VariableDeclarator === "number" || options.VariableDeclarator === "first") {
665
653
  options.VariableDeclarator = {
666
654
  var: options.VariableDeclarator,
667
655
  let: options.VariableDeclarator,
@@ -1349,10 +1337,27 @@ module.exports = {
1349
1337
  },
1350
1338
 
1351
1339
  VariableDeclaration(node) {
1352
- const variableIndent = Object.prototype.hasOwnProperty.call(options.VariableDeclarator, node.kind)
1340
+ let variableIndent = Object.prototype.hasOwnProperty.call(options.VariableDeclarator, node.kind)
1353
1341
  ? options.VariableDeclarator[node.kind]
1354
1342
  : DEFAULT_VARIABLE_INDENT;
1355
1343
 
1344
+ const firstToken = sourceCode.getFirstToken(node),
1345
+ lastToken = sourceCode.getLastToken(node);
1346
+
1347
+ if (options.VariableDeclarator[node.kind] === "first") {
1348
+ if (node.declarations.length > 1) {
1349
+ addElementListIndent(
1350
+ node.declarations,
1351
+ firstToken,
1352
+ lastToken,
1353
+ "first"
1354
+ );
1355
+ return;
1356
+ }
1357
+
1358
+ variableIndent = DEFAULT_VARIABLE_INDENT;
1359
+ }
1360
+
1356
1361
  if (node.declarations[node.declarations.length - 1].loc.start.line > node.loc.start.line) {
1357
1362
 
1358
1363
  /*
@@ -1374,13 +1379,10 @@ module.exports = {
1374
1379
  * on the same line as the start of the declaration, provided that there are declarators that
1375
1380
  * follow this one.
1376
1381
  */
1377
- const firstToken = sourceCode.getFirstToken(node);
1378
-
1379
1382
  offsets.setDesiredOffsets(node.range, firstToken, variableIndent, true);
1380
1383
  } else {
1381
- offsets.setDesiredOffsets(node.range, sourceCode.getFirstToken(node), variableIndent);
1384
+ offsets.setDesiredOffsets(node.range, firstToken, variableIndent);
1382
1385
  }
1383
- const lastToken = sourceCode.getLastToken(node);
1384
1386
 
1385
1387
  if (astUtils.isSemicolonToken(lastToken)) {
1386
1388
  offsets.ignoreToken(lastToken);
@@ -30,7 +30,7 @@ module.exports = {
30
30
  type: "problem",
31
31
 
32
32
  docs: {
33
- description: "disallow irregular whitespace outside of strings and comments",
33
+ description: "disallow irregular whitespace",
34
34
  category: "Possible Errors",
35
35
  recommended: true,
36
36
  url: "https://eslint.org/docs/rules/no-irregular-whitespace"
@@ -0,0 +1,51 @@
1
+ /**
2
+ * @fileoverview Reports useless `catch` clauses that just rethrow their error.
3
+ * @author Teddy Katz
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Rule Definition
10
+ //------------------------------------------------------------------------------
11
+
12
+ module.exports = {
13
+ meta: {
14
+ type: "suggestion",
15
+
16
+ docs: {
17
+ description: "disallow unnecessary `catch` clauses",
18
+ category: "Best Practices",
19
+ recommended: false,
20
+ url: "https://eslint.org/docs/rules/no-useless-catch"
21
+ },
22
+
23
+ schema: []
24
+ },
25
+
26
+ create(context) {
27
+ return {
28
+ CatchClause(node) {
29
+ if (
30
+ node.param.type === "Identifier" &&
31
+ node.body.body.length &&
32
+ node.body.body[0].type === "ThrowStatement" &&
33
+ node.body.body[0].argument.type === "Identifier" &&
34
+ node.body.body[0].argument.name === node.param.name
35
+ ) {
36
+ if (node.parent.finalizer) {
37
+ context.report({
38
+ node,
39
+ message: "Unnecessary catch clause."
40
+ });
41
+ } else {
42
+ context.report({
43
+ node: node.parent,
44
+ message: "Unnecessary try/catch wrapper."
45
+ });
46
+ }
47
+ }
48
+ }
49
+ };
50
+ }
51
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "5.10.0",
3
+ "version": "5.11.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {