css_knife/
visit_map.rs

1use crate::visit_selectors::ClassVisitor;
2
3use swc_core::{
4    common::{sync::Lrc, FileName, SourceMap},
5    ecma::codegen::{text_writer::JsWriter, Emitter},
6    ecma::{
7        parser::{lexer::Lexer, Parser, StringInput},
8        visit::{as_folder, FoldWith, VisitMut},
9    },
10};
11
12pub fn check_js(
13    old_content: &String,
14    class_visitor: &ClassVisitor,
15) -> Option<Vec<u8>> {
16    let map_visitor = MapVisitor::new(class_visitor);
17    let cm: Lrc<SourceMap> = Default::default();
18    let fm = cm.new_source_file(
19        FileName::Custom("test.js".into()),
20        old_content.into(),
21    );
22    let lexer = Lexer::new(
23        swc_core::ecma::parser::Syntax::Es(Default::default()),
24        Default::default(),
25        StringInput::from(&*fm),
26        None,
27    );
28    let mut parser = Parser::new_from(lexer);
29    let s = parser.parse_program();
30    let mut code = vec![];
31    let mut srcmap = vec![];
32
33    match s {
34        Ok(program) => {
35            let program = program.fold_with(&mut as_folder(map_visitor));
36
37            {
38                let mut emitter = Emitter {
39                    cfg: Default::default(),
40                    cm: cm.clone(),
41                    comments: None,
42                    wr: JsWriter::new(
43                        cm.clone(),
44                        "\n",
45                        &mut code,
46                        Some(&mut srcmap),
47                    ),
48                };
49                if let Some(module) = program.as_script() {
50                    if emitter.emit_script(module).is_ok() {
51                        return Some(code);
52                    }
53                }
54                None
55            }
56        }
57        Err(_) => None,
58    }
59}
60
61pub struct MapVisitor<'a> {
62    pub is_set: bool,
63    pub first_string: Option<String>,
64    pub class_visitor: &'a ClassVisitor,
65}
66
67impl<'a> MapVisitor<'a> {
68    fn new(class_visitor: &'a ClassVisitor) -> Self {
69        Self {
70            is_set: false,
71            first_string: None,
72            class_visitor,
73        }
74    }
75}
76
77impl<'a> VisitMut for MapVisitor<'a> {
78    fn visit_mut_ident(&mut self, n: &mut swc_core::ecma::ast::Ident) {
79        let s = n.to_string();
80        if s.starts_with("set") {
81            self.is_set = true;
82        } else {
83            self.is_set = false;
84            self.first_string = None;
85        }
86    }
87
88    fn visit_mut_str(&mut self, n: &mut swc_core::ecma::ast::Str) {
89        if self.is_set {
90            match &self.first_string {
91                Some(s) => {
92                    let new_str = &self.class_visitor.get(s);
93                    if let Some(new_str) = new_str {
94                        let new_str = format!("'{}'", new_str);
95                        n.raw = Some(new_str.into());
96                    }
97                    self.is_set = false;
98                    self.first_string = None;
99                }
100                None => {
101                    self.is_set = true;
102                    self.first_string = Some(n.value.to_string());
103                }
104            }
105        }
106    }
107}