eslint 9.3.0 → 9.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.
Files changed (36) hide show
  1. package/README.md +2 -2
  2. package/lib/api.js +1 -1
  3. package/lib/cli.js +2 -2
  4. package/lib/config/default-config.js +5 -0
  5. package/lib/config/flat-config-array.js +72 -9
  6. package/lib/config/flat-config-schema.js +46 -62
  7. package/lib/eslint/eslint-helpers.js +33 -23
  8. package/lib/eslint/eslint.js +15 -20
  9. package/lib/languages/js/index.js +247 -0
  10. package/lib/{source-code → languages/js/source-code}/source-code.js +38 -18
  11. package/lib/languages/js/validate-language-options.js +181 -0
  12. package/lib/linter/apply-disable-directives.js +8 -3
  13. package/lib/linter/linter.js +122 -121
  14. package/lib/linter/report-translator.js +14 -7
  15. package/lib/linter/vfile.js +104 -0
  16. package/lib/rule-tester/rule-tester.js +6 -3
  17. package/lib/rules/func-style.js +4 -4
  18. package/lib/rules/no-constructor-return.js +1 -1
  19. package/lib/rules/no-loop-func.js +161 -129
  20. package/lib/rules/no-sparse-arrays.js +26 -3
  21. package/messages/all-matched-files-ignored.js +21 -0
  22. package/package.json +11 -11
  23. /package/lib/{source-code → languages/js/source-code}/index.js +0 -0
  24. /package/lib/{source-code → languages/js/source-code}/token-store/backward-token-comment-cursor.js +0 -0
  25. /package/lib/{source-code → languages/js/source-code}/token-store/backward-token-cursor.js +0 -0
  26. /package/lib/{source-code → languages/js/source-code}/token-store/cursor.js +0 -0
  27. /package/lib/{source-code → languages/js/source-code}/token-store/cursors.js +0 -0
  28. /package/lib/{source-code → languages/js/source-code}/token-store/decorative-cursor.js +0 -0
  29. /package/lib/{source-code → languages/js/source-code}/token-store/filter-cursor.js +0 -0
  30. /package/lib/{source-code → languages/js/source-code}/token-store/forward-token-comment-cursor.js +0 -0
  31. /package/lib/{source-code → languages/js/source-code}/token-store/forward-token-cursor.js +0 -0
  32. /package/lib/{source-code → languages/js/source-code}/token-store/index.js +0 -0
  33. /package/lib/{source-code → languages/js/source-code}/token-store/limit-cursor.js +0 -0
  34. /package/lib/{source-code → languages/js/source-code}/token-store/padded-token-cursor.js +0 -0
  35. /package/lib/{source-code → languages/js/source-code}/token-store/skip-cursor.js +0 -0
  36. /package/lib/{source-code → languages/js/source-code}/token-store/utils.js +0 -0
