diff --git a/.changeset/fix-clippy-lints.md b/.changeset/fix-clippy-lints.md new file mode 100644 index 00000000..786e1e5f --- /dev/null +++ b/.changeset/fix-clippy-lints.md @@ -0,0 +1,5 @@ +--- +"agent-browser": patch +--- + +Fix all Clippy lint warnings in the Rust CLI: remove redundant import, use `.first()` instead of `.get(0)`, use `.copied()` instead of `.map(|s| *s)`, use `.contains()` instead of `.iter().any()`, use `then_some` instead of lazy `then`, and simplify redundant match guards. diff --git a/cli/src/commands.rs b/cli/src/commands.rs index 8c52752f..da950ff7 100644 --- a/cli/src/commands.rs +++ b/cli/src/commands.rs @@ -81,7 +81,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let url = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let url = rest.first().ok_or_else(|| ParseError::MissingArguments { context: cmd.to_string(), usage: "open ", })?; @@ -117,63 +117,63 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "click".to_string(), usage: "click ", })?; Ok(json!({ "id": id, "action": "click", "selector": sel })) } "dblclick" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "dblclick".to_string(), usage: "dblclick ", })?; Ok(json!({ "id": id, "action": "dblclick", "selector": sel })) } "fill" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "fill".to_string(), usage: "fill ", })?; Ok(json!({ "id": id, "action": "fill", "selector": sel, "value": rest[1..].join(" ") })) } "type" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "type".to_string(), usage: "type ", })?; Ok(json!({ "id": id, "action": "type", "selector": sel, "text": rest[1..].join(" ") })) } "hover" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "hover".to_string(), usage: "hover ", })?; Ok(json!({ "id": id, "action": "hover", "selector": sel })) } "focus" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "focus".to_string(), usage: "focus ", })?; Ok(json!({ "id": id, "action": "focus", "selector": sel })) } "check" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "check".to_string(), usage: "check ", })?; Ok(json!({ "id": id, "action": "check", "selector": sel })) } "uncheck" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "uncheck".to_string(), usage: "uncheck ", })?; Ok(json!({ "id": id, "action": "uncheck", "selector": sel })) } "select" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "select".to_string(), usage: "select ", })?; @@ -189,7 +189,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let src = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let src = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "drag".to_string(), usage: "drag ", })?; @@ -200,14 +200,14 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "upload".to_string(), usage: "upload ", })?; Ok(json!({ "id": id, "action": "upload", "selector": sel, "files": &rest[1..] })) } "download" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "download".to_string(), usage: "download ", })?; @@ -220,21 +220,21 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let key = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let key = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "press".to_string(), usage: "press ", })?; Ok(json!({ "id": id, "action": "press", "key": key })) } "keydown" => { - let key = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let key = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "keydown".to_string(), usage: "keydown ", })?; Ok(json!({ "id": id, "action": "keydown", "key": key })) } "keyup" => { - let key = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let key = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "keyup".to_string(), usage: "keyup ", })?; @@ -243,7 +243,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let dir = rest.get(0).unwrap_or(&"down"); + let dir = rest.first().unwrap_or(&"down"); let amount = rest .get(1) .and_then(|s| s.parse::().ok()) @@ -251,7 +251,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "scrollintoview".to_string(), usage: "scrollintoview ", })?; @@ -332,7 +332,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result().is_ok() { Ok( json!({ "id": id, "action": "wait", "timeout": arg.parse::().unwrap() }), @@ -353,7 +353,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { // Two args: first is selector, second is path (Some(*first), Some(*second)) @@ -383,7 +383,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let path = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let path = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "pdf".to_string(), usage: "pdf ", })?; @@ -442,17 +442,22 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result = stdin.lock().lines() + let lines: Vec = stdin + .lock() + .lines() .map(|l| l.unwrap_or_default()) .collect(); lines.join("\n") } else { let raw_script = script_parts.join(" "); if is_base64 { - let decoded = STANDARD.decode(&raw_script).map_err(|_| ParseError::InvalidValue { - message: "Invalid base64 encoding".to_string(), - usage: "eval -b ", - })?; + let decoded = + STANDARD + .decode(&raw_script) + .map_err(|_| ParseError::InvalidValue { + message: "Invalid base64 encoding".to_string(), + usage: "eval -b ", + })?; String::from_utf8(decoded).map_err(|_| ParseError::InvalidValue { message: "Base64 decoded to invalid UTF-8".to_string(), usage: "eval -b ", @@ -483,7 +488,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result() { - Ok(p) if p == 0 => { + Ok(0) => { return Err(ParseError::InvalidValue { message: "Invalid port: port must be greater than 0".to_string(), usage: "connect ", @@ -536,7 +541,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let op = rest.get(0).unwrap_or(&"get"); + let op = rest.first().unwrap_or(&"get"); match *op { "set" => { let name = rest.get(1).ok_or_else(|| ParseError::MissingArguments { @@ -650,7 +655,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result match rest.get(0).map(|s| *s) { + "tab" => match rest.first().copied() { Some("new") => { let mut cmd = json!({ "id": id, "action": "tab_new" }); if let Some(url) = rest.get(1) { @@ -675,7 +680,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { const VALID: &[&str] = &["new"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("new") => Ok(json!({ "id": id, "action": "window_new" })), Some(sub) => Err(ParseError::UnknownSubcommand { subcommand: sub.to_string(), @@ -690,10 +695,10 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - if rest.get(0).map(|s| *s) == Some("main") { + if rest.first().copied() == Some("main") { Ok(json!({ "id": id, "action": "mainframe" })) } else { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "frame".to_string(), usage: "frame ", })?; @@ -704,7 +709,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { const VALID: &[&str] = &["accept", "dismiss"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("accept") => { let mut cmd = json!({ "id": id, "action": "dialog", "response": "accept" }); if let Some(prompt_text) = rest.get(1) { @@ -726,7 +731,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { const VALID: &[&str] = &["start", "stop"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("start") => Ok(json!({ "id": id, "action": "trace_start" })), Some("stop") => { let path = rest.get(1).ok_or_else(|| ParseError::MissingArguments { @@ -749,7 +754,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { const VALID: &[&str] = &["start", "stop", "restart"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("start") => { let path = rest.get(1).ok_or_else(|| ParseError::MissingArguments { context: "record start".to_string(), @@ -800,15 +805,15 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { - let clear = rest.iter().any(|&s| s == "--clear"); + let clear = rest.contains(&"--clear"); Ok(json!({ "id": id, "action": "console", "clear": clear })) } "errors" => { - let clear = rest.iter().any(|&s| s == "--clear"); + let clear = rest.contains(&"--clear"); Ok(json!({ "id": id, "action": "errors", "clear": clear })) } "highlight" => { - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "highlight".to_string(), usage: "highlight ", })?; @@ -818,7 +823,7 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { const VALID: &[&str] = &["save", "load"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("save") => { let path = rest.get(1).ok_or_else(|| ParseError::MissingArguments { context: "state save".to_string(), @@ -847,14 +852,14 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result { // Alias for click (semantic clarity for touch interfaces) - let sel = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let sel = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "tap".to_string(), usage: "tap ", })?; Ok(json!({ "id": id, "action": "tap", "selector": sel })) } "swipe" => { - let direction = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let direction = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "swipe".to_string(), usage: "swipe [distance]", })?; @@ -868,13 +873,15 @@ pub fn parse_command(args: &[String], flags: &Flags) -> Result() { - cmd.as_object_mut().unwrap().insert("distance".to_string(), json!(d)); + cmd.as_object_mut() + .unwrap() + .insert("distance".to_string(), json!(d)); } } Ok(cmd) } "device" => { - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("list") | None => { // List available iOS simulators Ok(json!({ "id": id, "action": "device_list" })) @@ -897,7 +904,7 @@ fn parse_get(rest: &[&str], id: &str) -> Result { "text", "html", "value", "attr", "url", "title", "count", "box", "styles", ]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("text") => { let sel = rest.get(1).ok_or_else(|| ParseError::MissingArguments { context: "get text".to_string(), @@ -967,7 +974,7 @@ fn parse_get(rest: &[&str], id: &str) -> Result { fn parse_is(rest: &[&str], id: &str) -> Result { const VALID: &[&str] = &["visible", "enabled", "checked"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("visible") => { let sel = rest.get(1).ok_or_else(|| ParseError::MissingArguments { context: "is visible".to_string(), @@ -1014,14 +1021,14 @@ fn parse_find(rest: &[&str], id: &str) -> Result { "nth", ]; - let locator = rest.get(0).ok_or_else(|| ParseError::MissingArguments { + let locator = rest.first().ok_or_else(|| ParseError::MissingArguments { context: "find".to_string(), usage: "find [action] [text]", })?; let name_idx = rest.iter().position(|&s| s == "--name"); - let name = name_idx.and_then(|i| rest.get(i + 1).map(|s| *s)); - let exact = rest.iter().any(|&s| s == "--exact"); + let name = name_idx.and_then(|i| rest.get(i + 1).copied()); + let exact = rest.contains(&"--exact"); match *locator { "role" | "text" | "label" | "placeholder" | "alt" | "title" | "testid" | "first" @@ -1140,7 +1147,7 @@ fn parse_find(rest: &[&str], id: &str) -> Result { fn parse_mouse(rest: &[&str], id: &str) -> Result { const VALID: &[&str] = &["move", "down", "up", "wheel"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("move") => { let x_str = rest.get(1).ok_or_else(|| ParseError::MissingArguments { context: "mouse move".to_string(), @@ -1202,7 +1209,7 @@ fn parse_set(rest: &[&str], id: &str) -> Result { "media", ]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("viewport") => { let w_str = rest.get(1).ok_or_else(|| ParseError::MissingArguments { context: "set viewport".to_string(), @@ -1288,14 +1295,14 @@ fn parse_set(rest: &[&str], id: &str) -> Result { Ok(json!({ "id": id, "action": "credentials", "username": user, "password": pass })) } Some("media") => { - let color = if rest.iter().any(|&s| s == "dark") { + let color = if rest.contains(&"dark") { "dark" - } else if rest.iter().any(|&s| s == "light") { + } else if rest.contains(&"light") { "light" } else { "no-preference" }; - let reduced = if rest.iter().any(|&s| s == "reduced-motion") { + let reduced = if rest.contains(&"reduced-motion") { "reduce" } else { "no-preference" @@ -1318,15 +1325,15 @@ fn parse_set(rest: &[&str], id: &str) -> Result { fn parse_network(rest: &[&str], id: &str) -> Result { const VALID: &[&str] = &["route", "unroute", "requests"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("route") => { let url = rest.get(1).ok_or_else(|| ParseError::MissingArguments { context: "network route".to_string(), usage: "network route [--abort|--body ]", })?; - let abort = rest.iter().any(|&s| s == "--abort"); + let abort = rest.contains(&"--abort"); let body_idx = rest.iter().position(|&s| s == "--body"); - let body = body_idx.and_then(|i| rest.get(i + 1).map(|s| *s)); + let body = body_idx.and_then(|i| rest.get(i + 1).copied()); Ok(json!({ "id": id, "action": "route", "url": url, "abort": abort, "body": body })) } Some("unroute") => { @@ -1337,9 +1344,9 @@ fn parse_network(rest: &[&str], id: &str) -> Result { Ok(cmd) } Some("requests") => { - let clear = rest.iter().any(|&s| s == "--clear"); + let clear = rest.contains(&"--clear"); let filter_idx = rest.iter().position(|&s| s == "--filter"); - let filter = filter_idx.and_then(|i| rest.get(i + 1).map(|s| *s)); + let filter = filter_idx.and_then(|i| rest.get(i + 1).copied()); let mut cmd = json!({ "id": id, "action": "requests", "clear": clear }); if let Some(f) = filter { cmd["filter"] = json!(f); @@ -1360,9 +1367,9 @@ fn parse_network(rest: &[&str], id: &str) -> Result { fn parse_storage(rest: &[&str], id: &str) -> Result { const VALID: &[&str] = &["local", "session"]; - match rest.get(0).map(|s| *s) { + match rest.first().copied() { Some("local") | Some("session") => { - let storage_type = rest.get(0).unwrap(); + let storage_type = rest.first().unwrap(); let op = rest.get(1).unwrap_or(&"get"); let key = rest.get(2); let value = rest.get(3); @@ -2158,8 +2165,11 @@ mod tests { #[test] fn test_eval_base64_long_flag() { // "document.title" in base64 - let cmd = - parse_command(&args("eval --base64 ZG9jdW1lbnQudGl0bGU="), &default_flags()).unwrap(); + let cmd = parse_command( + &args("eval --base64 ZG9jdW1lbnQudGl0bGU="), + &default_flags(), + ) + .unwrap(); assert_eq!(cmd["action"], "evaluate"); assert_eq!(cmd["script"], "document.title"); } diff --git a/cli/src/connection.rs b/cli/src/connection.rs index b5cb26cd..be874da3 100644 --- a/cli/src/connection.rs +++ b/cli/src/connection.rs @@ -203,6 +203,7 @@ pub struct DaemonResult { pub already_running: bool, } +#[allow(clippy::too_many_arguments)] pub fn ensure_daemon( session: &str, headed: bool, diff --git a/cli/src/main.rs b/cli/src/main.rs index 01b1879b..706ff68f 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -10,9 +10,6 @@ use std::env; use std::fs; use std::process::exit; -#[cfg(unix)] -use libc; - #[cfg(windows)] use windows_sys::Win32::Foundation::CloseHandle; #[cfg(windows)] @@ -141,7 +138,7 @@ fn main() { let has_version = args.iter().any(|a| a == "--version" || a == "-V"); if has_help { - if let Some(cmd) = clean.get(0) { + if let Some(cmd) = clean.first() { if print_command_help(cmd) { return; } @@ -161,14 +158,14 @@ fn main() { } // Handle install separately - if clean.get(0).map(|s| s.as_str()) == Some("install") { + if clean.first().map(|s| s.as_str()) == Some("install") { let with_deps = args.iter().any(|a| a == "--with-deps" || a == "-d"); run_install(with_deps); return; } // Handle session separately (doesn't need daemon) - if clean.get(0).map(|s| s.as_str()) == Some("session") { + if clean.first().map(|s| s.as_str()) == Some("session") { run_session(&clean, &flags.session, flags.json); return; } @@ -247,11 +244,7 @@ fn main() { } else { None }, - if flags.cli_args { - Some("--args") - } else { - None - }, + if flags.cli_args { Some("--args") } else { None }, if flags.cli_user_agent { Some("--user-agent") } else { @@ -267,8 +260,8 @@ fn main() { } else { None }, - flags.ignore_https_errors.then(|| "--ignore-https-errors"), - flags.cli_allow_file_access.then(|| "--allow-file-access"), + flags.ignore_https_errors.then_some("--ignore-https-errors"), + flags.cli_allow_file_access.then_some("--allow-file-access"), ] .into_iter() .flatten() @@ -321,7 +314,7 @@ fn main() { } else { // It's a port number - validate and use cdpPort field let cdp_port: u16 = match cdp_value.parse::() { - Ok(p) if p == 0 => { + Ok(0) => { let msg = "Invalid CDP port: port must be greater than 0".to_string(); if flags.json { println!(r#"{{"success":false,"error":"{}"}}"#, msg); diff --git a/cli/src/output.rs b/cli/src/output.rs index 249c05f3..93b051e9 100644 --- a/cli/src/output.rs +++ b/cli/src/output.rs @@ -88,17 +88,28 @@ pub fn print_response(resp: &Response, json_mode: bool, action: Option<&str>) { // Separate real devices from simulators let real_devices: Vec<_> = devices .iter() - .filter(|d| d.get("isRealDevice").and_then(|v| v.as_bool()).unwrap_or(false)) + .filter(|d| { + d.get("isRealDevice") + .and_then(|v| v.as_bool()) + .unwrap_or(false) + }) .collect(); let simulators: Vec<_> = devices .iter() - .filter(|d| !d.get("isRealDevice").and_then(|v| v.as_bool()).unwrap_or(false)) + .filter(|d| { + !d.get("isRealDevice") + .and_then(|v| v.as_bool()) + .unwrap_or(false) + }) .collect(); if !real_devices.is_empty() { println!("Connected Devices:\n"); for device in real_devices.iter() { - let name = device.get("name").and_then(|v| v.as_str()).unwrap_or("Unknown"); + let name = device + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown"); let runtime = device.get("runtime").and_then(|v| v.as_str()).unwrap_or(""); let udid = device.get("udid").and_then(|v| v.as_str()).unwrap_or(""); println!(" {} {} ({})", color::green("●"), name, runtime); @@ -110,9 +121,15 @@ pub fn print_response(resp: &Response, json_mode: bool, action: Option<&str>) { if !simulators.is_empty() { println!("Simulators:\n"); for device in simulators.iter() { - let name = device.get("name").and_then(|v| v.as_str()).unwrap_or("Unknown"); + let name = device + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown"); let runtime = device.get("runtime").and_then(|v| v.as_str()).unwrap_or(""); - let state = device.get("state").and_then(|v| v.as_str()).unwrap_or("Unknown"); + let state = device + .get("state") + .and_then(|v| v.as_str()) + .unwrap_or("Unknown"); let udid = device.get("udid").and_then(|v| v.as_str()).unwrap_or(""); let state_indicator = if state == "Booted" { color::green("●")