use std::{
io::{Error as IoError, ErrorKind},
path::Path,
process::Command,
};
use crate::config::model::RawVizeConfig;
pub(super) fn parse_js_config(path: &Path) -> Result<RawVizeConfig, Box<dyn std::error::Error>> {
let config_path = if path.is_absolute() {
path.to_path_buf()
} else {
std::env::current_dir()?.join(path)
};
let config_path = config_path.canonicalize().unwrap_or(config_path);
let script = r#"
import { pathToFileURL } from "node:url";
const configPath = process.argv[1];
const module = await import(pathToFileURL(configPath).href);
const exported = module.default ?? module;
const config = typeof exported === "function"
? await exported({ mode: "development", command: "serve" })
: exported;
process.stdout.write(JSON.stringify(config ?? {}));
"#;
let output = Command::new("node")
.arg("--input-type=module")
.arg("-e")
.arg(script)
.arg(&config_path)
.current_dir(config_path.parent().unwrap_or_else(|| Path::new(".")))
.output()?;
if !output.status.success() {
let stderr = String::from_utf8_lossy(&output.stderr);
return Err(Box::new(IoError::new(
ErrorKind::InvalidData,
crate::cstr!("node failed to load config: {}", stderr.trim()).to_string(),
)));
}
Ok(serde_json::from_slice::<RawVizeConfig>(&output.stdout)?)
}