Skip to main content

stylex_transform/shared/utils/core/
member_expression.rs

1use stylex_constants::constants::messages::{
2  MEMBER_OBJ_NOT_IDENT, OBJECT_KEY_MUST_BE_IDENT, SPREAD_NOT_SUPPORTED,
3};
4use stylex_macros::{stylex_panic, stylex_unimplemented};
5use swc_core::{
6  atoms::Atom,
7  ecma::ast::{Expr, Lit, MemberExpr, MemberProp, ObjectLit, Prop, PropOrSpread},
8};
9
10use stylex_enums::style_vars_to_keep::{NonNullProp, NonNullProps};
11use stylex_structures::style_vars_to_keep::StyleVarsToKeep;
12
13use crate::shared::enums::data_structures::evaluate_result_value::EvaluateResultValue;
14use crate::shared::structures::functions::FunctionMap;
15use crate::shared::structures::state_manager::StateManager;
16use crate::shared::utils::ast::convertors::convert_lit_to_string;
17use crate::shared::utils::common::increase_ident_count;
18use crate::shared::utils::js::evaluate::evaluate;
19
20pub(crate) fn member_expression(
21  member: &MemberExpr,
22  index: &mut i32,
23  bail_out_index: &mut Option<i32>,
24  non_null_props: &mut NonNullProps,
25  state: &mut StateManager,
26  fns: &FunctionMap,
27) {
28  let object = member.obj.as_ref();
29  let property = &member.prop;
30
31  let mut obj_name: Option<&Atom> = None;
32  let mut prop_name: Option<Atom> = None;
33
34  if let Expr::Ident(ident) = object {
35    let obj_ident_name = &ident.sym;
36
37    obj_name = Some(&ident.sym);
38
39    if state.style_map.contains_key(&obj_ident_name.to_string()) {
40      match property {
41        MemberProp::Ident(ident) => {
42          prop_name = Some(ident.sym.clone());
43        },
44        MemberProp::Computed(computed) => {
45          if let Expr::Lit(lit) = computed.expr.as_ref() {
46            prop_name = convert_lit_to_string(lit).map(Atom::from);
47          }
48        },
49        _ => {},
50      }
51    }
52  }
53
54  let style_non_null_props: NonNullProps;
55
56  if let Some(bail_out_index) = bail_out_index
57    && index > bail_out_index
58  {
59    *non_null_props = NonNullProps::True;
60  }
61
62  if let NonNullProps::True = non_null_props {
63    style_non_null_props = NonNullProps::True;
64  } else {
65    let evaluate_result = evaluate(&Box::new(Expr::from(member.clone())), state, fns);
66
67    let style_value = evaluate_result.value;
68    let confident = evaluate_result.confident;
69
70    if !confident {
71      *non_null_props = NonNullProps::True;
72      style_non_null_props = NonNullProps::True;
73    } else {
74      if let NonNullProps::True = non_null_props {
75        style_non_null_props = NonNullProps::True;
76      } else {
77        style_non_null_props = non_null_props.clone();
78      }
79
80      if let NonNullProps::Vec(vec) = non_null_props
81        && let Some(EvaluateResultValue::Expr(Expr::Object(ObjectLit { props, .. }))) = style_value
82      {
83        let namespaces = props
84          .iter()
85          .filter_map(|item| match item {
86            PropOrSpread::Spread(_) => stylex_unimplemented!("{}", SPREAD_NOT_SUPPORTED),
87            PropOrSpread::Prop(prop) => match prop.as_ref() {
88              Prop::KeyValue(key_value) => match key_value.value.as_ref() {
89                Expr::Lit(Lit::Null(_)) => None,
90                _ => Some(match key_value.key.as_ident().map(|ident| &ident.sym) {
91                  Some(sym) => sym,
92                  None => stylex_panic!("{}", OBJECT_KEY_MUST_BE_IDENT),
93                }),
94              },
95              _ => stylex_unimplemented!(
96                "This property variant is not supported in member expression evaluation."
97              ),
98            },
99          })
100          .collect::<Vec<&Atom>>();
101
102        vec.extend(namespaces.into_iter().cloned());
103      }
104    }
105  }
106
107  if let Some(obj_name) = obj_name {
108    increase_ident_count(
109      state,
110      match object.as_ident() {
111        Some(i) => i,
112        None => stylex_panic!("{}", MEMBER_OBJ_NOT_IDENT),
113      },
114    );
115
116    let style_var_to_keep = StyleVarsToKeep(
117      obj_name.clone(),
118      match prop_name {
119        Some(prop_name) => NonNullProp::Atom(prop_name.clone()),
120        None => NonNullProp::True,
121      },
122      style_non_null_props,
123    );
124
125    state.style_vars_to_keep.insert(style_var_to_keep);
126  }
127}