use std::path::{Path, PathBuf};
use anyhow::{bail, Result};
use serde_json::Value;
pub(crate) fn project_dir(project_root: &Path, manifest: &Value) -> PathBuf {
let canonical = project_root.join("ui");
if canonical.join("package.json").is_file() {
return canonical;
}
manifest
.get("ui_path")
.and_then(Value::as_str)
.and_then(|path| path.strip_suffix("/dist"))
.map(|path| project_root.join(path))
.unwrap_or(canonical)
}
pub(crate) fn destination_relative(manifest: &Value) -> PathBuf {
manifest
.get("ui_path")
.and_then(Value::as_str)
.map(PathBuf::from)
.unwrap_or_else(|| PathBuf::from("ui/dist"))
}
pub(crate) fn source_dir(project_root: &Path, manifest: &Value) -> Result<PathBuf> {
let declared = project_root.join(destination_relative(manifest));
if declared.is_dir() {
return Ok(declared);
}
let canonical = project_root.join("ui/dist");
if canonical.is_dir() {
return Ok(canonical);
}
bail!(
"UI build produced no bundle; checked declared path {} and canonical path {}",
declared.display(),
canonical.display()
)
}
#[cfg(test)]
mod tests {
use std::path::PathBuf;
use super::*;
#[test]
fn legacy_dist_destination_uses_ui_dist_source() {
let project = tempfile::tempdir().unwrap();
std::fs::create_dir_all(project.path().join("ui/dist")).unwrap();
let manifest = serde_json::json!({"has_ui": true, "ui_path": "dist"});
assert_eq!(
source_dir(project.path(), &manifest).unwrap(),
project.path().join("ui/dist")
);
assert_eq!(destination_relative(&manifest), PathBuf::from("dist"));
}
#[test]
fn declared_source_wins_when_it_exists() {
let project = tempfile::tempdir().unwrap();
std::fs::create_dir_all(project.path().join("custom-ui")).unwrap();
std::fs::create_dir_all(project.path().join("ui/dist")).unwrap();
let manifest = serde_json::json!({"has_ui": true, "ui_path": "custom-ui"});
assert_eq!(
source_dir(project.path(), &manifest).unwrap(),
project.path().join("custom-ui")
);
}
#[test]
fn missing_source_reports_declared_and_canonical_paths() {
let project = tempfile::tempdir().unwrap();
let manifest = serde_json::json!({"has_ui": true, "ui_path": "dist"});
let error = source_dir(project.path(), &manifest)
.unwrap_err()
.to_string();
assert!(error.contains(&project.path().join("dist").display().to_string()));
assert!(error.contains(&project.path().join("ui/dist").display().to_string()));
}
}