use super::InstanceConfig;
use once_cell::sync::Lazy;
use regex::Regex;
pub(crate) fn from_config_string(config_string: &str) -> Result<InstanceConfig, String> {
let config_string = config_string.trim();
static RX_CONFIG_STRING_V1: Lazy<Regex> = Lazy::new(|| {
let directive = r#"[a-z]+"#;
let css_classname = r#"-?[_a-zA-Z]+[_a-zA-Z0-9-]*"#;
let title = r#"".*""#;
Regex::new(&format!(
"^({directive})?(\\.({css_classname})?)*( {title})?$"
))
.expect("config string v1 regex")
});
if !RX_CONFIG_STRING_V1.is_match(config_string) {
return Err("Invalid configuration string".to_owned());
}
let (directive, title) = config_string
.split_once(' ')
.map(|(directive, title)| (directive, Some(title)))
.unwrap_or_else(|| (config_string, None));
let title = title
.map(|title| {
serde_json::from_str::<String>(title)
.map_err(|error| format!("Error parsing JSON string: {error}"))
})
.transpose()?;
const CLASSNAME_SEPARATOR: char = '.';
let (directive, additional_classnames) = match directive.split_once(CLASSNAME_SEPARATOR) {
None => (directive, Vec::new()),
Some((directive, additional_classnames)) => (
directive,
additional_classnames
.split(CLASSNAME_SEPARATOR)
.filter(|classname| !classname.is_empty())
.map(|classname| classname.to_owned())
.collect(),
),
};
Ok(InstanceConfig {
directive: directive.to_owned(),
title,
id: None,
additional_classnames,
collapsible: None,
})
}
#[cfg(test)]
mod test {
use super::*;
use pretty_assertions::assert_eq;
#[test]
fn test_from_config_string() {
assert_eq!(
from_config_string("").unwrap(),
InstanceConfig {
directive: "".to_owned(),
title: None,
id: None,
additional_classnames: Vec::new(),
collapsible: None,
}
);
assert_eq!(
from_config_string(" ").unwrap(),
InstanceConfig {
directive: "".to_owned(),
title: None,
id: None,
additional_classnames: Vec::new(),
collapsible: None,
}
);
assert_eq!(
from_config_string("unknown").unwrap(),
InstanceConfig {
directive: "unknown".to_owned(),
title: None,
id: None,
additional_classnames: Vec::new(),
collapsible: None,
}
);
assert_eq!(
from_config_string("note").unwrap(),
InstanceConfig {
directive: "note".to_owned(),
title: None,
id: None,
additional_classnames: Vec::new(),
collapsible: None,
}
);
assert_eq!(
from_config_string("note.additional-classname").unwrap(),
InstanceConfig {
directive: "note".to_owned(),
title: None,
id: None,
additional_classnames: vec!["additional-classname".to_owned()],
collapsible: None,
}
);
}
#[test]
fn test_from_config_string_invalid_title_json() {
assert_eq!(
from_config_string(r#"note "\""#).unwrap_err(),
"Error parsing JSON string: EOF while parsing a string at line 1 column 3".to_owned()
);
}
#[test]
fn test_from_config_string_v2_format() {
assert_eq!(
from_config_string(r#"note title="Custom""#).unwrap_err(),
"Invalid configuration string".to_owned()
);
}
}