Замените все экземпляры определенного импорта через 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();
}