migrateFromListenerMiddleware
Проходит по файлу, использующему createListenerMiddleware / startListening из Redux Toolkit, и генерирует один *.trigger.ts на каждую регистрацию startListening({ actionCreator, effect }). Исходный файл остаётся нетронутым — адоптеры просматривают сгенерированные триггеры, подвязывают их в компонентах через useEvent, а когда готовы — удаляют регистрацию middleware.
Поставляется как программный API и как CLI-команда (triggery-codemod migrate-from-listener-middleware).
import { migrateFromListenerMiddleware } from '@triggery/codemod';
Сигнатура
Заголовок раздела «Сигнатура»function migrateFromListenerMiddleware(
options: MigrateFromListenerMiddlewareOptions,
): MigrateFromListenerMiddlewareResult;
interface MigrateFromListenerMiddlewareOptions {
readonly file: string;
readonly outDir?: string;
readonly dryRun?: boolean;
readonly project?: import('ts-morph').Project;
}
interface MigrateFromListenerMiddlewareResult {
readonly file: string;
readonly migrated: readonly MigratedListener[];
}
interface MigratedListener {
readonly eventName: string;
readonly triggerFilePath: string;
readonly triggerFileContent: string;
}Параметры
Заголовок раздела «Параметры»| Параметр | Тип | Обязательный | Описание |
|---|---|---|---|
file | string | да | Путь к файлу, объявляющему middleware. |
outDir | string | нет | Директория для сгенерированных файлов триггеров. По умолчанию — директория исходника. |
dryRun | boolean | нет | Спланировать изменения и вернуть их без записи на диск. |
project | ts-morph.Project | нет | Предсуществующий project — переиспользуй между батчами. |
Возвращает
Заголовок раздела «Возвращает»| Поле | Описание |
|---|---|
file | Исходный файл, который был обработан. |
migrated | По одной записи на каждый обработанный вызов startListening — имя, выходной путь, сгенерированный исходник. |
Поддерживаемые формы
Заголовок раздела «Поддерживаемые формы»Codemod распознаёт каноническую форму RTK:
startListening({
actionCreator: someAction,
effect: (action, listenerApi) => { /* … */ },
});Другие формы — matcher, predicate или type — обнаруживаются, но в V1 не трансформируются. Исходный файл не переписывается, так что повторные прогоны идемпотентны.
triggery-codemod migrate-from-listener-middleware [--out-dir <path>] [--dry-run] <file>| Флаг | Обязательный | Описание |
|---|---|---|
--out-dir | нет | Переопределить дефолтную выходную директорию. |
--dry-run | нет | Распечатать запланированные изменения без записи. |
Примеры
Заголовок раздела «Примеры»Программно
Заголовок раздела «Программно»import { migrateFromListenerMiddleware } from '@triggery/codemod';
const result = migrateFromListenerMiddleware({
file: 'src/store/listenerMiddleware.ts',
outDir: 'src/triggers',
});
for (const m of result.migrated) {
console.log(m.eventName, '→', m.triggerFilePath);
}triggery-codemod migrate-from-listener-middleware --out-dir src/triggers src/store/listenerMiddleware.tsВывод:
Migrated 3 listener(s) from src/store/listenerMiddleware.ts:
• user-logged-in → src/triggers/user-logged-in.trigger.ts
• product-added → src/triggers/product-added.trigger.ts
• cart-checked-out → src/triggers/cart-checked-out.trigger.tsЧто генерируется
Заголовок раздела «Что генерируется»Для каждого startListening({ actionCreator: userLoggedIn, effect: (action, api) => {...} }) codemod пишет:
import { createTrigger } from '@triggery/core';
/**
* Auto-migrated from a Redux Toolkit listenerMiddleware `startListening`
* registration. Review the generated handler …
*/
export const userLoggedInTrigger = createTrigger<{
events: { 'user-logged-in': unknown };
conditions: Record<string, never>;
actions: Record<string, never>;
}>({
id: 'user-logged-in',
events: ['user-logged-in'],
required: [],
async handler({ event, conditions, actions, check }) {
// TODO: original RTK effect body — refactor dispatch/getState into actions/conditions.
const action = event.payload;
/* … original effect body … */
},
});Имя события выводится из текста символа actionCreator. Codemod не пытается разрезолвить .type на action creator’е — это требовало бы type info — поэтому если slug’и action creator’а не совпадают с type-строкой слайса, имена событий правь руками.
Шаги дальше
Заголовок раздела «Шаги дальше»Сгенерированные триггеры — это стартеры. После прогона codemod-скрипта:
- Замени
listenerApi.dispatch(x)на действие Triggery — добавьactions.<name>в схему, зарегистрируй черезuseActionв подходящем компоненте. - Замени чтения
listenerApi.getState()типизированными условиями — регистрируй черезuseCondition. - Подключи зажигание нового события: компоненты, которые раньше диспатчили слушаемое действие, теперь зовут
useEvent(trigger, 'name'). - Когда каждый потребитель подвязан — удаляй блок
startListening.