Рефакторинг за допомогою codemods для автоматизації змін API
Уявіть, що вам потрібно здійснити масштабну зміну API у великому проєкті: перейменувати методи, змінити назви параметрів чи навіть перевпорядкувати аргументи у сотнях файлів. Зробити все вручну вкрай важко і ризиковано. Тут на допомогу приходять codemods — спеціальні скрипти, які можуть автоматизувати рефакторинг, використовуючи абстрактне синтаксичне дерево (AST). У цій статті поговоримо, навіщо потрібні codemods, як вони працюють і як вони допомагають у рефакторингу API.
Що таке codemods
Codemod — це скрипт, який аналізує вихідний код на рівні синтаксичного дерева, а потім перетворює його за певними правилами. В англомовній спільноті це часто називають AST transform, бо основна робота виконується через розбір коду в AST, внесення змін і генерацію коду назад.
Основні цілі codemods:
- Масштабний рефакторинг: заміна застарілого API, зміна назв змінних чи функцій.
- Міграція з однієї бібліотеки на іншу: автоматичне переписування імпортів і викликів.
- Усунення технічного боргу: оновлення коду відповідно до нових правил ESLint або стилю.
Навіщо потрібні codemods при зміні API
Коли велика бібліотека чи фреймворк випускає нову версію з оновленим API, розробникам часто потрібно:
- Змінити сигнатури функцій
- Перейменувати об’єкти чи методи
- Переписати імпорти (наприклад,
@angular/common/http
замість@angular/http
) - Видалити застарілий (deprecated) код
Зробити це вручну у великому кодовому базисі майже нереально. Codemods дають змогу виконати зміни автоматично за допомогою одного скрипта.
Приклад інструментів
jscodeshift
jscodeshift — це популярна утиліта від Facebook (Meta), яка використовує Babel або recast для роботи з кодом. Вона написана на Node.js і може швидко обходити всі файли у вашому проєкті.
Встановлення:
npm install -g jscodeshift
Приклад запуску:
jscodeshift -t renameFunction.js src/
Де renameFunction.js
— це ваш скрипт-трансформатор.
Babel transformations
Babel теж дає можливість писати власні трансформери (плагіни), але jscodeshift вважають більш спеціалізованим рішенням для codemods.
TS-morph або Typescript Compiler API
Якщо вам треба більш типобезпечний підхід або якщо код на TypeScript, можна використати ts-morph чи офіційний TypeScript Compiler API.
Приклад: перейменування методу в API
Припустімо, що у вас є функція getUser()
в десятках файлів, яку потрібно перейменувати на fetchUser()
. За допомогою jscodeshift це можна робити так:
- Створити файл
renameFunction.js
:
module.exports = function(file, api) {
const j = api.jscodeshift
const root = j(file.source)
// Шукаємо всі виклики getUser(...)
root.find(j.CallExpression, {
callee: {
type: 'Identifier',
name: 'getUser'
}
})
.forEach(path => {
// Замінюємо назву функції на fetchUser
path.value.callee.name = 'fetchUser'
})
return root.toSource()
}
- Запустити:
jscodeshift -t renameFunction.js src/
Скрипт пройдеться по всіх файлах у папці src/
і замінить виклики getUser(...)
на fetchUser(...)
.
Приклад: міграція іменованих імпортів
Уявімо, що раніше ми імпортували метод parseData
з import { parseData } from './utils'
, а тепер він називається processData
.
- Скрипт
migrateImports.js
:
module.exports = function(file, api) {
const j = api.jscodeshift
const root = j(file.source)
// Знаходимо імпорт з './utils' і замінюємо parseData на processData
root.find(j.ImportDeclaration, { source: { value: './utils' } })
.forEach(path => {
path.value.specifiers.forEach(specifier => {
if (specifier.imported.name === 'parseData') {
specifier.imported.name = 'processData'
}
})
})
return root.toSource()
}
- Запуск:
jscodeshift -t migrateImports.js src/
Поради для успішного використання codemods
- Створіть резервну копію коду або використовуйте систему контролю версій, щоб завжди можна було відкотити зміни.
- Пиши маленькі, інкрементальні скрипти: краще кілька маленьких трансформерів, ніж один великий, що робить все.
- Тестуйте скрипт на невеликій ділянці коду перед тим, як застосовувати до всього проєкту.
- Використовуйте типи (для TypeScript) якщо це можливо, щоб більш точно знаходити потрібні місця.
- Підключайте linter і форматер (наприклад, ESLint і Prettier) до фінального кроку, щоб отриманий код був читабельним.
Коли codemods не допоможуть
- Якщо логіка зміни складна і залежить від конкретного контексту, який важко відстежити в коді. Наприклад, якщо функцію викликають з різними аргументами залежно від умов, і ваша трансформація залежить від того, якими саме аргументами.
- Якщо API має дуже різні сценарії використання, які не вкладаються у шаблони.
Попри це, більшість механічних змін, як-от перейменування, зміна сигнатур функцій, видалення застарілих методів, можуть бути автоматизовані.
Висновок
Рефакторинг великого проєкту, в якому потрібно внести глобальні зміни в API, може забрати багато часу, якщо робити його вручну. Codemods дають змогу автоматизувати більшу частину роботи, зменшують ризик людських помилок і роблять процес масштабного оновлення коду більш прозорим.
Завдяки jscodeshift або аналогічним інструментам розробники можуть швидко оновлювати імпорти, перейменовувати функції та навіть змінювати структуру коду за кілька хвилин, а не днів. Головне — проєкт має бути підконтрольний системі версій, а самі скрипти краще писати й тестувати покроково.
Якщо у вашій команді часто змінюється API або ви готуєтеся до великого оновлення фреймворку чи бібліотек, варто розглянути можливості codemods як частини процесу рефакторингу. Це інвестиція, що швидко окупиться у вигляді зекономленого часу і покращення якості коду.