#![deny(clippy::print_stdout)]
use crate::mesdoc::interface::{BoxDynElement, Elements, IAttrValue, IElementTrait, INodeType};
use crate::mesdoc::selector::pattern::Nth;
use crate::mesdoc::selector::rule::{Matcher, Rule, RuleDefItem, RuleItem};
use crate::mesdoc::selector::MatchedQueue;
use crate::mesdoc::utils::{contains_chars, is_equal_chars};
use crate::mesdoc::{
constants::{
DEF_NODES_LEN, PRIORITY_PSEUDO_SELECTOR, SELECTOR_ALIAS_NAME_HEADER, SELECTOR_ALIAS_NAME_INPUT,
SELECTOR_ALIAS_NAME_SUBMIT,
},
selector::rule::MatchSpecifiedHandle,
};
use std::{cmp::Ordering, collections::VecDeque};
use std::{collections::HashMap, ops::Range};
const PRIORITY: u32 = PRIORITY_PSEUDO_SELECTOR;
fn nth_index_to_number(index: &Option<String>) -> isize {
index
.as_ref()
.expect("Nth's n and index must have one")
.parse::<isize>()
.expect("Nth's index is not ok")
}
fn pseudo_root(rules: &mut Vec<RuleItem>) {
let selector = ":root";
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(|_| Matcher {
specified_handle: Some(Box::new(|ele, mut callback| {
if ele.is_root_element() {
let total = ele.child_nodes_length();
for index in 0..total {
let node = ele
.child_nodes_item(index)
.expect("Child nodes item index must less than total");
if matches!(node.node_type(), INodeType::Element) {
let ele = node
.typed()
.into_element()
.expect("Call `typed` for element ele.");
if ele.tag_name() == "HTML" {
callback(&*ele, true, false);
}
}
}
}
})),
one_handle: Some(Box::new(|ele, _| {
if ele.tag_name() == "HTML" {
if let Some(parent) = &ele.parent() {
return matches!(parent.node_type(), INodeType::Document);
}
}
false
})),
..Default::default()
}),
);
rules.push(rule.into());
}
fn pseudo_empty(rules: &mut Vec<RuleItem>) {
let selector = ":empty";
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(|_| Matcher {
one_handle: Some(Box::new(|ele, _| {
let child_nodes = ele.child_nodes();
if child_nodes.is_empty() {
return true;
}
let mut only_comments = true;
for node in child_nodes {
match node.node_type() {
INodeType::Comment => continue,
_ => {
only_comments = false;
break;
}
}
}
only_comments
})),
..Default::default()
}),
);
rules.push(rule.into());
}
struct SiblingsNodeData<'a> {
range: Range<usize>,
allow_indexs: Option<Vec<usize>>,
parent: Option<BoxDynElement<'a>>,
}
fn group_siblings_then_done<T, F>(eles: &Elements, allow_indexs_fn: T, mut cb: F)
where
T: Fn(usize) -> Option<Vec<usize>>,
F: FnMut(&mut SiblingsNodeData),
{
let mut data = SiblingsNodeData {
range: 0..0,
allow_indexs: None,
parent: None,
};
for (index, ele) in eles.get_ref().iter().enumerate() {
if let Some(parent) = ele.parent() {
let mut is_first = false;
let mut in_next_group = false;
if let Some(prev_parent) = &data.parent {
if parent.is(prev_parent) {
data.range.end = index + 1;
} else {
in_next_group = true;
}
} else {
is_first = true;
}
if in_next_group {
cb(&mut data);
}
if is_first || in_next_group {
data.range.start = index;
data.range.end = index + 1;
data.allow_indexs = allow_indexs_fn(parent.children().length());
data.parent = Some(parent);
}
}
}
if !data.range.is_empty() {
cb(&mut data);
}
}
fn make_asc_or_desc_nth_child_specified(asc: bool, index: isize) -> MatchSpecifiedHandle {
if index > 0 {
let index = (index - 1) as usize;
if asc {
Box::new(move |ele, mut callback| {
let mut cur_index: usize = 0;
ele.child_nodes_item_since_by(
0,
false,
Box::new(|child| {
let is_matched = cur_index == index;
cur_index += 1;
callback(child, is_matched, true);
true
}),
);
})
} else {
Box::new(move |ele, mut callback| {
let total = ele.child_nodes_length();
let mut matched: VecDeque<bool> = VecDeque::with_capacity(total);
let mut cur_index: usize = 0;
ele.child_nodes_item_since_by(
total - 1,
true,
Box::new(|_| {
let is_matched = cur_index == index;
cur_index += 1;
matched.push_front(is_matched);
true
}),
);
let mut loop_index: usize = 0;
ele.child_nodes_item_since_by(
0,
false,
Box::new(|child| {
callback(child, matched[loop_index], true);
loop_index += 1;
true
}),
);
})
}
} else {
Box::new(move |_, _| {})
}
}
type NthChildHandle = Box<
dyn for<'a, 'r> Fn(
&'a Elements<'r>,
&'a Range<usize>,
&'a [usize],
&'a Elements<'r>,
) -> Vec<BoxDynElement<'r>>
+ Send
+ Sync,
>;
fn make_asc_or_desc_nth_child_handle(asc: bool) -> NthChildHandle {
if asc {
Box::new(
|eles: &Elements,
range: &Range<usize>,
allow_indexs: &[usize],
childs: &Elements|
-> Vec<BoxDynElement> {
let childs = childs.get_ref();
let mut finded: Vec<BoxDynElement> = Vec::with_capacity(allow_indexs.len());
if range.len() == childs.len() {
for &index in allow_indexs {
finded.push(childs[index].cloned());
}
} else {
let eles = eles.get_ref();
let siblings = &eles[range.start..range.end];
let mut start_index = 0;
let mut allow_start_index = 0;
let allow_indexs_total = allow_indexs.len();
'loop_sibling: for ele in siblings {
for (index, child) in childs[start_index..].iter().enumerate() {
if child.is(ele) {
let actual_index = start_index + index;
for &allow_index in &allow_indexs[allow_start_index..] {
match allow_index.cmp(&actual_index) {
Ordering::Equal => {
finded.push(ele.cloned());
allow_start_index += 1;
break;
}
Ordering::Less => {
allow_start_index += 1;
}
Ordering::Greater => {
break;
}
}
if allow_start_index >= allow_indexs_total {
break 'loop_sibling;
}
}
start_index = actual_index + 1;
break;
}
}
}
}
finded
},
)
} else {
Box::new(
|eles: &Elements, range: &Range<usize>, allow_indexs: &[usize], childs: &Elements| {
let childs = childs.get_ref();
let total = childs.len();
let mut finded: Vec<BoxDynElement> = Vec::with_capacity(allow_indexs.len());
if range.len() == total {
for &index in allow_indexs.iter().rev() {
finded.push(childs[total - index - 1].cloned());
}
} else {
let eles = eles.get_ref();
let siblings = &eles[range.start..range.end];
let mut cur_end = range.len();
for (index, child) in childs.iter().rev().enumerate() {
if allow_indexs.binary_search(&index).is_err() {
continue;
}
for (i, ele) in siblings[..cur_end].iter().rev().enumerate() {
if child.is(ele) {
cur_end -= i + 1;
finded.push(ele.cloned());
break;
}
}
if cur_end == 0 {
break;
}
}
finded.reverse();
}
finded
},
)
}
}
fn handle_nth_child<'r>(
data: &SiblingsNodeData,
eles: &Elements<'r>,
result: &mut Elements<'r>,
handle: &NthChildHandle,
) {
let allow_indexs = data.allow_indexs.as_ref().expect("allow indexs must set");
if allow_indexs.is_empty() {
return;
}
let childs = data
.parent
.as_ref()
.expect("parent must set in callback")
.children();
let finded = handle(eles, &data.range, allow_indexs, &childs);
result.get_mut_ref().extend(finded);
}
fn make_asc_or_desc_nth_child(selector: &'static str, asc: bool) -> RuleDefItem {
let name = selector;
RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |data: MatchedQueue| {
let nth_data = &data[2].data;
let n = nth_data.get("n").map(|s| s.clone());
let index = nth_data.get("index").map(|s| s.clone());
let handle = make_asc_or_desc_nth_child_handle(asc);
let specified_handle = if n.is_none() {
let index = nth_index_to_number(&index);
Some(make_asc_or_desc_nth_child_specified(asc, index))
} else {
None
};
Matcher {
all_handle: Some(Box::new(move |eles: &Elements, is_all| {
let mut result: Elements = Elements::with_capacity(DEF_NODES_LEN);
if is_all.is_none() {
group_siblings_then_done(
eles,
|total: usize| Some(Nth::get_allowed_indexs(&n, &index, total)),
|data: &mut SiblingsNodeData| {
handle_nth_child(data, eles, &mut result, &handle);
},
);
} else {
let total = eles.length();
let range = 0..total;
let allow_indexs = Nth::get_allowed_indexs(&n, &index, total);
let finded = handle(eles, &range, &allow_indexs, eles);
result.get_mut_ref().extend(finded);
}
result
})),
specified_handle,
..Default::default()
}
}),
)
}
fn pseudo_nth_child(rules: &mut Vec<RuleItem>) {
let rule = make_asc_or_desc_nth_child(":nth-child({spaces}{nth}{spaces})", true);
rules.push(rule.into());
}
fn pseudo_nth_last_child(rules: &mut Vec<RuleItem>) {
let rule = make_asc_or_desc_nth_child(":nth-last-child({spaces}{nth}{spaces})", false);
rules.push(rule.into());
}
fn make_first_or_last_child(selector: &'static str, asc: bool) -> RuleDefItem {
let name = selector;
RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |_| {
let handle = make_asc_or_desc_nth_child_handle(asc);
let specified_handle = Some(make_asc_or_desc_nth_child_specified(asc, 1));
Matcher {
all_handle: Some(Box::new(move |eles, _| {
let mut result: Elements = Elements::with_capacity(DEF_NODES_LEN);
group_siblings_then_done(
eles,
|_| Some(vec![0]),
|data: &mut SiblingsNodeData| {
handle_nth_child(data, eles, &mut result, &handle);
},
);
result
})),
specified_handle,
..Default::default()
}
}),
)
}
fn pseudo_first_child(rules: &mut Vec<RuleItem>) {
let rule = make_first_or_last_child(":first-child", true);
rules.push(rule.into());
}
fn pseudo_last_child(rules: &mut Vec<RuleItem>) {
let rule = make_first_or_last_child(":last-child", false);
rules.push(rule.into());
}
type NameCounterHashMap = HashMap<String, usize>;
fn get_allowed_name_ele(
ele: &dyn IElementTrait,
names: &mut NameCounterHashMap,
allow_indexs: &[usize],
node_indexs: &mut Vec<usize>,
) -> bool {
let name = ele.tag_name();
if let Some(index) = names.get_mut(&name) {
*index += 1;
if allow_indexs.binary_search(index).is_ok() {
node_indexs.push(ele.index());
return true;
}
} else {
let index = 0;
names.insert(name, index);
if allow_indexs[0] == 0 {
node_indexs.push(ele.index());
return true;
}
}
false
}
fn collect_avail_name_eles(
node_indexs: &mut [usize],
siblings: &[BoxDynElement],
finded: &mut Vec<BoxDynElement>,
) {
let av_total = node_indexs.len();
if av_total > 0 {
let mut av_index = 0;
let sib_total = siblings.len();
let mut sib_index = 0;
while av_index < av_total && sib_index < sib_total {
let cur_avail_index = node_indexs[av_index];
av_index += 1;
for ele in &siblings[sib_index..] {
let cur_sib_index = ele.index();
match cur_sib_index.cmp(&cur_avail_index) {
Ordering::Equal => {
finded.push(ele.cloned());
sib_index += 1;
break;
}
Ordering::Greater => {
break;
}
Ordering::Less => {
sib_index += 1;
}
}
}
}
}
}
fn make_asc_or_desc_nth_of_type_specified(asc: bool, index: isize) -> MatchSpecifiedHandle {
if index > 0 {
let allow_indexs = vec![(index - 1) as usize];
if asc {
Box::new(move |ele, mut callback| {
let mut names: NameCounterHashMap = HashMap::with_capacity(DEF_NODES_LEN);
let mut node_indexs: Vec<usize> = Vec::with_capacity(DEF_NODES_LEN);
ele.child_nodes_item_since_by(
0,
false,
Box::new(|child| {
let is_matched =
get_allowed_name_ele(child, &mut names, &allow_indexs, &mut node_indexs);
callback(child, is_matched, true);
true
}),
);
})
} else {
Box::new(move |ele, mut callback| {
let mut names: NameCounterHashMap = HashMap::with_capacity(DEF_NODES_LEN);
let mut node_indexs: Vec<usize> = Vec::with_capacity(DEF_NODES_LEN);
let total = ele.child_nodes_length();
let mut matched: VecDeque<bool> = VecDeque::with_capacity(total);
ele.child_nodes_item_since_by(
total - 1,
true,
Box::new(|child| {
let is_matched =
get_allowed_name_ele(child, &mut names, &allow_indexs, &mut node_indexs);
matched.push_front(is_matched);
true
}),
);
let mut loop_index: usize = 0;
ele.child_nodes_item_since_by(
0,
false,
Box::new(|child| {
callback(child, matched[loop_index], true);
loop_index += 1;
true
}),
);
})
}
} else {
Box::new(|_, _| {})
}
}
fn handle_nth_of_type(asc: bool, data: &SiblingsNodeData, eles: &Elements, result: &mut Elements) {
let allow_indexs = data
.allow_indexs
.as_ref()
.expect("Nth allow indexs must have");
if allow_indexs.is_empty() {
return;
}
let childs = data
.parent
.as_ref()
.expect("parent must set in callback")
.children();
let mut names: NameCounterHashMap = HashMap::with_capacity(DEF_NODES_LEN);
let mut node_indexs: Vec<usize> = Vec::with_capacity(childs.length());
let range = &data.range;
let eles = eles.get_ref();
let siblings = &eles[range.start..range.end];
if asc {
for child in childs.get_ref() {
get_allowed_name_ele(&**child, &mut names, allow_indexs, &mut node_indexs);
}
} else {
for child in childs.get_ref().iter().rev() {
get_allowed_name_ele(&**child, &mut names, allow_indexs, &mut node_indexs);
}
node_indexs.reverse();
}
collect_avail_name_eles(&mut node_indexs, siblings, result.get_mut_ref());
}
fn make_asc_or_desc_nth_of_type(selector: &'static str, asc: bool) -> RuleDefItem {
let name = selector;
RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |mut data: MatchedQueue| {
let nth_data = data.remove(2).data;
let n = nth_data.get("n").map(|s| s.clone());
let index = nth_data.get("index").map(|s| s.clone());
let specified_handle = if n.is_none() {
let index = nth_index_to_number(&index);
Some(make_asc_or_desc_nth_of_type_specified(asc, index))
} else {
None
};
Matcher {
all_handle: Some(Box::new(move |eles: &Elements, is_all| {
let mut result: Elements = Elements::with_capacity(DEF_NODES_LEN);
if is_all.is_none() {
group_siblings_then_done(
eles,
|total: usize| Some(Nth::get_allowed_indexs(&n, &index, total)),
|data: &mut SiblingsNodeData| {
handle_nth_of_type(asc, data, eles, &mut result);
},
);
} else {
let total = eles.length();
let allow_indexs = Some(Nth::get_allowed_indexs(&n, &index, total));
let parent = if total > 0 {
eles.get(0).expect("length > 0").parent()
} else {
None
};
let data = SiblingsNodeData {
range: 0..total,
allow_indexs,
parent,
};
handle_nth_of_type(asc, &data, eles, &mut result);
}
result
})),
specified_handle,
..Default::default()
}
}),
)
}
fn pseudo_nth_of_type(rules: &mut Vec<RuleItem>) {
let rule = make_asc_or_desc_nth_of_type(":nth-of-type({spaces}{nth}{spaces})", true);
rules.push(rule.into());
}
fn pseudo_nth_last_of_type(rules: &mut Vec<RuleItem>) {
let rule = make_asc_or_desc_nth_of_type(":nth-last-of-type({spaces}{nth}{spaces})", false);
rules.push(rule.into());
}
fn make_first_or_last_of_type(selector: &'static str, asc: bool) -> RuleDefItem {
let name = selector;
RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |_| {
let specified_handle = Some(make_asc_or_desc_nth_of_type_specified(asc, 1));
Matcher {
all_handle: Some(Box::new(move |eles: &Elements, _| {
let mut result: Elements = Elements::with_capacity(DEF_NODES_LEN);
group_siblings_then_done(
eles,
|_: usize| Some(vec![0]),
|data: &mut SiblingsNodeData| {
handle_nth_of_type(asc, data, eles, &mut result);
},
);
result
})),
specified_handle,
..Default::default()
}
}),
)
}
fn pseudo_first_of_type(rules: &mut Vec<RuleItem>) {
let rule = make_first_or_last_of_type(":first-of-type", true);
rules.push(rule.into());
}
fn pseudo_last_of_type(rules: &mut Vec<RuleItem>) {
let rule = make_first_or_last_of_type(":last-of-type", false);
rules.push(rule.into());
}
fn pseudo_only_child(rules: &mut Vec<RuleItem>) {
let selector = ":only-child";
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |_| Matcher {
all_handle: Some(Box::new(|eles: &Elements, _| {
let mut result = Elements::with_capacity(DEF_NODES_LEN);
let mut prev_parent: Option<BoxDynElement> = None;
for ele in eles.get_ref() {
if let Some(parent) = ele.parent() {
if let Some(prev_parent) = &prev_parent {
if prev_parent.is(&parent) {
continue;
}
}
let child_nodes = parent.child_nodes();
let mut count = 0;
for node in &child_nodes {
if matches!(node.node_type(), INodeType::Element) {
count += 1;
if count > 1 {
break;
}
}
}
if count == 1 {
result.push(ele.cloned());
}
prev_parent = Some(parent);
}
}
result
})),
..Default::default()
}),
);
rules.push(rule.into());
}
fn pseudo_only_of_type(rules: &mut Vec<RuleItem>) {
let selector = ":only-of-type";
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |_| Matcher {
all_handle: Some(Box::new(|eles: &Elements, _| {
let mut result = Elements::with_capacity(DEF_NODES_LEN);
group_siblings_then_done(
eles,
|_| None,
|data: &mut SiblingsNodeData| {
let childs = data
.parent
.as_ref()
.expect("parent must set in callback")
.children();
let eles = eles.get_ref();
let range = &data.range;
let siblings = &eles[range.start..range.end];
let mut only_names: Vec<(String, usize)> = Vec::with_capacity(DEF_NODES_LEN);
let mut repeated: Vec<String> = Vec::with_capacity(DEF_NODES_LEN);
for (index, child) in childs.get_ref().iter().enumerate() {
let name = child.tag_name();
if !repeated.contains(&name) {
let find_index = only_names
.iter()
.position(|(tag_name, _)| tag_name == &name);
if let Some(index) = find_index {
repeated.push(name);
only_names.remove(index);
} else {
only_names.push((name, index));
}
}
}
if !only_names.is_empty() {
let finded = result.get_mut_ref();
if siblings.len() == childs.length() {
for (_, index) in &only_names {
finded.push(siblings[*index].cloned());
}
} else {
let mut cur_index = 0;
for (name, _) in &only_names {
for (index, ele) in siblings[cur_index..].iter().enumerate() {
if &ele.tag_name() == name {
cur_index += index + 1;
finded.push(ele.cloned());
break;
}
}
}
}
}
},
);
result
})),
..Default::default()
}),
);
rules.push(rule.into());
}
fn pseudo_not(rules: &mut Vec<RuleItem>) {
let name = ":not";
let selector = ":not({spaces}{selector}{spaces})";
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(|data: MatchedQueue| {
let selector = data[2].chars.iter().collect::<String>();
Matcher {
all_handle: Some(Box::new(move |eles: &Elements, _| eles.not(&selector))),
..Default::default()
}
}),
);
rules.push(rule.into());
}
fn pseudo_contains(rules: &mut Vec<RuleItem>) {
let name = ":contains";
let selector = r##":contains({spaces}{regexp#(?:'((?:\\?+.)*?)'|"((?:\\?+.)*?)"|([^)\s'"<>/=`]*))#}{spaces})"##;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(|mut data: MatchedQueue| {
let mut find_chars = data.remove(2).chars;
if !find_chars.is_empty() {
let first = find_chars[0];
let search = if first == '"' || first == '\'' {
find_chars.pop();
find_chars.split_off(1)
} else {
find_chars
};
Matcher {
one_handle: Some(Box::new(move |ele, _| {
let contents = ele.text_contents();
contains_chars(&contents, &search)
})),
..Default::default()
}
} else {
Matcher {
one_handle: Some(Box::new(move |_, _| true)),
..Default::default()
}
}
}),
);
rules.push(rule.into());
}
fn pseudo_has(rules: &mut Vec<RuleItem>) {
let name = ":has";
let selector = ":has({spaces}{selector}{spaces})";
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(|data: MatchedQueue| {
let selector = data[2].chars.iter().collect::<String>();
Matcher {
all_handle: Some(Box::new(move |eles: &Elements, _| eles.has(&selector))),
..Default::default()
}
}),
);
rules.push(rule.into());
}
fn pseudo_checked(rules: &mut Vec<RuleItem>) {
let selector = ":checked";
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(|_| Matcher {
one_handle: Some(Box::new(|ele, _| {
let tag_name = ele.tag_names();
let input_tag = ['i', 'n', 'p', 'u', 't'];
let option_tag = ['o', 'p', 't', 'i', 'o', 'n'];
let select_tag = ['s', 'e', 'l', 'e', 'c', 't'];
if is_equal_chars(&tag_name, &input_tag) {
if let Some(IAttrValue::Value(input_type, _)) = ele.get_attribute("type") {
let lower_input_type = input_type.to_ascii_lowercase();
if lower_input_type == "checkbox" || lower_input_type == "radio" {
return ele.has_attribute("checked");
}
}
false
} else if is_equal_chars(&tag_name, &option_tag) {
let is_selected = ele.has_attribute("selected");
if is_selected {
true
} else {
if let Some(parent) = &ele.parent() {
if is_equal_chars(&parent.tag_names(), &select_tag)
&& !parent.has_attribute("multiple")
{
let mut prev = ele.previous_element_sibling();
while let Some(prev_ele) = &prev {
if is_equal_chars(&prev_ele.tag_names(), &option_tag) {
return false;
}
prev = prev_ele.previous_element_sibling();
}
fn check_selected_option(ele: &BoxDynElement, option_tag: &[char]) -> bool {
if is_equal_chars(&ele.tag_names(), option_tag) {
return ele.has_attribute("selected");
} else {
let total = ele.child_nodes_length();
for index in 0..total {
let node = ele
.child_nodes_item(index)
.expect("Child nodes item index must less than total");
if matches!(node.node_type(), INodeType::Element) {
let child = node
.typed()
.into_element()
.expect("Call `typed` for element ele.");
if check_selected_option(&child, option_tag) {
return true;
}
}
}
}
false
}
let mut next = ele.next_element_sibling();
while let Some(next_ele) = &next {
if check_selected_option(next_ele, &option_tag) {
return false;
}
next = next_ele.next_element_sibling();
}
return true;
}
}
false
}
} else {
false
}
})),
..Default::default()
}),
);
rules.push(rule.into());
}
fn pseudo_alias_header(rules: &mut Vec<RuleItem>) {
let (selector, alias) = SELECTOR_ALIAS_NAME_HEADER;
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |_| Rule::make_alias(alias)),
);
rules.push(rule.into());
}
fn pseudo_alias_input(rules: &mut Vec<RuleItem>) {
let (selector, alias) = SELECTOR_ALIAS_NAME_INPUT;
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |_| Rule::make_alias(alias)),
);
rules.push(rule.into());
}
fn pseudo_alias_submit(rules: &mut Vec<RuleItem>) {
let (selector, alias) = SELECTOR_ALIAS_NAME_SUBMIT;
let name = selector;
let rule = RuleDefItem(
name,
selector,
PRIORITY,
Box::new(move |_| Rule::make_alias(alias)),
);
rules.push(rule.into());
}
pub fn init(rules: &mut Vec<RuleItem>) {
pseudo_root(rules);
pseudo_empty(rules);
pseudo_first_child(rules);
pseudo_last_child(rules);
pseudo_only_child(rules);
pseudo_nth_child(rules);
pseudo_nth_last_child(rules);
pseudo_first_of_type(rules);
pseudo_last_of_type(rules);
pseudo_nth_of_type(rules);
pseudo_nth_last_of_type(rules);
pseudo_only_of_type(rules);
pseudo_not(rules);
pseudo_contains(rules);
pseudo_has(rules);
pseudo_checked(rules);
pseudo_alias_header(rules);
pseudo_alias_input(rules);
pseudo_alias_submit(rules);
}