def compile_attribute_selector(selector: parser.AttributeSelector): name = selector.lower_name operator = selector.operator value = selector.value and selector.value.lower() if operator is None: return lambda el: bool(el.attribute(name)) elif operator == "=": return lambda el: el.attribute(name) == value elif operator == "~=": return lambda el: value in split_whitespace(el.attribute(name)) elif operator == "^=": return lambda el: value and el.attribute(name).startswith(value) elif operator == "$=": return lambda el: value and el.attribute(name).endswith(value) elif operator == "*=": return lambda el: value and value in el.attribute(name) elif operator == "|=": def pipe_equal_matcher(el): v = el.attribute(name) return v == value or (v and v.startswith(value + "-")) return pipe_equal_matcher else: raise parser.SelectorError("Unknown attribute operator", operator)
def compile_node(selector): """ Dynamic dispatch selector nodes. Default behavior is a deny (no match). """ parser.SelectorError("Unknown selector", selector)
def compile_pseudo_class_selector(selector: parser.PseudoClassSelector): name = selector.name if name == "empty": return lambda el: not next(el.children(), 0) elif name in ("root", "hover", "focus", "active", "drop"): return lambda el: name in el.state() else: raise parser.SelectorError("Unknown pseudo-class", name)
def compile_functional_pseudo_class_selector( selector: parser.FunctionalPseudoClassSelector, ): name = selector.name if name not in ("has", "is", "not"): raise parser.SelectorError("Unknown pseudo-class", name) sub_selectors = compile_selector_list(selector.arguments) selector.specificity = max(spec for _, spec in sub_selectors) if name == "has": return lambda el: any( any(sel(c) for sel, _ in sub_selectors) for c in descendants(el)) elif name == "is": return lambda el: any(sel(el) for sel, _ in sub_selectors) elif name == "not": return lambda el: not any(sel(el) for sel, _ in sub_selectors)
def compile_combined_selector(selector: parser.CombinedSelector): left_inside = compile_node(selector.left) if selector.combinator == " ": def left(el): return any(left_inside(e) for e in ancestors(el)) elif selector.combinator == ">": def left(el): p = el.parent() return p is not None and left_inside(p) else: raise parser.SelectorError("Unknown combinator", selector.combinator) right = compile_node(selector.right) return lambda el: right(el) and left(el)