Skip to main content

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}