gale-lint 0.1.1

An extremely fast CSS linter, written in Rust
gale-lint-0.1.1 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 100x-400x faster.

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

Benchmarks

Real-world benchmarks using hyperfine (10 runs, 3 warmup). Each repo uses its own Stylelint config.

Repository Files Stylelint Gale Speedup
Bootstrap 99 1.569s 0.011s 143x
Carbon 1,116 8.767s 0.022s 399x
PatternFly 204 5.298s 0.015s 353x
Spectrum CSS 241 2.952s 0.011s 268x
GOV.UK Frontend 163 1.614s 0.011s 147x
Primer CSS 113 1.285s 0.010s 129x
Gutenberg 775 4.715s 0.042s 112x
wp-calypso 2,238 13.223s 0.131s 101x
Angular Components 620 1.843s 0.021s 88x
Discourse 355 1.438s 0.021s 69x

Parity: 0 false positives and 0 false negatives across all 16 tested repositories (6,673 files).

Reproduce these results: ./benchmarks/benchmark.sh

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).

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

250 built-in rules

Gale ships 250 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

VS Code

A VS Code extension is included at editors/vscode/.

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, and Mattermost.

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 and 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 version across all packages 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, 250 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