This directory contains the abstract syntax tree that represents a plain CSS file generated by Sass compilation. It differs from other Sass ASTs in two major ways:
-
Instead of being created by a parser, it's created by the evaluator as it traverses the Sass AST.
-
Because of various Sass features like
@extend
and at-rule hoisting, the CSS AST is mutable even though all other ASTs are immutable.
Note: the CSS AST doesn't have its own representation of declaration values.
Instead, declaration values are represented as Value
objects. This does mean
that a CSS AST can be in a state where some of its values aren't representable
in plain CSS (such as maps)—in this case, the serializer will emit an error.
Internally, the CSS AST is mutable to allow for operations like hoisting rules
to the root of the AST and updating existing selectors when @extend
rules are
encountered. However, because mutability poses a high risk for "spooky action
at a distance", we limit access to mutating APIs exclusively to the evaluator.
We do this by having an unmodifiable interface (written in this directory) for
each CSS AST node which only exposes members that don't modify the node in
question. The implementations of those interfaces, which do have modifying
methods, live in the modifiable
directory. We then universally refer to the
immutable node interfaces except specifically in the evaluator, and the type
system automatically ensures we don't accidentally mutate anything we don't
intend to.
(Of course, it's always possible to cast an immutable node type to a mutable one, but that's a very clear code smell that a reviewer can easily identify.)
A lesser-known fact about Sass is that it actually supports three syntaxes for its source files: SCSS, the indented syntax, and plain CSS. But even when it parses plain CSS, it uses the Sass AST rather than the CSS AST to represent it so that parsing logic can easily be shared with the other stylesheet parsers.