swc_css_ast/
value.rs

1use std::hash::{Hash, Hasher};
2
3use is_macro::Is;
4use string_enum::StringEnum;
5use swc_atoms::Atom;
6use swc_common::{ast_node, util::take::Take, EqIgnoreSpan, Span};
7
8use crate::Function;
9
10#[ast_node("Ident")]
11#[derive(Eq, PartialOrd, Ord, Hash)]
12pub struct Ident {
13    pub span: Span,
14
15    pub value: Atom,
16    #[cfg_attr(
17        feature = "encoding-impl",
18        encoding(with = "cbor4ii::core::types::Maybe")
19    )]
20    pub raw: Option<Atom>,
21}
22
23impl EqIgnoreSpan for Ident {
24    #[inline]
25    fn eq_ignore_span(&self, other: &Self) -> bool {
26        self.value == other.value
27    }
28}
29
30impl PartialEq<str> for Ident {
31    #[inline]
32    fn eq(&self, other: &str) -> bool {
33        &*self.value == other
34    }
35}
36
37impl Take for Ident {
38    #[inline]
39    fn dummy() -> Self {
40        Self {
41            span: Default::default(),
42            value: Default::default(),
43            raw: Default::default(),
44        }
45    }
46}
47
48#[ast_node("CustomIdent")]
49#[derive(Eq, Hash)]
50pub struct CustomIdent {
51    pub span: Span,
52
53    pub value: Atom,
54    #[cfg_attr(
55        feature = "encoding-impl",
56        encoding(with = "cbor4ii::core::types::Maybe")
57    )]
58    pub raw: Option<Atom>,
59}
60
61impl EqIgnoreSpan for CustomIdent {
62    #[inline]
63    fn eq_ignore_span(&self, other: &Self) -> bool {
64        self.value == other.value
65    }
66}
67
68#[ast_node("DashedIdent")]
69#[derive(Eq, Hash)]
70pub struct DashedIdent {
71    pub span: Span,
72
73    pub value: Atom,
74    #[cfg_attr(
75        feature = "encoding-impl",
76        encoding(with = "cbor4ii::core::types::Maybe")
77    )]
78    pub raw: Option<Atom>,
79}
80
81impl EqIgnoreSpan for DashedIdent {
82    #[inline]
83    fn eq_ignore_span(&self, other: &Self) -> bool {
84        self.value == other.value
85    }
86}
87
88impl PartialEq<str> for DashedIdent {
89    #[inline]
90    fn eq(&self, other: &str) -> bool {
91        &*self.value == other
92    }
93}
94
95#[ast_node("CustomPropertyName")]
96#[derive(Eq, Hash)]
97pub struct CustomPropertyName {
98    pub span: Span,
99
100    pub value: Atom,
101    #[cfg_attr(
102        feature = "encoding-impl",
103        encoding(with = "cbor4ii::core::types::Maybe")
104    )]
105    pub raw: Option<Atom>,
106}
107
108impl EqIgnoreSpan for CustomPropertyName {
109    fn eq_ignore_span(&self, other: &Self) -> bool {
110        self.value == other.value
111    }
112}
113
114/// Quoted string.
115#[ast_node("String")]
116#[derive(Eq, Hash)]
117pub struct Str {
118    pub span: Span,
119
120    pub value: Atom,
121    #[cfg_attr(
122        feature = "encoding-impl",
123        encoding(with = "cbor4ii::core::types::Maybe")
124    )]
125    pub raw: Option<Atom>,
126}
127
128impl EqIgnoreSpan for Str {
129    fn eq_ignore_span(&self, other: &Self) -> bool {
130        self.value == other.value
131    }
132}
133
134#[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)]
135#[cfg_attr(
136    feature = "rkyv",
137    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
138)]
139#[cfg_attr(
140    feature = "rkyv",
141    rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
142        __S::Error: rkyv::rancor::Source))
143)]
144#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))]
145#[cfg_attr(feature = "rkyv", repr(u32))]
146#[cfg_attr(
147    feature = "encoding-impl",
148    derive(::swc_common::Encode, ::swc_common::Decode)
149)]
150pub enum DelimiterValue {
151    /// `,`
152    Comma,
153    /// `/`
154    Solidus,
155    /// `;`
156    Semicolon,
157}
158
159#[ast_node("Delimiter")]
160#[derive(Eq, Hash, EqIgnoreSpan)]
161pub struct Delimiter {
162    pub span: Span,
163    pub value: DelimiterValue,
164}
165
166// TODO small AST improve for `CurrentColorOrSystemColor` and
167// `NamedColorOrTransparent`
168#[ast_node(no_unknown)]
169#[derive(Eq, Hash, Is, EqIgnoreSpan)]
170pub enum Color {
171    #[tag("AbsoluteColorBase")]
172    AbsoluteColorBase(AbsoluteColorBase),
173    #[tag("Ident")]
174    CurrentColorOrSystemColor(Ident),
175    // <device-cmyk()> only
176    #[tag("Function")]
177    Function(Function),
178}
179
180#[ast_node(no_unknown)]
181#[derive(Eq, Hash, Is, EqIgnoreSpan)]
182pub enum AbsoluteColorBase {
183    #[tag("HexColor")]
184    HexColor(HexColor),
185    #[tag("Ident")]
186    NamedColorOrTransparent(Ident),
187    #[tag("Function")]
188    Function(Function),
189}
190
191#[ast_node("HexColor")]
192#[derive(Eq, Hash, EqIgnoreSpan)]
193pub struct HexColor {
194    /// Includes `#`
195    pub span: Span,
196    /// Does **not** include `#`
197    pub value: Atom,
198    /// Does **not** include `#`
199    #[cfg_attr(
200        feature = "encoding-impl",
201        encoding(with = "cbor4ii::core::types::Maybe")
202    )]
203    pub raw: Option<Atom>,
204}
205
206#[ast_node(no_unknown)]
207#[derive(Eq, Hash, Is, EqIgnoreSpan)]
208pub enum AlphaValue {
209    #[tag("Number")]
210    Number(Number),
211    #[tag("Percentage")]
212    Percentage(Percentage),
213}
214
215#[ast_node(no_unknown)]
216#[derive(Eq, Hash, Is, EqIgnoreSpan)]
217pub enum Hue {
218    #[tag("Number")]
219    Number(Number),
220    #[tag("Angle")]
221    Angle(Angle),
222}
223
224#[ast_node(no_unknown)]
225#[derive(Eq, Hash, Is, EqIgnoreSpan)]
226pub enum CmykComponent {
227    #[tag("Number")]
228    Number(Number),
229    #[tag("Percentage")]
230    Percentage(Percentage),
231    #[tag("Function")]
232    Function(Function),
233}
234
235#[ast_node(no_unknown)]
236#[derive(Eq, Hash, Is, EqIgnoreSpan)]
237pub enum Dimension {
238    #[tag("Length")]
239    Length(Length),
240
241    #[tag("Angle")]
242    Angle(Angle),
243
244    #[tag("Time")]
245    Time(Time),
246
247    #[tag("Frequency")]
248    Frequency(Frequency),
249
250    #[tag("Resolution")]
251    Resolution(Resolution),
252
253    #[tag("Flex")]
254    Flex(Flex),
255
256    #[tag("UnknownDimension")]
257    UnknownDimension(UnknownDimension),
258}
259
260#[ast_node("Length")]
261#[derive(Eq, Hash, EqIgnoreSpan)]
262pub struct Length {
263    pub span: Span,
264    pub value: Number,
265    pub unit: Ident,
266}
267
268#[ast_node("Angle")]
269#[derive(Eq, Hash, EqIgnoreSpan)]
270pub struct Angle {
271    pub span: Span,
272    pub value: Number,
273    pub unit: Ident,
274}
275
276#[ast_node("Time")]
277#[derive(Eq, Hash, EqIgnoreSpan)]
278pub struct Time {
279    pub span: Span,
280    pub value: Number,
281    pub unit: Ident,
282}
283
284#[ast_node("Frequency")]
285#[derive(Eq, Hash, EqIgnoreSpan)]
286pub struct Frequency {
287    pub span: Span,
288    pub value: Number,
289    pub unit: Ident,
290}
291
292#[ast_node("Resolution")]
293#[derive(Eq, Hash, EqIgnoreSpan)]
294pub struct Resolution {
295    pub span: Span,
296    pub value: Number,
297    pub unit: Ident,
298}
299
300#[ast_node("Flex")]
301#[derive(Eq, Hash, EqIgnoreSpan)]
302pub struct Flex {
303    pub span: Span,
304    pub value: Number,
305    pub unit: Ident,
306}
307
308#[ast_node("UnknownDimension")]
309#[derive(Eq, Hash, EqIgnoreSpan)]
310pub struct UnknownDimension {
311    pub span: Span,
312    pub value: Number,
313    pub unit: Ident,
314}
315
316#[ast_node("Percentage")]
317#[derive(Eq, Hash, EqIgnoreSpan)]
318pub struct Percentage {
319    pub span: Span,
320    pub value: Number,
321}
322
323#[ast_node(no_unknown)]
324#[derive(Eq, Hash, Is, EqIgnoreSpan)]
325pub enum LengthPercentage {
326    #[tag("Length")]
327    Length(Length),
328    #[tag("Percentage")]
329    Percentage(Percentage),
330}
331
332#[ast_node(no_unknown)]
333#[derive(Eq, Hash, Is, EqIgnoreSpan)]
334pub enum FrequencyPercentage {
335    #[tag("Frequency")]
336    Frequency(Frequency),
337    #[tag("Percentage")]
338    Percentage(Percentage),
339}
340
341#[ast_node(no_unknown)]
342#[derive(Eq, Hash, Is, EqIgnoreSpan)]
343pub enum AnglePercentage {
344    #[tag("Angle")]
345    Angle(Angle),
346    #[tag("Percentage")]
347    Percentage(Percentage),
348}
349
350#[ast_node(no_unknown)]
351#[derive(Eq, Hash, Is, EqIgnoreSpan)]
352pub enum TimePercentage {
353    #[tag("Time")]
354    Time(Time),
355    #[tag("Percentage")]
356    Percentage(Percentage),
357}
358
359#[ast_node("Integer")]
360#[derive(Eq, Hash)]
361pub struct Integer {
362    pub span: Span,
363    pub value: i64,
364    #[cfg_attr(
365        feature = "encoding-impl",
366        encoding(with = "cbor4ii::core::types::Maybe")
367    )]
368    pub raw: Option<Atom>,
369}
370
371impl EqIgnoreSpan for Integer {
372    fn eq_ignore_span(&self, other: &Self) -> bool {
373        self.value == other.value
374    }
375}
376
377#[ast_node("Number")]
378pub struct Number {
379    pub span: Span,
380    pub value: f64,
381    #[cfg_attr(
382        feature = "encoding-impl",
383        encoding(with = "cbor4ii::core::types::Maybe")
384    )]
385    pub raw: Option<Atom>,
386}
387
388impl Eq for Number {}
389
390#[allow(clippy::derived_hash_with_manual_eq)]
391#[allow(clippy::transmute_float_to_int)]
392impl Hash for Number {
393    fn hash<H: Hasher>(&self, state: &mut H) {
394        fn integer_decode(val: f64) -> (u64, i16, i8) {
395            let bits: u64 = f64::to_bits(val);
396            let sign: i8 = if bits >> 63 == 0 { 1 } else { -1 };
397            let mut exponent: i16 = ((bits >> 52) & 0x7ff) as i16;
398            let mantissa = if exponent == 0 {
399                (bits & 0xfffffffffffff) << 1
400            } else {
401                (bits & 0xfffffffffffff) | 0x10000000000000
402            };
403
404            exponent -= 1023 + 52;
405            (mantissa, exponent, sign)
406        }
407
408        self.span.hash(state);
409        integer_decode(self.value).hash(state);
410    }
411}
412
413impl EqIgnoreSpan for Number {
414    fn eq_ignore_span(&self, other: &Self) -> bool {
415        self.value == other.value
416    }
417}
418
419#[ast_node("Ratio")]
420#[derive(Eq, Hash, EqIgnoreSpan)]
421pub struct Ratio {
422    pub span: Span,
423    pub left: Number,
424    #[cfg_attr(
425        feature = "encoding-impl",
426        encoding(with = "cbor4ii::core::types::Maybe")
427    )]
428    pub right: Option<Number>,
429}
430
431#[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)]
432#[cfg_attr(
433    feature = "rkyv",
434    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
435)]
436#[cfg_attr(
437    feature = "rkyv",
438    rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
439        __S::Error: rkyv::rancor::Source))
440)]
441#[cfg_attr(feature = "rkyv", derive(bytecheck::CheckBytes))]
442#[cfg_attr(feature = "rkyv", repr(u32))]
443#[cfg_attr(
444    feature = "encoding-impl",
445    derive(::swc_common::Encode, ::swc_common::Decode)
446)]
447pub enum BinOp {
448    /// `+`
449    Add,
450    /// `-`
451    Sub,
452    /// `*`
453    Mul,
454    /// `/`
455    Div,
456}
457
458#[ast_node("Url")]
459#[derive(Eq, Hash, EqIgnoreSpan)]
460pub struct Url {
461    pub span: Span,
462    pub name: Ident,
463    #[cfg_attr(
464        feature = "encoding-impl",
465        encoding(with = "cbor4ii::core::types::Maybe")
466    )]
467    pub value: Option<Box<UrlValue>>,
468    #[cfg_attr(
469        feature = "encoding-impl",
470        encoding(with = "cbor4ii::core::types::Maybe")
471    )]
472    pub modifiers: Option<Vec<UrlModifier>>,
473}
474
475#[ast_node(no_unknown)]
476#[derive(Eq, Hash, Is, EqIgnoreSpan)]
477pub enum UrlValue {
478    #[tag("Str")]
479    Str(Str),
480    #[tag("UrlValueRaw")]
481    Raw(UrlValueRaw),
482}
483
484#[ast_node("UrlValueRaw")]
485#[derive(Eq, Hash, EqIgnoreSpan)]
486pub struct UrlValueRaw {
487    pub span: Span,
488
489    pub value: Atom,
490    #[cfg_attr(
491        feature = "encoding-impl",
492        encoding(with = "cbor4ii::core::types::Maybe")
493    )]
494    pub raw: Option<Atom>,
495}
496
497#[ast_node(no_unknown)]
498#[derive(Eq, Hash, Is, EqIgnoreSpan)]
499pub enum UrlModifier {
500    #[tag("Ident")]
501    Ident(Ident),
502    #[tag("Function")]
503    Function(Function),
504}
505
506#[ast_node("UnicodeRange")]
507#[derive(Eq, Hash)]
508pub struct UnicodeRange {
509    pub span: Span,
510
511    pub start: Atom,
512
513    #[cfg_attr(
514        feature = "encoding-impl",
515        encoding(with = "cbor4ii::core::types::Maybe")
516    )]
517    pub end: Option<Atom>,
518    #[cfg_attr(
519        feature = "encoding-impl",
520        encoding(with = "cbor4ii::core::types::Maybe")
521    )]
522    pub raw: Option<Atom>,
523}
524
525impl EqIgnoreSpan for UnicodeRange {
526    #[inline]
527    fn eq_ignore_span(&self, other: &Self) -> bool {
528        self.start == other.start && self.end == other.end
529    }
530}
531
532#[ast_node("CalcSum")]
533#[derive(Eq, Hash, EqIgnoreSpan)]
534pub struct CalcSum {
535    pub span: Span,
536    pub expressions: Vec<CalcProductOrOperator>,
537}
538
539#[ast_node(no_unknown)]
540#[derive(Eq, Hash, Is, EqIgnoreSpan)]
541pub enum CalcProductOrOperator {
542    #[tag("CalcProduct")]
543    Product(CalcProduct),
544    #[tag("CalcOperator")]
545    Operator(CalcOperator),
546}
547
548#[ast_node("CalcProduct")]
549#[derive(Eq, Hash, EqIgnoreSpan)]
550pub struct CalcProduct {
551    pub span: Span,
552    pub expressions: Vec<CalcValueOrOperator>,
553}
554
555#[ast_node("CalcOperator")]
556#[derive(Eq, Hash, EqIgnoreSpan)]
557pub struct CalcOperator {
558    pub span: Span,
559    pub value: CalcOperatorType,
560}
561
562#[derive(StringEnum, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash, Is, EqIgnoreSpan)]
563#[cfg_attr(
564    feature = "rkyv",
565    derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
566)]
567#[cfg_attr(
568    feature = "rkyv",
569    rkyv(serialize_bounds(__S: rkyv::ser::Writer + rkyv::ser::Allocator,
570        __S::Error: rkyv::rancor::Source))
571)]
572#[cfg_attr(feature = "rkyv-impl", derive(bytecheck::CheckBytes))]
573#[cfg_attr(feature = "rkyv-impl", repr(u32))]
574#[cfg_attr(
575    feature = "encoding-impl",
576    derive(::swc_common::Encode, ::swc_common::Decode)
577)]
578pub enum CalcOperatorType {
579    /// `+`
580    Add,
581    /// `-`
582    Sub,
583    /// `*`
584    Mul,
585    /// `/`
586    Div,
587}
588
589#[ast_node(no_unknown)]
590#[derive(Eq, Hash, Is, EqIgnoreSpan)]
591pub enum CalcValueOrOperator {
592    #[tag("CalcValue")]
593    Value(CalcValue),
594    #[tag("CalcOperator")]
595    Operator(CalcOperator),
596}
597
598#[ast_node(no_unknown)]
599#[derive(Eq, Hash, Is, EqIgnoreSpan)]
600pub enum CalcValue {
601    #[tag("Number")]
602    Number(Number),
603    #[tag("Dimension")]
604    Dimension(Dimension),
605    #[tag("Percentage")]
606    Percentage(Percentage),
607    #[tag("Ident")]
608    Constant(Ident),
609    #[tag("CalcSum")]
610    Sum(CalcSum),
611    #[tag("Function")]
612    Function(Function),
613}
614
615#[ast_node(no_unknown)]
616#[derive(Eq, Hash, Is, EqIgnoreSpan)]
617pub enum FamilyName {
618    #[tag("Str")]
619    Str(Str),
620    #[tag("SequenceOfCustomIdents")]
621    SequenceOfCustomIdents(SequenceOfCustomIdents),
622}
623
624#[ast_node("SequenceOfCustomIdents")]
625#[derive(Eq, Hash, EqIgnoreSpan)]
626pub struct SequenceOfCustomIdents {
627    pub span: Span,
628    pub value: Vec<CustomIdent>,
629}