From ad1467a055b938611114c9cb66f9b39a81e96431 Mon Sep 17 00:00:00 2001 From: Ronen Amiel Date: Tue, 14 Jan 2025 18:56:47 +0200 Subject: [PATCH] report on misused jsx spread attribute --- .../src/rules/no-misused-spread.ts | 5 +- .../tests/rules/no-misused-spread.test.ts | 175 ++++++++++++++++++ 2 files changed, 179 insertions(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-misused-spread.ts b/packages/eslint-plugin/src/rules/no-misused-spread.ts index 4fe980893616..17991adc6a49 100644 --- a/packages/eslint-plugin/src/rules/no-misused-spread.ts +++ b/packages/eslint-plugin/src/rules/no-misused-spread.ts @@ -99,7 +99,9 @@ export default createRule({ } } - function checkObjectSpread(node: TSESTree.SpreadElement): void { + function checkObjectSpread( + node: TSESTree.JSXSpreadAttribute | TSESTree.SpreadElement, + ): void { const type = getConstrainedTypeAtLocation(services, node.argument); if (typeMatchesSomeSpecifier(type, options.allow, services.program)) { @@ -175,6 +177,7 @@ export default createRule({ return { 'ArrayExpression > SpreadElement': checkArrayOrCallSpread, 'CallExpression > SpreadElement': checkArrayOrCallSpread, + JSXSpreadAttribute: checkObjectSpread, 'ObjectExpression > SpreadElement': checkObjectSpread, }; }, diff --git a/packages/eslint-plugin/tests/rules/no-misused-spread.test.ts b/packages/eslint-plugin/tests/rules/no-misused-spread.test.ts index 38ebeea2dcab..8701ea580daa 100644 --- a/packages/eslint-plugin/tests/rules/no-misused-spread.test.ts +++ b/packages/eslint-plugin/tests/rules/no-misused-spread.test.ts @@ -133,6 +133,32 @@ ruleTester.run('no-misused-spread', rule, { const o = { ...promiseLike }; `, + { + code: ` + const obj = { a: 1, b: 2 }; + const o =
; + `, + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + { + code: ` + declare const obj: { a: number; b: number } | any; + const o =
; + `, + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, { code: ` @@ -1493,5 +1519,154 @@ ruleTester.run('no-misused-spread', rule, { }, ], }, + + { + code: ` + const o =
; + `, + errors: [ + { + column: 24, + endColumn: 38, + line: 2, + messageId: 'noArraySpreadInObject', + }, + ], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + { + code: ` + class A {} + + const o =
; + `, + errors: [ + { + column: 24, + endColumn: 30, + line: 4, + messageId: 'noClassDeclarationSpreadInObject', + }, + ], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + { + code: ` + const o =
; + `, + errors: [ + { + column: 24, + endColumn: 39, + line: 2, + messageId: 'noClassInstanceSpreadInObject', + }, + ], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + { + code: ` + function f() {} + + const o =
; + `, + errors: [ + { + column: 24, + endColumn: 30, + line: 4, + messageId: 'noFunctionSpreadInObject', + }, + ], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + { + code: ` + const o =
; + `, + errors: [ + { + column: 24, + endColumn: 47, + line: 2, + messageId: 'noIterableSpreadInObject', + }, + ], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + { + code: ` + declare const map: Map; + + const o =
; + `, + errors: [ + { + column: 24, + endColumn: 32, + line: 4, + messageId: 'noMapSpreadInObject', + }, + ], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, + { + code: ` + const promise = new Promise(() => {}); + + const o =
; + `, + errors: [ + { + column: 24, + endColumn: 36, + line: 4, + messageId: 'noPromiseSpreadInObject', + }, + ], + languageOptions: { + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + }, + }, + }, ], });