Skip to main content

stylex_transform/shared/utils/
validators.rs

1use rustc_hash::FxHashSet;
2use stylex_macros::stylex_panic;
3use stylex_structures::top_level_expression::TopLevelExpression;
4use swc_core::{
5  atoms::Atom,
6  ecma::ast::{ArrowExpr, CallExpr, Expr, KeyValueProp, Lit, Pat, VarDeclarator},
7};
8
9use crate::shared::enums::data_structures::evaluate_result_value::EvaluateResultValue;
10use crate::shared::structures::state_manager::StateManager;
11use crate::shared::utils::ast::convertors::create_string_expr;
12use crate::shared::utils::ast::helpers::is_variable_named_exported;
13use crate::shared::utils::common::get_import_from;
14use crate::shared::utils::log::build_code_frame_error::build_code_frame_error_and_panic;
15use stylex_ast::ast::factories::{create_expr_or_spread, create_key_value_prop_ident};
16use stylex_constants::constants::common::VAR_GROUP_HASH_KEY;
17use stylex_constants::constants::messages::{
18  DUPLICATE_CONDITIONAL, EXPECTED_CSS_VAR, ILLEGAL_PROP_ARRAY_VALUE, ILLEGAL_PROP_VALUE,
19  INVALID_PSEUDO_OR_AT_RULE, MEMBER_OBJ_NOT_IDENT, NO_OBJECT_SPREADS, NON_OBJECT_KEYFRAME,
20  NON_STATIC_SECOND_ARG_CREATE_THEME_VALUE, ONLY_NAMED_PARAMETERS_IN_DYNAMIC_STYLE_FUNCTIONS,
21  ONLY_OVERRIDE_DEFINE_VARS, illegal_argument_length, non_export_named_declaration,
22  non_static_value, non_style_object, unbound_call_value,
23};
24
25use super::{
26  ast::convertors::{convert_key_value_to_str, convert_lit_to_string},
27  common::get_key_values_from_object,
28};
29
30pub(crate) fn validate_stylex_create(call: &CallExpr, state: &mut StateManager) {
31  if !is_create_call(call, state) {
32    return;
33  }
34
35  if state.find_call_declaration(call).is_none()
36    && state
37      .find_top_level_expr(
38        call,
39        |tpe: &TopLevelExpression| matches!(tpe.1, Expr::Array(_)),
40        None,
41      )
42      .is_none()
43  {
44    build_code_frame_error_and_panic(
45      &Expr::Call(call.clone()),
46      &Expr::Call(call.clone()),
47      &unbound_call_value("create"),
48      state,
49    );
50  }
51
52  if call.args.len() != 1 {
53    build_code_frame_error_and_panic(
54      &Expr::Call(call.clone()),
55      &Expr::Call(call.clone()),
56      &illegal_argument_length("create", 1),
57      state,
58    );
59  }
60
61  let first_arg = &call.args[0];
62  if !first_arg.expr.is_object() {
63    build_code_frame_error_and_panic(
64      &Expr::Call(call.clone()),
65      &first_arg.expr,
66      &non_style_object("create"),
67      state,
68    );
69  }
70
71  let has_spread = if let Expr::Object(obj) = first_arg.expr.as_ref() {
72    obj
73      .props
74      .iter()
75      .any(|prop| matches!(prop, swc_core::ecma::ast::PropOrSpread::Spread(_)))
76  } else {
77    false
78  };
79
80  if has_spread {
81    build_code_frame_error_and_panic(
82      &Expr::Call(call.clone()),
83      &first_arg.expr,
84      NO_OBJECT_SPREADS,
85      state,
86    );
87  }
88}
89
90pub(crate) fn validate_stylex_keyframes_indent(var_decl: &VarDeclarator, state: &mut StateManager) {
91  if !is_keyframes_call(var_decl, state) {
92    return;
93  }
94
95  let init_expr = match &var_decl.init {
96    Some(init) => init.clone(),
97    None => stylex_panic!("{}", non_static_value("keyframes")),
98  };
99
100  let init_call = init_expr.as_call().unwrap_or_else(|| {
101    build_code_frame_error_and_panic(
102      &init_expr,
103      &init_expr,
104      &non_static_value("keyframes"),
105      state,
106    );
107  });
108
109  match state.find_top_level_expr(init_call, |_| false, None) {
110    Some(_) => {},
111    None => build_code_frame_error_and_panic(
112      &init_expr,
113      &init_expr,
114      &unbound_call_value("keyframes"),
115      state,
116    ),
117  }
118
119  if init_call.args.len() != 1 {
120    build_code_frame_error_and_panic(
121      &init_expr,
122      &init_expr,
123      &illegal_argument_length("keyframes", 1),
124      state,
125    );
126  }
127
128  let first_arg: &_ = &init_call.args[0];
129  if !first_arg.expr.is_object() {
130    build_code_frame_error_and_panic(
131      &init_expr,
132      &first_arg.expr,
133      &non_style_object("keyframes"),
134      state,
135    );
136  }
137}
138
139pub(crate) fn validate_stylex_position_try_indent(
140  var_decl: &VarDeclarator,
141  state: &mut StateManager,
142) {
143  if !is_position_try_call(var_decl, state) {
144    return;
145  }
146
147  let init_expr = match &var_decl.init {
148    Some(init) => init.clone(),
149    None => stylex_panic!("{}", non_static_value("positionTry")),
150  };
151
152  let init_call = init_expr.as_call().unwrap_or_else(|| {
153    build_code_frame_error_and_panic(
154      &init_expr,
155      &init_expr,
156      &non_static_value("positionTry"),
157      state,
158    );
159  });
160
161  match state.find_top_level_expr(init_call, |_| false, None) {
162    Some(_) => {},
163    None => build_code_frame_error_and_panic(
164      &init_expr,
165      &init_expr,
166      &unbound_call_value("positionTry"),
167      state,
168    ),
169  }
170
171  if init_call.args.len() != 1 {
172    build_code_frame_error_and_panic(
173      &init_expr,
174      &init_expr,
175      &illegal_argument_length("positionTry", 1),
176      state,
177    );
178  }
179
180  let first_arg: &_ = &init_call.args[0];
181  if !first_arg.expr.is_object() {
182    build_code_frame_error_and_panic(
183      &init_expr,
184      &first_arg.expr,
185      &non_style_object("positionTry"),
186      state,
187    );
188  }
189}
190
191pub(crate) fn validate_stylex_default_marker_indent(call: &CallExpr, state: &mut StateManager) {
192  if !is_default_marker_call(call, state) {
193    return;
194  }
195
196  let call_expr = Expr::from(call.clone());
197
198  if !call.args.is_empty() {
199    build_code_frame_error_and_panic(
200      &call_expr,
201      &Box::new(call_expr.clone()),
202      &illegal_argument_length("defaultMarker", 1),
203      state,
204    );
205  }
206}
207
208pub(crate) fn validate_stylex_view_transition_class_indent(
209  var_decl: &VarDeclarator,
210  state: &mut StateManager,
211) {
212  if !is_view_transition_class_call(var_decl, state) {
213    return;
214  }
215
216  let init_expr = match &var_decl.init {
217    Some(init) => init.clone(),
218    None => stylex_panic!("{}", non_static_value("viewTransitionClass")),
219  };
220
221  let init_call = init_expr.as_call().unwrap_or_else(|| {
222    build_code_frame_error_and_panic(
223      &init_expr,
224      &init_expr,
225      &non_static_value("viewTransitionClass"),
226      state,
227    );
228  });
229
230  match state.find_top_level_expr(init_call, |_| false, None) {
231    Some(_) => {},
232    None => build_code_frame_error_and_panic(
233      &init_expr,
234      &init_expr,
235      &unbound_call_value("viewTransitionClass"),
236      state,
237    ),
238  }
239
240  if init_call.args.len() != 1 {
241    build_code_frame_error_and_panic(
242      &init_expr,
243      &init_expr,
244      &illegal_argument_length("viewTransitionClass", 1),
245      state,
246    );
247  }
248
249  let first_arg: &_ = &init_call.args[0];
250  if !first_arg.expr.is_object() {
251    build_code_frame_error_and_panic(
252      &init_expr,
253      &first_arg.expr,
254      &non_style_object("viewTransitionClass"),
255      state,
256    );
257  }
258}
259
260pub(crate) fn validate_stylex_create_theme_indent(
261  var_decl: &Option<VarDeclarator>,
262  call: &CallExpr,
263  state: &mut StateManager,
264) {
265  if !is_create_theme_call(call, state) {
266    return;
267  }
268
269  let var_decl = var_decl.as_ref().unwrap_or_else(|| {
270    build_code_frame_error_and_panic(
271      &Expr::Call(call.clone()),
272      &Expr::Call(call.clone()),
273      &unbound_call_value("createTheme"),
274      state,
275    );
276  });
277
278  let init_expr = var_decl.init.as_ref().unwrap_or_else(|| {
279    build_code_frame_error_and_panic(
280      &Expr::Call(call.clone()),
281      &Expr::Call(call.clone()),
282      &unbound_call_value("createTheme"),
283      state,
284    );
285  });
286
287  let init = init_expr.as_call().unwrap_or_else(|| {
288    build_code_frame_error_and_panic(
289      init_expr,
290      &Expr::Call(call.clone()),
291      &non_static_value("createTheme"),
292      state,
293    );
294  });
295
296  match state.find_top_level_expr(call, |_| false, None) {
297    Some(_) => {},
298    None => build_code_frame_error_and_panic(
299      init_expr,
300      &Expr::Call(call.clone()),
301      &unbound_call_value("createTheme"),
302      state,
303    ),
304  };
305
306  if init.args.len() != 2 {
307    build_code_frame_error_and_panic(
308      init_expr,
309      &Expr::Call(call.clone()),
310      &illegal_argument_length("createTheme", 1),
311      state,
312    );
313  }
314
315  let second_arg = &init.args[1];
316
317  let is_valid_second_arg = match second_arg.expr.as_ref() {
318    Expr::Ident(ident) => get_import_from(state, ident).is_none(),
319    Expr::Object(_) => true,
320    _ => false,
321  };
322
323  if !is_valid_second_arg {
324    build_code_frame_error_and_panic(
325      init_expr,
326      &Expr::Call(call.clone()),
327      NON_STATIC_SECOND_ARG_CREATE_THEME_VALUE,
328      state,
329    );
330  }
331}
332
333pub(crate) fn find_and_validate_stylex_define_vars(
334  call: &CallExpr,
335  state: &mut StateManager,
336) -> Option<TopLevelExpression> {
337  if !is_define_vars_call(call, state) {
338    return None;
339  }
340
341  let call_expr = Expr::from(call.clone());
342
343  let stylex_create_theme_top_level_expr = match state.find_top_level_expr(call, |_| false, None) {
344    Some(stylex_create_theme_top_level_expr) => stylex_create_theme_top_level_expr,
345    None => build_code_frame_error_and_panic(
346      &call_expr,
347      &call
348        .args
349        .get(2)
350        .cloned()
351        .unwrap_or_else(|| create_expr_or_spread(call_expr.clone()))
352        .expr,
353      &unbound_call_value("defineVars"),
354      state,
355    ),
356  };
357
358  if call.args.len() != 1 {
359    build_code_frame_error_and_panic(
360      &call_expr,
361      &call
362        .args
363        .get(1)
364        .cloned()
365        .unwrap_or_else(|| create_expr_or_spread(call_expr.clone()))
366        .expr,
367      &illegal_argument_length("defineVars", 1),
368      state,
369    );
370  }
371
372  if !is_variable_named_exported(stylex_create_theme_top_level_expr, state) {
373    build_code_frame_error_and_panic(
374      &call_expr,
375      &call_expr,
376      &non_export_named_declaration("defineVars"),
377      state,
378    );
379  }
380
381  Some(stylex_create_theme_top_level_expr.clone())
382}
383
384pub(crate) fn validate_stylex_define_marker_indent(call: &CallExpr, state: &mut StateManager) {
385  if !is_define_marker_call(call, state) {
386    return;
387  }
388
389  let call_expr = Expr::from(call.clone());
390
391  if !call.args.is_empty() {
392    build_code_frame_error_and_panic(
393      &call_expr,
394      &Box::new(call_expr.clone()),
395      &illegal_argument_length("defineMarker", 0),
396      state,
397    );
398  }
399
400  let define_marker_top_level_expr = match state.find_top_level_expr(call, |_| false, None) {
401    Some(define_marker_top_level_expr) => define_marker_top_level_expr,
402    None => build_code_frame_error_and_panic(
403      &call_expr,
404      &call
405        .args
406        .get(2)
407        .cloned()
408        .unwrap_or_else(|| create_expr_or_spread(call_expr.clone()))
409        .expr,
410      &unbound_call_value("defineMarker"),
411      state,
412    ),
413  };
414
415  if !is_variable_named_exported(define_marker_top_level_expr, state) {
416    build_code_frame_error_and_panic(
417      &call_expr,
418      &call_expr,
419      &non_export_named_declaration("defineMarker"),
420      state,
421    );
422  }
423}
424
425pub(crate) fn find_and_validate_stylex_define_consts(
426  call: &CallExpr,
427  state: &mut StateManager,
428) -> Option<TopLevelExpression> {
429  if !is_define_consts_call(call, state) {
430    return None;
431  }
432
433  let call_expr = Expr::from(call.clone());
434
435  let define_consts_top_level_expr = match state.find_top_level_expr(call, |_| false, None) {
436    Some(define_consts_top_level_expr) => define_consts_top_level_expr,
437    None => build_code_frame_error_and_panic(
438      &call_expr,
439      &call
440        .args
441        .get(2)
442        .cloned()
443        .unwrap_or_else(|| create_expr_or_spread(call_expr.clone()))
444        .expr,
445      &unbound_call_value("defineConsts"),
446      state,
447    ),
448  };
449
450  if call.args.len() != 1 {
451    build_code_frame_error_and_panic(
452      &call_expr,
453      &call
454        .args
455        .get(1)
456        .cloned()
457        .unwrap_or_else(|| create_expr_or_spread(call_expr.clone()))
458        .expr,
459      &illegal_argument_length("defineConsts", 1),
460      state,
461    );
462  }
463
464  if !is_variable_named_exported(define_consts_top_level_expr, state) {
465    build_code_frame_error_and_panic(
466      &call_expr,
467      &call_expr,
468      &non_export_named_declaration("defineConsts"),
469      state,
470    );
471  }
472
473  Some(define_consts_top_level_expr.clone())
474}
475
476pub(crate) fn is_create_call(call: &CallExpr, state: &StateManager) -> bool {
477  is_target_call(("create", &state.stylex_create_import), call, state)
478}
479
480pub(crate) fn is_props_call(call: &CallExpr, state: &StateManager) -> bool {
481  is_target_call(("props", &state.stylex_props_import), call, state)
482}
483
484pub(crate) fn is_attrs_call(call: &CallExpr, state: &StateManager) -> bool {
485  is_target_call(("attrs", &state.stylex_attrs_import), call, state)
486}
487
488pub(crate) fn is_keyframes_call(var_decl: &VarDeclarator, state: &StateManager) -> bool {
489  let init = var_decl.init.as_ref().and_then(|init| init.clone().call());
490
491  match init {
492    Some(call) => is_target_call(("keyframes", &state.stylex_keyframes_import), &call, state),
493    _ => false,
494  }
495}
496
497pub(crate) fn is_position_try_call(var_decl: &VarDeclarator, state: &StateManager) -> bool {
498  let init = var_decl.init.as_ref().and_then(|init| init.clone().call());
499
500  match init {
501    Some(call) => is_target_call(
502      ("positionTry", &state.stylex_position_try_import),
503      &call,
504      state,
505    ),
506    _ => false,
507  }
508}
509
510pub(crate) fn is_default_marker_call(call: &CallExpr, state: &StateManager) -> bool {
511  is_target_call(
512    ("defaultMarker", &state.stylex_default_marker_import),
513    call,
514    state,
515  )
516}
517
518pub(crate) fn is_view_transition_class_call(
519  var_decl: &VarDeclarator,
520  state: &StateManager,
521) -> bool {
522  let init = var_decl.init.as_ref().and_then(|init| init.clone().call());
523
524  match init {
525    Some(call) => is_target_call(
526      (
527        "viewTransitionClass",
528        &state.stylex_view_transition_class_import,
529      ),
530      &call,
531      state,
532    ),
533    _ => false,
534  }
535}
536
537pub(crate) fn is_create_theme_call(call: &CallExpr, state: &StateManager) -> bool {
538  is_target_call(
539    ("createTheme", &state.stylex_create_theme_import),
540    call,
541    state,
542  )
543}
544
545pub(crate) fn is_define_vars_call(call: &CallExpr, state: &StateManager) -> bool {
546  is_target_call(
547    ("defineVars", &state.stylex_define_vars_import),
548    call,
549    state,
550  )
551}
552
553pub(crate) fn is_define_consts_call(call: &CallExpr, state: &StateManager) -> bool {
554  is_target_call(
555    ("defineConsts", &state.stylex_define_consts_import),
556    call,
557    state,
558  )
559}
560
561pub(crate) fn is_define_marker_call(call: &CallExpr, state: &StateManager) -> bool {
562  is_target_call(
563    ("defineMarker", &state.stylex_define_marker_import),
564    call,
565    state,
566  )
567}
568pub(crate) fn is_target_call(
569  (call_name, imports_map): (&str, &FxHashSet<Atom>),
570  call: &CallExpr,
571  state: &StateManager,
572) -> bool {
573  let is_create_ident = call
574    .callee
575    .as_expr()
576    .and_then(|arg| arg.as_ident())
577    .is_some_and(|ident| imports_map.contains(&ident.sym));
578
579  let is_create_member = call
580    .callee
581    .as_expr()
582    .and_then(|expr| expr.as_member())
583    .is_some_and(|member| {
584      member.obj.is_ident()
585        && member.prop.as_ident().is_some_and(|ident| {
586          ident.sym == call_name
587            && state.stylex_import_stringified().contains(
588              &match member.obj.as_ident() {
589                Some(ident) => ident,
590                None => stylex_panic!("{}", MEMBER_OBJ_NOT_IDENT),
591              }
592              .sym
593              .to_string(),
594            )
595        })
596    });
597
598  is_create_ident || is_create_member
599}
600pub(crate) fn validate_namespace(
601  namespaces: &[KeyValueProp],
602  conditions: &[String],
603  state: &mut StateManager,
604) {
605  for namespace in namespaces {
606    match namespace.value.as_ref() {
607      Expr::Lit(lit) => {
608        if !matches!(
609          lit,
610          Lit::Str(_) | Lit::Null(_) | Lit::Num(_) | Lit::BigInt(_)
611        ) {
612          build_code_frame_error_and_panic(
613            &Expr::Lit(lit.clone()),
614            &Expr::Lit(lit.clone()),
615            ILLEGAL_PROP_VALUE,
616            state,
617          );
618        }
619      },
620      Expr::Array(array) => {
621        for elem in array.elems.iter().flatten() {
622          if elem.spread.is_some() {
623            build_code_frame_error_and_panic(
624              &Expr::Array(array.clone()),
625              &Expr::Array(array.clone()),
626              "Spread operator not implemented",
627              state,
628            );
629          }
630
631          if !matches!(elem.expr.as_ref(), Expr::Lit(_)) {
632            build_code_frame_error_and_panic(
633              &Expr::Array(array.clone()),
634              &Expr::Array(array.clone()),
635              ILLEGAL_PROP_ARRAY_VALUE,
636              state,
637            );
638          }
639        }
640      },
641      Expr::Object(object) => {
642        let key = convert_key_value_to_str(namespace);
643
644        if key.starts_with('@') || key.starts_with(':') || key.starts_with('[') {
645          if conditions.contains(&key) {
646            build_code_frame_error_and_panic(
647              &Expr::Object(object.clone()),
648              &Expr::Object(object.clone()),
649              DUPLICATE_CONDITIONAL,
650              state,
651            );
652          }
653
654          let nested_key_values = get_key_values_from_object(object);
655
656          let mut extended_conditions = conditions.to_vec();
657          extended_conditions.push(key);
658
659          validate_namespace(&nested_key_values, &extended_conditions, state);
660        } else {
661          let conditional_styles_key_values = get_key_values_from_object(object);
662
663          for conditional_style in &conditional_styles_key_values {
664            validate_conditional_styles(conditional_style, &[], state);
665          }
666        }
667      },
668      _ => {},
669    }
670  }
671}
672
673pub(crate) fn validate_dynamic_style_params(
674  path: &ArrowExpr,
675  params: &[Pat],
676  state: &mut StateManager,
677) {
678  if params.iter().any(|param| !param.is_ident()) {
679    let path_expr = Expr::Arrow(path.clone());
680
681    build_code_frame_error_and_panic(
682      &path_expr,
683      &path_expr,
684      ONLY_NAMED_PARAMETERS_IN_DYNAMIC_STYLE_FUNCTIONS,
685      state,
686    )
687  }
688}
689
690pub(crate) fn validate_conditional_styles(
691  inner_key_value: &KeyValueProp,
692  conditions: &[String],
693  state: &mut StateManager,
694) {
695  let inner_key = convert_key_value_to_str(inner_key_value);
696  let inner_value = inner_key_value.value.clone();
697
698  if !(inner_key.starts_with(':')
699      || inner_key.starts_with('@')
700      || inner_key.starts_with('[')
701      // This is a placeholder for `defineConsts` values that are later inlined
702      || inner_key.starts_with("var(--")
703      || inner_key == "default")
704  {
705    stylex_panic!("{}", INVALID_PSEUDO_OR_AT_RULE);
706  }
707
708  if conditions.contains(&inner_key) {
709    stylex_panic!("{}", DUPLICATE_CONDITIONAL);
710  }
711
712  match inner_value.as_ref() {
713    Expr::Lit(_) => {},
714    Expr::Array(array) => {
715      for elem in array.elems.iter().flatten() {
716        match elem.expr.as_ref() {
717          Expr::Lit(_) => {},
718          _ => build_code_frame_error_and_panic(
719            &Expr::Array(array.clone()),
720            &Expr::Array(array.clone()),
721            ILLEGAL_PROP_VALUE,
722            state,
723          ),
724        }
725      }
726    },
727    Expr::Object(object) => {
728      let nested_key_values = get_key_values_from_object(object);
729
730      let mut extended_conditions = conditions.to_vec();
731      extended_conditions.push(inner_key);
732
733      for nested_key_value in nested_key_values.iter() {
734        validate_conditional_styles(nested_key_value, &extended_conditions, state);
735      }
736    },
737    Expr::Ident(_) => {},
738    _ => build_code_frame_error_and_panic(&inner_value, &inner_value, ILLEGAL_PROP_VALUE, state),
739  }
740}
741
742pub(crate) fn assert_valid_keyframes(obj: &EvaluateResultValue, state: &mut StateManager) {
743  match obj {
744    EvaluateResultValue::Expr(expr) => match expr {
745      Expr::Object(object) => {
746        let key_values = get_key_values_from_object(object);
747
748        for key_value in key_values.iter() {
749          match key_value.value.as_ref() {
750            Expr::Object(_) => {},
751            _ => {
752              build_code_frame_error_and_panic(expr, expr, NON_OBJECT_KEYFRAME, state);
753            },
754          }
755        }
756      },
757      _ => {
758        build_code_frame_error_and_panic(expr, expr, &non_style_object("keyframes"), state);
759      },
760    },
761    _ => stylex_panic!("{}", non_static_value("keyframes")),
762  }
763}
764
765pub(crate) fn assert_valid_properties(
766  obj: &EvaluateResultValue,
767  valid_keys: &[&str],
768  error_message: &str,
769  state: &mut StateManager,
770) {
771  if let EvaluateResultValue::Expr(expr) = obj
772    && let Expr::Object(object) = expr
773  {
774    let key_values = get_key_values_from_object(object);
775
776    for key_value in key_values.iter() {
777      let key = convert_key_value_to_str(key_value);
778      if !valid_keys.contains(&key.as_str()) {
779        build_code_frame_error_and_panic(expr, expr, error_message, state);
780      }
781    }
782  }
783}
784
785fn assert_stylex_arg(value: &EvaluateResultValue, state: &mut StateManager, fn_name: &str) {
786  if let EvaluateResultValue::Expr(expr) = value {
787    if !expr.is_object() {
788      build_code_frame_error_and_panic(expr, expr, &non_style_object(fn_name), state);
789    }
790  } else {
791    stylex_panic!("{}", non_static_value(fn_name));
792  }
793}
794
795pub(crate) fn assert_valid_position_try(obj: &EvaluateResultValue, state: &mut StateManager) {
796  assert_stylex_arg(obj, state, "positionTry");
797}
798
799pub(crate) fn assert_valid_view_transition_class(
800  obj: &EvaluateResultValue,
801  state: &mut StateManager,
802) {
803  assert_stylex_arg(obj, state, "viewTransitionClass");
804}
805
806pub(crate) fn validate_theme_variables(
807  variables: &EvaluateResultValue,
808  state: &StateManager,
809) -> KeyValueProp {
810  if let Some(theme_ref) = variables.as_theme_ref() {
811    let mut cloned_theme_ref = theme_ref.clone();
812
813    let value = cloned_theme_ref.get(VAR_GROUP_HASH_KEY, state);
814
815    let key_value = create_key_value_prop_ident(
816      VAR_GROUP_HASH_KEY,
817      create_string_expr(
818        match value.as_css_var() {
819          Some(v) => v,
820          None => stylex_panic!("{}", EXPECTED_CSS_VAR),
821        }
822        .as_str(),
823      ),
824    );
825
826    return key_value;
827  }
828
829  if !variables.as_expr().is_some_and(|expr| expr.is_object()) {
830    stylex_panic!("{}", ONLY_OVERRIDE_DEFINE_VARS);
831  }
832
833  match variables
834    .as_expr()
835    .and_then(|expr| expr.as_object())
836    .map(get_key_values_from_object)
837    .and_then(|key_values| {
838      for key_value in key_values.into_iter() {
839        let key = convert_key_value_to_str(&key_value);
840
841        if key == VAR_GROUP_HASH_KEY {
842          let value = &key_value.value;
843
844          if let Some(lit) = value.as_lit() {
845            let value = convert_lit_to_string(lit);
846
847            if value
848              .and_then(|value| if value.is_empty() { None } else { Some(value) })
849              .is_some()
850            {
851              return Some(key_value);
852            }
853          }
854        }
855      }
856
857      None
858    }) {
859    Some(key_value) => key_value,
860    None => stylex_panic!("{}", ONLY_OVERRIDE_DEFINE_VARS),
861  }
862}