From 55a58ff0ae0434970537657ec2cb0bc7ab64c13d Mon Sep 17 00:00:00 2001 From: Brad Zacher Date: Sun, 8 Mar 2020 18:33:36 -0700 Subject: [PATCH] feat(eslint-plugin): [no-unsafe-call] support tagged templates (#1680) --- .../docs/rules/no-unsafe-call.md | 5 ++++ .../eslint-plugin/src/rules/no-unsafe-call.ts | 25 +++++++++++-------- .../tests/rules/no-unsafe-call.test.ts | 21 ++++++++++++++++ 3 files changed, 41 insertions(+), 10 deletions(-) diff --git a/packages/eslint-plugin/docs/rules/no-unsafe-call.md b/packages/eslint-plugin/docs/rules/no-unsafe-call.md index 7a9cdb79f54..3c18b7c1ee2 100644 --- a/packages/eslint-plugin/docs/rules/no-unsafe-call.md +++ b/packages/eslint-plugin/docs/rules/no-unsafe-call.md @@ -21,6 +21,9 @@ nestedAny.prop['a'](); new anyVar(); new nestedAny.prop(); + +anyVar`foo`; +nestedAny.prop`foo`; ``` Examples of **correct** code for this rule: @@ -33,6 +36,8 @@ nestedAny.prop.a(); (() => {})(); new Map(); + +String.raw`foo`; ``` ## Related to diff --git a/packages/eslint-plugin/src/rules/no-unsafe-call.ts b/packages/eslint-plugin/src/rules/no-unsafe-call.ts index 906a82d53d2..42630181936 100644 --- a/packages/eslint-plugin/src/rules/no-unsafe-call.ts +++ b/packages/eslint-plugin/src/rules/no-unsafe-call.ts @@ -1,7 +1,7 @@ import { TSESTree } from '@typescript-eslint/experimental-utils'; import * as util from '../util'; -type MessageIds = 'unsafeCall' | 'unsafeNew'; +type MessageIds = 'unsafeCall' | 'unsafeNew' | 'unsafeTemplateTag'; export default util.createRule<[], MessageIds>({ name: 'no-unsafe-call', @@ -16,6 +16,7 @@ export default util.createRule<[], MessageIds>({ messages: { unsafeCall: 'Unsafe call of an any typed value', unsafeNew: 'Unsafe construction of an any type value', + unsafeTemplateTag: 'Unsafe any typed template tag', }, schema: [], }, @@ -25,14 +26,11 @@ export default util.createRule<[], MessageIds>({ const checker = program.getTypeChecker(); function checkCall( - node: - | TSESTree.CallExpression - | TSESTree.OptionalCallExpression - | TSESTree.NewExpression, - reportingNode: TSESTree.Expression = node.callee, - messageId: MessageIds = 'unsafeCall', + node: TSESTree.Node, + reportingNode: TSESTree.Node, + messageId: MessageIds, ): void { - const tsNode = esTreeNodeToTSNodeMap.get(node.callee); + const tsNode = esTreeNodeToTSNodeMap.get(node); const type = checker.getTypeAtLocation(tsNode); if (util.isTypeAnyType(type)) { context.report({ @@ -43,9 +41,16 @@ export default util.createRule<[], MessageIds>({ } return { - 'CallExpression, OptionalCallExpression': checkCall, + 'CallExpression, OptionalCallExpression'( + node: TSESTree.CallExpression | TSESTree.OptionalCallExpression, + ): void { + checkCall(node.callee, node.callee, 'unsafeCall'); + }, NewExpression(node): void { - checkCall(node, node, 'unsafeNew'); + checkCall(node.callee, node, 'unsafeNew'); + }, + 'TaggedTemplateExpression > *.tag'(node: TSESTree.Node): void { + checkCall(node, node, 'unsafeTemplateTag'); }, }; }, diff --git a/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts b/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts index b5fc6408ed6..1930db27326 100644 --- a/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts +++ b/packages/eslint-plugin/tests/rules/no-unsafe-call.test.ts @@ -19,6 +19,7 @@ ruleTester.run('no-unsafe-call', rule, { 'function foo(x?: { a: () => void }) { x?.a() }', 'function foo(x: { a?: () => void }) { x.a?.() }', 'new Map()', + 'String.raw`foo`', ], invalid: [ ...batchedSingleLineTests({ @@ -102,5 +103,25 @@ function foo(x: { a: any }) { new x.a() } }, ], }), + ...batchedSingleLineTests({ + code: ` +function foo(x: any) { x\`foo\` } +function foo(x: { tag: any }) { x.tag\`foo\` } + `, + errors: [ + { + messageId: 'unsafeTemplateTag', + line: 2, + column: 24, + endColumn: 25, + }, + { + messageId: 'unsafeTemplateTag', + line: 3, + column: 33, + endColumn: 38, + }, + ], + }), ], });