Something went wrong. Try again.
npx ccusage
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105use std::ffi::OsString;
pub(crate) struct ArgParser { pub(crate) args: Vec<String>, index: usize, pending_value: Option<String>,}
impl ArgParser { pub(crate) fn new(args: Vec<OsString>) -> Result<Self, String> { let mut parsed = Vec::with_capacity(args.len()); for arg in args { parsed.push( arg.into_string() .map_err(|_| "Arguments must be valid UTF-8".to_string())?, ); } Ok(Self { args: parsed, index: 0, pending_value: None, }) }
pub(crate) fn peek(&self) -> Option<&str> { self.args.get(self.index).map(String::as_str) }
pub(crate) fn peek_name(&self) -> Option<&str> { self.peek() .map(|arg| arg.split_once('=').map_or(arg, |(name, _)| name)) }
pub(crate) fn next(&mut self) -> Option<String> { let value = self.args.get(self.index)?.clone(); self.index += 1; Some(value) }
pub(crate) fn next_flag(&mut self) -> Result<String, String> { self.pending_value = None; let arg = self .next() .ok_or_else(|| "Expected option but reached end of arguments".to_string())?; if let Some((flag, value)) = arg.split_once('=') { if !flag.starts_with('-') { return Err(format!("Expected option, got '{arg}'")); } self.pending_value = Some(value.to_string()); return Ok(flag.to_string()); } if arg.starts_with('-') { Ok(arg) } else { Err(format!("Expected option, got '{arg}'")) } }
pub(crate) fn value_for(&mut self, flag: &str) -> Result<String, String> { if let Some(value) = self.pending_value.take() { if value.is_empty() { return Err(format!("Missing value for {flag}")); } return Ok(value); } let value = self .next() .ok_or_else(|| format!("Missing value for {flag}"))?; if value.starts_with('-') { return Err(format!("Missing value for {flag}")); } Ok(value) }}
#[cfg(test)]mod tests { use std::ffi::OsString;
use super::*;
fn parser(args: &[&str]) -> ArgParser { ArgParser::new(args.iter().map(OsString::from).collect()).unwrap() }
#[test] fn clears_inline_value_when_reading_next_flag() { let mut parser = parser(&["--json=ignored", "--since", "20260101"]);
assert_eq!(parser.next_flag().unwrap(), "--json"); assert_eq!(parser.next_flag().unwrap(), "--since"); assert_eq!(parser.value_for("--since").unwrap(), "20260101"); }
#[test] fn rejects_inline_values_on_non_options() { let mut parser = parser(&["daily=bad"]);
assert_eq!( parser.next_flag().unwrap_err(), "Expected option, got 'daily=bad'" ); }}