Calculate the specificity based on a CSS Selector string,
Based on the patterns from premailer/css_parser by Alex Dunae

@see https://github.com/premailer/css_parser/blob/master/lib/css_parser/regexps.rb
@param string $selector
@return Specificity
339643
public function calculateSpecificityBasedOnASelector($selector)
    {
        $idSelectorsPattern = "  \#";
        $classAttributesPseudoClassesSelectorsPattern = "  (\.[\w]+)                     # classes
                        |
                        \[(\w+)                       # attributes
                        |
                        (\:(                          # pseudo classes
                          link|visited|active
                          |hover|focus
                          |lang
                          |target
                          |enabled|disabled|checked|indeterminate
                          |root
                          |nth-child|nth-last-child|nth-of-type|nth-last-of-type
                          |first-child|last-child|first-of-type|last-of-type
                          |only-child|only-of-type
                          |empty|contains
                        ))";

        $typePseudoElementsSelectorPattern = "  ((^|[\s\+\>\~]+)[\w]+       # elements
                        |
                        \:{1,2}(                    # pseudo-elements
                          after|before
                          |first-letter|first-line
                          |selection
                        )
                      )";

        return new Specificity(
            preg_match_all("/{$idSelectorsPattern}/ix", $selector, $matches),
            preg_match_all("/{$classAttributesPseudoClassesSelectorsPattern}/ix", $selector, $matches),
            preg_match_all("/{$typePseudoElementsSelectorPattern}/ix", $selector, $matches)
        );
    }
69392
function getSpecificity(selectorText) {
    return specificity
        .calculate(selectorText)[0]
        .specificity
        .split(',')
        .map(function(s) {
            return parseInt(s, 10);
        });
}
426159
public function format($selector)
    {
        $sortedElements = collect($this->elements)->sortByDesc(function ($element, $key) {
            return strlen($key);
        })->toArray();

        $selector = str_replace(
            array_keys($sortedElements), array_values($sortedElements), $originalSelector = $selector
        );

        if (Str::startsWith($selector, '@') && $selector === $originalSelector) {
            $selector = '[dusk="'.explode('@', $selector)[1].'"]';
        }

        return trim($this->prefix.' '.$selector);
    }
689970
public function parse($selector)
    {
        if ('/' === $selector) {
            return array();
        }

        if ('/' !== substr($selector, 0, 1)) {
            throw new \InvalidArgumentException(sprintf(
                'Path "%s" must be absolute',
                $selector
            ));
        }

        $selector = substr($selector, 1);

        $segments = array();
        $elements = explode('/', $selector);

        foreach ($elements as $index => $element) {
            if ($this->processWildcard($element)) {
                $flags = self::T_PATTERN;
            } else {
                $flags = self::T_STATIC;
            }

            if ($index === (count($elements) - 1)) {
                $flags = $flags | self::T_LAST;
            }

            $segments[] = array($element, $flags);
        }

        return $segments;
    }
438839
public function parent(string $selector = "*"): ?Element
    {
        if ($selector === "*") {
            $prefix = "parent";
        } else {
            $prefix = "ancestor";
        }

        $selector = preg_replace("/\.([a-zA-Z0-9_-]+)/", "[contains(@class, '$1')]", $selector);

        return $this->findElement(WebDriverBy::xpath("{$prefix}::{$selector}"));
    }
