use crate::internals::utils::is_unquotable_js_identifier;
use std::borrow::Cow;
use std::fmt::Display;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
#[derive(Clone, Debug, PartialEq)]
pub enum ContextPathPart<'a> {
String(Cow<'a, str>),
Index(usize),
}
impl ContextPathPart<'_> {
pub fn to_static(&self) -> ContextPathPart<'static> {
match self {
Self::String(inner) => {
let cloned_inner = inner.clone().into_owned();
let cow = Cow::<'static, str>::Owned(cloned_inner);
ContextPathPart::String(cow)
}
Self::Index(index) => ContextPathPart::Index(*index),
}
}
}
impl Display for ContextPathPart<'_> {
fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
match self {
Self::String(inner) => {
if is_unquotable_js_identifier(inner) {
write!(formatter, ".{inner}")
} else {
write!(formatter, r#"."{inner}""#)
}
}
Self::Index(inner) => write!(formatter, "[{inner}]"),
}
}
}
impl<'a> From<&'a String> for ContextPathPart<'a> {
fn from(inner: &'a String) -> Self {
Self::String(Cow::Borrowed(inner))
}
}
impl From<usize> for ContextPathPart<'_> {
fn from(inner: usize) -> Self {
Self::Index(inner)
}
}
#[cfg(test)]
mod test_fmt {
use super::*;
#[test]
fn it_should_print_whole_paths_without_quotes_when_an_identifier() {
let path = ContextPathPart::String(std::borrow::Cow::Owned("example".to_string()));
let output = format!("{path}");
assert_eq!(output, r#".example"#);
}
#[test]
fn it_should_print_paths_with_quotes_when_not_an_identifier() {
let path = ContextPathPart::String(std::borrow::Cow::Owned("my-example".to_string()));
let output = format!("{path}");
assert_eq!(output, r#"."my-example""#);
}
#[test]
fn it_should_print_empty_paths_as_quotes() {
let path = ContextPathPart::String(std::borrow::Cow::Owned("".to_string()));
let output = format!("{path}");
assert_eq!(output, r#"."""#);
}
#[test]
fn it_should_print_paths_with_spaces_with_quotes() {
let path = ContextPathPart::String(std::borrow::Cow::Owned("".to_string()));
let output = format!("{path}");
assert_eq!(output, r#"."""#);
}
}
#[cfg(test)]
mod test_from {
use super::*;
#[test]
fn it_should_convert_strings_to_string_paths() {
let path_raw = format!("my_path");
let path = ContextPathPart::from(&path_raw);
assert_eq!(path, ContextPathPart::String(Cow::Borrowed(&path_raw)));
}
#[test]
fn it_should_convert_usize_to_index_paths() {
let path = ContextPathPart::from(123_usize);
assert_eq!(path, ContextPathPart::Index(123));
}
}