1#[cfg(test)]
2mod tests {
3 use crate::shared::structures::functions::FunctionMap;
4 use crate::shared::structures::state::EvaluationState;
5 use crate::shared::structures::state_manager::StateManager;
6 use crate::shared::utils::ast::convertors::{
7 binary_expr_to_num, binary_expr_to_string, convert_string_to_prop_name,
8 };
9 use stylex_enums::misc::BinaryExprType;
10 use swc_core::{
11 common::SyntaxContext,
12 ecma::ast::{BinExpr, BinaryOp, Expr, Ident, IdentName, Lit, Str},
13 };
14
15 fn make_num_expr(val: f64) -> Expr {
16 Expr::Lit(Lit::Num(swc_core::ecma::ast::Number {
17 value: val,
18 span: Default::default(),
19 raw: None,
20 }))
21 }
22 fn make_str_expr(val: &str) -> Expr {
23 Expr::Lit(Lit::Str(Str {
24 value: val.into(),
25 span: Default::default(),
26 raw: None,
27 }))
28 }
29 fn make_ident_expr(name: &str) -> Expr {
30 Expr::Ident(Ident {
31 span: Default::default(),
32 sym: name.into(),
33 optional: false,
34 ctxt: SyntaxContext::empty(),
35 })
36 }
37
38 #[test]
39 fn string_to_prop_name_with_quotes() {
40 let keys_with_quotes = vec!["2ip", "123", "1b3", "1bc", "2xl", "x*x", "x-x", "x,x"];
41
42 for key in keys_with_quotes {
43 assert!(
44 convert_string_to_prop_name(key).unwrap().is_str(),
45 "Key '{}' should be wrapped in quotes",
46 key
47 );
48 }
49 }
50
51 #[test]
52 fn string_to_prop_name_without_quotes() {
53 let keys_without_quotes = vec![
54 "_abc_",
55 "_ABC_",
56 "$123AB",
57 "$abc_",
58 "$abc$",
59 "$ABC$",
60 "$ABC123",
61 "abc_",
62 "abc",
63 "ABC",
64 "abc$",
65 "break",
66 "case",
67 "catch",
68 "class",
69 "const",
70 "continue",
71 "debugger",
72 "default",
73 "delete",
74 "do",
75 "else",
76 "export",
77 "extends",
78 "false",
79 "finally",
80 "for",
81 "function",
82 "if",
83 "import",
84 "in",
85 "instanceof",
86 "new",
87 "null",
88 "return",
89 "super",
90 "switch",
91 "this",
92 "throw",
93 "true",
94 "try",
95 "typeof",
96 "var",
97 "void",
98 "while",
99 "with",
100 "x_x",
101 "x$x",
102 "xl",
103 ];
104
105 for key in keys_without_quotes {
106 assert!(
107 convert_string_to_prop_name(key).unwrap().is_ident(),
108 "Key '{}' should not be wrapped in quotes",
109 key
110 );
111 }
112 }
113
114 #[test]
115 fn test_binary_expr_to_num_arithmetic() {
116 let mut state = EvaluationState::new();
117 let mut traversal_state = StateManager::default();
118 let fns = FunctionMap::default();
119 let left = Box::new(make_num_expr(10.0));
120 let right = Box::new(make_num_expr(2.0));
121 let ops = [
122 BinaryOp::Add,
123 BinaryOp::Sub,
124 BinaryOp::Mul,
125 BinaryOp::Div,
126 BinaryOp::Mod,
127 BinaryOp::Exp,
128 ];
129 let expected = [12.0, 8.0, 20.0, 5.0, 0.0, 100.0];
130 for (op, exp) in ops.iter().zip(expected.iter()) {
131 let bin = BinExpr {
132 op: *op,
133 left: left.clone(),
134 right: right.clone(),
135 span: Default::default(),
136 };
137 let res = binary_expr_to_num(&bin, &mut state, &mut traversal_state, &fns).unwrap();
138 match res {
139 BinaryExprType::Number(n) => assert_eq!(n, *exp),
140 _ => panic!("Expected number result"),
141 }
142 }
143 }
144
145 #[test]
146 fn test_binary_expr_to_num_comparison() {
147 let mut state = EvaluationState::new();
148 let mut traversal_state = StateManager::default();
149 let fns = FunctionMap::default();
150 let left = Box::new(make_num_expr(10.0));
151 let right = Box::new(make_num_expr(2.0));
152 let cases = [
153 (BinaryOp::Lt, 0.0),
154 (BinaryOp::LtEq, 0.0),
155 (BinaryOp::Gt, 1.0),
156 (BinaryOp::GtEq, 1.0),
157 (BinaryOp::EqEq, 0.0),
158 (BinaryOp::NotEq, 1.0),
159 (BinaryOp::EqEqEq, 0.0),
160 (BinaryOp::NotEqEq, 1.0),
161 ];
162 for (op, exp) in cases.iter() {
163 let bin = BinExpr {
164 op: *op,
165 left: left.clone(),
166 right: right.clone(),
167 span: Default::default(),
168 };
169 let res = binary_expr_to_num(&bin, &mut state, &mut traversal_state, &fns).unwrap();
170 match res {
171 BinaryExprType::Number(n) => assert_eq!(n, *exp),
172 _ => panic!("Expected number result"),
173 }
174 }
175 }
176
177 #[test]
178 fn test_binary_expr_to_num_bitwise() {
179 let mut state = EvaluationState::new();
180 let mut traversal_state = StateManager::default();
181 let fns = FunctionMap::default();
182 let left = Box::new(make_num_expr(6.0));
183 let right = Box::new(make_num_expr(3.0));
184 let cases = [
185 (BinaryOp::BitAnd, 2.0),
186 (BinaryOp::BitOr, 7.0),
187 (BinaryOp::BitXor, 5.0),
188 (BinaryOp::RShift, 0.0),
189 (BinaryOp::LShift, 48.0),
190 (BinaryOp::ZeroFillRShift, 0.0),
191 ];
192 for (op, exp) in cases.iter() {
193 let bin = BinExpr {
194 op: *op,
195 left: left.clone(),
196 right: right.clone(),
197 span: Default::default(),
198 };
199 let res = binary_expr_to_num(&bin, &mut state, &mut traversal_state, &fns).unwrap();
200 match res {
201 BinaryExprType::Number(n) => assert_eq!(n, *exp),
202 _ => panic!("Expected number result"),
203 }
204 }
205 }
206
207 #[test]
208 fn test_binary_expr_to_num_logical() {
209 let mut state = EvaluationState::new();
210 let mut traversal_state = StateManager::default();
211 let fns = FunctionMap::default();
212 let left = Box::new(make_num_expr(0.0));
213 let right = Box::new(make_num_expr(5.0));
214 let bin_or = BinExpr {
215 op: BinaryOp::LogicalOr,
216 left: left.clone(),
217 right: right.clone(),
218 span: Default::default(),
219 };
220 let res_or = binary_expr_to_num(&bin_or, &mut state, &mut traversal_state, &fns).unwrap();
221 match res_or {
222 BinaryExprType::Number(n) => assert_eq!(n, 5.0),
223 _ => panic!("Expected number result"),
224 }
225 let left = Box::new(make_num_expr(2.0));
226 let right = Box::new(make_num_expr(0.0));
227 let bin_and = BinExpr {
228 op: BinaryOp::LogicalAnd,
229 left: left.clone(),
230 right: right.clone(),
231 span: Default::default(),
232 };
233 let res_and = binary_expr_to_num(&bin_and, &mut state, &mut traversal_state, &fns).unwrap();
234 match res_and {
235 BinaryExprType::Number(n) => assert_eq!(n, 0.0),
236 _ => panic!("Expected number result"),
237 }
238 let left = Box::new(make_num_expr(0.0));
239 let right = Box::new(make_num_expr(7.0));
240 let bin_nullish = BinExpr {
241 op: BinaryOp::NullishCoalescing,
242 left: left.clone(),
243 right: right.clone(),
244 span: Default::default(),
245 };
246 let res_nullish =
247 binary_expr_to_num(&bin_nullish, &mut state, &mut traversal_state, &fns).unwrap();
248 match res_nullish {
249 BinaryExprType::Number(n) => assert_eq!(n, 7.0),
250 _ => panic!("Expected number result"),
251 }
252 }
253
254 #[test]
255 fn test_binary_expr_to_string_add() {
256 let mut state = EvaluationState::new();
257 let mut traversal_state = StateManager::default();
258 let fns = FunctionMap::default();
259 let left = Box::new(make_str_expr("foo"));
260 let right = Box::new(make_str_expr("bar"));
261 let bin = BinExpr {
262 op: BinaryOp::Add,
263 left,
264 right,
265 span: Default::default(),
266 };
267 let res = binary_expr_to_string(&bin, &mut state, &mut traversal_state, &fns).unwrap();
268 match res {
269 BinaryExprType::String(s) => assert_eq!(s, "foobar"),
270 _ => panic!("Expected string result"),
271 }
272 }
273
274 #[test]
275 #[should_panic]
276 fn test_binary_expr_to_string_non_add() {
277 let mut state = EvaluationState::new();
278 let mut traversal_state = StateManager::default();
279 let fns = FunctionMap::default();
280 let left = Box::new(make_str_expr("foo"));
281 let right = Box::new(make_str_expr("bar"));
282 let bin = BinExpr {
283 op: BinaryOp::Sub,
284 left,
285 right,
286 span: Default::default(),
287 };
288 let _ = binary_expr_to_string(&bin, &mut state, &mut traversal_state, &fns);
289 }
290
291 #[test]
292 fn test_binary_expr_to_num_in_operator() {
293 let mut state = EvaluationState::new();
294 let mut traversal_state = StateManager::default();
295 let fns = FunctionMap::default();
296 let left = Box::new(make_num_expr(10.0));
297 let right_zero = Box::new(make_num_expr(0.0));
298 let right_non_zero = Box::new(make_num_expr(1.0));
299
300 let bin_zero = BinExpr {
301 op: BinaryOp::In,
302 left: left.clone(),
303 right: right_zero,
304 span: Default::default(),
305 };
306 let res_zero = binary_expr_to_num(&bin_zero, &mut state, &mut traversal_state, &fns).unwrap();
307 match res_zero {
308 BinaryExprType::Number(n) => assert_eq!(n, 1.0),
309 _ => panic!("Expected number result"),
310 }
311
312 let bin_non_zero = BinExpr {
313 op: BinaryOp::In,
314 left,
315 right: right_non_zero,
316 span: Default::default(),
317 };
318 let res_non_zero =
319 binary_expr_to_num(&bin_non_zero, &mut state, &mut traversal_state, &fns).unwrap();
320 match res_non_zero {
321 BinaryExprType::Number(n) => assert_eq!(n, 0.0),
322 _ => panic!("Expected number result"),
323 }
324 }
325
326 #[test]
327 fn test_binary_expr_to_num_instanceof_operator() {
328 let mut state = EvaluationState::new();
329 let mut traversal_state = StateManager::default();
330 let fns = FunctionMap::default();
331 let left = Box::new(make_num_expr(10.0));
332 let right_zero = Box::new(make_num_expr(0.0));
333 let right_non_zero = Box::new(make_num_expr(2.0));
334
335 let bin_zero = BinExpr {
336 op: BinaryOp::InstanceOf,
337 left: left.clone(),
338 right: right_zero,
339 span: Default::default(),
340 };
341 let res_zero = binary_expr_to_num(&bin_zero, &mut state, &mut traversal_state, &fns).unwrap();
342 match res_zero {
343 BinaryExprType::Number(n) => assert_eq!(n, 1.0),
344 _ => panic!("Expected number result"),
345 }
346
347 let bin_non_zero = BinExpr {
348 op: BinaryOp::InstanceOf,
349 left,
350 right: right_non_zero,
351 span: Default::default(),
352 };
353 let res_non_zero =
354 binary_expr_to_num(&bin_non_zero, &mut state, &mut traversal_state, &fns).unwrap();
355 match res_non_zero {
356 BinaryExprType::Number(n) => assert_eq!(n, 0.0),
357 _ => panic!("Expected number result"),
358 }
359 }
360
361 #[test]
362 fn test_binary_expr_add_strings_returns_string() {
363 let mut state = EvaluationState::new();
364 let mut traversal_state = StateManager::default();
365 let fns = FunctionMap::default();
366 let left = Box::new(make_str_expr("foo"));
367 let right = Box::new(make_str_expr("bar"));
368 let bin = BinExpr {
369 op: BinaryOp::Add,
370 left,
371 right,
372 span: Default::default(),
373 };
374 let res = binary_expr_to_string(&bin, &mut state, &mut traversal_state, &fns).unwrap();
375 match res {
376 BinaryExprType::String(s) => assert_eq!(s, "foobar"),
377 _ => panic!("Expected string result from string addition in num evaluator"),
378 }
379 }
380
381 #[test]
382 fn test_binary_expr_to_num_left_unresolved_returns_err() {
383 let mut state = EvaluationState::new();
384 let mut traversal_state = StateManager::default();
385 let fns = FunctionMap::default();
386 let left = Box::new(make_ident_expr("x"));
387 let right = Box::new(make_num_expr(1.0));
388 let bin = BinExpr {
389 op: BinaryOp::Add,
390 left,
391 right,
392 span: Default::default(),
393 };
394 let res = binary_expr_to_num(&bin, &mut state, &mut traversal_state, &fns);
395 assert!(
396 res.is_err(),
397 "Expected error when left side is unresolved and state is not confident"
398 );
399 }
400
401 #[test]
402 fn test_binary_expr_to_num_logical_or_with_unresolved_right_returns_left() {
403 let mut state = EvaluationState::new();
404 let mut traversal_state = StateManager::default();
405 let fns = FunctionMap::default();
406 let left = Box::new(make_num_expr(3.0));
407 let right = Box::new(make_ident_expr("unknown"));
408 let bin = BinExpr {
409 op: BinaryOp::LogicalOr,
410 left,
411 right: right.clone(),
412 span: Default::default(),
413 };
414 let res = binary_expr_to_num(&bin, &mut state, &mut traversal_state, &fns).unwrap();
415
416 match res {
417 BinaryExprType::Number(n) => assert_eq!(n, 3.0),
418 _ => panic!(
419 "Expected number result equal to left operand when right is unresolved for LogicalOr"
420 ),
421 }
422
423 let left = Box::new(make_num_expr(0.0));
424
425 let bin = BinExpr {
426 op: BinaryOp::LogicalOr,
427 left,
428 right,
429 span: Default::default(),
430 };
431
432 let res = binary_expr_to_num(&bin, &mut state, &mut traversal_state, &fns);
433
434 assert!(
435 res.is_err(),
436 "Expected error when left side is unresolved and state is not confident"
437 );
438 }
439
440 #[test]
441 fn test_binary_expr_to_string_right_unresolved_returns_null_on_add() {
442 let mut state = EvaluationState::new();
443 state.confident = false;
445 let mut traversal_state = StateManager::default();
446 let fns = FunctionMap::default();
447 let left = Box::new(make_str_expr("foo"));
448 let right = Box::new(make_ident_expr("bar"));
449 let bin = BinExpr {
450 op: BinaryOp::Add,
451 left,
452 right,
453 span: Default::default(),
454 };
455 let res = binary_expr_to_string(&bin, &mut state, &mut traversal_state, &fns);
456 assert!(
457 res.is_err(),
458 "Expected error when right side is unresolved and op is Add in string evaluator"
459 );
460 }
461
462 #[test]
463 fn test_binary_expr_to_string_right_unresolved_logical_or_returns_left() {
464 let mut state = EvaluationState::new();
465 let mut traversal_state = StateManager::default();
466 let fns = FunctionMap::default();
467 let left = Box::new(make_str_expr("foo"));
468 let right = Box::new(make_ident_expr("baz"));
469 let bin = BinExpr {
470 op: BinaryOp::LogicalOr,
471 left,
472 right,
473 span: Default::default(),
474 };
475 let res = binary_expr_to_string(&bin, &mut state, &mut traversal_state, &fns).unwrap();
476 match res {
477 BinaryExprType::String(s) => assert_eq!(s, "foo"),
478 _ => panic!("Expected left string when right is unresolved and op is LogicalOr"),
479 }
480 }
481
482 #[test]
483 fn test_simple_tpl_to_string_without_expressions() {
484 use crate::shared::utils::ast::convertors::convert_tpl_to_string_lit;
485 use swc_core::ecma::ast::{Tpl, TplElement};
486
487 let tpl = Tpl {
489 span: Default::default(),
490 exprs: vec![],
491 quasis: vec![TplElement {
492 span: Default::default(),
493 tail: true,
494 cooked: Some("hello world".into()),
495 raw: "hello world".into(),
496 }],
497 };
498
499 let result = convert_tpl_to_string_lit(&tpl);
500 assert!(result.is_some(), "Should convert simple template to string");
501
502 if let Some(Lit::Str(str_lit)) = result {
503 assert_eq!(
504 str_lit.value.as_str().expect("Failed to get string Value"),
505 "hello world"
506 );
507 } else {
508 panic!("Expected Lit::Str");
509 }
510 }
511
512 #[test]
513 fn test_simple_tpl_to_string_with_expressions() {
514 use crate::shared::utils::ast::convertors::convert_tpl_to_string_lit;
515 use swc_core::ecma::ast::{Tpl, TplElement};
516
517 let tpl = Tpl {
519 span: Default::default(),
520 exprs: vec![Box::new(make_ident_expr("name"))],
521 quasis: vec![
522 TplElement {
523 span: Default::default(),
524 tail: false,
525 cooked: Some("hello ".into()),
526 raw: "hello ".into(),
527 },
528 TplElement {
529 span: Default::default(),
530 tail: true,
531 cooked: Some("".into()),
532 raw: "".into(),
533 },
534 ],
535 };
536
537 let result = convert_tpl_to_string_lit(&tpl);
538 assert!(
539 result.is_none(),
540 "Should not convert template with expressions"
541 );
542 }
543
544 #[test]
545 fn test_convert_simple_tpl_to_str_expr() {
546 use crate::shared::utils::ast::convertors::convert_simple_tpl_to_str_expr;
547 use swc_core::ecma::ast::{Tpl, TplElement};
548
549 let tpl = Tpl {
551 span: Default::default(),
552 exprs: vec![],
553 quasis: vec![TplElement {
554 span: Default::default(),
555 tail: true,
556 cooked: Some("var(--font-geist-sans), sans-serif".into()),
557 raw: "var(--font-geist-sans), sans-serif".into(),
558 }],
559 };
560
561 let expr = Expr::Tpl(tpl);
562 let result = convert_simple_tpl_to_str_expr(expr);
563
564 match result {
565 Expr::Lit(Lit::Str(str_lit)) => {
566 assert_eq!(
567 str_lit.value.as_str().expect("Failed to get string Value"),
568 "var(--font-geist-sans), sans-serif"
569 );
570 },
571 _ => panic!("Expected Expr::Lit(Lit::Str)"),
572 }
573 }
574
575 #[test]
576 fn test_convert_simple_tpl_to_str_expr_with_expressions() {
577 use crate::shared::utils::ast::convertors::convert_simple_tpl_to_str_expr;
578 use swc_core::ecma::ast::{Tpl, TplElement};
579
580 let tpl = Tpl {
582 span: Default::default(),
583 exprs: vec![Box::new(make_ident_expr("value"))],
584 quasis: vec![
585 TplElement {
586 span: Default::default(),
587 tail: false,
588 cooked: Some("prefix ".into()),
589 raw: "prefix ".into(),
590 },
591 TplElement {
592 span: Default::default(),
593 tail: true,
594 cooked: Some(" suffix".into()),
595 raw: " suffix".into(),
596 },
597 ],
598 };
599
600 let expr = Expr::Tpl(tpl.clone());
601 let result = convert_simple_tpl_to_str_expr(expr);
602
603 match result {
605 Expr::Tpl(_) => {
606 },
608 _ => panic!("Expected Expr::Tpl to remain unchanged"),
609 }
610 }
611
612 #[test]
613 fn test_convert_concat_to_tpl_expr_simple() {
614 use crate::shared::utils::ast::convertors::convert_concat_to_tpl_expr;
615 use swc_core::ecma::ast::{CallExpr, Callee, ExprOrSpread, MemberExpr, MemberProp};
616
617 let call_expr = CallExpr {
619 span: Default::default(),
620 callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
621 span: Default::default(),
622 obj: Box::new(make_str_expr("hello")),
623 prop: MemberProp::Ident(IdentName {
624 span: Default::default(),
625 sym: "concat".into(),
626 }),
627 }))),
628 args: vec![ExprOrSpread {
629 spread: None,
630 expr: Box::new(make_str_expr("world")),
631 }],
632 ..Default::default()
633 };
634
635 let expr = Expr::Call(call_expr);
636 let result = convert_concat_to_tpl_expr(expr);
637
638 match result {
640 Expr::Tpl(tpl) => {
641 assert_eq!(tpl.quasis.len(), 2, "Should have 2 quasis");
642 assert_eq!(tpl.exprs.len(), 1, "Should have 1 expression");
643 assert_eq!(
644 tpl.quasis[0]
645 .cooked
646 .as_ref()
647 .expect("Failed to get string value"),
648 "hello",
649 "First quasi should be 'hello'"
650 );
651 },
652 _ => panic!("Expected Expr::Tpl"),
653 }
654 }
655
656 #[test]
657 fn test_convert_concat_to_tpl_expr_multiple_args() {
658 use crate::shared::utils::ast::convertors::convert_concat_to_tpl_expr;
659 use swc_core::ecma::ast::{CallExpr, Callee, ExprOrSpread, MemberExpr, MemberProp};
660
661 let call_expr = CallExpr {
663 span: Default::default(),
664 callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
665 span: Default::default(),
666 obj: Box::new(make_str_expr("prefix")),
667 prop: MemberProp::Ident(IdentName {
668 span: Default::default(),
669 sym: "concat".into(),
670 }),
671 }))),
672 args: vec![
673 ExprOrSpread {
674 spread: None,
675 expr: Box::new(make_ident_expr("var1")),
676 },
677 ExprOrSpread {
678 spread: None,
679 expr: Box::new(make_ident_expr("var2")),
680 },
681 ExprOrSpread {
682 spread: None,
683 expr: Box::new(make_ident_expr("var3")),
684 },
685 ],
686 ..Default::default()
687 };
688
689 let expr = Expr::Call(call_expr);
690 let result = convert_concat_to_tpl_expr(expr);
691
692 match result {
694 Expr::Tpl(tpl) => {
695 assert_eq!(tpl.quasis.len(), 4, "Should have 4 quasis");
696 assert_eq!(tpl.exprs.len(), 3, "Should have 3 expressions");
697 assert_eq!(
698 tpl.quasis[0]
699 .cooked
700 .as_ref()
701 .expect("Failed to get cooked value"),
702 "prefix",
703 "First quasi should be 'prefix'"
704 );
705 assert!(tpl.quasis[3].tail, "Last quasi should have tail=true");
706 },
707 _ => panic!("Expected Expr::Tpl"),
708 }
709 }
710
711 #[test]
712 fn test_convert_concat_to_tpl_expr_not_concat_method() {
713 use crate::shared::utils::ast::convertors::convert_concat_to_tpl_expr;
714 use swc_core::ecma::ast::{CallExpr, Callee, ExprOrSpread, MemberExpr, MemberProp};
715
716 let call_expr = CallExpr {
718 span: Default::default(),
719 callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
720 span: Default::default(),
721 obj: Box::new(make_str_expr("hello")),
722 prop: MemberProp::Ident(IdentName {
723 span: Default::default(),
724 sym: "split".into(), }),
726 }))),
727 args: vec![ExprOrSpread {
728 spread: None,
729 expr: Box::new(make_str_expr("world")),
730 }],
731 ..Default::default()
732 };
733
734 let original_expr = Expr::Call(call_expr.clone());
735 let result = convert_concat_to_tpl_expr(original_expr);
736
737 match result {
739 Expr::Call(_) => {
740 },
742 _ => panic!("Expected Expr::Call to remain unchanged"),
743 }
744 }
745
746 #[test]
747 fn test_convert_concat_to_tpl_expr_non_call_expr() {
748 use crate::shared::utils::ast::convertors::convert_concat_to_tpl_expr;
749
750 let expr = make_str_expr("hello");
752 let result = convert_concat_to_tpl_expr(expr);
753
754 match result {
756 Expr::Lit(Lit::Str(str_lit)) => {
757 assert_eq!(
758 str_lit.value.as_str().expect("Failed to get string value"),
759 "hello"
760 );
761 },
762 _ => panic!("Expected Expr::Lit(Lit::Str) to remain unchanged"),
763 }
764 }
765
766 #[test]
767 fn test_convert_concat_to_tpl_expr_with_spread() {
768 use crate::shared::utils::ast::convertors::convert_concat_to_tpl_expr;
769 use swc_core::ecma::ast::{CallExpr, Callee, ExprOrSpread, MemberExpr, MemberProp};
770
771 let call_expr = CallExpr {
773 span: Default::default(),
774 callee: Callee::Expr(Box::new(Expr::Member(MemberExpr {
775 span: Default::default(),
776 obj: Box::new(make_str_expr("prefix")),
777 prop: MemberProp::Ident(IdentName {
778 span: Default::default(),
779 sym: "concat".into(),
780 }),
781 }))),
782 args: vec![ExprOrSpread {
783 spread: Some(Default::default()),
784 expr: Box::new(make_ident_expr("args")),
785 }],
786 ..Default::default()
787 };
788
789 let expr = Expr::Call(call_expr);
790 let result = convert_concat_to_tpl_expr(expr);
791
792 match result {
794 Expr::Tpl(tpl) => {
795 assert_eq!(
796 tpl.quasis.len(),
797 1,
798 "Should have 1 quasi (spread args are skipped)"
799 );
800 assert_eq!(
801 tpl.exprs.len(),
802 0,
803 "Should have 0 expressions (spread args are skipped)"
804 );
805 },
806 _ => panic!("Expected Expr::Tpl"),
807 }
808 }
809}