andybalholm / cascadia

CSS selector library in Go
BSD 2-Clause "Simplified" License
697 stars 65 forks source link

Fails with has and direct child selector #43

Open ViRb3 opened 4 years ago

ViRb3 commented 4 years ago

Problem

Cascadia seems to fail with the has psudo-class and a direct child selector

From MDN

The following selector matches only elements that directly contain an child: a:has(> img)

Cascadia test

var selectorTests = []selectorTest{
    {
        `<html><a><img></img></a></html>`,
        "a:has(> img)",
        []string{
            "<a><img></img></a>",
        },
    },
        ...
}

Result

selector_test.go:651: error compiling "a:has(> img)": expected identifier, found > instead

Is there any chance to get this implemented? Thanks!

ViRb3 commented 4 years ago

I just noticed an alternative way to do this, using the :scope psuedo-class. According to MDN, equivalent usage would be as follows:

var selected = context.querySelectorAll(':scope > img');

Unfortunately, Cascadia doesn't support this psuedo-class. Is there an existing way to achieve what I want?

andybalholm commented 4 years ago

No, Cascadia has no concept of scope at all. A selector either matches an element or it doesn't. There is no provision for matching an element relative to a given scope. In this sense it's like the Selectors "live profile"—but I copied :has from jQuery.

mitar commented 2 years ago

In the context of goquery it would be really useful if one could do something like:

table.Find(":scope > tbody > tr > th")

To find only th directly under the top-level table, and not find some nested table. But it seems this is currently not possible.

I made an goquery issue as well: https://github.com/PuerkitoBio/goquery/issues/414

mitar commented 2 years ago

I was thinking, :scope in the context of cascadia could just be the node from which the selector starts?

andybalholm commented 2 years ago

Yes, that's what it would be. But Cascadia selectors don't know where they start. The basic interface of the Cascadia package is Matcher:

type Matcher interface {
    Match(n *html.Node) bool
}

A Matcher can be called on to match a node from anywhere in the page, in no particular order. It has no concept of a "starting point".

mitar commented 2 years ago

But it would work for MatchAll and Query.

andybalholm commented 2 years ago

No, because those are implemented as wrappers around Match. Almost everything in Cascadia is built around the Match interface.

Support for scope would require such an extensive rewrite that the result wouldn't really be Cascadia any more. It would be an all-new CSS selector package.

erkie commented 1 year ago

Just so I understand this thread, support for div:has(> article) will not and cannot be support in Cascadias current form?

andybalholm commented 1 year ago

Right.