Cascade.PpSourceCSS Pretty Printer
A minification-aware printer for CSS that uses direct buffer writing for performance. This module provides formatting combinators that can produce both minified and formatted CSS output.
The core abstraction is the formatter type 'a t = ctx -> 'a -> unit which writes values of type 'a directly to a buffer based on the context.
Design principles:
Set of strings, used for theme variable names.
type ctx = {minify : bool;Whether to produce minified output
*)level : int;Current nesting depth
*)indent : int option;Indent width per nesting level. None disables per-level indentation even when not minifying.
out : out;Output sink
*)inline : bool;Whether to inline variables or not
*)in_function : bool;Whether inside a CSS function (var fallback, color-mix). Affects keyword casing: currentColor becomes currentcolor.
in_calc : bool;Inside a calc(): suppress canonicalisations that cross a typed leaf boundary (calc is type-aware so <percentage> and <number> are not interchangeable).
in_feature_query : bool;Set while serialising the value of an @supports (property: value) feature test. The value is a capability predicate for that exact syntax, so lossy rewrites (e.g. static colour folding) are suppressed there.
lossless : bool;Set under --minify --lossless: suppress colour-channel rounding and other colour approximations while keeping exact serialisation shortenings.
enforce_spec : bool;Set under --minify --enforce-spec: emit the shortest spec-canonical serialisation without evergreen-target facts, so target-dependent shortenings (e.g. the oklch/lch chroma number -> percentage swap) are suppressed.
}Formatter context containing output configuration
val ctx :
?minify:bool ->
?indent:int ->
?inline:bool ->
?lossless:bool ->
?enforce_spec:bool ->
Buffer.t ->
ctxctx buf builds a formatter context writing to buf, for the serialise-to-string / measuring helpers.
val size :
?minify:bool ->
?indent:int ->
?inline:bool ->
?lossless:bool ->
?enforce_spec:bool ->
'a t ->
'a ->
intsize formatter value is the byte length of to_string formatter value without allocating the result string. Use it for size-based decisions instead of measuring String.length (to_string ...).
val to_string :
?minify:bool ->
?indent:int ->
?inline:bool ->
?lossless:bool ->
?enforce_spec:bool ->
'a t ->
'a ->
stringto_string formatter value runs the formatter and returns a string. The optional indent sets the per-level indent width (default: None under minify, Some 2 otherwise). enforce_spec suppresses target-dependent shortenings.
last_char ctx is the most recently emitted byte, or None if nothing has been written yet. Use it for token-boundary spacing decisions instead of reaching into the output sink directly.
quoted_string ?quote writes a quote-delimited string (default '"') with proper escaping of the delimiter quote and backslashes.
These formatters control whitespace and indentation for readable output. They respect the minification setting - producing no output when minifying.
token_sp writes a token-boundary space: a regular space in pretty mode, and a space under minify only when the previous output character would otherwise re-tokenise with the next one. Drops the space after ) or % since both cleanly close their token (CSS Syntax 3 sec. 4).
nest n formatter runs formatter with indentation increased by n levels.
Functions for combining and transforming formatters
f ++ g sequences two formatters: runs f then g on the same input.
pair ~sep f g formats a pair using f for first, g for second, with optional separator between them.
triple ~sep f g h formats a triple using f, g, h for the three components, with optional separator between them.
list ~sep formatter formats a list with separator between elements.
column ctx returns the current column position (chars since last newline).
list_wrap ?threshold ~sep ~wrap_indent formatter formats a list like list but wraps to a new line (indented by wrap_indent spaces) when the current column exceeds threshold (default 80). No-op when minifying.
option ~none formatter formats an option, using none formatter for None.
CSS number formatters that handle minification rules like dropping leading zeros and avoiding scientific notation
string_of_float ?drop_leading_zero ?max_decimals f converts a float to a string.
drop_leading_zero: if true, omits leading zero for 0 < |n| < 1 (.5 instead of 0.5)max_decimals: maximum decimal precision (default 8)float formats floating point numbers with CSS rules:
float_compact like float but always drops leading zeros regardless of minification mode. Used for oklch chroma values where Tailwind always uses compact format (e.g. .034 not 0.034).
float_n n formats float to exactly n decimal places using round-half-up. Used for CSS color channels and opacity where precision matters.
round_sig n f rounds f to n significant digits.
unit ctx f suffix formats a number with a unit suffix, e.g. "3.5px" or "0" for zero.
pct ctx f formats a percentage value with the % suffix. The value is expected to be in the range 0-100. The unit is always emitted: CSS Values 4 sec. 6.5 only allows the unit to drop on a zero <length>, not a zero <percentage>.
in_feature_query ctx is true while serialising an @supports feature-test value, where lossy rewrites must be suppressed.
enter_feature_query ctx marks ctx as inside an @supports feature-test value.
cond predicate then_fmt else_fmt conditionally chooses formatter based on context predicate.
space_if_pretty is an alias for sp - outputs space when not minifying.
op_char outputs a character with spaces around it when not minifying. Useful for operators like +, -, *, / in expressions.
braces formatter wraps formatter in braces with proper spacing and indentation: { <indented content> } when formatting, {<content>} when minifying.
braced_list formatter wraps a list in braces with one item per line at one indent level deeper and the closing brace back at the parent's indentation.
braced_semicolon_list formatter is braced_list with items separated by semicolon_cut and, in pretty output, a trailing semicolon after the last item, matching style rule bodies.
call_list name item formats a function call with a comma-separated list of items: name(a, b, c).
call_2 name a b formats a 2-arg function call: name(a, b).
call_3 name a b c formats a 3-arg function call: name(a, b, c).