Skip to content
GitHubXDiscord

@triggery/codemod

Codemods that mechanically migrate React / Redux side-effect code to Triggery’s event → conditions → actions model. Powered by ts-morph so the output is real TypeScript — JSX, types, and imports preserved.

npm bundle

pnpm add -D @triggery/codemod
Command / ExportPurpose
triggery-codemod extract-trigger --name <event> <file>Pull a useEffect(() => { ... }, []) block out of a component into a sibling <name>.trigger.ts.
triggery-codemod migrate-from-listener-middleware <file>Generate one trigger per RTK startListening({ actionCreator, effect }) call.
extractTrigger, migrateFromListenerMiddlewareProgrammatic API for the two codemods.

Add --dry-run to preview without writing.

# Pull a useEffect block out of a component into a *.trigger.ts file.
npx triggery-codemod extract-trigger --name new-message src/Chat.tsx

# Generate one trigger per RTK listenerMiddleware effect.
npx triggery-codemod migrate-from-listener-middleware src/store/middleware.ts

Programmatic API:

import { extractTrigger, migrateFromListenerMiddleware } from '@triggery/codemod';

extractTrigger({ file: 'src/Chat.tsx', name: 'new-message' });
migrateFromListenerMiddleware({ file: 'src/store/middleware.ts' });

Reads the first useEffect(() => { ... }, []) in the file and writes a sibling <name>.trigger.ts containing a stub createTrigger({...}). The component is rewritten to call useEvent(<name>Trigger, '<event-name>') instead.

The codemod intentionally does not:

  • Infer the events / conditions / actions schema generic — you write it.
  • Move closure-captured state into typed conditions — refactor by hand.
  • Touch cleanup functions or effects with conditional deps — handle manually.

For each startListening({ actionCreator, effect }) call in the file, generates one <event-name>.trigger.ts. The effect body is dropped verbatim into the new trigger’s handler with a // TODO: refactor dispatch/getState into actions/conditions marker.

Other listenerMiddleware shapes (matcher, predicate, type) are detected but skipped — they need human review.