# CSS::Minifier

CSS minifier for Raku - parses, optimizes, and re-serializes CSS stylesheets.

## Features

- **Plugin pipeline** - modular optimization passes (values, colors, dedup, merging)
- **Two levels** - level 1 (safe normalizations) vs level 2 (structural optimizations)
- **Color optimization** - shorten hex colors, optionally convert to named colors (delegated to CSS::Writer/CSS::Properties)
- **Value normalization** - `bold` → `700`, `normal` → `400`
- **Duplicate removal** - identical rulesets and `@font-face` blocks deduplicated
- **Ruleset merging** - same-selector rules merged, same-declaration selectors combined
- **Shorthand consolidation** - leverages CSS::Properties optimizer for compact output
- **License preservation** - `/*! */` comments kept with `--preserve-licenses`
- **Unknown property preservation** - declarations CSS::Properties doesn't recognize (e.g. `text-decoration-line`, `display: flex`) are pre-scanned from raw CSS and re-injected into the minified output. Disable with `:!preserve-unknown`.
- **CLI tool** - `cssminify` with stdin/file input and output redirection

## Dependencies

- [CSS::Stylesheet](https://raku.land/zef:dwarring/CSS::Stylesheet) - CSS parsing and AST
- [CSS::Properties](https://raku.land/zef:dwarring/CSS::Properties) - property optimization
- [CSS::Writer](https://raku.land/zef:dwarring/CSS::Writer) - CSS serialization

## Installation

```bash
zef install CSS::Minifier
```

### Installing from source

```bash
cd /path/to/CSS-Minifier
zef install .
```

Requires Raku 6.d or later.

## Usage

### Command Line

```bash
# Read from file
cssminify input.css > output.css

# Level 2 (structural optimizations: dedup, merging)
cssminify -l2 input.css > output.css

# Write to file
cssminify -o output.css input.css

# Read from stdin
cat input.css | cssminify

# Preserve license comments
cssminify -p input.css

# Disable hex color shortening (keep #FF0000 instead of #F00)
cssminify --no-color-masks input.css

# Disable unknown-property preservation (declarations dropped by CSS::Properties stay dropped)
cssminify --no-preserve-unknown input.css

# Separate rules with newlines (readable output)
cssminify -r input.css

# Convert hex colors to named colors
cssminify -n input.css

# Verbose output (log plugin names)
cssminify -v input.css

# Print version
cssminify --version
```

#### Flags

| Short | Long | Description |
|---|---|---|
| `-o` | `--output` | Write to file instead of stdout |
| `-l` | `--level` | Optimization level: 1 (default) or 2 (structural) |
| `-p` | `--preserve-licenses` | Keep `/*! */` license comments |
| `-n` | `--color-names` | Convert hex colors to named colors |
| `-m` / `-/m` | `--color-masks` / `--no-color-masks` | Enable/disable hex color shortening |
| `-u` / `-/u` | `--preserve-unknown` / `--no-preserve-unknown` | Enable/disable unknown-property preservation (default: enabled) |
| `-r` | `--readable` | Separate rules with newlines |
| `-v` | `--verbose` | Log plugin names to stderr |
| | `--version` | Print version and exit |

Negatable booleans accept `--no-flag` (long) or `-/f` (short), e.g. `--no-color-masks` or `-/m`.

Short flags with values use `=` or fused syntax: `-l=2` or `-l2` (not `-l 2`).

### Library

```raku
use CSS::Minifier;

# Level 1 - safe normalizations
my $min = CSS::Minifier.minify($css);

# Level 2 - structural optimizations (dedup, merging)
my $min = CSS::Minifier.minify($css, :level(2));

# Preserve license comments
my $min = CSS::Minifier.minify($css, :preserve-licenses);

# Convert hex colors to named colors
my $min = CSS::Minifier.minify($css, :color-names);

# Disable hex color shortening
my $min = CSS::Minifier.minify($css, :!color-masks);

# Disable unknown-property preservation (dropped by CSS::Properties)
my $min = CSS::Minifier.minify($css, :!preserve-unknown);

# Add custom plugins (runs after all level plugins, in append order)
# Custom plugins must implement the CSS::Minifier::Plugin role.
my $min = CSS::Minifier.minify($css, :level(2), :extra-plugins[$my-plugin]);
```

## Optimization Levels

### Level 1 (default)
- Font-weight normalization (`bold` → `700`, `normal` → `400`)
- Color shortening (`#FF0000` → `#F00`, `red` → `#F00`)
- Shorthand consolidation (via CSS::Properties optimizer)
- Comment removal (`/*! */` kept with `--preserve-licenses`)
- Whitespace removal (via compact writer)

### Level 2
- Duplicate ruleset removal
- `@font-face` deduplication
- Same-selector ruleset merging
- Same-declaration selector combination (propertyless parsing artifacts are skipped, not barriers)



## Examples

### Input
```css
h1 { color: red; }
h2 { color: red; }
h1 { margin: 0; }
```

### Level 1 Output
```css
h1{color:#F00}h2{color:#F00}h1{margin:0}
```

### Level 2 Output
```css
h1, h2{color:#F00}h1{margin:0}
```
# AUTHOR

Sasha Abbott <sashaa@disroot.org>

# LICENSE

This library is free software; you can redistribute it and/or modify it under CC0.
