Skip to main content

stylex_transform/transform/stylex/
transform_stylex_keyframes_call.rs

1use std::rc::Rc;
2use stylex_constants::constants::messages::{SPREAD_NOT_SUPPORTED, expected_call_expression};
3
4use indexmap::IndexMap;
5use rustc_hash::FxHashMap;
6use stylex_macros::{stylex_panic, stylex_unimplemented};
7use swc_core::ecma::ast::VarDeclarator;
8use swc_core::{common::comments::Comments, ecma::ast::Expr};
9
10use crate::StyleXTransform;
11use crate::shared::structures::functions::FunctionConfigType;
12use crate::shared::structures::functions::{FunctionConfig, FunctionMap, FunctionType};
13use crate::shared::structures::types::{FunctionMapIdentifiers, FunctionMapMemberExpression};
14use crate::shared::transformers::stylex_first_that_works::stylex_first_that_works;
15use crate::shared::transformers::stylex_keyframes::stylex_keyframes;
16use crate::shared::utils::ast::convertors::create_string_expr;
17use crate::shared::utils::js::evaluate::evaluate;
18use crate::shared::utils::log::build_code_frame_error::build_code_frame_error;
19use crate::shared::utils::validators::{
20  assert_valid_keyframes, is_keyframes_call, validate_stylex_keyframes_indent,
21};
22use stylex_constants::constants::messages::{non_static_value, non_style_object};
23
24impl<C> StyleXTransform<C>
25where
26  C: Comments,
27{
28  pub(crate) fn transform_stylex_keyframes_call(
29    &mut self,
30    var_decl: &VarDeclarator,
31  ) -> Option<Expr> {
32    let is_keyframes_call = is_keyframes_call(var_decl, &self.state);
33
34    if is_keyframes_call {
35      validate_stylex_keyframes_indent(var_decl, &mut self.state);
36
37      let call = match var_decl.init.as_ref().and_then(|decl| decl.as_call()) {
38        Some(call) => call,
39        None => stylex_panic!("{}", expected_call_expression("keyframes")),
40      };
41
42      let first_arg = call.args.first().map(|first_arg| match &first_arg.spread {
43        Some(_) => stylex_unimplemented!("{}", SPREAD_NOT_SUPPORTED),
44        None => first_arg.expr.clone(),
45      })?;
46
47      let mut identifiers: FunctionMapIdentifiers = FxHashMap::default();
48      let mut member_expressions: FunctionMapMemberExpression = FxHashMap::default();
49
50      let first_that_works_fn = FunctionConfig {
51        fn_ptr: FunctionType::ArrayArgs(stylex_first_that_works),
52        takes_path: false,
53      };
54
55      for name in &self.state.stylex_first_that_works_import {
56        identifiers.insert(
57          name.clone(),
58          Box::new(FunctionConfigType::Regular(first_that_works_fn.clone())),
59        );
60      }
61
62      for name in &self.state.stylex_import {
63        let member_expression = member_expressions.entry(name.clone()).or_default();
64
65        member_expression.insert(
66          "firstThatWorks".into(),
67          Box::new(FunctionConfigType::Regular(first_that_works_fn.clone())),
68        );
69      }
70
71      self
72        .state
73        .apply_stylex_env(&mut identifiers, &mut member_expressions);
74
75      let function_map: Box<FunctionMap> = Box::new(FunctionMap {
76        identifiers,
77        member_expressions,
78        disable_imports: false,
79      });
80
81      let evaluated_arg = evaluate(&first_arg, &mut self.state, &function_map);
82
83      assert!(
84        evaluated_arg.confident,
85        "{}",
86        build_code_frame_error(
87          &Expr::Call(call.clone()),
88          &evaluated_arg.deopt.unwrap_or_else(|| *first_arg.to_owned()),
89          &non_static_value("keyframes"),
90          &mut self.state,
91        )
92      );
93
94      let value = match evaluated_arg.value {
95        Some(value) => {
96          assert!(
97            value
98              .as_expr()
99              .map(|expr| expr.is_object())
100              .unwrap_or(false),
101            "{}",
102            build_code_frame_error(
103              &Expr::Call(call.clone()),
104              &evaluated_arg.deopt.unwrap_or_else(|| *first_arg.to_owned()),
105              &non_style_object("keyframes"),
106              &mut self.state,
107            )
108          );
109          value
110        },
111        None => stylex_panic!(
112          "{}",
113          build_code_frame_error(
114            &Expr::Call(call.clone()),
115            &evaluated_arg.deopt.unwrap_or_else(|| *first_arg.to_owned()),
116            &non_static_value("keyframes"),
117            &mut self.state,
118          )
119        ),
120      };
121
122      assert_valid_keyframes(&value, &mut self.state);
123
124      let (animation_name, injectable_style) = stylex_keyframes(&value, &mut self.state);
125
126      let mut injected_styles = IndexMap::new();
127
128      injected_styles.insert(animation_name.clone(), Rc::new(injectable_style));
129
130      let result_ast = create_string_expr(animation_name.as_str());
131
132      self
133        .state
134        .register_styles(call, &injected_styles, &result_ast, None);
135
136      Some(result_ast)
137    } else {
138      None
139    }
140  }
141}