jscodeshift icon indicating copy to clipboard operation
jscodeshift copied to clipboard

Better way to traverse nodes to find only direct descendants

Open drFabio opened this issue 3 years ago • 2 comments

What would be a good way to traverse down an object tree?

Consider the following file

// menu.js
const menu = {
  beverages: {
    soft: {
      water: 2,
      juice: 3,
    },
  },
  happyHour: {
    beverages: {
      soft: {
        water: 1,
        juice: 2,
      },
    },
  },
};

How could someone differentiate menu.beverages from menu.happyHour.beverages?

Doing the following codemod

// minimalExample.js
export default (fileInfo, api, options) => {
  const j = api.jscodeshift;

  const root = j(fileInfo.source);
  const rootPaths = root.find(j.VariableDeclarator, {
    id: { name: "menu" },
  });
  rootPaths
    .find(j.Property, { key: { name: "beverages" } })
    .replaceWith((nodePath) => {
      const { node } = nodePath;
      console.log(node);

      node.key.name = "theFoundBeverage";
      return node;
    });

  return root.toSource();
};

that can be run as

jscodeshift -t minimalExample.js  menu.js  -d -p  

Both beverages would become theFoundBeverage.

Modifying the beverages to have a filter that would traverse a path that would find the first non ObjectExpression node and compare with the root would make only the first one be modified

// minimalExample.js
export default (fileInfo, api, options) => {
  const j = api.jscodeshift;

  const root = j(fileInfo.source);
  const rootPaths = root.find(j.VariableDeclarator, {
    id: { name: "menu" },
  });
  rootPaths
    .find(j.Property, { key: { name: "beverages" } })
    .filter((path) => isDirectChildOfObject(rootPaths.get(0).node, path))
    .replaceWith((nodePath) => {
      const { node } = nodePath;
      console.log(node);

      node.key.name = "theFoundBeverage";
      return node;
    });

  return root.toSource();
};

function isDirectChildOfObject(parent, child) {
  let current = child.parentPath;
  // Ignoring object expressions
  while (current.node && current.node.type === "ObjectExpression") {
    current = current.parentPath;
  }

  return current.node === parent;
}

Is there a better way? I way to say "Given this path only consider if it is a direct child" ?

Thanks in advance

drFabio avatar Oct 06 '20 19:10 drFabio

did you figure it out?

sibelius avatar Jun 21 '22 18:06 sibelius

did you figure it out?

Not really , the problem just was solved good enough and I gave up...

drFabio avatar Jul 04 '22 10:07 drFabio