use std::collections::BTreeSet;
macro_rules! spec_file {
($name:literal) => {
include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/../../protocol-spec/",
$name
))
};
}
const MIXINS: &str = spec_file!("mixins.yml");
pub(crate) const BROWSER: &str = spec_file!("browser.yml");
pub(crate) const BROWSER_TYPE: &str = spec_file!("browserType.yml");
pub(crate) const FRAME: &str = spec_file!("frame.yml");
pub(crate) const BROWSER_CONTEXT: &str = spec_file!("browserContext.yml");
pub(crate) const API_REQUEST_CONTEXT: &str = spec_file!("api.yml");
pub(crate) const PAGE: &str = spec_file!("page.yml");
pub(crate) fn command_parameters(spec: &str, command: &str) -> BTreeSet<String> {
let mut lines = spec.lines();
lines
.by_ref()
.find(|line| *line == format!(" {command}:"))
.unwrap_or_else(|| panic!("no command `{command}` in the spec"));
lines
.by_ref()
.find(|line| *line == " parameters:")
.unwrap_or_else(|| panic!("command `{command}` declares no parameters"));
let mut parameters = BTreeSet::new();
for line in lines {
if !line.trim().is_empty() && indent(line) <= 6 {
break;
}
if indent(line) != 8 {
continue;
}
let Some((key, value)) = line.trim().split_once(':') else {
continue;
};
if key.starts_with("$mixin") {
parameters.extend(mixin_properties(value.trim()));
} else {
parameters.insert(key.to_string());
}
}
parameters
}
pub(crate) fn nested_properties(mixin: &str, property: &str) -> BTreeSet<String> {
let mut lines = MIXINS.lines();
lines
.by_ref()
.find(|line| *line == format!("{mixin}:"))
.unwrap_or_else(|| panic!("no mixin `{mixin}` in mixins.yml"));
lines
.by_ref()
.take_while(|line| line.trim().is_empty() || indent(line) > 0)
.find(|line| *line == format!(" {property}:"))
.unwrap_or_else(|| panic!("no property `{property}` in mixin `{mixin}`"));
let mut properties = BTreeSet::new();
for line in lines {
if !line.trim().is_empty() && indent(line) <= 4 {
break;
}
if indent(line) != 8 {
continue;
}
let Some((key, value)) = line.trim().split_once(':') else {
continue;
};
if key.starts_with("$mixin") {
properties.extend(mixin_properties(value.trim()));
} else {
properties.insert(key.to_string());
}
}
properties
}
pub(crate) fn mixin_properties(name: &str) -> BTreeSet<String> {
let mut lines = MIXINS.lines();
lines
.by_ref()
.find(|line| *line == format!("{name}:"))
.unwrap_or_else(|| panic!("no mixin `{name}` in mixins.yml"));
lines
.take_while(|line| line.trim().is_empty() || indent(line) > 0)
.filter(|line| indent(line) == 4)
.filter_map(|line| line.trim().split_once(':').map(|(key, _)| key.to_string()))
.collect()
}
fn indent(line: &str) -> usize {
line.len() - line.trim_start().len()
}
pub(crate) fn keys(value: &serde_json::Value) -> BTreeSet<String> {
value
.as_object()
.expect("options serialize to a JSON object")
.keys()
.cloned()
.collect()
}