Repository: sindresorhus/eslint-plugin-unicorn (JavaScript)

Issue:
`no-array-for-each` should skip fix if second parameter is not an `Identifier`
<!-- ✨ Thanks for reporting a bug! ➡️ Please don't ignore this template -->

#1812 makes me realize that the following edge cases will cause runtime error by autofix.

```js
// The second parameter default value can be a reference from first parameter
array.forEach((element, index = element) => {})
array.forEach(({foo}, index = foo) => {})
```

Even if it's not an `AssignmentPattern`
```js
// The second parameter property value can be value from first parameter
array.forEach((element, {bar = element}) => {})
array.forEach(({foo}, {bar = foo}) => {})
```

If `array` is a real array, the second parameter should be a number, so we should only allow `Identifier`.

//cc @TimShilov


Discussion:
@fisker I'm happy to help on this one but I'm struggling to wrap my head around how tests work in this repo so I cannot come up with a failing test.

I've added these cases 
```js
'foo.forEach((bar, index = bar) => {})',
'foo.forEach(({bar}, {index = bar}) => {});',
```
... to snapshot invalid cases here
https://github.com/sindresorhus/eslint-plugin-unicorn/blob/166524a5613d9f0e27cb5bc505fe83d86ff9e7b2/test/no-array-for-each.mjs#L26-L28
 but the tests are still passing just fine.
 
 If you can push me in the right direction I can make a PR.
Just check the snapshots are expected.



Patch:
diff --git a/rules/no-array-for-each.js b/rules/no-array-for-each.js
index 8df8ee66ea..eb863f86be 100644
--- a/rules/no-array-for-each.js
+++ b/rules/no-array-for-each.js
@@ -351,6 +351,8 @@ function isFixable(callExpression, {scope, functionInfo, allIdentifiers, context
 		!(parameters.length === 1 || parameters.length === 2)
 		// `array.forEach((element = defaultValue) => {})`
 		|| (parameters.length === 1 && parameters[0].type === 'AssignmentPattern')
+		// https://github.com/sindresorhus/eslint-plugin-unicorn/issues/1814
+		|| (parameters.length === 2 && parameters[1].type !== 'Identifier')
 		|| parameters.some(({type, typeAnnotation}) => type === 'RestElement' || typeAnnotation)
 		|| !isFunctionParametersSafeToFix(callback, {scope, callExpression, allIdentifiers, context})
 	) {


Test patch:
diff --git a/test/no-array-for-each.mjs b/test/no-array-for-each.mjs
index 400965b490..1d16ba62cc 100644
--- a/test/no-array-for-each.mjs
+++ b/test/no-array-for-each.mjs
@@ -523,6 +523,10 @@ test.snapshot({
 				for (index of bar);
 			});
 		`,
+		'array.forEach((element, index = element) => {})',
+		'array.forEach(({foo}, index = foo) => {})',
+		'array.forEach((element, {bar = element}) => {})',
+		'array.forEach(({foo}, {bar = foo}) => {})',
 	],
 });
 
diff --git a/test/snapshots/no-array-for-each.mjs.md b/test/snapshots/no-array-for-each.mjs.md
index cb052a94d8..0337e67e2d 100644
--- a/test/snapshots/no-array-for-each.mjs.md
+++ b/test/snapshots/no-array-for-each.mjs.md
@@ -3537,12 +3537,6 @@ Generated by [AVA](https://avajs.dev).
 ## Invalid #196
       1 | foo.forEach((element, {bar: {bar: [index]}}) => {bar(element, index)})
 
-> Output
-
-    `␊
-      1 | for (const [{bar: {bar: [index]}}, element] of foo.entries()) {bar(element, index)}␊
-    `
-
 > Error 1/1
 
     `␊
@@ -3553,12 +3547,6 @@ Generated by [AVA](https://avajs.dev).
 ## Invalid #197
       1 | foo?.forEach((element, {bar: {bar: [index]}}) => {bar(element, index)})
 
-> Output
-
-    `␊
-      1 | if (foo) for (const [{bar: {bar: [index]}}, element] of foo.entries()) {bar(element, index)}␊
-    `
-
 > Error 1/1
 
     `␊
@@ -3569,12 +3557,6 @@ Generated by [AVA](https://avajs.dev).
 ## Invalid #198
       1 | foo.forEach((element = elementDefaultValue, index = indexDefaultValue) => {})
 
-> Output
-
-    `␊
-      1 | for (const [index = indexDefaultValue, element = elementDefaultValue] of foo.entries()) {}␊
-    `
-
 > Error 1/1
 
     `␊
@@ -3585,12 +3567,6 @@ Generated by [AVA](https://avajs.dev).
 ## Invalid #199
       1 | foo?.forEach((element = elementDefaultValue, index = indexDefaultValue) => {})
 
-> Output
-
-    `␊
-      1 | if (foo) for (const [index = indexDefaultValue, element = elementDefaultValue] of foo.entries()) {}␊
-    `
-
 > Error 1/1
 
     `␊
@@ -4966,3 +4942,43 @@ Generated by [AVA](https://avajs.dev).
       2 | 	for (index of bar);␊
       3 | });␊
     `
+
+## Invalid #268
+      1 | array.forEach((element, index = element) => {})
+
+> Error 1/1
+
+    `␊
+    > 1 | array.forEach((element, index = element) => {})␊
+        |       ^^^^^^^ Use \`for…of\` instead of \`.forEach(…)\`.␊
+    `
+
+## Invalid #269
+      1 | array.forEach(({foo}, index = foo) => {})
+
+> Error 1/1
+
+    `␊
+    > 1 | array.forEach(({foo}, index = foo) => {})␊
+        |       ^^^^^^^ Use \`for…of\` instead of \`.forEach(…)\`.␊
+    `
+
+## Invalid #270
+      1 | array.forEach((element, {bar = element}) => {})
+
+> Error 1/1
+
+    `␊
+    > 1 | array.forEach((element, {bar = element}) => {})␊
+        |       ^^^^^^^ Use \`for…of\` instead of \`.forEach(…)\`.␊
+    `
+
+## Invalid #271
+      1 | array.forEach(({foo}, {bar = foo}) => {})
+
+> Error 1/1
+
+    `␊
+    > 1 | array.forEach(({foo}, {bar = foo}) => {})␊
+        |       ^^^^^^^ Use \`for…of\` instead of \`.forEach(…)\`.␊
+    `
diff --git a/test/snapshots/no-array-for-each.mjs.snap b/test/snapshots/no-array-for-each.mjs.snap
index 9d44859e01..4d8097a871 100644
Binary files a/test/snapshots/no-array-for-each.mjs.snap and b/test/snapshots/no-array-for-each.mjs.snap differ