From c97cc372cbae2d428fa4609eeda894b46e971826 Mon Sep 17 00:00:00 2001 From: Milos Djermanovic Date: Thu, 19 Mar 2020 21:00:28 +0100 Subject: [PATCH] Fix: remove type arguments in prefer-object-spread (fixes #13058) --- lib/rules/prefer-object-spread.js | 4 +- .../object-assign-with-generic-1.js | 343 ++++++++++++++++++ .../object-assign-with-generic-2.js | 198 ++++++++++ tests/lib/rules/prefer-object-spread.js | 53 ++- 4 files changed, 595 insertions(+), 3 deletions(-) create mode 100644 tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-1.js create mode 100644 tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-2.js diff --git a/lib/rules/prefer-object-spread.js b/lib/rules/prefer-object-spread.js index 1344433f52f..ab252c73ae3 100644 --- a/lib/rules/prefer-object-spread.js +++ b/lib/rules/prefer-object-spread.js @@ -181,8 +181,8 @@ function defineFixer(node, sourceCode) { const leftParen = sourceCode.getTokenAfter(node.callee, isOpeningParenToken); const rightParen = sourceCode.getLastToken(node); - // Remove the callee `Object.assign` - yield fixer.remove(node.callee); + // Remove everything before the opening paren: callee `Object.assign`, type arguments, and whitespace between the callee and the paren. + yield fixer.removeRange([node.range[0], leftParen.range[0]]); // Replace the parens of argument list to braces. if (needsParens(node, sourceCode)) { diff --git a/tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-1.js b/tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-1.js new file mode 100644 index 00000000000..1981f50857a --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-1.js @@ -0,0 +1,343 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser@2.24.0 + * Source code: + * const obj = Object.assign<{}, Record>({}, getObject()); + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "VariableDeclaration", + declarations: [ + { + type: "VariableDeclarator", + id: { + type: "Identifier", + name: "obj", + range: [6, 9], + loc: { start: { line: 1, column: 6 }, end: { line: 1, column: 9 } } + }, + init: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "Identifier", + name: "Object", + range: [12, 18], + loc: { + start: { line: 1, column: 12 }, + end: { line: 1, column: 18 } + } + }, + property: { + type: "Identifier", + name: "assign", + range: [19, 25], + loc: { + start: { line: 1, column: 19 }, + end: { line: 1, column: 25 } + } + }, + computed: false, + optional: false, + range: [12, 25], + loc: { + start: { line: 1, column: 12 }, + end: { line: 1, column: 25 } + } + }, + arguments: [ + { + type: "ObjectExpression", + properties: [], + range: [56, 58], + loc: { + start: { line: 1, column: 56 }, + end: { line: 1, column: 58 } + } + }, + { + type: "CallExpression", + callee: { + type: "Identifier", + name: "getObject", + range: [60, 69], + loc: { + start: { line: 1, column: 60 }, + end: { line: 1, column: 69 } + } + }, + arguments: [], + optional: false, + range: [60, 71], + loc: { + start: { line: 1, column: 60 }, + end: { line: 1, column: 71 } + } + } + ], + optional: false, + range: [12, 72], + loc: { + start: { line: 1, column: 12 }, + end: { line: 1, column: 72 } + }, + typeParameters: { + type: "TSTypeParameterInstantiation", + range: [25, 55], + params: [ + { + type: "TSTypeLiteral", + members: [], + range: [26, 28], + loc: { + start: { line: 1, column: 26 }, + end: { line: 1, column: 28 } + } + }, + { + type: "TSTypeReference", + typeName: { + type: "Identifier", + name: "Record", + range: [30, 36], + loc: { + start: { line: 1, column: 30 }, + end: { line: 1, column: 36 } + } + }, + typeParameters: { + type: "TSTypeParameterInstantiation", + range: [36, 54], + params: [ + { + type: "TSStringKeyword", + range: [37, 43], + loc: { + start: { line: 1, column: 37 }, + end: { line: 1, column: 43 } + } + }, + { + type: "TSArrayType", + elementType: { + type: "TSStringKeyword", + range: [45, 51], + loc: { + start: { line: 1, column: 45 }, + end: { line: 1, column: 51 } + } + }, + range: [45, 53], + loc: { + start: { line: 1, column: 45 }, + end: { line: 1, column: 53 } + } + } + ], + loc: { + start: { line: 1, column: 36 }, + end: { line: 1, column: 54 } + } + }, + range: [30, 54], + loc: { + start: { line: 1, column: 30 }, + end: { line: 1, column: 54 } + } + } + ], + loc: { + start: { line: 1, column: 25 }, + end: { line: 1, column: 55 } + } + } + }, + range: [6, 72], + loc: { start: { line: 1, column: 6 }, end: { line: 1, column: 72 } } + } + ], + kind: "const", + range: [0, 73], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 73 } } + } + ], + sourceType: "script", + range: [0, 73], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 73 } }, + tokens: [ + { + type: "Keyword", + value: "const", + range: [0, 5], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 5 } } + }, + { + type: "Identifier", + value: "obj", + range: [6, 9], + loc: { start: { line: 1, column: 6 }, end: { line: 1, column: 9 } } + }, + { + type: "Punctuator", + value: "=", + range: [10, 11], + loc: { start: { line: 1, column: 10 }, end: { line: 1, column: 11 } } + }, + { + type: "Identifier", + value: "Object", + range: [12, 18], + loc: { start: { line: 1, column: 12 }, end: { line: 1, column: 18 } } + }, + { + type: "Punctuator", + value: ".", + range: [18, 19], + loc: { start: { line: 1, column: 18 }, end: { line: 1, column: 19 } } + }, + { + type: "Identifier", + value: "assign", + range: [19, 25], + loc: { start: { line: 1, column: 19 }, end: { line: 1, column: 25 } } + }, + { + type: "Punctuator", + value: "<", + range: [25, 26], + loc: { start: { line: 1, column: 25 }, end: { line: 1, column: 26 } } + }, + { + type: "Punctuator", + value: "{", + range: [26, 27], + loc: { start: { line: 1, column: 26 }, end: { line: 1, column: 27 } } + }, + { + type: "Punctuator", + value: "}", + range: [27, 28], + loc: { start: { line: 1, column: 27 }, end: { line: 1, column: 28 } } + }, + { + type: "Punctuator", + value: ",", + range: [28, 29], + loc: { start: { line: 1, column: 28 }, end: { line: 1, column: 29 } } + }, + { + type: "Identifier", + value: "Record", + range: [30, 36], + loc: { start: { line: 1, column: 30 }, end: { line: 1, column: 36 } } + }, + { + type: "Punctuator", + value: "<", + range: [36, 37], + loc: { start: { line: 1, column: 36 }, end: { line: 1, column: 37 } } + }, + { + type: "Identifier", + value: "string", + range: [37, 43], + loc: { start: { line: 1, column: 37 }, end: { line: 1, column: 43 } } + }, + { + type: "Punctuator", + value: ",", + range: [43, 44], + loc: { start: { line: 1, column: 43 }, end: { line: 1, column: 44 } } + }, + { + type: "Identifier", + value: "string", + range: [45, 51], + loc: { start: { line: 1, column: 45 }, end: { line: 1, column: 51 } } + }, + { + type: "Punctuator", + value: "[", + range: [51, 52], + loc: { start: { line: 1, column: 51 }, end: { line: 1, column: 52 } } + }, + { + type: "Punctuator", + value: "]", + range: [52, 53], + loc: { start: { line: 1, column: 52 }, end: { line: 1, column: 53 } } + }, + { + type: "Punctuator", + value: ">", + range: [53, 54], + loc: { start: { line: 1, column: 53 }, end: { line: 1, column: 54 } } + }, + { + type: "Punctuator", + value: ">", + range: [54, 55], + loc: { start: { line: 1, column: 54 }, end: { line: 1, column: 55 } } + }, + { + type: "Punctuator", + value: "(", + range: [55, 56], + loc: { start: { line: 1, column: 55 }, end: { line: 1, column: 56 } } + }, + { + type: "Punctuator", + value: "{", + range: [56, 57], + loc: { start: { line: 1, column: 56 }, end: { line: 1, column: 57 } } + }, + { + type: "Punctuator", + value: "}", + range: [57, 58], + loc: { start: { line: 1, column: 57 }, end: { line: 1, column: 58 } } + }, + { + type: "Punctuator", + value: ",", + range: [58, 59], + loc: { start: { line: 1, column: 58 }, end: { line: 1, column: 59 } } + }, + { + type: "Identifier", + value: "getObject", + range: [60, 69], + loc: { start: { line: 1, column: 60 }, end: { line: 1, column: 69 } } + }, + { + type: "Punctuator", + value: "(", + range: [69, 70], + loc: { start: { line: 1, column: 69 }, end: { line: 1, column: 70 } } + }, + { + type: "Punctuator", + value: ")", + range: [70, 71], + loc: { start: { line: 1, column: 70 }, end: { line: 1, column: 71 } } + }, + { + type: "Punctuator", + value: ")", + range: [71, 72], + loc: { start: { line: 1, column: 71 }, end: { line: 1, column: 72 } } + }, + { + type: "Punctuator", + value: ";", + range: [72, 73], + loc: { start: { line: 1, column: 72 }, end: { line: 1, column: 73 } } + } + ], + comments: [] +}); diff --git a/tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-2.js b/tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-2.js new file mode 100644 index 00000000000..8cac4784686 --- /dev/null +++ b/tests/fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-2.js @@ -0,0 +1,198 @@ +"use strict"; + +/** + * Parser: @typescript-eslint/parser@2.24.0 + * Source code: + * Object.assign<{}, A>({}, foo); + */ + +exports.parse = () => ({ + type: "Program", + body: [ + { + type: "ExpressionStatement", + expression: { + type: "CallExpression", + callee: { + type: "MemberExpression", + object: { + type: "Identifier", + name: "Object", + range: [0, 6], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 6 } } + }, + property: { + type: "Identifier", + name: "assign", + range: [7, 13], + loc: { start: { line: 1, column: 7 }, end: { line: 1, column: 13 } } + }, + computed: false, + optional: false, + range: [0, 13], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 13 } } + }, + arguments: [ + { + type: "ObjectExpression", + properties: [], + range: [21, 23], + loc: { + start: { line: 1, column: 21 }, + end: { line: 1, column: 23 } + } + }, + { + type: "Identifier", + name: "foo", + range: [25, 28], + loc: { + start: { line: 1, column: 25 }, + end: { line: 1, column: 28 } + } + } + ], + optional: false, + range: [0, 29], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 29 } }, + typeParameters: { + type: "TSTypeParameterInstantiation", + range: [13, 20], + params: [ + { + type: "TSTypeLiteral", + members: [], + range: [14, 16], + loc: { + start: { line: 1, column: 14 }, + end: { line: 1, column: 16 } + } + }, + { + type: "TSTypeReference", + typeName: { + type: "Identifier", + name: "A", + range: [18, 19], + loc: { + start: { line: 1, column: 18 }, + end: { line: 1, column: 19 } + } + }, + range: [18, 19], + loc: { + start: { line: 1, column: 18 }, + end: { line: 1, column: 19 } + } + } + ], + loc: { start: { line: 1, column: 13 }, end: { line: 1, column: 20 } } + } + }, + range: [0, 30], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 30 } } + } + ], + sourceType: "script", + range: [0, 30], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 30 } }, + tokens: [ + { + type: "Identifier", + value: "Object", + range: [0, 6], + loc: { start: { line: 1, column: 0 }, end: { line: 1, column: 6 } } + }, + { + type: "Punctuator", + value: ".", + range: [6, 7], + loc: { start: { line: 1, column: 6 }, end: { line: 1, column: 7 } } + }, + { + type: "Identifier", + value: "assign", + range: [7, 13], + loc: { start: { line: 1, column: 7 }, end: { line: 1, column: 13 } } + }, + { + type: "Punctuator", + value: "<", + range: [13, 14], + loc: { start: { line: 1, column: 13 }, end: { line: 1, column: 14 } } + }, + { + type: "Punctuator", + value: "{", + range: [14, 15], + loc: { start: { line: 1, column: 14 }, end: { line: 1, column: 15 } } + }, + { + type: "Punctuator", + value: "}", + range: [15, 16], + loc: { start: { line: 1, column: 15 }, end: { line: 1, column: 16 } } + }, + { + type: "Punctuator", + value: ",", + range: [16, 17], + loc: { start: { line: 1, column: 16 }, end: { line: 1, column: 17 } } + }, + { + type: "Identifier", + value: "A", + range: [18, 19], + loc: { start: { line: 1, column: 18 }, end: { line: 1, column: 19 } } + }, + { + type: "Punctuator", + value: ">", + range: [19, 20], + loc: { start: { line: 1, column: 19 }, end: { line: 1, column: 20 } } + }, + { + type: "Punctuator", + value: "(", + range: [20, 21], + loc: { start: { line: 1, column: 20 }, end: { line: 1, column: 21 } } + }, + { + type: "Punctuator", + value: "{", + range: [21, 22], + loc: { start: { line: 1, column: 21 }, end: { line: 1, column: 22 } } + }, + { + type: "Punctuator", + value: "}", + range: [22, 23], + loc: { start: { line: 1, column: 22 }, end: { line: 1, column: 23 } } + }, + { + type: "Punctuator", + value: ",", + range: [23, 24], + loc: { start: { line: 1, column: 23 }, end: { line: 1, column: 24 } } + }, + { + type: "Identifier", + value: "foo", + range: [25, 28], + loc: { start: { line: 1, column: 25 }, end: { line: 1, column: 28 } } + }, + { + type: "Punctuator", + value: ")", + range: [28, 29], + loc: { start: { line: 1, column: 28 }, end: { line: 1, column: 29 } } + }, + { + type: "Punctuator", + value: ";", + range: [29, 30], + loc: { start: { line: 1, column: 29 }, end: { line: 1, column: 30 } } + } + ], + comments: [] +}); diff --git a/tests/lib/rules/prefer-object-spread.js b/tests/lib/rules/prefer-object-spread.js index c2b32e15b19..91bf08a2f74 100644 --- a/tests/lib/rules/prefer-object-spread.js +++ b/tests/lib/rules/prefer-object-spread.js @@ -103,7 +103,18 @@ ruleTester.run("prefer-object-spread", rule, { } ] }, - + { + code: "Object.assign ({}, foo)", + output: "({ ...foo})", + errors: [ + { + messageId: "useSpreadMessage", + type: "CallExpression", + line: 1, + column: 1 + } + ] + }, { code: "Object.assign({}, { foo: 'bar' })", output: "({ foo: 'bar'})", @@ -473,6 +484,18 @@ ruleTester.run("prefer-object-spread", rule, { } ] }, + { + code: "let a = Object.assign ({}, a)", + output: "let a = { ...a}", + errors: [ + { + messageId: "useSpreadMessage", + type: "CallExpression", + line: 1, + column: 9 + } + ] + }, { code: "let a = Object.assign({ a: 1 }, b)", output: "let a = {a: 1, ...b}", @@ -940,6 +963,34 @@ ruleTester.run("prefer-object-spread", rule, { column: 1 } ] + }, + + // https://github.com/eslint/eslint/issues/13058 + { + code: "const obj = Object.assign<{}, Record>({}, getObject());", + output: "const obj = { ...getObject()};", + parser: require.resolve("../../fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-1"), + errors: [ + { + messageId: "useSpreadMessage", + type: "CallExpression", + line: 1, + column: 13 + } + ] + }, + { + code: "Object.assign<{}, A>({}, foo);", + output: "({ ...foo});", + parser: require.resolve("../../fixtures/parsers/typescript-parsers/object-assign-with-generic/object-assign-with-generic-2"), + errors: [ + { + messageId: "useSpreadMessage", + type: "CallExpression", + line: 1, + column: 1 + } + ] } ] });