| name | refactor |
| description | Perform large-scale refactors and renames in TypeScript codebases. Use when renaming symbols across files, doing pattern replacements, changing function signatures, or performing codebase-wide refactors. Prefer AST-aware tools over text-based replacements. |
Large-Scale Refactoring
Perform codebase-wide refactors using AST-aware tools for accuracy and safety. This skill emphasizes scripted approaches over individual file edits and integrates with the gameplan workflow for complex changes.
When to Use
- Renaming symbols (functions, types, variables) across multiple files
- Pattern replacements (e.g., updating API calls, changing import paths)
- Function signature changes that affect many call sites
- Migrating from one API/pattern to another
- Removing deprecated code paths
- Consistent style/naming transformations
Complexity Assessment
Before starting, assess the refactor complexity:
| Complexity | Files Affected | Patterns | Approach |
|---|
| Simple | < 20 files | Single pattern | Direct ast-grep execution |
| Medium | 20-100 files | Multiple patterns | Scripted approach with verification |
| Complex | 100+ files, behavioral changes | Multiple patterns, tests affected | Create a gameplan first |
Complex refactors involving architectural changes, multi-step migrations, or behavioral modifications should use the gameplan workflow. See platform/flowglad-next/llm-prompts/new-gameplan.md for the template.
Core Principles
- Understand scope BEFORE making changes - Search and count affected files before executing replacements
- Work at AST level - Default to ast-grep for syntax-aware matching (per CLAUDE.md guidance)
- Verify after changes - Always run
bun run check after refactoring
- Prefer idempotent transformations - Running the same refactor twice should produce the same result
- For complex refactors - Use multi-patch strategy with
[INFRA] patches shipping first
Tool Selection
Prefer tools higher in this hierarchy:
See tools-reference.md for detailed usage of each tool.
Simple Refactor Workflow
For refactors affecting < 100 files with a single pattern:
Step 1: Understand the Scope
ast-grep --lang typescript -p 'oldFunctionName($$$ARGS)' --json | jq length
ast-grep --lang typescript -p 'oldFunctionName($$$ARGS)' -r 'newFunctionName($$$ARGS)' --interactive
Step 2: Create a Checkpoint
git status
git stash push -m "pre-refactor checkpoint"
Step 3: Execute the Refactor
ast-grep --lang typescript -p 'oldFunctionName($$$ARGS)' -r 'newFunctionName($$$ARGS)' --update-all
Step 4: Verify Changes
bun run check
git diff --stat
git diff
Step 5: Handle Edge Cases
Some matches may require manual attention:
- Dynamic references (e.g.,
obj[funcName])
- String literals containing the pattern
- Comments and documentation
Step 6: Run Tests
bun run test:backend
Step 7: Commit
git add -A
git commit -m "refactor: rename oldFunctionName to newFunctionName
Co-Authored-By: Claude <noreply@anthropic.com>"
Complex Refactor Workflow
For refactors involving 100+ files, behavioral changes, or architectural modifications:
Step 1: Create a Gameplan
Use the gameplan template at platform/flowglad-next/llm-prompts/new-gameplan.md. The gameplan should include:
- Problem Statement: What we're changing and why
- Current State Analysis: How the code currently works
- Required Changes: Specific files, functions, and transformations
- Acceptance Criteria: What "done" looks like
- Patches: Ordered list of incremental changes
Step 2: Follow Multi-Patch Strategy
Organize patches by classification:
| Classification | Description | When to Ship |
|---|
[INFRA] | No observable behavior change (types, helpers, test stubs) | Ship early |
[GATED] | New behavior behind feature flag | Ship before activation |
[BEHAVIOR] | Changes observable behavior | Ship last, keep small |
Goal: Maximize [INFRA] and [GATED] patches. Ship non-functional changes first to enable early review and reduce risk.
Step 3: Test-First Pattern
Write test stubs with .skip markers BEFORE implementation:
describe('newApiCall', () => {
it.skip('should return the expected shape', async () => {
})
})
Implement and unskip tests in the same patch as the code being tested.
Step 4: Execute Patches in Order
For each patch:
- Read the patch specification from the gameplan
- Execute the changes (prefer ast-grep/ts-morph over manual edits)
- Run
bun run check
- Run tests (
bun run test:backend)
- Commit with patch reference
Common Refactoring Patterns
Rename a Function
ast-grep --lang typescript -p 'oldName($$$ARGS)'
ast-grep --lang typescript -p 'oldName($$$ARGS)' -r 'newName($$$ARGS)' --update-all
Rename a Type
ast-grep --lang typescript -p ': OldType'
ast-grep --lang typescript -p 'OldType<$T>'
ast-grep --lang typescript -p ': OldType' -r ': NewType' --update-all
ast-grep --lang typescript -p 'OldType<$T>' -r 'NewType<$T>' --update-all
Change Function Signature (Add Parameter)
ast-grep --lang typescript -p 'myFunc($ARG1, $ARG2)'
ast-grep --lang typescript -p 'myFunc($ARG1, $ARG2)' -r 'myFunc($ARG1, $ARG2, { newOption: false })' --update-all
Update Import Paths
ast-grep --lang typescript -p "import { $$$IMPORTS } from '@/old/path'"
ast-grep --lang typescript -p "import { \$\$\$IMPORTS } from '@/old/path'" -r "import { \$\$\$IMPORTS } from '@/new/path'" --update-all
Remove Deprecated Function Calls
ast-grep --lang typescript -p 'deprecatedInit()' -r '' --update-all
See ast-grep-patterns.md for more patterns.
Verification Checklist
After any refactor:
Reference Documentation
- ast-grep-patterns.md - Pattern library and metavariable syntax
- tools-reference.md - Detailed tool comparison and usage
platform/flowglad-next/llm-prompts/new-gameplan.md - Gameplan template for complex refactors
Example: Full Refactor Session
Rename createBillingRun to initiateBillingRun across the codebase:
ast-grep --lang typescript -p 'createBillingRun' --json | jq length
ast-grep --lang typescript -p 'createBillingRun($$$ARGS)' -r 'initiateBillingRun($$$ARGS)'
ast-grep --lang typescript -p 'createBillingRun($$$ARGS)' -r 'initiateBillingRun($$$ARGS)' --update-all
ast-grep --lang typescript -p 'const createBillingRun = $BODY' -r 'const initiateBillingRun = $BODY' --update-all
ast-grep --lang typescript -p 'typeof createBillingRun' -r 'typeof initiateBillingRun' --update-all
bun run check
git diff --stat
git diff
bun run test:backend
git add -A
git commit -m "refactor: rename createBillingRun to initiateBillingRun
Renamed for clarity - 'initiate' better describes the action of
starting a billing run process.
Co-Authored-By: Claude <noreply@anthropic.com>"