eslint 8.47.0 → 8.57.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 (118) hide show
  1. package/README.md +18 -13
  2. package/bin/eslint.js +38 -5
  3. package/conf/rule-type-list.json +25 -33
  4. package/lib/api.js +29 -1
  5. package/lib/cli-engine/cli-engine.js +2 -2
  6. package/lib/cli-engine/lint-result-cache.js +18 -6
  7. package/lib/cli.js +36 -6
  8. package/lib/config/flat-config-schema.js +124 -61
  9. package/lib/config/rule-validator.js +2 -1
  10. package/lib/eslint/eslint-helpers.js +9 -11
  11. package/lib/eslint/eslint.js +7 -0
  12. package/lib/eslint/flat-eslint.js +33 -18
  13. package/lib/linter/apply-disable-directives.js +127 -13
  14. package/lib/linter/code-path-analysis/code-path-analyzer.js +32 -24
  15. package/lib/linter/code-path-analysis/code-path-segment.js +52 -24
  16. package/lib/linter/code-path-analysis/code-path-state.js +1108 -243
  17. package/lib/linter/code-path-analysis/code-path.js +128 -33
  18. package/lib/linter/code-path-analysis/fork-context.js +173 -72
  19. package/lib/linter/config-comment-parser.js +36 -2
  20. package/lib/linter/linter.js +183 -82
  21. package/lib/options.js +24 -3
  22. package/lib/rule-tester/flat-rule-tester.js +113 -25
  23. package/lib/rule-tester/rule-tester.js +176 -23
  24. package/lib/rules/array-bracket-newline.js +3 -0
  25. package/lib/rules/array-bracket-spacing.js +3 -0
  26. package/lib/rules/array-callback-return.js +175 -25
  27. package/lib/rules/array-element-newline.js +3 -0
  28. package/lib/rules/arrow-parens.js +3 -0
  29. package/lib/rules/arrow-spacing.js +3 -0
  30. package/lib/rules/block-spacing.js +3 -0
  31. package/lib/rules/brace-style.js +3 -0
  32. package/lib/rules/comma-dangle.js +3 -0
  33. package/lib/rules/comma-spacing.js +3 -0
  34. package/lib/rules/comma-style.js +3 -0
  35. package/lib/rules/computed-property-spacing.js +3 -0
  36. package/lib/rules/consistent-return.js +32 -7
  37. package/lib/rules/constructor-super.js +37 -14
  38. package/lib/rules/dot-location.js +3 -0
  39. package/lib/rules/eol-last.js +3 -0
  40. package/lib/rules/for-direction.js +38 -24
  41. package/lib/rules/func-call-spacing.js +3 -0
  42. package/lib/rules/function-call-argument-newline.js +3 -0
  43. package/lib/rules/function-paren-newline.js +3 -0
  44. package/lib/rules/generator-star-spacing.js +3 -0
  45. package/lib/rules/getter-return.js +33 -8
  46. package/lib/rules/implicit-arrow-linebreak.js +3 -0
  47. package/lib/rules/indent.js +3 -0
  48. package/lib/rules/index.js +1 -0
  49. package/lib/rules/jsx-quotes.js +3 -0
  50. package/lib/rules/key-spacing.js +3 -0
  51. package/lib/rules/keyword-spacing.js +3 -0
  52. package/lib/rules/linebreak-style.js +3 -0
  53. package/lib/rules/lines-around-comment.js +3 -0
  54. package/lib/rules/lines-between-class-members.js +95 -7
  55. package/lib/rules/logical-assignment-operators.js +31 -3
  56. package/lib/rules/max-len.js +3 -0
  57. package/lib/rules/max-statements-per-line.js +3 -0
  58. package/lib/rules/multiline-ternary.js +3 -0
  59. package/lib/rules/new-parens.js +3 -0
  60. package/lib/rules/newline-per-chained-call.js +3 -0
  61. package/lib/rules/no-array-constructor.js +85 -6
  62. package/lib/rules/no-confusing-arrow.js +3 -0
  63. package/lib/rules/no-console.js +74 -2
  64. package/lib/rules/no-extra-parens.js +3 -0
  65. package/lib/rules/no-extra-semi.js +3 -0
  66. package/lib/rules/no-fallthrough.js +42 -14
  67. package/lib/rules/no-floating-decimal.js +3 -0
  68. package/lib/rules/no-invalid-this.js +1 -1
  69. package/lib/rules/no-misleading-character-class.js +65 -15
  70. package/lib/rules/no-mixed-operators.js +3 -0
  71. package/lib/rules/no-mixed-spaces-and-tabs.js +3 -0
  72. package/lib/rules/no-multi-spaces.js +3 -0
  73. package/lib/rules/no-multiple-empty-lines.js +3 -0
  74. package/lib/rules/no-new-object.js +7 -0
  75. package/lib/rules/no-object-constructor.js +117 -0
  76. package/lib/rules/no-promise-executor-return.js +157 -16
  77. package/lib/rules/no-prototype-builtins.js +90 -2
  78. package/lib/rules/no-restricted-imports.js +54 -31
  79. package/lib/rules/no-restricted-properties.js +15 -28
  80. package/lib/rules/no-tabs.js +3 -0
  81. package/lib/rules/no-this-before-super.js +38 -11
  82. package/lib/rules/no-trailing-spaces.js +3 -0
  83. package/lib/rules/no-unreachable-loop.js +47 -12
  84. package/lib/rules/no-unreachable.js +39 -10
  85. package/lib/rules/no-useless-return.js +35 -4
  86. package/lib/rules/no-whitespace-before-property.js +3 -0
  87. package/lib/rules/nonblock-statement-body-position.js +3 -0
  88. package/lib/rules/object-curly-newline.js +3 -0
  89. package/lib/rules/object-curly-spacing.js +3 -0
  90. package/lib/rules/object-property-newline.js +3 -0
  91. package/lib/rules/one-var-declaration-per-line.js +3 -0
  92. package/lib/rules/operator-linebreak.js +3 -0
  93. package/lib/rules/padded-blocks.js +3 -0
  94. package/lib/rules/padding-line-between-statements.js +3 -0
  95. package/lib/rules/quote-props.js +3 -0
  96. package/lib/rules/quotes.js +3 -0
  97. package/lib/rules/require-atomic-updates.js +21 -7
  98. package/lib/rules/rest-spread-spacing.js +3 -0
  99. package/lib/rules/semi-spacing.js +3 -0
  100. package/lib/rules/semi-style.js +3 -0
  101. package/lib/rules/semi.js +3 -0
  102. package/lib/rules/space-before-blocks.js +3 -0
  103. package/lib/rules/space-before-function-paren.js +3 -0
  104. package/lib/rules/space-in-parens.js +3 -0
  105. package/lib/rules/space-infix-ops.js +3 -0
  106. package/lib/rules/space-unary-ops.js +3 -0
  107. package/lib/rules/spaced-comment.js +3 -0
  108. package/lib/rules/switch-colon-spacing.js +3 -0
  109. package/lib/rules/template-curly-spacing.js +3 -0
  110. package/lib/rules/template-tag-spacing.js +3 -0
  111. package/lib/rules/utils/ast-utils.js +111 -1
  112. package/lib/rules/wrap-iife.js +3 -0
  113. package/lib/rules/wrap-regex.js +3 -0
  114. package/lib/rules/yield-star-spacing.js +3 -0
  115. package/lib/shared/severity.js +49 -0
  116. package/lib/source-code/source-code.js +329 -3
  117. package/messages/eslintrc-incompat.js +1 -1
  118. package/package.json +24 -17
