Skip to main content

browser_control/cli/
routing.rs

1//! Shared routing glue for the `<browser>[/<tab>]` positional commands
2//! (`eval`, `fetch`, `storage`, …).
3//!
4//! These commands all parse the same positional shape and then peel the
5//! `/<tab>` suffix back off to recover the bare `<browser>` selector for
6//! [`crate::cli::mcp::resolve_browser`]. Keeping that one operation here
7//! avoids the three identical copies the routing handlers used to carry.
8
9/// Strip a `/<tab>` suffix from a raw `<browser>[/<tab>]` positional.
10///
11/// `tab` is the tab name already parsed out of `raw` (via
12/// [`crate::cli::env_resolver::parse_target`]). When `Some`, the matching
13/// `/<name>` suffix is removed; if `raw` doesn't actually end in that
14/// suffix the original is returned unchanged (defensive — the caller
15/// derives `tab` from the same `raw`, so a mismatch shouldn't happen).
16pub fn strip_tab(raw: &str, tab: Option<&str>) -> String {
17    match tab {
18        Some(name) => raw
19            .strip_suffix(&format!("/{name}"))
20            .unwrap_or(raw)
21            .to_string(),
22        None => raw.to_string(),
23    }
24}
25
26#[cfg(test)]
27mod tests {
28    use super::*;
29
30    #[test]
31    fn strip_tab_removes_suffix_when_present() {
32        assert_eq!(strip_tab("brave/cart", Some("cart")), "brave");
33        assert_eq!(strip_tab("brave", None), "brave");
34        // If `tab` is `Some` but does not in fact match the suffix, the
35        // original raw is returned unchanged (defensive — shouldn't happen
36        // in practice because the caller derives `tab` from the same raw).
37        assert_eq!(strip_tab("brave/cart", Some("other")), "brave/cart");
38    }
39}