Skip to content

Commit 01ebbc8

Browse files
committed
🐛 fix: handle functions better
1 parent cda7d7a commit 01ebbc8

File tree

2 files changed

+56
-24
lines changed

2 files changed

+56
-24
lines changed

src/strict-jsx-conditionals.ts

Lines changed: 34 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,8 @@ module.exports = {
6363
}
6464
interface MakeFixFunctionArrayParams {
6565
tokens: TSESTree.Token[] | null
66-
preferBoolean?: Boolean
66+
preferBoolean?: boolean
67+
callExpression?: boolean
6768
}
6869

6970
type MakeFixFunctionReturnType =
@@ -77,32 +78,36 @@ module.exports = {
7778
const makeFixFunctionArray = ({
7879
tokens,
7980
preferBoolean,
81+
callExpression,
8082
}: MakeFixFunctionArrayParams): MakeFixFunctionArrayReturnType => {
8183
if (!tokens) {
8284
return null
8385
}
8486

8587
if (preferBoolean) {
8688
return (fixer: TSESLint.RuleFixer): TSESLint.RuleFix[] => {
87-
return tokens.map(token => {
88-
if (token.value === '!') {
89-
return fixer.remove(token)
90-
} else {
91-
return fixer.replaceText(token, `Boolean(${token.value})`)
92-
}
93-
})
89+
const rest = tokens
90+
.filter((t, i) => !(i < 2 && t.value === '!'))
91+
.map(x => x.value)
92+
.join('')
93+
const lastToken = tokens.pop()
94+
const newText = `Boolean(${rest})`
95+
if (!lastToken) {
96+
throw new Error('Error occurred during auto-fix')
97+
}
98+
return [
99+
...tokens.map(t => fixer.remove(t)),
100+
fixer.replaceText(lastToken, newText),
101+
]
94102
}
95103
} else {
96104
return (fixer: TSESLint.RuleFixer): TSESLint.RuleFix[] => {
97105
return tokens
98106
.map(token => {
99-
if (token.value === '(' || token.value === ')') {
100-
return fixer.remove(token)
101-
}
102-
if (token.value === 'Boolean') {
103-
return fixer.remove(token)
104-
}
105-
if (token.type === AST_TOKEN_TYPES.Identifier) {
107+
if (
108+
token.type === AST_TOKEN_TYPES.Identifier &&
109+
token.value !== 'Boolean'
110+
) {
106111
return fixer.insertTextBefore(token, '!!')
107112
}
108113
})
@@ -141,7 +146,10 @@ module.exports = {
141146
)
142147
) {
143148
const token = sourceCode.getFirstToken(exp.left)
144-
149+
let tokens: TSESTree.Token[] | null = null
150+
if (exp.left.type === AST_NODE_TYPES.CallExpression) {
151+
tokens = sourceCode.getTokens(exp.left)
152+
}
145153
context.report({
146154
node,
147155
loc: {
@@ -155,10 +163,16 @@ module.exports = {
155163
},
156164
},
157165
messageId: 'someId',
158-
fix: makeFixFunction({
159-
token,
160-
preferBoolean: options?.preferBoolean,
161-
}),
166+
fix: tokens
167+
? makeFixFunctionArray({
168+
tokens,
169+
preferBoolean: options?.preferBoolean,
170+
callExpression: true,
171+
})
172+
: makeFixFunction({
173+
token,
174+
preferBoolean: options?.preferBoolean,
175+
}),
162176
})
163177
}
164178

src/strict-ts-conditionals.test.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ ruleTester.run('boolean-jsx-conditionals', rule as any, {
2525
`
2626
const Component = ({check}: {check: string}) => (<div>{Boolean(check.length) && <p>Check</p>}</div>)
2727
`,
28+
`
29+
const Component = ({check}: {check: ()=>boolean}) => (<div>{check() && <p>Check</p>}</div>)
30+
`,
2831
],
2932

3033
invalid: [
@@ -43,6 +46,11 @@ ruleTester.run('boolean-jsx-conditionals', rule as any, {
4346
output: `const Component = ({check}: {check: boolean | string }) => (<div>{!!check && <p>Check</p>}</div>)`,
4447
errors: [{ messageId: 'someId' }],
4548
},
49+
{
50+
code: `const Component = ({check}: {check: ()=>string }) => (<div>{check() && <p>Check</p>}</div>)`,
51+
output: `const Component = ({check}: {check: ()=>string }) => (<div>{!!check() && <p>Check</p>}</div>)`,
52+
errors: [{ messageId: 'someId' }],
53+
},
4654
{
4755
code: `const Component = ({check}: {check: boolean | null }) => (<div>{check && <p>Check</p>}</div>)`,
4856
output: `const Component = ({check}: {check: boolean | null }) => (<div>{!!check && <p>Check</p>}</div>)`,
@@ -63,8 +71,18 @@ ruleTester.run('boolean-jsx-conditionals', rule as any, {
6371
options: [{ preferBoolean: true }],
6472
},
6573
{
66-
code: `const Component = ({check}: {check: boolean | null }) => (<div>{!!check && <p>Check</p>}</div>)`,
67-
output: `const Component = ({check}: {check: boolean | null }) => (<div>{Boolean(check) && <p>Check</p>}</div>)`,
74+
code: `const Component = ({check}: {check:(arg: string)=>string }) => (<div>{check('some') && <p>Check</p>}</div>)`,
75+
output: `const Component = ({check}: {check:(arg: string)=>string }) => (<div>{Boolean(check('some')) && <p>Check</p>}</div>)`,
76+
errors: [
77+
{
78+
messageId: 'someId',
79+
},
80+
],
81+
options: [{ preferBoolean: true }],
82+
},
83+
{
84+
code: `const Component = ({check}: {check: boolean | null }) => (<div>{!!check() && <p>Check</p>}</div>)`,
85+
output: `const Component = ({check}: {check: boolean | null }) => (<div>{Boolean(check()) && <p>Check</p>}</div>)`,
6886
errors: [
6987
{
7088
messageId: 'someId',
@@ -73,8 +91,8 @@ ruleTester.run('boolean-jsx-conditionals', rule as any, {
7391
options: [{ preferBoolean: true, normalize: true }],
7492
},
7593
{
76-
code: `const Component = ({check}: {check: boolean | null }) => (<div>{Boolean(check) && <p>Check</p>}</div>)`,
77-
output: `const Component = ({check}: {check: boolean | null }) => (<div>{!!check && <p>Check</p>}</div>)`,
94+
code: `const Component = ({check}: {check: boolean | null }) => (<div>{Boolean(check()) && <p>Check</p>}</div>)`,
95+
output: `const Component = ({check}: {check: boolean | null }) => (<div>{!!check() && <p>Check</p>}</div>)`,
7896
errors: [
7997
{
8098
messageId: 'someId',

0 commit comments

Comments
 (0)