gale-lint 0.1.5

An extremely fast CSS linter, written in Rust
gale-lint-0.1.5 is not a library.

Gale

An extremely fast CSS linter. Drop-in replacement for Stylelint.

npm version CI license: MIT

Gale reads your existing .stylelintrc, runs the same rules, and produces the same output. Just 10x-100x faster.

One line change in your package.json. No config migration.

Benchmarks

Real-world benchmarks using hyperfine (10 runs, 3 warmup) on an Apple M4 Max. Each repo uses its own Stylelint config. Results vary by machine -- run ./benchmarks/benchmark.sh to reproduce on yours.

Repository Files Stylelint Gale Speedup
Angular Components 621 0.743s 0.008s 96x
Fundamental Styles 392 3.628s 0.060s 61x
GOV.UK Frontend 149 2.352s 0.044s 54x
Discourse 356 0.529s 0.010s 51x
Joomla 169 1.033s 0.025s 41x
Carbon 1,116 0.385s 0.010s 38x
Bootstrap 99 0.737s 0.021s 35x
Gutenberg 778 0.447s 0.013s 34x
PatternFly 204 0.377s 0.013s 29x
SLDS 446 0.323s 0.014s 24x

Parity: 0 false positives and 0 false negatives across all 22 tested repositories (5,790 files).

Quick start

# Install
npm install -D @lyricalstring/gale

# Lint (uses your existing .stylelintrc)
npx gale "src/**/*.css"

# Autofix
npx gale --fix "src/**/*.css"

Migrate from Stylelint

Change one line in package.json:

 {
   "scripts": {
-    "lint:css": "stylelint 'src/**/*.css'"
+    "lint:css": "gale 'src/**/*.css'"
   }
 }

Your .stylelintrc stays exactly the same. Gale reads the same config files, follows the same extends chains, honors /* stylelint-disable */ comments, and produces the same JSON output format.

Installation

npm (recommended)

npm install -D @lyricalstring/gale

The npm package automatically downloads the correct platform binary on install. Supported platforms: macOS (arm64, x64), Linux (x64, arm64).

Cargo

cargo install gale-lint

The crate is named gale-lint on crates.io (since gale was taken), but the installed binary is called gale.

From source

git clone https://github.com/LyricalString/gale.git
cd gale
cargo build --release
# Binary at target/release/gale

GitHub releases

Download pre-built binaries from GitHub Releases.

What's supported

260+ built-in rules

Gale ships 260+ built-in rules across four categories:

