structural-refactor
v0.1.5
Published
CLI for IntelliJ-style structural refactoring of JavaScript/TypeScript codebases
Downloads
566
Maintainers
Readme
sref — Structural Refactoring CLI
IntelliJ-style structural refactoring for JavaScript and TypeScript codebases, from the command line.
sref performs AST-based refactoring — no regex, no string matching. It parses your code into an abstract syntax tree, understands the structure, and makes precise transformations that update every reference across your entire project.
Why sref?
Most code transformation tools work on text. sref works on structure. When you rename a symbol, it finds every import, every usage, every re-export — not by searching for strings, but by resolving the actual dependency graph. This means:
- Renames that update all imports across 200 files in one command
- Safe deletes that refuse to remove code that's still referenced
- Extract/inline operations that understand scope, closures, and types
- Module conversions that rewrite
require()toimportwith correct specifiers - An undo stack that can reverse any operation
Installation
# Requires Node >= 18
npm install -g structural-refactor
# Or use directly with npx
npx structural-refactor <command>
# Or in a project with pnpm
pnpm add -D structural-refactorQuick Start
# See what's in your project
sref discover list --dir .
# Find a specific symbol
sref discover find createUser
# Rename it everywhere
sref rename symbol createUser --to createAccount --dry-run
sref rename symbol createUser --to createAccount
# Oops, undo that
sref undoEvery destructive command supports --dry-run to preview changes as a diff before applying them.
Global Options
These flags work with any command:
| Flag | Description |
|------|-------------|
| --dry-run | Preview changes without writing to disk |
| --json | Output results as JSON (for scripting/piping) |
| --verbose | Show detailed operation logs |
| --tsconfig <path> | Path to tsconfig.json (auto-detected by default) |
| --scope <path> | Limit operations to a directory subset |
| --no-confirm | Skip confirmation prompts |
Commands
rename — Rename symbols, files, or modules
rename symbol <name> --to <newName>
Renames a symbol across the entire project. Updates the declaration, all usages, all imports, and all re-exports.
# Rename by name (auto-resolved from project index)
sref rename symbol UserService --to AccountService
# Rename with explicit location (for disambiguation)
sref rename symbol handler --to requestHandler --path src/server.ts:42:10The --path flag uses file:line:col format. If omitted, sref searches the project index and resolves the symbol by name. If multiple symbols share the same name, it will ask you to disambiguate with --path.
rename file <path> --to <newPath>
Moves/renames a file and updates every import pointing to it.
sref rename file src/utils/helpers.ts --to src/utils/string-helpers.tsextract — Extract code into new declarations
extract variable --path <file> --start <line:col> --end <line:col> --name <name>
Extracts an expression into a const (or let) variable.
sref extract variable \
--path src/api.ts \
--start 15:5 --end 15:48 \
--name baseUrl \
--kind constextract function --path <file> --start <line:col> --end <line:col> --name <name>
Extracts a selection of code into a new function. Automatically detects parameters (variables used but not declared in the selection) and return values.
sref extract function \
--path src/handlers.ts \
--start 20:3 --end 35:4 \
--name validateInputextract interface --path <file> --class <className> --name <name>
Extracts a TypeScript interface from a class's public methods and properties.
sref extract interface --path src/service.ts --class UserService --name IUserServiceinline — Inline declarations at their usage sites
The inverse of extract. Replaces a declaration with its value/body at every usage site, then removes the declaration.
inline variable --path <file:line:col>
sref inline variable --path src/config.ts:10:7inline function --path <file:line:col>
Inlines a function body at every call site, substituting arguments for parameters.
sref inline function --path src/utils.ts:25:17inline type-alias --path <file:line:col>
Replaces a type alias with its definition at every usage site.
sref inline type-alias --path src/types.ts:5:6move — Move symbols or files
move symbol <name> --from <file> --to <file>
Moves an exported symbol from one file to another. Updates all imports across the project to point to the new location.
sref move symbol parseConfig --from src/utils.ts --to src/config/parser.tsmove file <path> --to <newPath>
Alias for rename file — moves a file and rewrites all import paths.
sref move file src/old-location.ts --to src/new-location.tssignature — Change function signatures
signature change <fnName> --path <file>
Add or remove parameters from a function. Updates the declaration and all call sites.
# Add a parameter
sref signature change processOrder --path src/orders.ts --add-param logger:Logger
# Remove a parameter
sref signature change processOrder --path src/orders.ts --remove-param verbosesignature to-arrow --path <file:line:col>
Converts a function declaration to an arrow function expression.
sref signature to-arrow --path src/handlers.ts:10:1signature to-async --path <file:line:col>
Adds the async keyword to a function and wraps the return type in Promise<>.
sref signature to-async --path src/api.ts:30:1type — Type refactorings
type safe-delete <name> --path <file>
Deletes a symbol only if nothing references it. If the symbol is still imported or used, the operation fails with a clear error showing where the references are.
sref type safe-delete oldHelper --path src/utils.ts --dry-run
sref type safe-delete oldHelper --path src/utils.tstype convert --path <file:line:col>
Toggles between type alias and interface. Converts the declaration and adjusts syntax accordingly (= vs {}).
sref type convert --path src/types.ts:8:1modify — Modify declaration modifiers and keywords
A Swiss army knife for changing declaration attributes without rewriting code manually.
# Add export keyword
sref modify UserConfig --path src/config.ts --export
# Remove export keyword
sref modify InternalHelper --path src/utils.ts --no-export
# Make a function async
sref modify fetchData --path src/api.ts --async
# Set visibility on a class member
sref modify password --path src/user.ts --scope private
# Add readonly
sref modify id --path src/entity.ts --readonly
# Change return type
sref modify getUser --path src/service.ts --return-type "Promise<User | null>"
# Add a parameter
sref modify handleRequest --path src/server.ts --add-param ctx:Context
# Remove a parameter
sref modify handleRequest --path src/server.ts --remove-param legacy
# Change variable declaration kind
sref modify count --path src/state.ts --kind let
# Add/remove decorators
sref modify UserController --path src/controllers.ts --add-decorator Injectable
sref modify UserController --path src/controllers.ts --remove-decorator DeprecatedOptions are composable — you can combine multiple modifications in a single command:
sref modify fetchUser --path src/api.ts --async --export --return-type "Promise<User>"member — Class member operations
member encapsulate <fieldName> --class <className> --path <file>
Generates getter/setter methods for a class field and makes it private.
sref member encapsulate name --class User --path src/user.tsclass — Class refactorings
class to-functions --path <file> --class <className>
Converts a class into standalone functions. Each method becomes a function, the constructor becomes a factory function.
sref class to-functions --path src/calculator.ts --class Calculatorclass composition --path <file> --class <className>
Replaces class inheritance (extends) with composition. Creates a delegate field and forwards method calls.
sref class composition --path src/admin.ts --class AdminUsermodule — Module system refactorings
module cjs-to-esm
Converts CommonJS require()/module.exports to ESM import/export syntax.
# Convert a single file
sref module cjs-to-esm --path src/legacy.js
# Convert all files in the project
sref module cjs-to-esmmodule default-to-named --path <file>
Converts a default export to a named export and updates all import sites.
sref module default-to-named --path src/utils.tsmodule replace-with-import <name> --from <module> --path <file>
Replaces a local function/variable definition with an import from another module. Useful for deduplicating code — when the same function exists locally but is already available from a shared module.
sref module replace-with-import formatDate --from ./helpers.js --path src/utils.tsquality — Code quality refactorings
quality deduplicate <name> --canonical <file>
Finds all duplicate definitions of a symbol across the project and replaces them with imports from a single canonical source.
# Find and replace all duplicate `formatDate` definitions,
# keeping the one in src/utils/date.ts
sref quality deduplicate formatDate --canonical src/utils/date.ts
# Limit scope to a specific directory
sref quality deduplicate formatDate --canonical src/utils/date.ts --scope src/featuresdiscover — Explore your codebase
Discovery commands use a fast oxc-parser-based index (no ts-morph overhead) to query your project.
discover list
Lists all functions, classes, interfaces, types, and enums in the project.
sref discover list --dir .
sref discover list --kind function --exported
sref discover list --kind class --file "src/services/**"| Flag | Description |
|------|-------------|
| --kind <type> | Filter by function, class, interface, type, enum, arrow |
| --exported | Only show exported symbols |
| --file <pattern> | Filter by file path pattern |
discover find <name>
Finds all code units with a specific name.
sref discover find createUserdiscover similar <name>
Finds structurally similar code — functions with similar parameter signatures, similar body patterns, or similar names.
sref discover similar handleRequest --min-score 0.5 --limit 10discover search
Search by function signature or structural pattern.
# Find all functions that take a Logger parameter
sref discover search --params Logger
# Find all async functions
sref discover search --async
# Find functions with 3 parameters
sref discover search --param-count 3
# Find by return type
sref discover search --returns Promise
# Find interfaces that have a specific member
sref discover search --has-member serialize
# Combine filters
sref discover search --kind function --async --name "handle"analyze — Analyze project structure
Deep analysis using the full dependency graph, control flow, and data flow.
analyze info
Shows project type, framework, TypeScript configuration, path aliases, and workspace packages.
sref analyze info --dir .analyze deps
Displays the full dependency tree — internal module dependencies and external packages.
sref analyze deps --dir .
sref analyze deps --internal # only internal imports
sref analyze deps --external # only npm packagesanalyze graph
Shows the module dependency graph as nodes and edges.
# Full project graph
sref analyze graph --dir .
# Graph for a specific file (imports, exports, imported-by)
sref analyze graph --file src/core/engine.tsanalyze exports / analyze imports
Lists what each file exports or imports.
sref analyze exports --dir .
sref analyze imports --file src/api/routes.tsanalyze cfg --file <path> --function <name>
Builds a control flow graph for a specific function. Shows basic blocks, branches, and call sites.
sref analyze cfg --file src/parser.ts --function parseExpressionanalyze dfg --file <path> --function <name>
Builds a data flow graph for a function. Shows how values flow through variables, parameters, and return statements.
sref analyze dfg --file src/transform.ts --function applyRulesanalyze call-graph
Builds a cross-file call graph — which functions call which, across the entire project.
sref analyze call-graph --dir .
sref analyze call-graph --function processOrderpatterns — Detect architecture and design patterns
Automatically detects design patterns (factory, singleton, observer, builder, etc.) and architectural patterns (layered architecture, dependency injection, etc.) in your codebase.
patterns detect
Full pattern detection report with evidence and file locations.
sref patterns detect --dir .patterns list
Quick list of detected patterns with confidence scores.
sref patterns list --dir .
sref patterns list --category architectural
sref patterns list --category creationalCategories: creational, structural, behavioral, architectural, framework
patterns layers
Shows detected architectural layers and their dependencies.
sref patterns layers --dir .patterns summary
One-line architecture summary.
sref patterns summary --dir .undo — Undo the last refactoring
Every operation is recorded in a .sref/undo-stack.json file. Undo reverses the last operation by restoring original file contents.
sref undoJSON Output
Every command supports --json for machine-readable output. This makes sref composable with other tools:
# Pipe dependency analysis into jq
sref analyze deps --json | jq '.stats'
# Get all exported functions as JSON
sref discover list --exported --kind function --json
# Script a rename and check the result
sref rename symbol oldName --to newName --dry-run --json | jq '.files | length'Architecture
sref uses a two-tier parser design for speed and precision:
Tier 1 — oxc-parser: A fast Rust-based parser used for indexing all files via worker threads. Builds the import graph and symbol index. This powers
discover,analyze, andpatternscommands.Tier 2 — ts-morph: Full TypeScript compiler API wrapper, loaded lazily and only for the files that need refactoring. This powers all mutation commands (
rename,extract,inline,move, etc.).
Additional infrastructure:
- oxc-resolver for Node.js-compatible module resolution
- fast-glob for file discovery
- Content-hash caching via xxhash-wasm + msgpack for incremental re-indexing
- Worker threads for parallel file parsing
Development
git clone https://github.com/artpar/structural-refactor
cd structural-refactor
pnpm install
pnpm test # run tests
pnpm test:watch # watch mode
pnpm dev # run CLI via tsx (hot reload)
# Run any command in dev mode
npx tsx bin/sref.ts discover list --dir .
npx tsx bin/sref.ts rename symbol Foo --to Bar --dry-runLicense
MIT
