PluginProbe ʕ •ᴥ•ʔ
MailPoet – Newsletters, Email Marketing, and Automation / 5.23.1
MailPoet – Newsletters, Email Marketing, and Automation v5.23.1
5.28.1 5.28.0 5.27.0 5.26.0 5.26.1 5.25.0 5.24.0 4.43.0 4.43.1 4.44.0 4.44.1 4.45.0 4.46.0 4.47.0 4.48.0 4.48.1 4.48.2 4.49.0 4.49.1 4.5.0 4.5.1 4.5.2 4.50.0 4.50.1 4.51.0 4.51.1 4.51.2 4.52.0 4.53.0 4.54.0 4.55.0 4.56.0 4.57.0 4.58.0 4.58.1 4.58.2 4.6.0 4.6.1 4.6.2 4.7.0 4.7.1 4.8.0 4.8.1 4.9.0 5.0.0 5.0.1 5.0.2 5.1.0 5.1.1 5.10.0 5.10.1 5.11.0 5.12.0 5.12.1 5.12.10 5.12.11 5.12.12 5.12.13 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.12.7 5.12.8 5.12.9 5.13.0 5.13.1 5.13.2 5.14.0 5.14.1 5.14.2 5.14.3 5.15.0 5.15.1 5.16.0 5.16.1 5.16.2 5.16.3 5.16.4 5.17.0 5.17.1 5.17.2 5.17.3 5.17.4 5.17.5 5.17.6 5.18.0 5.19.0 5.2.0 5.2.1 5.2.2 5.2.3 5.20.0 5.21.0 5.21.1 5.21.2 5.21.3 5.22.0 5.22.1 5.22.2 5.22.3 5.22.4 5.23.0 5.23.1 5.23.2 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 5.5.2 5.6.0 5.6.1 5.6.2 5.6.3 5.6.4 5.7.0 5.7.1 5.8.0 5.8.1 5.9.0 3.0.0-beta.15 3.7.1 3.0.0-beta.16 3.7.2 3.0.0-beta.17 3.7.3 3.0.0-beta.18 3.7.4 3.0.0-beta.19 3.7.5 3.0.0-beta.2 3.7.6 3.0.0-beta.20 3.7.8 3.0.0-beta.21 3.70.0 3.0.0-beta.22 3.71.0 3.0.0-beta.23 3.71.1 3.0.0-beta.23.1 3.71.2 3.0.0-beta.23.2 3.71.3 3.0.0-beta.24 3.72.0 3.0.0-beta.25 3.73.0 3.0.0-beta.26 3.73.1 3.0.0-beta.27 3.73.2 3.0.0-beta.28 3.74.0 3.0.0-beta.29 3.74.1 3.0.0-beta.3 3.74.2 3.0.0-beta.30 3.74.3 3.0.0-beta.31 3.75.0 3.0.0-beta.32 3.75.1 3.0.0-beta.33 3.76.0 3.0.0-beta.33.1 3.77.0 3.0.0-beta.34.0.0 3.77.1 3.0.0-beta.36.0.0 3.78.0 3.0.0-beta.36.0.1 3.79.0 3.0.0-beta.36.2.0 3.8 3.0.0-beta.36.3.0 3.8.1 3.0.0-beta.36.3.1 3.8.2 3.0.0-beta.37.0.0 3.8.3 3.0.0-beta.4 3.8.4 3.0.0-beta.5 3.8.5 3.0.0-beta.6 3.8.6 3.0.0-beta.7 3.80.0 3.0.0-beta.7.1 3.81.0 3.0.0-beta.8 3.82.0 3.0.0-beta.9 3.83.0 3.0.0-rc.1.0.0 3.84.0 3.0.0-rc.1.0.1 3.84.1 3.0.0-rc.1.0.2 3.85.0 3.0.0-rc.1.0.3 3.85.1 3.0.0-rc.1.0.4 3.86.0 3.0.0-rc.2.0.0 3.87.0 3.0.0-rc.2.0.1 3.87.1 3.0.0-rc.2.0.2 3.87.2 3.0.0-rc.2.0.3 3.88.0 3.0.1 3.88.1 3.0.2 3.88.2 3.0.3 3.89.0 3.0.4 3.89.1 3.0.5 3.89.2 3.0.6 3.89.3 3.0.7 3.89.4 3.0.8 3.9.0 3.0.9 3.9.1 3.1.0 3.90.0 3.10 3.90.1 3.10.1 3.90.2 3.100.0 3.91.0 3.100.1 3.91.1 3.100.2 3.92.0 3.101.0 3.92.1 3.101.1 3.93.0 3.102.0 3.93.1 3.102.1 3.94.0 3.103.0 3.95.0 3.103.1 3.95.1 3.11.0 3.96.0 3.11.1 3.96.1 3.11.2 3.97.0 3.11.3 3.98.0 3.11.4 3.98.1 3.11.5 3.99.0 3.12.0 3.99.1 3.12.1 4.0.0 3.13.0 4.0.1 3.14.0 4.1.0 3.14.1 4.1.1 3.15.0 4.10.0 3.16.0 4.11.0 3.16.1 4.11.1 3.16.2 4.12.0 3.16.3 4.12.1 3.17.0 4.12.2 3.17.1 4.13.0 3.17.2 4.14.0 3.18.0 4.15.0 3.18.1 4.16.0 3.18.2 4.17.0 3.19.0 4.17.1 3.19.1 4.18.0 3.19.2 4.18.1 3.19.3 4.19.0 3.2.0 4.2.0 3.2.1 4.20.0 3.2.2 4.20.1 3.2.3 4.20.2 3.2.4 4.21.0 3.2.5 4.22.0 3.20.0 4.22.1 3.21.0 4.22.2 3.21.1 4.23.0 3.22.0 4.24.0 3.23.0 4.25.0 3.23.1 4.26.0 3.23.2 4.26.1 3.24.0 4.27.0 3.25.0 4.28.0 3.25.1 4.29.0 3.26.0 4.3.0 3.26.1 4.3.1 3.27.0 4.30.0 3.28.0 4.31.0 3.29.0 4.31.1 3.3.0 4.32.0 3.3.1 4.33.0 3.3.2 4.34.0 3.3.3 4.35.0 3.3.4 4.35.1 3.3.5 4.36.0 3.3.6 4.37.0 3.30.0 4.38.0 3.31.0 4.39.0 3.31.1 4.4.0 3.32.0 4.40.0 3.32.1 4.41.0 3.32.2 4.41.1 3.33.0 4.41.2 3.34.0 4.41.3 3.34.1 4.42.0 3.34.2 4.42.1 3.34.3 3.34.4 3.35.0 3.35.1 3.35.3 3.35.4 3.36.0 3.37.0 3.37.1 3.37.2 3.37.3 3.38.0 3.38.1 3.39.0 3.39.1 3.39.2 3.4.0 3.4.1 3.4.2 3.4.3 3.4.4 3.40.0 3.40.1 3.41.0 3.41.1 3.41.2 3.42.0 3.42.1 3.42.2 3.42.3 3.43.0 3.43.1 3.44.0 3.45.0 3.45.1 3.46.0 3.46.1 3.46.10 3.46.11 3.46.12 3.46.13 3.46.14 3.46.2 3.46.3 3.46.4 3.46.5 3.46.6 3.46.7 3.46.8 3.46.9 3.47.0 3.47.1 3.47.10 3.47.11 3.47.2 3.47.3 3.47.5 3.47.6 3.47.7 3.47.9 3.48.0 3.48.1 3.49.0 3.49.1 3.5.0 3.5.1 3.50.0 3.51.0 3.51.1 3.51.2 3.52.0 3.53.0 3.54.0 3.54.1 3.54.2 3.54.3 3.55.0 3.55.1 3.56.0 3.56.1 3.56.2 3.57.0 3.57.1 3.58.0 3.59.0 3.59.1 3.59.2 3.6.0 3.6.1 3.6.2 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.60.0 3.60.1 3.60.10 3.60.11 3.60.12 3.60.2 3.60.3 3.60.4 3.60.6 3.60.7 3.60.8 3.60.9 3.61.0 3.62.0 3.62.1 3.63.0 3.64.0 3.64.1 3.64.2 3.64.3 3.65.0 trunk 3.65.1 3.0.0 3.66.0 3.0.0-beta.1 3.67.0 3.0.0-beta.10 3.67.1 3.0.0-beta.11 3.68.0 3.0.0-beta.12 3.69.0 3.0.0-beta.13 3.69.1 3.0.0-beta.14 3.7.0
mailpoet / vendor-prefixed / symfony / css-selector / Parser / Parser.php
mailpoet / vendor-prefixed / symfony / css-selector / Parser Last commit date
Handler 2 years ago Shortcut 2 years ago Tokenizer 2 years ago Parser.php 2 years ago ParserInterface.php 2 years ago Reader.php 2 years ago Token.php 2 years ago TokenStream.php 2 years ago index.php 2 years ago
Parser.php
245 lines
1 <?php
2 namespace MailPoetVendor\Symfony\Component\CssSelector\Parser;
3 if (!defined('ABSPATH')) exit;
4 use MailPoetVendor\Symfony\Component\CssSelector\Exception\SyntaxErrorException;
5 use MailPoetVendor\Symfony\Component\CssSelector\Node;
6 use MailPoetVendor\Symfony\Component\CssSelector\Parser\Tokenizer\Tokenizer;
7 class Parser implements ParserInterface
8 {
9 private $tokenizer;
10 public function __construct(?Tokenizer $tokenizer = null)
11 {
12 $this->tokenizer = $tokenizer ?? new Tokenizer();
13 }
14 public function parse(string $source) : array
15 {
16 $reader = new Reader($source);
17 $stream = $this->tokenizer->tokenize($reader);
18 return $this->parseSelectorList($stream);
19 }
20 public static function parseSeries(array $tokens) : array
21 {
22 foreach ($tokens as $token) {
23 if ($token->isString()) {
24 throw SyntaxErrorException::stringAsFunctionArgument();
25 }
26 }
27 $joined = \trim(\implode('', \array_map(function (Token $token) {
28 return $token->getValue();
29 }, $tokens)));
30 $int = function ($string) {
31 if (!\is_numeric($string)) {
32 throw SyntaxErrorException::stringAsFunctionArgument();
33 }
34 return (int) $string;
35 };
36 switch (\true) {
37 case 'odd' === $joined:
38 return [2, 1];
39 case 'even' === $joined:
40 return [2, 0];
41 case 'n' === $joined:
42 return [1, 0];
43 case !\str_contains($joined, 'n'):
44 return [0, $int($joined)];
45 }
46 $split = \explode('n', $joined);
47 $first = $split[0] ?? null;
48 return [$first ? '-' === $first || '+' === $first ? $int($first . '1') : $int($first) : 1, isset($split[1]) && $split[1] ? $int($split[1]) : 0];
49 }
50 private function parseSelectorList(TokenStream $stream) : array
51 {
52 $stream->skipWhitespace();
53 $selectors = [];
54 while (\true) {
55 $selectors[] = $this->parserSelectorNode($stream);
56 if ($stream->getPeek()->isDelimiter([','])) {
57 $stream->getNext();
58 $stream->skipWhitespace();
59 } else {
60 break;
61 }
62 }
63 return $selectors;
64 }
65 private function parserSelectorNode(TokenStream $stream) : Node\SelectorNode
66 {
67 [$result, $pseudoElement] = $this->parseSimpleSelector($stream);
68 while (\true) {
69 $stream->skipWhitespace();
70 $peek = $stream->getPeek();
71 if ($peek->isFileEnd() || $peek->isDelimiter([','])) {
72 break;
73 }
74 if (null !== $pseudoElement) {
75 throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
76 }
77 if ($peek->isDelimiter(['+', '>', '~'])) {
78 $combinator = $stream->getNext()->getValue();
79 $stream->skipWhitespace();
80 } else {
81 $combinator = ' ';
82 }
83 [$nextSelector, $pseudoElement] = $this->parseSimpleSelector($stream);
84 $result = new Node\CombinedSelectorNode($result, $combinator, $nextSelector);
85 }
86 return new Node\SelectorNode($result, $pseudoElement);
87 }
88 private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = \false) : array
89 {
90 $stream->skipWhitespace();
91 $selectorStart = \count($stream->getUsed());
92 $result = $this->parseElementNode($stream);
93 $pseudoElement = null;
94 while (\true) {
95 $peek = $stream->getPeek();
96 if ($peek->isWhitespace() || $peek->isFileEnd() || $peek->isDelimiter([',', '+', '>', '~']) || $insideNegation && $peek->isDelimiter([')'])) {
97 break;
98 }
99 if (null !== $pseudoElement) {
100 throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
101 }
102 if ($peek->isHash()) {
103 $result = new Node\HashNode($result, $stream->getNext()->getValue());
104 } elseif ($peek->isDelimiter(['.'])) {
105 $stream->getNext();
106 $result = new Node\ClassNode($result, $stream->getNextIdentifier());
107 } elseif ($peek->isDelimiter(['['])) {
108 $stream->getNext();
109 $result = $this->parseAttributeNode($result, $stream);
110 } elseif ($peek->isDelimiter([':'])) {
111 $stream->getNext();
112 if ($stream->getPeek()->isDelimiter([':'])) {
113 $stream->getNext();
114 $pseudoElement = $stream->getNextIdentifier();
115 continue;
116 }
117 $identifier = $stream->getNextIdentifier();
118 if (\in_array(\strtolower($identifier), ['first-line', 'first-letter', 'before', 'after'])) {
119 // Special case: CSS 2.1 pseudo-elements can have a single ':'.
120 // Any new pseudo-element must have two.
121 $pseudoElement = $identifier;
122 continue;
123 }
124 if (!$stream->getPeek()->isDelimiter(['('])) {
125 $result = new Node\PseudoNode($result, $identifier);
126 continue;
127 }
128 $stream->getNext();
129 $stream->skipWhitespace();
130 if ('not' === \strtolower($identifier)) {
131 if ($insideNegation) {
132 throw SyntaxErrorException::nestedNot();
133 }
134 [$argument, $argumentPseudoElement] = $this->parseSimpleSelector($stream, \true);
135 $next = $stream->getNext();
136 if (null !== $argumentPseudoElement) {
137 throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
138 }
139 if (!$next->isDelimiter([')'])) {
140 throw SyntaxErrorException::unexpectedToken('")"', $next);
141 }
142 $result = new Node\NegationNode($result, $argument);
143 } else {
144 $arguments = [];
145 $next = null;
146 while (\true) {
147 $stream->skipWhitespace();
148 $next = $stream->getNext();
149 if ($next->isIdentifier() || $next->isString() || $next->isNumber() || $next->isDelimiter(['+', '-'])) {
150 $arguments[] = $next;
151 } elseif ($next->isDelimiter([')'])) {
152 break;
153 } else {
154 throw SyntaxErrorException::unexpectedToken('an argument', $next);
155 }
156 }
157 if (empty($arguments)) {
158 throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
159 }
160 $result = new Node\FunctionNode($result, $identifier, $arguments);
161 }
162 } else {
163 throw SyntaxErrorException::unexpectedToken('selector', $peek);
164 }
165 }
166 if (\count($stream->getUsed()) === $selectorStart) {
167 throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek());
168 }
169 return [$result, $pseudoElement];
170 }
171 private function parseElementNode(TokenStream $stream) : Node\ElementNode
172 {
173 $peek = $stream->getPeek();
174 if ($peek->isIdentifier() || $peek->isDelimiter(['*'])) {
175 if ($peek->isIdentifier()) {
176 $namespace = $stream->getNext()->getValue();
177 } else {
178 $stream->getNext();
179 $namespace = null;
180 }
181 if ($stream->getPeek()->isDelimiter(['|'])) {
182 $stream->getNext();
183 $element = $stream->getNextIdentifierOrStar();
184 } else {
185 $element = $namespace;
186 $namespace = null;
187 }
188 } else {
189 $element = $namespace = null;
190 }
191 return new Node\ElementNode($namespace, $element);
192 }
193 private function parseAttributeNode(Node\NodeInterface $selector, TokenStream $stream) : Node\AttributeNode
194 {
195 $stream->skipWhitespace();
196 $attribute = $stream->getNextIdentifierOrStar();
197 if (null === $attribute && !$stream->getPeek()->isDelimiter(['|'])) {
198 throw SyntaxErrorException::unexpectedToken('"|"', $stream->getPeek());
199 }
200 if ($stream->getPeek()->isDelimiter(['|'])) {
201 $stream->getNext();
202 if ($stream->getPeek()->isDelimiter(['='])) {
203 $namespace = null;
204 $stream->getNext();
205 $operator = '|=';
206 } else {
207 $namespace = $attribute;
208 $attribute = $stream->getNextIdentifier();
209 $operator = null;
210 }
211 } else {
212 $namespace = $operator = null;
213 }
214 if (null === $operator) {
215 $stream->skipWhitespace();
216 $next = $stream->getNext();
217 if ($next->isDelimiter([']'])) {
218 return new Node\AttributeNode($selector, $namespace, $attribute, 'exists', null);
219 } elseif ($next->isDelimiter(['='])) {
220 $operator = '=';
221 } elseif ($next->isDelimiter(['^', '$', '*', '~', '|', '!']) && $stream->getPeek()->isDelimiter(['='])) {
222 $operator = $next->getValue() . '=';
223 $stream->getNext();
224 } else {
225 throw SyntaxErrorException::unexpectedToken('operator', $next);
226 }
227 }
228 $stream->skipWhitespace();
229 $value = $stream->getNext();
230 if ($value->isNumber()) {
231 // if the value is a number, it's casted into a string
232 $value = new Token(Token::TYPE_STRING, (string) $value->getValue(), $value->getPosition());
233 }
234 if (!($value->isIdentifier() || $value->isString())) {
235 throw SyntaxErrorException::unexpectedToken('string or identifier', $value);
236 }
237 $stream->skipWhitespace();
238 $next = $stream->getNext();
239 if (!$next->isDelimiter([']'])) {
240 throw SyntaxErrorException::unexpectedToken('"]"', $next);
241 }
242 return new Node\AttributeNode($selector, $namespace, $attribute, $operator, $value->getValue());
243 }
244 }
245