@@ -0,0 +1,117 @@
1
+ /**
2
+ * @fileoverview Rule to disallow calls to the `Object` constructor without an argument
3
+ * @author Francesco Trotta
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //------------------------------------------------------------------------------
9
+ // Requirements
10
+ //------------------------------------------------------------------------------
11
+
12
+ const {
13
+ getVariableByName,
14
+ isArrowToken,
15
+ isStartOfExpressionStatement,
16
+ needsPrecedingSemicolon
17
+ } = require("./utils/ast-utils");
18
+
19
+ //------------------------------------------------------------------------------
20
+ // Rule Definition
21
+ //------------------------------------------------------------------------------
22
+
23
+ /** @type {import('../shared/types').Rule} */
24
+ module.exports = {
25
+ meta: {
26
+ type: "suggestion",
27
+
28
+ docs: {
29
+ description: "Disallow calls to the `Object` constructor without an argument",
30
+ recommended: false,
31
+ url: "https://eslint.org/docs/latest/rules/no-object-constructor"
32
+ },
33
+
34
+ hasSuggestions: true,
35
+
36
+ schema: [],
37
+
38
+ messages: {
39
+ preferLiteral: "The object literal notation {} is preferable.",
40
+ useLiteral: "Replace with '{{replacement}}'.",
41
+ useLiteralAfterSemicolon: "Replace with '{{replacement}}', add preceding semicolon."
42
+ }
43
+ },
44
+
45
+ create(context) {
46
+
47
+ const sourceCode = context.sourceCode;
48
+
49
+ /**
50
+ * Determines whether or not an object literal that replaces a specified node needs to be enclosed in parentheses.
51
+ * @param {ASTNode} node The node to be replaced.
52
+ * @returns {boolean} Whether or not parentheses around the object literal are required.
53
+ */
54
+ function needsParentheses(node) {
55
+ if (isStartOfExpressionStatement(node)) {
56
+ return true;
57
+ }
58
+
59
+ const prevToken = sourceCode.getTokenBefore(node);
60
+
61
+ if (prevToken && isArrowToken(prevToken)) {
62
+ return true;
63
+ }
64
+
65
+ return false;
66
+ }
67
+
68
+ /**
69
+ * Reports on nodes where the `Object` constructor is called without arguments.
70
+ * @param {ASTNode} node The node to evaluate.
71
+ * @returns {void}
72
+ */
73
+ function check(node) {
74
+ if (node.callee.type !== "Identifier" || node.callee.name !== "Object" || node.arguments.length) {
75
+ return;
76
+ }
77
+
78
+ const variable = getVariableByName(sourceCode.getScope(node), "Object");
79
+
80
+ if (variable && variable.identifiers.length === 0) {
81
+ let replacement;
82
+ let fixText;
83
+ let messageId = "useLiteral";
84
+
85
+ if (needsParentheses(node)) {
86
+ replacement = "({})";
87
+ if (needsPrecedingSemicolon(sourceCode, node)) {
88
+ fixText = ";({})";
89
+ messageId = "useLiteralAfterSemicolon";
90
+ } else {
91
+ fixText = "({})";
92
+ }
93
+ } else {
94
+ replacement = fixText = "{}";
95
+ }
96
+
97
+ context.report({
98
+ node,
99
+ messageId: "preferLiteral",
100
+ suggest: [
101
+ {
102
+ messageId,
103
+ data: { replacement },
104
+ fix: fixer => fixer.replaceText(node, fixText)
105
+ }
106
+ ]
107
+ });
108
+ }
109
+ }
110
+
111
+ return {
112
+ CallExpression: check,
113
+ NewExpression: check
114
+ };
115
+
116
+ }
117
+ };
@@ -10,6 +10,7 @@
10
10
  //------------------------------------------------------------------------------
