use super::PackageArtifact;
use alef_core::config::ResolvedCrateConfig;
use anyhow::{Context, Result};
use std::fs;
use std::path::{Path, PathBuf};
pub fn package_wasm(
config: &ResolvedCrateConfig,
workspace_root: &Path,
output_dir: &Path,
_version: &str,
) -> Result<PackageArtifact> {
let wasm_crate = crate::crate_name_from_output(config, alef_core::config::extras::Language::Wasm)
.unwrap_or_else(|| format!("{}-wasm", config.name));
let crate_dir = workspace_root.join("crates").join(&wasm_crate);
let build_cmd = format!("wasm-pack build {} --release --target bundler", crate_dir.display());
crate::run_shell_command_in(&build_cmd, workspace_root)?;
let pkg_dir = crate_dir.join("pkg");
if !pkg_dir.exists() {
anyhow::bail!(
"wasm-pack build did not produce pkg/ directory at {}",
pkg_dir.display()
);
}
crate::run_shell_command_in("npm pack", &pkg_dir)?;
let tgz_path = find_tgz(&pkg_dir).context("npm pack: no .tgz found in pkg/")?;
let file_name = tgz_path
.file_name()
.context("tgz has no filename")?
.to_string_lossy()
.to_string();
let dest = output_dir.join(&file_name);
fs::copy(&tgz_path, &dest).with_context(|| format!("copying {} to {}", tgz_path.display(), dest.display()))?;
Ok(PackageArtifact {
path: dest,
name: file_name,
checksum: None,
})
}
fn find_tgz(dir: &Path) -> Result<PathBuf> {
let mut candidates: Vec<PathBuf> = fs::read_dir(dir)?
.filter_map(|e| e.ok())
.map(|e| e.path())
.filter(|p| p.extension().is_some_and(|e| e == "tgz"))
.collect();
candidates.sort_by_key(|p| {
fs::metadata(p)
.and_then(|m| m.modified())
.unwrap_or(std::time::SystemTime::UNIX_EPOCH)
});
candidates
.into_iter()
.next_back()
.with_context(|| format!("no .tgz found in {}", dir.display()))
}
#[cfg(test)]
mod tests {
use super::*;
use std::fs;
use tempfile::TempDir;
#[test]
fn find_tgz_returns_latest() {
let tmp = TempDir::new().unwrap();
fs::write(tmp.path().join("a.tgz"), b"a").unwrap();
fs::write(tmp.path().join("b.tgz"), b"b").unwrap();
let result = find_tgz(tmp.path()).unwrap();
assert!(result.extension().unwrap() == "tgz");
}
#[test]
fn find_tgz_empty_dir_errors() {
let tmp = TempDir::new().unwrap();
let result = find_tgz(tmp.path());
assert!(result.is_err());
}
}