33 * SPDX-License-Identifier: Apache-2.0
44 */
55
6- import { AST_NODE_TYPES , ESLintUtils } from '@typescript-eslint/utils'
6+ import { AST_NODE_TYPES , ESLintUtils , TSESTree } from '@typescript-eslint/utils'
77import { Rule } from 'eslint'
88
99export const errMsg = 'Avoid using JSON.stringify within logging and error messages, prefer %O.'
1010
1111/**
1212 * Check if a given expression is a JSON.stringify call.
1313 */
14-
15- function isJsonStringifyCall ( node : any ) : boolean {
14+ function isJsonStringifyCall ( node : TSESTree . CallExpressionArgument ) : boolean {
1615 return (
1716 node . type === AST_NODE_TYPES . CallExpression &&
1817 node . callee . type === AST_NODE_TYPES . MemberExpression &&
@@ -23,16 +22,24 @@ function isJsonStringifyCall(node: any): boolean {
2322 )
2423}
2524
25+ function isTemplateWithStringifyCall ( node : TSESTree . CallExpressionArgument ) : boolean {
26+ return (
27+ node . type === AST_NODE_TYPES . TemplateLiteral &&
28+ node . expressions . some ( ( e : TSESTree . Expression ) => isJsonStringifyCall ( e ) )
29+ )
30+ }
31+
2632/**
2733 * Check if node is representing syntax of the form getLogger().f(msg) for some f and msg.
2834 *
2935 */
30- function isLoggerCall ( node : any ) : boolean {
36+ function isLoggerCall ( node : TSESTree . CallExpression ) : boolean {
3137 return (
32- node . callee . type === AST_NODE_TYPES . MemberExpression &&
33- node . callee . object . type === AST_NODE_TYPES . CallExpression &&
34- node . callee . object . callee . type === AST_NODE_TYPES . Identifier &&
35- node . callee . object . callee . name === 'getLogger'
38+ ( node . callee . type === AST_NODE_TYPES . MemberExpression &&
39+ node . callee . object . type === AST_NODE_TYPES . CallExpression &&
40+ node . callee . object . callee . type === AST_NODE_TYPES . Identifier &&
41+ node . callee . object . callee . name === 'getLogger' ) ||
42+ isDisguisedLoggerCall ( node )
3643 )
3744}
3845
@@ -45,13 +52,14 @@ function isLoggerCall(node: any): boolean {
4552 * 1) If the left side is an identifier including the word logger
4653 * 2) If the left side is a property of some object, including the word logger.
4754 */
48- function isDisguisedLoggerCall ( node : any ) : boolean {
55+ function isDisguisedLoggerCall ( node : TSESTree . CallExpression ) : boolean {
4956 return (
5057 ( node . callee . type === AST_NODE_TYPES . MemberExpression &&
5158 node . callee . object . type === AST_NODE_TYPES . Identifier &&
5259 node . callee . object . name . toLowerCase ( ) . includes ( 'logger' ) ) ||
5360 ( node . callee . type === AST_NODE_TYPES . MemberExpression &&
5461 node . callee . object . type === AST_NODE_TYPES . MemberExpression &&
62+ node . callee . object . property . type === AST_NODE_TYPES . Identifier &&
5563 node . callee . object . property . name . toLowerCase ( ) . includes ( 'logger' ) )
5664 )
5765}
@@ -72,30 +80,14 @@ export default ESLintUtils.RuleCreator.withoutDocs({
7280 defaultOptions : [ ] ,
7381 create ( context ) {
7482 return {
75- CallExpression ( node ) {
76- // Look for a getLogger().f() call or a disguised one, see isDisguisedLoggerCall for more info.
77- if ( isLoggerCall ( node ) || isDisguisedLoggerCall ( node ) ) {
78- // For each argument to the call above, check if it contains a JSON.stringify
79- node . arguments . forEach ( ( arg ) => {
80- // Check if arg itself if a JSON.stringify call
81- if ( isJsonStringifyCall ( arg ) ) {
82- return context . report ( {
83- node : node ,
84- messageId : 'errMsg' ,
85- } )
86- }
87- // Check if the arg contains a template ex. '${...}'
88- if ( arg . type === AST_NODE_TYPES . TemplateLiteral ) {
89- arg . expressions . forEach ( ( e ) => {
90- // Check the template for a JSON.stringify call.
91- if ( isJsonStringifyCall ( e ) ) {
92- return context . report ( {
93- node : node ,
94- messageId : 'errMsg' ,
95- } )
96- }
97- } )
98- }
83+ CallExpression ( node : TSESTree . CallExpression ) {
84+ if (
85+ isLoggerCall ( node ) &&
86+ node . arguments . some ( ( arg ) => isJsonStringifyCall ( arg ) || isTemplateWithStringifyCall ( arg ) )
87+ ) {
88+ return context . report ( {
89+ node : node ,
90+ messageId : 'errMsg' ,
9991 } )
10092 }
10193 } ,
0 commit comments