I've found now I'm trying to replace
an expression and I don't care whats in it.
in this example I've found the this.state.showMenu && this.handleMouseDown
portion in
<a
onMouseDown={this.state.showMenu && this.handleMouseDown}
>
I need to convert to:
<a
onMouseDown={this.state.showMenu ? this.handleMouseDown : undefined}
>
how can I do so without explicitly reconstructing the tree? I just want to do something like
path.replaceText("this.state.showMenu ? this.handleMouseDown : undefined")
Here's a transformer that does what you describe:
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source)
root
.find(j.JSXExpressionContainer)
.replaceWith(path => {
return j.jsxExpressionContainer(
j.conditionalExpression(
j.identifier(j(path.value.expression.left).toSource()),
j.identifier(j(path.value.expression.right).toSource()),
j.identifier('undefined')
)
)
})
return root.toSource()
}
See it in action here.
You can also just put arbitrary text in the JSXExpressionContainer
node:
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source)
root
.find(j.JSXExpressionContainer)
.replaceWith(path => {
return j.jsxExpressionContainer(
j.identifier('whatever you want')
)
})
return root.toSource()
}
See this example.
Finally, you don't even need to return a JSXExpressionContainer
.
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source)
root
.find(j.JSXExpressionContainer)
.replaceWith(path => {
return j.identifier("this isn't valid JS, but works just fine")
})
return root.toSource()
}
See the result here.