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}