From ea6c5ec3a13392890b614ccaf61500ae3af721bb Mon Sep 17 00:00:00 2001 From: mdm317 Date: Sat, 23 Nov 2024 16:12:04 +0900 Subject: [PATCH 01/10] test : add testcase --- .../tests/rules/no-deprecated.test.ts | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts index ba4e27555657..62e7d3e9c6a9 100644 --- a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts +++ b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts @@ -205,21 +205,6 @@ ruleTester.run('no-deprecated', rule, { default as ts, } from 'typescript'; `, - - // TODO: Can anybody figure out how to get this to report on `b`? - // getContextualType retrieves the union type, but it has no symbol... - ` - interface AProps { - /** @deprecated */ - b: number | string; - } - - function A(props: AProps) { - return
; - } - - const a = ; - `, ` namespace A { /** @deprecated */ @@ -286,6 +271,30 @@ ruleTester.run('no-deprecated', rule, { `, ], invalid: [ + { + code: ` + interface AProps { + /** @deprecated */ + b: number | string; + } + + function A(props: AProps) { + return
; + } + + const a = ; + `, + errors: [ + { + column: 20, + data: { name: 'b' }, + endColumn: 21, + endLine: 11, + line: 11, + messageId: 'deprecated', + }, + ], + }, { code: ` /** @deprecated */ var a = undefined; @@ -2465,7 +2474,7 @@ ruleTester.run('no-deprecated', rule, { code: ` /** @deprecated */ declare function decorator(constructor: Function); - + @decorator export class Foo {} `, @@ -2500,5 +2509,18 @@ ruleTester.run('no-deprecated', rule, { }, ], }, + { + code: 'const a =
;', + errors: [ + { + column: 16, + data: { name: 'aria-grabbed', reason: 'in ARIA 1.1' }, + endColumn: 28, + endLine: 1, + line: 1, + messageId: 'deprecatedWithReason', + }, + ], + }, ], }); From a06f122b8039c1ced3275027668dd2e5c3b0b1b4 Mon Sep 17 00:00:00 2001 From: mdm317 Date: Sat, 23 Nov 2024 16:13:33 +0900 Subject: [PATCH 02/10] fix : check if a JSX attribute is deprecated --- .../eslint-plugin/src/rules/no-deprecated.ts | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/eslint-plugin/src/rules/no-deprecated.ts b/packages/eslint-plugin/src/rules/no-deprecated.ts index 4ee51d4a3835..0962e2e650b7 100644 --- a/packages/eslint-plugin/src/rules/no-deprecated.ts +++ b/packages/eslint-plugin/src/rules/no-deprecated.ts @@ -271,11 +271,32 @@ export default createRule({ ); } + function getJSXAttributeDeprecation( + openingElement: TSESTree.JSXOpeningElement, + node: IdentifierLike, + ): string | undefined { + if (openingElement.name.type !== AST_NODE_TYPES.JSXIdentifier) { + return; + } + const tsNode = services.esTreeNodeToTSNodeMap.get(openingElement.name); + const contextType = checker.getContextualType(tsNode); + if (!contextType) { + return; + } + const symbol = contextType.getProperty(node.name); + return getJsDocDeprecation(symbol); + } + function getDeprecationReason(node: IdentifierLike): string | undefined { const callLikeNode = getCallLikeNode(node); if (callLikeNode) { return getCallLikeDeprecation(callLikeNode); } + + if (node.parent.type === AST_NODE_TYPES.JSXAttribute) { + return getJSXAttributeDeprecation(node.parent.parent, node); + } + if (node.parent.type === AST_NODE_TYPES.Property) { return getJsDocDeprecation( services.getTypeAtLocation(node.parent.parent).getProperty(node.name), From ba379b42e218581734cd2d9a8803954ed0df9a8e Mon Sep 17 00:00:00 2001 From: mdm317 Date: Sat, 23 Nov 2024 16:24:55 +0900 Subject: [PATCH 03/10] test : fix text result --- packages/eslint-plugin/tests/rules/no-deprecated.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts index 62e7d3e9c6a9..62a3918febd9 100644 --- a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts +++ b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts @@ -286,9 +286,9 @@ ruleTester.run('no-deprecated', rule, { `, errors: [ { - column: 20, + column: 22, data: { name: 'b' }, - endColumn: 21, + endColumn: 23, endLine: 11, line: 11, messageId: 'deprecated', From 8b9066665d8582ab32f129248167c1cb28da4e78 Mon Sep 17 00:00:00 2001 From: mdm317 Date: Tue, 26 Nov 2024 19:03:32 +0900 Subject: [PATCH 04/10] fix : check all jsx names --- packages/eslint-plugin/src/rules/no-deprecated.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-deprecated.ts b/packages/eslint-plugin/src/rules/no-deprecated.ts index 0962e2e650b7..a6b479df4e61 100644 --- a/packages/eslint-plugin/src/rules/no-deprecated.ts +++ b/packages/eslint-plugin/src/rules/no-deprecated.ts @@ -275,11 +275,8 @@ export default createRule({ openingElement: TSESTree.JSXOpeningElement, node: IdentifierLike, ): string | undefined { - if (openingElement.name.type !== AST_NODE_TYPES.JSXIdentifier) { - return; - } const tsNode = services.esTreeNodeToTSNodeMap.get(openingElement.name); - const contextType = checker.getContextualType(tsNode); + const contextType = checker.getContextualType(tsNode as ts.Expression); if (!contextType) { return; } From 63afd1d03fea14b4cbbd12ae840b03e4a6edb867 Mon Sep 17 00:00:00 2001 From: mdm317 Date: Tue, 26 Nov 2024 19:03:53 +0900 Subject: [PATCH 05/10] test : add test case for all jsx name --- .../tests/rules/no-deprecated.test.ts | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts index 62a3918febd9..0ffa379ae1a2 100644 --- a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts +++ b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts @@ -2522,5 +2522,64 @@ ruleTester.run('no-deprecated', rule, { }, ], }, + { + code: ` + declare namespace JSX { + interface IntrinsicElements { + 'foo-bar:baz-bam': { + name: string; + /** + * @deprecated + */ + deprecatedProp: string; + }; + } + } + + const componentDashed = ; + `, + errors: [ + { + column: 59, + data: { name: 'deprecatedProp' }, + endColumn: 73, + endLine: 14, + line: 14, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + import * as React from 'react'; + + interface Props { + /** + * @deprecated + */ + deprecatedProp: string; + } + + interface Tab { + List: React.FC; + } + + const Tab: Tab = { + List: () =>
Hi
, + }; + + const anotherExample = ; + `, + errors: [ + { + column: 42, + data: { name: 'deprecatedProp' }, + endColumn: 56, + endLine: 19, + line: 19, + messageId: 'deprecated', + }, + ], + }, ], }); From e25b6a242b0fd47d40cc6f41f92d2c1ceda920a4 Mon Sep 17 00:00:00 2001 From: mdm317 Date: Thu, 28 Nov 2024 19:12:00 +0900 Subject: [PATCH 06/10] test : increase coverage --- packages/eslint-plugin/src/rules/no-deprecated.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-deprecated.ts b/packages/eslint-plugin/src/rules/no-deprecated.ts index a6b479df4e61..447ebe463f84 100644 --- a/packages/eslint-plugin/src/rules/no-deprecated.ts +++ b/packages/eslint-plugin/src/rules/no-deprecated.ts @@ -276,11 +276,11 @@ export default createRule({ node: IdentifierLike, ): string | undefined { const tsNode = services.esTreeNodeToTSNodeMap.get(openingElement.name); - const contextType = checker.getContextualType(tsNode as ts.Expression); - if (!contextType) { - return; - } - const symbol = contextType.getProperty(node.name); + + const symbol = checker + .getContextualType(tsNode as ts.Expression) + ?.getProperty(node.name); + return getJsDocDeprecation(symbol); } From 96f3b7640a39bbd77b9c745a7e4711ffef72a248 Mon Sep 17 00:00:00 2001 From: mdm317 Date: Fri, 29 Nov 2024 00:29:05 +0900 Subject: [PATCH 07/10] fix : type assertion for test coverage --- packages/eslint-plugin/src/rules/no-deprecated.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-deprecated.ts b/packages/eslint-plugin/src/rules/no-deprecated.ts index 447ebe463f84..1909b397f596 100644 --- a/packages/eslint-plugin/src/rules/no-deprecated.ts +++ b/packages/eslint-plugin/src/rules/no-deprecated.ts @@ -277,9 +277,12 @@ export default createRule({ ): string | undefined { const tsNode = services.esTreeNodeToTSNodeMap.get(openingElement.name); - const symbol = checker - .getContextualType(tsNode as ts.Expression) - ?.getProperty(node.name); + const contextualType = nullThrows( + checker.getContextualType(tsNode as ts.Expression), + 'Expected jsx opening element name to have contextualType', + ); + + const symbol = contextualType.getProperty(node.name); return getJsDocDeprecation(symbol); } From 3309db8dbb22255ab4f5f4ebb867781398aa1611 Mon Sep 17 00:00:00 2001 From: mdm317 Date: Fri, 29 Nov 2024 22:37:54 +0900 Subject: [PATCH 08/10] refactor : change variable name --- packages/eslint-plugin/src/rules/no-deprecated.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-deprecated.ts b/packages/eslint-plugin/src/rules/no-deprecated.ts index 1909b397f596..05a139e2ab1e 100644 --- a/packages/eslint-plugin/src/rules/no-deprecated.ts +++ b/packages/eslint-plugin/src/rules/no-deprecated.ts @@ -273,7 +273,7 @@ export default createRule({ function getJSXAttributeDeprecation( openingElement: TSESTree.JSXOpeningElement, - node: IdentifierLike, + propertyName: string, ): string | undefined { const tsNode = services.esTreeNodeToTSNodeMap.get(openingElement.name); @@ -282,7 +282,7 @@ export default createRule({ 'Expected jsx opening element name to have contextualType', ); - const symbol = contextualType.getProperty(node.name); + const symbol = contextualType.getProperty(propertyName); return getJsDocDeprecation(symbol); } @@ -294,7 +294,7 @@ export default createRule({ } if (node.parent.type === AST_NODE_TYPES.JSXAttribute) { - return getJSXAttributeDeprecation(node.parent.parent, node); + return getJSXAttributeDeprecation(node.parent.parent, node.name); } if (node.parent.type === AST_NODE_TYPES.Property) { From 63b00e17b2dfcde2ca45a8bbb50266fbedd335cd Mon Sep 17 00:00:00 2001 From: mdm317 Date: Sat, 7 Dec 2024 16:09:12 +0900 Subject: [PATCH 09/10] Update packages/eslint-plugin/src/rules/no-deprecated.ts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Josh Goldberg ✨ --- packages/eslint-plugin/src/rules/no-deprecated.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-plugin/src/rules/no-deprecated.ts b/packages/eslint-plugin/src/rules/no-deprecated.ts index 05a139e2ab1e..1a02d26fcde0 100644 --- a/packages/eslint-plugin/src/rules/no-deprecated.ts +++ b/packages/eslint-plugin/src/rules/no-deprecated.ts @@ -279,7 +279,7 @@ export default createRule({ const contextualType = nullThrows( checker.getContextualType(tsNode as ts.Expression), - 'Expected jsx opening element name to have contextualType', + 'Expected JSX opening element name to have contextualType', ); const symbol = contextualType.getProperty(propertyName); From ae9717e6b8b406c08e59fa83502d5fd49c0aaa44 Mon Sep 17 00:00:00 2001 From: mdm317 Date: Sat, 7 Dec 2024 16:28:50 +0900 Subject: [PATCH 10/10] Add a test case namespace and attribute are of type "any" "unknown" "error" --- .../tests/rules/no-deprecated.test.ts | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts index 28749fc41f2b..8bbbe83a0837 100644 --- a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts +++ b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts @@ -269,6 +269,49 @@ ruleTester.run('no-deprecated', rule, { } } `, + ` + declare namespace JSX {} + + ; + `, + ` + declare namespace JSX { + interface IntrinsicElements { + foo: any; + } + } + + ; + `, + ` + declare namespace JSX { + interface IntrinsicElements { + foo: unknown; + } + } + + ; + `, + ` + declare namespace JSX { + interface IntrinsicElements { + foo: { + bar: any; + }; + } + } + ; + `, + ` + declare namespace JSX { + interface IntrinsicElements { + foo: { + bar: unknown; + }; + } + } + ; + `, ], invalid: [ {