marianoguerra/css/ast does not have a README file

    AnB

    pub(all) struct AnB {
    a : Int
    b : Int
    } derive(Eq,
    Debug
    )

    AttrCase

    pub(all) enum AttrCase {
    Default
    Insensitive
    Sensitive
    } derive(Eq,
    Debug
    )

    AttrOp

    pub(all) enum AttrOp {
    Exact
    Includes
    DashMatch
    Prefix
    Suffix
    Substring
    } derive(Eq,
    Debug
    )

    AttrOp::text

    fn AttrOp::text(self : AttrOp) -> String

    AttrSelector

    pub(all) struct AttrSelector {
    ns : NsPrefix?
    name : String
    matcher : (AttrOp, AttrValue)?
    case_ : AttrCase
    } derive(Eq,
    Debug
    )

    AttrValue

    pub(all) enum AttrValue {
    Str(String)
    Ident(String)
    } derive(Eq,
    Debug
    )

    BlockItem

    pub(all) enum BlockItem {
    Decl(Declaration)
    Rule(CssRule)
    Comment(Comment)
    Bogus(Bogus)
    } derive(Eq,
    Debug
    )

    The body of a rule: declarations and nested rules, in source order.

    One sequence rather than two fields, because the cascade is order-sensitive and CSS nesting interleaves them. lightningcss splits !important out into a second vector for the same reason a minifier would; that reordering is unrecoverable, so importance is a field on Declaration here.

    Bogus

    What could not be parsed, kept so that the tree covers the whole source.

    text is the exact source the node replaced. Keeping it is what lets the printer echo an unparsable region verbatim instead of deleting it -- a stylesheet with one vendor hack the parser does not know should come back with that hack still in it.

    Combinator

    pub(all) enum Combinator {
    Descendant
    Child
    NextSibling
    SubsequentSibling
    Column
    } derive(Eq,
    Debug
    )

    Comment

    pub(all) struct Comment {
    text : String
    span :
    Span

    } derive(Eq,
    Debug
    )

    A /* ... */ comment.

    text is the body, without the delimiters. Comments are attached to the construct they precede rather than being free-floating, because a printer that keeps them has to know where to put them back.

    ComponentValue

    pub(all) enum ComponentValue {
    Ident(String)
    Str(String)
    Num(Number)
    Dimension(Number, String)
    Percentage(Number)
    Hex(String)
    Url(String)
    Function(String, Array[ComponentValue])
    Paren(Array[ComponentValue])
    Bracket(Array[ComponentValue])
    Comma
    Slash
    Delim(String)
    Bogus(Bogus)
    } derive(Eq,
    Debug
    )

    A component value: the generic model that every declaration value uses.

    Generic rather than per-property, and that is the load-bearing choice in the whole design. lightningcss types some five hundred properties, which buys static guarantees and costs the ability to represent anything the table does not know -- a vendor hack, a property added last month, a value behind a flag. A stylesheet full of those is not an edge case, it is Tuesday.

    The typed reading is recovered on demand by the lenses in css/value (as_length, as_color, ...), the way biome layers value_ext.rs over its untyped tree. That keeps coverage total and makes the typed view something you opt into per question rather than something the parser must decide up front for every property in existence.

    Compound

    pub(all) struct Compound {
    type_sel : TypeSelector?
    quals : Array[Qualifier]
    span :
    Span

    } derive(Eq,
    Debug
    )

    One element's worth of selector: an optional type, then qualifiers.

    Condition

    pub(all) enum Condition {
    Feature(Feature)
    Decl(Declaration)
    SelectorFn(Array[Selector])
    Operation(LogicalOp, Array[Condition])
    Unknown(Array[ComponentValue])
    Bogus(Bogus)
    } derive(Eq,
    Debug
    )

    A @media, @supports or @container condition.

    Operation is n-ary and stored flattened: a and b and c is one node with three children, not two nested nodes. biome nests them because its grammar language cannot express an n-ary list with interleaved keywords; there is no such constraint here, and the flat form is what makes the round-trip property a plain equality instead of an equality-modulo-associativity.

    ContainerRule

    pub(all) struct ContainerRule {
    name : String?
    condition : Condition
    body : Array[BlockItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    CssRule

    pub(all) enum CssRule {
    Style(StyleRule)
    Media(MediaRule)
    Supports(SupportsRule)
    Container(ContainerRule)
    Layer(LayerRule)
    Keyframes(KeyframesRule)
    FontFace(DeclBlock)
    Page(PageRule)
    Property(PropertyRule)
    Import(ImportRule)
    Charset(String,
    Span
    )
    Namespace(NamespaceRule)
    Scope(ScopeRule)
    StartingStyle(Array[BlockItem],
    Span
    )
    CounterStyle(String, DeclBlock)
    Unknown(UnknownAtRule)
    Bogus(Bogus)
    } derive(Eq,
    Debug
    )

    A rule, at any level.

    Style rules and at-rules are one enum rather than two because CSS nesting lets either appear wherever the other can, and splitting them would mean every body was a pair of lists that had lost their relative order.

    DeclBlock

    pub(all) struct DeclBlock {
    decls : Array[BlockItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    A block that may hold only declarations -- @font-face, @page, a keyframe. Typed separately so the parser can refuse a nested rule there rather than accepting one and printing something invalid.

    Declaration

    pub(all) struct Declaration {
    property : PropertyName
    value : Array[ComponentValue]
    important : Bool
    span :
    Span

    } derive(Eq,
    Debug
    )

    Feature

    pub(all) enum Feature {
    Boolean(String)
    Plain(String, Array[ComponentValue])
    Range(String, RangeOp, Array[ComponentValue])
    Interval(Array[ComponentValue], RangeOp, String, RangeOp, Array[ComponentValue])
    } derive(Eq,
    Debug
    )

    A media or container feature test, in all four shapes CSS gives it.

    ImportRule

    pub(all) struct ImportRule {
    url : String
    layer : LayerName??
    supports : Condition?
    media : Array[MediaQuery]
    span :
    Span

    } derive(Eq,
    Debug
    )

    layer has three states and they are all different: absent, layer (anonymous), and layer(name). The nested option is what says so in the type rather than in a comment.

    KeyframeBlock

    pub(all) struct KeyframeBlock {
    selectors : Array[KeyframeSelector]
    decls : DeclBlock
    span :
    Span

    } derive(Eq,
    Debug
    )

    KeyframeSelector

    pub(all) enum KeyframeSelector {
    From
    To
    Percentage(Number)
    } derive(Eq,
    Debug
    )

    KeyframesName

    pub(all) enum KeyframesName {
    Ident(String)
    Str(String)
    } derive(Eq,
    Debug
    )

    KeyframesRule

    pub(all) struct KeyframesRule {
    name : KeyframesName
    frames : Array[KeyframeBlock]
    span :
    Span

    } derive(Eq,
    Debug
    )

    LayerName

    pub(all) struct LayerName {
    parts : Array[String]
    } derive(Eq,
    Debug
    )

    A dotted layer name: base.theme is ["base", "theme"].

    LayerRule

    pub(all) struct LayerRule {
    names : Array[LayerName]
    body : Array[BlockItem]?
    span :
    Span

    } derive(Eq,
    Debug
    )

    body is None for the statement form @layer a, b; and Some for the block form. The two are different rules in CSS, not one rule with an optional body, and the parser must know which it is to print it back.

    LogicalOp

    pub(all) enum LogicalOp {
    And
    Or
    Not
    } derive(Eq,
    Debug
    )

    MediaQualifier

    pub(all) enum MediaQualifier {
    Only
    Not
    } derive(Eq,
    Debug
    )

    MediaQuery

    pub(all) struct MediaQuery {
    qualifier : MediaQualifier?
    media_type : String?
    condition : Condition?
    } derive(Eq,
    Debug
    )

    MediaRule

    pub(all) struct MediaRule {
    queries : Array[MediaQuery]
    body : Array[BlockItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    NamespaceRule

    pub(all) struct NamespaceRule {
    prefix : String?
    url : String
    span :
    Span

    } derive(Eq,
    Debug
    )

    NsPrefix

    pub(all) enum NsPrefix {
    None_
    Any
    Named(String)
    } derive(Eq,
    Debug
    )

    |a is None_, *|a is Any, svg|a is Named.

    Number

    pub(all) struct Number {
    repr : String
    value : Double
    is_int : Bool
    } derive(Eq,
    Debug
    )

    A number, with the spelling it had in the source.

    repr exists because CSS distinguishes 1 from 1.0 nowhere semantically but everywhere visually, and a formatter that rewrote every number would produce a diff on every line of a file it was asked only to reindent. value is what arithmetic uses; repr is what the printer emits.

    Number::of_int

    fn Number::of_int(n : Int) -> Number

    PageRule

    pub(all) struct PageRule {
    selectors : Array[String]
    body : Array[BlockItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    PropertyName

    pub(all) enum PropertyName {
    Ident(String)
    Custom(String)
    } derive(Eq,
    Debug
    )

    Custom carries the leading --, so that the two cases never have to be re-joined to be printed and a -- can never be lost.

    PropertyName::text

    fn PropertyName::text(self : PropertyName) -> String

    PropertyRule

    pub(all) struct PropertyRule {
    name : String
    decls : DeclBlock
    span :
    Span

    } derive(Eq,
    Debug
    )

    PseudoClass

    pub(all) enum PseudoClass {
    Simple(String)
    Nth(String, AnB, Array[Selector]?)
    Sub(String, Array[Selector])
    Lang(Array[String])
    Dir(String)
    Unknown(String, Array[ComponentValue])
    } derive(Eq,
    Debug
    )

    Grouped by the shape of the argument, not by the name -- biome's choice, and the one that makes printing expressible. Simple takes nothing, Sub takes a selector list, Nth takes An+B with an optional of clause.

    PseudoElement

    pub(all) enum PseudoElement {
    Simple(String)
    Sub(String, Array[Selector])
    Fn(String, Array[ComponentValue])
    } derive(Eq,
    Debug
    )

    Qualifier

    pub(all) enum Qualifier {
    Class(String)
    Id(String)
    Attr(AttrSelector)
    Pseudo(PseudoClass)
    Element(PseudoElement)
    Nesting
    Bogus(Bogus)
    } derive(Eq,
    Debug
    )

    RangeOp

    pub(all) enum RangeOp {
    Lt
    Le
    Gt
    Ge
    Eq
    } derive(Eq,
    Debug
    )

    RangeOp::text

    fn RangeOp::text(self : RangeOp) -> String

    ScopeRule

    pub(all) struct ScopeRule {
    start : Array[Selector]?
    end : Array[Selector]?
    body : Array[BlockItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    Selector

    pub(all) enum Selector {
    Simple(Compound)
    Complex(Selector, Combinator, Compound)
    Relative(Combinator, Selector)
    Bogus(Bogus)
    } derive(Eq,
    Debug
    )

    A selector.

    Complex is left-nested by construction: its right operand is a Compound, not a Selector, so a > b + c has exactly one shape and associativity needs no normalisation pass. lightningcss stores a flat right-to-left component vector, which is the right thing for a matcher and the wrong thing for a printer; biome's recursion is what this follows.

    StyleRule

    pub(all) struct StyleRule {
    selectors : Array[Selector]
    body : Array[BlockItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    Stylesheet

    pub(all) struct Stylesheet {
    items : Array[TopItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    SupportsRule

    pub(all) struct SupportsRule {
    condition : Condition
    body : Array[BlockItem]
    span :
    Span

    } derive(Eq,
    Debug
    )

    TopItem

    pub(all) enum TopItem {
    Rule(CssRule)
    Comment(Comment)
    Bogus(Bogus)
    } derive(Eq,
    Debug
    )

    TypeSelector

    pub(all) enum TypeSelector {
    Universal(NsPrefix?)
    Named(NsPrefix?, String)
    } derive(Eq,
    Debug
    )

    UnknownAtRule

    pub(all) struct UnknownAtRule {
    name : String
    prelude : Array[ComponentValue]
    block : Array[BlockItem]?
    span :
    Span

    } derive(Eq,
    Debug
    )

    Source Files

    Powered by MoonBit

    Site sourceReport issuePackagesBuild queueSkillsStatistics

    © 2026 mooncakes.io