use std::path::{Path, PathBuf};
use crate::error::ConversionError;
use crate::format::InputFormat;
#[derive(Debug, Clone)]
pub struct SourceDocument {
pub name: String,
pub format: InputFormat,
pub bytes: Vec<u8>,
pub path: Option<PathBuf>,
pub base_url: Option<String>,
}
impl SourceDocument {
pub fn from_file(path: impl AsRef<Path>) -> Result<Self, ConversionError> {
let path = path.as_ref();
let ext = path.extension().and_then(|e| e.to_str()).ok_or_else(|| {
ConversionError::UnknownFormat {
hint: format!("no extension on {}", path.display()),
}
})?;
let format =
InputFormat::from_extension(ext).ok_or_else(|| ConversionError::UnknownFormat {
hint: format!("unrecognized extension '.{ext}'"),
})?;
let bytes = std::fs::read(path)?;
let name = path
.file_stem()
.and_then(|s| s.to_str())
.unwrap_or("document")
.to_string();
Ok(Self {
name,
format,
bytes,
path: Some(path.to_path_buf()),
base_url: None,
})
}
pub fn from_bytes(name: impl Into<String>, format: InputFormat, bytes: Vec<u8>) -> Self {
Self {
name: name.into(),
format,
bytes,
path: None,
base_url: None,
}
}
pub fn with_base_url(mut self, url: impl Into<String>) -> Self {
self.base_url = Some(url.into());
self
}
pub fn base_dir(&self) -> Option<&Path> {
self.path.as_deref().and_then(Path::parent)
}
pub fn text(&self) -> Result<&str, ConversionError> {
std::str::from_utf8(&self.bytes)
.map_err(|e| ConversionError::Parse(format!("input is not valid UTF-8: {e}")))
}
}