next.js/turbopack/crates/turbo-tasks-fs/src/util.rs
util.rs67 lines2.2 KB
use std::{
    io::{self, ErrorKind},
    path::{Path, PathBuf},
};

use anyhow::{Context, Result, anyhow};
use turbo_tasks::ResolvedVc;

use crate::{DiskFileSystem, FileSystemPath};

/// Converts a disk access `Result<T>` into a `Result<Some<T>>`, where a [`ErrorKind::NotFound`] (or
/// [`ErrorKind::InvalidFilename`]) error results in a [`None`] value. This is purely to reduce
/// boilerplate code comparing [`ErrorKind::NotFound`] errors against all other errors.
pub fn extract_disk_access<T>(value: io::Result<T>, path: &Path) -> Result<Option<T>> {
    match value {
        Ok(v) => Ok(Some(v)),
        Err(e) if matches!(e.kind(), ErrorKind::NotFound | ErrorKind::InvalidFilename) => Ok(None),
        // ast-grep-ignore: no-context-format
        Err(e) => Err(anyhow!(e).context(format!("reading file {}", path.display()))),
    }
}

pub async fn uri_from_file(root: FileSystemPath, path: Option<&str>) -> Result<String> {
    let root_fs = root.fs;
    let root_fs = &*ResolvedVc::try_downcast_type::<DiskFileSystem>(root_fs)
        .context("Expected root to have a DiskFileSystem")?
        .await?;

    let path = match path {
        Some(path) => root.join(path)?,
        None => root,
    };

    Ok(uri_from_path_buf(root_fs.to_sys_path(&path)))
}

#[cfg(not(target_os = "windows"))]
pub fn uri_from_path_buf(sys_path: PathBuf) -> String {
    use turbo_unix_path::sys_to_unix;
    let sys_path = sys_path.to_string_lossy();

    format!(
        "file://{}",
        sys_to_unix(&sys_path)
            .split('/')
            .map(|s| urlencoding::encode(s))
            .collect::<Vec<_>>()
            .join("/")
    )
}

#[cfg(target_os = "windows")]
pub fn uri_from_path_buf(sys_path: PathBuf) -> String {
    let raw_path = sys_path.to_string_lossy().to_string();
    let normalized_path = raw_path.replace('\\', "/");

    let mut segments = normalized_path.split('/');

    let first = segments.next().unwrap_or_default(); // e.g., "C:"
    let encoded_path = std::iter::once(first.to_string()) // keep "C:" intact
        .chain(segments.map(|s| urlencoding::encode(s).into_owned()))
        .collect::<Vec<_>>()
        .join("/");

    format!("file:///{}", encoded_path)
}
Quest for Codev2.0.0
/
SIGN IN