Category Count Examples
Core Stylelint 144 block-no-empty, color-no-invalid-hex, property-no-unknown
SCSS (scss/*) 44 scss/at-rule-no-unknown, scss/no-duplicate-mixins, scss/dollar-variable-pattern
Stylistic (@stylistic/*) 59 stylistic/indentation, stylistic/declaration-colon-space-after, stylistic/no-eol-whitespace
Order (order/*) 3 order/order, order/properties-order, order/properties-alphabetical-order

SCSS and stylistic rules are built in -- no extra plugins required.

Config compatibility

All Stylelint config formats are supported:

File Format
gale.json JSON (native)
gale.toml TOML (native)
.stylelintrc JSON or YAML
.stylelintrc.json JSON
.stylelintrc.yml / .yaml YAML
stylelint.config.js / .cjs JavaScript

Feature overview

  • SCSS and Less out of the box (no plugins needed)
  • Autofix via --fix
  • File caching via --cache (skips unchanged files)
  • LSP server for editor integration (--lsp)
  • Parallel linting using all CPU cores
  • Inline disable comments (stylelint-disable and gale-disable)
  • JSON, text, and compact output formatters matching Stylelint's format
  • extends with built-in presets, npm packages, and relative paths
  • .galeignore files (gitignore syntax) for custom exclusions

Not yet supported

  • Custom JavaScript plugins. Third-party rule packages (community plugins) are not supported. Gale only runs its built-in rules.
  • package.json config. The "stylelint" field in package.json is not read.
  • Sass indented syntax. .sass files are not supported (.scss works fine).

Configuration

Gale searches for config files walking up from the working directory. To generate a starter config:

npx gale --init

Example config

{
  "extends": "gale:recommended",
  "rules": {
    "block-no-empty": true,
    "color-hex-length": "warning",
    "number-max-precision": ["error", { "max": 4 }],
    "declaration-no-important": "off"
  }
}

Rule value formats

Format Meaning
true Enable at error severity
false or "off" Disable
"error" Enable at error severity
"warning" Enable at warning severity
["error", { options }] Enable with options

Built-in presets

Preset Description
gale:recommended Sensible defaults (29 rules: 15 error + 14 warning)
gale:all All rules enabled at warning severity

You can also extend npm packages like stylelint-config-standard directly.

Extends resolution

The extends field supports:

Value Resolution
"gale:recommended" Built-in preset
"gale:all" Built-in preset
"./path/to/config.json" Relative path to another config file
"stylelint-config-standard" npm package (resolved from node_modules/)

Resolution is recursive with cycle detection. Later extends entries override earlier ones. User rules always override extended rules.

CLI reference

gale [OPTIONS] [FILES]...
Flag Description
<files> Files, directories, or glob patterns to lint
--fix Automatically fix problems
-q, --quiet Only report errors
-f, --formatter <type> Output: text (default), json, compact
-c, --config <path> Config file path
--max-warnings <n> Error if warnings exceed threshold
--cache Skip unchanged files
--cache-location <path> Custom cache file path (default: .gale_cache)
--stdin Read from stdin
--stdin-filename <name> Virtual filename for stdin (default: stdin.css)
--ignore-path <file> Custom ignore file (gitignore syntax)
--no-ignore Disable all ignore file processing
--print-config <file> Print resolved config as JSON
--init Generate starter config
--lsp Start LSP server

Editor integration

Any LSP-compatible editor

gale --lsp

Works with Neovim, Helix, Zed, and any editor supporting the Language Server Protocol.

Development

Prerequisites

  • Rust 2024 edition (1.85+)
  • Python 3 (for differential tests)
  • Node.js 16+ (for differential tests and npm packaging)

Build and test

cargo build                          # Debug build
cargo build --release                # Release build
cargo test --workspace               # Run all tests
cargo test -p gale_linter            # Tests for a specific crate
cargo test -p gale_linter block_no_empty  # A specific test
cargo clippy --workspace -- -D warnings   # Lint the Rust code
cargo fmt --check                    # Check formatting

Run the linter

cargo run -- "src/**/*.css"          # Lint
cargo run -- --fix "src/**/*.css"    # Autofix
cargo run -- --formatter json src/   # JSON output

Debug and profiling

GALE_DEBUG_PERF=1 cargo run --release -- src/   # Per-phase timings to stderr
GALE_LOG=debug cargo run -- src/                # Tracing/logging output

Differential testing

Compare Gale output against Stylelint on real-world repositories:

python tests/differential/run.py              # All repos
python tests/differential/run.py bootstrap    # Specific repo
python tests/differential/run.py --benchmark  # Include timing comparison
python tests/differential/run.py --list       # List available repos
python tests/differential/run.py --css-only   # Skip SCSS/Less
python tests/differential/run.py --skip-build # Use existing binary

The test corpus includes Bootstrap, Gutenberg, Carbon, Angular Components, wp-calypso, Discourse, GOV.UK Frontend, Spectrum CSS, Docusaurus, Grafana, Material UI, freeCodeCamp, PatternFly, Primer CSS, Elastic EUI, Mattermost, Mastodon, JupyterLab, Joomla, SLDS, rsuite, and Fundamental Styles.

Benchmarks

bash benchmarks/benchmark.sh         # Full benchmark suite
bash benchmarks/run-benchmark.sh     # Quick benchmark

Releasing

Releases are automated via GitHub Actions when you push a version tag:

# 1. Update the version in Cargo.toml (workspace.package.version)
# 2. Commit the version bump
# 3. Tag and push
git tag v0.2.0
git push && git push --tags

The release workflow will:

  1. Build binaries for Linux (x64, arm64) and macOS (x64, arm64)
  2. Create a GitHub Release with the binaries
  3. Publish the npm package (@lyricalstring/gale) with the matching version

Manual npm build

# Build for current platform
./scripts/build-npm.sh

# Build for all platforms (requires cross + Docker)
./scripts/build-npm.sh --all

# Set npm package version before building
./scripts/build-npm.sh --version 0.2.0

Architecture

Gale is organized as a Cargo workspace with seven crates:

gale (binary)
  |
  v
gale_cli         CLI definition (clap), file discovery, orchestration
  |
  +-- gale_config       Config loading, resolution, presets
  +-- gale_linter       Rule trait, registry, runner, 260+ built-in rules
  |     +-- gale_css_parser    CSS/SCSS/Less parser (lightningcss + raffia)
  |     +-- gale_diagnostics   Span, Diagnostic, LintResult, Fix/Edit types
  +-- gale_formatter    Output formatters (text, json, compact)
  +-- gale_lsp          Language Server Protocol server
Crate Responsibility
gale_css_parser Wraps lightningcss (CSS) and raffia (SCSS/Less) into a unified, owned AST
gale_diagnostics Core types: Span, Diagnostic, LintResult, Fix, Edit
gale_linter Rule trait, RuleRegistry, LintRunner, inline disable comments, all rule implementations
gale_config Config file discovery, parsing (JSON/YAML/TOML/JS), extends resolution, built-in presets
gale_formatter TextFormatter, JsonFormatter, CompactFormatter matching Stylelint output
gale_cli Clap CLI, file discovery with ignore support, cache layer, --fix orchestration
gale_lsp LSP server for real-time editor diagnostics

See CLAUDE.md for detailed architecture docs and how to add rules.

License

MIT