Skip to content

[CssSelector] :where pseudo-class and attribute error #59669

Open
@mho22

Description

@mho22

Symfony version(s) affected

^7.2

Description

Selector [hidden]:where(:is(span)) should return : "descendant-or-self::*[(@hidden) and (name() = 'span')]" but returns : "descendant-or-self::*[(@hidden) or (name() = 'span')]".

Selector [hidden]:where(:not(span)) will affect each descendant and self tag.

How to reproduce

test.php

<?php

require __DIR__ . "/vendor/autoload.php";


use Symfony\Component\CssSelector\CssSelectorConverter;


$converter = new CssSelectorConverter();



$css = "span:where(:is(#foo))";

var_dump( $converter->toXPath( $css ) );
echo "\n\n";


$css = "span:where(:not(#foo))";

var_dump( $converter->toXPath( $css ) );
echo "\n\n";


$css = "[hidden]:where(:is(span))";

var_dump( $converter->toXPath( $css ) );
echo "\n\n";

$css = "[hidden]:where(:not(span))";

var_dump( $converter->toXPath( $css ) );
echo "\n\n";

composer.json

{
    "require": {
        "symfony/css-selector": "^7.2"
    }
}

Returns :

string(37) "descendant-or-self::span[@id = 'foo']"


string(42) "descendant-or-self::span[not(@id = 'foo')]"


string(53) "descendant-or-self::*[(@hidden) or (name() = 'span')]"


string(58) "descendant-or-self::*[(@hidden) or (not(name() = 'span'))]"

Instead of :

string(37) "descendant-or-self::span[@id = 'foo']"


string(42) "descendant-or-self::span[not(@id = 'foo')]"


string(53) "descendant-or-self::*[(@hidden) and (name() = 'span')]"


string(58) "descendant-or-self::*[(@hidden) and (not(name() = 'span'))]"

Possible Solution

This is related to the NodeExtension class translateSpecificityAdjustment method returns 'or' as condition only.

symfony/css-selector/XPath/Extension/NodeExtension.php line 115 :

    public function translateSpecificityAdjustment(Node\SpecificityAdjustmentNode $node, Translator $translator): XPathExpr
    {
        $xpath = $translator->nodeToXPath($node->selector);

        foreach ($node->arguments as $argument) {
            $expr = $translator->nodeToXPath($argument);
            $expr->addNameTest();
            if ($condition = $expr->getCondition()) {
                $xpath->addCondition($condition, 'or');
            }
        }

        return $xpath;
    }

Replacing 'or' with 'and' make this work but 4 other tests are obviously failing now.

I have to dig more into this but I would be glad to suggest a pull request for this if I am not wrong.

Additional Context

Tailwind CSS v4 adds a base selector in file node_modules/tailwindcss/preflight.css line 381 :

[hidden]:where(:not([hidden='until-found'])) {
  display: none !important;
}

When using package CssToInlineStyles to inline Tailwind css classes into a html file, each tag from that file gets an additional display style display : none !important.

Image

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions