#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VfsEntry {
pub path: String,
pub bytes: Vec<u8>,
}
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)]
mod tests {
use super::{VfsEntry, normalize_import_path};
#[derive(Debug, Clone, Default, PartialEq, Eq)]
struct Vfs {
entries: Vec<VfsEntry>,
}
impl Vfs {
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(())
}
}
fn is_system_path(path: &str) -> bool {
path.split('/').any(|part| part == "__MACOSX" || part == ".DS_Store")
}
#[test]
fn rejects_parent_segments() {
let mut vfs = Vfs::default();
let result = vfs.insert("../escape.md", b"bad".to_vec());
assert!(matches!(result, Err(crate::ImportError::InvalidSource(_))));
}
}