eslint 6.3.0 → 6.4.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,36 @@
1
+ v6.4.0 - September 13, 2019
2
+
3
+ * [`e915fff`](https://github.com/eslint/eslint/commit/e915fffb6089a23ff1cae926cc607f9b87dc1819) Docs: Improve examples and clarify default option (#12067) (Yuping Zuo)
4
+ * [`540296f`](https://github.com/eslint/eslint/commit/540296fcecd232a09dc873a5a22f5839b59b7842) Update: enforceForClassMembers option to accessor-pairs (fixes #12063) (#12192) (Milos Djermanovic)
5
+ * [`d3c2334`](https://github.com/eslint/eslint/commit/d3c2334646eae9287d5be9e457d041e445efb512) Update: flag nested block with declaration as error (#12193) (David Waller)
6
+ * [`b2498d2`](https://github.com/eslint/eslint/commit/b2498d284b9c30ed1543429c2f45d9014e12fe22) Update: Fix handling of property names in no-self-assign (#12105) (Milos Djermanovic)
7
+ * [`1ee61b0`](https://github.com/eslint/eslint/commit/1ee61b06715fcc750be2c923034a1e59ba663287) Update: enforceForClassMembers computed-property-spacing (fixes #12049) (#12214) (Milos Djermanovic)
8
+ * [`520c922`](https://github.com/eslint/eslint/commit/520c92270eed6e90c1a796e8af275980f01705e0) Docs: Added naming convention details to plugin usage (#12202) (Henrique Barcelos)
9
+ * [`f826eab`](https://github.com/eslint/eslint/commit/f826eabbeecddb047f58f4e7308a14c18148d369) Fix: Allow line comment exception in object-curly-spacing (fixes #11902) (#12216) (Milos Djermanovic)
10
+ * [`db2a29b`](https://github.com/eslint/eslint/commit/db2a29beb0fa28183f65bf9e659c66c03a8918b5) Update: indentation of comment followed by semicolon (fixes #12232) (#12243) (Kai Cataldo)
11
+ * [`ae17d1c`](https://github.com/eslint/eslint/commit/ae17d1ca59dd466aa64da0680ec2453c2dc3b80d) Fix: no-sequences is reporting incorrect locations (#12241) (Milos Djermanovic)
12
+ * [`365331a`](https://github.com/eslint/eslint/commit/365331a42e22af5a77ac9cfa9673d6a8f653eb5a) Fix: object-shorthand providing invalid fixes for typescript (#12260) (Brad Zacher)
13
+ * [`1c921c6`](https://github.com/eslint/eslint/commit/1c921c6dfd7ddfb0308c8103e53d32c1241475f0) New: add no-import-assign (fixes #12237) (#12252) (Toru Nagashima)
14
+ * [`3be04fd`](https://github.com/eslint/eslint/commit/3be04fd6a4e7b3f5a5ecb845a29cf29b71fe2dfb) New: Add prefer-regex-literals rule (fixes #12238) (#12254) (Milos Djermanovic)
15
+ * [`37c0fde`](https://github.com/eslint/eslint/commit/37c0fdeb87b92a0b779b125adf45535b79b65757) Update: Report global Atomics calls in no-obj-calls (fixes #12234) (#12258) (Milos Djermanovic)
16
+ * [`985c9e5`](https://github.com/eslint/eslint/commit/985c9e5eba351965a8a1491a41dbdcc78154b8f4) Fix: space-before-function-paren autofix removes comments (fixes #12259) (#12264) (Milos Djermanovic)
17
+ * [`01da7d0`](https://github.com/eslint/eslint/commit/01da7d04c4e5a7376cf241ec02db7971726a1bf9) Fix: eqeqeq rule reports incorrect locations (#12265) (Milos Djermanovic)
18
+ * [`319e4d8`](https://github.com/eslint/eslint/commit/319e4d8386ea846928f0f906c251b46043a53491) Docs: adding finally example (#12256) (Jens Melgaard)
19
+ * [`d52328f`](https://github.com/eslint/eslint/commit/d52328f012f3704c7d1ce39427e63f80531c7979) Docs: fix no-sequences `with` examples (#12239) (Milos Djermanovic)
20
+ * [`a41fdc0`](https://github.com/eslint/eslint/commit/a41fdc07404a7675d14183fab245fb8f49dcb858) Fix: Remove autofixer for no-unsafe-negation (#12157) (Milos Djermanovic)
21
+ * [`e38f5fd`](https://github.com/eslint/eslint/commit/e38f5fdfc786363a3eae642f1a69a8725600aa61) Update: fix no-octal-escape false negatives after \0 (#12079) (Milos Djermanovic)
22
+ * [`9418fbe`](https://github.com/eslint/eslint/commit/9418fbe0eb31cace3debe27b620709628df2fad7) Sponsors: Sync README with website (ESLint Jenkins)
23
+ * [`acc5ec5`](https://github.com/eslint/eslint/commit/acc5ec5082aed466a29899f651e6767b39155aec) Sponsors: Sync README with website (ESLint Jenkins)
24
+ * [`460c5ad`](https://github.com/eslint/eslint/commit/460c5ad176eaf39ff579cd96b3bcbe0539093f8f) Sponsors: Sync README with website (ESLint Jenkins)
25
+ * [`0313441`](https://github.com/eslint/eslint/commit/0313441d016c8aa0674c135f9da67a676e766ec5) New: add rule default-param-last (fixes #11361) (#12188) (Chiawen Chen)
26
+ * [`7621f5d`](https://github.com/eslint/eslint/commit/7621f5d2aa7d87e798b75ca47d6889c280597e99) Update: add more specific linting messages to space-in-parens (#11121) (Che Fisher)
27
+ * [`21eb904`](https://github.com/eslint/eslint/commit/21eb9044135c01b6c12188517bba840614483fc6) Fix: basePath of OverrideTester (fixes #12032) (#12205) (Toru Nagashima)
28
+ * [`86e5e65`](https://github.com/eslint/eslint/commit/86e5e657ea3fbf12b10524abcbc197afd215a060) Sponsors: Sync README with website (ESLint Jenkins)
29
+ * [`2b1a13f`](https://github.com/eslint/eslint/commit/2b1a13fa0de8360586857f3ced8da514c971297d) Fix: no-extra-boolean-cast reports wrong negation node (fixes #11324) (#12197) (Milos Djermanovic)
30
+ * [`ba8c2aa`](https://github.com/eslint/eslint/commit/ba8c2aa0154561fbeca33db0343cb39a7fbd9b4f) Sponsors: Sync README with website (ESLint Jenkins)
31
+ * [`a0a9746`](https://github.com/eslint/eslint/commit/a0a9746724ccd22c721ddc1b25c566aa9acea154) Docs: Fix link in no-irregular-whitespace.md (#12196) (Timo Tijhof)
32
+ * [`e10eeba`](https://github.com/eslint/eslint/commit/e10eebab4abd193dee697c4de7fb2d95bbab2d8c) Fix: quotes autofix produces syntax error with octal escape sequences (#12118) (Milos Djermanovic)
33
+
1
34
  v6.3.0 - August 30, 2019
2
35
 
3
36
  * [`0acdefb`](https://github.com/eslint/eslint/commit/0acdefb97f35bb09db2910540c70dc377a01ad62) Chore: refactor code (#12113) (James George)
package/README.md CHANGED
@@ -262,9 +262,9 @@ The following companies, organizations, and individuals support ESLint's ongoing
262
262
  <!-- NOTE: This section is autogenerated. Do not manually edit.-->
263
263
  <!--sponsorsstart-->
264
264
  <h3>Gold Sponsors</h3>
265
- <p><a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/eeb91aa/logo.png" alt="Shopify" height="96"></a> <a href="http://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/d1b37c4/logo.png" alt="Salesforce" height="96"></a> <a href="https://badoo.com/team?utm_source=eslint"><img src="https://images.opencollective.com/badoo/2826a3b/logo.png" alt="Badoo" height="96"></a> <a href="https://www.airbnb.com/"><img src="https://images.opencollective.com/airbnb/001a341/logo.png" alt="Airbnb" height="96"></a> <a href="https://code.facebook.com/projects/"><img src="https://images.opencollective.com/fbopensource/fbb8a5b/logo.png" alt="Facebook Open Source" height="96"></a></p><h3>Silver Sponsors</h3>
265
+ <p><a href="https://www.shopify.com"><img src="https://images.opencollective.com/shopify/eeb91aa/logo.png" alt="Shopify" height="96"></a> <a href="http://engineering.salesforce.com"><img src="https://images.opencollective.com/salesforce/d1b37c4/logo.png" alt="Salesforce" height="96"></a> <a href="https://badoo.com/team?utm_source=eslint"><img src="https://images.opencollective.com/badoo/2826a3b/logo.png" alt="Badoo" 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://code.facebook.com/projects/"><img src="https://images.opencollective.com/fbopensource/fbb8a5b/logo.png" alt="Facebook Open Source" height="96"></a></p><h3>Silver Sponsors</h3>
266
266
  <p><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>
267
- <p><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/0b37d14/logo.png" alt="Free Icons by Icons8" height="32"></a> <a href="https://uxplanet.org/top-ui-ux-design-agencies-user-experience-firms-8c54697e290"><img src="https://images.opencollective.com/ui-ux-design-agencies/cae5dfe/logo.png" alt="UI UX Design Agencies" height="32"></a> <a href="https://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" 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/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://tekhattan.com"><img src="https://images.opencollective.com/tekhattan/bc73c28/logo.png" alt="TekHattan" height="32"></a> <a href="https://www.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" height="32"></a> <a href="http://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/jsheroes1/9fedf0b/logo.png" alt="JSHeroes " height="32"></a></p>
267
+ <p><a href="https://discordapp.com"><img src="https://images.opencollective.com/discordapp/7e3d9a9/logo.png" alt="Discord" height="32"></a> <a href="https://moneypug.co.uk/"><img src="https://images.opencollective.com/moneypug/45f8d53/logo.png" alt="MONEYPUG" height="32"></a> <a href="https://icons8.com"><img src="https://images.opencollective.com/icons8/0b37d14/logo.png" alt="Free Icons by Icons8" height="32"></a> <a href="https://uxplanet.org/top-ui-ux-design-agencies-user-experience-firms-8c54697e290"><img src="https://images.opencollective.com/ui-ux-design-agencies/cae5dfe/logo.png" alt="UI UX Design Agencies" height="32"></a> <a href="https://clay.global"><img src="https://images.opencollective.com/clayglobal/2468f34/logo.png" alt="clay" 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://themeisle.com"><img src="https://images.opencollective.com/themeisle/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://tekhattan.com"><img src="https://images.opencollective.com/tekhattan/bc73c28/logo.png" alt="TekHattan" height="32"></a> <a href="https://www.marfeel.com/"><img src="https://images.opencollective.com/marfeel/4b88e30/logo.png" alt="Marfeel" height="32"></a> <a href="http://www.firesticktricks.com"><img src="https://images.opencollective.com/fire-stick-tricks/b8fbe2c/logo.png" alt="Fire Stick Tricks" height="32"></a> <a href="https://jsheroes.io/"><img src="https://images.opencollective.com/jsheroes1/9fedf0b/logo.png" alt="JSHeroes " height="32"></a></p>
268
268
  <!--sponsorsend-->
269
269
 
270
270
  ## <a name="technology-sponsors"></a>Technology Sponsors
@@ -125,10 +125,10 @@ class OverrideTester {
125
125
  */
126
126
  static and(a, b) {
127
127
  if (!b) {
128
- return a;
128
+ return a && new OverrideTester(a.patterns, a.basePath);
129
129
  }
130
130
  if (!a) {
131
- return b;
131
+ return new OverrideTester(b.patterns, b.basePath);
132
132
  }
133
133
 
134
134
  assert.strictEqual(a.basePath, b.basePath);
@@ -152,7 +152,7 @@ module.exports = {
152
152
  type: "suggestion",
153
153
 
154
154
  docs: {
155
- description: "enforce getter and setter pairs in objects",
155
+ description: "enforce getter and setter pairs in objects and classes",
156
156
  category: "Best Practices",
157
157
  recommended: false,
158
158
  url: "https://eslint.org/docs/rules/accessor-pairs"
@@ -168,6 +168,10 @@ module.exports = {
168
168
  setWithoutGet: {
169
169
  type: "boolean",
170
170
  default: true
171
+ },
172
+ enforceForClassMembers: {
173
+ type: "boolean",
174
+ default: false
171
175
  }
172
176
  },
173
177
  additionalProperties: false
@@ -177,13 +181,16 @@ module.exports = {
177
181
  missingGetterInPropertyDescriptor: "Getter is not present in property descriptor.",
178
182
  missingSetterInPropertyDescriptor: "Setter is not present in property descriptor.",
179
183
  missingGetterInObjectLiteral: "Getter is not present for {{ name }}.",
180
- missingSetterInObjectLiteral: "Setter is not present for {{ name }}."
184
+ missingSetterInObjectLiteral: "Setter is not present for {{ name }}.",
185
+ missingGetterInClass: "Getter is not present for class {{ name }}.",
186
+ missingSetterInClass: "Setter is not present for class {{ name }}."
181
187
  }
182
188
  },
183
189
  create(context) {
184
190
  const config = context.options[0] || {};
185
191
  const checkGetWithoutSet = config.getWithoutSet === true;
186
192
  const checkSetWithoutGet = config.setWithoutGet !== false;
193
+ const enforceForClassMembers = config.enforceForClassMembers === true;
187
194
  const sourceCode = context.getSourceCode();
188
195
 
189
196
  /**
@@ -201,6 +208,13 @@ module.exports = {
201
208
  loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
202
209
  data: { name: astUtils.getFunctionNameWithKind(node.value) }
203
210
  });
211
+ } else if (node.type === "MethodDefinition") {
212
+ context.report({
213
+ node,
214
+ messageId: `${messageKind}InClass`,
215
+ loc: astUtils.getFunctionHeadLoc(node.value, sourceCode),
216
+ data: { name: astUtils.getFunctionNameWithKind(node.value) }
217
+ });
204
218
  } else {
205
219
  context.report({
206
220
  node,
@@ -313,15 +327,41 @@ module.exports = {
313
327
  }
314
328
  }
315
329
 
316
- return {
317
- ObjectExpression(node) {
318
- if (checkSetWithoutGet || checkGetWithoutSet) {
319
- checkObjectLiteral(node);
320
- if (isPropertyDescriptor(node)) {
321
- checkPropertyDescriptor(node);
322
- }
323
- }
330
+ /**
331
+ * Checks the given object expression as an object literal and as a possible property descriptor.
332
+ * @param {ASTNode} node `ObjectExpression` node to check.
333
+ * @returns {void}
334
+ * @private
335
+ */
336
+ function checkObjectExpression(node) {
337
+ checkObjectLiteral(node);
338
+ if (isPropertyDescriptor(node)) {
339
+ checkPropertyDescriptor(node);
324
340
  }
325
- };
341
+ }
342
+
343
+ /**
344
+ * Checks the given class body.
345
+ * @param {ASTNode} node `ClassBody` node to check.
346
+ * @returns {void}
347
+ * @private
348
+ */
349
+ function checkClassBody(node) {
350
+ const methodDefinitions = node.body.filter(m => m.type === "MethodDefinition");
351
+
352
+ checkList(methodDefinitions.filter(m => m.static));
353
+ checkList(methodDefinitions.filter(m => !m.static));
354
+ }
355
+
356
+ const listeners = {};
357
+
358
+ if (checkSetWithoutGet || checkGetWithoutSet) {
359
+ listeners.ObjectExpression = checkObjectExpression;
360
+ if (enforceForClassMembers) {
361
+ listeners.ClassBody = checkClassBody;
362
+ }
363
+ }
364
+
365
+ return listeners;
326
366
  }
327
367
  };
@@ -26,6 +26,16 @@ module.exports = {
26
26
  schema: [
27
27
  {
28
28
  enum: ["always", "never"]
29
+ },
30
+ {
31
+ type: "object",
32
+ properties: {
33
+ enforceForClassMembers: {
34
+ type: "boolean",
35
+ default: false
36
+ }
37
+ },
38
+ additionalProperties: false
29
39
  }
30
40
  ],
31
41
 
@@ -41,6 +51,7 @@ module.exports = {
41
51
  create(context) {
42
52
  const sourceCode = context.getSourceCode();
43
53
  const propertyNameMustBeSpaced = context.options[0] === "always"; // default is "never"
54
+ const enforceForClassMembers = context.options[1] && context.options[1].enforceForClassMembers;
44
55
 
45
56
  //--------------------------------------------------------------------------
46
57
  // Helpers
@@ -178,10 +189,16 @@ module.exports = {
178
189
  // Public
179
190
  //--------------------------------------------------------------------------
180
191
 
181
- return {
192
+ const listeners = {
182
193
  Property: checkSpacing("key"),
183
194
  MemberExpression: checkSpacing("property")
184
195
  };
185
196
 
197
+ if (enforceForClassMembers) {
198
+ listeners.MethodDefinition = checkSpacing("key");
199
+ }
200
+
201
+ return listeners;
202
+
186
203
  }
187
204
  };
@@ -0,0 +1,61 @@
1
+ /**
2
+ * @fileoverview enforce default parameters to be last
3
+ * @author Chiawen Chen
4
+ */
5
+
6
+ "use strict";
7
+
8
+ module.exports = {
9
+ meta: {
10
+ type: "suggestion",
11
+
12
+ docs: {
13
+ description: "enforce default parameters to be last",
14
+ category: "Best Practices",
15
+ recommended: false,
16
+ url: "https://eslint.org/docs/rules/default-param-last"
17
+ },
18
+
19
+ schema: [],
20
+
21
+ messages: {
22
+ shouldBeLast: "Default parameters should be last."
23
+ }
24
+ },
25
+
26
+ create(context) {
27
+
28
+ /**
29
+ * @param {ASTNode} node function node
30
+ * @returns {void}
31
+ */
32
+ function handleFunction(node) {
33
+ let hasSeenPlainParam = false;
34
+
35
+ for (let i = node.params.length - 1; i >= 0; i -= 1) {
36
+ const param = node.params[i];
37
+
38
+ if (
39
+ param.type !== "AssignmentPattern" &&
40
+ param.type !== "RestElement"
41
+ ) {
42
+ hasSeenPlainParam = true;
43
+ continue;
44
+ }
45
+
46
+ if (hasSeenPlainParam && param.type === "AssignmentPattern") {
47
+ context.report({
48
+ node: param,
49
+ messageId: "shouldBeLast"
50
+ });
51
+ }
52
+ }
53
+ }
54
+
55
+ return {
56
+ FunctionDeclaration: handleFunction,
57
+ FunctionExpression: handleFunction,
58
+ ArrowFunctionExpression: handleFunction
59
+ };
60
+ }
61
+ };
@@ -116,18 +116,6 @@ module.exports = {
116
116
  return astUtils.isNullLiteral(node.right) || astUtils.isNullLiteral(node.left);
117
117
  }
118
118
 
119
- /**
120
- * Gets the location (line and column) of the binary expression's operator
121
- * @param {ASTNode} node The binary expression node to check
122
- * @returns {Object} { line, column } location of operator
123
- * @private
124
- */
125
- function getOperatorLocation(node) {
126
- const opToken = sourceCode.getTokenAfter(node.left);
127
-
128
- return { line: opToken.loc.start.line, column: opToken.loc.start.column };
129
- }
130
-
131
119
  /**
132
120
  * Reports a message for this rule.
133
121
  * @param {ASTNode} node The binary expression node that was checked
@@ -136,21 +124,21 @@ module.exports = {
136
124
  * @private
137
125
  */
138
126
  function report(node, expectedOperator) {
127
+ const operatorToken = sourceCode.getFirstTokenBetween(
128
+ node.left,
129
+ node.right,
130
+ token => token.value === node.operator
131
+ );
132
+
139
133
  context.report({
140
134
  node,
141
- loc: getOperatorLocation(node),
135
+ loc: operatorToken.loc,
142
136
  messageId: "unexpected",
143
137
  data: { expectedOperator, actualOperator: node.operator },
144
138
  fix(fixer) {
145
139
 
146
140
  // If the comparison is a `typeof` comparison or both sides are literals with the same type, then it's safe to fix.
147
141
  if (isTypeOfBinary(node) || areLiteralsAndSameType(node)) {
148
- const operatorToken = sourceCode.getFirstTokenBetween(
149
- node.left,
150
- node.right,
151
- token => token.value === node.operator
152
- );
153
-
154
142
  return fixer.replaceText(operatorToken, expectedOperator);
155
143
  }
156
144
  return null;
@@ -1588,18 +1588,23 @@ module.exports = {
1588
1588
  return;
1589
1589
  }
1590
1590
 
1591
- // If the token matches the expected expected indentation, don't report it.
1592
- if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) {
1593
- return;
1594
- }
1595
-
1596
1591
  if (astUtils.isCommentToken(firstTokenOfLine)) {
1597
1592
  const tokenBefore = precedingTokens.get(firstTokenOfLine);
1598
1593
  const tokenAfter = tokenBefore ? sourceCode.getTokenAfter(tokenBefore) : sourceCode.ast.tokens[0];
1599
-
1600
1594
  const mayAlignWithBefore = tokenBefore && !hasBlankLinesBetween(tokenBefore, firstTokenOfLine);
1601
1595
  const mayAlignWithAfter = tokenAfter && !hasBlankLinesBetween(firstTokenOfLine, tokenAfter);
1602
1596
 
1597
+ /*
1598
+ * If a comment precedes a line that begins with a semicolon token, align to that token, i.e.
1599
+ *
1600
+ * let foo
1601
+ * // comment
1602
+ * ;(async () => {})()
1603
+ */
1604
+ if (tokenAfter && astUtils.isSemicolonToken(tokenAfter) && !astUtils.isTokenOnSameLine(firstTokenOfLine, tokenAfter)) {
1605
+ offsets.setDesiredOffset(firstTokenOfLine, tokenAfter, 0);
1606
+ }
1607
+
1603
1608
  // If a comment matches the expected indentation of the token immediately before or after, don't report it.
1604
1609
  if (
1605
1610
  mayAlignWithBefore && validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(tokenBefore)) ||
@@ -1609,6 +1614,11 @@ module.exports = {
1609
1614
  }
1610
1615
  }
1611
1616
 
1617
+ // If the token matches the expected indentation, don't report it.
1618
+ if (validateTokenIndent(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine))) {
1619
+ return;
1620
+ }
1621
+
1612
1622
  // Otherwise, report the token/comment.
1613
1623
  report(firstTokenOfLine, offsets.getDesiredIndent(firstTokenOfLine));
1614
1624
  });
@@ -37,6 +37,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
37
37
  "constructor-super": () => require("./constructor-super"),
38
38
  curly: () => require("./curly"),
39
39
  "default-case": () => require("./default-case"),
40
+ "default-param-last": () => require("./default-param-last"),
40
41
  "dot-location": () => require("./dot-location"),
41
42
  "dot-notation": () => require("./dot-notation"),
42
43
  "eol-last": () => require("./eol-last"),
@@ -131,6 +132,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
131
132
  "no-implicit-coercion": () => require("./no-implicit-coercion"),
132
133
  "no-implicit-globals": () => require("./no-implicit-globals"),
133
134
  "no-implied-eval": () => require("./no-implied-eval"),
135
+ "no-import-assign": () => require("./no-import-assign"),
134
136
  "no-inline-comments": () => require("./no-inline-comments"),
135
137
  "no-inner-declarations": () => require("./no-inner-declarations"),
136
138
  "no-invalid-regexp": () => require("./no-invalid-regexp"),
@@ -241,6 +243,7 @@ module.exports = new LazyLoadingRuleMap(Object.entries({
241
243
  "prefer-object-spread": () => require("./prefer-object-spread"),
242
244
  "prefer-promise-reject-errors": () => require("./prefer-promise-reject-errors"),
243
245
  "prefer-reflect": () => require("./prefer-reflect"),
246
+ "prefer-regex-literals": () => require("./prefer-regex-literals"),
244
247
  "prefer-rest-params": () => require("./prefer-rest-params"),
245
248
  "prefer-spread": () => require("./prefer-spread"),
246
249
  "prefer-template": () => require("./prefer-template"),
@@ -96,7 +96,7 @@ module.exports = {
96
96
  grandparent.callee.name === "Boolean")
97
97
  ) {
98
98
  context.report({
99
- node,
99
+ node: parent,
100
100
  messageId: "unexpectedNegation",
101
101
  fix: fixer => {
102
102
  if (hasCommentsInside(parent)) {
@@ -0,0 +1,238 @@
1
+ /**
2
+ * @fileoverview Rule to flag updates of imported bindings.
3
+ * @author Toru Nagashima <https://github.com/mysticatea>
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Helpers
10
+ //------------------------------------------------------------------------------
11
+
12
+ const { findVariable, getPropertyName } = require("eslint-utils");
13
+
14
+ const MutationMethods = {
15
+ Object: new Set([
16
+ "assign", "defineProperties", "defineProperty", "freeze",
17
+ "setPrototypeOf"
18
+ ]),
19
+ Reflect: new Set([
20
+ "defineProperty", "deleteProperty", "set", "setPrototypeOf"
21
+ ])
22
+ };
23
+
24
+ /**
25
+ * Check if a given node is LHS of an assignment node.
26
+ * @param {ASTNode} node The node to check.
27
+ * @returns {boolean} `true` if the node is LHS.
28
+ */
29
+ function isAssignmentLeft(node) {
30
+ const { parent } = node;
31
+
32
+ return (
33
+ (
34
+ parent.type === "AssignmentExpression" &&
35
+ parent.left === node
36
+ ) ||
37
+
38
+ // Destructuring assignments
39
+ parent.type === "ArrayPattern" ||
40
+ (
41
+ parent.type === "Property" &&
42
+ parent.value === node &&
43
+ parent.parent.type === "ObjectPattern"
44
+ ) ||
45
+ parent.type === "RestElement" ||
46
+ (
47
+ parent.type === "AssignmentPattern" &&
48
+ parent.left === node
49
+ )
50
+ );
51
+ }
52
+
53
+ /**
54
+ * Check if a given node is the operand of mutation unary operator.
55
+ * @param {ASTNode} node The node to check.
56
+ * @returns {boolean} `true` if the node is the operand of mutation unary operator.
57
+ */
58
+ function isOperandOfMutationUnaryOperator(node) {
59
+ const { parent } = node;
60
+
61
+ return (
62
+ (
63
+ parent.type === "UpdateExpression" &&
64
+ parent.argument === node
65
+ ) ||
66
+ (
67
+ parent.type === "UnaryExpression" &&
68
+ parent.operator === "delete" &&
69
+ parent.argument === node
70
+ )
71
+ );
72
+ }
73
+
74
+ /**
75
+ * Check if a given node is the iteration variable of `for-in`/`for-of` syntax.
76
+ * @param {ASTNode} node The node to check.
77
+ * @returns {boolean} `true` if the node is the iteration variable.
78
+ */
79
+ function isIterationVariable(node) {
80
+ const { parent } = node;
81
+
82
+ return (
83
+ (
84
+ parent.type === "ForInStatement" &&
85
+ parent.left === node
86
+ ) ||
87
+ (
88
+ parent.type === "ForOfStatement" &&
89
+ parent.left === node
90
+ )
91
+ );
92
+ }
93
+
94
+ /**
95
+ * Check if a given node is the iteration variable of `for-in`/`for-of` syntax.
96
+ * @param {ASTNode} node The node to check.
97
+ * @param {Scope} scope A `escope.Scope` object to find variable (whichever).
98
+ * @returns {boolean} `true` if the node is the iteration variable.
99
+ */
100
+ function isArgumentOfWellKnownMutationFunction(node, scope) {
101
+ const { parent } = node;
102
+
103
+ if (
104
+ parent.type === "CallExpression" &&
105
+ parent.arguments[0] === node &&
106
+ parent.callee.type === "MemberExpression" &&
107
+ parent.callee.object.type === "Identifier"
108
+ ) {
109
+ const { callee } = parent;
110
+ const { object } = callee;
111
+
112
+ if (Object.keys(MutationMethods).includes(object.name)) {
113
+ const variable = findVariable(scope, object);
114
+
115
+ return (
116
+ variable !== null &&
117
+ variable.scope.type === "global" &&
118
+ MutationMethods[object.name].has(getPropertyName(callee, scope))
119
+ );
120
+ }
121
+ }
122
+
123
+ return false;
124
+ }
125
+
126
+ /**
127
+ * Check if the identifier node is placed at to update members.
128
+ * @param {ASTNode} id The Identifier node to check.
129
+ * @param {Scope} scope A `escope.Scope` object to find variable (whichever).
130
+ * @returns {boolean} `true` if the member of `id` was updated.
131
+ */
132
+ function isMemberWrite(id, scope) {
133
+ const { parent } = id;
134
+
135
+ return (
136
+ (
137
+ parent.type === "MemberExpression" &&
138
+ parent.object === id &&
139
+ (
140
+ isAssignmentLeft(parent) ||
141
+ isOperandOfMutationUnaryOperator(parent) ||
142
+ isIterationVariable(parent)
143
+ )
144
+ ) ||
145
+ isArgumentOfWellKnownMutationFunction(id, scope)
146
+ );
147
+ }
148
+
149
+ /**
150
+ * Get the mutation node.
151
+ * @param {ASTNode} id The Identifier node to get.
152
+ * @returns {ASTNode} The mutation node.
153
+ */
154
+ function getWriteNode(id) {
155
+ let node = id.parent;
156
+
157
+ while (
158
+ node &&
159
+ node.type !== "AssignmentExpression" &&
160
+ node.type !== "UpdateExpression" &&
161
+ node.type !== "UnaryExpression" &&
162
+ node.type !== "CallExpression" &&
163
+ node.type !== "ForInStatement" &&
164
+ node.type !== "ForOfStatement"
165
+ ) {
166
+ node = node.parent;
167
+ }
168
+
169
+ return node || id;
170
+ }
171
+
172
+ //------------------------------------------------------------------------------
173
+ // Rule Definition
174
+ //------------------------------------------------------------------------------
175
+
176
+ module.exports = {
177
+ meta: {
178
+ type: "problem",
179
+
180
+ docs: {
181
+ description: "disallow assigning to imported bindings",
182
+ category: "Possible Errors",
183
+ recommended: false,
184
+ url: "https://eslint.org/docs/rules/no-import-assign"
185
+ },
186
+
187
+ schema: [],
188
+
189
+ messages: {
190
+ readonly: "'{{name}}' is read-only.",
191
+ readonlyMember: "The members of '{{name}}' are read-only."
192
+ }
193
+ },
194
+
195
+ create(context) {
196
+ return {
197
+ ImportDeclaration(node) {
198
+ const scope = context.getScope();
199
+
200
+ for (const variable of context.getDeclaredVariables(node)) {
201
+ const shouldCheckMembers = variable.defs.some(
202
+ d => d.node.type === "ImportNamespaceSpecifier"
203
+ );
204
+ let prevIdNode = null;
205
+
206
+ for (const reference of variable.references) {
207
+ const idNode = reference.identifier;
208
+
209
+ /*
210
+ * AssignmentPattern (e.g. `[a = 0] = b`) makes two write
211
+ * references for the same identifier. This should skip
212
+ * the one of the two in order to prevent redundant reports.
213
+ */
214
+ if (idNode === prevIdNode) {
215
+ continue;
216
+ }
217
+ prevIdNode = idNode;
218
+
219
+ if (reference.isWrite()) {
220
+ context.report({
221
+ node: getWriteNode(idNode),
222
+ messageId: "readonly",
223
+ data: { name: idNode.name }
224
+ });
225
+ } else if (shouldCheckMembers && isMemberWrite(idNode, scope)) {
226
+ context.report({
227
+ node: getWriteNode(idNode),
228
+ messageId: "readonlyMember",
229
+ data: { name: idNode.name }
230
+ });
231
+ }
232
+ }
233
+ }
234
+ }
235
+ };
236
+
237
+ }
238
+ };