11
11
 
12
12
  const { findVariable } = require("@eslint-community/eslint-utils");
13
+ const astUtils = require("./utils/ast-utils");
13
14
 
14
15
  //------------------------------------------------------------------------------
15
16
  // Helpers
@@ -59,6 +60,78 @@ function isPromiseExecutor(node, scope) {
59
60
  isGlobalReference(parent.callee, getOuterScope(scope));
60
61
  }
61
62
 
63
+ /**
64
+ * Checks if the given node is a void expression.
65
+ * @param {ASTNode} node The node to check.
66
+ * @returns {boolean} - `true` if the node is a void expression
67
+ */
68
+ function expressionIsVoid(node) {
69
+ return node.type === "UnaryExpression" && node.operator === "void";
70
+ }
71
+
72
+ /**
73
+ * Fixes the linting error by prepending "void " to the given node
74
+ * @param {Object} sourceCode context given by context.sourceCode
75
+ * @param {ASTNode} node The node to fix.
76
+ * @param {Object} fixer The fixer object provided by ESLint.
77
+ * @returns {Array<Object>} - An array of fix objects to apply to the node.
78
+ */
79
+ function voidPrependFixer(sourceCode, node, fixer) {
80
+
81
+ const requiresParens =
82
+
83
+ // prepending `void ` will fail if the node has a lower precedence than void
84
+ astUtils.getPrecedence(node) < astUtils.getPrecedence({ type: "UnaryExpression", operator: "void" }) &&
85
+
86
+ // check if there are parentheses around the node to avoid redundant parentheses
87
+ !astUtils.isParenthesised(sourceCode, node);
88
+
89
+ // avoid parentheses issues
90
+ const returnOrArrowToken = sourceCode.getTokenBefore(
91
+ node,
92
+ node.parent.type === "ArrowFunctionExpression"
93
+ ? astUtils.isArrowToken
94
+
95
+ // isReturnToken
96
+ : token => token.type === "Keyword" && token.value === "return"
97
+ );
98
+
99
+ const firstToken = sourceCode.getTokenAfter(returnOrArrowToken);
100
+
101
+ const prependSpace =
102
+
103
+ // is return token, as => allows void to be adjacent
104
+ returnOrArrowToken.value === "return" &&
105
+
106
+ // If two tokens (return and "(") are adjacent
107
+ returnOrArrowToken.range[1] === firstToken.range[0];
108
+
109
+ return [
110
+ fixer.insertTextBefore(firstToken, `${prependSpace ? " " : ""}void ${requiresParens ? "(" : ""}`),
111
+ fixer.insertTextAfter(node, requiresParens ? ")" : "")
112
+ ];
113
+ }
114
+
115
+ /**
116
+ * Fixes the linting error by `wrapping {}` around the given node's body.
117
+ * @param {Object} sourceCode context given by context.sourceCode
118
+ * @param {ASTNode} node The node to fix.
119
+ * @param {Object} fixer The fixer object provided by ESLint.
120
+ * @returns {Array<Object>} - An array of fix objects to apply to the node.
121
+ */
122
+ function curlyWrapFixer(sourceCode, node, fixer) {
123
+
124
+ // https://github.com/eslint/eslint/pull/17282#issuecomment-1592795923
125
+ const arrowToken = sourceCode.getTokenBefore(node.body, astUtils.isArrowToken);
126
+ const firstToken = sourceCode.getTokenAfter(arrowToken);
127
+ const lastToken = sourceCode.getLastToken(node);
128
+
129
+ return [
130
+ fixer.insertTextBefore(firstToken, "{"),
131
+ fixer.insertTextAfter(lastToken, "}")
132
+ ];
133
+ }
134
+
62
135
  //------------------------------------------------------------------------------
