Skip to content

Releases: zoosky/accent-sass

accent-sass 0.16.0

Choose a tag to compare

@zoosky zoosky released this 13 Sep 09:41
Immutable release. Only release title and notes can be modified.
2308d33

Install

[dependencies]
accent-sass = "0.16.0"

Published to crates.io as accent-sass, accent_sass_compiler and accent-sass-macro. Documentation: https://zoosky.github.io/accent-sass.

The browser package is published to npm as @zoosky/accent-sass, at the same version:

npm install @zoosky/accent-sass

Sixty merged pull requests since 0.15.0: a JavaScript API and a C ABI for the WebAssembly builds, --check on the command line, the move of the reference implementation to dart-sass 1.104.1, the first deprecation warning, and a run of fixes that bring @extend, builtin calls, selectors and error positions in line with dart-sass.

The minor version rises because four changes are breaking while the major version is 0: @extend across a media query is an error, builtin calls are checked against dart-sass's parameter lists, seven inputs dart-sass refuses are rejected, and a selector whose combinators cannot match is omitted.

Against the pinned sass-spec revision (b39c32768) the suite stands at 14,147 of 14,266 passing, measured on macOS 2026-09-13; the Linux CI runner reports two fewer, the same offset as before. This release moved the pin from 4a9eea66, which added 48 runs, so the count is not directly comparable with 0.15.0's 13,926 of 14,218. Bulma, Pico, Foundation and USWDS compile byte-identically to dart-sass 1.104.1.

Added

  • a C ABI for WebAssembly hosts, behind the wasi-exports feature. accent_sass_alloc, accent_sass_dealloc, accent_sass_compile_string, accent_sass_compile_path and accent_sass_result_free turn the wasm32-wasip1 cdylib into a reactor a plugin host instantiates once and calls many times, instead of paying process startup per stylesheet. Strings cross as UTF-8 in linear memory and a result is three 32-bit words: status, pointer, length. Built with the workspace's small profile, the module is 1.31 MiB against 2.42 MiB under release
  • options for that C ABI. accent_sass_options_new returns an opaque handle a host fills in and passes to accent_sass_compile_string_with_options or accent_sass_compile_path_with_options, which covers output style, entry point syntax, load paths, charset, alertAscii and quiet. The setters are named after dart-sass's JavaScript API so this ABI and the browser binding do not drift apart; a value the ABI does not define is refused rather than rounded to a default. accent_sass_compile_string and accent_sass_compile_path are unchanged and still compile with defaults
  • a JavaScript API for the browser build. compileString(source, options) and compile(path, options) join from_string, which keeps working. The options are style, syntax, loadPaths, files, url, charset, alertAscii, quiet and logger, named after dart-sass's JavaScript API wherever it has a name for the same knob; a failed compile throws an Error carrying message, formatted, file, line and column, and index.d.ts declares the surface with real types. Before this the package exported one function with StdFs behind it, so every @use failed at run time with Can't find stylesheet to import. and a page could compile a single stylesheet and nothing else
  • MemoryFs and from_string_with_file_name are public. The browser binding resolves imports through MemoryFs, and making it a public type rather than something private to the binding is what lets cargo test reach it: the bindings themselves exist only on wasm32-unknown-unknown. It also stands on its own for a host that already holds its stylesheets, such as a CMS compiling a theme out of a database
  • --check on the command line, which compiles and writes nothing. Given an output file it compares the CSS it produced against what that file already holds, so a job can ask whether committed CSS is still what the Sass produces without a build step, a temporary file or a diff. It exits 3 on a stale or missing output file and 1 on a stylesheet that does not compile, which keeps "your CSS is out of date" and "your Sass is broken" apart in a log; 2 is still clap's usage error. Writing nothing is the point of the mode: it reports whether a build is current without being able to change the answer
  • deprecation warnings, starting with bogus-combinators. A style rule whose selector has a leading, trailing or repeated combinator, and an @extend inside one, now warn as dart-sass 1.104.1 does: the same message, and a source frame that marks the selector and the declaration, comment or at-rule that makes it a problem. a > {b: c} was silently dropped from the output before, and now says why. After five warnings of one deprecation the rest are counted, and the count is reported at the end
  • Logger::deprecation and Logger::repetitive_deprecations_omitted, with the Deprecation and DeprecationWarning types they receive. Both methods have defaults, so an existing logger keeps compiling: a deprecation reaches it through Logger::warn with the message alone, and the count is dropped. DeprecationWarning::formatted holds the full text StdLogger prints
  • Options::verbose and --verbose, which report every deprecation warning instead of counting the ones after the fifth. --verbose was accepted and hidden before, and did nothing
  • --indented works, and is no longer hidden. It reads the entry point as the indented syntax whatever the file is called. That matters most for --stdin, which is the one input route with no extension to infer a syntax from, and the route the flag exists to serve

