Замените все экземпляры определенного импорта через jscodeshift

хорошо, поэтому у меня есть код, который выглядит так:

      import { wait } from "@testing-library/react";

describe("MyTest", () => {
  it("should wait", async () => {
    await wait(() => {
      console.log("Done");
    });
  });
});

Я хочу изменить этот член импорта waitбыть waitFor. Я могу изменить это в AST так:

          source
      .find(j.ImportDeclaration)
      .filter((path) => path.node.source.value === "@testing-library/react")
      .find(j.ImportSpecifier)
      .filter((path) => path.node.imported.name === "wait")
      .replaceWith(j.importSpecifier(j.identifier("waitFor")))
      .toSource()

Однако выведенный код будет выглядеть следующим образом:

      import { waitFor } from "@testing-library/react";

describe("MyTest", () => {
  it("should wait", async () => {
    await wait(() => {
      console.log("Done");
    });
  });
});

Я ищу способ изменить все последующие использования этого импорта, чтобы они соответствовали новому имени.

Возможно ли это с помощью jscodeshift?

1 ответ

Вы можете сделать это, посетив все узлы, отфильтровав те с именем, на которое вы ориентируетесь («подождите»), и заменив их новыми узлами.

Чтобы найти соответствующие узлы, вы можете либо пройтись по коллекции, возвращаемой методом jscodeshift, и добавить туда свою логику, либо вы можете датьfind()второй аргумент. Это должен быть предикат, используемый для фильтрации:

      const isWaitExpression = (node) =>
    node.callee && node.callee.name === "wait";

// I've used "root" where you used "source"
root
    .find(j.CallExpression, isWaitExpression)

Затем вы можете заменить эти узлы наreplaceWith():

      const replaceExpression = (path, j) =>
    j.callExpression(j.identifier("waitFor"), path.node.arguments);

root
   .find(j.CallExpression, isWaitExpression)
   .replaceWith((path) => replaceExpression(path, j));

Это может показаться немного запутанным, но для созданияCallExpressionузел, вы вызываетеcallExpression()метод из API. Обратите внимание на кожух верблюда.

В целом преобразователь, который переименовывает «wait» из RTL в «waitFor» — как именованное объявление импорта, так и каждый экземпляр, где он вызывается в файле, — можно сделать следующим образом:

      const isWaitExpression = (node) => node.callee && node.callee.name === "wait";

const replaceExpression = (path, j) =>
  j.callExpression(j.identifier("waitFor"), path.node.arguments);

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

  root
    .find(j.ImportDeclaration)
    .filter((path) => path.node.source.value === "@testing-library/react")
    .find(j.ImportSpecifier)
    .filter((path) => path.node.imported.name === "wait")
    .replaceWith(j.importSpecifier(j.identifier("waitFor")));

  root
    .find(j.CallExpression, isWaitExpression)
    .replaceWith((path) => replaceExpression(path, j));

  return root.toSource();
}

А вот ссылка на него в AST Explorer

Другие вопросы по тегам