From 22f78d97486195f91a74bcf3570903200790fa83 Mon Sep 17 00:00:00 2001 From: yeonjuan Date: Tue, 19 Sep 2023 22:34:21 +0900 Subject: [PATCH] fix(eslint-plugin): [no-confusing-void-expression] handle unfixable cases --- .../src/rules/no-confusing-void-expression.ts | 25 ++++++ .../no-confusing-void-expression.test.ts | 84 ++++++++++++++++++- 2 files changed, 106 insertions(+), 3 deletions(-) diff --git a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts index 66ac9e28c512..3d6fdfd67016 100644 --- a/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts +++ b/packages/eslint-plugin/src/rules/no-confusing-void-expression.ts @@ -118,6 +118,9 @@ export default util.createRule({ node, messageId: 'invalidVoidExprArrow', fix(fixer) { + if (!canFix(arrowFunction)) { + return null; + } const arrowBody = arrowFunction.body; const arrowBodyText = sourceCode.getText(arrowBody); const newArrowBodyText = `{ ${arrowBodyText}; }`; @@ -160,6 +163,9 @@ export default util.createRule({ node, messageId: 'invalidVoidExprReturnLast', fix(fixer) { + if (!canFix(returnStmt)) { + return null; + } const returnValue = returnStmt.argument!; const returnValueText = sourceCode.getText(returnValue); let newReturnStmtText = `${returnValueText};`; @@ -334,5 +340,24 @@ export default util.createRule({ return ['(', '[', '`'].includes(startToken.value); } + + function canFix(node: TSESTree.Node): boolean { + const services = util.getParserServices(context); + + let targetNode: TSESTree.Node | null = null; + + if (node.type === AST_NODE_TYPES.ReturnStatement) { + targetNode = node.argument; + } else if (node.type === AST_NODE_TYPES.ArrowFunctionExpression) { + targetNode = node.body; + } + + if (targetNode) { + const type = util.getConstrainedTypeAtLocation(services, targetNode); + return tsutils.isTypeFlagSet(type, ts.TypeFlags.VoidLike); + } + + return true; + } }, }); diff --git a/packages/eslint-plugin/tests/rules/no-confusing-void-expression.test.ts b/packages/eslint-plugin/tests/rules/no-confusing-void-expression.test.ts index a6b5cab492ce..c03d89ed6a61 100644 --- a/packages/eslint-plugin/tests/rules/no-confusing-void-expression.test.ts +++ b/packages/eslint-plugin/tests/rules/no-confusing-void-expression.test.ts @@ -199,12 +199,25 @@ function notcool(input: string) { { code: 'foo => foo && console.log(foo);', errors: [{ line: 1, column: 15, messageId: 'invalidVoidExprArrow' }], - output: `foo => { foo && console.log(foo); };`, + }, + { + code: '(foo: undefined) => foo && console.log(foo);', + errors: [{ line: 1, column: 28, messageId: 'invalidVoidExprArrow' }], + output: `(foo: undefined) => { foo && console.log(foo); };`, }, { code: 'foo => foo || console.log(foo);', errors: [{ line: 1, column: 15, messageId: 'invalidVoidExprArrow' }], - output: `foo => { foo || console.log(foo); };`, + }, + { + code: '(foo: undefined) => foo || console.log(foo);', + errors: [{ line: 1, column: 28, messageId: 'invalidVoidExprArrow' }], + output: `(foo: undefined) => { foo || console.log(foo); };`, + }, + { + code: '(foo: void) => foo || console.log(foo);', + errors: [{ line: 1, column: 23, messageId: 'invalidVoidExprArrow' }], + output: `(foo: void) => { foo || console.log(foo); };`, }, { code: 'foo => (foo ? console.log(true) : console.log(false));', @@ -310,7 +323,72 @@ function notcool(input: string) { }; `, }, - + { + code: ` + const f = function () { + let num = 1; + return num ? console.log('foo') : num; + }; + `, + errors: [{ line: 4, column: 24, messageId: 'invalidVoidExprReturnLast' }], + }, + { + code: ` + const f = function () { + let undef = undefined; + return undef ? console.log('foo') : undef; + }; + `, + errors: [{ line: 4, column: 26, messageId: 'invalidVoidExprReturnLast' }], + output: ` + const f = function () { + let undef = undefined; + undef ? console.log('foo') : undef; + }; + `, + }, + { + code: ` + const f = function () { + let num = 1; + return num || console.log('foo'); + }; + `, + errors: [{ line: 4, column: 25, messageId: 'invalidVoidExprReturnLast' }], + }, + { + code: ` + const f = function () { + let bar = void 0; + return bar || console.log('foo'); + }; + `, + errors: [{ line: 4, column: 25, messageId: 'invalidVoidExprReturnLast' }], + output: ` + const f = function () { + let bar = void 0; + bar || console.log('foo'); + }; + `, + }, + { + code: ` + let num = 1; + const foo = () => (num ? console.log('foo') : num); + `, + errors: [{ line: 3, column: 34, messageId: 'invalidVoidExprArrow' }], + }, + { + code: ` + let bar = void 0; + const foo = () => (bar ? console.log('foo') : bar); + `, + errors: [{ line: 3, column: 34, messageId: 'invalidVoidExprArrow' }], + output: ` + let bar = void 0; + const foo = () => { bar ? console.log('foo') : bar; }; + `, + }, { options: [{ ignoreVoidOperator: true }], code: "return console.log('foo');",