Skip to main content

oak_css/ast/
mod.rs

1#![doc = include_str!("readme.md")]
2use core::range::Range;
3use oak_core::tree::{GreenNode, RedNode, TypedNode};
4
5/// CSS selector variant.
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[derive(Clone, Debug, PartialEq, Eq, Hash)]
8pub enum Selector {
9    /// Element selector (e.g., `div`).
10    Element(String),
11    /// Class selector (e.g., `.class`).
12    Class(String),
13    /// ID selector (e.g., `#id`).
14    Id(String),
15    /// Attribute selector (e.g., `[attr]`).
16    Attribute {
17        /// The attribute name.
18        name: String,
19        /// Optional attribute value.
20        value: Option<String>,
21        /// Optional attribute operator.
22        operator: Option<String>,
23    },
24    /// Pseudo-class selector (e.g., `:hover`).
25    PseudoClass(String),
26    /// Pseudo-element selector (e.g., `::before`).
27    PseudoElement(String),
28    /// Descendant selector (e.g., `div p`).
29    Descendant(Box<Selector>, Box<Selector>),
30    /// Child selector (e.g., `div > p`).
31    Child(Box<Selector>, Box<Selector>),
32    /// Adjacent sibling selector (e.g., `div + p`).
33    AdjacentSibling(Box<Selector>, Box<Selector>),
34    /// General sibling selector (e.g., `div ~ p`).
35    GeneralSibling(Box<Selector>, Box<Selector>),
36}
37
38/// CSS value variant.
39#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
40#[derive(Clone, Debug, PartialEq)]
41pub enum Value {
42    /// Keyword value (e.g., `none`, `auto`).
43    Keyword(String),
44    /// Numeric value with unit (e.g., `10px`, `50%`).
45    Numeric {
46        /// The numeric value.
47        value: f64,
48        /// Optional unit.
49        unit: Option<String>,
50    },
51    /// Color value (e.g., `#fff`, `rgb(255, 255, 255)`).
52    Color(String),
53    /// String value (e.g., `"text"`).
54    String(String),
55    /// URL value (e.g., `url("image.png")`).
56    Url(String),
57    /// Function value (e.g., `calc(100% - 20px)`).
58    Function {
59        /// The function name.
60        name: String,
61        /// The function arguments.
62        arguments: Vec<Value>,
63    },
64    /// List of values (e.g., `1px 2px 3px`).
65    List(Vec<Value>),
66    /// Nested value (for complex expressions).
67    Nested(Box<Value>),
68}
69
70/// CSS declaration consisting of a property name, value, and source span.
71#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
72#[derive(Clone, Debug, PartialEq)]
73pub struct Declaration {
74    /// The property name (e.g., `color`).
75    pub property: String,
76    /// The property value.
77    pub value: Value,
78    /// The range in the source code where this declaration is defined.
79    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
80    pub span: Range<usize>,
81}
82
83/// CSS rule set consisting of selectors and declarations.
84#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
85#[derive(Clone, Debug, PartialEq)]
86pub struct RuleSet {
87    /// The selectors for this rule set.
88    pub selectors: Vec<Selector>,
89    /// The declarations for this rule set.
90    pub declarations: Vec<Declaration>,
91    /// The range in the source code where this rule set is defined.
92    #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
93    pub span: Range<usize>,
94}
95
96/// CSS at-rule variant.
97#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
98#[derive(Clone, Debug, PartialEq)]
99pub enum AtRule {
100    /// Media query rule (e.g., `@media screen and (max-width: 600px)`).
101    Media {
102        /// The media query condition.
103        condition: String,
104        /// The rule sets inside the media query.
105        rules: Vec<RuleSet>,
106        /// The range in the source code where this media rule is defined.
107        #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
108        span: Range<usize>,
109    },
110    /// Import rule (e.g., `@import "style.css"`).
111    Import {
112        /// The import path.
113        path: String,
114        /// Optional media query.
115        media: Option<String>,
116        /// The range in the source code where this import rule is defined.
117        #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
118        span: Range<usize>,
119    },
120    /// Font face rule (e.g., `@font-face`).
121    FontFace {
122        /// The font face declarations.
123        declarations: Vec<Declaration>,
124        /// The range in the source code where this font face rule is defined.
125        #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
126        span: Range<usize>,
127    },
128    /// Keyframes rule (e.g., `@keyframes animation`).
129    Keyframes {
130        /// The animation name.
131        name: String,
132        /// The keyframe rules.
133        keyframes: Vec<(String, Vec<Declaration>)>,
134        /// The range in the source code where this keyframes rule is defined.
135        #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
136        span: Range<usize>,
137    },
138    /// Other at-rules.
139    Other {
140        /// The at-rule name.
141        name: String,
142        /// The at-rule content.
143        content: String,
144        /// The range in the source code where this at-rule is defined.
145        #[cfg_attr(feature = "serde", serde(with = "oak_core::serde_range"))]
146        span: Range<usize>,
147    },
148}
149
150/// CSS AST node variant.
151#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
152#[derive(Clone, Debug, PartialEq)]
153pub enum CssNode {
154    /// A rule set.
155    RuleSet(RuleSet),
156    /// An at-rule.
157    AtRule(AtRule),
158    /// A comment.
159    Comment(String),
160}
161
162/// Root node of the CSS AST.
163#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
164#[derive(Clone, Debug, PartialEq)]
165pub struct CssRoot {
166    /// The top-level nodes in the CSS document.
167    pub nodes: Vec<CssNode>,
168}
169
170impl<'a> TypedNode<'a> for CssRoot {
171    type Language = crate::CssLanguage;
172
173    fn cast(_node: RedNode<'a, Self::Language>) -> Option<Self> {
174        // 这里需要根据实际情况实现从 RedNode 到 CssRoot 的转换
175        // 暂时返回一个空的 CssRoot
176        Some(Self { nodes: Vec::new() })
177    }
178
179    fn green(&self) -> &'a GreenNode<'a, Self::Language> {
180        // 这里需要返回底层的 GreenNode
181        // 暂时返回一个空的 GreenNode 引用
182        // 注意:这是一个临时实现,需要根据实际情况修复
183        panic!("CssRoot::green() not implemented")
184    }
185}