pub const OG_IMAGE_CANDIDATE_PREFIX: &str = "og-image:";
const TEMPLATE_CALLS: &[&str] = &["defineOgImage", "defineOgImageComponent"];
const RENDERER_SUFFIXES: &[&str] = &["Satori", "Browser", "Takumi"];
const DIRECTORY_PREFIXES: &[&str] = &["OgImageCommunity", "OgImageTemplate", "OgImage"];
#[must_use]
pub fn is_template_call(callee: &str) -> bool {
TEMPLATE_CALLS.contains(&callee)
}
#[must_use]
pub fn template_candidate(name: &str) -> Option<String> {
let mut joined = String::with_capacity(name.len());
for (idx, segment) in name.split('.').enumerate() {
let mut chars = segment.chars();
if idx > 0
&& let Some(first) = chars.next()
{
joined.extend(first.to_uppercase());
joined.push_str(chars.as_str());
} else {
joined.push_str(segment);
}
}
let base = strip_nonempty_suffix(&joined, RENDERER_SUFFIXES);
let base = strip_nonempty_prefix(base, DIRECTORY_PREFIXES);
(!base.is_empty()).then(|| format!("{OG_IMAGE_CANDIDATE_PREFIX}{base}"))
}
fn strip_nonempty_suffix<'a>(name: &'a str, suffixes: &[&str]) -> &'a str {
suffixes
.iter()
.find_map(|suffix| name.strip_suffix(suffix).filter(|rest| !rest.is_empty()))
.unwrap_or(name)
}
fn strip_nonempty_prefix<'a>(name: &'a str, prefixes: &[&str]) -> &'a str {
prefixes
.iter()
.find_map(|prefix| name.strip_prefix(prefix).filter(|rest| !rest.is_empty()))
.unwrap_or(name)
}
#[cfg(all(test, not(miri)))]
mod tests {
use super::*;
#[test]
fn call_names_and_component_names_share_one_key() {
for name in [
"Docs",
"Docs.takumi",
"DocsTakumi",
"OgImageDocs",
"OgImageDocsTakumi",
"OgImageTemplateDocs",
"OgImageCommunityDocs.satori",
] {
assert_eq!(
template_candidate(name).as_deref(),
Some("og-image:Docs"),
"{name}"
);
}
assert_eq!(
template_candidate("BlogPost.browser").as_deref(),
Some("og-image:BlogPost")
);
}
#[test]
fn a_name_that_is_only_a_prefix_or_suffix_stays() {
assert_eq!(
template_candidate("OgImage").as_deref(),
Some("og-image:OgImage")
);
assert_eq!(
template_candidate("Takumi").as_deref(),
Some("og-image:Takumi")
);
assert_eq!(template_candidate(""), None);
}
#[test]
fn a_static_template_name_becomes_a_candidate() {
let info = crate::tests::parse_ts(
"defineOgImage('Docs.takumi', {});\ndefineOgImageComponent(`Blog`);\ndefineOgImage(name);\ndefineOgImage(`A${x}`);\nog.defineOgImage('Member');\n",
);
let og: Vec<&str> = info
.auto_import_candidates
.iter()
.map(String::as_str)
.filter(|name| name.starts_with(OG_IMAGE_CANDIDATE_PREFIX))
.collect();
assert_eq!(og, ["og-image:Blog", "og-image:Docs"]);
assert!(
info.auto_import_candidates
.iter()
.any(|name| name == "defineOgImage"),
"the call itself stays a candidate"
);
}
#[test]
fn only_the_template_calls_match() {
assert!(is_template_call("defineOgImage"));
assert!(is_template_call("defineOgImageComponent"));
assert!(!is_template_call("defineOgImageScreenshot"));
assert!(!is_template_call("useSeoMeta"));
}
}