Skip to main content

oak_less/ast/
mod.rs

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