dbg_swc/es/
exec_test.rs

1use std::{
2    fs,
3    path::{Path, PathBuf},
4    process::{Command, Stdio},
5    sync::Arc,
6};
7
8use anyhow::{bail, Context, Result};
9use clap::{Args, Subcommand};
10use swc_common::SourceMap;
11use swc_ecma_minifier::option::MinifyOptions;
12use swc_ecma_transforms_base::fixer::fixer;
13use swc_ecma_visit::VisitMutWith;
14use swc_timer::timer;
15use tracing::info;
16
17use crate::{bundle::bundle, util::print_js};
18
19/// [Experimental] Execute a javascript file after performing some
20/// preprocessing.
21#[derive(Debug, Subcommand)]
22pub enum ExecForTestingCommand {
23    MinifiedBundle(TestMinifiedBundleCommand),
24}
25
26impl ExecForTestingCommand {
27    pub fn run(self, cm: Arc<SourceMap>) -> Result<()> {
28        let _timer = timer!("test");
29
30        let output = {
31            let _timer = timer!("process");
32
33            match self {
34                ExecForTestingCommand::MinifiedBundle(cmd) => cmd.run(cm),
35            }?
36        };
37
38        {
39            let _timer = timer!("run");
40            let stdout = output
41                .runtime
42                .execute(&output.path)
43                .context("failed to execute generated code")?;
44
45            info!("----- Stdout -----\n{}", stdout);
46        }
47
48        Ok(())
49    }
50}
51
52#[derive(Debug, Args)]
53pub struct TestMinifiedBundleCommand {
54    entry: String,
55}
56
57impl TestMinifiedBundleCommand {
58    fn run(self, cm: Arc<SourceMap>) -> Result<Output> {
59        let bundle = bundle(cm.clone(), &self.entry)?;
60
61        let mut minified = {
62            let _timer = timer!("minify");
63            swc_ecma_minifier::optimize(
64                bundle.module.into(),
65                cm.clone(),
66                None,
67                None,
68                &MinifyOptions {
69                    compress: Some(Default::default()),
70                    mangle: Some(Default::default()),
71                    ..Default::default()
72                },
73                &swc_ecma_minifier::option::ExtraOptions {
74                    unresolved_mark: bundle.unresolved_mark,
75                    top_level_mark: bundle.top_level_mark,
76                    mangle_name_cache: None,
77                },
78            )
79            .expect_module()
80        };
81
82        minified.visit_mut_with(&mut fixer(None));
83
84        let code = print_js(cm, &minified, true).context("failed to convert ast to code")?;
85
86        let path = Path::new("output.js").to_path_buf();
87        fs::write(&path, code.as_bytes()).context("failed to write code as file")?;
88
89        Ok(Output {
90            path,
91            runtime: JsRuntime::Deno,
92        })
93    }
94}
95
96pub struct Output {
97    pub path: PathBuf,
98    pub runtime: JsRuntime,
99}
100
101pub enum JsRuntime {
102    // Node,
103    Deno,
104}
105
106impl JsRuntime {
107    pub fn execute(&self, path: &Path) -> Result<String> {
108        match self {
109            // JsRuntime::Node => todo!("node.execute"),
110            JsRuntime::Deno => {
111                let mut cmd = Command::new("deno");
112                cmd.arg("run").arg("--no-check");
113
114                cmd.arg(path);
115
116                cmd.stderr(Stdio::inherit());
117
118                let output = cmd.output().context("failed to get output from deno")?;
119
120                if !output.status.success() {
121                    bail!("deno exited with status {}", output.status);
122                }
123
124                Ok(
125                    (String::from_utf8(output.stdout).context("deno emitted non-utf8 string")?)
126                        .trim()
127                        .to_string(),
128                )
129            }
130        }
131    }
132}