|null $lineNumber * @param int<0, max>|null $columnNumber */ public function __construct(string $rule, ?int $lineNumber = null, ?int $columnNumber = null) { $this->rule = $rule; $this->setPosition($lineNumber, $columnNumber); } /** * @param list $commentsBeforeRule * * @throws UnexpectedEOFException * @throws UnexpectedTokenException * * @internal since V8.8.0 */ public static function parse(ParserState $parserState, array $commentsBeforeRule = []): Rule { $comments = \array_merge($commentsBeforeRule, $parserState->consumeWhiteSpace()); $rule = new Rule( $parserState->parseIdentifier(!$parserState->comes('--')), $parserState->currentLine(), $parserState->currentColumn() ); $rule->setComments($comments); $rule->addComments($parserState->consumeWhiteSpace()); $parserState->consume(':'); $value = Value::parseValue($parserState, self::listDelimiterForRule($rule->getRule())); $rule->setValue($value); $parserState->consumeWhiteSpace(); if ($parserState->comes('!')) { $parserState->consume('!'); $parserState->consumeWhiteSpace(); $parserState->consume('important'); $rule->setIsImportant(true); } $parserState->consumeWhiteSpace(); while ($parserState->comes(';')) { $parserState->consume(';'); } return $rule; } /** * Returns a list of delimiters (or separators). * The first item is the innermost separator (or, put another way, the highest-precedence operator). * The sequence continues to the outermost separator (or lowest-precedence operator). * * @param non-empty-string $rule * * @return list */ private static function listDelimiterForRule(string $rule): array { if (\preg_match('/^font($|-)/', $rule)) { return [',', '/', ' ']; } switch ($rule) { case 'src': return [' ', ',']; default: return [',', ' ', '/']; } } /** * @param non-empty-string $rule */ public function setRule(string $rule): void { $this->rule = $rule; } /** * @return non-empty-string */ public function getRule(): string { return $this->rule; } /** * @return RuleValueList|string|null */ public function getValue() { return $this->value; } /** * @param RuleValueList|string|null $value */ public function setValue($value): void { $this->value = $value; } /** * Adds a value to the existing value. Value will be appended if a `RuleValueList` exists of the given type. * Otherwise, the existing value will be wrapped by one. * * @param RuleValueList|array $value */ public function addValue($value, string $type = ' '): void { if (!\is_array($value)) { $value = [$value]; } if (!($this->value instanceof RuleValueList) || $this->value->getListSeparator() !== $type) { $currentValue = $this->value; $this->value = new RuleValueList($type, $this->getLineNumber()); if ($currentValue !== null && $currentValue !== '') { $this->value->addListComponent($currentValue); } } foreach ($value as $valueItem) { $this->value->addListComponent($valueItem); } } public function setIsImportant(bool $isImportant): void { $this->isImportant = $isImportant; } public function getIsImportant(): bool { return $this->isImportant; } /** * @return non-empty-string */ public function render(OutputFormat $outputFormat): string { $formatter = $outputFormat->getFormatter(); $result = "{$formatter->comments($this)}{$this->rule}:{$formatter->spaceAfterRuleName()}"; if ($this->value instanceof Value) { // Can also be a ValueList $result .= $this->value->render($outputFormat); } else { $result .= $this->value; } if ($this->isImportant) { $result .= ' !important'; } $result .= ';'; return $result; } }