eslint 7.18.0 → 7.19.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,24 @@
1
+ v7.19.0 - January 30, 2021
2
+
3
+ * [`ce7f061`](https://github.com/eslint/eslint/commit/ce7f06121d9eb9cc2b3da24b4456b4d382e1413b) Update: add shadowed variable loc to message in no-shadow (fixes #13646) (#13841) (t-mangoe)
4
+ * [`c60e23f`](https://github.com/eslint/eslint/commit/c60e23ff306a14ca6eabcadb275ed27995fcc6e4) Update: fix `let` logic in for-in and for-of loops in no-extra-parens (#14011) (Milos Djermanovic)
5
+ * [`d76e8f6`](https://github.com/eslint/eslint/commit/d76e8f69bd791357c67ada7b5c55608acf29b622) Fix: no-useless-rename invalid autofix with parenthesized identifiers (#14032) (Milos Djermanovic)
6
+ * [`5800d92`](https://github.com/eslint/eslint/commit/5800d921144ec330b6ee7cd03364434007331354) Docs: Clarify stylistic rule update policy (#14052) (Brandon Mills)
7
+ * [`0ccf6d2`](https://github.com/eslint/eslint/commit/0ccf6d200147437b338cadb34546451972befd75) Docs: remove configuring.md (#14036) (Milos Djermanovic)
8
+ * [`65bb0ab`](https://github.com/eslint/eslint/commit/65bb0abde56f72586036fff151aa2d13f1b7be6c) Chore: Clean up new issue workflow (#14040) (Nicholas C. Zakas)
9
+ * [`e1da90f`](https://github.com/eslint/eslint/commit/e1da90fc414a3c9c16f52db4a5bd81bd4f9532a4) Fix: nested indenting for offsetTernaryExpressions: true (fixes #13971) (#13972) (Chris Brody)
10
+ * [`1a078b9`](https://github.com/eslint/eslint/commit/1a078b9166f29cb3760435ddbc1a0da4a0974d4a) Update: check ternary `:` even if `?` was reported in space-infix-ops (#13963) (Milos Djermanovic)
11
+ * [`fb27422`](https://github.com/eslint/eslint/commit/fb274226242eaebc1480fc9c901202986afc3c8a) Fix: extend prefer-const fixer range to whole declaration (fixes #13899) (#14033) (Nitin Kumar)
12
+ * [`e0b05c7`](https://github.com/eslint/eslint/commit/e0b05c704f3ce6f549d14718236d22fe49fcb611) Docs: add a correct example to no-unsafe-optional-chaining (refs #14029) (#14050) (armin yahya)
13
+ * [`46e836d`](https://github.com/eslint/eslint/commit/46e836d46442d2ec756038a2e12ba19b74394dbd) Sponsors: Sync README with website (ESLint Jenkins)
14
+ * [`3fc4fa4`](https://github.com/eslint/eslint/commit/3fc4fa485ca9ccd5e16dbc7e53ba31452d22dc4a) Docs: update configuring links (#14038) (Milos Djermanovic)
15
+ * [`8561c21`](https://github.com/eslint/eslint/commit/8561c2116ef89e53ebffb750066f1b00a4acdb76) Docs: fix broken links in configuring/README.md (#14046) (Milos Djermanovic)
16
+ * [`1c309eb`](https://github.com/eslint/eslint/commit/1c309ebca4a81a0faf397103dbc621019dea8c9c) Update: fix no-invalid-regexp false negatives with no flags specified (#14018) (Milos Djermanovic)
17
+ * [`f6602d5`](https://github.com/eslint/eslint/commit/f6602d569427e9e2a4f3b5ca3fc3a8bffb28d15e) Docs: Reorganize Configuration Documentation (#13837) (klkhan)
18
+ * [`c753b44`](https://github.com/eslint/eslint/commit/c753b442ef67867a178ffc2ad29b4e0534f72469) Sponsors: Sync README with website (ESLint Jenkins)
19
+ * [`a4fdb70`](https://github.com/eslint/eslint/commit/a4fdb7001aa41b9ad8bb92cc8a47b9135c94afc7) Docs: Fixed Typo (#14007) (Yash Singh)
20
+ * [`f7ca481`](https://github.com/eslint/eslint/commit/f7ca48165d025e01c38698352cff24d1de87cc8b) Docs: Explain why we disable lock files (refs eslint/tsc-meetings#234) (#14006) (Brandon Mills)
21
+
1
22
  v7.18.0 - January 15, 2021
2
23
 
3
24
  * [`e3264b2`](https://github.com/eslint/eslint/commit/e3264b26a625d926a1ea96df1c4b643af5c3797c) Upgrade: @eslint/eslintrc to improve error message for invalid extends (#14009) (Milos Djermanovic)
package/README.md CHANGED
@@ -35,10 +35,11 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
35
35
  6. [Releases](#releases)
36
36
  7. [Security Policy](#security-policy)
37
37
  8. [Semantic Versioning Policy](#semantic-versioning-policy)
38
- 9. [License](#license)
39
- 10. [Team](#team)
40
- 11. [Sponsors](#sponsors)
41
- 12. [Technology Sponsors](#technology-sponsors)
38
+ 9. [Stylistic Rule Updates](#stylistic-rule-updates)
39
+ 10. [License](#license)
40
+ 11. [Team](#team)
41
+ 12. [Sponsors](#sponsors)
42
+ 13. [Technology Sponsors](#technology-sponsors)
42
43
 
43
44
  ## <a name="installation-and-usage"></a>Installation and Usage
44
45
 
@@ -136,6 +137,16 @@ Once a language feature has been adopted into the ECMAScript standard (stage 4 a
136
137
 
137
138
  Join our [Mailing List](https://groups.google.com/group/eslint) or [Chatroom](https://eslint.org/chat).
138
139
 
140
+ ### Why doesn't ESLint lock dependency versions?
141
+
142
+ Lock files like `package-lock.json` are helpful for deployed applications. They ensure that dependencies are consistent between environments and across deployments.
143
+
144
+ Packages like `eslint` that get published to the npm registry do not include lock files. `npm install eslint` as a user will respect version constraints in ESLint's `package.json`. ESLint and its dependencies will be included in the user's lock file if one exists, but ESLint's own lock file would not be used.
145
+
146
+ We intentionally don't lock dependency versions so that we have the latest compatible dependency versions in development and CI that our users get when installing ESLint in a project.
147
+
148
+ The Twilio blog has a [deeper dive](https://www.twilio.com/blog/lockfiles-nodejs) to learn more.
149
+
139
150
  ## <a name="releases"></a>Releases
140
151
 
141
152
  We have scheduled releases every two weeks on Friday or Saturday. You can follow a [release issue](https://github.com/eslint/eslint/issues?q=is%3Aopen+is%3Aissue+label%3Arelease) for updates about the scheduling of any particular release.
@@ -177,6 +188,15 @@ ESLint follows [semantic versioning](https://semver.org). However, due to the na
177
188
 
178
189
  According to our policy, any minor update may report more linting errors than the previous release (ex: from a bug fix). As such, we recommend using the tilde (`~`) in `package.json` e.g. `"eslint": "~3.1.0"` to guarantee the results of your builds.
179
190
 
191
+ ## <a name="stylistic-rule-updates"></a>Stylistic Rule Updates
192
+
193
+ Stylistic rules are frozen according to [our policy](https://eslint.org/blog/2020/05/changes-to-rules-policies) on how we evaluate new rules and rule changes.
194
+ This means:
195
+
196
+ * **Bug fixes**: We will still fix bugs in stylistic rules.
197
+ * **New ECMAScript features**: We will also make sure stylistic rules are compatible with new ECMAScript features.
198
+ * **New options**: We will **not** add any new options to stylistic rules unless an option is the only way to fix a bug or support a newly-added ECMAScript feature.
199
+
180
200
  ## <a name="license"></a>License
181
201
 
182
202
  [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Feslint%2Feslint.svg?type=large)](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Feslint%2Feslint?ref=badge_large)
@@ -261,8 +281,8 @@ The following companies, organizations, and individuals support ESLint's ongoing
261
281
  <!--sponsorsstart-->
262
282
  <h3>Platinum Sponsors</h3>
263
283
  <p><a href="https://automattic.com"><img src="https://images.opencollective.com/photomatt/ff91f0b/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
264
- <p><a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/e780cd4/logo.png" alt="Shopify" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://aka.ms/microsoftfossfund"><img src="https://avatars1.githubusercontent.com/u/67931232?u=7fddc652a464d7151b97e8f108392af7d54fa3e8&v=4" alt="Microsoft FOSS Fund Sponsorships" height="96"></a></p><h3>Silver Sponsors</h3>
265
- <p><a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/amp/c8a3b25/logo.png" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
284
+ <p><a href="https://google.com/chrome"><img src="https://images.opencollective.com/chrome/dc55bd4/logo.png" alt="Chrome's Web Framework & Tools Performance Fund" height="96"></a> <a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/e780cd4/logo.png" alt="Shopify" height="96"></a> <a href="https://www.salesforce.com"><img src="https://images.opencollective.com/salesforce/ca8f997/logo.png" alt="Salesforce" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/d327d66/logo.png" alt="Airbnb" height="96"></a> <a href="https://aka.ms/microsoftfossfund"><img src="https://avatars.githubusercontent.com/u/67931232?u=7fddc652a464d7151b97e8f108392af7d54fa3e8&v=4" alt="Microsoft FOSS Fund Sponsorships" height="96"></a></p><h3>Silver Sponsors</h3>
285
+ <p><a href="https://retool.com/"><img src="https://images.opencollective.com/retool/98ea68e/logo.png" alt="Retool" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a> <a href="https://www.ampproject.org/"><img src="https://images.opencollective.com/amp/c8a3b25/logo.png" alt="AMP Project" height="64"></a></p><h3>Bronze Sponsors</h3>
266
286
  <p><a href="https://streamat.se"><img src="https://images.opencollective.com/streamat/46890db/logo.png" alt="Streamat" height="32"></a> <a href="https://thestandarddaily.com/"><img src="https://images.opencollective.com/eric-watson/db4e598/avatar.png" alt="The Standard Daily" height="32"></a> <a href="https://writersperhour.com"><img src="https://images.opencollective.com/writersperhour/5787d4b/logo.png" alt="Writers Per Hour" height="32"></a> <a href="https://www.betacalendars.com/february-calendar.html"><img src="https://images.opencollective.com/betacalendars/9334b33/logo.png" alt="February 2021 calendar" height="32"></a> <a href="https://buy.fineproxy.org/eng/"><img src="https://images.opencollective.com/buy-fineproxy-org/b282e39/logo.png" alt="Buy.Fineproxy.Org" height="32"></a> <a href="https://www.crosswordsolver.org/anagram-solver/"><img src="https://images.opencollective.com/anagram-solver/2666271/logo.png" alt="Anagram Solver" height="32"></a> <a href="null"><img src="https://images.opencollective.com/bugsnag-stability-monitoring/c2cef36/logo.png" alt="Bugsnag Stability Monitoring" height="32"></a> <a href="https://mixpanel.com"><img src="https://images.opencollective.com/mixpanel/cd682f7/logo.png" alt="Mixpanel" height="32"></a> <a href="https://www.vpsserver.com"><img src="https://images.opencollective.com/vpsservercom/logo.png" alt="VPS Server" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/7fa1641/logo.png" alt="Icons8: free icons, photos, illustrations, and music" height="32"></a> <a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a></p>
267
287
  <!--sponsorsend-->
268
288
 
@@ -1178,6 +1178,7 @@ module.exports = {
1178
1178
  offsets.setDesiredOffset(colonToken, firstToken, 1);
1179
1179
 
1180
1180
  offsets.setDesiredOffset(firstConsequentToken, firstToken,
1181
+ firstConsequentToken.type === "Punctuator" &&
1181
1182
  options.offsetTernaryExpressions ? 2 : 1);
1182
1183
 
1183
1184
  /*
@@ -844,45 +844,49 @@ module.exports = {
844
844
  ExportDefaultDeclaration: node => checkExpressionOrExportStatement(node.declaration),
845
845
  ExpressionStatement: node => checkExpressionOrExportStatement(node.expression),
846
846
 
847
- "ForInStatement, ForOfStatement"(node) {
848
- if (node.left.type !== "VariableDeclarator") {
847
+ ForInStatement(node) {
848
+ if (node.left.type !== "VariableDeclaration") {
849
849
  const firstLeftToken = sourceCode.getFirstToken(node.left, astUtils.isNotOpeningParenToken);
850
850
 
851
851
  if (
852
- firstLeftToken.value === "let" && (
853
-
854
- /*
855
- * If `let` is the only thing on the left side of the loop, it's the loop variable: `for ((let) of foo);`
856
- * Removing it will cause a syntax error, because it will be parsed as the start of a VariableDeclarator.
857
- */
858
- (firstLeftToken.range[1] === node.left.range[1] || /*
859
- * If `let` is followed by a `[` token, it's a property access on the `let` value: `for ((let[foo]) of bar);`
860
- * Removing it will cause the property access to be parsed as a destructuring declaration of `foo` instead.
861
- */
862
- astUtils.isOpeningBracketToken(
863
- sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken)
864
- ))
852
+ firstLeftToken.value === "let" &&
853
+ astUtils.isOpeningBracketToken(
854
+ sourceCode.getTokenAfter(firstLeftToken, astUtils.isNotClosingParenToken)
865
855
  )
866
856
  ) {
857
+
858
+ // ForInStatement#left expression cannot start with `let[`.
867
859
  tokensToIgnore.add(firstLeftToken);
868
860
  }
869
861
  }
870
862
 
871
- if (node.type === "ForOfStatement") {
872
- const hasExtraParens = node.right.type === "SequenceExpression"
873
- ? hasDoubleExcessParens(node.right)
874
- : hasExcessParens(node.right);
863
+ if (hasExcessParens(node.left)) {
864
+ report(node.left);
865
+ }
875
866
 
876
- if (hasExtraParens) {
877
- report(node.right);
878
- }
879
- } else if (hasExcessParens(node.right)) {
867
+ if (hasExcessParens(node.right)) {
880
868
  report(node.right);
881
869
  }
870
+ },
871
+
872
+ ForOfStatement(node) {
873
+ if (node.left.type !== "VariableDeclaration") {
874
+ const firstLeftToken = sourceCode.getFirstToken(node.left, astUtils.isNotOpeningParenToken);
875
+
876
+ if (firstLeftToken.value === "let") {
877
+
878
+ // ForOfStatement#left expression cannot start with `let`.
879
+ tokensToIgnore.add(firstLeftToken);
880
+ }
881
+ }
882
882
 
883
883
  if (hasExcessParens(node.left)) {
884
884
  report(node.left);
885
885
  }
886
+
887
+ if (hasExcessParensWithPrecedence(node.right, PRECEDENCE_OF_ASSIGNMENT_EXPR)) {
888
+ report(node.right);
889
+ }
886
890
  },
887
891
 
888
892
  ForStatement(node) {
@@ -69,6 +69,28 @@ module.exports = {
69
69
  return node && node.type === "Literal" && typeof node.value === "string";
70
70
  }
71
71
 
72
+ /**
73
+ * Gets flags of a regular expression created by the given `RegExp()` or `new RegExp()` call
74
+ * Examples:
75
+ * new RegExp(".") // => ""
76
+ * new RegExp(".", "gu") // => "gu"
77
+ * new RegExp(".", flags) // => null
78
+ * @param {ASTNode} node `CallExpression` or `NewExpression` node
79
+ * @returns {string|null} flags if they can be determined, `null` otherwise
80
+ * @private
81
+ */
82
+ function getFlags(node) {
83
+ if (node.arguments.length < 2) {
84
+ return "";
85
+ }
86
+
87
+ if (isString(node.arguments[1])) {
88
+ return node.arguments[1].value;
89
+ }
90
+
91
+ return null;
92
+ }
93
+
72
94
  /**
73
95
  * Check syntax error in a given pattern.
74
96
  * @param {string} pattern The RegExp pattern to validate.
@@ -104,18 +126,23 @@ module.exports = {
104
126
  return;
105
127
  }
106
128
  const pattern = node.arguments[0].value;
107
- let flags = isString(node.arguments[1]) ? node.arguments[1].value : "";
129
+ let flags = getFlags(node);
108
130
 
109
- if (allowedFlags) {
131
+ if (flags && allowedFlags) {
110
132
  flags = flags.replace(allowedFlags, "");
111
133
  }
112
134
 
113
- // If flags are unknown, check both are errored or not.
114
- const message = validateRegExpFlags(flags) || (
115
- flags
116
- ? validateRegExpPattern(pattern, flags.indexOf("u") !== -1)
117
- : validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
118
- );
135
+ const message =
136
+ (
137
+ flags && validateRegExpFlags(flags)
138
+ ) ||
139
+ (
140
+
141
+ // If flags are unknown, report the regex only if its pattern is invalid both with and without the "u" flag
142
+ flags === null
143
+ ? validateRegExpPattern(pattern, true) && validateRegExpPattern(pattern, false)
144
+ : validateRegExpPattern(pattern, flags.includes("u"))
145
+ );
119
146
 
120
147
  if (message) {
121
148
  context.report({
@@ -44,7 +44,8 @@ module.exports = {
44
44
  ],
45
45
 
46
46
  messages: {
47
- noShadow: "'{{name}}' is already declared in the upper scope."
47
+ noShadow: "'{{name}}' is already declared in the upper scope on line {{shadowedLine}} column {{shadowedColumn}}.",
48
+ noShadowGlobal: "'{{name}}' is already a global variable."
48
49
  }
49
50
  },
50
51
 
@@ -117,6 +118,29 @@ module.exports = {
117
118
  return def && def.name.range;
118
119
  }
119
120
 
121
+ /**
122
+ * Get declared line and column of a variable.
123
+ * @param {eslint-scope.Variable} variable The variable to get.
124
+ * @returns {Object} The declared line and column of the variable.
125
+ */
126
+ function getDeclaredLocation(variable) {
127
+ const identifier = variable.identifiers[0];
128
+ let obj;
129
+
130
+ if (identifier) {
131
+ obj = {
132
+ global: false,
133
+ line: identifier.loc.start.line,
134
+ column: identifier.loc.start.column + 1
135
+ };
136
+ } else {
137
+ obj = {
138
+ global: true
139
+ };
140
+ }
141
+ return obj;
142
+ }
143
+
120
144
  /**
121
145
  * Checks if a variable is in TDZ of scopeVar.
122
146
  * @param {Object} variable The variable to check.
@@ -165,10 +189,18 @@ module.exports = {
165
189
  !isOnInitializer(variable, shadowed) &&
166
190
  !(options.hoist !== "all" && isInTdz(variable, shadowed))
167
191
  ) {
192
+ const location = getDeclaredLocation(shadowed);
193
+ const messageId = location.global ? "noShadowGlobal" : "noShadow";
194
+ const data = { name: variable.name };
195
+
196
+ if (!location.global) {
197
+ data.shadowedLine = location.line;
198
+ data.shadowedColumn = location.column;
199
+ }
168
200
  context.report({
169
201
  node: variable.identifiers[0],
170
- messageId: "noShadow",
171
- data: variable
202
+ messageId,
203
+ data
172
204
  });
173
205
  }
174
206
  }
@@ -5,6 +5,12 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const astUtils = require("./utils/ast-utils");
13
+
8
14
  //------------------------------------------------------------------------------
9
15
  // Rule Definition
10
16
  //------------------------------------------------------------------------------
@@ -54,11 +60,10 @@ module.exports = {
54
60
  * Reports error for unnecessarily renamed assignments
55
61
  * @param {ASTNode} node node to report
56
62
  * @param {ASTNode} initial node with initial name value
57
- * @param {ASTNode} result node with new name value
58
63
  * @param {string} type the type of the offending node
59
64
  * @returns {void}
60
65
  */
61
- function reportError(node, initial, result, type) {
66
+ function reportError(node, initial, type) {
62
67
  const name = initial.type === "Identifier" ? initial.name : initial.value;
63
68
 
64
69
  return context.report({
@@ -69,18 +74,21 @@ module.exports = {
69
74
  type
70
75
  },
71
76
  fix(fixer) {
72
- if (sourceCode.commentsExistBetween(initial, result)) {
77
+ const replacementNode = node.type === "Property" ? node.value : node.local;
78
+
79
+ if (sourceCode.getCommentsInside(node).length > sourceCode.getCommentsInside(replacementNode).length) {
73
80
  return null;
74
81
  }
75
82
 
76
- const replacementText = result.type === "AssignmentPattern"
77
- ? sourceCode.getText(result)
78
- : name;
83
+ // Don't autofix code such as `({foo: (foo) = a} = obj);`, parens are not allowed in shorthand properties.
84
+ if (
85
+ replacementNode.type === "AssignmentPattern" &&
86
+ astUtils.isParenthesised(sourceCode, replacementNode.left)
87
+ ) {
88
+ return null;
89
+ }
79
90
 
80
- return fixer.replaceTextRange([
81
- initial.range[0],
82
- result.range[1]
83
- ], replacementText);
91
+ return fixer.replaceText(node, sourceCode.getText(replacementNode));
84
92
  }
85
93
  });
86
94
  }
@@ -97,19 +105,11 @@ module.exports = {
97
105
 
98
106
  for (const property of node.properties) {
99
107
 
100
- /*
101
- * TODO: Remove after babel-eslint removes ExperimentalRestProperty
102
- * https://github.com/eslint/eslint/issues/12335
103
- */
104
- if (property.type === "ExperimentalRestProperty") {
105
- continue;
106
- }
107
-
108
108
  /**
109
109
  * Properties using shorthand syntax and rest elements can not be renamed.
110
110
  * If the property is computed, we have no idea if a rename is useless or not.
111
111
  */
112
- if (property.shorthand || property.type === "RestElement" || property.computed) {
112
+ if (property.type !== "Property" || property.shorthand || property.computed) {
113
113
  continue;
114
114
  }
115
115
 
@@ -117,7 +117,7 @@ module.exports = {
117
117
  const renamedKey = property.value.type === "AssignmentPattern" ? property.value.left.name : property.value.name;
118
118
 
119
119
  if (key === renamedKey) {
120
- reportError(property, property.key, property.value, "Destructuring assignment");
120
+ reportError(property, property.key, "Destructuring assignment");
121
121
  }
122
122
  }
123
123
  }
@@ -134,7 +134,7 @@ module.exports = {
134
134
 
135
135
  if (node.imported.name === node.local.name &&
136
136
  node.imported.range[0] !== node.local.range[0]) {
137
- reportError(node, node.imported, node.local, "Import");
137
+ reportError(node, node.imported, "Import");
138
138
  }
139
139
  }
140
140
 
@@ -150,7 +150,7 @@ module.exports = {
150
150
 
151
151
  if (node.local.name === node.exported.name &&
152
152
  node.local.range[0] !== node.exported.range[0]) {
153
- reportError(node, node.local, node.exported, "Export");
153
+ reportError(node, node.local, "Export");
154
154
  }
155
155
 
156
156
  }
@@ -5,6 +5,11 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const FixTracker = require("./utils/fix-tracker");
8
13
  const astUtils = require("./utils/ast-utils");
9
14
 
10
15
  //------------------------------------------------------------------------------
@@ -451,10 +456,18 @@ module.exports = {
451
456
  messageId: "useConst",
452
457
  data: node,
453
458
  fix: shouldFix
454
- ? fixer => fixer.replaceText(
455
- sourceCode.getFirstToken(varDeclParent, t => t.value === varDeclParent.kind),
456
- "const"
457
- )
459
+ ? fixer => {
460
+ const letKeywordToken = sourceCode.getFirstToken(varDeclParent, t => t.value === varDeclParent.kind);
461
+
462
+ /**
463
+ * Extend the replacement range to the whole declaration,
464
+ * in order to prevent other fixes in the same pass
465
+ * https://github.com/eslint/eslint/issues/13899
466
+ */
467
+ return new FixTracker(fixer, sourceCode)
468
+ .retainRange(varDeclParent.range)
469
+ .replaceTextRange(letKeywordToken.range, "const");
470
+ }
458
471
  : null
459
472
  });
460
473
  });
@@ -132,7 +132,9 @@ module.exports = {
132
132
 
133
133
  if (nonSpacedConsequentNode) {
134
134
  report(node, nonSpacedConsequentNode);
135
- } else if (nonSpacedAlternateNode) {
135
+ }
136
+
137
+ if (nonSpacedAlternateNode) {
136
138
  report(node, nonSpacedAlternateNode);
137
139
  }
138
140
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "7.18.0",
3
+ "version": "7.19.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {