node_html_parser/css_select/
convert.rs1use crate::css_select::legacy::{AttrOp, Combinator, CompoundSelector, Pseudo, Selector};
2use crate::css_select::types::{AttributeAction, AttributeSelector, InternalSelector, PseudoData};
3
4fn simple_pseudo(name: &str) -> InternalSelector {
9 InternalSelector::Pseudo {
10 name: name.into(),
11 data: PseudoData::None,
12 }
13}
14
15fn compound_to_internal(comp: &CompoundSelector) -> Vec<InternalSelector> {
17 let mut out = Vec::new();
18 if let Some(tag) = &comp.tag {
19 out.push(InternalSelector::Tag { name: tag.clone() });
20 }
21 if let Some(id) = &comp.id {
22 out.push(InternalSelector::Attribute(AttributeSelector {
23 name: "id".into(),
24 action: AttributeAction::Equals,
25 value: Some(id.clone()),
26 ignore_case: false,
27 }));
28 }
29 for cls in &comp.classes {
30 out.push(InternalSelector::Attribute(AttributeSelector {
31 name: "class".into(),
32 action: AttributeAction::Element,
33 value: Some(cls.clone()),
34 ignore_case: false,
35 }));
36 }
37 for a in &comp.attrs {
38 let action = match a.op {
39 AttrOp::Exists => AttributeAction::Exists,
40 AttrOp::Eq => AttributeAction::Equals,
41 AttrOp::Prefix => AttributeAction::Start,
42 AttrOp::Suffix => AttributeAction::End,
43 AttrOp::Substr => AttributeAction::Any,
44 AttrOp::Includes => AttributeAction::Element,
45 AttrOp::Dash => AttributeAction::Hyphen,
46 };
47 out.push(InternalSelector::Attribute(AttributeSelector {
48 name: a.name.clone(),
49 action,
50 value: if matches!(a.op, AttrOp::Exists) {
51 None
52 } else {
53 Some(a.value.clone())
54 },
55 ignore_case: matches!(a.case, crate::css_select::legacy::CaseMode::Insensitive),
56 }));
57 }
58 for p in &comp.pseudos {
59 match p {
60 Pseudo::Not(list) => {
61 let mut groups: Vec<Vec<InternalSelector>> = Vec::new();
62 for sel in list {
63 for seq in selector_to_internal(sel) {
64 groups.push(seq);
65 }
66 }
67 out.push(InternalSelector::Pseudo {
68 name: "not".into(),
69 data: PseudoData::SubSelectors(groups),
70 });
71 }
72 Pseudo::FirstChild => out.push(simple_pseudo("first-child")),
73 Pseudo::LastChild => out.push(simple_pseudo("last-child")),
74 Pseudo::OnlyChild => out.push(simple_pseudo("only-child")),
75 Pseudo::FirstOfType => out.push(simple_pseudo("first-of-type")),
76 Pseudo::LastOfType => out.push(simple_pseudo("last-of-type")),
77 Pseudo::OnlyOfType => out.push(simple_pseudo("only-of-type")),
78 Pseudo::NthChild(expr) => out.push(InternalSelector::Pseudo {
79 name: "nth-child".into(),
80 data: PseudoData::Nth(expr.clone()),
81 }),
82 Pseudo::NthLastChild(expr) => out.push(InternalSelector::Pseudo {
83 name: "nth-last-child".into(),
84 data: PseudoData::Nth(expr.clone()),
85 }),
86 Pseudo::NthOfType(expr) => out.push(InternalSelector::Pseudo {
87 name: "nth-of-type".into(),
88 data: PseudoData::Nth(expr.clone()),
89 }),
90 Pseudo::NthLastOfType(expr) => out.push(InternalSelector::Pseudo {
91 name: "nth-last-of-type".into(),
92 data: PseudoData::Nth(expr.clone()),
93 }),
94 Pseudo::Is(list) => {
95 let mut groups = Vec::new();
96 for sel in list {
97 for seq in selector_to_internal(sel) {
98 groups.push(seq);
99 }
100 }
101 out.push(InternalSelector::Pseudo {
102 name: "is".into(),
103 data: PseudoData::SubSelectors(groups),
104 });
105 }
106 Pseudo::Where(list) => {
107 let mut groups = Vec::new();
108 for sel in list {
109 for seq in selector_to_internal(sel) {
110 groups.push(seq);
111 }
112 }
113 out.push(InternalSelector::Pseudo {
114 name: "where".into(),
115 data: PseudoData::SubSelectors(groups),
116 });
117 }
118 Pseudo::Has(list) => {
119 let mut groups = Vec::new();
120 for sel in list {
121 for seq in selector_to_internal(sel) {
122 groups.push(seq);
123 }
124 }
125 out.push(InternalSelector::Pseudo {
126 name: "has".into(),
127 data: PseudoData::SubSelectors(groups),
128 });
129 }
130 Pseudo::Empty => out.push(simple_pseudo("empty")),
131 Pseudo::Root => out.push(simple_pseudo("root")),
132 Pseudo::Scope => out.push(simple_pseudo("scope")),
133 }
134 }
135 out
136}
137
138pub fn selector_to_internal(sel: &Selector) -> Vec<Vec<InternalSelector>> {
139 let mut seq: Vec<InternalSelector> = Vec::new();
140 let parts = &sel.0;
141 if parts.is_empty() {
142 return vec![seq];
143 }
144 for (idx, (_comb, comp)) in parts.iter().enumerate() {
145 let mut simple_tokens = compound_to_internal(comp);
146 seq.append(&mut simple_tokens);
147 if let Some((Some(next_comb), _)) = parts.get(idx + 1) {
148 let comb_token = match next_comb {
149 Combinator::Descendant => InternalSelector::Descendant,
150 Combinator::Child => InternalSelector::Child,
151 Combinator::Adjacent => InternalSelector::Adjacent,
152 Combinator::Sibling => InternalSelector::Sibling,
153 };
154 seq.push(comb_token);
155 }
156 }
157 vec![seq]
158}