xarxaprod-wp-theme/vendor/mck89/peast/lib/Peast/Selector/Node/Combinator.php

139 lines
3.8 KiB
PHP

<?php
/**
* This file is part of the Peast package
*
* (c) Marco Marchiò <marco.mm89@gmail.com>
*
* For the full copyright and license information refer to the LICENSE file
* distributed with this source code
*/
namespace Peast\Selector\Node;
use Peast\Selector\Matches;
use Peast\Syntax\Utils;
use Peast\Traverser;
/**
* Selector combinator class
*
* @author Marco Marchiò <marco.mm89@gmail.com>
*/
class Combinator
{
/**
* Operator
*
* @var string|null
*/
protected $operator;
/**
* Selector parts
*
* @var Part\Part[]
*/
protected $parts = array();
/**
* Sets the operator
*
* @param string $operator Operator
* @return $this
*/
public function setOperator($operator)
{
$this->operator = $operator;
return $this;
}
/**
* Adds a new selector part
*
* @param Part\Part $part Part
* @return $this
*/
public function addPart(Part\Part $part)
{
$this->parts[] = $part;
return $this;
}
/**
* Executes the current group on the given matches
*
* @param Matches $matches Matches
*/
public function exec(Matches $matches)
{
$parts = $this->parts;
//Sort the parts by priority to execute faster checks first
usort($parts, function ($p1, $p2) {
$pr1 = $p1->getPriority();
$pr2 = $p2->getPriority();
if ($pr1 === $pr2) {
return 0;
} elseif ($pr1 < $pr2) {
return -1;
} else {
return 1;
}
});
$filter = function ($node, $parent) use ($parts) {
foreach ($parts as $part) {
if (!$part->check($node, $parent)) {
return false;
}
}
return true;
};
switch ($this->operator) {
case " ":
case ">":
$children = $this->operator === ">";
$matches->map(function ($curNode) use ($filter, $children) {
$ret = array();
$curNode->traverse(
function ($node, $parent) use ($filter, $children, &$ret) {
if ($filter($node, $parent)) {
$ret[] = array($node, $parent);
}
if ($children) {
return Traverser::DONT_TRAVERSE_CHILD_NODES;
}
},
array(
"skipStartingNode" => true,
"passParentNode" => true
)
);
return $ret;
});
break;
case "~":
case "+":
$adjacent = $this->operator === "+";
$matches->map(function ($node, $parent) use ($filter, $adjacent) {
$ret = array();
$evaluate = false;
$props = $parent ? Utils::getExpandedNodeProperties($parent) : array();
foreach ($props as $propNode) {
if ($evaluate) {
if ($propNode && $filter($propNode, $parent)) {
$ret[] = array($propNode, $parent);
}
if ($adjacent) {
break;
}
} elseif ($propNode === $node) {
$evaluate = true;
}
}
return $ret;
});
break;
default:
$matches->filter($filter);
break;
}
}
}