985227
function(selector) {
        var token = {},     // one token per simple selector (left selector holds combinator)
            tokens = [],    // array of tokens
            id,             // unique id for the simple selector (if found)
            found = false,  // whether or not any matches were found this pass
            patterns = Y.Selector._patterns,
            match;          // the regex match

        selector = Y.Selector._replaceShorthand(selector); // convert ID and CLASS shortcuts to attributes

        /*
            Search for selector patterns, store, and strip them from the selector string
            until no patterns match (invalid selector) or we run out of chars.

            Multiple attributes and pseudos are allowed, in any order.
            for example:
                'form:first-child[type=button]:not(button)[lang|=en]'
        */
        do {
            found = false; // reset after full pass
            for (var re in patterns) {
                if (YAHOO.lang.hasOwnProperty(patterns, re)) {
                    if (re != 'tag' && re != 'combinator') { // only one allowed
                        token[re] = token[re] || [];
                    }
                    if ( (match = patterns[re].exec(selector)) ) { // note assignment
                        found = true;
                        if (re != 'tag' && re != 'combinator') { // only one allowed
                            // capture ID for fast path to element
                            if (re === 'attributes' && match[1] === 'id') {
                                token.id = match[3];
                            }

                            token[re].push(match.slice(1));
                        } else { // single selector (tag, combinator)
                            token[re] = match[1];
                        }
                        selector = selector.replace(match[0], ''); // strip current match from selector
                        if (re === 'combinator' || !selector.length) { // next token or done
                            token.attributes = Y.Selector._fixAttributes(token.attributes);
                            token.pseudos = token.pseudos || [];
                            token.tag = token.tag ? token.tag.toUpperCase() : '*';
                            tokens.push(token);

                            token = { // prep next token
                                previous: token
                            };
                        }
                    }
                }
            }
        } while (found);

        return tokens;
    }
