1use std::env::current_dir;
2use std::path::PathBuf;
3use std::process::Command;
4
5use bon::Builder;
6
7#[cfg_attr(docsrs, doc(cfg(feature = "compile")))]
8#[derive(Builder)]
9pub struct BunTsCompile {
10 src_files: Vec<PathBuf>,
12 output_dir: PathBuf,
14 output_file: Option<String>,
16 #[builder(default = true)]
17 minify: bool,
18 extra_flags: Option<Vec<String>>,
20 #[builder(default = false)]
24 skip_if_no_bun: bool,
25}
26
27impl BunTsCompile {
28 pub fn run(&self) {
29 fn bun_exists() -> bool {
30 Command::new("bun")
31 .arg("--version")
32 .output()
33 .map(|o| o.status.success())
34 .unwrap_or(false)
35 }
36 if self.skip_if_no_bun && !bun_exists() {
37 println!("cargo:warning=Bun does not exist and configuration allows this, skipping bun build.");
38 return;
39 }
40
41 let src_files = self
42 .src_files
43 .iter()
44 .map(|e| {
45 e.to_str()
46 .expect("a src file is not a valid utf-8 string")
47 .to_owned()
48 })
49 .collect::<Vec<_>>();
50 let output_dir = self
51 .output_dir
52 .to_str()
53 .expect("The output file is not a valid utf-8 string")
54 .to_owned();
55
56 let mut args = Vec::new();
57 args.push("build".to_owned());
58 args.extend(src_files);
59
60 if let Some(output_file) = &self.output_file {
61 args.extend([
62 "--compile".to_owned(),
63 "--outfile".to_owned(),
64 self.output_dir
65 .join(output_file)
66 .to_str()
67 .unwrap()
68 .to_owned(),
69 ])
70 } else {
71 args.extend(["--outdir".to_owned(), output_dir]);
72 }
73 if self.minify {
74 args.extend([
75 "--minify-syntax".to_owned(),
76 "--minify-whitespace".to_owned(),
77 ]);
80 }
81 args.push("--target=browser".to_owned());
82 args.extend(self.extra_flags.iter().flatten().cloned());
83
84 let output = Command::new("bun")
86 .args(&args)
87 .output()
88 .expect("Failed to execute bun build");
89 if !output.status.success() {
90 panic!(
91 "bun build failed.\nArgs: `{}`\nCurrent Directory: `{}`\nStderr:\n{}",
92 args.join(" "),
93 current_dir().unwrap().display(),
94 String::from_utf8_lossy(&output.stderr)
95 );
96 }
97 }
98}