#![cfg_attr(not(target_arch = "wasm32"), allow(dead_code))]
use std::path::PathBuf;
use eure::query::{EureQueryError, TextFile};
pub fn uri_to_text_file(uri: &str) -> Result<TextFile, EureQueryError> {
if uri.starts_with("https://") {
TextFile::parse(uri)
} else {
let path = uri_to_path(uri);
Ok(TextFile::from_path(PathBuf::from(path)))
}
}
pub fn uri_to_path(uri: &str) -> String {
let path = if let Some(stripped) = uri.strip_prefix("file:///") {
if stripped.chars().nth(1) == Some(':') {
stripped.to_string()
} else {
format!("/{}", stripped)
}
} else if let Some(stripped) = uri.strip_prefix("file://") {
stripped.to_string()
} else {
uri.to_string()
};
percent_decode(&path)
}
pub fn percent_decode(s: &str) -> String {
percent_encoding::percent_decode_str(s)
.decode_utf8_lossy()
.into_owned()
}
pub fn text_file_to_uri(file: &TextFile) -> String {
match file {
TextFile::Local(path) => {
let path_str = path.components().collect::<PathBuf>().display().to_string();
const PATH_ESCAPE: &percent_encoding::AsciiSet = &percent_encoding::CONTROLS
.add(b' ')
.add(b'#')
.add(b'?')
.add(b'%');
let path_str = percent_encoding::utf8_percent_encode(&path_str, PATH_ESCAPE);
let path_str = path_str.to_string();
if path_str.starts_with('/') {
format!("file://{}", path_str)
} else {
format!("file:///{}", path_str)
}
}
TextFile::Remote(url) => url.to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::Path;
mod uri_to_path_tests {
use super::*;
#[test]
fn unix_absolute_path() {
let path = uri_to_path("file:///home/user/file.eure");
assert_eq!(path, "/home/user/file.eure");
}
#[test]
fn unix_root_path() {
let path = uri_to_path("file:///file.eure");
assert_eq!(path, "/file.eure");
}
#[test]
fn windows_absolute_path() {
let path = uri_to_path("file:///C:/Users/user/file.eure");
assert_eq!(path, "C:/Users/user/file.eure");
}
#[test]
fn percent_encoded_spaces() {
let path = uri_to_path("file:///home/user/my%20file.eure");
assert_eq!(path, "/home/user/my file.eure");
}
#[test]
fn percent_encoded_unicode() {
let path = uri_to_path("file:///home/user/%E6%97%A5%E6%9C%AC%E8%AA%9E.eure");
assert_eq!(path, "/home/user/日本語.eure");
}
#[test]
fn non_uri_passthrough() {
let path = uri_to_path("/direct/path");
assert_eq!(path, "/direct/path");
}
}
mod uri_to_text_file_tests {
use super::*;
#[test]
fn file_uri_returns_local() {
let file = uri_to_text_file("file:///home/user/file.eure").unwrap();
assert!(file.as_local_path().is_some());
assert_eq!(
file.as_local_path().unwrap(),
Path::new("/home/user/file.eure")
);
}
#[test]
fn https_url_returns_remote() {
let file = uri_to_text_file("https://example.com/schema.eure").unwrap();
assert!(file.as_url().is_some());
assert_eq!(
file.as_url().unwrap().as_str(),
"https://example.com/schema.eure"
);
}
#[test]
fn windows_file_uri() {
let file = uri_to_text_file("file:///C:/Users/test.eure").unwrap();
assert!(file.as_local_path().is_some());
assert_eq!(
file.as_local_path().unwrap(),
Path::new("C:/Users/test.eure")
);
}
#[test]
fn invalid_url_returns_error() {
let result = uri_to_text_file("https://");
assert!(result.is_err());
}
}
mod text_file_to_uri_tests {
use super::*;
#[test]
fn local_unix_path() {
let file = TextFile::from_path(PathBuf::from("/home/user/file.eure"));
assert_eq!(text_file_to_uri(&file), "file:///home/user/file.eure");
}
#[test]
fn local_windows_path() {
let file = TextFile::from_path(PathBuf::from("C:/Users/file.eure"));
assert_eq!(text_file_to_uri(&file), "file:///C:/Users/file.eure");
}
#[test]
fn unicode_paths_are_encoded_and_round_trip() {
for (path, expected_uri) in [
(
"/home/user/日本語.eure",
"file:///home/user/%E6%97%A5%E6%9C%AC%E8%AA%9E.eure",
),
("/home/user/😀.eure", "file:///home/user/%F0%9F%98%80.eure"),
(
"C:/Users/日本語 😀.eure",
"file:///C:/Users/%E6%97%A5%E6%9C%AC%E8%AA%9E%20%F0%9F%98%80.eure",
),
] {
let file = TextFile::from_path(PathBuf::from(path));
let uri = text_file_to_uri(&file);
assert_eq!(uri, expected_uri);
assert_eq!(uri_to_text_file(&uri).unwrap(), file);
}
}
#[test]
fn path_delimiters_and_literal_percent_escapes_round_trip() {
let file = TextFile::from_path(PathBuf::from("/home/user/a b#c?d%20.eure"));
let uri = text_file_to_uri(&file);
assert_eq!(uri, "file:///home/user/a%20b%23c%3Fd%2520.eure");
let parsed: lsp_types::Uri = uri.parse().unwrap();
assert!(parsed.query().is_none());
assert!(parsed.fragment().is_none());
assert_eq!(uri_to_text_file(parsed.as_str()).unwrap(), file);
}
#[test]
fn remote_url() {
let file = TextFile::parse("https://example.com/schema.eure").unwrap();
assert_eq!(text_file_to_uri(&file), "https://example.com/schema.eure");
}
}
}