0.3.0 - 2026-06-13
Release Notes
Since 0.2.0. Conformance holds at 100% of the attempted sass-spec suite
(13,896 / 13,896) — but that suite covers valid inputs plus the errors it
expects; this cycle hardened sasso to reject the same malformed inputs
dart-sass rejects, and cut more of the @extend and value hot paths.
Changed
- Strict input validation. Beyond matching dart-sass's output, sasso now
errors — rather than silently accepting — on malformed input, each with
dart-sass's exact message: an invalid hex literal (#00000,#0g),
out-of-grammarrgb()/hsl()channel units and legacy-vs-modern argument
shapes, a duplicate@mixin/@functionparameter, a malformed number
exponent (1e-), a non-identifier@use/@forwardnamespace, a misplaced
@content/@extend, a style rule / declaration /@extendin a@function
body, a map or empty list used as a CSS value (#{(a:1)},-()), a
malformed:nth-child()An+B or empty:not()selector, a stray!in a
selector, a leading-empty@extendtarget, and a malformed@charset/
@at-root (…)query. Found by a leniency-mining sweep that diffed every
category against dart-sass; the fixes are uncovered by the spec, so the
ratchet is unchanged.
Performance
- Transitive
@extendwent from ~151× slower than dart-sass to faster
on a deep extend chain: a match pre-filter with typed dedup, an incremental
per-rule fold (killing the O(N²) closure re-derivation), borrowed
scope-originals, and cached typed selector hashes — the@extendmaps are
now FxHash + typedComplex/Simplekeys, guarded by a render-injectivity
parity proof. Byte-identical output throughout. - Reference-counted composite values —
Str/List/MapareRc-backed,
so cloning a read-only$variableis an O(1) refcount bump instead of a deep
copy (copy-on-write for the mutating builtins): ~7× fewer instructions and
~13× less peak memory when a large list/map is passed through a call chain. Cow-borrowed argument-name normalization (called 4–6× per function
call) plus trimmed function-call-path allocations — ~15% fewer instructions
on a function-heavy compile.- Arena in-place
realloc— the scoped bump arena extends its tail
allocation in place instead of stranding a dead buffer on everyVec
doubling, trimming peak memory on parse-heavy compiles. - Net: pure-compile throughput ~7.4 ms on the large benchmark (was ~9–10),
~2.3–2.9× faster thangrassand ~19–30× faster than the dart-sass JS bin.
Internal
eval.rssplit into aneval/module directory andcolor.rsinto a
color/directory (pure code moves); the typed selector model gained a
parity-proof harness; the stringly hoist markers became typedOutNode
variants; the@extendcartesian-order bool became aCartesianOrderenum;
OutNoderule/at-rule constructors collapsed duplicated construction sites.
All byte-identical, each verified base-binary-vs-refactor.
Tooling
- The WebAssembly npm package publishes via OIDC Trusted Publishing (no token).
- Benchmark harness uses portable temp-file handling (
mktemp -d).
Install sasso 0.3.0
Install prebuilt binaries via shell script
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/momiji-rs/sasso/releases/download/v0.3.0/sasso-installer.sh | shInstall prebuilt binaries via powershell script
powershell -ExecutionPolicy Bypass -c "irm https://github.com/momiji-rs/sasso/releases/download/v0.3.0/sasso-installer.ps1 | iex"Download sasso 0.3.0
| File | Platform | Checksum |
|---|---|---|
| sasso-aarch64-apple-darwin.tar.xz | Apple Silicon macOS | checksum |
| sasso-x86_64-apple-darwin.tar.xz | Intel macOS | checksum |
| sasso-x86_64-pc-windows-msvc.zip | x64 Windows | checksum |
| sasso-aarch64-unknown-linux-gnu.tar.xz | ARM64 Linux | checksum |
| sasso-x86_64-unknown-linux-gnu.tar.xz | x64 Linux | checksum |
| sasso-aarch64-unknown-linux-musl.tar.xz | ARM64 MUSL Linux | checksum |
| sasso-x86_64-unknown-linux-musl.tar.xz | x64 MUSL Linux | checksum |