Skip to content

Releases: jayeshmepani/cssforge

v0.7.0 — Shared-State `:is()` Factoring (Review Specificity)

Choose a tag to compare

@github-actions github-actions released this 18 Sep 03:55

What's new

Review required: :is() can raise specificity

:is() is not a comma list. Each selector in a, button { } keeps its own specificity. :is(a, button) uses max(a, button).

/* 0.6.1 — no plan (missing pattern) */
a:hover,
button:hover,
[role="button"]:hover,
.clickable:hover {
  cursor: pointer;
}

/* 0.7.0 — applied on refactor */
:is(a, button, [role="button"], .clickable):hover {
  cursor: pointer;
}
Branch Before After :is()
a:hover, button:hover (0, 1, 1) (0, 2, 0)
[role="button"]:hover, .clickable:hover (0, 2, 0) (0, 2, 0)

a:hover / button:hover get class-level weight. That can change which rule wins. Read the unified diff before you keep the file.

Still REVIEW (not auto-applied):

  • :is() that includes an ID (for example :is(.alpha, #hero) .title)
  • modernize-where — :where() zeros specificity to (0, 0, 0)

Use --allow-review only if you intend those.

Use :is(), not ::is(). ::is is invalid CSS.

Bugfix: shared-state :is() was missing

modernize-is already knew same-base different states:

.button:hover, .button:focus → .button:is(:hover, :focus) (same spec → SAFE in 0.6.1)

It did not know different bases with the same state (a:hover, button:hover). That produced no plan. That hole is filled. Still 28 rules; this is not a 29th rule.

Bugfix: identical-body merge is a comma list, not :is()

::selection { background: Highlight !important; color: HighlightText !important; }
.button--primary { background: Highlight !important; color: HighlightText !important; }

becomes:

::selection,
.button--primary {
  background: Highlight !important;
  color: HighlightText !important;
}

This is merge-identical-rule-bodies. A comma list does not change each selector’s specificity. 0.6.1 marked mixed-spec merges REVIEW as if they were :is(), so the TUI never applied them. They are SAFE now.

Do not write :is(::selection, .button--primary). Pseudo-elements cannot go in :is() / :where() / :not().

Official multi-platform binaries

Platform Architecture Archive
Windows Intel / AMD x64 cssforge-v0.7.0-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.7.0-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.7.0-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.7.0-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.7.0-macos-arm64.tar.gz

Installation

Cargo

cargo install cssforge --version 0.7.0

Linux

tar -xvf cssforge-v0.7.0-linux-x64.tar.gz
cp cssforge-v0.7.0-linux-x64/cssforge ~/.local/bin/
chmod +x ~/.local/bin/cssforge
cssforge --version

Checksums

SHA256 checksums are included with the release in SHA256SUMS.txt.

sha256sum -c SHA256SUMS.txt

Verification

This release was verified with:

cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo build --release --workspace

v0.6.1 — Valid Multiline Values & Mixed-Media Gather

Choose a tag to compare

@github-actions github-actions released this 17 Sep 17:42

What's new

CSSForge 0.6.1 is a patch on shipped v0.6.0. The 28th rule from 0.6.0 is unchanged. This release fixes Refactor apply producing invalid CSS and dropping declarations from mixed @media blocks. Transformations stay forward-only, range-based, and reviewable. Cascade order is not rewritten.

v0.6.0 added dedupe-identical-declarations and stopped gather from cloning already-nested descendants. Use 0.6.1 instead of 0.6.0 if you apply the Refactor preset.

Multiline values stay one declaration

Refactor no longer treats each line of a value as its own declaration. Parentheses, brackets, strings, and continuation lines are tracked so these stay intact:

  • filter: drop-shadow(...) drop-shadow(...) (including a line break between functions)

  • background: linear-gradient( … ) / radial-gradient( … ) split across lines

  • Multiline custom properties such as --shadow:

    filter: drop-shadow(0 2px 20px rgba(45, 212, 191, 0.14))
        drop-shadow(0 8px 30px rgba(0, 0, 0, 0.75));

    stays one filter declaration. 0.6.0 could emit a stray drop-shadow(...); (unknown word) and background: linear-gradient(;.

Body re-indent no longer injects ; onto continuation lines.

Mixed @media parent declarations survive gather

When an already-nested @media contains both parent declarations and a child rule, gather still nests the child under its home but no longer deletes the parent declarations.

.split-layout {
  lottie-player { max-width: 440px; }

  @media (width >= 840px) {
    grid-template-columns: 1.2fr 0.8fr;
    align-items: center;
    lottie-player { max-width: 100%; }
  }
}

grid-template-columns and align-items remain on .split-layout. 0.6.0 could drop them and leave a stray }.

Conflicting identical selectors are not concatenated

Adjacent or gathered copies of the same selector are not merged when they declare the same property with different values (including !important vs not). Exact duplicates are still removed by dedupe-identical-declarations.

Example: :focus-visible { outline: 3px solid Highlight; } and :focus-visible { outline: 2px solid Highlight !important; } stay two rules so cascade order does not collapse into a single block with duplicate properties.

From 0.6.0 (unchanged)

  • 28th rule dedupe-identical-declarations: exact-duplicate declarations and identical nested copies in the same block, first occurrence kept; different values left untouched; custom property names case-sensitive.
  • Gather applies that cleanup when merging and does not re-absorb nodes already nested in the home rule (the 32-pass clone loop).

Documentation and versioning

This is a Cargo 0.x patch on 0.6.0. No new public RuleId. RuleId::ALL remains [RuleId; 28].

Official multi-platform binaries

Platform Architecture Archive
Windows Intel / AMD x64 cssforge-v0.6.1-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.6.1-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.6.1-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.6.1-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.6.1-macos-arm64.tar.gz

Installation

Cargo

cargo install cssforge --version 0.6.1

Linux

tar -xvf cssforge-v0.6.1-linux-x64.tar.gz
cp cssforge-v0.6.1-linux-x64/cssforge ~/.local/bin/
chmod +x ~/.local/bin/cssforge
cssforge --version

Checksums

SHA256 checksums are included with the release in SHA256SUMS.txt.

sha256sum -c SHA256SUMS.txt

Verification

This release was verified with:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets
cargo build --release --workspace

v0.6.0 — Dedupe Identical Declarations & Stable Gather

Choose a tag to compare

@github-actions github-actions released this 17 Sep 07:35

What's new

CSSForge 0.6.0 adds a 28th transformation rule for exact-duplicate cleanup and stops gather from cloning work it has already nested. Transformations stay forward-only, range-based, and reviewable. Cascade order is not rewritten.

28th rule — dedupe-identical-declarations

  • Removes exact-duplicate declarations in the same block, keeping the first occurrence.

  • Removes identical nested rule copies in the same block, keeping the first copy.

  • Does not drop later declarations that have a different value. color: red; followed by color: blue; is left intact so the winning cascade value does not change.

  • Does not treat color: red and color: red !important as the same declaration.

  • Treats custom property names as case-sensitive (--token is not --Token).

  • Enabled in Conservative, Modern, Refactor, and Aggressive.

    .card {
      color: red;
      color: red;
      display: none;
      display: none;
      color: blue;
    }

    becomes:

    .card {
      color: red;
      display: none;
      color: blue;
    }

Gather no longer clones already-nested descendants

  • gather-related-selector-rules still selects the same related selectors.
  • When gather merges those rules, it now applies the same exact-duplicate cleanup.
  • Nodes that are already nested inside the home rule are not re-absorbed as extra copies.
  • This reaches a fixed point on repeated runs instead of growing the stylesheet every pass.

Previously, Refactor apply could fail on real nested stylesheets with:

Error: CSS transformations did not reach a stable result after 32 passes

because gather kept appending duplicate nested declarations such as extra display: none; and extra & > .cluster { ... } blocks. That loop is closed.

Documentation and rule catalog

The README and HTML documentation now describe all 28 transformation rules, including dedupe-identical-declarations. RuleId::ALL is [RuleId; 28]. This is a Cargo 0.x minor bump from 0.5.1 because a public enum variant was added.

Official multi-platform binaries

Platform Architecture Archive
Windows Intel / AMD x64 cssforge-v0.6.0-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.6.0-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.6.0-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.6.0-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.6.0-macos-arm64.tar.gz

Installation

Cargo

cargo install cssforge --version 0.6.0

Linux

tar -xvf cssforge-v0.6.0-linux-x64.tar.gz
cp cssforge-v0.6.0-linux-x64/cssforge ~/.local/bin/
chmod +x ~/.local/bin/cssforge
cssforge --version

Checksums

SHA256 checksums are included with the release in SHA256SUMS.txt.

sha256sum -c SHA256SUMS.txt

Verification

This release was verified with:

cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test --workspace --all-targets
cargo build --release --workspace

v0.5.1 — Restore Complete Gather & Spec-Accurate Nesting Selector

Choose a tag to compare

@github-actions github-actions released this 16 Sep 12:51

What's new

CSSForge 0.5.1 is a patch for 0.5.0. Complete gather of related selectors was already in 0.4.0 and earlier. Nesting-safety work in 0.5.0 made that gather lossy: nested @supports / @media were skipped, a wide REVIEW span hid SAFE nests, and & was rewritten as if it were a Sass parent pointer. This release restores that gather and makes native & match the spec.

Restore complete gather

Prefix-related rules for the same selector gather into the first home again, including nested conditionals:

.stack-card {
  &:last-child { margin-bottom: 0; }

  &:hover {
    .project-card-marvel__media {
      img { transform: scale(1.035); }
      &::after { left: 160%; }
    }
  }

  @supports (animation-timeline: view()) {
    @media (prefers-reduced-motion: no-preference) {
      .card-inner { animation-name: recede; }
      &:last-child .card-inner { animation: none; }
    }
  }
}
  • @supports { @media { .home .child } } is no longer skipped. The at-rule chain inverts under .home; inner selectors stay relative (.card-inner, &:last-child .card-inner).
  • Hover chains factor as before: &:hover .media img and &:hover .media::after become &:hover { .media { img; &::after } }.
  • Gather replaces only the home rule. Remote members are separate delete plans, so a gather span cannot hide unrelated SAFE nests between the first and last related rule.
  • Mixed @media blocks that also contain other selectors (for example :root and .card-inner beside .stack-card) stay grouped and are not exploded into each parent.
  • nest-layer-by-selector and other cascade-order changes remain REVIEW.

Native & is :is(parent)

The nesting selector substitutes the parent selector list, not a parent element and not a text paste. A later pass must not wrap that result as if & still meant the original subject.

/* invalid — `&` is .card-inner, so this is .card-inner:last-child .card-inner */
.card-inner {
  &:last-child & { animation: none; }
}

/* valid — `&` is still .stack-card */
.stack-card {
  &:last-child .card-inner { animation: none; }
}
  • Does not nest tr:last-child td under td as td { tr { &:last-child & } }. That desugars to td tr and matches nothing in a table.

  • Nests from the row instead:

    .archive-table {
      tr {
        &:last-child td { border-bottom: none; }
        &:hover td { background: transparent; }
      }
    }
  • Valid reverse-& cases are unchanged: .featured .card → .card { .featured & { } }, :not(.card) → :not(&).

  • Selectors that already contain & are not treated as a state base, so tr:last-child & is not rewritten to tr { &:last-child & }.

Stable application

  • SAFE local nests win over overlapping REVIEW gathers, so refactor no longer stalls while valid nests sit inside a gather span.
  • Prefix-safe gather applies again on the refactor preset (TUI and cssforge apply --preset refactor) without --allow-review.
  • Appended (reverse-&) gathers stay REVIEW when they would change matching.
  • Fixed-point apply is unchanged: overlapping plans still run until the source is stable.

Official multi-platform binaries

Platform Architecture Archive
Windows Intel / AMD x64 cssforge-v0.5.1-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.5.1-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.5.1-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.5.1-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.5.1-macos-arm64.tar.gz

Installation

Cargo

cargo install cssforge --version 0.5.1

Linux

tar -xvf cssforge-v0.5.1-linux-x64.tar.gz
cp cssforge-v0.5.1-linux-x64/cssforge ~/.local/bin/
chmod +x ~/.local/bin/cssforge
cssforge --version

Checksums

SHA256 checksums are included with the release in SHA256SUMS.txt.

sha256sum -c SHA256SUMS.txt

Verification

This release was verified with:

cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo build --release --workspace

v0.5.0 — Native Nesting Safety, Embedded Templates & Stable Refactoring

Choose a tag to compare

@github-actions github-actions released this 10 Sep 08:38

What's new

CSSForge 0.5.0 strengthens the refactoring engine around native CSS nesting, modern selector functions, conditional at-rules, and real-world template files. The release keeps transformations forward-only, range-based, and reviewable.

Native nesting safety

  • Generates valid native nesting for child, sibling, descendant, pseudo-class, attribute, and compound-selector relationships.

  • Emits an explicit nesting selector when a combinator needs an anchored parent:

    .c-command-hero {
      & > .c-bolt {
        z-index: 4;
      }
    }
  • Rejects malformed Sass-style structures such as a bare > { ... } block and avoids re-parenting selectors that are already nested or relative.

  • Preserves existing nesting selectors and reaches a fixed point on repeated runs, preventing transformation loops and partial multi-run application.

Modern selector handling

  • Factors safe selector alternatives into :is(...) only when the matching behavior and specificity are preserved.
  • Preserves the different semantics of :is(), :where(), :has(), and :not().
  • Calculates functional-pseudo specificity using the highest argument specificity where required.
  • Does not combine pseudo-elements such as ::before, ::after, :before, or :after into functional pseudo-classes, because that produces invalid selectors.
  • Keeps :has() relative arguments intact and does not rewrite selector-list logic inside functional pseudo-classes.

Conditional at-rules and layers

  • Supports safe nesting and planning inside nestable @media, @supports, @container, @scope, @layer, and @starting-style blocks.
  • Keeps @starting-style selector relationships exact so opening-state transitions are not accidentally broadened.
  • Merges adjacent compatible conditional blocks while preserving unrelated siblings and nested conditional content.
  • Keeps gather-related-selector-rules layer-scoped; declarations are not moved between named layers.
  • Preserves named layer identity and declaration order when applying nest-layer-by-selector.

Embedded framework and template files

CSSForge can discover and transform CSS inside <style>...</style> blocks in supported template sources, including Blade/PHP, HTML, Vue, Svelte, Astro, Twig, ERB, and Handlebars-style files. Only the style-content ranges are transformed; surrounding template code is preserved.

Stable application and review behavior

  • Applies overlapping plans until the source reaches a stable result without repeatedly requiring manual re-runs.
  • Prevents broad gather candidates from hiding more precise selector plans.
  • Emits one spanning plan where overlapping edits could otherwise orphan deletion-only plans.
  • Keeps potentially cascade-changing transformations marked for review instead of silently applying them.
  • Preserves UTF-8 declaration values and multiline custom-property content.

Documentation and rule catalog

The README and HTML documentation now describe all 27 transformation rules, including nest-layer-by-selector, embedded style-block support, selector safety, and the fixed-point application model.

Official multi-platform binaries

Platform Architecture Archive
Windows Intel / AMD x64 cssforge-v0.5.0-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.5.0-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.5.0-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.5.0-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.5.0-macos-arm64.tar.gz

Installation

Cargo

cargo install cssforge --version 0.5.0

Linux

tar -xvf cssforge-v0.5.0-linux-x64.tar.gz
cp cssforge-v0.5.0-linux-x64/cssforge ~/.local/bin/
chmod +x ~/.local/bin/cssforge
cssforge --version

Checksums

SHA256 checksums are included with the release in SHA256SUMS.txt.

sha256sum -c SHA256SUMS.txt

Verification

This release was verified with:

cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace
cargo build --release --workspace

v0.4.0 — Layer-Safe Gather & Nest Layers by Selector

Choose a tag to compare

@github-actions github-actions released this 19 Aug 09:10

What's new

nest-layer-by-selector (27th rule)

The same exact selector in multiple named @layer blocks is hoisted and rewritten as nested @layer blocks. Layer identity and first-declared order stay the same. This does not create a child layer such as tokens.base.

@layer tokens { :root { A } }
@layer base   { :root { B } }

/* becomes */

:root {
  @layer tokens { A }
  @layer base   { B }
}

An existing @layer reset, tokens, base, … list still defines order. The rule does not hoist when an unlayered rule sits between the layers.

Gather is layer-scoped

gather-related-selector-rules only merges related rules inside the same named layer (or both unlayered). It will not copy @layer base declarations into @layer tokens.

At-rule preludes (@layer tokens, @media …) are not treated as selector prefixes, so a second apply cannot smash named layers into @layer { tokens {} base {} }.

Other gather fixes

  • Mixed @supports with a dominant home (for example .custom-select plus selectedcontent) inverts into that home instead of dropping chrome.
  • Gather emits one spanning plan so overlapping nest plans cannot orphan delete-only plans.
  • Related nests factor deeper: button { &:hover }, &:open { … }, &.compact { … }.
  • Prefix-only sibling nesting — no &:open & / &:focus & rewrite of descendants.

README and the HTML catalog now list all 27 rules, including nest-layer-by-selector.

Official multi-platform binaries

Platform Architecture Archive
Windows Intel / AMD x64 cssforge-v0.4.0-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.4.0-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.4.0-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.4.0-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.4.0-macos-arm64.tar.gz

Checksums

SHA256 checksums are in SHA256SUMS.txt.

sha256sum -c SHA256SUMS.txt

v0.3.1 — Comment Carry & Nest Merge

Choose a tag to compare

@github-actions github-actions released this 18 Aug 09:30

Safety-first semantic CSS refactoring and modernization workbench.

🩹 Patch on 0.3.0

Gather/nest selectors are unchanged from 0.3.0 (including :focus-visible { .skip-link:focus:not(&) }). This release only fixes how comments and duplicate nested blocks are assembled.

  • Leading comments travel with gathered rules: a /* … */ immediately above a moved rule is copied into the parent (just above the nest) and removed from the old location. No more orphan comments after gather.
  • Same nested selector merges: &.flash { animation } plus &.flash { @media { animation: none } } become one &.flash block.

📦 Version

0.3.0 → 0.3.1

Compatible with 0.3 (cssforge-core = "0.3" will pick this up).


Official Multi-Platform Binaries

Platform Architecture Archive File
Windows Intel / AMD x64 cssforge-v0.3.1-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.3.1-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.3.1-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.3.1-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.3.1-macos-arm64.tar.gz

Checksums

SHA256 checksums are available in SHA256SUMS.txt.

Verification Example

sha256sum -c SHA256SUMS.txt

v0.3.0 — Smart Gather & Nesting

Choose a tag to compare

@github-actions github-actions released this 18 Aug 08:26

Safety-first semantic CSS refactoring and modernization workbench.

🧠 Smart Gather & Nesting

gather-related-selector-rules and the nest family now pick one home per rule instead of copying the same declarations into every matching parent.

  • Strongest existing parent wins: specificity first (.skip-link beats *; a class beats body). On a tie, prefix nesting (+ *, &:has(*)) beats appended &.
  • Appended & (MDN): when no stronger prefix home exists, reverse the context — .featured .card → .card { .featured & { } }, :not(.card) → :not(&).
  • Gather through conditionals: related rules inside @media / @supports / @container / @starting-style can invert into the parent (.skip-link { :not(*) { @media (width <= 1024px) { … } } }).
  • Busy at-rules stay grouped: if an at-block has 3+ inner style rules that would land in 2+ different homes, the @media (etc.) is left populated. One or two inners, or every inner assigned to the same home, still nest into that selector.
  • Universal / document roots are weak homes: *, html, body, :root, and :host no longer absorb component rules via appended & (no more .skip-link+& / .skip-link:has(&) inside *).

🛡️ Safer Transformations

  • Selector lists are not combinators: ::view-transition-old(root), ::view-transition-new(root) is no longer rewritten as ::view-transition-new(root) { ::view-transition-old(root), & { } }. A comma list stays a list.
  • Pseudo-elements are not gather homes: & cannot represent ::…, so ::view-transition-* / ::before rules are not used as merge targets for other selectors.
  • Selector-list lines stay intact: &, / &::before, / &:hover, are not treated as declarations, so they no longer become &::before,; or a stray ;.
  • Missing semicolons repaired: last declarations without ; get one before a nested {, so display: block !important no longer runs into + .tabpanel {.
  • Media range syntax modernizes features with or without spaces: (max-width:60rem) → (width <= 60rem).

📦 Version

0.2.1 → 0.3.0

This is a 0.x minor: same CLI and the same 26 rule IDs, but default gather/nest output can change. Dependents pinned to 0.2 will not pick this up automatically.


Official Multi-Platform Binaries

Platform Architecture Archive File
Windows Intel / AMD x64 cssforge-v0.3.0-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.3.0-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.3.0-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.3.0-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.3.0-macos-arm64.tar.gz

Checksums

SHA256 checksums are available in SHA256SUMS.txt.

Verification Example

sha256sum -c SHA256SUMS.txt

v0.2.1 — Smart Safe File Discovery

Choose a tag to compare

@github-actions github-actions released this 18 Aug 05:49

Safety-first semantic CSS refactoring and modernization workbench.

📁 Smart Safe File Discovery Engine

CSSForge now applies zero-config safety ignore filters when scanning workspaces recursively, protecting build artifacts and preventing recursion loops:

  • Generated & Artifact Exclusions: Automatically ignores *.modern.css (prevents recursive re-modernization on output files), *.min.css, *.bundle.css, *.chunk.css, *.map.css, and backup files (*.bak.css, *.backup.css).
  • Directory Exclusions: Automatically skips node_modules/, target/, dist/, build/, out/, .next/, .nuxt/, .turbo/, .svelte-kit/, vendor/, .git/, .hg/, .svn/, and .cache/.
  • Explicit Target Override: Explicitly targeting any file path directly (e.g. cssforge interactive ./dist/bundle.min.css) continues to process the requested file.

📦 Version

0.2.0 → 0.2.1


Official Multi-Platform Binaries

Platform Architecture Archive File
Windows Intel / AMD x64 cssforge-v0.2.1-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.2.1-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.2.1-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.2.1-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.2.1-macos-arm64.tar.gz

Checksums

SHA256 checksums are available in SHA256SUMS.txt.

Verification Example

sha256sum -c SHA256SUMS.txt

v0.2.0 — Gather Related Selectors, Select All & Windows TUI Scroll Fix

Choose a tag to compare

@github-actions github-actions released this 17 Aug 17:35

Safety-first semantic CSS refactoring and modernization workbench.

Gather related selector rules

CSSForge can now gather scattered, non-adjacent occurrences of the same selector into one canonical rule block.

/* before — same selector, far apart */
.skip-link { position: absolute; font-weight: 700; }
/* …unrelated rules, comments, @keyframes… */
.skip-link { font: optional; }
.skip-link+* { display: block; }
.skip-link::backdrop { background-color: gray; }
.skip-link:has(*) { color: #27ca3f; }
/* after */
.skip-link {
    position: absolute;
    font-weight: 700;
    font: optional;

    + * { display: block; }
    &::backdrop { background-color: gray; }
    &:has(*) { color: #27ca3f; }
}

What is gathered:

  • Exact selector duplicates — later blocks merge into the first; declarations are promoted to the top of that block
  • Directly attached pseudo-classes / elements → &:hover, &:has(*), &::backdrop
  • Combinator variants → + *, > .child, ~ .peer
  • Whitespace descendants → :not(*), .child (no spurious &)

Intervening rules, comments, and @keyframes are left untouched.

Safety: REVIEW. Requires --allow-review on the CLI, or enabling the rule in the TUI. Verify cascade order after apply.

TUI

  • Windows scroll fix on Select Rules: wrapped descriptions no longer bleed into the next row or desync the cursor. Each rule is one clipped line; only the list pane scrolls; header and enabled-count stay fixed.
  • PgUp / PgDn move the rules (and files) cursor by a page.
  • Select All (a) on the rules screen — same toggle-all behavior as files. Press again to deselect all.

Fixes

  • Worktree preservation: GatherRelatedSelectorRules previously replaced first.start..last.end, deleting everything between non-adjacent matches (including @keyframes). It now writes one replacement at first.start..first.end and a deletion plan per later occurrence.
  • Descendant & prefix: extract_related_nested_selector no longer prepends & to whitespace-separated descendants. .skip-link :not(*) nests as :not(*), not &:not(*).

Version

0.1.0 → 0.2.0

Official Multi-Platform Binaries

Platform Architecture Archive File
Windows Intel / AMD x64 cssforge-v0.2.0-windows-x64.zip
Windows Snapdragon / ARM64 cssforge-v0.2.0-windows-arm64.zip
Linux Intel / AMD x64 cssforge-v0.2.0-linux-x64.tar.gz
Linux Snapdragon / ARM64 cssforge-v0.2.0-linux-arm64.tar.gz
macOS Apple Silicon M-Series cssforge-v0.2.0-macos-arm64.tar.gz

Checksums

SHA256 checksums are available in SHA256SUMS.txt.

Verification Example

sha256sum -c SHA256SUMS.txt