# reformat
A modular code transformation framework for applying code transformations to code in a set of source code files.
Organized as a Cargo workspace:
- **reformat-core**: Core transformation library
- **reformat-cli**: Command-line interface
- **reformat-plugins**: Plugin system (foundation)
## Features
### Default Command (Quick Processing)
- Run all common transformations in a single pass with `reformat <path>`
- Combines three operations efficiently:
1. Rename files to lowercase
2. Transform task emojis to text alternatives
3. Remove trailing whitespace
- **3x faster** than running individual commands separately
- Perfect for quick project cleanup: `reformat -r src/`
### Case Format Conversion
- Convert between 6 case formats: camelCase, PascalCase, snake_case, SCREAMING_SNAKE_CASE, kebab-case, and SCREAMING-KEBAB-CASE
- Process single files or entire directories (with recursive option)
- Dry-run mode to preview changes
- Filter files by glob patterns
- Filter which words to convert using regex patterns
- Add prefix/suffix to converted identifiers
- Support for multiple file extensions (.c, .h, .py, .md, .js, .ts, .java, .cpp, .hpp)
### Whitespace Cleaning
- Remove trailing whitespace from files
- Preserve line endings and file structure
- Recursive directory processing
- Extension filtering with sensible defaults
- Dry-run mode to preview changes
- Automatically skips hidden files and build directories
### Emoji Transformation
- Replace task completion emojis with text alternatives (✅ → [x], ☐ → [ ], etc.)
- Replace status indicator emojis (🟡 → [yellow], 🟢 → [green], 🔴 → [red])
- Remove non-task emojis from code and documentation
- Smart replacements for common task tracking symbols
- Configurable behavior (replace task emojis, remove others, or both)
- Support for markdown, documentation, and source files
### File Grouping
- Organize files by common prefix into subdirectories
- Automatically detect file prefixes based on separator character
- Optional prefix stripping from filenames after moving
- **Suffix-based splitting** (`--from-suffix`): Split at the LAST separator for multi-part prefixes
- Preview mode to see what groups would be created
- Configurable minimum file count for group creation
- Recursive processing for nested directories
- **Broken reference detection**: Automatically scan codebase for references to moved files
- **Interactive fix workflow**: Review and apply fixes for broken references
- Change tracking with `changes.json` and `fixes.json` output files
### Presets
- Define reusable transformation pipelines in a `reformat.json` config file
- Run named presets with `reformat -p <preset-name> <path>`
- Chain any combination of steps: `rename`, `emojis`, `clean`, `convert`, `group`
- Per-step configuration overrides (case transforms, file extensions, separators, etc.)
- Dry-run mode applies to all steps in the preset
- Step validation with clear error messages for unknown steps
### Logging & UI
- Multi-level verbosity control (`-v`, `-vv`, `-vvv`)
- Quiet mode for silent operation (`-q`)
- File logging for debugging (`--log-file`)
- Progress spinners with indicatif
- Automatic operation timing
- Color-coded console output
## Installation
Install from crates.io:
```bash
cargo install reformat
```
Or install from the workspace:
```bash
cargo install --path reformat-cli
```
Or build from source:
```bash
cargo build --release -p reformat
```
The binary will be at `./target/release/reformat`
## Library Usage
Add to your `Cargo.toml`:
```toml
[dependencies]
reformat-core = "0.1.4"
```
### Case Conversion
```rust
use reformat_core::{CaseConverter, CaseFormat};
let converter = CaseConverter::new(
CaseFormat::CamelCase, // from
CaseFormat::SnakeCase, // to
None, // file_extensions
false, // recursive
false, // dry_run
String::new(), // prefix
String::new(), // suffix
None, // strip_prefix
None, // strip_suffix
None, // replace_prefix_from
None, // replace_prefix_to
None, // replace_suffix_from
None, // replace_suffix_to
None, // glob_pattern
None, // word_filter
)?;
converter.process_directory(std::path::Path::new("src"))?;
```
### Whitespace Cleaning
```rust
use reformat_core::{WhitespaceCleaner, WhitespaceOptions};
let mut options = WhitespaceOptions::default();
options.dry_run = false;
options.recursive = true;
let cleaner = WhitespaceCleaner::new(options);
let (files_cleaned, lines_cleaned) = cleaner.process(std::path::Path::new("src"))?;
println!("Cleaned {} lines in {} files", lines_cleaned, files_cleaned);
```
### Combined Processing (Default Command)
```rust
use reformat_core::{CombinedProcessor, CombinedOptions};
let mut options = CombinedOptions::default();
options.recursive = true;
options.dry_run = false;
let processor = CombinedProcessor::new(options);
let stats = processor.process(std::path::Path::new("src"))?;
println!("Files renamed: {}", stats.files_renamed);
println!("Emojis transformed: {} files ({} changes)",
stats.files_emoji_transformed, stats.emoji_changes);
println!("Whitespace cleaned: {} files ({} lines)",
stats.files_whitespace_cleaned, stats.whitespace_lines_cleaned);
```
### File Grouping
```rust
use reformat_core::{FileGrouper, GroupOptions};
let mut options = GroupOptions::default();
options.strip_prefix = true; // Remove prefix from filenames
options.from_suffix = false; // Set true to split at LAST separator
options.min_count = 2; // Require at least 2 files to create a group
options.dry_run = false;
let grouper = FileGrouper::new(options);
let stats = grouper.process(std::path::Path::new("templates"))?;
println!("Directories created: {}", stats.dirs_created);
println!("Files moved: {}", stats.files_moved);
println!("Files renamed: {}", stats.files_renamed);
```
## Quick Start
### Default Command (Recommended)
The fastest way to clean up your code:
```bash
# Process directory (non-recursive)
reformat <path>
# Process recursively
reformat -r <path>
# Preview changes without modifying files
reformat -d <path>
```
**What it does:**
1. Renames files to lowercase
2. Transforms task emojis: ✅ → [x], ☐ → [ ]
3. Removes trailing whitespace
**Example:**
```bash
# Clean up an entire project directory
reformat -r src/
# Preview changes first
reformat -d -r docs/
# Process a single file
reformat README.md
```
**Output:**
```
Renamed '/tmp/TestFile.txt' -> '/tmp/testfile.txt'
Transformed emojis in '/tmp/testfile.txt'
Cleaned 2 lines in '/tmp/testfile.txt'
Processed files:
- Renamed: 1 file(s)
- Emoji transformations: 1 file(s) (1 changes)
- Whitespace cleaned: 1 file(s) (2 lines)
```
## Usage
### Case Conversion
Basic conversion (using subcommand):
```bash
reformat convert --from-camel --to-snake myfile.py
```
Recursive directory conversion:
```bash
reformat convert --from-snake --to-camel -r src/
```
Dry run (preview changes):
```bash
reformat convert --from-camel --to-kebab --dry-run mydir/
```
Add prefix to all converted identifiers:
```bash
reformat convert --from-camel --to-snake --prefix "old_" myfile.py
```
Filter files by pattern:
```bash
reformat convert --from-camel --to-snake -r --glob "*test*.py" src/
```
Only convert specific identifiers:
```bash
reformat convert --from-camel --to-snake --word-filter "^get.*" src/
```
### Whitespace Cleaning
Clean all default file types in current directory:
```bash
reformat clean .
```
Clean with dry-run to preview changes:
```bash
reformat clean --dry-run src/
```
Clean only specific file types:
```bash
reformat clean -e .py -e .rs src/
```
Clean a single file:
```bash
reformat clean myfile.py
```
### Emoji Transformation
Replace task emojis with text in markdown files:
```bash
reformat emojis docs/
```
Process with dry-run to preview changes:
```bash
reformat emojis --dry-run README.md
```
Only replace task emojis, keep other emojis:
```bash
reformat emojis --replace-task --no-remove-other docs/
```
Process specific file types:
```bash
reformat emojis -e .md -e .txt project/
```
### File Grouping
Organize files by common prefix into subdirectories:
```bash
# Preview what groups would be created
reformat group --preview templates/
# Dry run to see what would happen
reformat group --dry-run templates/
# Group files (keep original filenames)
reformat group templates/
# Group files and strip prefix from filenames
reformat group --strip-prefix templates/
# Group by suffix (split at LAST separator) - for multi-part prefixes
reformat group --from-suffix templates/
# Process subdirectories recursively
reformat group -r templates/
# Use custom separator (e.g., hyphen)
reformat group -s '-' templates/
# Require at least 3 files to create a group
reformat group -m 3 templates/
```
Example transformation with `--strip-prefix` (splits at FIRST separator):
```
Before: After:
templates/ templates/
├── wbs_create.tmpl ├── wbs/
├── wbs_delete.tmpl │ ├── create.tmpl
├── wbs_list.tmpl │ ├── delete.tmpl
├── work_package_create.tmpl │ └── list.tmpl
├── work_package_delete.tmpl ├── work/
└── other.txt │ ├── package_create.tmpl
│ └── package_delete.tmpl
└── other.txt
```
Example transformation with `--from-suffix` (splits at LAST separator):
```
Before: After:
templates/ templates/
├── activity_relationships_list.tmpl ├── activity_relationships/
├── activity_relationships_create.tmpl │ ├── list.tmpl
├── activity_relationships_delete.tmpl │ ├── create.tmpl
├── user_profile_edit.tmpl │ └── delete.tmpl
├── user_profile_view.tmpl ├── user_profile/
└── other.txt │ ├── edit.tmpl
│ └── view.tmpl
└── other.txt
```
#### Broken Reference Detection
After grouping files, reformat can scan your codebase for broken references:
```bash
# Interactive mode (default) - prompts for scanning
reformat group --strip-prefix templates/
# Output:
# Grouping complete:
# - Directories created: 2
# - Files moved: 5
#
# Changes recorded to: changes.json
#
# Would you like to scan for broken references? [y/N]: y
# Enter directories to scan: src
#
# Found 3 broken reference(s).
# Proposed fixes written to: fixes.json
#
# Review fixes.json and apply changes? [y/N]: y
# Fixed 3 reference(s) in 2 file(s).
```
```bash
# Non-interactive mode with automatic scanning
reformat group --strip-prefix --no-interactive --scope src templates/
# Skip reference scanning entirely
reformat group --strip-prefix --no-interactive templates/
```
**Generated files:**
- `changes.json` - Record of all file operations (for auditing)
- `fixes.json` - Proposed reference fixes (review before applying)
### Presets
Define reusable transformation pipelines in a `reformat.json` file in your project root:
```json
{
"code": {
"steps": ["rename", "emojis", "clean"],
"rename": {
"case_transform": "lowercase",
"space_replace": "hyphen"
},
"emojis": {
"replace_task_emojis": true,
"remove_other_emojis": false,
"file_extensions": [".md", ".txt"]
},
"clean": {
"remove_trailing": true,
"file_extensions": [".rs", ".py"]
}
},
"templates": {
"steps": ["group", "clean"],
"group": {
"separator": "_",
"min_count": 3,
"strip_prefix": true
}
}
}
```
Run a preset:
```bash
reformat -p code src/
# Dry-run to preview changes
reformat -p code -d src/
# Run a different preset
reformat -p templates web/templates/
```
**Available step configuration options:**
| `rename` | `case_transform` (lowercase/uppercase/capitalize), `space_replace` (underscore/hyphen), `recursive`, `include_symlinks` |
| `emojis` | `replace_task_emojis`, `remove_other_emojis`, `file_extensions`, `recursive` |
| `clean` | `remove_trailing`, `file_extensions`, `recursive` |
| `convert` | `from_format`, `to_format`, `file_extensions`, `recursive`, `prefix`, `suffix`, `glob`, `word_filter` |
| `group` | `separator`, `min_count`, `strip_prefix`, `from_suffix`, `recursive` |
Steps without explicit configuration use sensible defaults.
### Logging and Debugging
Control output verbosity:
```bash
# Info level output (-v)
reformat -v convert --from-camel --to-snake src/
# Debug level output (-vv)
reformat -vv clean src/
# Silent mode (errors only)
reformat -q convert --from-camel --to-snake src/
# Log to file
reformat --log-file debug.log -v convert --from-camel --to-snake src/
```
Output example with `-v`:
```
2025-10-10T00:15:08.927Z [INFO] Converting from CamelCase to SnakeCase
2025-10-10T00:15:08.927Z [INFO] Target path: /tmp/test.py
2025-10-10T00:15:08.927Z [INFO] Recursive: false, Dry run: false
Converted '/tmp/test.py'
2025-10-10T00:15:08.931Z [INFO] Conversion completed successfully
2025-10-10T00:15:08.931Z [INFO] run_convert(), Elapsed=4.089125ms
```
## Case Format Options
- `--from-camel` / `--to-camel` - camelCase (firstName, lastName)
- `--from-pascal` / `--to-pascal` - PascalCase (FirstName, LastName)
- `--from-snake` / `--to-snake` - snake_case (first_name, last_name)
- `--from-screaming-snake` / `--to-screaming-snake` - SCREAMING_SNAKE_CASE (FIRST_NAME, LAST_NAME)
- `--from-kebab` / `--to-kebab` - kebab-case (first-name, last-name)
- `--from-screaming-kebab` / `--to-screaming-kebab` - SCREAMING-KEBAB-CASE (FIRST-NAME, LAST-NAME)
## Examples
### Case Conversion Examples
Convert Python file from camelCase to snake_case:
```bash
reformat convert --from-camel --to-snake main.py
```
Convert C++ project from snake_case to PascalCase:
```bash
reformat convert --from-snake --to-pascal -r -e .cpp -e .hpp src/
```
Preview converting JavaScript getters to snake_case:
```bash
reformat convert --from-camel --to-snake --word-filter "^get.*" -d src/
```
### Whitespace Cleaning Examples
Clean trailing whitespace from entire project:
```bash
reformat clean -r .
```
Clean only Python files in src directory:
```bash
reformat clean -e .py src/
```
Preview what would be cleaned without making changes:
```bash
reformat clean --dry-run .
```
### Emoji Transformation Examples
Transform task emojis in documentation:
```bash
reformat emojis -r docs/
```
Example transformation:
```markdown
Before:
- Task done ✅
- Task pending ☐
- Warning ⚠ issue
- 🟡 In progress
- 🟢 Complete
- 🔴 Blocked
After:
- Task done [x]
- Task pending [ ]
- Warning [!] issue
- [yellow] In progress
- [green] Complete
- [red] Blocked
```
Process only markdown files:
```bash
reformat emojis -e .md README.md
```
### File Grouping Examples
Organize template files by prefix (split at first separator):
```bash
reformat group --strip-prefix web/templates/
```
Organize files with multi-part prefixes (split at last separator):
```bash
# activity_relationships_list.tmpl -> activity_relationships/list.tmpl
reformat group --from-suffix web/templates/
```
Preview groups without making changes:
```bash
reformat group --preview web/templates/
```
Example output:
```
Found 2 potential group(s):
wbs (3 files):
- wbs_create.tmpl
- wbs_delete.tmpl
- wbs_list.tmpl
work (2 files):
- work_package_create.tmpl
- work_package_delete.tmpl
```
Group files with hyphen separator:
```bash
reformat group -s '-' --strip-prefix components/
```
Recursively organize nested directories:
```bash
reformat group -r --strip-prefix src/
```
Group files and automatically scan for broken references:
```bash
reformat group --strip-prefix --scope src templates/
```
Example `changes.json`:
```json
{
"operation": "group",
"timestamp": "2026-01-15T16:30:00+00:00",
"base_dir": "/project/templates",
"changes": [
{"type": "directory_created", "path": "wbs"},
{"type": "file_moved", "from": "wbs_create.tmpl", "to": "wbs/create.tmpl"}
]
}
```
Example `fixes.json`:
```json
{
"generated_from": "changes.json",
"fixes": [
{
"file": "src/handler.go",
"line": 15,
"context": "template.ParseFiles(\"wbs_create.tmpl\")",
"old_reference": "wbs_create.tmpl",
"new_reference": "wbs/create.tmpl"
}
]
}
```
### Preset Examples
Run a multi-step cleanup preset:
```bash
# Define in reformat.json, then run:
reformat -p code src/
# Output:
# rename: 3 file(s) renamed
# emojis: 2 file(s), 5 change(s)
# clean: 4 file(s), 12 line(s) cleaned
# Preset 'code' complete.
```
Preview preset changes without modifying files:
```bash
reformat -p code -d src/
```
Case conversion preset:
```json
{
"snake-to-camel": {
"steps": ["convert"],
"convert": {
"from_format": "snake",
"to_format": "camel",
"file_extensions": [".py"],
"recursive": true
}
}
}
```
```bash
reformat -p snake-to-camel src/
```
## License
MIT License. See [LICENSE](LICENSE) for details.