const CEL_RESERVED_WORDS: &[&str] = &[
"true",
"false",
"null",
"in",
"as",
"break",
"const",
"continue",
"else",
"for",
"function",
"if",
"import",
"let",
"loop",
"package",
"namespace",
"return",
"var",
"void",
"while",
];
#[must_use]
#[inline]
pub fn escape_field_name(name: &str) -> String {
if CEL_RESERVED_WORDS.contains(&name) {
return format!("__{name}__");
}
if name.contains('_') || name.contains('.') || name.contains('-') || name.contains('/') {
let mut escaped = String::with_capacity(name.len() * 2);
for ch in name.chars() {
match ch {
'_' => escaped.push_str("__"),
'.' => escaped.push_str("__dot__"),
'-' => escaped.push_str("__dash__"),
'/' => escaped.push_str("__slash__"),
_ => escaped.push(ch),
}
}
return escaped;
}
name.to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn reserved_word_namespace() {
assert_eq!(escape_field_name("namespace"), "__namespace__");
}
#[test]
fn reserved_word_default_is_not_reserved() {
assert_eq!(escape_field_name("default"), "default");
}
#[test]
fn all_reserved_words() {
for &word in CEL_RESERVED_WORDS {
assert_eq!(escape_field_name(word), format!("__{word}__"));
}
}
#[test]
fn dash_escaping() {
assert_eq!(escape_field_name("foo-bar"), "foo__dash__bar");
}
#[test]
fn dot_escaping() {
assert_eq!(escape_field_name("a.b"), "a__dot__b");
}
#[test]
fn slash_escaping() {
assert_eq!(escape_field_name("x/y"), "x__slash__y");
}
#[test]
fn underscore_doubling() {
assert_eq!(escape_field_name("my_field"), "my__field");
}
#[test]
fn mixed_special_characters() {
assert_eq!(escape_field_name("a-b_c.d"), "a__dash__b__c__dot__d");
}
#[test]
fn no_escaping_needed() {
assert_eq!(escape_field_name("replicas"), "replicas");
assert_eq!(escape_field_name("spec"), "spec");
assert_eq!(escape_field_name("fooBar"), "fooBar");
}
#[test]
fn empty_string() {
assert_eq!(escape_field_name(""), "");
}
#[test]
fn reserved_word_takes_priority_over_special_chars() {
assert_eq!(escape_field_name("in"), "__in__");
}
#[test]
fn multiple_dashes() {
assert_eq!(escape_field_name("a-b-c"), "a__dash__b__dash__c");
}
#[test]
fn leading_underscore() {
assert_eq!(escape_field_name("_private"), "__private");
}
#[test]
fn slash_in_annotation_key() {
assert_eq!(
escape_field_name("app.kubernetes.io/name"),
"app__dot__kubernetes__dot__io__slash__name"
);
}
}