cssdiff

package
v0.3.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 17, 2026 License: MIT Imports: 5 Imported by: 0

Documentation

Overview

Package cssdiff implements the normalized, order-preserving CSS-AST model used to make real changes in theme-CSS output mechanically detectable.

tdewolff/parse/v2/css exposes a grammar-TOKEN stream, not a navigable AST — there is no off-the-shelf Go CSS-AST diff library and no p.AST() call to consume — so this package materializes its own thin Stylesheet/Rule/ Declaration model on top of that stream (see build.go's Parse function) rather than depending on one.

Declaration and rule ORDER is cascade-significant in CSS and is therefore preserved exactly as authored; only within-node values are normalized (hex color casing, whitespace, comments, quote style). This is a deliberate departure from general-purpose, order-independent stylesheet- equivalence tooling: for verifying the same theme-CSS engine's output across a change, a reordered declaration is a real, detectable change.

This package is the CONF-03 spike: it proves the model + grammar-stream builder make declaration-value changes and reorders detectable at the model level (see spike_test.go). The full comparator and theme negative tests are built on top of this model in a later objective.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Equal

func Equal(expected, actual string) (equal bool, diff string)

Equal reports whether two CSS strings are semantically equal under the rules documented on the package, returning a human-readable unified-style diff of the first differences when they are not. A parse error on either side yields (false, "<side>: parse error: ...").

Types

type Declaration

type Declaration struct {
	Property  string
	Value     string
	Important bool
}

Declaration is a single normalized CSS property/value pair within a Rule.

Important reports whether the declaration carried a trailing "!important" in the source; when true, Value has already had the "!important" marker stripped.

type Rule

type Rule struct {
	Selector     string
	Declarations []Declaration
	AtRule       string
}

Rule is a single CSS ruleset: a selector plus its ordered Declarations.

AtRule carries the raw, minimally-processed text of the at-rule this Rule was found under (e.g. "@media(max-width:400px)"), or is empty for a plain ruleset. At-rule semantics (nested-rule modeling, @media/@keyframes- specific behavior) are deliberately out of scope for this spike; AtRule exists only so the shape is forward-compatible without implementing that semantics now (see 00-RESEARCH.md Open Question 2). When Rule itself represents a standalone at-rule statement (e.g. "@import url(x.css);"), Selector and Declarations are both zero-valued.

type Stylesheet

type Stylesheet struct {
	Rules []Rule
}

Stylesheet is the normalized, order-preserving model of a parsed CSS stylesheet: an ordered list of Rules exactly as they appear in the source, with within-node normalization applied (see Parse in build.go). Rule order is never sorted or otherwise reshuffled.

func Parse

func Parse(cssText string) (Stylesheet, error)

Parse builds a normalized Stylesheet from raw CSS by walking the tdewolff/parse/v2/css grammar-token stream.

tdewolff/parse/v2/css exposes a grammar-TOKEN stream, not a navigable AST — there is no p.AST() to consume — so this function materializes the model itself via the documented p.Next()/p.Values() walk over css.GrammarType constants (see `go doc github.com/tdewolff/parse/v2/css` for the pinned v2.8.13 API this was written against).

Rule and declaration order is preserved exactly as authored: CSS cascade order is significant, so nothing here sorts or set-compares rules or declarations. Only within-node normalization is applied while values are captured: hex colors are lowercased, redundant whitespace collapses (tdewolff's own lexer already collapses whitespace RUNS to a single token; this function does not re-introduce or discard the separators that survive that pass), comments are stripped (dropped at the top level; already excluded from selector/declaration token streams by the underlying lexer), and quote style is canonicalized to double quotes.

At-rule contents (@media, @keyframes, @import, etc.) are captured only as a raw, opaque prelude string on Rule.AtRule — deliberately minimal per this spike's scope (00-RESEARCH.md Open Question 2); nested rules inside an at-rule block are not modeled individually.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL