Search code examples
javascriptbabeljsabstract-syntax-tree

How to remove parent property and function with babel transform?


Say I have this code

import someOtherFunction from 'whatever'

function testFunction(hello) {
  return someOtherFunction(hello.world.name)
}

I want to transform this to something like:

import someOtherFunction from 'whatever'

function testFunction(hello) {
  return world.name
}

Basically, I want to remove the hello property and the function wrapping them.

What I have achieved so far:

transformSync(code, {
  plugins: [
    function customPlugin() {
      return {
        visitor: {
          Identifier(path) {
            if (path.isIdentifier({ name: 'world' })) {
              if (
                path.parentPath.isMemberExpression()
                && path.parentPath.get('object').isIdentifier({ name: 'hello' })
              ) {
                path.parentPath.name = '' // remove hello property?
              }
            }
          }
        }
      }
    },
  ]
})

Solution

  • You can use replaceWith() to achieve transform you need:

    transformSync(code, {
      plugins: [
        function customPlugin() {
          return {
            visitor: {
              Identifier(path) {
                if (path.isIdentifier({ name: 'world' })) {
                  if (
                    path.parentPath.isMemberExpression()
                    && path.parentPath.get('object').isIdentifier({ name: 'hello' })
                  ) {
                       const objectPath = path.parentPath.parentPath.get('object');
                       const callExpressionPath = path.parentPath.parentPath.parentPath;
                
                       objectPath.replaceWith(path.node);
                       callExpressionPath.replaceWith(path.parentPath.parentPath.node);
                  }
                }
              }
            }
          }
        },
      ]
    })
    

    Here is playground: https://astexplorer.net/#/gist/25cddb49aaa339ac43f9ffe379b503ac/9f7c8c2f8e39f5164d39187a84fb8eb481f7780c

    You can also achieve it in a much simpler way, with the tool I'm working on: 🐊Putout. The transform will look this way:

    export const replace = () => ({
        '__(hello.world.name)': 'world.name',
    });
    

    Here is playground: https://putout.cloudcmd.io/#/gist/023465614b7ca1194ba6f3b22be3af7c/a17bc62c3cf10f823ba007d759ec3de3298b4a2d

    const source = `
        import someOtherFunction from 'whatever'
    
        function testFunction(hello) {
            return someOtherFunction(hello.world.name)
        }
    `;
    
    const {code} = putout(source, {
        plugins: [
            ['remove-hello', {
                report: () => `Remove 'hello'`,
                replace: () => ({
                    '__(hello.world.name)': 'world.name',
                }),
            }]
        ]
     });
     
     console.log(code);
    <script src="https://cdn.jsdelivr.net/npm/@putout/bundle@1.7/bundle/putout-iife.js"></script>