#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VfsEntry {
pub path: String,
pub bytes: Vec<u8>,
}
#[cfg(test)]
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Vfs {
entries: Vec<VfsEntry>,
}
#[cfg(test)]
impl Vfs {
pub fn insert(&mut self, path: impl Into<String>, bytes: Vec<u8>) -> crate::ImportResult<()> {
let path = normalize_import_path(&path.into());
if path.is_empty() {
return Err(crate::ImportError::InvalidSource("empty path".to_string()));
}
if path.split('/').any(|part| part == "..") {
return Err(crate::ImportError::InvalidSource(format!(
"path escapes import root: {path}"
)));
}
if is_system_path(&path) {
return Ok(());
}
self.entries.push(VfsEntry { path, bytes });
Ok(())
}
}
pub fn normalize_import_path(path: &str) -> String {
let mut parts = Vec::new();
let path = path.replace('\\', "/");
for part in path.split('/') {
if part.is_empty() || part == "." {
continue;
}
if part == ".." {
if parts.last().is_some_and(|part| *part != "..") {
parts.pop();
} else {
parts.push(part);
}
continue;
}
parts.push(part);
}
parts.join("/")
}
#[cfg(test)]
fn is_system_path(path: &str) -> bool {
path.split('/').any(|part| part == "__MACOSX" || part == ".DS_Store")
}