@@ -14,7 +14,7 @@ module.exports = {
14
14
  type: "suggestion",
15
15
 
16
16
  docs: {
17
- description: "Enforce the consistent use of either `function` declarations or expressions",
17
+ description: "Enforce the consistent use of either `function` declarations or expressions assigned to variables",
18
18
  recommended: false,
19
19
  url: "https://eslint.org/docs/latest/rules/func-style"
20
20
  },
@@ -100,7 +100,7 @@ module.exports = {
100
100
  stack.pop();
101
101
  },
102
102
 
103
- ThisExpression() {
103
+ "ThisExpression, Super"() {
104
104
  if (stack.length > 0) {
105
105
  stack[stack.length - 1] = true;
106
106
  }
@@ -113,9 +113,9 @@ module.exports = {
113
113
  };
114
114
 
115
115
  nodesToCheck["ArrowFunctionExpression:exit"] = function(node) {
116
- const hasThisExpr = stack.pop();
116
+ const hasThisOrSuperExpr = stack.pop();
117
117
 
118
- if (!hasThisExpr && node.parent.type === "VariableDeclarator") {
118
+ if (!hasThisOrSuperExpr && node.parent.type === "VariableDeclarator") {
119
119
  if (
120
120
  enforceDeclarations &&
121
121
  (typeof exportFunctionStyle === "undefined" || node.parent.parent.parent.type !== "ExportNamedDeclaration")
@@ -49,7 +49,7 @@ module.exports = {
49
49
  if (
50
50
  last.parent.type === "MethodDefinition" &&
51
51
  last.parent.kind === "constructor" &&
52
- (node.parent.parent === last || node.argument)
52
+ node.argument
53
53
  ) {
54
54
  context.report({
55
55
  node,
@@ -9,140 +9,16 @@
9
9
  // Helpers
10
10
  //------------------------------------------------------------------------------
11
11
 
12
- /**
13
- * Gets the containing loop node of a specified node.
14
- *
15
- * We don't need to check nested functions, so this ignores those.
16
- * `Scope.through` contains references of nested functions.
17
- * @param {ASTNode} node An AST node to get.
18
- * @returns {ASTNode|null} The containing loop node of the specified node, or
19
- * `null`.
20
- */
21
- function getContainingLoopNode(node) {
22
- for (let currentNode = node; currentNode.parent; currentNode = currentNode.parent) {
23
- const parent = currentNode.parent;
24
-
25
- switch (parent.type) {
26
- case "WhileStatement":
27
- case "DoWhileStatement":
28
- return parent;
29
-
30
- case "ForStatement":
31
-
32
- // `init` is outside of the loop.
33
- if (parent.init !== currentNode) {
34
- return parent;
35
- }
36
- break;
37
-
38
- case "ForInStatement":
39
- case "ForOfStatement":
40
-
41
- // `right` is outside of the loop.
42
- if (parent.right !== currentNode) {
43
- return parent;
44
- }
45
- break;
46
-
47
- case "ArrowFunctionExpression":
48
- case "FunctionExpression":
49
- case "FunctionDeclaration":
50
-
51
- // We don't need to check nested functions.
52
- return null;
53
-
54
- default:
55
- break;
56
- }
57
- }
58
-
59
- return null;
60
- }
61
12
 
62
13
  /**
63
- * Gets the containing loop node of a given node.
64
- * If the loop was nested, this returns the most outer loop.
65
- * @param {ASTNode} node A node to get. This is a loop node.
66
- * @param {ASTNode|null} excludedNode A node that the result node should not
67
- * include.
68
- * @returns {ASTNode} The most outer loop node.
14
+ * Identifies is a node is a FunctionExpression which is part of an IIFE
15
+ * @param {ASTNode} node Node to test
16
+ * @returns {boolean} True if it's an IIFE
69
17
  */
70
- function getTopLoopNode(node, excludedNode) {
71
- const border = excludedNode ? excludedNode.range[1] : 0;
72
- let retv = node;
73
- let containingLoopNode = node;
74
-
75
- while (containingLoopNode && containingLoopNode.range[0] >= border) {
76
- retv = containingLoopNode;
77
- containingLoopNode = getContainingLoopNode(containingLoopNode);
78
- }
79
-
80
- return retv;
18
+ function isIIFE(node) {
19
+ return (node.type === "FunctionExpression" || node.type === "ArrowFunctionExpression") && node.parent && node.parent.type === "CallExpression" && node.parent.callee === node;
81
20
  }
82
21
 
83
- /**
84
- * Checks whether a given reference which refers to an upper scope's variable is
85
- * safe or not.
86
- * @param {ASTNode} loopNode A containing loop node.
87
- * @param {eslint-scope.Reference} reference A reference to check.
88
- * @returns {boolean} `true` if the reference is safe or not.
89
- */
90
- function isSafe(loopNode, reference) {
91
- const variable = reference.resolved;
92
- const definition = variable && variable.defs[0];
93
- const declaration = definition && definition.parent;
94
- const kind = (declaration && declaration.type === "VariableDeclaration")
95
- ? declaration.kind
96
- : "";
97
-
98
- // Variables which are declared by `const` is safe.
99
- if (kind === "const") {
100
- return true;
101
- }
102
-
103
- /*
104
- * Variables which are declared by `let` in the loop is safe.
105
- * It's a different instance from the next loop step's.
106
- */
107
- if (kind === "let" &&
108
- declaration.range[0] > loopNode.range[0] &&
109
- declaration.range[1] < loopNode.range[1]
110
- ) {
111
- return true;
112
- }
113
-
114
- /*
115
- * WriteReferences which exist after this border are unsafe because those
116
- * can modify the variable.
117
- */
118
- const border = getTopLoopNode(
119
- loopNode,
120
- (kind === "let") ? declaration : null
121
- ).range[0];
122
-
123
- /**
124
- * Checks whether a given reference is safe or not.
125
- * The reference is every reference of the upper scope's variable we are
126
- * looking now.
127
- *
128
- * It's safe if the reference matches one of the following condition.
129
- * - is readonly.
130
- * - doesn't exist inside a local function and after the border.
131
- * @param {eslint-scope.Reference} upperRef A reference to check.
132
- * @returns {boolean} `true` if the reference is safe.
133
- */
134
- function isSafeReference(upperRef) {
135
- const id = upperRef.identifier;
136
-
137
- return (
138
- !upperRef.isWrite() ||
139
- variable.scope.variableScope === upperRef.from.variableScope &&
140
- id.range[0] < border
141
- );
142
- }
143
-
144
- return Boolean(variable) && variable.references.every(isSafeReference);
145
- }
146
22
 
147
23
  //------------------------------------------------------------------------------
148
24
  // Rule Definition
@@ -168,8 +44,147 @@ module.exports = {
168
44
 
169
45
  create(context) {
170
46
 
47
+ const SKIPPED_IIFE_NODES = new Set();
171
48
  const sourceCode = context.sourceCode;
172
49
 
50
+ /**
51
+ * Gets the containing loop node of a specified node.
52
+ *
53
+ * We don't need to check nested functions, so this ignores those, with the exception of IIFE.
54
+ * `Scope.through` contains references of nested functions.
55
+ * @param {ASTNode} node An AST node to get.
56
+ * @returns {ASTNode|null} The containing loop node of the specified node, or
57
+ * `null`.
58
+ */
59
+ function getContainingLoopNode(node) {
60
+ for (let currentNode = node; currentNode.parent; currentNode = currentNode.parent) {
61
+ const parent = currentNode.parent;
62
+
63
+ switch (parent.type) {
64
+ case "WhileStatement":
65
+ case "DoWhileStatement":
66
+ return parent;
67
+
68
+ case "ForStatement":
69
+
70
+ // `init` is outside of the loop.
71
+ if (parent.init !== currentNode) {
72
+ return parent;
73
+ }
74
+ break;
75
+
76
+ case "ForInStatement":
77
+ case "ForOfStatement":
78
+
79
+ // `right` is outside of the loop.
80
+ if (parent.right !== currentNode) {
81
+ return parent;
82
+ }
83
+ break;
84
+
85
+ case "ArrowFunctionExpression":
86
+ case "FunctionExpression":
87
+ case "FunctionDeclaration":
88
+
89
+ // We need to check nested functions only in case of IIFE.
90
+ if (SKIPPED_IIFE_NODES.has(parent)) {
91
+ break;
92
+ }
93
+
94
+ return null;
95
+ default:
96
+ break;
97
+ }
98
+ }
99
+
100
+ return null;
101
+ }
102
+
103
+ /**
104
+ * Gets the containing loop node of a given node.
105
+ * If the loop was nested, this returns the most outer loop.
106
+ * @param {ASTNode} node A node to get. This is a loop node.
107
+ * @param {ASTNode|null} excludedNode A node that the result node should not
108
+ * include.
109
+ * @returns {ASTNode} The most outer loop node.
110
+ */
111
+ function getTopLoopNode(node, excludedNode) {
112
+ const border = excludedNode ? excludedNode.range[1] : 0;
113
+ let retv = node;
114
+ let containingLoopNode = node;
115
+
116
+ while (containingLoopNode && containingLoopNode.range[0] >= border) {
117
+ retv = containingLoopNode;
118
+ containingLoopNode = getContainingLoopNode(containingLoopNode);
119
+ }
120
+
121
+ return retv;
122
+ }
123
+
124
+ /**
125
+ * Checks whether a given reference which refers to an upper scope's variable is
126
+ * safe or not.
127
+ * @param {ASTNode} loopNode A containing loop node.
128
+ * @param {eslint-scope.Reference} reference A reference to check.
129
+ * @returns {boolean} `true` if the reference is safe or not.
130
+ */
131
+ function isSafe(loopNode, reference) {
132
+ const variable = reference.resolved;
133
+ const definition = variable && variable.defs[0];
134
+ const declaration = definition && definition.parent;
135
+ const kind = (declaration && declaration.type === "VariableDeclaration")
136
+ ? declaration.kind
137
+ : "";
138
+
139
+ // Variables which are declared by `const` is safe.
140
+ if (kind === "const") {
141
+ return true;
142
+ }
143
+
144
+ /*
145
+ * Variables which are declared by `let` in the loop is safe.
146
+ * It's a different instance from the next loop step's.
147
+ */
148
+ if (kind === "let" &&
149
+ declaration.range[0] > loopNode.range[0] &&
150
+ declaration.range[1] < loopNode.range[1]
151
+ ) {
152
+ return true;
153
+ }
154
+
155
+ /*
156
+ * WriteReferences which exist after this border are unsafe because those
157
+ * can modify the variable.
158
+ */
159
+ const border = getTopLoopNode(
160
+ loopNode,
161
+ (kind === "let") ? declaration : null
162
+ ).range[0];
163
+
164
+ /**
165
+ * Checks whether a given reference is safe or not.
166
+ * The reference is every reference of the upper scope's variable we are
167
+ * looking now.
168
+ *
169
+ * It's safe if the reference matches one of the following condition.
170
+ * - is readonly.
171
+ * - doesn't exist inside a local function and after the border.
172
+ * @param {eslint-scope.Reference} upperRef A reference to check.
173
+ * @returns {boolean} `true` if the reference is safe.
174
+ */
175
+ function isSafeReference(upperRef) {
176
+ const id = upperRef.identifier;
177
+
178
+ return (
179
+ !upperRef.isWrite() ||
180
+ variable.scope.variableScope === upperRef.from.variableScope &&
181
+ id.range[0] < border
182
+ );
183
+ }
184
+
185
+ return Boolean(variable) && variable.references.every(isSafeReference);
186
+ }
187
+
173
188
  /**
174
189
  * Reports functions which match the following condition:
175
190
  *
@@ -186,6 +201,23 @@ module.exports = {
186
201
  }
187
202
 
188
203
  const references = sourceCode.getScope(node).through;
204
+
205
+ // Check if the function is not asynchronous or a generator function
206
+ if (!(node.async || node.generator)) {
207
+ if (isIIFE(node)) {
208
+
209
+ const isFunctionExpression = node.type === "FunctionExpression";
210
+
211
+ // Check if the function is referenced elsewhere in the code
212
+ const isFunctionReferenced = isFunctionExpression && node.id ? references.some(r => r.identifier.name === node.id.name) : false;
213
+
214
+ if (!isFunctionReferenced) {
215
+ SKIPPED_IIFE_NODES.add(node);
216
+ return;
217
+ }
218
+ }
219
+ }
220
+
189
221
  const unsafeRefs = references.filter(r => r.resolved && !isSafe(loopNode, r)).map(r => r.identifier.name);
190
222
 
191
223
  if (unsafeRefs.length > 0) {
@@ -4,6 +4,8 @@
4
4
  */
5
5
  "use strict";
6
6
 
7
+ const astUtils = require("./utils/ast-utils");
8
+
7
9
  //------------------------------------------------------------------------------
8
10
  // Rule Definition
9
11
  //------------------------------------------------------------------------------
@@ -36,11 +38,32 @@ module.exports = {
36
38
  return {
37
39
 
38
40
  ArrayExpression(node) {
41
+ if (!node.elements.includes(null)) {
42
+ return;
43
+ }
44
+
45
+ const { sourceCode } = context;
46
+ let commaToken;
47
+
48
+ for (const [index, element] of node.elements.entries()) {
49
+ if (index === node.elements.length - 1 && element) {
50
+ return;
51
+ }
52
+
53
+ commaToken = sourceCode.getTokenAfter(
54
+ element ?? commaToken ?? sourceCode.getFirstToken(node),
55
+ astUtils.isCommaToken
56
+ );
39
57
 
40
- const emptySpot = node.elements.includes(null);
58
+ if (element) {
59
+ continue;
60
+ }
41
61
 
42
- if (emptySpot) {
43
- context.report({ node, messageId: "unexpectedSparseArray" });
62
+ context.report({
63
+ node,
64
+ loc: commaToken.loc,
65
+ messageId: "unexpectedSparseArray"
66
+ });
44
67
  }
45
68
  }
46
69
 
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ module.exports = function(it) {
4
+ const { pattern } = it;
5
+
6
+ return `
7
+ You are linting "${pattern}", but all of the files matching the glob pattern "${pattern}" are ignored.
8
+
9
+ If you don't want to lint these files, remove the pattern "${pattern}" from the list of arguments passed to ESLint.
10
+
11
+ If you do want to lint these files, explicitly list one or more of the files from this glob that you'd like to lint to see more details about why they are ignored.
12
+
13
+ * If the file is ignored because of a matching ignore pattern, check global ignores in your config file.
14
+ https://eslint.org/docs/latest/use/configure/ignore
15
+
16
+ * If the file is ignored because no matching configuration was supplied, check file patterns in your config file.
17
+ https://eslint.org/docs/latest/use/configure/configuration-files#specifying-files-with-arbitrary-extensions
18
+
19
+ * If the file is ignored because it is located outside of the base path, change the location of your config file to be in a parent directory.
20
+ `.trimStart();
21
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eslint",
3
- "version": "9.3.0",
3
+ "version": "9.5.0",
4
4
  "author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
5
5
  "description": "An AST-based pattern checker for JavaScript.",
6
6
  "bin": {
@@ -62,15 +62,15 @@
62
62
  "messages"
63
63
  ],
64
64
  "repository": "eslint/eslint",
65
- "funding": "https://opencollective.com/eslint",
65
+ "funding": "https://eslint.org/donate",
66
66
  "homepage": "https://eslint.org",
67
67
  "bugs": "https://github.com/eslint/eslint/issues/",
68
68
  "dependencies": {
69
69
  "@eslint-community/eslint-utils": "^4.2.0",
70
70
  "@eslint-community/regexpp": "^4.6.1",
71
+ "@eslint/config-array": "^0.16.0",
71
72
  "@eslint/eslintrc": "^3.1.0",
72
- "@eslint/js": "9.3.0",
73
- "@humanwhocodes/config-array": "^0.13.0",
73
+ "@eslint/js": "9.5.0",
74
74
  "@humanwhocodes/module-importer": "^1.0.1",
75
75
  "@humanwhocodes/retry": "^0.3.0",
76
76
  "@nodelib/fs.walk": "^1.2.8",
@@ -82,7 +82,7 @@
82
82
  "eslint-scope": "^8.0.1",
83
83
  "eslint-visitor-keys": "^4.0.0",
84
84
  "espree": "^10.0.1",
85
- "esquery": "^1.4.2",
85
+ "esquery": "^1.5.0",
86
86
  "esutils": "^2.0.2",
87
87
  "fast-deep-equal": "^3.1.3",
88
88
  "file-entry-cache": "^8.0.0",
@@ -107,11 +107,11 @@
107
107
  "@eslint-community/eslint-plugin-eslint-comments": "^4.3.0",
108
108
  "@types/estree": "^1.0.5",
109
109
  "@types/node": "^20.11.5",
110
- "@wdio/browser-runner": "^8.14.6",
111
- "@wdio/cli": "^8.14.6",
112
- "@wdio/concise-reporter": "^8.14.0",
113
- "@wdio/globals": "^8.14.6",
114
- "@wdio/mocha-framework": "^8.14.0",
110
+ "@wdio/browser-runner": "^8.38.3",
111
+ "@wdio/cli": "^8.38.2",
112
+ "@wdio/concise-reporter": "^8.38.2",
113
+ "@wdio/globals": "^8.38.2",
114
+ "@wdio/mocha-framework": "^8.38.2",
115
115
  "babel-loader": "^8.0.5",
116
116
  "c8": "^7.12.0",
117
117
  "chai": "^4.0.1",
@@ -142,7 +142,7 @@
142
142
  "markdown-it": "^12.2.0",
143
143
  "markdown-it-container": "^3.0.0",
144
144
  "markdownlint": "^0.34.0",
145
- "markdownlint-cli": "^0.40.0",
145
+ "markdownlint-cli": "^0.41.0",
146
146
  "marked": "^4.0.8",
147
147
  "metascraper": "^5.25.7",
148
148
  "metascraper-description": "^5.25.7",