I have this AST explorer snippet which almost lets me do what I want, which is to turn this:
function bar() {return 42;}
var baz = {}
import 'get-outta-here';
into
import 'get-outta-here';
function wrap() {
function bar() {return 42;}
var baz = {}
}();
i.e. wrap all top-level statements and declarations except the import
ones. However, my jscodeshift transform is buggy in a way I can't understand.
I suspect my wrapping logic is off: root.get().value.program.body
sounds hacky.
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source);
const wrapper = j(j.expressionStatement(
j.callExpression(
j.functionExpression(
j.identifier('foo'), [],
j.blockStatement(root.get().value.program.body)
), []), []));
const nodes = root.find(j.ImportDeclaration).nodes();
root.find(j.ImportDeclaration).remove();
// wraps, but doesn't re-add the import at top-level
return wrapper.toSource();
// fails
// return wrapper.find(j.Statement).at(0).insertBefore(nodes).toSource();
// moves it to the beginning, but no wrap
return root.find(j.Statement).at(0).insertBefore(nodes).toSource();
}
Got it. Just use j.program
to put a proper "Program" AST in wrapper
.
export default function transformer(file, api) {
const j = api.jscodeshift;
const root = j(file.source);
const wrapper = j(
j.program([
j.expressionStatement(
j.callExpression(
j.functionExpression(
j.identifier("foo"),
[],
j.blockStatement(root.get().value.program.body)
),
[]
),
[]
)
])
);
const imports = root.find(j.ImportDeclaration);
const nodes = imports.nodes();
imports.remove();
return wrapper.find(j.Statement).at(0).insertBefore(nodes).toSource();
}