862480
function calculateSpecificity(selector) {
  var specificity = [0, 0, 0, 0];

  // Cannot use RegExp literals for all regular expressions, IE does not accept
  // the syntax.

  // Matches a backslash followed by six hexadecimal digits followed by an
  // optional single whitespace character.
  var escapeHexadecimalRegex = new RegExp('\\\\[0-9A-Fa-f]{6}\\s?', 'g');
  // Matches a backslash followed by fewer than six hexadecimal digits
  // followed by a mandatory single whitespace character.
  var escapeHexadecimalRegex2 = new RegExp('\\\\[0-9A-Fa-f]{1,5}\\s', 'g');
  // Matches a backslash followed by any character
  var escapeSpecialCharacter = /\\./g;
  selector = replaceWithPlainText(selector, escapeHexadecimalRegex);
  selector = replaceWithPlainText(selector, escapeHexadecimalRegex2);
  selector = replaceWithPlainText(selector, escapeSpecialCharacter);

  // Remove the negation pseudo-class (:not) but leave its argument because
  // specificity is calculated on its argument.
  var pseudoClassWithNotRegex = new RegExp(':not\\(([^\\)]*)\\)', 'g');
  selector = selector.replace(pseudoClassWithNotRegex, '     $1 ');

  // Remove anything after a left brace in case a user has pasted in a rule,
  // not just a selector.
  var rulesRegex = new RegExp('{[^]*', 'gm');
  selector = selector.replace(rulesRegex, '');

  // The following regular expressions assume that selectors matching the
  // preceding regular expressions have been removed.

  // SPECIFICITY 2: Counts attribute selectors.
  var attributeRegex = new RegExp('(\\[[^\\]]+\\])', 'g');
  selector = replaceWithEmptyText(selector, specificity, attributeRegex, 2);

  // SPECIFICITY 1: Counts ID selectors.
  var idRegex = new RegExp('(#[^\\#\\s\\+>~\\.\\[:]+)', 'g');
  selector = replaceWithEmptyText(selector, specificity, idRegex, 1);

  // SPECIFICITY 2: Counts class selectors.
  var classRegex = new RegExp('(\\.[^\\s\\+>~\\.\\[:]+)', 'g');
  selector = replaceWithEmptyText(selector, specificity, classRegex, 2);

  // SPECIFICITY 3: Counts pseudo-element selectors.
  var pseudoElementRegex =
      /(::[^\s\+>~\.\[:]+|:first-line|:first-letter|:before|:after)/gi;
  selector = replaceWithEmptyText(selector, specificity, pseudoElementRegex, 3);

  // SPECIFICITY 2: Counts pseudo-class selectors.
  // A regex for pseudo classes with brackets. For example:
  //   :nth-child()
  //   :nth-last-child()
  //   :nth-of-type()
  //   :nth-last-type()
  //   :lang()
  var pseudoClassWithBracketsRegex = /(:[\w-]+\([^\)]*\))/gi;
  selector = replaceWithEmptyText(
      selector, specificity, pseudoClassWithBracketsRegex, 2);
  // A regex for other pseudo classes, which don't have brackets.
  var pseudoClassRegex = /(:[^\s\+>~\.\[:]+)/g;
  selector = replaceWithEmptyText(selector, specificity, pseudoClassRegex, 2);

  // Remove universal selector and separator characters.
  selector = selector.replace(/[\*\s\+>~]/g, ' ');

  // Remove any stray dots or hashes which aren't attached to words.
  // These may be present if the user is live-editing this selector.
  selector = selector.replace(/[#\.]/g, ' ');

  // SPECIFICITY 3: The only things left should be element selectors.
  var elementRegex = /([^\s\+>~\.\[:]+)/g;
  selector = replaceWithEmptyText(selector, specificity, elementRegex, 3);

  return specificity;
}
597183
private function selectFirst($links, $selector)
    {
        $result = array();
        $formats = preg_split('/\s*,\s*/', $selector);

        // has to be in this order
        foreach ($formats as $f) {

            foreach ($links as $l) {

                if (stripos($l['format'], $f) !== false || $f == 'any') {
                    $result[] = $l;
                }
            }
        }

        return $result;
    }
987393
private function convertToParagraph(string $selector): self {
        $nodes = $this->document()->find($selector);

        foreach ($nodes as $node) {
            $tagNodes = $node->find('a, blockquote, dl, div, img, ol, p, pre, table, ul');

            if (!$tagNodes->count()) {
                $this->replaceElementsWithPara($node);
            } else {
                $replacements = $this->getReplacementNodes($node);

                $node->contents()->remove();
                $node->append($replacements);
            }
        }

        return $this;
    }
431024
public function applyRule($selector, $style)
    {
        if($selector) {
            $nodes = $this->_getNodesForCssSelector($selector);
            $style = $this->_styleToArray($style);

            foreach($nodes as $node) {
                $current = $node->hasAttribute("style") ?
                    $this->_styleToArray($node->getAttribute("style")) :
                    array();

                $current = $this->_mergeStyles($current, $style);

                $node->setAttribute("style", $this->_arrayToStyle($current));
            }
        }

        return $this;
    }
122887
public function setSelector( $selector )
    {
        $this->selector = empty( $selector )
            ? self::SELECTOR_ALL
            : (string) $selector;

        $matches = array();

        if ( empty( $this->rootParagraphId ) &&
             preg_match( '/#paragraph-(\d+)/', $selector, $matches ) )
        {
            $this->setRootParagraphId( $matches[1] );
        }

        return $this;
    }
775742
public function filter($selector)
    {
        $converter = $this->createCssSelectorConverter();

        // The CssSelector already prefixes the selector with descendant-or-self::
        return $this->filterRelativeXPath($converter->toXPath($selector));
    }
1110213
public function selectorToXpath($selector, $locator)
    {
        if ('xpath' === $selector) {
            if (!is_string($locator)) {
                throw new \InvalidArgumentException('The xpath selector expects to get a string as locator');
            }

            return $locator;
        }

        return $this->getSelector($selector)->translateToXPath($locator);
    }
563578
public static function cssToXpath($selector, $prefix = '//')
    {
        $paths = [];

        while ($selector !== '') {
            list($xpath, $selector) = static::parseAndConvertSelector($selector, $prefix);

            if (substr($selector, 0, 1) === ',') {
                $selector = trim($selector, ', ');
            }

            $paths[] = $xpath;
        }

        return implode('|', $paths);
    }
847060
function ( selector ) {
            var node = this.element().nextSibling;
            if ( !node ) return;
    
            //comment, text
            if ( node.nodeType == 8 || node.nodeType == 3 && !$B.string.trim(node.data) ) {
                return $B( node ).next( selector );
            } else {
                if ( typeof selector === 'string' ) node = $B.selector.match( node, selector )? node : undefined;
                return node;
            }
        }
834829
public function hasRuleBySelector( $selector ){
		foreach( $this->rules as $rule )
			if( $selector == $rule->getSelector() )
				return TRUE;
		return FALSE;
	}
449145
public function getSpecification($element = '')
    {
        if (isset($element) && $element !== '') {
            $spec = $this->pattern->specification[$this->getOption('doctype')][$element];
        } else {
            $spec = $this->pattern->specification[$this->getOption('doctype')];
        }
        return $spec;
    }