dbg_swc/util/
mod.rs

1use std::{
2    io::Write,
3    path::{Path, PathBuf},
4    process::{Child, Command, Stdio},
5    sync::Arc,
6};
7
8use anyhow::{bail, Context, Result};
9use flate2::{write::ZlibEncoder, Compression};
10use swc_common::{comments::SingleThreadedComments, errors::HANDLER, Mark, SourceFile, SourceMap};
11use swc_ecma_ast::{EsVersion, Module};
12use swc_ecma_codegen::text_writer::{omit_trailing_semi, JsWriter, WriteJs};
13use swc_ecma_parser::{parse_file_as_module, Syntax};
14use swc_ecma_transforms_base::resolver;
15use swc_ecma_visit::VisitMutWith;
16
17pub mod minifier;
18
19/// Type annotation
20pub fn wrap_task<T, F>(op: F) -> Result<T>
21where
22    F: FnOnce() -> Result<T>,
23{
24    op()
25}
26
27pub fn gzipped_size(code: &str) -> usize {
28    let mut e = ZlibEncoder::new(Vec::new(), Compression::new(9));
29    e.write_all(code.as_bytes()).unwrap();
30    let compressed_bytes = e.finish().unwrap();
31    compressed_bytes.len()
32}
33
34pub fn make_pretty(f: &Path) -> Result<()> {
35    let mut c = Command::new("npx");
36    c.stderr(Stdio::inherit());
37    c.arg("js-beautify").arg("--replace").arg(f);
38
39    let output = c.output().context("failed to run prettier")?;
40
41    if !output.status.success() {
42        bail!("prettier failed");
43    }
44
45    Ok(())
46}
47
48pub fn parse_js(fm: Arc<SourceFile>) -> Result<ModuleRecord> {
49    let unresolved_mark = Mark::new();
50    let top_level_mark = Mark::new();
51
52    let mut errors = Vec::new();
53    let comments = SingleThreadedComments::default();
54    let res = parse_file_as_module(
55        &fm,
56        Syntax::Es(Default::default()),
57        EsVersion::latest(),
58        Some(&comments),
59        &mut errors,
60    )
61    .map_err(|err| HANDLER.with(|handler| err.into_diagnostic(handler).emit()));
62
63    for err in errors {
64        HANDLER.with(|handler| err.into_diagnostic(handler).emit());
65    }
66
67    let mut m = match res {
68        Ok(v) => v,
69        Err(()) => bail!("failed to parse a js file as a module"),
70    };
71
72    m.visit_mut_with(&mut resolver(unresolved_mark, top_level_mark, false));
73
74    Ok(ModuleRecord {
75        module: m,
76        comments,
77        top_level_mark,
78        unresolved_mark,
79    })
80}
81
82pub fn print_js(cm: Arc<SourceMap>, m: &Module, minify: bool) -> Result<String> {
83    let mut buf = Vec::new();
84
85    {
86        let mut wr = Box::new(JsWriter::new(cm.clone(), "\n", &mut buf, None)) as Box<dyn WriteJs>;
87        if minify {
88            wr = Box::new(omit_trailing_semi(wr));
89        }
90
91        let mut e = swc_ecma_codegen::Emitter {
92            cfg: swc_ecma_codegen::Config::default().with_minify(true),
93            cm,
94            comments: None,
95            wr,
96        };
97
98        e.emit_module(m).unwrap();
99    }
100
101    String::from_utf8(buf).context("swc emitted non-utf8 output")
102}
103
104#[derive(Debug, Clone)]
105pub struct ModuleRecord {
106    pub module: Module,
107    pub comments: SingleThreadedComments,
108    pub top_level_mark: Mark,
109    pub unresolved_mark: Mark,
110}
111
112pub fn all_js_files(path: &Path) -> Result<Vec<PathBuf>> {
113    wrap_task(|| {
114        if path.is_dir() {
115            let mut files = Vec::new();
116            for entry in path.read_dir().context("failed to read dir")? {
117                let entry = entry.context("read_dir returned an error")?;
118                let path = entry.path();
119                files.extend(all_js_files(&path)?);
120            }
121            Ok(files)
122        } else if path.extension() == Some("js".as_ref()) {
123            Ok(vec![path.to_path_buf()])
124        } else {
125            Ok(Vec::new())
126        }
127    })
128    .with_context(|| format!("failed to get list of `.js` files in {}", path.display()))
129}
130
131pub(crate) struct ChildGuard(pub Child);
132
133impl Drop for ChildGuard {
134    fn drop(&mut self) {
135        if let Err(e) = self.0.kill() {
136            eprintln!("Could not kill child process: {e}")
137        }
138    }
139}