Changed

  • the reference implementation moves from dart-sass 1.103.1 to 1.104.1, and the changes of both releases are followed. A loud comment written above @use or @forward is written once, where it stands. Exact negative zero prints as -0 rather than 0, so it keeps its sign when used in a CSS calculation; math.round, math.ceil, math.floor and the calculation round() still return 0, because dart-sass rounds to an integer. A colour channel that is NaN or negative zero becomes 0, and so does a hue that is infinite: hsl(math.div(1, 0), 50%, 50%) is now hsl(0, 50%, 50%) rather than hsl(calc(NaN), 50%, 50%). As in dart-sass, color.change() on an rgb colour keeps such a channel until the colour is converted to another space, and red(), green() and blue() read a -0 channel back as 0
  • Breaking: @extend across a media query is an error. An @extend written inside @media may only extend a selector in the identical query; extending across queries would need the extended rule to exist in a context it was never written for. It extended silently before, which is worse than refusing: the check was commented out and the store never recorded a selector's media context at all, so every selector looked top-level. !optional does not silence it, since it says the extension need not match anything rather than that a wrong match is allowed
  • Breaking: builtin calls are checked against dart-sass's parameter lists. Builtins read their arguments by position with no declared parameter list, so an unknown name could not be rejected and a real one could not be found: map.remove($key: 1) and list.join(c, d, $invalid: true) compiled. All 196 registrations now carry the parameter list dart-sass 1.103.1 declares, overloads included, and a call picks its overload, is verified against it, and has its named arguments bound to their declared positions. The unknown-name error says "parameter", as dart-sass does, for user-defined functions too
  • Breaking: seven inputs dart-sass refuses are rejected. A style rule inside a keyframe block, @mixin --a and @include --a (plain CSS is getting mixins of its own and -- names are reserved for them), a custom property nested beneath another declaration, and an unbalanced bracket in a selector. The bracket tracking also closes ten fixtures in the indented syntax, where a newline inside a bracket no longer ends the selector
  • Breaking: a selector whose combinators cannot match is omitted. Two combinators in a row, more than one leading combinator, or a trailing one make a selector bogus, so a rule left with nothing visible is not printed and a useless selector can no longer act as an extender. The rules are ported from the dart-sass 1.104.0 source, which hides such selectors when writing CSS rather than in the evaluator, so selector.parse(":is(.a > + .b)") still keeps its argument. selector.replace() raises dart-sass's "components may not be empty" where it used to panic
  • Breaking: two parse errors say what dart-sass 1.104.1 says. Where a selector should start but nothing does, the error is expected end of rule. rather than expected "}"., and text that starts no rule, such as ! {} or a !optional on a line of its own in the indented syntax, is unrecognized syntax over that text. An unclosed block reports what its contents expected, so @function foo() { and a {foo: {bar: red say Expected identifier. as dart-sass does

Fixed

  • an error points where dart-sass points. Input that ends early was reported one column short, on its last character rather than just past it, and an input ending in a newline highlighted the newline across the line. A missing expression highlighted everything back to the start of the expression, so a {b: 1 + ;} underlined 1 + where dart-sass puts one caret at the ;. As in dart-sass, an "expected" error whose place is the start of a line now points at the end of the line before it, and a missing expression directly after #{ highlights the #{. Only the caret moved; no message changed
  • ten command-line flags consumed the argument after them. --indented, --update, --no-error-css, --no-source-map, `--embed-sources...
Read more