eslint 8.32.0 → 8.34.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/README.md CHANGED
@@ -10,10 +10,10 @@
10
10
  # ESLint
11
11
 
12
12
  [Website](https://eslint.org) |
13
- [Configuring](https://eslint.org/docs/latest/use/configure) |
13
+ [Configure ESLint](https://eslint.org/docs/latest/use/configure) |
14
14
  [Rules](https://eslint.org/docs/rules/) |
15
- [Contributing](https://eslint.org/docs/latest/contribute) |
16
- [Reporting Bugs](https://eslint.org/docs/latest/contribute/report-bugs) |
15
+ [Contribute to ESLint](https://eslint.org/docs/latest/contribute) |
16
+ [Report Bugs](https://eslint.org/docs/latest/contribute/report-bugs) |
17
17
  [Code of Conduct](https://eslint.org/conduct) |
18
18
  [Twitter](https://twitter.com/geteslint) |
19
19
  [Mailing List](https://groups.google.com/group/eslint) |
@@ -59,7 +59,7 @@ After that, you can run ESLint on any file or directory like this:
59
59
 
60
60
  ## Configuration
61
61
 
62
- After running `npm init @eslint/config`, you'll have a `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
62
+ After running `npm init @eslint/config`, you'll have an `.eslintrc` file in your directory. In it, you'll see some rules configured like this:
63
63
 
64
64
  ```json
65
65
  {
@@ -294,7 +294,7 @@ The following companies, organizations, and individuals support ESLint's ongoing
294
294
  <p><a href="#"><img src="https://images.opencollective.com/2021-frameworks-fund/logo.png" alt="Chrome Frameworks Fund" height="undefined"></a> <a href="https://automattic.com"><img src="https://images.opencollective.com/automattic/d0ef3e1/logo.png" alt="Automattic" height="undefined"></a></p><h3>Gold Sponsors</h3>
295
295
  <p><a href="https://ridicorp.com/career/"><img src="https://images.opencollective.com/ridi-corporation/175dcf3/logo.png" alt="RIDI" height="96"></a> <a href="https://engineering.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></p><h3>Silver Sponsors</h3>
296
296
  <p><a href="https://sentry.io"><img src="https://avatars.githubusercontent.com/u/1396951?v=4" alt="Sentry" height="64"></a> <a href="https://liftoff.io/"><img src="https://images.opencollective.com/liftoff/5c4fa84/logo.png" alt="Liftoff" height="64"></a></p><h3>Bronze Sponsors</h3>
297
- <p><a href="https://themeisle.com"><img src="https://images.opencollective.com/themeisle/d5592fe/logo.png" alt="ThemeIsle" height="32"></a> <a href="https://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" 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="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://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p>
297
+ <p><a href="https://paydaysay.com/"><img src="https://images.opencollective.com/payday-say-organization/9cd2467/logo.png" alt="PayDay Say" 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://nx.dev"><img src="https://images.opencollective.com/nx/0efbe42/logo.png" alt="Nx (by Nrwl)" 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="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://discord.com"><img src="https://images.opencollective.com/discordapp/f9645d9/logo.png" alt="Discord" height="32"></a> <a href="https://transloadit.com/"><img src="https://avatars.githubusercontent.com/u/125754?v=4" alt="Transloadit" height="32"></a> <a href="https://www.ignitionapp.com"><img src="https://avatars.githubusercontent.com/u/5753491?v=4" alt="Ignition" height="32"></a> <a href="https://herocoders.com"><img src="https://avatars.githubusercontent.com/u/37549774?v=4" alt="HeroCoders" height="32"></a> <a href="https://quickbookstoolhub.com"><img src="https://avatars.githubusercontent.com/u/95090305?u=e5bc398ef775c9ed19f955c675cdc1fb6abf01df&v=4" alt="QuickBooks Tool hub" height="32"></a></p>
298
298
  <!--sponsorsend-->
299
299
 
300
300
  ## Technology Sponsors
@@ -568,41 +568,6 @@ async function findFiles({
568
568
  ];
569
569
  }
570
570
 
571
-
572
- /**
573
- * Checks whether a file exists at the given location
574
- * @param {string} resolvedPath A path from the CWD
575
- * @throws {Error} As thrown by `fs.statSync` or `fs.isFile`.
576
- * @returns {boolean} `true` if a file exists
577
- */
578
- function fileExists(resolvedPath) {
579
- try {
580
- return fs.statSync(resolvedPath).isFile();
581
- } catch (error) {
582
- if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
583
- return false;
584
- }
585
- throw error;
586
- }
587
- }
588
-
589
- /**
590
- * Checks whether a directory exists at the given location
591
- * @param {string} resolvedPath A path from the CWD
592
- * @throws {Error} As thrown by `fs.statSync` or `fs.isDirectory`.
593
- * @returns {boolean} `true` if a directory exists
594
- */
595
- function directoryExists(resolvedPath) {
596
- try {
597
- return fs.statSync(resolvedPath).isDirectory();
598
- } catch (error) {
599
- if (error && (error.code === "ENOENT" || error.code === "ENOTDIR")) {
600
- return false;
601
- }
602
- throw error;
603
- }
604
- }
605
-
606
571
  //-----------------------------------------------------------------------------
607
572
  // Results-related Helpers
608
573
  //-----------------------------------------------------------------------------
@@ -924,8 +889,6 @@ function getCacheFile(cacheFile, cwd) {
924
889
 
925
890
  module.exports = {
926
891
  isGlobPattern,
927
- directoryExists,
928
- fileExists,
929
892
  findFiles,
930
893
 
931
894
  isNonEmptyString,
@@ -16,7 +16,7 @@ const astUtils = require("./utils/ast-utils");
16
16
  //------------------------------------------------------------------------------
17
17
 
18
18
  const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
19
- const TARGET_METHODS = /^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort)$/u;
19
+ const TARGET_METHODS = /^(?:every|filter|find(?:Last)?(?:Index)?|flatMap|forEach|map|reduce(?:Right)?|some|sort|toSorted)$/u;
20
20
 
21
21
  /**
22
22
  * Checks a given code path segment is reachable.
@@ -47,6 +47,7 @@ module.exports = {
47
47
  ]
48
48
  }
49
49
  },
50
+ type: "array",
50
51
  items: [
51
52
  {
52
53
  oneOf: [
@@ -766,6 +766,38 @@ module.exports = {
766
766
  return false;
767
767
  }
768
768
 
769
+ /**
770
+ * Checks if the left-hand side of an assignment is an identifier, the operator is one of
771
+ * `=`, `&&=`, `||=` or `??=` and the right-hand side is an anonymous class or function.
772
+ *
773
+ * As per https://tc39.es/ecma262/#sec-assignment-operators-runtime-semantics-evaluation, an
774
+ * assignment involving one of the operators `=`, `&&=`, `||=` or `??=` where the right-hand
775
+ * side is an anonymous class or function and the left-hand side is an *unparenthesized*
776
+ * identifier has different semantics than other assignments.
777
+ * Specifically, when an expression like `foo = function () {}` is evaluated, `foo.name`
778
+ * will be set to the string "foo", i.e. the identifier name. The same thing does not happen
779
+ * when evaluating `(foo) = function () {}`.
780
+ * Since the parenthesizing of the identifier in the left-hand side is significant in this
781
+ * special case, the parentheses, if present, should not be flagged as unnecessary.
782
+ * @param {ASTNode} node an AssignmentExpression node.
783
+ * @returns {boolean} `true` if the left-hand side of the assignment is an identifier, the
784
+ * operator is one of `=`, `&&=`, `||=` or `??=` and the right-hand side is an anonymous
785
+ * class or function; otherwise, `false`.
786
+ */
787
+ function isAnonymousFunctionAssignmentException({ left, operator, right }) {
788
+ if (left.type === "Identifier" && ["=", "&&=", "||=", "??="].includes(operator)) {
789
+ const rhsType = right.type;
790
+
791
+ if (rhsType === "ArrowFunctionExpression") {
792
+ return true;
793
+ }
794
+ if ((rhsType === "FunctionExpression" || rhsType === "ClassExpression") && !right.id) {
795
+ return true;
796
+ }
797
+ }
798
+ return false;
799
+ }
800
+
769
801
  return {
770
802
  ArrayExpression(node) {
771
803
  node.elements
@@ -804,7 +836,8 @@ module.exports = {
804
836
  },
805
837
 
806
838
  AssignmentExpression(node) {
807
- if (canBeAssignmentTarget(node.left) && hasExcessParens(node.left)) {
839
+ if (canBeAssignmentTarget(node.left) && hasExcessParens(node.left) &&
840
+ (!isAnonymousFunctionAssignmentException(node) || isParenthesisedTwice(node.left))) {
808
841
  report(node.left);
809
842
  }
810
843
 
@@ -27,27 +27,78 @@ module.exports = {
27
27
  },
28
28
 
29
29
  schema: [{
30
- type: "object",
31
- properties: {
32
- restrictedNamedExports: {
33
- type: "array",
34
- items: {
35
- type: "string"
30
+ anyOf: [
31
+ {
32
+ type: "object",
33
+ properties: {
34
+ restrictedNamedExports: {
35
+ type: "array",
36
+ items: {
37
+ type: "string"
38
+ },
39
+ uniqueItems: true
40
+ }
36
41
  },
37
- uniqueItems: true
42
+ additionalProperties: false
43
+ },
44
+ {
45
+ type: "object",
46
+ properties: {
47
+ restrictedNamedExports: {
48
+ type: "array",
49
+ items: {
50
+ type: "string",
51
+ pattern: "^(?!default$)"
52
+ },
53
+ uniqueItems: true
54
+ },
55
+ restrictDefaultExports: {
56
+ type: "object",
57
+ properties: {
58
+
59
+ // Allow/Disallow `export default foo; export default 42; export default function foo() {}` format
60
+ direct: {
61
+ type: "boolean"
62
+ },
63
+
64
+ // Allow/Disallow `export { foo as default };` declarations
65
+ named: {
66
+ type: "boolean"
67
+ },
68
+
69
+ // Allow/Disallow `export { default } from "mod"; export { default as default } from "mod";` declarations
70
+ defaultFrom: {
71
+ type: "boolean"
72
+ },
73
+
74
+ // Allow/Disallow `export { foo as default } from "mod";` declarations
75
+ namedFrom: {
76
+ type: "boolean"
77
+ },
78
+
79
+ // Allow/Disallow `export * as default from "mod"`; declarations
80
+ namespaceFrom: {
81
+ type: "boolean"
82
+ }
83
+ },
84
+ additionalProperties: false
85
+ }
86
+ },
87
+ additionalProperties: false
38
88
  }
39
- },
40
- additionalProperties: false
89
+ ]
41
90
  }],
42
91
 
43
92
  messages: {
44
- restrictedNamed: "'{{name}}' is restricted from being used as an exported name."
93
+ restrictedNamed: "'{{name}}' is restricted from being used as an exported name.",
94
+ restrictedDefault: "Exporting 'default' is restricted."
45
95
  }
46
96
  },
47
97
 
48
98
  create(context) {
49
99
 
50
100
  const restrictedNames = new Set(context.options[0] && context.options[0].restrictedNamedExports);
101
+ const restrictDefaultExports = context.options[0] && context.options[0].restrictDefaultExports;
51
102
 
52
103
  /**
53
104
  * Checks and reports given exported name.
@@ -63,6 +114,42 @@ module.exports = {
63
114
  messageId: "restrictedNamed",
64
115
  data: { name }
65
116
  });
117
+ return;
118
+ }
119
+
120
+ if (name === "default") {
121
+ if (node.parent.type === "ExportAllDeclaration") {
122
+ if (restrictDefaultExports && restrictDefaultExports.namespaceFrom) {
123
+ context.report({
124
+ node,
125
+ messageId: "restrictedDefault"
126
+ });
127
+ }
128
+
129
+ } else { // ExportSpecifier
130
+ const isSourceSpecified = !!node.parent.parent.source;
131
+ const specifierLocalName = astUtils.getModuleExportName(node.parent.local);
132
+
133
+ if (!isSourceSpecified && restrictDefaultExports && restrictDefaultExports.named) {
134
+ context.report({
135
+ node,
136
+ messageId: "restrictedDefault"
137
+ });
138
+ return;
139
+ }
140
+
141
+ if (isSourceSpecified && restrictDefaultExports) {
142
+ if (
143
+ (specifierLocalName === "default" && restrictDefaultExports.defaultFrom) ||
144
+ (specifierLocalName !== "default" && restrictDefaultExports.namedFrom)
145
+ ) {
146
+ context.report({
147
+ node,
148
+ messageId: "restrictedDefault"
149
+ });
150
+ }
151
+ }
152
+ }
66
153
  }
67
154
  }
68
155
 
@@ -73,6 +160,15 @@ module.exports = {
73
160
  }
74
161
  },
75
162
 
163
+ ExportDefaultDeclaration(node) {
164
+ if (restrictDefaultExports && restrictDefaultExports.direct) {
165
+ context.report({
166
+ node,
167
+ messageId: "restrictedDefault"
168
+ });
169
+ }
170
+ },
171
+
76
172
  ExportNamedDeclaration(node) {
77
173
  const declaration = node.declaration;
78
174
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "8.32.0",
3
+ "version": "8.34.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {