zenith_core/ast/style.rs
1//! Style block and style definition types.
2
3use std::collections::BTreeMap;
4
5use crate::ast::span::Span;
6use crate::ast::value::PropertyValue;
7
8/// An unknown property child encountered inside a `style` block.
9///
10/// The name was not in the recognized set of visual style keys, so it cannot
11/// be applied as a visual cascade. It is preserved here so that the
12/// validator can emit `style.unknown_property` warnings.
13#[derive(Debug, Clone, PartialEq)]
14pub struct UnknownStyleProp {
15 /// The raw property value (first positional argument of the child node).
16 pub raw: String,
17}
18
19/// A named style definition, holding a map of recognized visual properties.
20#[derive(Debug, Clone, PartialEq)]
21pub struct Style {
22 /// Globally unique style ID.
23 pub id: String,
24 /// Recognized visual properties, keyed by their canonical hyphenated name.
25 ///
26 /// Canonical keys: `fill`, `stroke`, `stroke-width`, `stroke-alignment`,
27 /// `font-family`, `font-size`, `font-weight`, `line-height`, `radius`,
28 /// `padding`, `gap`.
29 pub properties: BTreeMap<String, PropertyValue>,
30 /// Unknown (unrecognized) child node names encountered in the style block.
31 ///
32 /// These are preserved so the validator can emit `style.unknown_property`
33 /// warnings without re-parsing the source.
34 pub unknown_props: BTreeMap<String, UnknownStyleProp>,
35 /// Byte-range of this `style` node in the source (for diagnostics).
36 pub source_span: Option<Span>,
37}
38
39/// The top-level `styles` block containing named style definitions.
40#[derive(Debug, Clone, PartialEq, Default)]
41pub struct StyleBlock {
42 /// Ordered list of style definitions.
43 pub styles: Vec<Style>,
44 /// Byte-range of the `styles` block in the source (for diagnostics).
45 pub source_span: Option<Span>,
46}
47
48/// Canonical hyphenated keys for recognized style visual properties.
49///
50/// Underscore variants are normalized to these forms by
51/// [`canonicalize_style_key`] during parsing and transaction application.
52pub const STYLE_RECOGNIZED_KEYS: &[&str] = &[
53 "fill",
54 "stroke",
55 "stroke-width",
56 "stroke-alignment",
57 "font-family",
58 "font-size",
59 "font-weight",
60 "line-height",
61 "radius",
62 "padding",
63 "gap",
64];
65
66/// Map underscore-spelled style child names to their canonical hyphenated form.
67///
68/// Normalizes underscore variants (`stroke_width` → `stroke-width`, etc.) and
69/// returns the canonical key if it is in [`STYLE_RECOGNIZED_KEYS`], or `None`
70/// if the name is unrecognized after normalization.
71pub fn canonicalize_style_key(name: &str) -> Option<&'static str> {
72 // Normalize underscore to hyphen for comparison.
73 let normalized: &str = match name {
74 "stroke_width" => "stroke-width",
75 "stroke_alignment" => "stroke-alignment",
76 "font_family" => "font-family",
77 "font_size" => "font-size",
78 "font_weight" => "font-weight",
79 "line_height" => "line-height",
80 other => other,
81 };
82 STYLE_RECOGNIZED_KEYS
83 .iter()
84 .copied()
85 .find(|&k| k == normalized)
86}