stylex_transform/shared/utils/core/
member_expression.rs1use 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}