stylex_transform/shared/transformers/
stylex_define_vars.rs1use 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 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}