So if I would need to change code like this:
var amazed = $(['foo', 'bar']).map(function(i, el){
return this + '!';
});
into Native like
var amazed = (['foo', 'bar']).map(function(el, i){
return el + '!';
});
I can do something like (https://astexplorer.net/#/0rIHMowCQf)
return j(file.source)
.find(j.Identifier).filter(ident => {
if (ident.node.name == '$') console.log(ident);
return ident.node.name == '$';
}).replaceWith('').toSource();
as a first step and that will delete the jQuery $
sign and just leave a ()
which can work, but feels like I am cheating since I am just giving a empty Identifier to the CallExpression. I still have to discover how to replace the order of the arguments.
Can js code shift be used for such cases, like transforming jQuery to Native, and eventually just:
var amazed = ['foo', 'bar'].map(function(el, i){
return el + '!';
});
You can absolute use jscodeshift for this. Just be aware of the limitations:
$
might refer to jQuery.There might be calls to jQuery's .map
function that look like
var foo = $(['foo', 'bar']);
foo.map(...);
which you probably won't be able to catch.
However, these might not be issues in your code base. Writing generic codemods is hard(er). Writing one that works for your specific codebase is easier.
I would to the following:
Find all CallExpression
's whose callee
is a MemberExpression
and that MemberExpression
has map
as its property and $(...)
as its object. You can also verify that the argument passed to $
is an array literal. That would again have the limitation that it wouldn't consider var foo = []; $(foo);
.
Then you can replace the the "inner" CallExpression
with its argument. Replacing the function parameters of the callback is simply to.
All of that together. All the checks are optional. The less strict the tests are, the more use cases you can cover, but the possibility for getting false positives will also be larger.
return j(file.source)
.find(j.CallExpression, {
callee: {
property: {
name: 'map'
},
// verify that we call map on $(...)
object: {
callee: {
name: '$',
},
// verify that the argument is an array literal
arguments: {
0: {
type: 'ArrayExpression'
}
},
}
},
})
.forEach(path => {
const jQueryArgument = path.node.callee.object.arguments[0];
// replace "inner" CallExpression with argument
path.node.callee.object = jQueryArgument;
// switch callback arguments
var callback = path.node.arguments[0];
callback.params.reverse();
})
.toSource();