PluginProbe
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress / 11.1.0
AcyMailing – An Ultimate Newsletter Plugin and Marketing Automation Solution for WordPress v11.1.0
11.1.1 11.1.0 11.0.5 11.0.4 11.0.3 11.0.2 11.0.1 11.0.0 10.11.1 10.11.0 10.10.2 10.10.1 10.10.0 10.9.1 trunk 10.0.0 10.0.1 10.1.0 10.1.1 10.1.2 10.1.3 10.1.4 10.2.0 10.2.1 10.2.2 All 62 releases
← All changes | back/Libraries/Sabberworm/CSS/src/Value/Value.php +126 -113 10.1.4 → 11.1.0 View file →
@@ -1,117 +1,136 @@
1 1 <?php
2 2
3 -namespace Sabberworm\CSS\Value;
3 +declare(strict_types=1);
4 4
5 -use Sabberworm\CSS\Parsing\ParserState;
6 -use Sabberworm\CSS\Parsing\SourceException;
7 -use Sabberworm\CSS\Parsing\UnexpectedEOFException;
8 -use Sabberworm\CSS\Parsing\UnexpectedTokenException;
9 -use Sabberworm\CSS\Renderable;
5 +namespace AcyMailing\Libraries\Sabberworm\CSS\Value;
10 6
11 -abstract class Value implements Renderable
7 +use AcyMailing\Libraries\Sabberworm\CSS\CSSElement;
8 +use AcyMailing\Libraries\Sabberworm\CSS\Parsing\ParserState;
9 +use AcyMailing\Libraries\Sabberworm\CSS\Parsing\SourceException;
10 +use AcyMailing\Libraries\Sabberworm\CSS\Parsing\UnexpectedEOFException;
11 +use AcyMailing\Libraries\Sabberworm\CSS\Parsing\UnexpectedTokenException;
12 +use AcyMailing\Libraries\Sabberworm\CSS\Position\Position;
13 +use AcyMailing\Libraries\Sabberworm\CSS\Position\Positionable;
14 +
15 +/**
16 + * Abstract base class for specific classes of CSS values: `Size`, `Color`, `CSSString` and `URL`, and another
17 + * abstract subclass `ValueList`.
18 + */
19 +abstract class Value implements CSSElement, Positionable
12 20 {
13 - /**
14 - * @var int
15 - */
16 - protected $iLineNo;
21 + use Position;
17 22
18 23 /**
19 - * @param int $iLineNo
24 + * @param int<1, max>|null $lineNumber
20 25 */
21 - public function __construct($iLineNo = 0)
26 + public function __construct(?int $lineNumber = null)
22 27 {
23 - $this->iLineNo = $iLineNo;
28 + $this->setPosition($lineNumber);
24 29 }
25 30
26 31 /**
27 - * @param array<array-key, string> $aListDelimiters
32 + * @param array<non-empty-string> $listDelimiters
28 33 *
29 - * @return RuleValueList|CSSFunction|CSSString|LineName|Size|URL|string
34 + * @return Value|string
30 35 *
31 36 * @throws UnexpectedTokenException
32 37 * @throws UnexpectedEOFException
38 + *
39 + * @internal since V8.8.0
33 40 */
34 - public static function parseValue(ParserState $oParserState, array $aListDelimiters = [])
41 + public static function parseValue(ParserState $parserState, array $listDelimiters = [])
35 42 {
36 - /** @var array<int, RuleValueList|CSSFunction|CSSString|LineName|Size|URL|string> $aStack */
37 - $aStack = [];
38 - $oParserState->consumeWhiteSpace();
43 + /** @var list<Value|string> $stack */
44 + $stack = [];
45 + $parserState->consumeWhiteSpace();
39 46 //Build a list of delimiters and parsed values
40 47 while (
41 - !($oParserState->comes('}') || $oParserState->comes(';') || $oParserState->comes('!')
42 - || $oParserState->comes(')')
43 - || $oParserState->comes('\\'))
48 + !($parserState->comes('}') || $parserState->comes(';') || $parserState->comes('!')
49 + || $parserState->comes(')')
50 + || $parserState->isEnd())
44 51 ) {
45 - if (count($aStack) > 0) {
46 - $bFoundDelimiter = false;
47 - foreach ($aListDelimiters as $sDelimiter) {
48 - if ($oParserState->comes($sDelimiter)) {
49 - array_push($aStack, $oParserState->consume($sDelimiter));
50 - $oParserState->consumeWhiteSpace();
51 - $bFoundDelimiter = true;
52 + if (\count($stack) > 0) {
53 + $foundDelimiter = false;
54 + foreach ($listDelimiters as $delimiter) {
55 + if ($parserState->comes($delimiter)) {
56 + \array_push($stack, $parserState->consume($delimiter));
57 + $parserState->consumeWhiteSpace();
58 + $foundDelimiter = true;
52 59 break;
53 60 }
54 61 }
55 - if (!$bFoundDelimiter) {
62 + if (!$foundDelimiter) {
56 63 //Whitespace was the list delimiter
57 - array_push($aStack, ' ');
64 + \array_push($stack, ' ');
58 65 }
59 66 }
60 - array_push($aStack, self::parsePrimitiveValue($oParserState));
61 - $oParserState->consumeWhiteSpace();
67 + \array_push($stack, self::parsePrimitiveValue($parserState));
68 + $parserState->consumeWhiteSpace();
62 69 }
63 70 // Convert the list to list objects
64 - foreach ($aListDelimiters as $sDelimiter) {
65 - if (count($aStack) === 1) {
66 - return $aStack[0];
71 + foreach ($listDelimiters as $delimiter) {
72 + $stackSize = \count($stack);
73 + if ($stackSize === 1) {
74 + return $stack[0];
67 75 }
68 - $iStartPosition = null;
69 - while (($iStartPosition = array_search($sDelimiter, $aStack, true)) !== false) {
70 - $iLength = 2; //Number of elements to be joined
71 - for ($i = $iStartPosition + 2; $i < count($aStack); $i += 2, ++$iLength) {
72 - if ($sDelimiter !== $aStack[$i]) {
76 + $newStack = [];
77 + for ($offset = 0; $offset < $stackSize; ++$offset) {
78 + if ($offset === ($stackSize - 1) || $delimiter !== $stack[$offset + 1]) {
79 + $newStack[] = $stack[$offset];
80 + continue;
81 + }
82 + $length = 2; //Number of elements to be joined
83 + for ($i = $offset + 3; $i < $stackSize; $i += 2, ++$length) {
84 + if ($delimiter !== $stack[$i]) {
73 85 break;
74 86 }
75 87 }
76 - $oList = new RuleValueList($sDelimiter, $oParserState->currentLine());
77 - for ($i = $iStartPosition - 1; $i - $iStartPosition + 1 < $iLength * 2; $i += 2) {
78 - $oList->addListComponent($aStack[$i]);
88 + $list = new RuleValueList($delimiter, $parserState->currentLine());
89 + for ($i = $offset; $i - $offset < $length * 2; $i += 2) {
90 + $list->addListComponent($stack[$i]);
79 91 }
80 - array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, [$oList]);
92 + $newStack[] = $list;
93 + $offset += $length * 2 - 2;
81 94 }
95 + $stack = $newStack;
82 96 }
83 - if (!isset($aStack[0])) {
97 + if (!isset($stack[0])) {
84 98 throw new UnexpectedTokenException(
85 - " {$oParserState->peek()} ",
86 - $oParserState->peek(1, -1) . $oParserState->peek(2),
99 + " {$parserState->peek()} ",
100 + $parserState->peek(1, -1) . $parserState->peek(2),
87 101 'literal',
88 - $oParserState->currentLine()
102 + $parserState->currentLine()
89 103 );
90 104 }
91 - return $aStack[0];
105 + return $stack[0];
92 106 }
93 107
94 108 /**
95 - * @param bool $bIgnoreCase
96 - *
97 109 * @return CSSFunction|string
98 110 *
99 111 * @throws UnexpectedEOFException
100 112 * @throws UnexpectedTokenException
113 + *
114 + * @internal since V8.8.0
101 115 */
102 - public static function parseIdentifierOrFunction(ParserState $oParserState, $bIgnoreCase = false)
116 + public static function parseIdentifierOrFunction(ParserState $parserState, bool $ignoreCase = false)
103 117 {
104 - $sResult = $oParserState->parseIdentifier($bIgnoreCase);
118 + $anchor = $parserState->anchor();
119 + $result = $parserState->parseIdentifier($ignoreCase);
105 120
106 - if ($oParserState->comes('(')) {
107 - $oParserState->consume('(');
108 - $aArguments = Value::parseValue($oParserState, ['=', ' ', ',']);
109 - $sResult = new CSSFunction($sResult, $aArguments, ',', $oParserState->currentLine());
110 - $oParserState->consume(')');
121 + if ($parserState->comes('(')) {
122 + $anchor->backtrack();
123 + if ($parserState->streql('url', $result)) {
124 + $result = URL::parse($parserState);
125 + } elseif ($parserState->streql('calc', $result)) {
126 + $result = CalcFunction::parse($parserState);
127 + } else {
128 + $result = CSSFunction::parse($parserState, $ignoreCase);
129 + }
111 130 }
112 131
113 - return $sResult;
132 + return $result;
114 133 }
115 134
116 135 /**
117 136 * @return CSSFunction|CSSString|LineName|Size|URL|string
@@ -118,81 +137,75 @@
118 137 *
119 138 * @throws UnexpectedEOFException
120 139 * @throws UnexpectedTokenException
121 140 * @throws SourceException
141 + *
142 + * @internal since V8.8.0
122 143 */
123 - public static function parsePrimitiveValue(ParserState $oParserState)
144 + public static function parsePrimitiveValue(ParserState $parserState)
124 145 {
125 - $oValue = null;
126 - $oParserState->consumeWhiteSpace();
146 + $value = null;
147 + $parserState->consumeWhiteSpace();
127 148 if (
128 - is_numeric($oParserState->peek())
129 - || ($oParserState->comes('-.')
130 - && is_numeric($oParserState->peek(1, 2)))
131 - || (($oParserState->comes('-') || $oParserState->comes('.')) && is_numeric($oParserState->peek(1, 1)))
149 + \is_numeric($parserState->peek())
150 + || ($parserState->comes('-.')
151 + && \is_numeric($parserState->peek(1, 2)))
152 + || (($parserState->comes('-') || $parserState->comes('.')) && \is_numeric($parserState->peek(1, 1)))
132 153 ) {
133 - $oValue = Size::parse($oParserState);
134 - } elseif ($oParserState->comes('#') || $oParserState->comes('rgb', true) || $oParserState->comes('hsl', true)) {
135 - $oValue = Color::parse($oParserState);
136 - } elseif ($oParserState->comes('url', true)) {
137 - $oValue = URL::parse($oParserState);
138 - } elseif (
139 - $oParserState->comes('calc', true) || $oParserState->comes('-webkit-calc', true)
140 - || $oParserState->comes('-moz-calc', true)
141 - ) {
142 - $oValue = CalcFunction::parse($oParserState);
143 - } elseif ($oParserState->comes("'") || $oParserState->comes('"')) {
144 - $oValue = CSSString::parse($oParserState);
145 - } elseif ($oParserState->comes("progid:") && $oParserState->getSettings()->bLenientParsing) {
146 - $oValue = self::parseMicrosoftFilter($oParserState);
147 - } elseif ($oParserState->comes("[")) {
148 - $oValue = LineName::parse($oParserState);
149 - } elseif ($oParserState->comes("U+")) {
150 - $oValue = self::parseUnicodeRangeValue($oParserState);
154 + $value = Size::parse($parserState);
155 + } elseif ($parserState->comes('#') || $parserState->comes('rgb', true) || $parserState->comes('hsl', true)) {
156 + $value = Color::parse($parserState);
157 + } elseif ($parserState->comes("'") || $parserState->comes('"')) {
158 + $value = CSSString::parse($parserState);
159 + } elseif ($parserState->comes('progid:') && $parserState->getSettings()->usesLenientParsing()) {
160 + $value = self::parseMicrosoftFilter($parserState);
161 + } elseif ($parserState->comes('[')) {
162 + $value = LineName::parse($parserState);
163 + } elseif ($parserState->comes('U+')) {
164 + $value = self::parseUnicodeRangeValue($parserState);
151 165 } else {
152 - $oValue = self::parseIdentifierOrFunction($oParserState);
166 + $nextCharacter = $parserState->peek(1);
167 + try {
168 + $value = self::parseIdentifierOrFunction($parserState);
169 + } catch (UnexpectedTokenException $e) {
170 + if (\in_array($nextCharacter, ['+', '-', '*', '/'], true)) {
171 + $value = $parserState->consume(1);
172 + } else {
173 + throw $e;
174 + }
175 + }
153 176 }
154 - $oParserState->consumeWhiteSpace();
155 - return $oValue;
177 + $parserState->consumeWhiteSpace();
178 +
179 + return $value;
156 180 }
157 181
158 182 /**
159 - * @return CSSFunction
160 - *
161 183 * @throws UnexpectedEOFException
162 184 * @throws UnexpectedTokenException
163 185 */
164 - private static function parseMicrosoftFilter(ParserState $oParserState)
186 + private static function parseMicrosoftFilter(ParserState $parserState): CSSFunction
165 187 {
166 - $sFunction = $oParserState->consumeUntil('(', false, true);
167 - $aArguments = Value::parseValue($oParserState, [',', '=']);
168 - return new CSSFunction($sFunction, $aArguments, ',', $oParserState->currentLine());
188 + $function = $parserState->consumeUntil('(', false, true);
189 + $arguments = Value::parseValue($parserState, [',', '=']);
190 + return new CSSFunction($function, $arguments, ',', $parserState->currentLine());
169 191 }
170 192
171 193 /**
172 - * @return string
173 - *
174 194 * @throws UnexpectedEOFException
175 195 * @throws UnexpectedTokenException
176 196 */
177 - private static function parseUnicodeRangeValue(ParserState $oParserState)
197 + private static function parseUnicodeRangeValue(ParserState $parserState): string
178 198 {
179 - $iCodepointMaxLength = 6; // Code points outside BMP can use up to six digits
180 - $sRange = "";
181 - $oParserState->consume("U+");
199 + $codepointMaxLength = 6; // Code points outside BMP can use up to six digits
200 + $range = '';
201 + $parserState->consume('U+');
182 202 do {
183 - if ($oParserState->comes('-')) {
184 - $iCodepointMaxLength = 13; // Max length is 2 six digit code points + the dash(-) between them
203 + if ($parserState->comes('-')) {
204 + $codepointMaxLength = 13; // Max length is 2 six-digit code points + the dash(-) between them
185 205 }
186 - $sRange .= $oParserState->consume(1);
187 - } while (strlen($sRange) < $iCodepointMaxLength && preg_match("/[A-Fa-f0-9\?-]/", $oParserState->peek()));
188 - return "U+{$sRange}";
189 - }
206 + $range .= $parserState->consume(1);
207 + } while (\strlen($range) < $codepointMaxLength && \preg_match('/[A-Fa-f0-9\\?-]/', $parserState->peek()));
190 208
191 - /**
192 - * @return int
193 - */
194 - public function getLineNo()
195 - {
196 - return $this->iLineNo;
209 + return "U+{$range}";
197 210 }
198 211 }