Codemod with jscodeshift - remove comma from import

1.4k views Asked by At

I'm trying to write a small codemod to refactor some of the code. Consider I've somethihng like this:

import { mod1, mod2, mod3 } from 'package1'
import localMod from 'package2'

and I wanted to change this to:

import { mod1, mod3 } from 'package1'
import * as mod2 from 'new-package'
import localMod from 'package2'

As a first step, I'm trying to remove mod2 from the 1st line of import which I did successfully, but I'm not able to remove the comma after mod1.

My code snippet so far look like this:

module.exports = function transformer(file, api) {
  const j = api.jscodeshift;
  const root = j(file.source);

  const reactApolloImports = root
    .find(j.ImportDeclaration)
    .filter(nodepath => nodepath.value.source.value === "package1")
    .find(j.Identifier)
    .forEach(nodepath => {
      if (nodepath.name === "imported" && nodepath.node.name === "mod2") {
        j(nodepath).remove();
      }
    });

  return root.toSource();
};

Please help.

2

There are 2 answers

0
ford04 On

Instead of searching for and removing j.Identifier inside j.ImportDeclaration, find their parent nodes by j.ImportSpecifier expression instead. If you remove these, you should be fine.

It is more understandable, if you paste your import { mod1, mod2, mod3 } from 'package1' statement into AST Explorer.

enter image description here

Code:

module.exports = function transformer(file, api) {
  const j = api.jscodeshift;
  const root = j(file.source);

  const reactApolloImports = root
    .find(j.ImportDeclaration)
    .filter(impDecNodePath => impDecNodePath.value.source.value === "package1")
    .forEach(impDecNodePathFiltered => {
      j(impDecNodePathFiltered)
        // find ImportSpecifier here instead of Identifier
        .find(j.ImportSpecifier)
        .forEach(impSpecNodePath => {
          if (impSpecNodePath.node.imported.name === "mod2") {
            j(impSpecNodePath).remove();
          }
        });
    });

  return root.toSource();
};

Changed output:

import { mod1, mod3 } from 'package1';
import localMod from 'package2'

Hope, it helps.

0
coderaiser On

You can use putout code transformer for this purpose, it make things much easier:

Here is the plugin you need, it is Replacer:

export const replace = () => ({
    'import {parse, compare, transform} from "putout"': `{
        import {parse, transform} from 'putout';
        import compare from '@putout/compare';
    }`,
}),

Also we will use a plugin @putout/plugin-remove-nested-blocks to remove additional blocks:

const replaceImports = {
    report: () => '',
    replace: () => ({
        'import {parse, compare, transform} from "putout"': `{
            import {parse, transform} from 'putout';
            import compare from '@putout/compare';
        }`,
    }),
};

const source = `
    import {parse, compare, transform} from 'putout';
`;

const {code} = putout(source, {
    plugins: [
        ['replaceImports', replaceImports],
        'remove-nested-blocks',
    ],
});

Result will be:

import {parse, transform} from 'putout';
import compare from '@putout/compare';

Here is how it looks with your example (with no remove-nested-blocks applied):

enter image description here

The main benefit is encapsulating work with AST so you can do more things faster and simpler.