Transforming $.extend
CallExpression
node
1 step: find a visitor: {
CallExpression(path) {
// …
}
}
CallExpression
is $.extend
2 step: ensure that the Input:
$.extend({}, objA, objB);
^ ^^^^^^
Visitor:
const { callee, arguments: args } = path.node;
if (!t.isMemberExpression(callee)) {
return;
}
if (
callee.object.name === "$" &&
callee.property.name === "extend"
) {
// yes …
}
extend
helper
3 step: define the In order to actually extend two objects we are going to inject a helper function called extend
(and renamed to avoid an identifier collision).
The @babel/template
package provide a way to manage code snippets as a template.
Visitor:
const extendHelper = defineHelper(`
var ID = function(out) {
// …
return out;
};
`);
In the template we will renamed the ID
identifier, you can have the processed template by running: extendHelper({ ID: … });
.
extend
helper
4 step: injecting the Diff:
+var _extend = function (out) {
+ // …
+ return out;
+};
$.extend({}, objA, objB);
Visitor:
// Generate a safe identifier by looking to the current scope
const helperId = path.scope.generateUidIdentifier("extend");
// Process the template
const helper = extendHelper({ID: helperId});
// Inject it into the scope (before the call)
path.insertBefore([helper]);
$.extend
to call our helper
4 step: rename Now that we have our helper in the scope, we need to change the call to $.extend
to actually use it.
For simplicity we can override the entire callee
object with an identifier.
Diff:
var _extend = function (out) {
// …
return out;
};
-$.extend({}, objA, objB);
+_extend({}, objA, objB);
Visitor:
path.node.callee = helperId;