From 8cdd66f29bcf7750ce0317dfe536880d72c09182 Mon Sep 17 00:00:00 2001 From: Guillaume Ayoub Date: Wed, 22 May 2024 19:01:17 +0200 Subject: [PATCH] Fix CSS nesting for nested selectors with comma --- tests/css/test_nesting.py | 2 ++ weasyprint/css/validation/__init__.py | 43 ++++++++++++++++----------- 2 files changed, 27 insertions(+), 18 deletions(-) diff --git a/tests/css/test_nesting.py b/tests/css/test_nesting.py index f3b4630cd..ba05c811e 100644 --- a/tests/css/test_nesting.py +++ b/tests/css/test_nesting.py @@ -13,6 +13,8 @@ 'p { div & { width: 10px } width: 20px }', 'div { & { & { p { & { width: 10px } } } } }', '@media print { div { p { width: 10px } } }', + 'div { em, p { width: 10px } }', + 'p { a, div & { width: 10px } }', )) def test_nesting_block(style): page, = render_pages(''' diff --git a/weasyprint/css/validation/__init__.py b/weasyprint/css/validation/__init__.py index 7bce8a64e..00a433619 100644 --- a/weasyprint/css/validation/__init__.py +++ b/weasyprint/css/validation/__init__.py @@ -149,26 +149,33 @@ def preprocess_declarations(base_url, declarations, prelude=None): # Nested rule. if prelude is None: continue - declaration_prelude = declaration.prelude - if NESTING_SELECTOR in declaration.prelude: - # Replace & selector by parent. - declaration_prelude = [] - for token in declaration.prelude: - if token == NESTING_SELECTOR: - declaration_prelude.extend(is_token) - else: - declaration_prelude.append(token) - else: - # No & selector, prepend parent. - is_token = ( - LiteralToken(1, 1, ':'), - FunctionBlock(1, 1, 'is', prelude)) - declaration_prelude = [ - *is_token, WhitespaceToken(1, 1, ' '), - *declaration.prelude] + declaration_prelude = [] + token_groups = [[]] + for token in declaration.prelude: + if token == ',': + token_groups.append([]) + else: + token_groups[-1].append(token) + for token_group in token_groups: + if NESTING_SELECTOR in token_group: + # Replace & selector by parent. + for token in declaration.prelude: + if token == NESTING_SELECTOR: + declaration_prelude.extend(is_token) + else: + declaration_prelude.append(token) + else: + # No & selector, prepend parent. + is_token = ( + LiteralToken(1, 1, ':'), + FunctionBlock(1, 1, 'is', prelude)) + declaration_prelude.extend([ + *is_token, WhitespaceToken(1, 1, ' '), + *token_group]) + declaration_prelude.append(LiteralToken(1, 1, ',')) yield from preprocess_declarations( base_url, parse_blocks_contents(declaration.content), - declaration_prelude) + declaration_prelude[:-1]) if declaration.type != 'declaration': continue