stylex_transform/transform/stylex/
transform_stylex_keyframes_call.rs1use 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}