diff --git a/packages/eslint-plugin/src/rules/no-deprecated.ts b/packages/eslint-plugin/src/rules/no-deprecated.ts index 71b333488b55..91b5755b8d3c 100644 --- a/packages/eslint-plugin/src/rules/no-deprecated.ts +++ b/packages/eslint-plugin/src/rules/no-deprecated.ts @@ -451,6 +451,15 @@ export default createRule({ return; } + // Computed identifier expressions are handled by checkMemberExpression + if ( + parent.type === AST_NODE_TYPES.MemberExpression && + parent.computed && + parent.property === node + ) { + return; + } + if (parent.type === AST_NODE_TYPES.ExportSpecifier) { // only deal with the alias (exported) side, not the local binding if (parent.exported !== node) { diff --git a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts index e5a0937f4264..81ad5c7516c9 100644 --- a/packages/eslint-plugin/tests/rules/no-deprecated.test.ts +++ b/packages/eslint-plugin/tests/rules/no-deprecated.test.ts @@ -45,8 +45,42 @@ ruleTester.run('no-deprecated', rule, { /** @deprecated */ c: 2, }; + a['b']; + `, + ` + const a = { + b: 1, + /** @deprecated */ c: 2, + }; + + a['b' + 'c']; + `, + ` + const a = { + b: 1, + /** @deprecated */ c: 2, + }; + + const key = 'b'; + + a[key]; + `, + ` + const a = { + b: 1, + /** @deprecated */ c: 2, + }; + a?.b; `, + ` + const a = { + b: 1, + /** @deprecated */ c: 2, + }; + + a?.['b']; + `, ` declare const a: { b: 1; @@ -55,6 +89,52 @@ ruleTester.run('no-deprecated', rule, { a.b; `, + ` + declare const a: { + b: 1; + /** @deprecated */ c: 2; + }; + + a['b']; + `, + ` + declare const a: { + b: 1; + /** @deprecated */ c: 2; + }; + + a[\`\${'b'}\`]; + `, + ` + declare const a: { + b: 1; + /** @deprecated */ c: 2; + }; + + const key = 'b'; + + a[\`\${key}\`]; + `, + ` + declare const a: { + /** @deprecated */ c: 1; + cc: 2; + }; + + const key = 'c'; + + a[\`\${key + key}\`]; + `, + ` + declare const a: { + /** @deprecated */ c: 1; + cc: 2; + }; + + const key = 'c'; + + a[\`\${key}\${key}\`]; + `, ` class A { b: 1; @@ -63,6 +143,41 @@ ruleTester.run('no-deprecated', rule, { new A().b; `, + ` + class A { + b: 1; + /** @deprecated */ c: 2; + } + + new A()['b']; + `, + ` + class A { + b: 1; + /** @deprecated */ c: 2; + } + const key = 'b'; + + new A()[b]; + `, + ` + class A { + c: 1; + } + class B { + /** @deprecated */ c: 2; + } + + new A()['c']; + `, + ` + class A { + b: () => {}; + /** @deprecated */ c: () => {}; + } + + new A()['b'](); + `, ` class A { accessor b: 1; @@ -71,6 +186,14 @@ ruleTester.run('no-deprecated', rule, { new A().b; `, + ` + class A { + accessor b: 1; + /** @deprecated */ accessor c: 2; + } + + new A()['b']; + `, ` declare class A { /** @deprecated */ @@ -80,6 +203,15 @@ ruleTester.run('no-deprecated', rule, { A.c; `, + ` + declare class A { + /** @deprecated */ + static b: string; + static c: string; + } + + A['c']; + `, ` declare class A { /** @deprecated */ @@ -89,6 +221,15 @@ ruleTester.run('no-deprecated', rule, { A.c; `, + ` + declare class A { + /** @deprecated */ + static accessor b: string; + static accessor c: string; + } + + A['c']; + `, ` namespace A { /** @deprecated */ @@ -98,6 +239,15 @@ ruleTester.run('no-deprecated', rule, { A.c; `, + ` + namespace A { + /** @deprecated */ + export const b = ''; + export const c = ''; + } + + A['c']; + `, ` enum A { /** @deprecated */ @@ -107,6 +257,15 @@ ruleTester.run('no-deprecated', rule, { A.c; `, + ` + enum A { + /** @deprecated */ + b = 'b', + c = 'c', + } + + A['c']; + `, ` function a(value: 'b' | undefined): void; /** @deprecated */ @@ -461,30 +620,6 @@ exists('/foo'); const c = a['b']; `, - { - code: ` - interface AllowedType { - /** @deprecated */ - prop: string; - } - - const obj: AllowedType = { - prop: 'test', - }; - - const value = obj['prop']; - `, - options: [ - { - allow: [ - { - from: 'file', - name: 'AllowedType', - }, - ], - }, - ], - }, ` const a = { /** @deprecated */ @@ -740,13 +875,13 @@ exists('/foo'); { code: ` /** @deprecated */ const a = { b: 1 }; - console.log(a); + a; `, errors: [ { - column: 21, + column: 9, data: { name: 'a' }, - endColumn: 22, + endColumn: 10, endLine: 3, line: 3, messageId: 'deprecated', @@ -791,13 +926,13 @@ exists('/foo'); { code: ` /** @deprecated */ const a = { b: 1 }; - console.log(a.b); + a.b; `, errors: [ { - column: 21, + column: 9, data: { name: 'a' }, - endColumn: 22, + endColumn: 10, endLine: 3, line: 3, messageId: 'deprecated', @@ -807,13 +942,45 @@ exists('/foo'); { code: ` /** @deprecated */ const a = { b: 1 }; - console.log(a?.b); + a['b']; `, errors: [ { - column: 21, + column: 9, data: { name: 'a' }, - endColumn: 22, + endColumn: 10, + endLine: 3, + line: 3, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + /** @deprecated */ const a = { b: 1 }; + a?.b; + `, + errors: [ + { + column: 9, + data: { name: 'a' }, + endColumn: 10, + endLine: 3, + line: 3, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + /** @deprecated */ const a = { b: 1 }; + a?.['b']; + `, + errors: [ + { + column: 9, + data: { name: 'a' }, + endColumn: 10, endLine: 3, line: 3, messageId: 'deprecated', @@ -868,6 +1035,22 @@ exists('/foo'); }, ], }, + { + code: ` + /** @deprecated */ const a = { b: { c: 1 } }; + a?.['b']?.['c']; + `, + errors: [ + { + column: 9, + data: { name: 'a' }, + endColumn: 10, + endLine: 3, + line: 3, + messageId: 'deprecated', + }, + ], + }, { code: ` const a = { @@ -886,6 +1069,43 @@ exists('/foo'); }, ], }, + { + code: ` + const a = { + /** @deprecated */ b: 1, + }; + const key = 'b'; + a[key]; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 6, + line: 6, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + const a = { + /** @deprecated */ b: { c: 1 }, + }; + a['b']['c']; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 5, + line: 5, + messageId: 'deprecated', + }, + ], + }, { code: ` declare const a: { @@ -1197,13 +1417,238 @@ exists('/foo'); declare const a: A; - const { b } = a; + const { b } = a; + `, + errors: [ + { + column: 17, + data: { name: 'b' }, + endColumn: 18, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b(): string; + } + + declare const a: A; + + a.b; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 12, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b(): string; + } + + declare const a: A; + const key = 'b'; + + a[key]; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 10, + line: 10, + messageId: 'deprecated', + }, + ], + }, + { + // only: true, + code: ` + declare class A { + /** @deprecated */ + b(): string; + } + + declare const a: A; + const key = 'b'; + + a[key](); + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 10, + line: 10, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b(): string; + } + + declare const a: A; + + a.b(); + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 12, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b: () => string; + } + + declare const a: A; + + a.b; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 12, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b: () => string; + } + + declare const a: A; + + a['b']; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b(): string; + } + + declare const a: A; + const key = 'b'; + + a[\`\${key}\`]; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 19, + endLine: 10, + line: 10, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + computed(): string; + } + + declare const a: A; + const k1 = 'comp'; + const k2 = 'uted'; + + a[\`\${k1}\${k2}\`]; + `, + errors: [ + { + column: 11, + data: { name: 'computed' }, + endColumn: 23, + endLine: 11, + line: 11, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b(): string; + } + + declare const a: A; + const c = \`\${a.b}\`; + `, + errors: [ + { + column: 24, + data: { name: 'b' }, + endColumn: 25, + endLine: 8, + line: 8, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + b: () => string; + } + + declare const a: A; + + a.b(); `, errors: [ { - column: 17, + column: 11, data: { name: 'b' }, - endColumn: 18, + endColumn: 12, endLine: 9, line: 9, messageId: 'deprecated', @@ -1214,18 +1659,18 @@ exists('/foo'); code: ` declare class A { /** @deprecated */ - b(): string; + b: () => string; } declare const a: A; - a.b; + a['b'](); `, errors: [ { column: 11, data: { name: 'b' }, - endColumn: 12, + endColumn: 14, endLine: 9, line: 9, messageId: 'deprecated', @@ -1234,9 +1679,9 @@ exists('/foo'); }, { code: ` - declare class A { + interface A { /** @deprecated */ - b(): string; + b: () => string; } declare const a: A; @@ -1256,44 +1701,46 @@ exists('/foo'); }, { code: ` - declare class A { + interface A { /** @deprecated */ b: () => string; } declare const a: A; + const key = 'b'; - a.b; + a[key]; `, errors: [ { column: 11, data: { name: 'b' }, - endColumn: 12, - endLine: 9, - line: 9, + endColumn: 14, + endLine: 10, + line: 10, messageId: 'deprecated', }, ], }, { code: ` - declare class A { + interface A { /** @deprecated */ b: () => string; } declare const a: A; + const key = 'b'; - a.b(); + a[key](); `, errors: [ { column: 11, data: { name: 'b' }, - endColumn: 12, - endLine: 9, - line: 9, + endColumn: 14, + endLine: 10, + line: 10, messageId: 'deprecated', }, ], @@ -1307,13 +1754,13 @@ exists('/foo'); declare const a: A; - a.b(); + a['b'](); `, errors: [ { column: 11, data: { name: 'b' }, - endColumn: 12, + endColumn: 14, endLine: 9, line: 9, messageId: 'deprecated', @@ -1387,6 +1834,26 @@ exists('/foo'); }, ], }, + { + code: ` + declare class A { + /** @deprecated */ + static b: string; + } + + A['b']; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 7, + line: 7, + messageId: 'deprecated', + }, + ], + }, { code: ` declare const a: { @@ -1407,6 +1874,26 @@ exists('/foo'); }, ], }, + { + code: ` + declare const a: { + /** @deprecated */ + b: string; + }; + + a['b']; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 7, + line: 7, + messageId: 'deprecated', + }, + ], + }, { code: ` interface A { @@ -1579,6 +2066,26 @@ exists('/foo'); }, ], }, + { + code: ` + namespace A { + /** @deprecated */ + export const b = ''; + } + + A['b']; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 7, + line: 7, + messageId: 'deprecated', + }, + ], + }, { code: ` export namespace A { @@ -1619,6 +2126,26 @@ exists('/foo'); }, ], }, + { + code: ` + namespace A { + /** @deprecated */ + export function b() {} + } + + A['b'](); + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 7, + line: 7, + messageId: 'deprecated', + }, + ], + }, { code: ` namespace assert { @@ -1705,6 +2232,48 @@ exists('/foo'); }, ], }, + { + code: ` + enum A { + /** @deprecated */ + a, + } + + const key = 'a'; + + A[key]; + `, + errors: [ + { + column: 11, + data: { name: 'a' }, + endColumn: 14, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + enum A { + /** @deprecated */ + a, + } + + A['a']; + `, + errors: [ + { + column: 11, + data: { name: 'a' }, + endColumn: 14, + endLine: 7, + line: 7, + messageId: 'deprecated', + }, + ], + }, { code: ` /** @deprecated */ @@ -3059,6 +3628,28 @@ exists('/foo'); declare const a: A; + a['b']; + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare class A { + /** @deprecated */ + accessor b: () => string; + } + + declare const a: A; + a.b(); `, errors: [ @@ -3072,6 +3663,28 @@ exists('/foo'); }, ], }, + { + code: ` + declare class A { + /** @deprecated */ + accessor b: () => string; + } + + declare const a: A; + + a['b'](); + `, + errors: [ + { + column: 11, + data: { name: 'b' }, + endColumn: 14, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, { code: ` class A { @@ -3245,6 +3858,31 @@ exists('/foo'); }, ], }, + { + code: ` + declare const Keys: { + a: 1; + }; + + const a = { + /** @deprecated reason for deprecation */ + [1]: 'string', + }; + + const key = Keys.a; + const c = a[key]; + `, + errors: [ + { + column: 21, + data: { name: '1', reason: 'reason for deprecation' }, + endColumn: 24, + endLine: 12, + line: 12, + messageId: 'deprecatedWithReason', + }, + ], + }, { code: ` const a = { @@ -3286,6 +3924,50 @@ exists('/foo'); }, ], }, + { + code: ` + declare function x(): 'b'; + + const a = { + /** @deprecated */ + b: 'string', + }; + + const c = a[x()]; + `, + errors: [ + { + column: 21, + data: { name: 'b' }, + endColumn: 24, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, + { + code: ` + declare const x: { y: 'b' }; + + const a = { + /** @deprecated */ + b: 'string', + }; + + const c = a[x.y]; + `, + errors: [ + { + column: 21, + data: { name: 'b' }, + endColumn: 24, + endLine: 9, + line: 9, + messageId: 'deprecated', + }, + ], + }, { code: ` import { deprecatedFunction } from './deprecated';