From fa542c2806311341a001b859fea6f34bd79412aa Mon Sep 17 00:00:00 2001 From: YagUber Date: Mon, 14 Sep 2026 15:16:32 -0500 Subject: [PATCH] fix(parser): do not mangle preprocessor directives --- abp/filters/parser.py | 6 ++++++ tests/test_parser.py | 24 ++++++++++++++++++++++++ tests/test_renderer.py | 9 +++++++++ 3 files changed, 39 insertions(+) diff --git a/abp/filters/parser.py b/abp/filters/parser.py index d190e58..be9a8e7 100644 --- a/abp/filters/parser.py +++ b/abp/filters/parser.py @@ -184,6 +184,7 @@ def _line_type(name, field_names, format_string): Header = _line_type("Header", "version", "[{.version}]") EmptyLine = _line_type("EmptyLine", "", "") Comment = _line_type("Comment", "text", "! {.text}") +Preprocessor = _line_type("Preprocessor", "text", "!#{.text}") Metadata = _line_type("Metadata", "key value", "! {0.key}: {0.value}") Filter = _line_type("Filter", "text selector action options", "{.text}") Include = _line_type("Include", "target", "%include {0.target}%") @@ -414,6 +415,11 @@ def parse_line(line, position="body"): if match: return Header(match.group(1)) + if stripped.startswith("!#"): + directive = stripped[2:] + if directive and not directive[:1].isspace(): + return Preprocessor(directive) + if stripped.startswith("!"): match = METADATA_REGEXP.match(line) if match: diff --git a/tests/test_parser.py b/tests/test_parser.py index 9686024..7d5d075 100644 --- a/tests/test_parser.py +++ b/tests/test_parser.py @@ -176,6 +176,30 @@ def test_parse_filters(filter_text, expected): assert getattr(parsed, attribute) == expected_value +@pytest.mark.parametrize("text", [ + "!#if (foo || bar)", + "!#else", + "!#endif", + "!#include my_filter.txt", +]) +def test_parse_preprocessor_directive(text): + line = parse_line(text) + assert line.type == "preprocessor" + assert line.to_string() == text + + +def test_parse_bad_preprocessor_directive(): + line = parse_line("! #if bar") + assert line.type == "comment" + assert line.to_string() == "! #if bar" + + +def test_parse_bare_directive_as_comment(): + line = parse_line("!#") + assert line.type == "comment" + assert line.to_string() == "! #" + + def test_parse_comment(): line = parse_line("! Block foo") assert line.type == "comment" diff --git a/tests/test_renderer.py b/tests/test_renderer.py index 0595031..07fc773 100644 --- a/tests/test_renderer.py +++ b/tests/test_renderer.py @@ -122,3 +122,12 @@ def test_remove_checksum(head): src = MockSource(fl="[Adblock]\n! Comment\n! Checksum: foo") got = render_str("fl", {}, src) assert got == head + "! Comment" + + +def test_preprocessor_directives(head): + src = MockSource( + fl="[Adblock]\n%include fragment%", + fragment="!#if foo\n||example.com^\n!#endif", + ) + got = render_str("fl", {}, src) + assert "!#if foo\n||example.com^\n!#endif" in got