How to wrap all toplevel statements and declarations except imports in jscodeshift?

560 views Asked by At

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 can wrap, and remove the imports, but I can't move them to the top.
  • I can move them to the top but not wrap

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();
}
1

There are 1 answers

1
joao On BEST ANSWER

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();
}