diff --git a/lib/rules/prefer-object-spread.js b/lib/rules/prefer-object-spread.js index bbcd88bee3d..00f5fb6d4c8 100644 --- a/lib/rules/prefer-object-spread.js +++ b/lib/rules/prefer-object-spread.js @@ -25,6 +25,36 @@ function hasArraySpread(node) { return node.arguments.some(arg => arg.type === "SpreadElement"); } +/** + * Determines whether the given node is an accessor property (getter/setter). + * @param {ASTNode} node Node to check. + * @returns {boolean} `true` if the node is a getter or a setter. + */ +function isAccessorProperty(node) { + return node.type === "Property" && + (node.kind === "get" || node.kind === "set"); +} + +/** + * Determines whether the given object expression node has accessor properties (getters/setters). + * @param {ASTNode} node `ObjectExpression` node to check. + * @returns {boolean} `true` if the node has at least one getter/setter. + */ +function hasAccessors(node) { + return node.properties.some(isAccessorProperty); +} + +/** + * Determines whether the given call expression node has object expression arguments with accessor properties (getters/setters). + * @param {ASTNode} node `CallExpression` node to check. + * @returns {boolean} `true` if the node has at least one argument that is an object expression with at least one getter/setter. + */ +function hasArgumentsWithAccessors(node) { + return node.arguments + .filter(arg => arg.type === "ObjectExpression") + .some(hasAccessors); +} + /** * Helper that checks if the node needs parentheses to be valid JS. * The default is to wrap the node in parentheses to avoid parsing errors. @@ -249,7 +279,11 @@ module.exports = { if ( node.arguments.length >= 1 && node.arguments[0].type === "ObjectExpression" && - !hasArraySpread(node) + !hasArraySpread(node) && + !( + node.arguments.length > 1 && + hasArgumentsWithAccessors(node) + ) ) { const messageId = node.arguments.length === 1 ? "useLiteralMessage" diff --git a/tests/lib/rules/prefer-object-spread.js b/tests/lib/rules/prefer-object-spread.js index 11c16d60cc3..9ec3cf630fd 100644 --- a/tests/lib/rules/prefer-object-spread.js +++ b/tests/lib/rules/prefer-object-spread.js @@ -59,7 +59,19 @@ ruleTester.run("prefer-object-spread", rule, { ` import { Object, Array } from 'globals'; Object.assign({ foo: 'bar' }); - ` + `, + + // ignore Object.assign() with > 1 arguments if any of the arguments is an object expression with a getter/setter + "Object.assign({ get a() {} }, {})", + "Object.assign({ set a(val) {} }, {})", + "Object.assign({ get a() {} }, foo)", + "Object.assign({ set a(val) {} }, foo)", + "Object.assign({ foo: 'bar', get a() {}, baz: 'quux' }, quuux)", + "Object.assign({ foo: 'bar', set a(val) {} }, { baz: 'quux' })", + "Object.assign({}, { get a() {} })", + "Object.assign({}, { set a(val) {} })", + "Object.assign({}, { foo: 'bar', get a() {} }, {})", + "Object.assign({ foo }, bar, {}, { baz: 'quux', set a(val) {}, quuux }, {})" ], invalid: [ @@ -834,6 +846,20 @@ ruleTester.run("prefer-object-spread", rule, { column: 1 } ] + }, + + // report Object.assign() with getters/setters if the function call has only 1 argument + { + code: "Object.assign({ get a() {}, set b(val) {} })", + output: "({get a() {}, set b(val) {}})", + errors: [ + { + messageId: "useLiteralMessage", + type: "CallExpression", + line: 1, + column: 1 + } + ] } ] });