Skip to main content

stylex_transform/shared/transformers/
stylex_define_vars.rs

1use std::rc::Rc;
2
3use indexmap::IndexMap;
4use stylex_macros::{stylex_panic, stylex_unimplemented, stylex_unreachable};
5use swc_core::ecma::ast::{KeyValueProp, PropName};
6
7use crate::shared::enums::data_structures::evaluate_result_value::EvaluateResultValue;
8use crate::shared::enums::data_structures::flat_compiled_styles_value::FlatCompiledStylesValue;
9use crate::shared::enums::data_structures::obj_map_type::ObjMapType;
10use crate::shared::structures::state_manager::StateManager;
11use crate::shared::structures::types::{FlatCompiledStyles, InjectableStylesMap};
12use crate::shared::utils::common::{create_hash, get_css_value};
13use crate::shared::utils::core::define_vars_utils::construct_css_variables_string;
14use crate::shared::utils::object::obj_map;
15use stylex_constants::constants::common::VAR_GROUP_HASH_KEY;
16use stylex_constants::constants::messages::{
17  EXPORT_ID_NOT_SET, INJECTABLE_STYLE_NOT_SUPPORTED, VALUES_MUST_BE_OBJECT,
18};
19use stylex_types::enums::data_structures::injectable_style::InjectableStyleKind;
20use stylex_types::structures::injectable_style::InjectableStyle;
21
22pub(crate) fn stylex_define_vars(
23  variables: &EvaluateResultValue,
24  state: &mut StateManager,
25) -> (FlatCompiledStyles, InjectableStylesMap) {
26  let var_group_hash = format!(
27    "{}{}",
28    state.options.class_name_prefix,
29    create_hash(match state.export_id.as_ref() {
30      Some(id) => id,
31      None => stylex_panic!("{}", EXPORT_ID_NOT_SET),
32    })
33  );
34
35  let mut typed_variables: FlatCompiledStyles = IndexMap::new();
36
37  let Some(variables) = variables.as_expr().and_then(|expr| expr.as_object()) else {
38    stylex_panic!("{}", VALUES_MUST_BE_OBJECT)
39  };
40
41  let variables_map = obj_map(
42    ObjMapType::Object(variables.clone()),
43    state,
44    |item, state| -> Rc<FlatCompiledStylesValue> {
45      let result = match item.as_ref() {
46        FlatCompiledStylesValue::InjectableStyle(_) => {
47          stylex_panic!("{}", INJECTABLE_STYLE_NOT_SUPPORTED)
48        },
49        FlatCompiledStylesValue::Tuple(key, value, _) => {
50          let str_to_hash = format!(
51            "{}.{}",
52            match state.export_id.as_ref() {
53              Some(id) => id,
54              None => stylex_panic!("{}", EXPORT_ID_NOT_SET),
55            },
56            key
57          );
58
59          let debug = state.options.debug;
60          let enable_debug_class_names = state.options.enable_debug_class_names;
61
62          let var_safe_key = if key.chars().next().unwrap_or('\0') >= '0'
63            && key.chars().next().unwrap_or('\0') <= '9'
64          {
65            format!("_{}", key)
66          } else {
67            key.to_string()
68          }
69          .chars()
70          .map(|c| if c.is_alphanumeric() { c } else { '_' })
71          .collect::<String>();
72
73          // Created hashed variable names with fileName//themeName//key
74          let name_hash = if key.starts_with("--") {
75            key.get(2..).unwrap_or_default()
76          } else if debug && enable_debug_class_names {
77            &format!(
78              "{}-{}{}",
79              var_safe_key,
80              &state.options.class_name_prefix,
81              create_hash(str_to_hash.as_str())
82            )
83          } else {
84            &format!(
85              "{}{}",
86              &state.options.class_name_prefix,
87              create_hash(str_to_hash.as_str())
88            )
89          };
90
91          let (css_value, css_type) = get_css_value(KeyValueProp {
92            key: PropName::Str(key.clone().into()),
93            value: value.clone(),
94          });
95
96          FlatCompiledStylesValue::Tuple(name_hash.to_string(), css_value, css_type)
97        },
98        _ => stylex_unimplemented!("Unsupported value type in define vars"),
99      };
100
101      Rc::new(result)
102    },
103  );
104
105  let mut theme_variables_objects = obj_map(
106    ObjMapType::Map(variables_map.clone()),
107    state,
108    |item, _| match item.as_ref() {
109      FlatCompiledStylesValue::InjectableStyle(_) => {
110        stylex_panic!("{}", INJECTABLE_STYLE_NOT_SUPPORTED)
111      },
112      FlatCompiledStylesValue::Tuple(key, _, _) => {
113        Rc::new(FlatCompiledStylesValue::String(format!("var(--{})", key)))
114      },
115      _ => stylex_unreachable!("Unsupported value type"),
116    },
117  );
118
119  let injectable_styles =
120    construct_css_variables_string(&variables_map, &var_group_hash, &mut typed_variables);
121
122  let injectable_types = obj_map(
123    ObjMapType::Map(typed_variables),
124    state,
125    |item, _| -> Rc<FlatCompiledStylesValue> {
126      let result = match item.as_ref() {
127        FlatCompiledStylesValue::CSSType(name_hash, syntax, initial_value) => {
128          let property = format!(
129            "@property --{} {{ syntax: \"{}\"; inherits: true; initial-value: {} }}",
130            name_hash, syntax, initial_value
131          );
132
133          FlatCompiledStylesValue::InjectableStyle(InjectableStyle {
134            ltr: property,
135            ..Default::default()
136          })
137        },
138        _ => stylex_unreachable!("Unsupported value type"),
139      };
140
141      Rc::new(result)
142    },
143  );
144
145  let mut injectable_types: InjectableStylesMap = injectable_types
146    .iter()
147    .filter_map(|(key, value)| {
148      value.as_injectable_style().map(|inj_style| {
149        (
150          key.to_owned(),
151          Rc::new(InjectableStyleKind::Regular(inj_style.clone())),
152        )
153      })
154    })
155    .collect();
156
157  theme_variables_objects.insert(
158    VAR_GROUP_HASH_KEY.to_owned(),
159    Rc::new(FlatCompiledStylesValue::String(var_group_hash)),
160  );
161
162  injectable_types.extend(injectable_styles);
163
164  (theme_variables_objects, injectable_types)
165}