Skip to content

Commit 1d29d22

Browse files
authored
fix: detect default this binding in Array.fromAsync callbacks (#20456)
1 parent 11644b1 commit 1d29d22

3 files changed

Lines changed: 44 additions & 7 deletions

File tree

lib/rules/utils/ast-utils.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,15 @@ function isArrayFromMethod(node) {
526526
return isSpecificMemberAccess(node, arrayOrTypedArrayPattern, "from");
527527
}
528528

529+
/**
530+
* Checks whether or not a node is `Array.fromAsync`.
531+
* @param {ASTNode} node A node to check.
532+
* @returns {boolean} Whether or not the node is a `Array.fromAsync`.
533+
*/
534+
function isArrayFromAsyncMethod(node) {
535+
return isSpecificMemberAccess(node, "Array", "fromAsync");
536+
}
537+
529538
/**
530539
* Checks whether or not a node is a method which expects a function as a first argument, and `thisArg` as a second argument.
531540
* @param {ASTNode} node A node to check.
@@ -1462,6 +1471,7 @@ module.exports = {
14621471
isLoop,
14631472
isInLoop,
14641473
isArrayFromMethod,
1474+
isArrayFromAsyncMethod,
14651475
isParenthesised,
14661476
createGlobalLinebreakMatcher,
14671477
equalTokens,
@@ -1793,7 +1803,10 @@ module.exports = {
17931803
isNullOrUndefined(parent.arguments[1])
17941804
);
17951805
}
1796-
if (isArrayFromMethod(parent.callee)) {
1806+
if (
1807+
isArrayFromMethod(parent.callee) ||
1808+
isArrayFromAsyncMethod(parent.callee)
1809+
) {
17971810
return (
17981811
parent.arguments.length !== 3 ||
17991812
parent.arguments[1] !== currentNode ||

tests/lib/rules/no-eval.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ ruleTester.run("no-eval", rule, {
135135
"array.findLast(function (x) { return this.eval.includes(x); }, { eval: ['foo', 'bar'] });",
136136
"callbacks.findLastIndex(function (cb) { return cb(this.eval); }, this);",
137137
"['1+1'].flatMap(function (str) { return this.eval(str); }, new Evaluator);",
138+
{
139+
code: "Array.fromAsync(values, async function (value) { return this.eval(await value); }, context);",
140+
languageOptions: { ecmaVersion: 2017 },
141+
},
138142

139143
// Allows indirect eval
140144
{ code: "(0, eval)('foo')", options: [{ allowIndirect: true }] },

tests/lib/rules/no-invalid-this.js

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -481,13 +481,13 @@ const patterns = [
481481
},
482482

483483
// Array methods.
484-
{
485-
code: "Array.from([], function() { console.log(this); z(x => console.log(x, this)); });",
484+
...["from", "fromAsync"].map(methodName => ({
485+
code: `Array.${methodName}([], function() { console.log(this); z(x => console.log(x, this)); });`,
486486
languageOptions: { ecmaVersion: 6 },
487487
errors,
488488
valid: [NORMAL],
489489
invalid: [USE_STRICT, IMPLIED_STRICT, MODULES],
490-
},
490+
})),
491491
...[
492492
"every",
493493
"filter",
@@ -506,12 +506,12 @@ const patterns = [
506506
valid: [NORMAL],
507507
invalid: [USE_STRICT, IMPLIED_STRICT, MODULES],
508508
})),
509-
{
510-
code: "Array.from([], function() { console.log(this); z(x => console.log(x, this)); }, obj);",
509+
...["from", "fromAsync"].map(methodName => ({
510+
code: `Array.${methodName}([], function() { console.log(this); z(x => console.log(x, this)); }, obj);`,
511511
languageOptions: { ecmaVersion: 6 },
512512
valid: [NORMAL, USE_STRICT, IMPLIED_STRICT, MODULES],
513513
invalid: [],
514-
},
514+
})),
515515
...[
516516
"every",
517517
"filter",
@@ -1123,6 +1123,17 @@ ruleTesterTypeScript.run("no-invalid-this", rule, {
11231123
);
11241124
`,
11251125

1126+
`
1127+
Array.fromAsync(
1128+
[],
1129+
function () {
1130+
console.log(this);
1131+
z(x => console.log(x, this));
1132+
},
1133+
obj,
1134+
);
1135+
`,
1136+
11261137
`
11271138
foo.every(function () {
11281139
console.log(this);
@@ -1606,6 +1617,15 @@ ruleTesterTypeScript.run("no-invalid-this", rule, {
16061617
},
16071618
{
16081619
code: `
1620+
Array.fromAsync([], function () {
1621+
console.log(this);
1622+
z(x => console.log(x, this));
1623+
});
1624+
`,
1625+
errors,
1626+
},
1627+
{
1628+
code: `
16091629
foo.every(function () {
16101630
console.log(this);
16111631
z(x => console.log(x, this));

0 commit comments

Comments
 (0)