magi-code 0.77.1

Repository-aware CLI coding agent for terminal work
Documentation
use std::path::{Component, Path, PathBuf};

pub(crate) fn lexical_normalize(path: &Path) -> PathBuf {
    let mut normalized = PathBuf::new();
    for component in path.components() {
        match component {
            Component::CurDir => {}
            Component::ParentDir => {
                normalized.pop();
            }
            other => normalized.push(other.as_os_str()),
        }
    }
    normalized
}

#[cfg(test)]
mod tests {
    use super::lexical_normalize;
    use std::path::{Path, PathBuf};

    #[test]
    fn normalizes_absolute_path() {
        let root = Path::new(std::path::MAIN_SEPARATOR_STR);
        let path = root
            .join("alpha")
            .join(".")
            .join("beta")
            .join("..")
            .join("gamma");
        assert_eq!(lexical_normalize(&path), root.join("alpha").join("gamma"));
    }

    #[test]
    fn clamps_relative_parent_traversal() {
        assert_eq!(
            lexical_normalize(Path::new("../../alpha/../beta")),
            PathBuf::from("beta")
        );
    }

    #[test]
    fn clamps_rooted_parent_traversal_at_root() {
        let root = Path::new(std::path::MAIN_SEPARATOR_STR);
        assert_eq!(lexical_normalize(&root.join("..")), root.to_path_buf());
        assert_eq!(
            lexical_normalize(&root.join("alpha").join("..").join("..")),
            root.to_path_buf()
        );
    }

    #[test]
    fn removes_dots_without_changing_components() {
        assert_eq!(
            lexical_normalize(Path::new("./alpha/./beta")),
            PathBuf::from("alpha/beta")
        );
    }

    #[test]
    fn preserves_normal_components() {
        let path = Path::new("alpha").join("with space").join("café");
        assert_eq!(lexical_normalize(&path), path);
    }
}