63
136
  // Rule Definition
64
137
  //------------------------------------------------------------------------------
@@ -74,10 +147,27 @@ module.exports = {
74
147
  url: "https://eslint.org/docs/latest/rules/no-promise-executor-return"
75
148
  },
76
149
 
77
- schema: [],
150
+ hasSuggestions: true,
151
+
152
+ schema: [{
153
+ type: "object",
154
+ properties: {
155
+ allowVoid: {
156
+ type: "boolean",
157
+ default: false
158
+ }
159
+ },
160
+ additionalProperties: false
161
+ }],
78
162
 
79
163
  messages: {
80
- returnsValue: "Return values from promise executor functions cannot be read."
164
+ returnsValue: "Return values from promise executor functions cannot be read.",
165
+
166
+ // arrow and function suggestions
167
+ prependVoid: "Prepend `void` to the expression.",
168
+
169
+ // only arrow suggestions
170
+ wrapBraces: "Wrap the expression in `{}`."
81
171
  }
82
172
  },
83
173
 
@@ -85,26 +175,55 @@ module.exports = {
85
175
 
86
176
  let funcInfo = null;
87
177
  const sourceCode = context.sourceCode;
88
-
89
- /**
90
- * Reports the given node.
91
- * @param {ASTNode} node Node to report.
92
- * @returns {void}
93
- */
94
- function report(node) {
95
- context.report({ node, messageId: "returnsValue" });
96
- }
178
+ const {
179
+ allowVoid = false
180
+ } = context.options[0] || {};
97
181
 
98
182
  return {
99
183
 
100
184
  onCodePathStart(_, node) {
101
185
  funcInfo = {
102
186
  upper: funcInfo,
103
- shouldCheck: functionTypesToCheck.has(node.type) && isPromiseExecutor(node, sourceCode.getScope(node))
187
+ shouldCheck:
188
+ functionTypesToCheck.has(node.type) &&
189
+ isPromiseExecutor(node, sourceCode.getScope(node))
104
190
  };
105
191
 
106
- if (funcInfo.shouldCheck && node.type === "ArrowFunctionExpression" && node.expression) {
107
- report(node.body);
192
+ if (// Is a Promise executor
193
+ funcInfo.shouldCheck &&
194
+ node.type === "ArrowFunctionExpression" &&
195
+ node.expression &&
196
+
197
+ // Except void
198
+ !(allowVoid && expressionIsVoid(node.body))
199
+ ) {
200
+ const suggest = [];
201
+
202
+ // prevent useless refactors
203
+ if (allowVoid) {
204
+ suggest.push({
205
+ messageId: "prependVoid",
206
+ fix(fixer) {
207
+ return voidPrependFixer(sourceCode, node.body, fixer);
208
+ }
209
+ });
210
+ }
211
+
212
+ // Do not suggest wrapping an unnamed FunctionExpression in braces as that would be invalid syntax.
213
+ if (!(node.body.type === "FunctionExpression" && !node.body.id)) {
214
+ suggest.push({
215
+ messageId: "wrapBraces",
216
+ fix(fixer) {
217
+ return curlyWrapFixer(sourceCode, node, fixer);
218
+ }
219
+ });
220
+ }
221
+
222
+ context.report({
223
+ node: node.body,
224
+ messageId: "returnsValue",
225
+ suggest
226
+ });
108
227
  }
109
228
  },
110
229
 
@@ -113,9 +232,31 @@ module.exports = {
113
232
  },
114
233
 
115
234
  ReturnStatement(node) {
116
- if (funcInfo.shouldCheck && node.argument) {
117
- report(node);
235
+ if (!(funcInfo.shouldCheck && node.argument)) {
236
+ return;
118
237
  }
238
+
239
+ // node is `return <expression>`
240
+ if (!allowVoid) {
241
+ context.report({ node, messageId: "returnsValue" });
242
+ return;
243
+ }
244
+
245
+ if (expressionIsVoid(node.argument)) {
246
+ return;
247
+ }
248
+
249
+ // allowVoid && !expressionIsVoid
250
+ context.report({
251
+ node,
252
+ messageId: "returnsValue",
253
+ suggest: [{
254
+ messageId: "prependVoid",
255
+ fix(fixer) {
256
+ return voidPrependFixer(sourceCode, node.argument, fixer);
257
+ }
258
+ }]
259
+ });
119
260
  }
120
261
  };
121
262
  }
@@ -10,6 +10,37 @@
10
10
 
11
11
  const astUtils = require("./utils/ast-utils");
12
12
 
13
+ //------------------------------------------------------------------------------
14
+ // Helpers
15
+ //------------------------------------------------------------------------------
16
+
17
+ /**
18
+ * Returns true if the node or any of the objects
19
+ * to the left of it in the member/call chain is optional.
20
+ *
21
+ * e.g. `a?.b`, `a?.b.c`, `a?.()`, `a()?.()`
22
+ * @param {ASTNode} node The expression to check
23
+ * @returns {boolean} `true` if there is a short-circuiting optional `?.`
24
+ * in the same option chain to the left of this call or member expression,
25
+ * or the node itself is an optional call or member `?.`.
26
+ */
27
+ function isAfterOptional(node) {
28
+ let leftNode;
29
+
30
+ if (node.type === "MemberExpression") {
31
+ leftNode = node.object;
32
+ } else if (node.type === "CallExpression") {
33
+ leftNode = node.callee;
34
+ } else {
35
+ return false;
36
+ }
37
+ if (node.optional) {
38
+ return true;
39
+ }
40
+ return isAfterOptional(leftNode);
41
+ }
42
+
43
+
13
44
  //------------------------------------------------------------------------------
14
45
  // Rule Definition
15
46
  //------------------------------------------------------------------------------
@@ -25,10 +56,13 @@ module.exports = {
25
56
  url: "https://eslint.org/docs/latest/rules/no-prototype-builtins"
26
57
  },
27
58
 
59
+ hasSuggestions: true,
60
+
28
61
  schema: [],
29
62
 
30
63
  messages: {
31
- prototypeBuildIn: "Do not access Object.prototype method '{{prop}}' from target object."
64
+ prototypeBuildIn: "Do not access Object.prototype method '{{prop}}' from target object.",
65
+ callObjectPrototype: "Call Object.prototype.{{prop}} explicitly."
32
66
  }
33
67
  },
34
68
 
@@ -59,7 +93,61 @@ module.exports = {
59
93
  messageId: "prototypeBuildIn",
60
94
  loc: callee.property.loc,
61
95
  data: { prop: propName },
62
- node
96
+ node,
97
+ suggest: [
98
+ {
99
+ messageId: "callObjectPrototype",
100
+ data: { prop: propName },
101
+ fix(fixer) {
102
+ const sourceCode = context.sourceCode;
103
+
104
+ /*
105
+ * A call after an optional chain (e.g. a?.b.hasOwnProperty(c))
106
+ * must be fixed manually because the call can be short-circuited
107
+ */
108
+ if (isAfterOptional(node)) {
109
+ return null;
110
+ }
111
+
112
+ /*
113
+ * A call on a ChainExpression (e.g. (a?.hasOwnProperty)(c)) will trigger
114
+ * no-unsafe-optional-chaining which should be fixed before this suggestion
115
+ */
116
+ if (node.callee.type === "ChainExpression") {
117
+ return null;
118
+ }
119
+
120
+ const objectVariable = astUtils.getVariableByName(sourceCode.getScope(node), "Object");
121
+
122
+ /*
123
+ * We can't use Object if the global Object was shadowed,
124
+ * or Object does not exist in the global scope for some reason
125
+ */
126
+ if (!objectVariable || objectVariable.scope.type !== "global" || objectVariable.defs.length > 0) {
127
+ return null;
128
+ }
129
+
130
+ let objectText = sourceCode.getText(callee.object);
131
+
132
+ if (astUtils.getPrecedence(callee.object) <= astUtils.getPrecedence({ type: "SequenceExpression" })) {
133
+ objectText = `(${objectText})`;
134
+ }
135
+
136
+ const openParenToken = sourceCode.getTokenAfter(
137
+ node.callee,
138
+ astUtils.isOpeningParenToken
139
+ );
140
+ const isEmptyParameters = node.arguments.length === 0;
141
+ const delim = isEmptyParameters ? "" : ", ";
142
+ const fixes = [
143
+ fixer.replaceText(callee, `Object.prototype.${propName}.call`),
144
+ fixer.insertTextAfter(openParenToken, objectText + delim)
145
+ ];
146
+
147
+ return fixes;
148
+ }
149
+ }
150
+ ]
63
151
  });
