node_html_parser/css_select/
compile.rs

1use super::convert::selector_to_internal;
2use super::helpers::selectors::{is_traversal, sort_rules};
3use super::legacy::{apply_selector_from_el, parse_selector_list_public};
4use super::types::{Adapter, CompiledQuery, Options};
5use crate::css_select::general::compile_general_selector;
6use crate::css_select::types::InternalSelector;
7use crate::dom::element::HTMLElement;
8
9// 兼容旧实现:仍保留 legacy 后端 (稳定可靠),新管线逐步接入。
10// compile_token 继续走 legacy,防止现有对外 API 行为突变。
11pub fn compile_token<'a, A: Adapter>(
12	selector: &str,
13	_options: &Options<A>,
14	root: &'a HTMLElement,
15) -> CompiledQuery<'a, A> {
16	let legacy_list = parse_selector_list_public(selector);
17	CompiledQuery::new(move |el: &A::HTMLElement| {
18		let real = el as *const A::HTMLElement as *const HTMLElement;
19		let real_ref = unsafe { &*real };
20		for sel in &legacy_list {
21			if apply_selector_from_el(root, real_ref, sel) {
22				return true;
23			}
24		}
25		false
26	})
27}
28
29// ----------------------------- 新编译管线 (试验性) -----------------------------
30// 说明:
31// 1. 使用 legacy 解析 -> convert.rs 生成 InternalSelector 序列。
32// 2. 对每条序列按 traversal 边界分组并对组内 simple selectors 调用 sort_rules。
33// 3. 按顺序调用 compile_general_selector 构建谓词链。
34// 4. 多条 selector 之间 OR 组合。
35// 5. 暂未实现 :nth-* / 复杂伪类 runtime,相关伪类会在 general.rs 中返回 false(除 :empty)。
36
37fn reorder_with_sort(seq: &[InternalSelector]) -> Vec<InternalSelector> {
38	let mut out: Vec<InternalSelector> = Vec::with_capacity(seq.len());
39	let mut buffer: Vec<InternalSelector> = Vec::new();
40	for tok in seq {
41		if is_traversal(tok) {
42			if !buffer.is_empty() {
43				sort_rules(&mut buffer);
44				out.extend(buffer.drain(..));
45			}
46			out.push(tok.clone());
47		} else {
48			buffer.push(tok.clone());
49		}
50	}
51	if !buffer.is_empty() {
52		sort_rules(&mut buffer);
53		out.extend(buffer.drain(..));
54	}
55	out
56}
57
58pub fn compile_internal_new<'a, A: Adapter + 'a>(
59	selector: &str,
60	adapter: &'a A,
61) -> CompiledQuery<'a, A> {
62	let parsed = parse_selector_list_public(selector);
63	if parsed.is_empty() {
64		return CompiledQuery::new(|_| false);
65	}
66
67	// 针对每个逗号分隔 selector 构建一条链,最后 OR。
68	let mut chains: Vec<Box<dyn Fn(&A::HTMLElement) -> bool + 'a>> = Vec::new();
69	for sel in parsed {
70		let internal_groups = selector_to_internal(&sel); // Vec<Vec<InternalSelector>>; 当前每个 sel 只返回单一序列
71		for seq in internal_groups {
72			if seq.is_empty() {
73				continue;
74			}
75			// 相对选择器绝对化(简化版):若未出现 scope 且首 token 非 traversal,则在链前插入 :scope Descendant
76			let mut seq_work = seq.clone();
77			let has_scope = seq_work
78				.iter()
79				.any(|t| matches!(t, InternalSelector::Pseudo { name, .. } if name == "scope"));
80			if !has_scope {
81				if !seq_work.first().map(|t| is_traversal(t)).unwrap_or(false) {
82					seq_work.insert(0, InternalSelector::Descendant); // descendant between scope & rest
83					seq_work.insert(
84						0,
85						InternalSelector::Pseudo {
86							name: "scope".into(),
87							data: crate::css_select::types::PseudoData::None,
88						},
89					);
90				}
91			}
92			let reordered = reorder_with_sort(&seq_work);
93			let mut next: Box<dyn Fn(&A::HTMLElement) -> bool + 'a> = Box::new(|_| true);
94			for token in reordered.iter() {
95				next = compile_general_selector(next, token, adapter);
96				// 若某环节已成为永真 (未变化) 或永假 (目前不会出现) 可做早期优化,暂略。
97			}
98			chains.push(next);
99		}
100	}
101	if chains.is_empty() {
102		return CompiledQuery::new(|_| false);
103	}
104	let combined = move |el: &A::HTMLElement| {
105		for f in &chains {
106			if f(el) {
107				return true;
108			}
109		}
110		false
111	};
112	CompiledQuery::new(combined)
113}