update lock clucknut
All checks were successful
All checks were successful
This commit is contained in:
@@ -61,7 +61,7 @@ public function render(OutputFormat $outputFormat): string
|
||||
$arguments = ' ' . $arguments;
|
||||
}
|
||||
$result .= "@{$this->type}$arguments{$formatter->spaceBeforeOpeningBrace()}{";
|
||||
$result .= $this->renderRules($outputFormat);
|
||||
$result .= $this->renderDeclarations($outputFormat);
|
||||
$result .= '}';
|
||||
return $result;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
namespace Sabberworm\CSS\RuleSet;
|
||||
|
||||
use Sabberworm\CSS\Comment\Comment;
|
||||
use Sabberworm\CSS\Comment\CommentContainer;
|
||||
use Sabberworm\CSS\CSSElement;
|
||||
use Sabberworm\CSS\CSSList\CSSList;
|
||||
@@ -16,9 +17,10 @@
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
use Sabberworm\CSS\Property\Declaration;
|
||||
use Sabberworm\CSS\Property\KeyframeSelector;
|
||||
use Sabberworm\CSS\Property\Selector;
|
||||
use Sabberworm\CSS\Rule\Rule;
|
||||
use Sabberworm\CSS\Settings;
|
||||
|
||||
/**
|
||||
* This class represents a `RuleSet` constrained by a `Selector`.
|
||||
@@ -30,13 +32,14 @@
|
||||
*
|
||||
* Note that `CSSListItem` extends both `Commentable` and `Renderable`, so those interfaces must also be implemented.
|
||||
*/
|
||||
class DeclarationBlock implements CSSElement, CSSListItem, Positionable, RuleContainer
|
||||
class DeclarationBlock implements CSSElement, CSSListItem, Positionable, DeclarationList
|
||||
{
|
||||
use CommentContainer;
|
||||
use LegacyDeclarationListMethods;
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* @var array<Selector|string>
|
||||
* @var list<Selector>
|
||||
*/
|
||||
private $selectors = [];
|
||||
|
||||
@@ -65,66 +68,15 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ?
|
||||
$comments = [];
|
||||
$result = new DeclarationBlock($parserState->currentLine());
|
||||
try {
|
||||
$selectors = [];
|
||||
$selectorParts = [];
|
||||
$stringWrapperCharacter = null;
|
||||
$functionNestingLevel = 0;
|
||||
$consumedNextCharacter = false;
|
||||
static $stopCharacters = ['{', '}', '\'', '"', '(', ')', ','];
|
||||
do {
|
||||
if (!$consumedNextCharacter) {
|
||||
$selectorParts[] = $parserState->consume(1);
|
||||
}
|
||||
$selectorParts[] = $parserState->consumeUntil($stopCharacters, false, false, $comments);
|
||||
$nextCharacter = $parserState->peek();
|
||||
$consumedNextCharacter = false;
|
||||
switch ($nextCharacter) {
|
||||
case '\'':
|
||||
// The fallthrough is intentional.
|
||||
case '"':
|
||||
if (!\is_string($stringWrapperCharacter)) {
|
||||
$stringWrapperCharacter = $nextCharacter;
|
||||
} elseif ($stringWrapperCharacter === $nextCharacter) {
|
||||
if (\substr(\end($selectorParts), -1) !== '\\') {
|
||||
$stringWrapperCharacter = null;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '(':
|
||||
if (!\is_string($stringWrapperCharacter)) {
|
||||
++$functionNestingLevel;
|
||||
}
|
||||
break;
|
||||
case ')':
|
||||
if (!\is_string($stringWrapperCharacter)) {
|
||||
if ($functionNestingLevel <= 0) {
|
||||
throw new UnexpectedTokenException('anything but', ')');
|
||||
}
|
||||
--$functionNestingLevel;
|
||||
}
|
||||
break;
|
||||
case ',':
|
||||
if (!\is_string($stringWrapperCharacter) && $functionNestingLevel === 0) {
|
||||
$selectors[] = \implode('', $selectorParts);
|
||||
$selectorParts = [];
|
||||
$parserState->consume(1);
|
||||
$consumedNextCharacter = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} while (!\in_array($nextCharacter, ['{', '}'], true) || \is_string($stringWrapperCharacter));
|
||||
if ($functionNestingLevel !== 0) {
|
||||
throw new UnexpectedTokenException(')', $nextCharacter);
|
||||
}
|
||||
$selectors[] = \implode('', $selectorParts); // add final or only selector
|
||||
$selectors = self::parseSelectors($parserState, $list, $comments);
|
||||
$result->setSelectors($selectors, $list);
|
||||
if ($parserState->comes('{')) {
|
||||
$parserState->consume(1);
|
||||
}
|
||||
} catch (UnexpectedTokenException $e) {
|
||||
if ($parserState->getSettings()->usesLenientParsing()) {
|
||||
if (!$parserState->comes('}')) {
|
||||
$parserState->consumeUntil('}', false, true);
|
||||
if (!$parserState->consumeIfComes('}')) {
|
||||
$parserState->consumeUntil(['}', ParserState::EOF], false, true);
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
@@ -146,11 +98,29 @@ public static function parse(ParserState $parserState, ?CSSList $list = null): ?
|
||||
public function setSelectors($selectors, ?CSSList $list = null): void
|
||||
{
|
||||
if (\is_array($selectors)) {
|
||||
$this->selectors = $selectors;
|
||||
$selectorsToSet = $selectors;
|
||||
} else {
|
||||
$this->selectors = \explode(',', $selectors);
|
||||
// A string of comma-separated selectors requires parsing.
|
||||
try {
|
||||
$parserState = new ParserState($selectors, Settings::create());
|
||||
$selectorsToSet = self::parseSelectors($parserState, $list);
|
||||
if (!$parserState->isEnd()) {
|
||||
throw new UnexpectedTokenException('EOF', 'more');
|
||||
}
|
||||
} catch (UnexpectedTokenException $exception) {
|
||||
// The exception message from parsing may refer to the faux `{` block start token,
|
||||
// which would be confusing.
|
||||
// Rethrow with a more useful message, that also includes the selector(s) string that was passed.
|
||||
throw new UnexpectedTokenException(
|
||||
'Selector(s) string is not valid.',
|
||||
$selectors,
|
||||
'custom'
|
||||
);
|
||||
}
|
||||
}
|
||||
foreach ($this->selectors as $key => $selector) {
|
||||
|
||||
// Convert all items to a `Selector` if not already
|
||||
foreach ($selectorsToSet as $key => $selector) {
|
||||
if (!($selector instanceof Selector)) {
|
||||
if ($list === null || !($list instanceof KeyFrame)) {
|
||||
if (!Selector::isValid($selector)) {
|
||||
@@ -160,7 +130,7 @@ public function setSelectors($selectors, ?CSSList $list = null): void
|
||||
'custom'
|
||||
);
|
||||
}
|
||||
$this->selectors[$key] = new Selector($selector);
|
||||
$selectorsToSet[$key] = new Selector($selector);
|
||||
} else {
|
||||
if (!KeyframeSelector::isValid($selector)) {
|
||||
throw new UnexpectedTokenException(
|
||||
@@ -169,10 +139,13 @@ public function setSelectors($selectors, ?CSSList $list = null): void
|
||||
'custom'
|
||||
);
|
||||
}
|
||||
$this->selectors[$key] = new KeyframeSelector($selector);
|
||||
$selectorsToSet[$key] = new KeyframeSelector($selector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Discard the keys and reindex the array
|
||||
$this->selectors = \array_values($selectorsToSet);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -195,7 +168,7 @@ public function removeSelector($selectorToRemove): bool
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<Selector>
|
||||
* @return list<Selector>
|
||||
*/
|
||||
public function getSelectors(): array
|
||||
{
|
||||
@@ -208,65 +181,65 @@ public function getRuleSet(): RuleSet
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RuleSet::addRule()
|
||||
* @see RuleSet::addDeclaration()
|
||||
*/
|
||||
public function addRule(Rule $ruleToAdd, ?Rule $sibling = null): void
|
||||
public function addDeclaration(Declaration $declarationToAdd, ?Declaration $sibling = null): void
|
||||
{
|
||||
$this->ruleSet->addRule($ruleToAdd, $sibling);
|
||||
$this->ruleSet->addDeclaration($declarationToAdd, $sibling);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RuleSet::getRules()
|
||||
* @return array<int<0, max>, Declaration>
|
||||
*
|
||||
* @return array<int<0, max>, Rule>
|
||||
* @see RuleSet::getDeclarations()
|
||||
*/
|
||||
public function getRules(?string $searchPattern = null): array
|
||||
public function getDeclarations(?string $searchPattern = null): array
|
||||
{
|
||||
return $this->ruleSet->getRules($searchPattern);
|
||||
return $this->ruleSet->getDeclarations($searchPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RuleSet::setRules()
|
||||
* @param array<Declaration> $declarations
|
||||
*
|
||||
* @param array<Rule> $rules
|
||||
* @see RuleSet::setDeclarations()
|
||||
*/
|
||||
public function setRules(array $rules): void
|
||||
public function setDeclarations(array $declarations): void
|
||||
{
|
||||
$this->ruleSet->setRules($rules);
|
||||
$this->ruleSet->setDeclarations($declarations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RuleSet::getRulesAssoc()
|
||||
* @return array<string, Declaration>
|
||||
*
|
||||
* @return array<string, Rule>
|
||||
* @see RuleSet::getDeclarationsAssociative()
|
||||
*/
|
||||
public function getRulesAssoc(?string $searchPattern = null): array
|
||||
public function getDeclarationsAssociative(?string $searchPattern = null): array
|
||||
{
|
||||
return $this->ruleSet->getRulesAssoc($searchPattern);
|
||||
return $this->ruleSet->getDeclarationsAssociative($searchPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RuleSet::removeRule()
|
||||
* @see RuleSet::removeDeclaration()
|
||||
*/
|
||||
public function removeRule(Rule $ruleToRemove): void
|
||||
public function removeDeclaration(Declaration $declarationToRemove): void
|
||||
{
|
||||
$this->ruleSet->removeRule($ruleToRemove);
|
||||
$this->ruleSet->removeDeclaration($declarationToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RuleSet::removeMatchingRules()
|
||||
* @see RuleSet::removeMatchingDeclarations()
|
||||
*/
|
||||
public function removeMatchingRules(string $searchPattern): void
|
||||
public function removeMatchingDeclarations(string $searchPattern): void
|
||||
{
|
||||
$this->ruleSet->removeMatchingRules($searchPattern);
|
||||
$this->ruleSet->removeMatchingDeclarations($searchPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RuleSet::removeAllRules()
|
||||
* @see RuleSet::removeAllDeclarations()
|
||||
*/
|
||||
public function removeAllRules(): void
|
||||
public function removeAllDeclarations(): void
|
||||
{
|
||||
$this->ruleSet->removeAllRules();
|
||||
$this->ruleSet->removeAllDeclarations();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,4 +271,36 @@ public function render(OutputFormat $outputFormat): string
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, bool|int|float|string|array<mixed>|null>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getArrayRepresentation(): array
|
||||
{
|
||||
throw new \BadMethodCallException('`getArrayRepresentation` is not yet implemented for `' . self::class . '`');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param list<Comment> $comments
|
||||
*
|
||||
* @return list<Selector>
|
||||
*
|
||||
* @throws UnexpectedTokenException
|
||||
*/
|
||||
private static function parseSelectors(ParserState $parserState, ?CSSList $list, array &$comments = []): array
|
||||
{
|
||||
$selectorClass = $list instanceof KeyFrame ? KeyFrameSelector::class : Selector::class;
|
||||
$selectors = [];
|
||||
|
||||
while (true) {
|
||||
$selectors[] = $selectorClass::parse($parserState, $comments);
|
||||
if (!$parserState->consumeIfComes(',')) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $selectors;
|
||||
}
|
||||
}
|
||||
|
||||
77
vendor/sabberworm/php-css-parser/src/RuleSet/DeclarationList.php
vendored
Normal file
77
vendor/sabberworm/php-css-parser/src/RuleSet/DeclarationList.php
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabberworm\CSS\RuleSet;
|
||||
|
||||
use Sabberworm\CSS\Property\Declaration;
|
||||
|
||||
/**
|
||||
* Represents a CSS item that contains `Declaration`s, defining the methods to manipulate them.
|
||||
*/
|
||||
interface DeclarationList
|
||||
{
|
||||
public function addDeclaration(Declaration $declarationToAdd, ?Declaration $sibling = null): void;
|
||||
|
||||
public function removeDeclaration(Declaration $declarationToRemove): void;
|
||||
|
||||
public function removeMatchingDeclarations(string $searchPattern): void;
|
||||
|
||||
public function removeAllDeclarations(): void;
|
||||
|
||||
/**
|
||||
* @param array<Declaration> $declarations
|
||||
*/
|
||||
public function setDeclarations(array $declarations): void;
|
||||
|
||||
/**
|
||||
* @return array<int<0, max>, Declaration>
|
||||
*/
|
||||
public function getDeclarations(?string $searchPattern = null): array;
|
||||
|
||||
/**
|
||||
* @return array<string, Declaration>
|
||||
*/
|
||||
public function getDeclarationsAssociative(?string $searchPattern = null): array;
|
||||
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `addDeclaration()` instead.
|
||||
*/
|
||||
public function addRule(Declaration $declarationToAdd, ?Declaration $sibling = null): void;
|
||||
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `removeDeclaration()` instead.
|
||||
*/
|
||||
public function removeRule(Declaration $declarationToRemove): void;
|
||||
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `removeMatchingDeclarations()` instead.
|
||||
*/
|
||||
public function removeMatchingRules(string $searchPattern): void;
|
||||
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `removeAllDeclarations()` instead.
|
||||
*/
|
||||
public function removeAllRules(): void;
|
||||
|
||||
/**
|
||||
* @param array<Declaration> $declarations
|
||||
*
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `setDeclarations()` instead.
|
||||
*/
|
||||
public function setRules(array $declarations): void;
|
||||
|
||||
/**
|
||||
* @return array<int<0, max>, Declaration>
|
||||
*
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `getDeclarations()` instead.
|
||||
*/
|
||||
public function getRules(?string $searchPattern = null): array;
|
||||
|
||||
/**
|
||||
* @return array<string, Declaration>
|
||||
*
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `getDeclarationsAssociative()` instead.
|
||||
*/
|
||||
public function getRulesAssoc(?string $searchPattern = null): array;
|
||||
}
|
||||
75
vendor/sabberworm/php-css-parser/src/RuleSet/LegacyDeclarationListMethods.php
vendored
Normal file
75
vendor/sabberworm/php-css-parser/src/RuleSet/LegacyDeclarationListMethods.php
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Sabberworm\CSS\RuleSet;
|
||||
|
||||
use Sabberworm\CSS\Property\Declaration;
|
||||
|
||||
/**
|
||||
* Provides a mapping of the deprecated methods in a `DeclarationList` to their renamed replacements.
|
||||
*/
|
||||
trait LegacyDeclarationListMethods
|
||||
{
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `addDeclaration()` instead.
|
||||
*/
|
||||
public function addRule(Declaration $declarationToAdd, ?Declaration $sibling = null): void
|
||||
{
|
||||
$this->addDeclaration($declarationToAdd, $sibling);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `removeDeclaration()` instead.
|
||||
*/
|
||||
public function removeRule(Declaration $declarationToRemove): void
|
||||
{
|
||||
$this->removeDeclaration($declarationToRemove);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `removeMatchingDeclarations()` instead.
|
||||
*/
|
||||
public function removeMatchingRules(string $searchPattern): void
|
||||
{
|
||||
$this->removeMatchingDeclarations($searchPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `removeAllDeclarations()` instead.
|
||||
*/
|
||||
public function removeAllRules(): void
|
||||
{
|
||||
$this->removeAllDeclarations();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<Declaration> $declarations
|
||||
*
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `setDeclarations()` instead.
|
||||
*/
|
||||
public function setRules(array $declarations): void
|
||||
{
|
||||
$this->setDeclarations($declarations);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int<0, max>, Declaration>
|
||||
*
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `getDeclarations()` instead.
|
||||
*/
|
||||
public function getRules(?string $searchPattern = null): array
|
||||
{
|
||||
return $this->getDeclarations($searchPattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, Declaration>
|
||||
*
|
||||
* @deprecated in v9.2, will be removed in v10.0; use `getDeclarationsAssociative()` instead.
|
||||
*/
|
||||
public function getRulesAssoc(?string $searchPattern = null): array
|
||||
{
|
||||
return $this->getDeclarationsAssociative($searchPattern);
|
||||
}
|
||||
}
|
||||
@@ -4,33 +4,11 @@
|
||||
|
||||
namespace Sabberworm\CSS\RuleSet;
|
||||
|
||||
use Sabberworm\CSS\Rule\Rule;
|
||||
|
||||
/**
|
||||
* Represents a CSS item that contains `Rules`, defining the methods to manipulate them.
|
||||
*/
|
||||
interface RuleContainer
|
||||
{
|
||||
public function addRule(Rule $ruleToAdd, ?Rule $sibling = null): void;
|
||||
|
||||
public function removeRule(Rule $ruleToRemove): void;
|
||||
|
||||
public function removeMatchingRules(string $searchPattern): void;
|
||||
|
||||
public function removeAllRules(): void;
|
||||
use function Safe\class_alias;
|
||||
|
||||
if (!\class_exists(RuleContainer::class, false) && !\interface_exists(RuleContainer::class, false)) {
|
||||
/**
|
||||
* @param array<Rule> $rules
|
||||
* @deprecated in v9.2, will be removed in v10.0. Use `DeclarationList` instead, which is a direct replacement.
|
||||
*/
|
||||
public function setRules(array $rules): void;
|
||||
|
||||
/**
|
||||
* @return array<int<0, max>, Rule>
|
||||
*/
|
||||
public function getRules(?string $searchPattern = null): array;
|
||||
|
||||
/**
|
||||
* @return array<string, Rule>
|
||||
*/
|
||||
public function getRulesAssoc(?string $searchPattern = null): array;
|
||||
class_alias(DeclarationList::class, RuleContainer::class);
|
||||
}
|
||||
|
||||
@@ -13,31 +13,32 @@
|
||||
use Sabberworm\CSS\Parsing\UnexpectedTokenException;
|
||||
use Sabberworm\CSS\Position\Position;
|
||||
use Sabberworm\CSS\Position\Positionable;
|
||||
use Sabberworm\CSS\Rule\Rule;
|
||||
use Sabberworm\CSS\Property\Declaration;
|
||||
|
||||
/**
|
||||
* This class is a container for individual 'Rule's.
|
||||
* This class is a container for individual `Declaration`s.
|
||||
*
|
||||
* The most common form of a rule set is one constrained by a selector, i.e., a `DeclarationBlock`.
|
||||
* However, unknown `AtRule`s (like `@font-face`) are rule sets as well.
|
||||
*
|
||||
* If you want to manipulate a `RuleSet`, use the methods `addRule(Rule $rule)`, `getRules()` and `removeRule($rule)`
|
||||
* (which accepts either a `Rule` or a rule name; optionally suffixed by a dash to remove all related rules).
|
||||
* If you want to manipulate a `RuleSet`,
|
||||
* use the methods `addDeclaration()`, `getDeclarations()`, `removeDeclaration()`, `removeMatchingDeclarations()`, etc.
|
||||
*
|
||||
* Note that `CSSListItem` extends both `Commentable` and `Renderable`, so those interfaces must also be implemented.
|
||||
*/
|
||||
class RuleSet implements CSSElement, CSSListItem, Positionable, RuleContainer
|
||||
class RuleSet implements CSSElement, CSSListItem, Positionable, DeclarationList
|
||||
{
|
||||
use CommentContainer;
|
||||
use LegacyDeclarationListMethods;
|
||||
use Position;
|
||||
|
||||
/**
|
||||
* the rules in this rule set, using the property name as the key,
|
||||
* with potentially multiple rules per property name.
|
||||
* the declarations in this rule set, using the property name as the key,
|
||||
* with potentially multiple declarations per property name.
|
||||
*
|
||||
* @var array<string, array<int<0, max>, Rule>>
|
||||
* @var array<string, array<int<0, max>, Declaration>>
|
||||
*/
|
||||
private $rules = [];
|
||||
private $declarations = [];
|
||||
|
||||
/**
|
||||
* @param int<1, max>|null $lineNumber
|
||||
@@ -59,14 +60,15 @@ public static function parseRuleSet(ParserState $parserState, RuleSet $ruleSet):
|
||||
$parserState->consume(';');
|
||||
}
|
||||
while (true) {
|
||||
$commentsBeforeRule = $parserState->consumeWhiteSpace();
|
||||
$commentsBeforeDeclaration = [];
|
||||
$parserState->consumeWhiteSpace($commentsBeforeDeclaration);
|
||||
if ($parserState->comes('}')) {
|
||||
break;
|
||||
}
|
||||
$rule = null;
|
||||
$declaration = null;
|
||||
if ($parserState->getSettings()->usesLenientParsing()) {
|
||||
try {
|
||||
$rule = Rule::parse($parserState, $commentsBeforeRule);
|
||||
$declaration = Declaration::parse($parserState, $commentsBeforeDeclaration);
|
||||
} catch (UnexpectedTokenException $e) {
|
||||
try {
|
||||
$consumedText = $parserState->consumeUntil(["\n", ';', '}'], true);
|
||||
@@ -84,10 +86,10 @@ public static function parseRuleSet(ParserState $parserState, RuleSet $ruleSet):
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$rule = Rule::parse($parserState, $commentsBeforeRule);
|
||||
$declaration = Declaration::parse($parserState, $commentsBeforeDeclaration);
|
||||
}
|
||||
if ($rule instanceof Rule) {
|
||||
$ruleSet->addRule($rule);
|
||||
if ($declaration instanceof Declaration) {
|
||||
$ruleSet->addDeclaration($declaration);
|
||||
}
|
||||
}
|
||||
$parserState->consume('}');
|
||||
@@ -95,31 +97,31 @@ public static function parseRuleSet(ParserState $parserState, RuleSet $ruleSet):
|
||||
|
||||
/**
|
||||
* @throws \UnexpectedValueException
|
||||
* if the last `Rule` is needed as a basis for setting position, but does not have a valid position,
|
||||
* if the last `Declaration` is needed as a basis for setting position, but does not have a valid position,
|
||||
* which should never happen
|
||||
*/
|
||||
public function addRule(Rule $ruleToAdd, ?Rule $sibling = null): void
|
||||
public function addDeclaration(Declaration $declarationToAdd, ?Declaration $sibling = null): void
|
||||
{
|
||||
$propertyName = $ruleToAdd->getRule();
|
||||
if (!isset($this->rules[$propertyName])) {
|
||||
$this->rules[$propertyName] = [];
|
||||
$propertyName = $declarationToAdd->getPropertyName();
|
||||
if (!isset($this->declarations[$propertyName])) {
|
||||
$this->declarations[$propertyName] = [];
|
||||
}
|
||||
|
||||
$position = \count($this->rules[$propertyName]);
|
||||
$position = \count($this->declarations[$propertyName]);
|
||||
|
||||
if ($sibling !== null) {
|
||||
$siblingIsInSet = false;
|
||||
$siblingPosition = \array_search($sibling, $this->rules[$propertyName], true);
|
||||
$siblingPosition = \array_search($sibling, $this->declarations[$propertyName], true);
|
||||
if ($siblingPosition !== false) {
|
||||
$siblingIsInSet = true;
|
||||
$position = $siblingPosition;
|
||||
} else {
|
||||
$siblingIsInSet = $this->hasRule($sibling);
|
||||
$siblingIsInSet = $this->hasDeclaration($sibling);
|
||||
if ($siblingIsInSet) {
|
||||
// Maintain ordering within `$this->rules[$propertyName]`
|
||||
// by inserting before first `Rule` with a same-or-later position than the sibling.
|
||||
foreach ($this->rules[$propertyName] as $index => $rule) {
|
||||
if (self::comparePositionable($rule, $sibling) >= 0) {
|
||||
// Maintain ordering within `$this->declarations[$propertyName]`
|
||||
// by inserting before first `Declaration` with a same-or-later position than the sibling.
|
||||
foreach ($this->declarations[$propertyName] as $index => $declaration) {
|
||||
if (self::comparePositionable($declaration, $sibling) >= 0) {
|
||||
$position = $index;
|
||||
break;
|
||||
}
|
||||
@@ -127,69 +129,71 @@ public function addRule(Rule $ruleToAdd, ?Rule $sibling = null): void
|
||||
}
|
||||
}
|
||||
if ($siblingIsInSet) {
|
||||
// Increment column number of all existing rules on same line, starting at sibling
|
||||
// Increment column number of all existing declarations on same line, starting at sibling
|
||||
$siblingLineNumber = $sibling->getLineNumber();
|
||||
$siblingColumnNumber = $sibling->getColumnNumber();
|
||||
foreach ($this->rules as $rulesForAProperty) {
|
||||
foreach ($rulesForAProperty as $rule) {
|
||||
foreach ($this->declarations as $declarationsForAProperty) {
|
||||
foreach ($declarationsForAProperty as $declaration) {
|
||||
if (
|
||||
$rule->getLineNumber() === $siblingLineNumber &&
|
||||
$rule->getColumnNumber() >= $siblingColumnNumber
|
||||
$declaration->getLineNumber() === $siblingLineNumber &&
|
||||
$declaration->getColumnNumber() >= $siblingColumnNumber
|
||||
) {
|
||||
$rule->setPosition($siblingLineNumber, $rule->getColumnNumber() + 1);
|
||||
$declaration->setPosition($siblingLineNumber, $declaration->getColumnNumber() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
$ruleToAdd->setPosition($siblingLineNumber, $siblingColumnNumber);
|
||||
$declarationToAdd->setPosition($siblingLineNumber, $siblingColumnNumber);
|
||||
}
|
||||
}
|
||||
|
||||
if ($ruleToAdd->getLineNumber() === null) {
|
||||
if ($declarationToAdd->getLineNumber() === null) {
|
||||
//this node is added manually, give it the next best line
|
||||
$columnNumber = $ruleToAdd->getColumnNumber() ?? 0;
|
||||
$rules = $this->getRules();
|
||||
$rulesCount = \count($rules);
|
||||
if ($rulesCount > 0) {
|
||||
$last = $rules[$rulesCount - 1];
|
||||
$columnNumber = $declarationToAdd->getColumnNumber() ?? 0;
|
||||
$declarations = $this->getDeclarations();
|
||||
$declarationsCount = \count($declarations);
|
||||
if ($declarationsCount > 0) {
|
||||
$last = $declarations[$declarationsCount - 1];
|
||||
$lastsLineNumber = $last->getLineNumber();
|
||||
if (!\is_int($lastsLineNumber)) {
|
||||
throw new \UnexpectedValueException(
|
||||
'A Rule without a line number was found during addRule',
|
||||
'A Declaration without a line number was found during addDeclaration',
|
||||
1750718399
|
||||
);
|
||||
}
|
||||
$ruleToAdd->setPosition($lastsLineNumber + 1, $columnNumber);
|
||||
$declarationToAdd->setPosition($lastsLineNumber + 1, $columnNumber);
|
||||
} else {
|
||||
$ruleToAdd->setPosition(1, $columnNumber);
|
||||
$declarationToAdd->setPosition(1, $columnNumber);
|
||||
}
|
||||
} elseif ($ruleToAdd->getColumnNumber() === null) {
|
||||
$ruleToAdd->setPosition($ruleToAdd->getLineNumber(), 0);
|
||||
} elseif ($declarationToAdd->getColumnNumber() === null) {
|
||||
$declarationToAdd->setPosition($declarationToAdd->getLineNumber(), 0);
|
||||
}
|
||||
|
||||
\array_splice($this->rules[$propertyName], $position, 0, [$ruleToAdd]);
|
||||
\array_splice($this->declarations[$propertyName], $position, 0, [$declarationToAdd]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all rules matching the given rule name
|
||||
* Returns all declarations matching the given property name
|
||||
*
|
||||
* @example $ruleSet->getRules('font') // returns array(0 => $rule, …) or array().
|
||||
* @example $ruleSet->getDeclarations('font') // returns array(0 => $declaration, …) or array().
|
||||
*
|
||||
* @example $ruleSet->getRules('font-')
|
||||
* //returns an array of all rules either beginning with font- or matching font.
|
||||
* @example $ruleSet->getDeclarations('font-')
|
||||
* //returns an array of all declarations either beginning with font- or matching font.
|
||||
*
|
||||
* @param string|null $searchPattern
|
||||
* Pattern to search for. If null, returns all rules.
|
||||
* If the pattern ends with a dash, all rules starting with the pattern are returned
|
||||
* Pattern to search for. If null, returns all declarations.
|
||||
* If the pattern ends with a dash, all declarations starting with the pattern are returned
|
||||
* as well as one matching the pattern with the dash excluded.
|
||||
*
|
||||
* @return array<int<0, max>, Rule>
|
||||
* @return array<int<0, max>, Declaration>
|
||||
*/
|
||||
public function getRules(?string $searchPattern = null): array
|
||||
public function getDeclarations(?string $searchPattern = null): array
|
||||
{
|
||||
$result = [];
|
||||
foreach ($this->rules as $propertyName => $rules) {
|
||||
// Either no search rule is given or the search rule matches the found rule exactly
|
||||
// or the search rule ends in “-” and the found rule starts with the search rule.
|
||||
foreach ($this->declarations as $propertyName => $declarations) {
|
||||
// Either no search pattern was given
|
||||
// or the search pattern matches the found declaration's property name exactly
|
||||
// or the search pattern ends in “-”
|
||||
// ... and the found declaration's property name starts with the search pattern
|
||||
if (
|
||||
$searchPattern === null || $propertyName === $searchPattern
|
||||
|| (
|
||||
@@ -198,7 +202,7 @@ public function getRules(?string $searchPattern = null): array
|
||||
|| $propertyName === \substr($searchPattern, 0, -1))
|
||||
)
|
||||
) {
|
||||
$result = \array_merge($result, $rules);
|
||||
$result = \array_merge($result, $declarations);
|
||||
}
|
||||
}
|
||||
\usort($result, [self::class, 'comparePositionable']);
|
||||
@@ -207,89 +211,90 @@ public function getRules(?string $searchPattern = null): array
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides all the rules of this set.
|
||||
* Overrides all the declarations of this set.
|
||||
*
|
||||
* @param array<Rule> $rules The rules to override with.
|
||||
* @param array<Declaration> $declarations
|
||||
*/
|
||||
public function setRules(array $rules): void
|
||||
public function setDeclarations(array $declarations): void
|
||||
{
|
||||
$this->rules = [];
|
||||
foreach ($rules as $rule) {
|
||||
$this->addRule($rule);
|
||||
$this->declarations = [];
|
||||
foreach ($declarations as $declaration) {
|
||||
$this->addDeclaration($declaration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all rules matching the given pattern and returns them in an associative array with the rule’s name
|
||||
* as keys. This method exists mainly for backwards-compatibility and is really only partially useful.
|
||||
* Returns all declarations with property names matching the given pattern and returns them in an associative array
|
||||
* with the property names as keys.
|
||||
* This method exists mainly for backwards-compatibility and is really only partially useful.
|
||||
*
|
||||
* Note: This method loses some information: Calling this (with an argument of `background-`) on a declaration block
|
||||
* like `{ background-color: green; background-color; rgba(0, 127, 0, 0.7); }` will only yield an associative array
|
||||
* containing the rgba-valued rule while `getRules()` would yield an indexed array containing both.
|
||||
* containing the rgba-valued declaration while `getDeclarations()` would yield an indexed array containing both.
|
||||
*
|
||||
* @param string|null $searchPattern
|
||||
* Pattern to search for. If null, returns all rules. If the pattern ends with a dash,
|
||||
* all rules starting with the pattern are returned as well as one matching the pattern with the dash
|
||||
* Pattern to search for. If null, returns all declarations. If the pattern ends with a dash,
|
||||
* all declarations starting with the pattern are returned as well as one matching the pattern with the dash
|
||||
* excluded.
|
||||
*
|
||||
* @return array<string, Rule>
|
||||
* @return array<string, Declaration>
|
||||
*/
|
||||
public function getRulesAssoc(?string $searchPattern = null): array
|
||||
public function getDeclarationsAssociative(?string $searchPattern = null): array
|
||||
{
|
||||
/** @var array<string, Rule> $result */
|
||||
/** @var array<string, Declaration> $result */
|
||||
$result = [];
|
||||
foreach ($this->getRules($searchPattern) as $rule) {
|
||||
$result[$rule->getRule()] = $rule;
|
||||
foreach ($this->getDeclarations($searchPattern) as $declaration) {
|
||||
$result[$declaration->getPropertyName()] = $declaration;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a `Rule` from this `RuleSet` by identity.
|
||||
* Removes a `Declaration` from this `RuleSet` by identity.
|
||||
*/
|
||||
public function removeRule(Rule $ruleToRemove): void
|
||||
public function removeDeclaration(Declaration $declarationToRemove): void
|
||||
{
|
||||
$nameOfPropertyToRemove = $ruleToRemove->getRule();
|
||||
if (!isset($this->rules[$nameOfPropertyToRemove])) {
|
||||
$nameOfPropertyToRemove = $declarationToRemove->getPropertyName();
|
||||
if (!isset($this->declarations[$nameOfPropertyToRemove])) {
|
||||
return;
|
||||
}
|
||||
foreach ($this->rules[$nameOfPropertyToRemove] as $key => $rule) {
|
||||
if ($rule === $ruleToRemove) {
|
||||
unset($this->rules[$nameOfPropertyToRemove][$key]);
|
||||
foreach ($this->declarations[$nameOfPropertyToRemove] as $key => $declaration) {
|
||||
if ($declaration === $declarationToRemove) {
|
||||
unset($this->declarations[$nameOfPropertyToRemove][$key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes rules by property name or search pattern.
|
||||
* Removes declarations by property name or search pattern.
|
||||
*
|
||||
* @param string $searchPattern
|
||||
* pattern to remove.
|
||||
* If the pattern ends in a dash,
|
||||
* all rules starting with the pattern are removed as well as one matching the pattern with the dash
|
||||
* all declarations starting with the pattern are removed as well as one matching the pattern with the dash
|
||||
* excluded.
|
||||
*/
|
||||
public function removeMatchingRules(string $searchPattern): void
|
||||
public function removeMatchingDeclarations(string $searchPattern): void
|
||||
{
|
||||
foreach ($this->rules as $propertyName => $rules) {
|
||||
// Either the search rule matches the found rule exactly
|
||||
// or the search rule ends in “-” and the found rule starts with the search rule or equals it
|
||||
// (without the trailing dash).
|
||||
foreach ($this->declarations as $propertyName => $declarations) {
|
||||
// Either the search pattern matches the found declaration's property name exactly
|
||||
// or the search pattern ends in “-” and the found declaration's property name starts with the search
|
||||
// pattern or equals it (without the trailing dash).
|
||||
if (
|
||||
$propertyName === $searchPattern
|
||||
|| (\strrpos($searchPattern, '-') === \strlen($searchPattern) - \strlen('-')
|
||||
&& (\strpos($propertyName, $searchPattern) === 0
|
||||
|| $propertyName === \substr($searchPattern, 0, -1)))
|
||||
) {
|
||||
unset($this->rules[$propertyName]);
|
||||
unset($this->declarations[$propertyName]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function removeAllRules(): void
|
||||
public function removeAllDeclarations(): void
|
||||
{
|
||||
$this->rules = [];
|
||||
$this->declarations = [];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -297,20 +302,22 @@ public function removeAllRules(): void
|
||||
*/
|
||||
public function render(OutputFormat $outputFormat): string
|
||||
{
|
||||
return $this->renderRules($outputFormat);
|
||||
return $this->renderDeclarations($outputFormat);
|
||||
}
|
||||
|
||||
protected function renderRules(OutputFormat $outputFormat): string
|
||||
protected function renderDeclarations(OutputFormat $outputFormat): string
|
||||
{
|
||||
$result = '';
|
||||
$isFirst = true;
|
||||
$nextLevelFormat = $outputFormat->nextLevel();
|
||||
foreach ($this->getRules() as $rule) {
|
||||
foreach ($this->getDeclarations() as $declaration) {
|
||||
$nextLevelFormatter = $nextLevelFormat->getFormatter();
|
||||
$renderedRule = $nextLevelFormatter->safely(static function () use ($rule, $nextLevelFormat): string {
|
||||
return $rule->render($nextLevelFormat);
|
||||
});
|
||||
if ($renderedRule === null) {
|
||||
$renderedDeclaration = $nextLevelFormatter->safely(
|
||||
static function () use ($declaration, $nextLevelFormat): string {
|
||||
return $declaration->render($nextLevelFormat);
|
||||
}
|
||||
);
|
||||
if ($renderedDeclaration === null) {
|
||||
continue;
|
||||
}
|
||||
if ($isFirst) {
|
||||
@@ -319,7 +326,7 @@ protected function renderRules(OutputFormat $outputFormat): string
|
||||
} else {
|
||||
$result .= $nextLevelFormatter->spaceBetweenRules();
|
||||
}
|
||||
$result .= $renderedRule;
|
||||
$result .= $renderedDeclaration;
|
||||
}
|
||||
|
||||
$formatter = $outputFormat->getFormatter();
|
||||
@@ -331,6 +338,16 @@ protected function renderRules(OutputFormat $outputFormat): string
|
||||
return $formatter->removeLastSemicolon($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<string, bool|int|float|string|array<mixed>|null>
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public function getArrayRepresentation(): array
|
||||
{
|
||||
throw new \BadMethodCallException('`getArrayRepresentation` is not yet implemented for `' . self::class . '`');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int negative if `$first` is before `$second`; zero if they have the same position; positive otherwise
|
||||
*
|
||||
@@ -342,7 +359,7 @@ private static function comparePositionable(Positionable $first, Positionable $s
|
||||
$secondsLineNumber = $second->getLineNumber();
|
||||
if (!\is_int($firstsLineNumber) || !\is_int($secondsLineNumber)) {
|
||||
throw new \UnexpectedValueException(
|
||||
'A Rule without a line number was passed to comparePositionable',
|
||||
'A Declaration without a line number was passed to comparePositionable',
|
||||
1750637683
|
||||
);
|
||||
}
|
||||
@@ -352,7 +369,7 @@ private static function comparePositionable(Positionable $first, Positionable $s
|
||||
$secondsColumnNumber = $second->getColumnNumber();
|
||||
if (!\is_int($firstsColumnNumber) || !\is_int($secondsColumnNumber)) {
|
||||
throw new \UnexpectedValueException(
|
||||
'A Rule without a column number was passed to comparePositionable',
|
||||
'A Declaration without a column number was passed to comparePositionable',
|
||||
1750637761
|
||||
);
|
||||
}
|
||||
@@ -362,10 +379,10 @@ private static function comparePositionable(Positionable $first, Positionable $s
|
||||
return $firstsLineNumber - $secondsLineNumber;
|
||||
}
|
||||
|
||||
private function hasRule(Rule $rule): bool
|
||||
private function hasDeclaration(Declaration $declaration): bool
|
||||
{
|
||||
foreach ($this->rules as $rulesForAProperty) {
|
||||
if (\in_array($rule, $rulesForAProperty, true)) {
|
||||
foreach ($this->declarations as $declarationsForAProperty) {
|
||||
if (\in_array($declaration, $declarationsForAProperty, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user