Skip to main content

stylex_transform/shared/enums/data_structures/
evaluate_result_value.rs

1use std::{fmt, rc::Rc};
2
3use indexmap::IndexMap;
4use rustc_hash::FxHashMap;
5use serde::{Serialize, ser::Serializer};
6use stylex_macros::stylex_unimplemented;
7use swc_core::{
8  atoms::Atom,
9  ecma::{
10    ast::{Expr, KeyValueProp, Lit},
11    codegen::Config,
12  },
13};
14
15use crate::shared::structures::functions::FunctionConfig;
16use crate::shared::structures::theme_ref::ThemeRef;
17use crate::shared::structures::types::EvaluationCallback;
18use crate::shared::utils::log::build_code_frame_error::{CodeFrame, create_module, print_module};
19use stylex_structures::stylex_env::EnvEntry;
20
21pub enum EvaluateResultValue {
22  Expr(Expr),
23  Vec(Vec<Option<EvaluateResultValue>>),
24  Map(IndexMap<Expr, Vec<KeyValueProp>>),
25  Entries(IndexMap<Lit, Box<Expr>>),
26  Callback(EvaluationCallback),
27  FunctionConfig(FunctionConfig),
28  FunctionConfigMap(FxHashMap<Atom, FunctionConfig>),
29  ThemeRef(ThemeRef),
30  /// An env object from the `env` config option.
31  EnvObject(IndexMap<String, EnvEntry>),
32}
33
34impl Serialize for EvaluateResultValue {
35  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36  where
37    S: Serializer,
38  {
39    match self {
40      Self::Expr(expr) => {
41        let module = create_module(expr);
42        let code_frame = CodeFrame::new();
43
44        let printed_module = print_module(
45          &code_frame,
46          module,
47          Some(
48            Config::default()
49              .with_minify(true)
50              .with_omit_last_semi(true)
51              .with_reduce_escaped_newline(true),
52          ),
53        );
54
55        serializer.serialize_str(&printed_module)
56      },
57      Self::Map(_) => stylex_unimplemented!("Serialization of Map values is not yet supported."),
58      Self::Entries(_) => {
59        stylex_unimplemented!("Serialization of Entries values is not yet supported.")
60      },
61      Self::Callback(_) => {
62        stylex_unimplemented!("Serialization of Callback values is not yet supported.")
63      },
64      Self::FunctionConfig(_) => {
65        stylex_unimplemented!("Serialization of FunctionConfig values is not yet supported.")
66      },
67      Self::FunctionConfigMap(_) => {
68        stylex_unimplemented!("Serialization of FunctionConfigMap values is not yet supported.")
69      },
70      Self::ThemeRef(_) => {
71        stylex_unimplemented!("Serialization of ThemeRef values is not yet supported.")
72      },
73      Self::Vec(_) => {
74        stylex_unimplemented!("Serialization of Vec values is not yet supported.")
75      },
76      Self::EnvObject(_) => {
77        stylex_unimplemented!("Serialization of EnvObject values is not yet supported.")
78      },
79    }
80  }
81}
82
83impl Clone for EvaluateResultValue {
84  fn clone(&self) -> Self {
85    match self {
86      Self::Expr(e) => Self::Expr(e.clone()),
87      Self::Vec(v) => Self::Vec(v.clone()),
88      Self::Map(m) => Self::Map(m.clone()),
89      Self::Entries(e) => Self::Entries(e.clone()),
90      Self::FunctionConfig(f) => Self::FunctionConfig(f.clone()),
91      Self::FunctionConfigMap(f) => Self::FunctionConfigMap(f.clone()),
92      Self::Callback(c) => Self::Callback(Rc::clone(c)),
93      Self::ThemeRef(tr) => Self::ThemeRef(tr.clone()),
94      Self::EnvObject(e) => Self::EnvObject(e.clone()),
95    }
96  }
97}
98
99impl fmt::Debug for EvaluateResultValue {
100  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101    match self {
102      Self::Expr(e) => f.debug_tuple("Expr").field(e).finish(),
103      Self::Vec(v) => f.debug_tuple("Vec").field(v).finish(),
104      Self::Map(m) => f.debug_tuple("Map").field(m).finish(),
105      Self::Entries(e) => f.debug_tuple("Entries").field(e).finish(),
106      Self::FunctionConfig(e) => f.debug_tuple("FunctionConfig").field(e).finish(),
107      Self::FunctionConfigMap(e) => f.debug_tuple("FunctionConfigMap").field(e).finish(),
108      Self::ThemeRef(e) => f.debug_tuple("ThemeRef").field(e).finish(),
109      Self::Callback(_) => f.debug_tuple("Callback").field(&"Callback").finish(),
110      Self::EnvObject(e) => f.debug_tuple("EnvObject").field(e).finish(),
111    }
112  }
113}
114
115impl PartialEq for EvaluateResultValue {
116  fn eq(&self, other: &Self) -> bool {
117    match (self, other) {
118      (Self::Expr(e1), Self::Expr(e2)) => e1 == e2,
119      (Self::Vec(v1), Self::Vec(v2)) => v1 == v2,
120      (Self::ThemeRef(v1), Self::ThemeRef(v2)) => v1 == v2,
121      (Self::Map(m1), Self::Map(m2)) => m1 == m2,
122      (Self::FunctionConfig(f1), Self::FunctionConfig(f2)) => f1 == f2,
123      (Self::FunctionConfigMap(f1), Self::FunctionConfigMap(f2)) => f1 == f2,
124      (Self::Callback(_), Self::Callback(_)) => false,
125      (Self::EnvObject(_), Self::EnvObject(_)) => false,
126      _ => false,
127    }
128  }
129}
130
131impl EvaluateResultValue {
132  /// Extracts an ObjectLit from an EvaluateResultValue if it contains an Expr(Object).
133  ///
134  /// This is a common pattern when evaluating spread expressions or object literals.
135  ///
136  /// # Example
137  /// ```ignore
138  /// let Some(obj) = spread_expression.into_object() else {
139  ///   return None;
140  /// };
141  /// ```
142  #[inline]
143  pub fn into_object(self) -> Option<swc_core::ecma::ast::ObjectLit> {
144    match self {
145      Self::Expr(Expr::Object(obj)) => Some(obj),
146      _ => None,
147    }
148  }
149
150  /// Extracts an ArrayLit from an EvaluateResultValue if it contains an Expr(Array).
151  ///
152  /// This is a common pattern when evaluating array expressions.
153  ///
154  /// # Example
155  /// ```ignore
156  /// let Some(arr) = value.into_array() else {
157  ///   return None;
158  /// };
159  /// ```
160  #[inline]
161  pub fn into_array(self) -> Option<swc_core::ecma::ast::ArrayLit> {
162    match self {
163      Self::Expr(Expr::Array(arr)) => Some(arr),
164      _ => None,
165    }
166  }
167
168  /// Extracts a string key from an `EvaluateResultValue::Expr` variant.
169  ///
170  /// Handles the common pattern of resolving a property name from an evaluated expression:
171  /// - `Expr::Ident` → symbol name as string
172  /// - `Expr::Lit(Str)` → string value
173  /// - `Expr::Lit(Num)` → number formatted as string
174  /// - `Expr::Lit(BigInt)` → bigint formatted as string
175  /// - All other variants → `None`
176  ///
177  /// # Example
178  /// ```ignore
179  /// let key = property.as_string_key().expect("Property must be a string key");
180  /// ```
181  #[inline]
182  pub fn as_string_key(&self) -> Option<String> {
183    match self {
184      Self::Expr(expr) => match expr {
185        Expr::Ident(ident) => Some(ident.sym.to_string()),
186        Expr::Lit(Lit::Str(s)) => s.value.as_str().map(str::to_string),
187        Expr::Lit(Lit::Num(n)) => Some(n.value.to_string()),
188        Expr::Lit(Lit::BigInt(bi)) => Some(bi.value.to_string()),
189        _ => None,
190      },
191      _ => None,
192    }
193  }
194}