use std::path::PathBuf;
use zenith_session::DocMeta;
use super::resources::open_store;
use crate::history::{ensure_doc_id_in, read_doc_id};
pub struct Located {
pub path: PathBuf,
pub doc_id: Option<String>,
}
pub fn locate(reference: &str) -> Result<Located, String> {
if is_ulid(reference) {
let meta = read_meta(reference)?;
Ok(Located {
path: PathBuf::from(meta.path),
doc_id: Some(meta.doc_id),
})
} else {
let path = PathBuf::from(reference);
let doc_id = read_doc_id(&path).ok();
Ok(Located { path, doc_id })
}
}
pub fn ensure(reference: &str) -> Result<(PathBuf, String), String> {
if is_ulid(reference) {
let meta = read_meta(reference)?;
return Ok((PathBuf::from(meta.path), meta.doc_id));
}
let path = PathBuf::from(reference);
let paths = open_store()?;
let ensured = ensure_doc_id_in(&paths, &path)?;
Ok((path, ensured.doc_id))
}
fn read_meta(doc_id: &str) -> Result<DocMeta, String> {
let paths = open_store()?;
let meta_path = paths.meta_file(doc_id);
let bytes = std::fs::read(&meta_path)
.map_err(|_| format!("unknown doc-id '{doc_id}' (no local history on this machine)"))?;
serde_json::from_slice(&bytes).map_err(|e| format!("corrupt meta for '{doc_id}': {e}"))
}
fn is_ulid(s: &str) -> bool {
s.len() == 26 && s.bytes().all(is_crockford)
}
fn is_crockford(b: u8) -> bool {
b.is_ascii_digit()
|| matches!(b, b'A'..=b'H' | b'J' | b'K' | b'M' | b'N' | b'P'..=b'T' | b'V'..=b'Z')
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn ulid_shape_is_detected() {
assert!(is_ulid("01ARZ3NDEKTSV4RRFFQ69G5FAV"));
assert!(is_ulid("01BX5ZZKBKACTAV9WEVGEMMVRZ"));
}
#[test]
fn paths_are_not_ulids() {
assert!(!is_ulid("/tmp/poster.zen"));
assert!(!is_ulid("poster.zen"));
assert!(!is_ulid("01ARZ3NDEKTSV4RRFFQ69G5FAi"));
assert!(!is_ulid("01ARZ3NDEKTSV4RRFFQ69G5FAL"));
}
}