From a3cbe6e7862f1c8002cfe3dc624f89edec1e3ba5 Mon Sep 17 00:00:00 2001 From: Toru Nagashima Date: Fri, 19 Jun 2020 07:35:23 +0900 Subject: [PATCH] update prefer-spread --- lib/rules/prefer-spread.js | 8 ++---- tests/lib/rules/prefer-spread.js | 46 ++++++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/lib/rules/prefer-spread.js b/lib/rules/prefer-spread.js index bcb0dc0dd4c1..d3c3c4d22972 100644 --- a/lib/rules/prefer-spread.js +++ b/lib/rules/prefer-spread.js @@ -18,17 +18,13 @@ const astUtils = require("./utils/ast-utils"); */ function isVariadicApplyCalling(node) { return ( - node.callee.type === "MemberExpression" && - node.callee.property.type === "Identifier" && - node.callee.property.name === "apply" && - node.callee.computed === false && + astUtils.isSpecificMemberAccess(node.callee, null, "apply") && node.arguments.length === 2 && node.arguments[1].type !== "ArrayExpression" && node.arguments[1].type !== "SpreadElement" ); } - /** * Checks whether or not `thisArg` is not changed by `.apply()`. * @param {ASTNode|null} expectedThis The node that is the owner of the applied function. @@ -75,7 +71,7 @@ module.exports = { return; } - const applied = node.callee.object; + const applied = astUtils.skipChainExpression(astUtils.skipChainExpression(node.callee).object); const expectedThis = (applied.type === "MemberExpression") ? applied.object : null; const thisArg = node.arguments[0]; diff --git a/tests/lib/rules/prefer-spread.js b/tests/lib/rules/prefer-spread.js index 580d7faeba9d..7f48d845f1b4 100644 --- a/tests/lib/rules/prefer-spread.js +++ b/tests/lib/rules/prefer-spread.js @@ -18,7 +18,7 @@ const { RuleTester } = require("../../../lib/rule-tester"); const errors = [{ messageId: "preferSpread", type: "CallExpression" }]; -const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 6 } }); +const ruleTester = new RuleTester({ parserOptions: { ecmaVersion: 2020 } }); ruleTester.run("prefer-spread", rule, { valid: [ @@ -39,7 +39,11 @@ ruleTester.run("prefer-spread", rule, { // ignores incomplete things. "foo.apply();", "obj.foo.apply();", - "obj.foo.apply(obj, ...args)" + "obj.foo.apply(obj, ...args)", + + // Optional chaining + "(a?.b).c.foo.apply(a?.b.c, args);", + "a?.b.c.foo.apply((a?.b).c, args);" ], invalid: [ { @@ -73,6 +77,44 @@ ruleTester.run("prefer-spread", rule, { { code: "[].concat.apply([\n/*empty*/\n], args);", errors + }, + + // Optional chaining + { + code: "foo.apply?.(undefined, args);", + errors + }, + { + code: "foo?.apply(undefined, args);", + errors + }, + { + code: "foo?.apply?.(undefined, args);", + errors + }, + { + code: "(foo?.apply)(undefined, args);", + errors + }, + { + code: "(foo?.apply)?.(undefined, args);", + errors + }, + { + code: "(obj?.foo).apply(obj, args);", + errors + }, + { + code: "a?.b.c.foo.apply(a?.b.c, args);", + errors + }, + { + code: "(a?.b.c).foo.apply(a?.b.c, args);", + errors + }, + { + code: "(a?.b).c.foo.apply((a?.b).c, args);", + errors } ] });