eslint 10.4.1 → 10.5.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
@@ -45,7 +45,7 @@ ESLint is a tool for identifying and reporting on patterns found in ECMAScript/J
45
45
 
46
46
  ### Prerequisites
47
47
 
48
- To use ESLint, you must have [Node.js](https://nodejs.org/) (`^20.19.0`, `^22.13.0`, or `>=24`) installed and built with SSL support. (If you are using an official Node.js distribution, SSL is always built in.)
48
+ To use ESLint, you must have [Node.js](https://nodejs.org/) (`^20.19.0`, `^22.13.0`, or `>=24`) installed and built with SSL and ICU support. (If you are using an official Node.js distribution, both SSL and ICU are always built in.)
49
49
 
50
50
  If you use ESLint's TypeScript type definitions, TypeScript 5.3 or later is required.
51
51
 
@@ -10,6 +10,7 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const astUtils = require("./utils/ast-utils");
13
+ const { isAnySegmentReachable } = require("./utils/code-path-utils");
13
14
 
14
15
  //------------------------------------------------------------------------------
15
16
  // Helpers
@@ -30,21 +31,6 @@ function isTargetMethod(node) {
30
31
  return astUtils.isSpecificMemberAccess(node, null, TARGET_METHODS);
31
32
  }
32
33
 
33
- /**
34
- * Checks all segments in a set and returns true if any are reachable.
35
- * @param {Set<CodePathSegment>} segments The segments to check.
36
- * @returns {boolean} True if any segment is reachable; false otherwise.
37
- */
38
- function isAnySegmentReachable(segments) {
39
- for (const segment of segments) {
40
- if (segment.reachable) {
41
- return true;
42
- }
43
- }
44
-
45
- return false;
46
- }
47
-
48
34
  /**
49
35
  * Returns a human-legible description of an array method
50
36
  * @param {string} arrayMethodName A method name to fully qualify
@@ -10,26 +10,12 @@
10
10
 
11
11
  const astUtils = require("./utils/ast-utils");
12
12
  const { upperCaseFirst } = require("../shared/string-utils");
13
+ const { isAnySegmentReachable } = require("./utils/code-path-utils");
13
14
 
14
15
  //------------------------------------------------------------------------------
15
16
  // Helpers
16
17
  //------------------------------------------------------------------------------
17
18
 
18
- /**
19
- * Checks all segments in a set and returns true if all are unreachable.
20
- * @param {Set<CodePathSegment>} segments The segments to check.
21
- * @returns {boolean} True if all segments are unreachable; false otherwise.
22
- */
23
- function areAllSegmentsUnreachable(segments) {
24
- for (const segment of segments) {
25
- if (segment.reachable) {
26
- return false;
27
- }
28
- }
29
-
30
- return true;
31
- }
32
-
33
19
  /**
34
20
  * Checks whether a given node is a `constructor` method in an ES6 class
35
21
  * @param {ASTNode} node A node to check
@@ -100,7 +86,7 @@ module.exports = {
100
86
  */
101
87
  if (
102
88
  !funcInfo.hasReturnValue ||
103
- areAllSegmentsUnreachable(funcInfo.currentSegments) ||
89
+ !isAnySegmentReachable(funcInfo.currentSegments) ||
104
90
  astUtils.isES5Constructor(node) ||
105
91
  isClassConstructor(node)
106
92
  ) {
@@ -10,6 +10,7 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const astUtils = require("./utils/ast-utils");
13
+ const { isAnySegmentReachable } = require("./utils/code-path-utils");
13
14
 
14
15
  //------------------------------------------------------------------------------
15
16
  // Helpers
@@ -17,21 +18,6 @@ const astUtils = require("./utils/ast-utils");
17
18
 
18
19
  const TARGET_NODE_TYPE = /^(?:Arrow)?FunctionExpression$/u;
19
20
 
20
- /**
21
- * Checks all segments in a set and returns true if any are reachable.
22
- * @param {Set<CodePathSegment>} segments The segments to check.
23
- * @returns {boolean} True if any segment is reachable; false otherwise.
24
- */
25
- function isAnySegmentReachable(segments) {
26
- for (const segment of segments) {
27
- if (segment.reachable) {
28
- return true;
29
- }
30
- }
31
-
32
- return false;
33
- }
34
-
35
21
  //------------------------------------------------------------------------------
36
22
  // Rule Definition
37
23
  //------------------------------------------------------------------------------
@@ -54,6 +54,8 @@ module.exports = {
54
54
  },
55
55
 
56
56
  create(context) {
57
+ const sourceCode = context.sourceCode;
58
+
57
59
  //--------------------------------------------------------------------------
58
60
  // Helpers
59
61
  //--------------------------------------------------------------------------
@@ -102,6 +104,7 @@ module.exports = {
102
104
  if (len > maxDepth) {
103
105
  context.report({
104
106
  node,
107
+ loc: sourceCode.getFirstToken(node).loc,
105
108
  messageId: "tooDeeply",
106
109
  data: { depth: len, maxDepth },
107
110
  });
@@ -117,6 +120,18 @@ module.exports = {
117
120
  functionStack[functionStack.length - 1]--;
118
121
  }
119
122
 
123
+ /**
124
+ * Checks whether a node is an else-if statement.
125
+ * @param {ASTNode} node node to evaluate
126
+ * @returns {boolean} Whether the node is an else-if statement
127
+ */
128
+ function isElseIf(node) {
129
+ return (
130
+ node.parent.type === "IfStatement" &&
131
+ node.parent.alternate === node
132
+ );
133
+ }
134
+
120
135
  //--------------------------------------------------------------------------
121
136
  // Public API
122
137
  //--------------------------------------------------------------------------
@@ -129,7 +144,7 @@ module.exports = {
129
144
  StaticBlock: startFunction,
130
145
 
131
146
  IfStatement(node) {
132
- if (node.parent.type !== "IfStatement") {
147
+ if (!isElseIf(node)) {
133
148
  pushBlock(node);
134
149
  }
135
150
  },
@@ -142,7 +157,11 @@ module.exports = {
142
157
  ForInStatement: pushBlock,
143
158
  ForOfStatement: pushBlock,
144
159
 
145
- "IfStatement:exit": popBlock,
160
+ "IfStatement:exit"(node) {
161
+ if (!isElseIf(node)) {
162
+ popBlock();
163
+ }
164
+ },
146
165
  "SwitchStatement:exit": popBlock,
147
166
  "TryStatement:exit": popBlock,
148
167
  "DoWhileStatement:exit": popBlock,
@@ -222,6 +222,7 @@ module.exports = {
222
222
 
223
223
  context.report({
224
224
  node,
225
+ loc: astUtils.getFunctionHeadLoc(funcNode, sourceCode),
225
226
  messageId: "exceed",
226
227
  data: { name, lineCount, maxLines },
227
228
  });
@@ -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
  //------------------------------------------------------------------------------
@@ -53,6 +59,8 @@ module.exports = {
53
59
  },
54
60
 
55
61
  create(context) {
62
+ const sourceCode = context.sourceCode;
63
+
56
64
  //--------------------------------------------------------------------------
57
65
  // Constants
58
66
  //--------------------------------------------------------------------------
@@ -90,17 +98,25 @@ module.exports = {
90
98
  if (callbackStack.length > THRESHOLD) {
91
99
  const opts = { num: callbackStack.length, max: THRESHOLD };
92
100
 
93
- context.report({ node, messageId: "exceed", data: opts });
101
+ context.report({
102
+ node,
103
+ loc: astUtils.getFunctionHeadLoc(node, sourceCode),
104
+ messageId: "exceed",
105
+ data: opts,
106
+ });
94
107
  }
95
108
  }
96
109
 
97
110
  /**
98
111
  * Pops the call stack.
112
+ * @param {ASTNode} node The node to check.
99
113
  * @returns {void}
100
114
  * @private
101
115
  */
102
- function popStack() {
103
- callbackStack.pop();
116
+ function popStack(node) {
117
+ if (callbackStack.at(-1) === node) {
118
+ callbackStack.pop();
119
+ }
104
120
  }
105
121
 
106
122
  //--------------------------------------------------------------------------
@@ -108,6 +108,7 @@ module.exports = {
108
108
 
109
109
  context.report({
110
110
  node,
111
+ loc: astUtils.getFunctionHeadLoc(node, context.sourceCode),
111
112
  messageId: "exceed",
112
113
  data: { name, count, max },
113
114
  });
@@ -9,6 +9,7 @@
9
9
  //------------------------------------------------------------------------------
10
10
 
11
11
  const { directivesPattern } = require("../shared/directives");
12
+ const { isAnySegmentReachable } = require("./utils/code-path-utils");
12
13
 
13
14
  //------------------------------------------------------------------------------
14
15
  // Helpers
@@ -16,21 +17,6 @@ const { directivesPattern } = require("../shared/directives");
16
17
 
17
18
  const DEFAULT_FALLTHROUGH_COMMENT = /falls?\s?through/iu;
18
19
 
19
- /**
20
- * Checks all segments in a set and returns true if any are reachable.
21
- * @param {Set<CodePathSegment>} segments The segments to check.
22
- * @returns {boolean} True if any segment is reachable; false otherwise.
23
- */
24
- function isAnySegmentReachable(segments) {
25
- for (const segment of segments) {
26
- if (segment.reachable) {
27
- return true;
28
- }
29
- }
30
-
31
- return false;
32
- }
33
-
34
20
  /**
35
21
  * Checks whether or not a given comment string is really a fallthrough comment and not an ESLint directive.
36
22
  * @param {string} comment The comment string to check.
@@ -5,6 +5,8 @@
5
5
 
6
6
  "use strict";
7
7
 
8
+ const { isAnySegmentReachable } = require("./utils/code-path-utils");
9
+
8
10
  //------------------------------------------------------------------------------
9
11
  // Helpers
10
12
  //------------------------------------------------------------------------------
@@ -17,21 +19,6 @@ const allLoopTypes = [
17
19
  "ForOfStatement",
18
20
  ];
19
21
 
20
- /**
21
- * Checks all segments in a set and returns true if any are reachable.
22
- * @param {Set<CodePathSegment>} segments The segments to check.
23
- * @returns {boolean} True if any segment is reachable; false otherwise.
24
- */
25
- function isAnySegmentReachable(segments) {
26
- for (const segment of segments) {
27
- if (segment.reachable) {
28
- return true;
29
- }
30
- }
31
-
32
- return false;
33
- }
34
-
35
22
  /**
36
23
  * Determines whether the given node is the first node in the code path to which a loop statement
37
24
  * 'loops' for the next iteration.
@@ -4,6 +4,12 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ //------------------------------------------------------------------------------
8
+ // Requirements
9
+ //------------------------------------------------------------------------------
10
+
11
+ const { isAnySegmentReachable } = require("./utils/code-path-utils");
12
+
7
13
  //------------------------------------------------------------------------------
8
14
  // Helpers
9
15
  //------------------------------------------------------------------------------
@@ -23,21 +29,6 @@ function isInitialized(node) {
23
29
  return Boolean(node.init);
24
30
  }
25
31
 
26
- /**
27
- * Checks all segments in a set and returns true if all are unreachable.
28
- * @param {Set<CodePathSegment>} segments The segments to check.
29
- * @returns {boolean} True if all segments are unreachable; false otherwise.
30
- */
31
- function areAllSegmentsUnreachable(segments) {
32
- for (const segment of segments) {
33
- if (segment.reachable) {
34
- return false;
35
- }
36
- }
37
-
38
- return true;
39
- }
40
-
41
32
  /**
42
33
  * The class to distinguish consecutive unreachable statements.
43
34
  */
@@ -154,7 +145,7 @@ module.exports = {
154
145
  if (
155
146
  node &&
156
147
  (node.type === "PropertyDefinition" ||
157
- areAllSegmentsUnreachable(currentCodePathSegments))
148
+ !isAnySegmentReachable(currentCodePathSegments))
158
149
  ) {
159
150
  // Store this statement to distinguish consecutive statements.
160
151
  if (range.isEmpty) {
@@ -10,6 +10,7 @@
10
10
 
11
11
  const astUtils = require("./utils/ast-utils"),
12
12
  FixTracker = require("./utils/fix-tracker");
13
+ const { isAnySegmentReachable } = require("./utils/code-path-utils");
13
14
 
14
15
  //------------------------------------------------------------------------------
15
16
  // Helpers
@@ -60,21 +61,6 @@ function isInFinally(node) {
60
61
  return false;
61
62
  }
62
63
 
63
- /**
64
- * Checks all segments in a set and returns true if any are reachable.
65
- * @param {Set<CodePathSegment>} segments The segments to check.
66
- * @returns {boolean} True if any segment is reachable; false otherwise.
67
- */
68
- function isAnySegmentReachable(segments) {
69
- for (const segment of segments) {
70
- if (segment.reachable) {
71
- return true;
72
- }
73
- }
74
-
75
- return false;
76
- }
77
-
78
64
  //------------------------------------------------------------------------------
79
65
  // Rule Definition
80
66
  //------------------------------------------------------------------------------
@@ -28,9 +28,15 @@ module.exports = {
28
28
  },
29
29
 
30
30
  create(context) {
31
+ const sourceCode = context.sourceCode;
32
+
31
33
  return {
32
34
  WithStatement(node) {
33
- context.report({ node, messageId: "unexpectedWith" });
35
+ context.report({
36
+ node,
37
+ loc: sourceCode.getFirstToken(node).loc,
38
+ messageId: "unexpectedWith",
39
+ });
34
40
  },
35
41
  };
36
42
  },
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @fileoverview Code path related utilities.
3
+ */
4
+
5
+ "use strict";
6
+
7
+ /**
8
+ * Checks all segments in a set and returns true if any are reachable.
9
+ * @param {Set<CodePathSegment>} segments The segments to check.
10
+ * @returns {boolean} `true` if any segment is reachable; `false` otherwise.
11
+ */
12
+ function isAnySegmentReachable(segments) {
13
+ for (const segment of segments) {
14
+ if (segment.reachable) {
15
+ return true;
16
+ }
17
+ }
18
+
19
+ return false;
20
+ }
21
+
22
+ module.exports = { isAnySegmentReachable };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "10.4.1",
3
+ "version": "10.5.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "type": "commonjs",
@@ -78,8 +78,15 @@
78
78
  "test:fuzz": "node Makefile.js fuzz",
79
79
  "test:performance": "node Makefile.js perf",
80
80
  "test:pnpm": "cd tests/pnpm && node check.js && pnpm install && pnpm exec tsc",
81
- "test:types": "tsc -p tests/lib/types/tsconfig.json"
81
+ "test:types": "tsc -p tests/lib/types/tsconfig.json && npm run test:types --workspaces --if-present",
82
+ "test:types:5.3": "npx -p typescript@5.3 -y -- tsc -p tsconfig.types-legacy.json",
83
+ "test:types:5.x": "npx -p typescript@5.x -y -- tsc -p tsconfig.types.json",
84
+ "test:types:7.x": "npx -p @typescript/native-preview@latest -y -- tsgo -p tsconfig.types.json",
85
+ "test:types:all": "npm run test:types && npm run test:types:5.3 && npm run test:types:5.x && npm run test:types:7.x"
82
86
  },
87
+ "workspaces": [
88
+ "packages/*"
89
+ ],
83
90
  "gitHooks": {
84
91
  "pre-commit": "lint-staged"
85
92
  },
@@ -151,12 +158,12 @@
151
158
  "optionator": "^0.9.3"
152
159
  },
153
160
  "devDependencies": {
154
- "@arethetypeswrong/cli": "^0.18.0",
161
+ "@arethetypeswrong/cli": "^0.18.3",
155
162
  "@babel/core": "^7.4.3",
156
163
  "@babel/preset-env": "^7.4.3",
157
164
  "@cypress/webpack-preprocessor": "^6.0.2",
158
165
  "@eslint/eslintrc": "^3.3.5",
159
- "@eslint/json": "^1.2.0",
166
+ "@eslint/json": "^2.0.0",
160
167
  "@types/esquery": "^1.5.4",
161
168
  "@types/node": "^22.13.14",
162
169
  "@typescript-eslint/parser": "^8.58.2",
@@ -228,10 +235,5 @@
228
235
  "license": "MIT",
229
236
  "engines": {
230
237
  "node": "^20.19.0 || ^22.13.0 || >=24"
231
- },
232
- "overrides": {
233
- "@arethetypeswrong/core": {
234
- "fflate": "0.8.2"
235
- }
236
238
  }
237
239
  }