Skip to main content

stylex_transform/shared/structures/
theme_ref.rs

1use rustc_hash::FxHashMap;
2use stylex_macros::stylex_panic;
3
4use crate::shared::utils::common::{create_hash, gen_file_based_identifier};
5use stylex_constants::constants::common::VAR_GROUP_HASH_KEY;
6use stylex_enums::theme_ref::ThemeRefResult;
7
8use super::state_manager::StateManager;
9
10#[derive(Debug, Clone)]
11pub struct ThemeRef {
12  file_name: String,
13  export_name: String,
14  class_name_prefix: String,
15  map: FxHashMap<String, String>,
16}
17
18impl ThemeRef {
19  pub(crate) fn new(file_name: String, export_name: String, class_name_prefix: String) -> Self {
20    Self {
21      file_name,
22      export_name,
23      class_name_prefix,
24      map: FxHashMap::default(),
25    }
26  }
27
28  pub(crate) fn get(&mut self, key: &str, state: &StateManager) -> ThemeRefResult {
29    if key == "__IS_PROXY" {
30      return ThemeRefResult::Proxy;
31    }
32
33    if key == "toString" {
34      let value = format!(
35        "{}{}",
36        state.options.class_name_prefix,
37        create_hash(&gen_file_based_identifier(
38          &self.file_name,
39          &self.export_name,
40          None
41        ))
42      );
43      return ThemeRefResult::ToString(value);
44    }
45
46    if key.starts_with("--") {
47      let css_key = format!("var({})", key);
48      return ThemeRefResult::CssVar(css_key);
49    }
50    let entry = self.map.entry(key.to_string()).or_insert_with(|| {
51      let str_to_hash = gen_file_based_identifier(
52        &self.file_name,
53        &self.export_name,
54        if key == VAR_GROUP_HASH_KEY {
55          None
56        } else {
57          Some(key)
58        },
59      );
60
61      let debug = state.options.debug;
62      let enable_debug_class_names = state.options.enable_debug_class_names;
63
64      let var_safe_key = if key == VAR_GROUP_HASH_KEY {
65        String::new()
66      } else {
67        let mut safe = if key.chars().next().unwrap_or('\0').is_ascii_digit() {
68          format!("_{}", key)
69        } else {
70          key.to_string()
71        }
72        .chars()
73        .map(|c| if c.is_ascii_alphanumeric() { c } else { '_' })
74        .collect::<String>();
75
76        safe.push('-');
77
78        safe
79      };
80
81      let var_name = if debug && enable_debug_class_names {
82        format!(
83          "{}{}{}",
84          var_safe_key,
85          self.class_name_prefix,
86          create_hash(&str_to_hash)
87        )
88      } else {
89        format!("{}{}", self.class_name_prefix, create_hash(&str_to_hash))
90      };
91
92      if key == VAR_GROUP_HASH_KEY {
93        return var_name;
94      }
95
96      format!("var(--{})", var_name)
97    });
98
99    ThemeRefResult::CssVar(entry.to_string())
100  }
101
102  fn _set(&self, key: &str, value: &str) {
103    stylex_panic!(
104      "Cannot set value {} to key {} in theme {}",
105      value,
106      key,
107      self.file_name
108    );
109  }
110}
111
112impl PartialEq for ThemeRef {
113  fn eq(&self, _other: &Self) -> bool {
114    stylex_panic!("Theme references cannot be compared directly.");
115    // self.file_name == other.file_name && self.export_name == other.export_name
116  }
117}