styled_components/utils/
analyzer.rs1use swc_ecma_ast::*;
2use swc_ecma_visit::{noop_visit_type, visit_pass, Visit, VisitWith};
3
4use super::State;
5use crate::Config;
6
7pub fn analyzer<'a>(config: &'a Config, state: &'a mut State) -> impl 'a + Pass {
8 visit_pass(Analyzer { config, state })
9}
10
11pub fn analyze(config: &Config, program: &Program) -> State {
12 let mut state = State::default();
13
14 let mut v = Analyzer {
15 config,
16 state: &mut state,
17 };
18
19 program.visit_with(&mut v);
20
21 state
22}
23
24struct Analyzer<'a> {
25 config: &'a Config,
26 state: &'a mut State,
27}
28
29impl Visit for Analyzer<'_> {
30 noop_visit_type!(fail);
31
32 fn visit_var_declarator(&mut self, v: &VarDeclarator) {
33 v.visit_children_with(self);
34
35 if let (
36 Pat::Ident(name),
37 Some(Expr::Call(CallExpr {
38 callee: Callee::Expr(callee),
39 args,
40 ..
41 })),
42 ) = (&v.name, v.init.as_deref())
43 {
44 if let Expr::Ident(callee) = &**callee {
45 if &*callee.sym == "require" && args.len() == 1 && args[0].spread.is_none() {
46 if let Expr::Lit(Lit::Str(v)) = &*args[0].expr {
47 let is_styled = if self.config.top_level_import_paths.is_empty() {
48 &*v.value == "styled-components"
49 || v.value.starts_with("styled-components/")
50 } else {
51 self.config.top_level_import_paths.contains(&v.value)
52 };
53
54 if is_styled {
55 self.state.styled_required = Some(name.id.to_id());
56 self.state.unresolved_ctxt = Some(callee.ctxt);
57 }
58 }
59 }
60 }
61 }
62 }
63
64 fn visit_import_decl(&mut self, i: &ImportDecl) {
65 let is_styled = if self.config.top_level_import_paths.is_empty() {
66 &*i.src.value == "styled-components" || i.src.value.starts_with("styled-components/")
67 } else {
68 self.config.top_level_import_paths.contains(&i.src.value)
69 };
70
71 if is_styled {
72 for s in &i.specifiers {
73 match s {
74 ImportSpecifier::Named(s) => {
75 let imported = s
76 .imported
77 .as_ref()
78 .map(|v| match v {
79 ModuleExportName::Ident(v) => &*v.sym,
80 ModuleExportName::Str(v) => &*v.value,
81 })
82 .unwrap_or(&*s.local.sym);
83 self.state
84 .imported_local_named
85 .insert(imported.to_string(), s.local.to_id());
86 }
87 ImportSpecifier::Default(s) => {
88 self.state.imported_local_name = Some(s.local.to_id());
89 }
90 ImportSpecifier::Namespace(s) => {
91 self.state.imported_local_ns = Some(s.local.to_id());
92 }
93 }
94 }
95 }
96 }
97}