Skip to main content

stylex_transform/shared/utils/js/
native_functions.rs

1use crate::shared::enums::data_structures::evaluate_result_value::EvaluateResultValue;
2use crate::shared::structures::functions::FunctionMap;
3use crate::shared::structures::state_manager::StateManager;
4use crate::shared::utils::ast::convertors::{
5  convert_expr_to_str, convert_lit_to_number, create_string_expr,
6};
7use std::rc::Rc;
8use stylex_ast::ast::factories::{create_array_expression, create_expr_or_spread};
9use stylex_macros::{stylex_panic, stylex_unimplemented};
10use swc_core::ecma::ast::{Expr, ExprOrSpread};
11
12pub(crate) fn evaluate_map(
13  funcs: &[EvaluateResultValue],
14  args: &[Option<EvaluateResultValue>],
15) -> Option<EvaluateResultValue> {
16  let cb = funcs.first()?;
17
18  let cb = cb.as_callback()?;
19
20  let func_result = args
21    .iter()
22    .filter_map(|arg| {
23      let result = arg.as_ref()?;
24
25      match result {
26        EvaluateResultValue::Expr(_) => Some(evaluate_map_cb(cb, arg)),
27        EvaluateResultValue::Vec(vec) => {
28          let func_result = vec
29            .iter()
30            .map(|expr| {
31              let expr = evaluate_map_cb(cb, expr);
32
33              EvaluateResultValue::Expr(expr)
34            })
35            .collect::<Vec<EvaluateResultValue>>();
36
37          let elems = func_result
38            .into_iter()
39            .map(|item| Some(create_expr_or_spread(item.as_expr()?.clone())))
40            .collect::<Vec<Option<ExprOrSpread>>>();
41
42          Some(create_array_expression(elems))
43        },
44        _ => stylex_unimplemented!("Unhandled EvaluateResultValue in map callback"),
45      }
46    })
47    .collect::<Vec<Expr>>();
48
49  match func_result.first() {
50    Some(Expr::Array(array)) => Some(EvaluateResultValue::Expr(Expr::from(array.clone()))),
51    _ => Some(EvaluateResultValue::Expr(create_array_expression(
52      func_result
53        .into_iter()
54        .map(|expr| Some(create_expr_or_spread(expr)))
55        .collect(),
56    ))),
57  }
58}
59
60pub(crate) fn evaluate_join(
61  funcs: &[EvaluateResultValue],
62  args: &[Option<EvaluateResultValue>],
63  state: &mut StateManager,
64  functions: &FunctionMap,
65) -> Option<EvaluateResultValue> {
66  let join_arg = funcs.first()?;
67
68  let join_arg = match convert_expr_to_str(join_arg.as_expr()?, state, functions) {
69    Some(s) => s,
70    None => stylex_panic!("The join() separator argument must be a string value."),
71  };
72
73  let result = args
74    .iter()
75    .map(|arg_ref| {
76      let arg_expr = match arg_ref.as_ref().and_then(|arg| arg.as_expr()) {
77        Some(expr) => expr,
78        None => stylex_panic!("Array element must evaluate to a string for join()."),
79      };
80      match convert_expr_to_str(arg_expr, state, functions) {
81        Some(s) => s,
82        None => stylex_panic!("Array element must evaluate to a string for join()."),
83      }
84    })
85    .collect::<Vec<String>>()
86    .join(&join_arg);
87
88  Some(EvaluateResultValue::Expr(create_string_expr(&result)))
89}
90
91pub(crate) fn evaluate_filter(
92  funcs: &[EvaluateResultValue],
93  args: &[Option<EvaluateResultValue>],
94) -> Option<EvaluateResultValue> {
95  let cb = funcs.first()?;
96
97  let cb = cb.as_callback()?;
98
99  let func_result = args
100    .iter()
101    .filter_map(|arg| {
102      let result = arg.as_ref()?;
103
104      match result {
105        EvaluateResultValue::Expr(expr) => evaluate_filter_cb(cb, arg, expr),
106        EvaluateResultValue::Vec(vec) => {
107          let func_result = vec
108            .iter()
109            .filter_map(|expr| {
110              let result =
111                evaluate_filter_cb(cb, &expr.clone(), &expr.as_ref()?.as_expr()?.clone());
112
113              result.map(EvaluateResultValue::Expr)
114            })
115            .collect::<Vec<EvaluateResultValue>>();
116
117          let elems = func_result
118            .into_iter()
119            .map(|item| Some(create_expr_or_spread(item.as_expr()?.clone())))
120            .collect::<Vec<Option<ExprOrSpread>>>();
121
122          Some(create_array_expression(elems))
123        },
124        _ => stylex_unimplemented!("Unhandled EvaluateResultValue in filter callback"),
125      }
126    })
127    .collect::<Vec<Expr>>();
128
129  match func_result.first() {
130    Some(Expr::Array(array)) => Some(EvaluateResultValue::Expr(Expr::from(array.clone()))),
131    _ => Some(EvaluateResultValue::Expr(create_array_expression(
132      func_result
133        .into_iter()
134        .map(|expr| Some(create_expr_or_spread(expr)))
135        .collect(),
136    ))),
137  }
138}
139
140pub(crate) fn evaluate_map_cb(
141  cb: &Rc<dyn Fn(Vec<Option<EvaluateResultValue>>) -> Expr>,
142  cb_arg: &Option<EvaluateResultValue>,
143) -> Expr {
144  (cb)(vec![cb_arg.clone()])
145}
146
147pub(crate) fn evaluate_filter_cb(
148  cb: &Rc<dyn Fn(Vec<Option<EvaluateResultValue>>) -> Expr>,
149  cb_arg: &Option<EvaluateResultValue>,
150  item: &Expr,
151) -> Option<Expr> {
152  let result = evaluate_map_cb(cb, cb_arg);
153
154  let Some(lit) = result.as_lit() else {
155    stylex_panic!("Expr is not a literal");
156  };
157
158  if convert_lit_to_number(lit).unwrap_or_else(|error| stylex_panic!("{}", error)) == 0.0 {
159    None
160  } else {
161    Some(item.clone())
162  }
163}