Repository: starship/starship
File: src/modules/kubernetes.rs (Rust)

Code before:
                namespace: ctx_yaml["context"]["namespace"]
                    .as_str()
                    .filter(|s| !s.is_empty())
                    .map(String::from),
                cluster: ctx_yaml["context"]["cluster"]
                    .as_str()
                    .filter(|s| !s.is_empty())
                    .map(String::from),
            });
        }
    }
}

fn get_aliased_name<'a>(
    pattern: Option<&'a str>,
    current_value: Option<&str>,
    alias: Option<&'a str>,
) -> Option<String> {
    let replacement = alias.or(current_value)?.to_string();
    let Some(pattern) = pattern else {
        // If user pattern not set, treat it as a match-all pattern
        return Some(replacement);
    };
    // If a pattern is set, but we have no value, there is no match
    let value = current_value?;
    if value == pattern {
        return Some(replacement);
    }
    let re = match regex::Regex::new(&format!("^{pattern}$")) {
        Ok(re) => re,
        Err(error) => {
            log::warn!(
                "Could not compile regular expression `{}`:\n{}",
                &format!("^{pattern}$"),
                error
            );
            return None;
        }
    };
    let replaced = re.replace(value, replacement.as_str());
    match replaced {
        Cow::Owned(replaced) => Some(replaced),
        // It didn't match...
        _ => None,
    }
}

enum JsonOrYaml {
    Json(JsonValue),
    Yaml(Yaml),
}

Review comment (bug):
```suggestion
#[derive(Debug, Clone)]
enum Document {
    Json(JsonValue),
    Yaml(Yaml),
}
```

- `AorB` is not a great abstraction, I feel like `Document` is a better name; the variable bound to this value is often called `document` in this file as well, makes sense!
- it's good practice to derive the most common traits. Downstream crates wouldn't be able to otherwise. `Debug` is important for a baseline string representation (for logging, ...). Cloning is convenient. More is possible, but better to implement as-needed (this is subjective). More context: https://rust-lang.github.io/api-guidelines/interoperability.html#types-eagerly-implement-common-traits-c-common-traits (that book is a great resource anyway)

Code after:
        return Some(replacement);
    }
    let re = match regex::Regex::new(&format!("^{pattern}$")) {
        Ok(re) => re,
        Err(error) => {
            log::warn!(
                "Could not compile regular expression `{}`:\n{}",
                &format!("^{pattern}$"),
                error
            );
            return None;
        }
    };
    let replaced = re.replace(value, replacement.as_str());
    match replaced {
        Cow::Owned(replaced) => Some(replaced),
        // It didn't match...
        _ => None,
    }
}

#[derive(Debug)]
enum Document {
    Json(JsonValue),
    Yaml(Yaml),
}

trait DataValue {
    fn get(&self, key: &str) -> Option<&Self>;
    fn as_str(&self) -> Option<&str>;
    fn as_array(&self) -> Option<Vec<&Self>>;
}

impl DataValue for JsonValue {
    fn get(&self, key: &str) -> Option<&Self> {
        self.get(key)
    }

    fn as_str(&self) -> Option<&str> {
        self.as_str()
    }

    fn as_array(&self) -> Option<Vec<&Self>> {
        self.as_array().map(|arr| arr.iter().collect())
    }
}

impl DataValue for Yaml {
    fn get(&self, key: &str) -> Option<&Self> {
        match self {
            Yaml::Hash(map) => map.get(&Yaml::String(key.to_string())),