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}