64
152
  }
65
153
  }
@@ -74,6 +74,9 @@ const arrayOfStringsOrObjectPatterns = {
74
74
  minItems: 1,
75
75
  uniqueItems: true
76
76
  },
77
+ importNamePattern: {
78
+ type: "string"
79
+ },
77
80
  message: {
78
81
  type: "string",
79
82
  minLength: 1
@@ -115,8 +118,12 @@ module.exports = {
115
118
  patternAndImportNameWithCustomMessage: "'{{importName}}' import from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
116
119
 
117
120
  patternAndEverything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern.",
121
+
122
+ patternAndEverythingWithRegexImportName: "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used.",
118
123
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
119
124
  patternAndEverythingWithCustomMessage: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted from being used by a pattern. {{customMessage}}",
125
+ // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
126
+ patternAndEverythingWithRegexImportNameAndCustomMessage: "* import is invalid because import name matching '{{importNames}}' pattern from '{{importSource}}' is restricted from being used. {{customMessage}}",
120
127
 
121
128
  everything: "* import is invalid because '{{importNames}}' from '{{importSource}}' is restricted.",
122
129
  // eslint-disable-next-line eslint-plugin/report-message-format -- Custom message might not end in a period
@@ -175,10 +182,11 @@ module.exports = {
175
182
  }
176
183
 
177
184
  // relative paths are supported for this rule
178
- const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive, importNames }) => ({
185
+ const restrictedPatternGroups = restrictedPatterns.map(({ group, message, caseSensitive, importNames, importNamePattern }) => ({
179
186
  matcher: ignore({ allowRelativePaths: true, ignorecase: !caseSensitive }).add(group),
180
187
  customMessage: message,
181
- importNames
188
+ importNames,
189
+ importNamePattern
182
190
  }));
183
191
 
184
192
  // if no imports are restricted we don't need to check
@@ -262,12 +270,13 @@ module.exports = {
262
270
 
263
271
  const customMessage = group.customMessage;
264
272
  const restrictedImportNames = group.importNames;
273
+ const restrictedImportNamePattern = group.importNamePattern ? new RegExp(group.importNamePattern, "u") : null;
265
274
 
266
275
  /*
267
276
  * If we are not restricting to any specific import names and just the pattern itself,
268
277
  * report the error and move on
269
278
  */
270
- if (!restrictedImportNames) {
279
+ if (!restrictedImportNames && !restrictedImportNamePattern) {
271
280
  context.report({
272
281
  node,
273
282
  messageId: customMessage ? "patternWithCustomMessage" : "patterns",
@@ -279,40 +288,54 @@ module.exports = {
279
288
  return;
280
289
  }
281
290
 
282
- if (importNames.has("*")) {
283
- const specifierData = importNames.get("*")[0];
284
-
285
- context.report({
286
- node,
287
- messageId: customMessage ? "patternAndEverythingWithCustomMessage" : "patternAndEverything",
288
- loc: specifierData.loc,
289
- data: {
290
- importSource,
291
- importNames: restrictedImportNames,
292
- customMessage
291
+ importNames.forEach((specifiers, importName) => {
292
+ if (importName === "*") {
293
+ const [specifier] = specifiers;
294
+
295
+ if (restrictedImportNames) {
296
+ context.report({
297
+ node,
298
+ messageId: customMessage ? "patternAndEverythingWithCustomMessage" : "patternAndEverything",
299
+ loc: specifier.loc,
300
+ data: {
301
+ importSource,
302
+ importNames: restrictedImportNames,
303
+ customMessage
304
+ }
305
+ });
306
+ } else {
307
+ context.report({
308
+ node,
309
+ messageId: customMessage ? "patternAndEverythingWithRegexImportNameAndCustomMessage" : "patternAndEverythingWithRegexImportName",
310
+ loc: specifier.loc,
311
+ data: {
312
+ importSource,
313
+ importNames: restrictedImportNamePattern,
314
+ customMessage
315
+ }
316
+ });
293
317
  }
294
- });
295
- }
296
318
 
297
- restrictedImportNames.forEach(importName => {
298
- if (!importNames.has(importName)) {
299
319
  return;
300
320
  }
301
321
 
302
- const specifiers = importNames.get(importName);
303
-
304
- specifiers.forEach(specifier => {
305
- context.report({
306
- node,
307
- messageId: customMessage ? "patternAndImportNameWithCustomMessage" : "patternAndImportName",
308
- loc: specifier.loc,
309
- data: {
310
- importSource,
311
- customMessage,
312
- importName
313
- }
322
+ if (
323
+ (restrictedImportNames && restrictedImportNames.includes(importName)) ||
324
+ (restrictedImportNamePattern && restrictedImportNamePattern.test(importName))
325
+ ) {
326
+ specifiers.forEach(specifier => {
327
+ context.report({
328
+ node,
329
+ messageId: customMessage ? "patternAndImportNameWithCustomMessage" : "patternAndImportName",
330
+ loc: specifier.loc,
331
+ data: {
332
+ importSource,
333
+ customMessage,
334
+ importName
335
+ }
336
+ });
314
337
  });
315
- });
338
+ }
316
339
  });
317
340
  }
318
341
 
@@ -142,40 +142,27 @@ module.exports = {
142
142
  }
143
143
  }
144
144
 
145
- /**
146
- * Checks property accesses in a destructuring assignment expression, e.g. `var foo; ({foo} = bar);`
147
- * @param {ASTNode} node An AssignmentExpression or AssignmentPattern node
148
- * @returns {undefined}
149
- */
150
- function checkDestructuringAssignment(node) {
151
- if (node.right.type === "Identifier") {
152
- const objectName = node.right.name;
153
-
154
- if (node.left.type === "ObjectPattern") {
155
- node.left.properties.forEach(property => {
156
- checkPropertyAccess(node.left, objectName, astUtils.getStaticPropertyName(property));
157
- });
158
- }
159
- }
160
- }
161
-
162
145
  return {
163
146
  MemberExpression(node) {
164
147
  checkPropertyAccess(node, node.object && node.object.name, astUtils.getStaticPropertyName(node));
165
148
  },
166
- VariableDeclarator(node) {
167
- if (node.init && node.init.type === "Identifier") {
168
- const objectName = node.init.name;
169
-
170
- if (node.id.type === "ObjectPattern") {
171
- node.id.properties.forEach(property => {
172
- checkPropertyAccess(node.id, objectName, astUtils.getStaticPropertyName(property));
173
- });
149
+ ObjectPattern(node) {
150
+ let objectName = null;
151
+
152
+ if (node.parent.type === "VariableDeclarator") {
153
+ if (node.parent.init && node.parent.init.type === "Identifier") {
154
+ objectName = node.parent.init.name;
155
+ }
156
+ } else if (node.parent.type === "AssignmentExpression" || node.parent.type === "AssignmentPattern") {
157
+ if (node.parent.right.type === "Identifier") {
158
+ objectName = node.parent.right.name;
174
159
  }
175
160
  }
176
- },
177
- AssignmentExpression: checkDestructuringAssignment,
178
- AssignmentPattern: checkDestructuringAssignment
161
+
162
+ node.properties.forEach(property => {
163
+ checkPropertyAccess(node, objectName, astUtils.getStaticPropertyName(property));
164
+ });
165
+ }
179
166
  };
180
167
  }
181
168
  };
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * @fileoverview Rule to check for tabs inside a file
3
3
  * @author Gyandeep Singh
4
+ * @deprecated in ESLint v8.53.0
4
5
  */
5
6
 
6
7
  "use strict";
@@ -19,6 +20,8 @@ const anyNonWhitespaceRegex = /\S/u;
19
20
  /** @type {import('../shared/types').Rule} */
20
21
  module.exports = {
21
22
  meta: {
23
+ deprecated: true,
24
+ replacedBy: [],
22
25
  type: "layout",
23
26
 
24
27
  docs: {