fn extract_flags_from_help(help_text: &str) -> Vec<String> {
let mut flags = Vec::new();
let options_lines = extract_options_section_lines(help_text);
for line in options_lines {
if let Some(line_flags) = parse_flags_from_line(line) {
flags.extend(line_flags);
}
}
flags
}
fn extract_options_section_lines(help_text: &str) -> Vec<&str> {
let mut section_lines = Vec::new();
let mut in_options_section = false;
for line in help_text.lines() {
if is_options_section_start(line) {
in_options_section = true;
continue;
}
if is_section_boundary(line, in_options_section) {
break;
}
if in_options_section {
section_lines.push(line);
}
}
section_lines
}
fn is_options_section_start(line: &str) -> bool {
line.contains("Options:") || line.contains("FLAGS:")
}
fn is_section_boundary(line: &str, in_section: bool) -> bool {
in_section && !line.trim().is_empty() && !line.starts_with(' ')
}
fn parse_flags_from_line(line: &str) -> Option<Vec<String>> {
let trimmed = line.trim_start();
if !trimmed.starts_with('-') {
return None;
}
let flag_tokens: Vec<&str> = trimmed
.split_whitespace()
.take_while(|w| w.starts_with('-') || w == &",")
.collect();
let flags: Vec<String> = flag_tokens
.iter()
.filter(|token| token.starts_with('-'))
.map(|token| token.trim_end_matches(',').to_string())
.collect();
if flags.is_empty() {
None
} else {
Some(flags)
}
}
fn extract_flag_name(line: &str) -> String {
let trimmed = line.trim_start();
if let Some(long_flag) = trimmed.split_whitespace().find(|w| w.starts_with("--")) {
long_flag.trim_end_matches(',').to_string()
} else if let Some(short_flag) = trimmed
.split_whitespace()
.find(|w| w.starts_with('-') && !w.starts_with("--"))
{
short_flag.trim_end_matches(',').to_string()
} else {
"unknown".to_string()
}
}
pub fn find_undocumented_flags(
expected_flags: &[&str],
documented_flags: &[String],
) -> Vec<String> {
let documented_set: HashSet<String> = documented_flags.iter().map(|f| f.to_string()).collect();
expected_flags
.iter()
.filter(|flag| !documented_set.contains(**flag))
.map(|f| f.to_string())
.collect()
}