CSSForge
CSSForge is a safety-first semantic CSS refactoring and modernization workbench written in Rust.
Features
- Reusable
cssforge-coreanalysis and refactoring engine library cssforgenon-interactive CLI for analysis, planning, applying transforms, and rule discovery- Ratatui/Crossterm interactive TUI with visual 4-step wizard workflow and unified diff preview
- Lightning CSS integration for strict semantic AST validation
- Lossless source-range scanning and patch-based rewriting
- Conservative adjacent and local native CSS nesting transformations
- Transformation safety states and proof verification metadata
- Flexible output modes: dry-run, new-file, output-directory, overwrite-with-backup, overwrite, patch, and stdout
- Git dirty-tree protection for destructive write operations
- Structured JSON reporting for integration with automated workflows
Rules & Capabilities
CSSForge features 26 automated transformations split into Modernization and Structural Refactoring:
1. Modernization (Native Nesting, Range Syntax & Selectors)
Native Nesting & Selector Factoring
- Nest pseudo-classes (
nest-pseudo-class):.button:hover→.button { &:hover { ... } } - Nest pseudo-elements (
nest-pseudo-element):.card::before→.card { &::before { ... } } - Nest attribute states (
nest-attribute):.button[disabled]→.button { &[disabled] { ... } } - Nest compound states (
nest-compound):.item.active→.item { &.active { ... } } - Nest descendants (
nest-descendant):.card .title→.card { .title { ... } } - Nest combinators (
nest-combinator):.card > .title,.card + .peer,.card ~ .peer - Factor selector lists (
factor-selector-list): Factor comma-separated selectors sharing a base (.marker, .marker::before→.marker { &, &::before })
At-Rule Inlining
- Nest local
@media(nest-media): Inline immediately-following@mediablocks with matching selectors into nested rules - Nest local
@supports(nest-supports): Inline immediately-following@supportsblocks with matching selectors into nested rules - Nest local
@container(nest-container): Inline immediately-following@containerquery blocks into nested rules - Nest
@starting-style(nest-starting-style): Inline immediately-following@starting-styleblocks into parent selector rules
Modern Selectors & Media Syntax
- Consolidate
:not()selectors (consolidate-not): Consolidate chained:not()selectors (:not(a):not(b)→:not(a, b)) - Factor with
:is()(modernize-is): Factor selector-list alternatives with uniform specificity into:is(...)grouping - Modernize with
:where()(modernize-where): Factor selector-list alternatives into:where(...)for zero-specificity defaults - Modernize media range syntax (
modernize-media-range-syntax): Convertmin-width/max-width/min-height/max-heightto CSS Range Syntax (e.g.(width >= 800px))
2. Refactoring (Consolidation, Deduplication & Structural Cleanup)
At-Rule Block Merging
- Merge same named
@layerblocks (merge-same-named-layer): Consolidate separated blocks of the same named@layerinto their canonical first occurrence - Merge adjacent
@mediaqueries (merge-adjacent-media): Combine consecutive@mediablocks having identical query conditions - Merge adjacent
@supportsqueries (merge-adjacent-supports): Combine consecutive@supportsblocks having identical feature conditions - Merge adjacent
@containerqueries (merge-adjacent-container): Combine consecutive@containerblocks having identical container name & query conditions - Merge adjacent
@scopeblocks (merge-identical-scope): Combine consecutive@scopeblocks having identical root and limit parameters - Merge adjacent
@starting-styleblocks (merge-identical-starting-style): Combine consecutive top-level@starting-styleblocks into a single block
Selector & Body Deduplication
- Merge adjacent identical selectors (
merge-adjacent-identical-selector): Combine consecutive style rules sharing exact same selector - Merge identical rule bodies (
merge-identical-rule-bodies): Combine selectors sharing identical declaration bodies into a unified comma-separated rule - Factor identical states with
:is()(factor-identical-states-with-is): Combine multiple states of the same element sharing identical bodies into&:is(:hover, :focus, ...)form - Gather related selector rules (
gather-related-selector-rules): Gather scattered non-adjacent occurrences of the same selector — including exact duplicates, directly-attached pseudo-classes/elements (&:hover,&::before), combinator variants (+ *,> .child,~ .peer), and whitespace-descendant variants (:not(*)) — into the canonical first rule block - Prune overridden declarations & rules (
prune-overridden-declarations): Remove dead declarations and entire rules overridden by later identical selectors in the cascade
Safety rules strictly prohibit moving candidate rules across comments or unrelated CSS blocks. Parent selector lists, BEM token-concatenation lookalikes, and pseudo-element parent selectors are safely preserved.
Requirements
- Rust 1.85+ (Edition 2024, pinned to toolchain
1.97.1inrust-toolchain.toml)
Build
The binary will be created at:
target/release/cssforge
Interactive TUI
Run interactive mode in the current directory:
Or target a specific path:
TUI Step-by-Step Wizard Flow
CSSForge features an intuitive, 4-step workflow:
- Select Files: Choose target CSS files (
Spaceto toggle,afor all,Enterto confirm). - Select Rules: Choose modernization rules or presets (
Spaceto toggle,pfor preset,Enterto confirm). - Output Settings & Review: Select output mode (
↑/↓or1-7to choose,dfor diff preview,Enterto apply). - Done: View transformation summary and target paths (
Enterorqto exit,rto start over).
| Key | Action |
|---|---|
Enter |
Primary action: Confirm & advance to next step / Apply & Finish |
Esc / Backspace / b |
Go back to previous step |
Space |
Toggle highlighted item (file / rule / output mode) |
↑ ↓ or j k |
Move cursor / select option |
a |
Toggle all (files or rules) / refresh analysis |
p |
Cycle rule preset (Conservative ➔ Modern ➔ Aggressive ➔ Custom) |
d / v |
Inspect unified code diff and semantic proof checklist |
Tab / Shift+Tab |
Cycle steps forward / backward |
1…4 |
Jump directly to step 1 (Files), 2 (Rules), 3 (Output), 4 (Done) |
r |
Rediscover CSS files from disk / Start over |
q |
Quit |
CLI Usage
Analyze:
Generate transformation plans without modifying files:
Apply to new sibling files (default non-destructive mode):
Dry run:
Write a mirrored tree to an output directory:
Generate .patch files:
Overwrite with backup (requires acknowledgement):
Destructive overwrite modes are automatically blocked if Git reports an uncommitted working tree.
List available modernization rules:
Presets
- Analysis — No mutating rules enabled; surfaces modernization findings only.
- Conservative — Enables pseudo-class, pseudo-element, attribute, compound, local
@media, and local@supportsnesting. - Modern — Enables all implemented nesting and combinator rules.
- Aggressive — Maps to the modern rule set; unsafe architectural transformations are intentionally excluded.
- Custom — Manual rule selection via the interactive TUI.
Safety Model
Every generated transformation plan includes verification proof flags:
- Safety classification (
SAFE,REVIEW,UNSAFE) - Exact source byte ranges
- Original and proposed CSS text
- Selector-set proof flag
- Specificity proof flag
- Cascade-context proof flag
- Source-order proof flag
- Layer/scope proof flags
- Declaration and
!importantpreservation proof flags - Human-readable reason and warnings
Only verified SAFE plans are applied by default. The CLI can opt into REVIEW plans with --allow-review.
Source-Preservation Approach
Lightning CSS is used to validate CSS syntax and AST structures. CSSForge does not reserialize the full stylesheet through Lightning CSS; instead, the source scanner targets exact byte ranges and replaces only the structural cluster being transformed. Declaration bodies are preserved directly from the original source text, retaining formatting, comments, custom properties, and !important flags.
Unchanged ranges remain untouched.
Workspace Structure
cssforge/
├── Cargo.toml
├── rust-toolchain.toml
├── crates/
│ ├── cssforge-core/
│ │ └── src/
│ │ ├── discovery.rs
│ │ ├── engine.rs
│ │ ├── lib.rs
│ │ ├── model.rs
│ │ ├── output.rs
│ │ └── scanner.rs
│ ├── cssforge-tui/
│ │ └── src/
│ │ ├── app.rs
│ │ ├── banner.rs
│ │ ├── lib.rs
│ │ └── ui.rs
│ └── cssforge-cli/
│ └── src/main.rs
└── LICENSE
Testing
Run workspace test suite: