From a5b158c0f5565712c2f788eab63944dd18547eb2 Mon Sep 17 00:00:00 2001 From: Thierry Bela Date: Fri, 11 Nov 2022 22:32:22 -0500 Subject: [PATCH 01/10] #139 adding text-decoration shorthand --- .../Declaration}/Comment.php | 3 +- .../Declaration}/Config.php | 25 +- .../Declaration}/Property.php | 2 +- .../Declaration}/PropertyList.php | 3 +- src/Element/Declaration/PropertyMap.php | 473 ++++++++++++++++++ .../Declaration}/PropertySet.php | 2 +- .../Declaration}/PropertyTrait.php | 2 +- src/Element/RuleList.php | 4 +- src/Parser.php | 5 +- src/Parser/ParserTrait.php | 3 +- src/Process/Pool.php | 23 +- src/Property/PropertyMap.php | 446 ----------------- src/Renderer.php | 4 +- src/Value.php | 15 +- src/Value/BackgroundImage.php | 5 - src/Value/BackgroundPosition.php | 6 - src/Value/BackgroundRepeat.php | 2 +- src/Value/Color.php | 16 +- src/Value/CssAttribute.php | 5 - src/Value/CssFunction.php | 8 - src/Value/CssString.php | 10 - src/Value/CssUrl.php | 8 +- src/Value/FontFamily.php | 34 +- src/Value/FontSize.php | 11 - src/Value/FontStretch.php | 11 +- src/Value/FontWeight.php | 9 - src/Value/InvalidCssFunction.php | 4 +- src/Value/InvalidCssString.php | 4 +- src/Value/Keyword.php | 22 + src/Value/LineHeight.php | 8 - src/Value/Number.php | 20 +- src/Value/ParsableTrait.php | 41 ++ src/Value/ShortHand.php | 16 +- src/Value/TextDecoration.php | 95 ++++ src/Value/TextDecorationColor.php | 13 + src/Value/TextDecorationLine.php | 26 + src/Value/TextDecorationStyle.php | 24 + src/Value/TextDecorationThickness.php | 18 + src/Value/Unit.php | 36 +- src/Value/UnitTrait.php | 21 - src/Value/ValueTrait.php | 3 +- src/Value/Whitespace.php | 2 +- src/config.json | 2 +- test/src/BackgroundTest.php | 2 +- test/src/FontTest.php | 3 +- test/src/PropertiesTest.php | 19 +- test/src/RendererTest.php | 5 +- tool/BuildConfig.php | 61 ++- 48 files changed, 871 insertions(+), 709 deletions(-) rename src/{Property => Element/Declaration}/Comment.php (96%) rename src/{Property => Element/Declaration}/Config.php (86%) rename src/{Property => Element/Declaration}/Property.php (98%) rename src/{Property => Element/Declaration}/PropertyList.php (99%) create mode 100755 src/Element/Declaration/PropertyMap.php rename src/{Property => Element/Declaration}/PropertySet.php (99%) rename src/{Property => Element/Declaration}/PropertyTrait.php (93%) delete mode 100755 src/Property/PropertyMap.php create mode 100755 src/Value/Keyword.php create mode 100644 src/Value/ParsableTrait.php create mode 100755 src/Value/TextDecoration.php create mode 100755 src/Value/TextDecorationColor.php create mode 100755 src/Value/TextDecorationLine.php create mode 100755 src/Value/TextDecorationStyle.php create mode 100755 src/Value/TextDecorationThickness.php mode change 100755 => 100644 src/config.json diff --git a/src/Property/Comment.php b/src/Element/Declaration/Comment.php similarity index 96% rename from src/Property/Comment.php rename to src/Element/Declaration/Comment.php index 48c32111..ad9be00c 100755 --- a/src/Property/Comment.php +++ b/src/Element/Declaration/Comment.php @@ -1,9 +1,8 @@ $data) { - if (strpos($property, '.') !== false) { + if (str_contains($property, '.')) { continue; } @@ -167,7 +172,7 @@ public static function addSet ($shorthand, $pattern, array $properties, $separat foreach ($properties as $property => $data) { - if (strpos($property, '.') !== false) { + if (str_contains($property, '.')) { $config[$shorthand][preg_replace('#^[^.]+\.#', '', $property)] = $data; continue; @@ -177,7 +182,7 @@ public static function addSet ($shorthand, $pattern, array $properties, $separat if (isset($data['value_map'])) { - $map_keys = $value_map_keys[$properties[$property]['type']]; + $map_keys = $value_map_keys[$data['type']]; $config[$shorthand]['value_map'][$property] = array_map(function ($value) use ($map_keys) { diff --git a/src/Property/Property.php b/src/Element/Declaration/Property.php similarity index 98% rename from src/Property/Property.php rename to src/Element/Declaration/Property.php index c2052118..16853dd9 100755 --- a/src/Property/Property.php +++ b/src/Element/Declaration/Property.php @@ -1,6 +1,6 @@ shorthand = $shorthand; + + $config['required'] = []; + + if (isset($config['properties'])) { + + foreach ($config['properties'] as $property) { + + $config[$property] = Config::getPath('map.' . $property); + + unset($config[$property]['shorthand']); + + $this->property_type[$property] = $config[$property]; + + if (empty($config[$property]['optional'])) { + $config['required'][] = $property; + } + } + } + + $this->config = $config; + } + + // @todo vendor prefix support + public function has($property): bool + { + + return isset($this->properties[$property]); + } + + // @todo vendor prefix support + public function remove($property): static + { + + unset($this->properties[$property]); + + return $this; + } + + /** + * set property value + * @param string $name + * @param object[]|string $value + * @param array|null $leadingcomments + * @param array|null $trailingcomments + * @return PropertyMap + */ + public function set(string $name, $value, ?array $leadingcomments = null, ?array $trailingcomments = null, $src = null) + { + + // is valid property + if (($this->shorthand != $name) && !in_array($name, $this->config['properties'])) { + + throw new InvalidArgumentException('Invalid property ' . $name, 400); + } + + $optionalShorthand = isset($this->config['settings']['optional-shorthand']); + + // if all properties are present, is it safe to use the shorthand? + // font -> no? + // background -> no? + // text-decoration -> yes? + if ($optionalShorthand) { + + foreach ($this->config['required'] as $property) { + + if (!isset($this->properties[$property]) && $name != $property) { + + $optionalShorthand = false; + break; + } + } + } + + if ($optionalShorthand && !isset($this->properties[$this->shorthand])) { + + $this->properties = array_merge([$this->shorthand => new Property($this->shorthand)], $this->properties); + } + + // the type matches the shorthand - example system font + if ($name == $this->shorthand || !isset($this->properties[$this->shorthand])) { + + if ($name == $this->shorthand) { + + $this->properties = []; + } + + if (!isset($this->properties[$name])) { + + $this->properties[$name] = new Property($name); + } + + if ($src !== null) { + + $this->properties[$name]->setSrc($src); + } + + $this->properties[$name]->setValue($value)-> + setLeadingComments($leadingcomments)-> + setTrailingComments($trailingcomments); + + return $this; + } + + $this->properties[$name] = (new Property($name))->setValue($value)-> + setLeadingComments($leadingcomments)-> + setTrailingComments($trailingcomments); + + if ($src !== null) { + + $this->properties[$name]->setSrc($src); + } + + $separator = Config::getPath('map.' . $this->shorthand . '.separator'); + + $all = []; + + if (is_null($separator)) { + + $all = [$this->properties[$this->shorthand]->getValue()]; + } else { + + if (!is_array($value)) { + + $value = Value::parse($value, $name, true, '', '', true); + } + + $index = 0; + foreach ($this->properties[$this->shorthand]->getValue() as $v) { + + if ($v->type == 'separator' && $v->value == $separator) { + + $index++; + continue; + } + + $all[$index][] = $v; + } + + $index = 0; + foreach ($value as $v) { + + if ($v->type == 'separator' && $v->value == $separator) { + + $index++; + continue; + } + + $all[$index][] = $v; + } + } + + $props = []; + foreach ($this->properties as $key => $prop) { + + if ($key == $this->shorthand) { + + continue; + } + + $sep = Config::getPath('properties.' . $key . '.separator'); + $v = []; + + if (is_null($sep)) { + + $v = [$prop->getValue()]; + } else { + + $index = 0; + + foreach ($prop->getValue() as $val) { + + if ($val->type == 'separator' && $val->value == $separator) { + + $index++; + continue; + } + + $v[$index][] = $val; + } + } + + if (count($v) != count($all)) { + + return $this; + } + + $props[$key] = $v; + } + + $properties = $this->property_type; + $results = []; + + foreach ($all as $index => $values) { + + $data = []; + + if (is_null($values)) { + + $values = []; + } + + foreach ($values as $val) { + + if (in_array($val->type, ['separator', 'whitespace'])) { + + continue; + } + + if (!isset($data[$val->type])) { + + $data[$val->type] = $val; + } else { + + if (!is_array($data[$val->type])) { + + $data[$val->type] = [$data[$val->type]]; + } + + $data[$val->type][] = $val; + } + } + + foreach ($props as $k => $prop) { + + if ($name == $this->shorthand) { + + continue; + } + + $data[$k] = $prop[$index]; + } + + // match + $patterns = $this->config['pattern']; + + foreach ($patterns as $p => $pattern) { + + foreach (preg_split('#(\s+)#', $pattern, -1, PREG_SPLIT_NO_EMPTY) as $token) { + + if (empty($this->property_type[$token]['optional']) && (!isset($data[$token]) || (is_array($data[$token]) && !isset($data[$token][$index])))) { + + unset($patterns[$p]); + } + } + } + + if (empty($patterns)) { + + return $this; + } + + // + foreach ($data as $key => $val) { + + if (!is_array($val)) { + + $val = [$val]; + } + + $set = []; + + if (isset($properties[$key]['prefix'])) { + + $prefix = $properties[$key]['prefix']; + $set[] = (object)['type' => 'separator', 'value' => is_array($prefix) ? $prefix[1] : $prefix]; + } + + $set[] = $val[0]; + + // + if (Config::getPath('map.' . $key . '.multiple')) { + + $i = 0; + $j = count($val); + $sp = Config::getPath('map.' . $key . '.separator', ' '); + + $sp = $sp == ' ' ? ['type' => 'whitespace'] : ['type' => 'separator', 'value' => $sp]; + + while (++$i < $j) { + + $set[] = clone((object)$sp); + $set[] = $val[$i]; + } + } + + $data[$key] = $set; + } + + $set = []; + + foreach (preg_split('#(\s+)#', $pattern, -1, PREG_SPLIT_DELIM_CAPTURE) as $token) { + + if (isset($data[$token]) && isset($properties[$token]['prefix']) && is_array($properties[$token]['prefix'])) { + + $res = $set; + $j = count($res); + + while ($j--) { + + if (in_array($res[$j]->type, ['whitespace', 'separator'])) { + + continue; + } + + if ((isset($properties[$token]['multiple']) && $res[$j]->type == $token) || + $res[$j]->type == $properties[$token]['prefix'][0]['type']) { + + break; + } + + if ($res[$j]->type != $properties[$token]['prefix'][0]['type']) { + + return $this; + } + } + } + + if (trim($token) == '') { + + $set[] = (object)['type' => 'whitespace']; + } else if (isset($data[$token])) { + + array_splice($set, count($set), 0, $data[$token]); + } + } + + $results[] = $set; + } + + $set = []; + + $i = 0; + $j = count($results); + + array_splice($set, count($set), 0, $results[0]); + + while (++$i < $j) { + $set[] = (object)['type' => 'separator', 'value' => $separator]; + + array_splice($set, count($set), 0, $results[$i]); + } + + $data = Value::reduce($set, ['remove_defaults' => true]); + + if (empty($data)) { + + $this->properties[$name] = (new Property($name))->setValue($value); + return $this; + } + + $this->properties = [$this->shorthand => (new Property($this->shorthand))->setValue($data)-> + setLeadingComments($leadingcomments)-> + setTrailingComments($trailingcomments)]; + + return $this; + } + + /** + * set property + * @param string $name + * @param string $value + * @return PropertyMap + * @ignore + */ + protected function setProperty($name, $value) + { + + if (!isset($this->properties[$name])) { + + $this->properties[$name] = new Property($name); + } + + $this->properties[$name]->setValue($value); + + return $this; + } + + /** + * return Property array + * @return Property[] + */ + public function getProperties() + { + + return array_values($this->properties); + } + + /** + * convert this object to string + * @param string $join + * @return string + */ + public function render($join = "\n") + { + $glue = ';'; + $value = ''; + + foreach ($this->properties as $property) { + + $value .= $property->render() . $glue . $join; + } + + return rtrim($value, $glue . $join); + } + + /** + * @return bool + */ + + public function isEmpty() + { + + return empty($this->properties); + } + + /** + * convert this object to string + * @return string + */ + public function __toString() + { + + return $this->render(); + } +} \ No newline at end of file diff --git a/src/Property/PropertySet.php b/src/Element/Declaration/PropertySet.php similarity index 99% rename from src/Property/PropertySet.php rename to src/Element/Declaration/PropertySet.php index 27b58618..8e6f9e32 100755 --- a/src/Property/PropertySet.php +++ b/src/Element/Declaration/PropertySet.php @@ -1,6 +1,6 @@ catch(function (\Throwable $t) use($file, $slice) { + + echo new Exception(sprintf("error parsing %s:%s:%s:%s", $file, $slice[0]->line, $slice[0]->column, $slice[0]->index), $t->getCode(), $t); }); } @@ -1093,9 +1096,7 @@ protected function exitNode(object $token): void $context = $this->getContext(); array_pop($context->children); -// array_splice($context->children, count($context->children), 0, $token->children); $context->children = array_merge($context->children, $token->children); - } } diff --git a/src/Parser/ParserTrait.php b/src/Parser/ParserTrait.php index 85f44747..7e84caad 100755 --- a/src/Parser/ParserTrait.php +++ b/src/Parser/ParserTrait.php @@ -2,8 +2,7 @@ namespace TBela\CSS\Parser; -use TBela\CSS\Parser; -use TBela\CSS\Property\Config; +use TBela\CSS\Element\Declaration\Config; trait ParserTrait { diff --git a/src/Process/Pool.php b/src/Process/Pool.php index 30187306..d70a6319 100644 --- a/src/Process/Pool.php +++ b/src/Process/Pool.php @@ -190,7 +190,7 @@ protected function check($collect = true): bool break; } - $data = $this->storage[$thread]->data; + $data = $this->storage[$thread]; if ($collect && $thread->isTerminated()) { @@ -225,7 +225,7 @@ protected function check($collect = true): bool } else if (!$thread->isStarted()) { $thread->start(); - $this->emit('start', $data->index, $thread); + $this->emit('start', $data->data->index, $thread); $running++; } } @@ -366,30 +366,31 @@ public function cancel(): static protected function handleException(Throwable $e, $data): void { $class = new ReflectionClass($e::class); + $handler = null; - while ($class) { + foreach ($data->error as $name => $h) { - if (isset($data->error[$class->getName()])) { + if ($class->isSubclassOf($name)) { + $handler = $h; break; } - - $class = $class->getParentClass(); } - if ($class === false) { + if (is_null($handler)) { - $class = null; - } + if (isset($data->error['generic'])) { - $handler = $data->error[$class?->getName()] ?? $data->error['generic'] ?? null; + $handler = $data->error['generic']; + } + } if (is_callable($handler)) { call_user_func($handler, $e); } else { - throw new UnhandledException(sprintf("unhandled exception in task #%d", $data->index), $e->getCode(), $e); + throw new UnhandledException(sprintf("unhandled exception in task #%d", $data->data->index), $e->getCode(), $e); } } } \ No newline at end of file diff --git a/src/Property/PropertyMap.php b/src/Property/PropertyMap.php deleted file mode 100755 index 44133808..00000000 --- a/src/Property/PropertyMap.php +++ /dev/null @@ -1,446 +0,0 @@ -shorthand = $shorthand; - - $config['required'] = []; - - if (isset($config['properties'])) { - - foreach ($config['properties'] as $property) { - - $config[$property] = Config::getPath('map.' . $property); - - unset($config[$property]['shorthand']); - - $this->property_type[$property] = $config[$property]; - - if (empty($config[$property]['optional'])) { - $config['required'][] = $property; - } - } - } - - $this->config = $config; - } - - // @todo vendor prefix support - public function has($property): bool - { - - return isset($this->properties[$property]); - } - - // @todo vendor prefix support - public function remove($property): static - { - - unset($this->properties[$property]); - - return $this; - } - - /** - * set property value - * @param string $name - * @param object[]|string $value - * @param array|null $leadingcomments - * @param array|null $trailingcomments - * @return PropertyMap - */ - public function set(string $name, $value, ?array $leadingcomments = null, ?array $trailingcomments = null, $src = null) - { - - // is valid property - if (($this->shorthand != $name) && !in_array($name, $this->config['properties'])) { - - throw new InvalidArgumentException('Invalid property ' . $name, 400); - } - - // the type matches the shorthand - example system font - if ($name == $this->shorthand || !isset($this->properties[$this->shorthand])) { - - if ($name == $this->shorthand) { - - $this->properties = []; - } - - if (!isset($this->properties[$name])) { - - $this->properties[$name] = new Property($name); - } - - if ($src !== null) { - - $this->properties[$name]->setSrc($src); - } - - $this->properties[$name]->setValue($value)-> - setLeadingComments($leadingcomments)-> - setTrailingComments($trailingcomments); - - return $this; - } - - $this->properties[$name] = (new Property($name))->setValue($value)-> - setLeadingComments($leadingcomments)-> - setTrailingComments($trailingcomments); - - if ($src !== null) { - - $this->properties[$name]->setSrc($src); - } - - $separator = Config::getPath('map.' . $this->shorthand . '.separator'); - - $all = []; - - if (is_null($separator)) { - - $all = [$this->properties[$this->shorthand]->getValue()]; - } else { - - if (!is_array($value)) { - - $value = Value::parse($value, $name, true, '', '', true); - } - - $index = 0; - foreach ($this->properties[$this->shorthand]->getValue() as $v) { - - if ($v->type == 'separator' && $v->value == $separator) { - - $index++; - continue; - } - - $all[$index][] = $v; - } - - $index = 0; - foreach ($value as $v) { - - if ($v->type == 'separator' && $v->value == $separator) { - - $index++; - continue; - } - - $all[$index][] = $v; - } - } - - $props = []; - foreach ($this->properties as $key => $prop) { - - if ($key == $this->shorthand) { - - continue; - } - - $sep = Config::getPath('properties.' . $key . '.separator'); - $v = []; - - if (is_null($sep)) { - - $v = [$prop->getValue()]; - } else { - - $index = 0; - - foreach ($prop->getValue() as $val) { - - if ($val->type == 'separator' && $val->value == $separator) { - - $index++; - continue; - } - - $v[$index][] = $val; - } - } - - - if (count($v) != count($all)) { - - return $this; - } - - $props[$key] = $v; - } - - $properties = $this->property_type; - $results = []; - - foreach ($all as $index => $values) { - - $data = []; - - foreach ($values as $val) { - - if (in_array($val->type, ['separator', 'whitespace'])) { - - continue; - } - - if (!isset($data[$val->type])) { - - $data[$val->type] = $val; - } else { - - if (!is_array($data[$val->type])) { - - $data[$val->type] = [$data[$val->type]]; - } - - $data[$val->type][] = $val; - } - } - - foreach ($props as $k => $prop) { - - if ($name == $this->shorthand) { - - continue; - } - - $data[$k] = $prop[$index]; - } - - // match - $patterns = $this->config['pattern']; - - foreach ($patterns as $p => $pattern) { - - foreach (preg_split('#(\s+)#', $pattern, -1, PREG_SPLIT_NO_EMPTY) as $token) { - - if (empty($this->property_type[$token]['optional']) && (!isset($data[$token]) || (is_array($data[$token]) && !isset($data[$token][$index])))) { - - unset($patterns[$p]); - } - } - } - - if (empty($patterns)) { - - return $this; - } - - // - foreach ($data as $key => $val) { - - if (!is_array($val)) { - - $val = [$val]; - } - - $set = []; - - if (isset($properties[$key]['prefix'])) { - - $prefix = $properties[$key]['prefix']; - $set[] = (object)['type' => 'separator', 'value' => is_array($prefix) ? $prefix[1] : $prefix]; - } - - $set[] = $val[0]; - - // - if (Config::getPath('map.' . $key . '.multiple')) { - - $i = 0; - $j = count($val); - $sp = Config::getPath('map.' . $key . '.separator', ' '); - - $sp = $sp == ' ' ? ['type' => 'whitespace'] : ['type' => 'separator', 'value' => $sp]; - - while (++$i < $j) { - - $set[] = clone((object)$sp); - $set[] = $val[$i]; - } - } - - $data[$key] = $set; - } - - $set = []; - - foreach (preg_split('#(\s+)#', $pattern, -1, PREG_SPLIT_DELIM_CAPTURE) as $token) { - - if (isset($data[$token]) && isset($properties[$token]['prefix']) && is_array($properties[$token]['prefix'])) { - - $res = $set; - $j = count($res); - - while ($j--) { - - if (in_array($res[$j]->type, ['whitespace', 'separator'])) { - - continue; - } - - if ((isset($properties[$token]['multiple']) && $res[$j]->type == $token) || - $res[$j]->type == $properties[$token]['prefix'][0]['type']) { - - break; - } - - if ($res[$j]->type != $properties[$token]['prefix'][0]['type']) { - - return $this; - } - } - } - - if (trim($token) == '') { - - $set[] = (object)['type' => 'whitespace']; - } else if (isset($data[$token])) { - - array_splice($set, count($set), 0, $data[$token]); - } - } - - $results[] = $set; - } - - $set = []; - - $i = 0; - $j = count($results); - - array_splice($set, count($set), 0, $results[0]); - - while (++$i < $j) { - $set[] = (object)['type' => 'separator', 'value' => $separator]; - - array_splice($set, count($set), 0, $results[$i]); - } - - $data = Value::reduce($set, ['remove_defaults' => true]); - - if (empty($data)) { - - $this->properties[$name] = (new Property($name))->setValue($value); - return $this; - } - - $this->properties = [$this->shorthand => (new Property($this->shorthand))->setValue($data)-> - setLeadingComments($leadingcomments)-> - setTrailingComments($trailingcomments)]; - - return $this; - } - - /** - * set property - * @param string $name - * @param string $value - * @return PropertyMap - * @ignore - */ - protected function setProperty($name, $value) - { - - if (!isset($this->properties[$name])) { - - $this->properties[$name] = new Property($name); - } - - $this->properties[$name]->setValue($value); - - return $this; - } - - /** - * return Property array - * @return Property[] - */ - public function getProperties() - { - - return array_values($this->properties); - } - - /** - * convert this object to string - * @param string $join - * @return string - */ - public function render($join = "\n") - { - $glue = ';'; - $value = ''; - - foreach ($this->properties as $property) { - - $value .= $property->render() . $glue . $join; - } - - return rtrim($value, $glue . $join); - } - - /** - * @return bool - */ - - public function isEmpty() - { - - return empty($this->properties); - } - - /** - * convert this object to string - * @return string - */ - public function __toString() - { - - return $this->render(); - } -} \ No newline at end of file diff --git a/src/Renderer.php b/src/Renderer.php index 941a0092..17e4d001 100755 --- a/src/Renderer.php +++ b/src/Renderer.php @@ -6,14 +6,14 @@ use Exception; use stdClass; use TBela\CSS\Ast\Traverser; +use TBela\CSS\Element\Declaration\PropertyList; use TBela\CSS\Exceptions\IOException; +use TBela\CSS\Interfaces\ElementInterface; use TBela\CSS\Interfaces\ParsableInterface; use TBela\CSS\Interfaces\RenderableInterface; -use TBela\CSS\Interfaces\ElementInterface; use TBela\CSS\Parser\Helper; use TBela\CSS\Parser\SyntaxError; use TBela\CSS\Process\Pool as ProcessPool; -use TBela\CSS\Property\PropertyList; use function is_string; /** diff --git a/src/Value.php b/src/Value.php index c5050752..82b1753b 100755 --- a/src/Value.php +++ b/src/Value.php @@ -5,10 +5,10 @@ use InvalidArgumentException; use JsonSerializable; use stdClass; +use TBela\CSS\Element\Declaration\Config; use TBela\CSS\Interfaces\ObjectInterface; -use TBela\CSS\Property\Config; -use TBela\CSS\Value\Number; use TBela\CSS\Parser\ParserTrait; +use TBela\CSS\Value\Number; /** * CSS value base class @@ -94,6 +94,9 @@ public static function renderTokens(array $tokens, array $options = [], $join = case 'background-size': case 'background-repeat': case 'background-attachment': + case 'text-decoration': + case 'text-decoration-line': + case 'text-decoration-style': $result .= $token->value; @@ -141,6 +144,8 @@ public static function renderTokens(array $tokens, array $options = [], $join = case 'background-image': case 'background-origin': case 'background-position': + case 'text-decoration-color': + case 'text-decoration-thickness': $className = static::getClassName($token->type); $result .= $className::doRender($token, $options); @@ -341,7 +346,7 @@ public static function getInstance($data): Value * @param array $options * @return string */ - public function render(array $options = []): string + final public function render(array $options = []): string { return $this->data->value; @@ -1322,10 +1327,10 @@ protected static function getType(string $token, $preserve_quotes = false) if (substr($token, 0, 1) != '#' && is_numeric($token)) { $type->type = 'number'; - } else if ($token == 'currentcolor' || isset(Color::COLORS_NAMES[$token]) || preg_match('#^\#([a-f0-9]{8}|[a-f0-9]{6}|[a-f0-9]{4}|[a-f0-9]{3})$#i', $token)) { + } else if (strncasecmp($token, 'currentcolor', 12) === 0 || isset(Color::COLORS_NAMES[$token]) || preg_match('#^\#([a-f0-9]{8}|[a-f0-9]{6}|[a-f0-9]{4}|[a-f0-9]{3})$#i', $token)) { $type->type = 'color'; - $type->colorType = $token == 'currentcolor' ? 'keyword' : 'hex'; + $type->colorType = strncasecmp($token, 'currentcolor', 12) === 0 ? 'keyword' : 'hex'; } else if (preg_match('#^(((\+|-)?(?=\d*[.eE])([0-9]+\.?[0-9]*|\.[0-9]+)([eE](\+|-)?[0-9]+)?)|(\d+|(\d*\.\d+)))([a-zA-Z]+|%)$#', $token, $matches)) { $type->type = 'unit'; diff --git a/src/Value/BackgroundImage.php b/src/Value/BackgroundImage.php index 7b59bf11..be8b8bbb 100755 --- a/src/Value/BackgroundImage.php +++ b/src/Value/BackgroundImage.php @@ -27,11 +27,6 @@ protected static function validate($data): bool { return isset($data->name) && isset($data->arguments) && is_array($data->arguments); } - public function render(array $options = []): string - { - return $this->data->value ?? parent::render($options); - } - public static function doRender(object $data, array $options = []) { return $data->value ?? parent::doRender($data, $options); diff --git a/src/Value/BackgroundPosition.php b/src/Value/BackgroundPosition.php index 38befb39..bc919f14 100755 --- a/src/Value/BackgroundPosition.php +++ b/src/Value/BackgroundPosition.php @@ -198,12 +198,6 @@ protected static function check(array $set, $value, ...$values): bool return true; } - public function render(array $options = []): string - { - - return static::doRender($this->data, $options); - } - public static function doRender(object $data, array $options = []) { if (isset($data->unit)) { diff --git a/src/Value/BackgroundRepeat.php b/src/Value/BackgroundRepeat.php index b8148d37..4aa8c231 100755 --- a/src/Value/BackgroundRepeat.php +++ b/src/Value/BackgroundRepeat.php @@ -2,7 +2,7 @@ namespace TBela\CSS\Value; -use TBela\CSS\Property\Config; +use TBela\CSS\Element\Declaration\Config; use TBela\CSS\Value; /** diff --git a/src/Value/Color.php b/src/Value/Color.php index a8a25e9d..b3853381 100755 --- a/src/Value/Color.php +++ b/src/Value/Color.php @@ -13,7 +13,11 @@ class Color extends Value { - /** + use ParsableTrait; + + protected static string $propertyType = 'color'; + + /** * @inheritDoc */ protected static function validate($data):bool @@ -36,16 +40,6 @@ public static function match(object $data, $type): bool return $type == 'color'; } - /** - * @inheritDoc - * @throws \Exception - */ - public function render(array $options = []): string - { - - return static::doRender($this->data, $options); - } - /** * @throws \Exception */ diff --git a/src/Value/CssAttribute.php b/src/Value/CssAttribute.php index ff221484..1a186645 100755 --- a/src/Value/CssAttribute.php +++ b/src/Value/CssAttribute.php @@ -15,11 +15,6 @@ protected static function validate($data): bool { return isset($data->arguments) && is_array($data->arguments); } - public function render(array $options = []): string { - - return '['. $this->data->arguments->render($options).']'; - } - public static function doRender(object $data, array $options = []) { return '['. Value::renderTokens($data->arguments, $options).']'; diff --git a/src/Value/CssFunction.php b/src/Value/CssFunction.php index cb20f880..effc7128 100755 --- a/src/Value/CssFunction.php +++ b/src/Value/CssFunction.php @@ -18,14 +18,6 @@ protected static function validate($data): bool { return isset($data->name) && isset($data->arguments) && is_array($data->arguments); } - /** - * @inheritDoc - */ - public function render(array $options = []): string { - - return $this->data->name.'('. $this->data->arguments->render($options).')'; - } - /** * @inheritDoc */ diff --git a/src/Value/CssString.php b/src/Value/CssString.php index a949985a..0e46e70e 100755 --- a/src/Value/CssString.php +++ b/src/Value/CssString.php @@ -37,16 +37,6 @@ protected function __construct($data) parent::__construct($data); } - /** - * @inheritDoc - * @ignore - */ - public function render(array $options = []): string - { - - return static::doRender($this->data, $options); - } - public static function doRender(object $data, array $options = []) { $q = $data->q ?? ''; diff --git a/src/Value/CssUrl.php b/src/Value/CssUrl.php index 622fb3a8..10a51201 100755 --- a/src/Value/CssUrl.php +++ b/src/Value/CssUrl.php @@ -15,10 +15,10 @@ protected static function validate($data): bool { return $data->name ?? null === 'url' && isset($data->arguments) && is_array($data->arguments); } - public function render(array $options = []): string { - - return $this->data->name.'('. preg_replace('~^(["\'])([^\s\\1]+)\\1$~', '$2', $this->data->arguments->render($options)).')'; - } +// public function render(array $options = []): string { +// +// return $this->data->name.'('. preg_replace('~^(["\'])([^\s\\1]+)\\1$~', '$2', $this->data->arguments->render($options)).')'; +// } /** * @inheritDoc diff --git a/src/Value/FontFamily.php b/src/Value/FontFamily.php index e3df16d8..57a12606 100755 --- a/src/Value/FontFamily.php +++ b/src/Value/FontFamily.php @@ -8,37 +8,7 @@ */ class FontFamily extends ShortHand { - /** - * @inheritDoc - */ - public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool { + use ParsableTrait; - return $token->type == 'css-string' || $token->type == static::type(); - } - - /** - * @inheritDoc - * @throws \Exception - */ - protected static function doParse($string, $capture_whitespace = true, $context = '', $contextName = '', $preserve_quotes = false) - { - - $type = static::type(); - $tokens = static::getTokens($string, $capture_whitespace, $context, $contextName); - - foreach ($tokens as $token) { - - if (static::matchToken($token)) { - - if ($token->type == 'css-string') { - - $token->value = static::stripQuotes($token->value); - } - - $token->type = $type; - } - } - - return static::reduce($tokens); - } + protected static string $propertyType = 'css-string'; } diff --git a/src/Value/FontSize.php b/src/Value/FontSize.php index 835e34f3..6951a925 100755 --- a/src/Value/FontSize.php +++ b/src/Value/FontSize.php @@ -2,8 +2,6 @@ namespace TBela\CSS\Value; -use \TBela\CSS\Value; - /** * Css string value * @package TBela\CSS\Value @@ -45,13 +43,4 @@ public static function matchToken($token, $previousToken = null, $previousValue return $token->type == static::type(); } - - /** - * @inheritDoc - */ - public function render(array $options = []): string - { - - return static::doRender($this->data, $options); - } } diff --git a/src/Value/FontStretch.php b/src/Value/FontStretch.php index 9d1fe63a..7e0445cf 100755 --- a/src/Value/FontStretch.php +++ b/src/Value/FontStretch.php @@ -33,12 +33,13 @@ class FontStretch extends Value /** * @inheritDoc */ - public function render(array $options = []): string - { + public static function doRender(object $data, array $options = []) + { - if (!empty($options['compress'])) { - $value = $this->data->value; + if (!empty($options['compress'])) { + + $value = $data->value; if (isset(static::$keywords[$value])) { @@ -46,7 +47,7 @@ public function render(array $options = []): string } } - return $this->data->value; + return $data->value; } /** diff --git a/src/Value/FontWeight.php b/src/Value/FontWeight.php index 89d3c584..a7ab395a 100755 --- a/src/Value/FontWeight.php +++ b/src/Value/FontWeight.php @@ -34,15 +34,6 @@ class FontWeight extends Value protected static array $defaults = ['normal', '400', 'regular']; - /** - * @inheritDoc - */ - public function render(array $options = []): string - { - - return static::doRender($this->data, $options); - } - public static function doRender(object $data, array $options = []) { diff --git a/src/Value/InvalidCssFunction.php b/src/Value/InvalidCssFunction.php index e22cbe8e..7095d89e 100755 --- a/src/Value/InvalidCssFunction.php +++ b/src/Value/InvalidCssFunction.php @@ -22,9 +22,9 @@ protected static function validate($data): bool { /** * @inheritDoc */ - public function render(array $options = []): string { + public static function doRender(object $data, array $options = []): string { - return $this->data->name.'('. $this->data->arguments->render($options); + return $data->name.'('. $data->arguments->render($options); } /** diff --git a/src/Value/InvalidCssString.php b/src/Value/InvalidCssString.php index 2203e04e..c58fc96f 100755 --- a/src/Value/InvalidCssString.php +++ b/src/Value/InvalidCssString.php @@ -32,10 +32,10 @@ public function getValue() { * @inheritDoc * @ignore */ - public function render(array $options = []): string + public static function doRender(object $data, array $options = []): string { - return $this->data->q.$this->data->value; + return $data->q.$data->value; } public static function doRecover(object $data):object { diff --git a/src/Value/Keyword.php b/src/Value/Keyword.php new file mode 100755 index 00000000..68359f99 --- /dev/null +++ b/src/Value/Keyword.php @@ -0,0 +1,22 @@ +value; + } +} diff --git a/src/Value/LineHeight.php b/src/Value/LineHeight.php index f0d94cb9..a79f8e68 100755 --- a/src/Value/LineHeight.php +++ b/src/Value/LineHeight.php @@ -54,14 +54,6 @@ public static function matchToken($token, $previousToken = null, $previousValue return $token->type == static::type(); } - /** - * @inheritDoc - */ - public function render(array $options = []): string - { - return static::doRender($this->data, $options); - } - public static function doRender(object $data, array $options = []): string { $value = $data->value; diff --git a/src/Value/Number.php b/src/Value/Number.php index 017f924f..c619603c 100755 --- a/src/Value/Number.php +++ b/src/Value/Number.php @@ -48,11 +48,12 @@ protected static function validate($data): bool return isset($data->value) && is_numeric($data->value) && $data->value !== ''; } - /** - * @param string $value - * @return string - * @ignore - */ + /** + * @param string $value + * @param array $options + * @return string + * @ignore + */ public static function compress(string $value, array $options = []): string { @@ -95,18 +96,9 @@ public static function compress(string $value, array $options = []): string return implode('.', $value); } - /** - * @inheritDoc - */ - public function render(array $options = []): string - { - return static::doRender($this->data, $options); - } - public static function doRender(object $data, array $options = []) { - if (!empty($options['compress'])) { return static::compress($data->value, $options); diff --git a/src/Value/ParsableTrait.php b/src/Value/ParsableTrait.php new file mode 100644 index 00000000..a2cc0c73 --- /dev/null +++ b/src/Value/ParsableTrait.php @@ -0,0 +1,41 @@ +type == static::$propertyType || (isset($token->value) && in_array($token->value, static::$keywords)) || $token->type == static::type(); + } + + /** + * @inheritDoc + * @throws \Exception + */ + protected static function doParse(string $string, bool $capture_whitespace = true, $context = '', $contextName = '', $preserve_quotes = false) + { + + $type = static::type(); + $tokens = static::getTokens($string, $capture_whitespace, $context, $contextName); + + foreach ($tokens as $token) { + + if (static::matchToken($token)) { + + if ($token->type == static::$propertyType && isset($token->value)) { + + $token->value = static::stripQuotes($token->value); + } + + $token->type = $type; + } + } + + return static::reduce($tokens); + } +} \ No newline at end of file diff --git a/src/Value/ShortHand.php b/src/Value/ShortHand.php index df5971eb..e6dea099 100755 --- a/src/Value/ShortHand.php +++ b/src/Value/ShortHand.php @@ -2,9 +2,9 @@ namespace TBela\CSS\Value; -use \Exception; -use TBela\CSS\Property\Config; -use \TBela\CSS\Value; +use Exception; +use TBela\CSS\Element\Declaration\Config; +use TBela\CSS\Value; /** * parse shorthand @@ -88,14 +88,8 @@ public static function matchPattern(array $tokens) $j = count($tokens); $previous = null; - $next = null; - for ($i = 0; $i < $j; $i++) { - - if (!isset($tokens[$i]->type)) { - - echo new Exception('empty type not allowed'); - } + for ($i = 0; $i < $j; $i++) { if (in_array($tokens[$i]->type, ['separator', 'whitespace'])) { @@ -120,7 +114,7 @@ public static function matchPattern(array $tokens) $next = $tokens[++$k] ?? null; } - if (call_user_func($className, $tokens[$i], $tokens[$i - 1] ?? null, $previous, $tokens[$i + 1] ?? null, $next, $i, $tokens)) { + if (call_user_func($className, $tokens[$i], $tokens[$i - 1] ?? null, $previous, $tokens[$i + 1] ?? null, $next, $i, $tokens)) { $tokens[$i]->type = $pattern['type']; $previous = $tokens[$i]; diff --git a/src/Value/TextDecoration.php b/src/Value/TextDecoration.php new file mode 100755 index 00000000..ea755cee --- /dev/null +++ b/src/Value/TextDecoration.php @@ -0,0 +1,95 @@ + 'text-decoration-line', 'optional' => true], + ['type' => 'text-decoration-style', 'optional' => true], + ['type' => 'text-decoration-color', 'optional' => true], + ['type' => 'text-decoration-thickness', 'optional' => true] + ] + ]; + + /** + * @inheritDoc + */ +// public static function matchPattern(array $tokens) +// { +// +// $tokens = static::reduce(parent::matchPattern($tokens)); +// +// $result = []; +// +// for ($i = 0; $i < count($tokens); $i++) { +// +// if (in_array($tokens[$i]->type, ['separator', 'whitespace'])) { +// +// $result[] = $tokens[$i]; +// continue; +// } +// +// $k = $i; +// $j = count($tokens); +// $matches = [$tokens[$i]]; +// +// while (++$k < $j) { +// +// if ($tokens[$k]->type == 'whitespace') { +// +// continue; +// } +// +// if ($tokens[$k]->type != $tokens[$i]->type) { +// +// $k = $k - 1; +// +// if (count($matches) == 1) { +// +// array_splice($result, count($result), 0, array_slice($tokens, $i, $k - $i + 1)); +// $i = $k; +// continue 2; +// } +// +// break; +// } else { +// +// $matches[] = $tokens[$k]; +// } +// } +// +// $slice = array_slice($tokens, $i, $k - $i + 1); +// $className = static::getClassName($slice[0]->type); +// $keyword = $className::matchKeyword(Value::renderTokens($slice)); +// +// if (!is_null($keyword)) { +// +// $result[] = (object)['type' => $tokens[$i]->type, 'value' => $keyword]; +// } else { +// +// array_splice($result, count($result), 0, array_slice($tokens, $i, $k - $i + 1)); +// } +// +// $i = $k; +// } +// +// return $result; +// } +} diff --git a/src/Value/TextDecorationColor.php b/src/Value/TextDecorationColor.php new file mode 100755 index 00000000..16e11a4d --- /dev/null +++ b/src/Value/TextDecorationColor.php @@ -0,0 +1,13 @@ +value == 0); } - /** - * @inheritDoc - */ - public function render(array $options = []): string - { + /** + * @inheritDoc + */ + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + { - return static::doRender($this->data, $options); - } + return $token->type == 'unit' || in_array($token->value, static::$keywords) || $token->type == static::type(); + } public static function doRender(object $data, array $options = []) { @@ -82,4 +82,26 @@ public static function doRender(object $data, array $options = []) { return $data->value.$unit; } + + /** + * @inheritDoc + * @throws \Exception + */ + protected static function doParse(string $string, bool $capture_whitespace = true, $context = '', $contextName = '', $preserve_quotes = false) + { + + $type = static::type(); + $tokens = static::getTokens($string, $capture_whitespace, $context, $contextName); + + foreach ($tokens as $token) { + + if (static::matchToken($token)) { + + $token->value = static::stripQuotes($token->value); + $token->type = $type; + } + } + + return static::reduce($tokens); + } } diff --git a/src/Value/UnitTrait.php b/src/Value/UnitTrait.php index 18a14d99..fa6aa449 100755 --- a/src/Value/UnitTrait.php +++ b/src/Value/UnitTrait.php @@ -13,27 +13,6 @@ trait UnitTrait * @inheritDoc */ - public function render(array $options = []): string - { - - if (isset($this->data->unit)) { - - if ($this->data->value == '0') { - - return '0'; - } - - if (!empty($options['compress'])) { - - return Number::compress($this->data->value) . $this->data->unit; - } - - return $this->data->value . $this->data->unit; - } - - return $this->data->value; - } - public static function doRender(object $data, array $options = []) { $value = $data->value; diff --git a/src/Value/ValueTrait.php b/src/Value/ValueTrait.php index 7d58bc77..a07a46da 100755 --- a/src/Value/ValueTrait.php +++ b/src/Value/ValueTrait.php @@ -3,8 +3,7 @@ namespace TBela\CSS\Value; // pattern font-style font-variant font-weight font-stretch font-size / line-height <'font-family'> -use TBela\CSS\Property\Config; -use TBela\CSS\Value; +use TBela\CSS\Element\Declaration\Config; /** * parse font diff --git a/src/Value/Whitespace.php b/src/Value/Whitespace.php index b048abb0..aa9b12b9 100755 --- a/src/Value/Whitespace.php +++ b/src/Value/Whitespace.php @@ -29,7 +29,7 @@ public function getValue () { /** * @inheritDoc */ - public function render(array $options = []): string + public static function doRender(object $data, array $options = []): string { return ' '; } diff --git a/src/config.json b/src/config.json old mode 100755 new mode 100644 index 321ab56a..e3123d8a --- a/src/config.json +++ b/src/config.json @@ -1 +1 @@ -{"map":{"background":{"shorthand":"background","pattern":["background","background-image background-color background-position background-size background-repeat background-attachment background-clip background-origin"],"properties":["background-image","background-color","background-position","background-size","background-repeat","background-attachment","background-clip","background-origin"],"separator":","},"background-image":{"type":"background-image","optional":true,"shorthand":"background"},"background-color":{"type":"background-color","optional":true,"shorthand":"background"},"background-position":{"type":"background-position","multiple":true,"optional":true,"shorthand":"background"},"background-size":{"type":"background-size","multiple":true,"optional":true,"prefix":[{"type":"background-position"},"\/"],"shorthand":"background"},"background-repeat":{"type":"background-repeat","multiple":true,"optional":true,"shorthand":"background"},"background-attachment":{"type":"background-attachment","optional":true,"shorthand":"background"},"background-clip":{"type":"background-clip","optional":true,"shorthand":"background"},"background-origin":{"type":"background-origin","multiple":true,"optional":true,"shorthand":"background"},"font":{"shorthand":"font","pattern":["font","font-weight font-style font-variant font-stretch font-size line-height font-family"],"properties":["font-weight","font-style","font-variant","font-stretch","font-size","line-height","font-family"]},"font-weight":{"type":"font-weight","optional":true,"shorthand":"font"},"font-style":{"type":"font-style","optional":true,"shorthand":"font"},"font-variant":{"type":"font-variant","optional":true,"shorthand":"font"},"font-stretch":{"type":"font-stretch","optional":true,"shorthand":"font"},"font-size":{"type":"font-size","shorthand":"font"},"line-height":{"type":"line-height","optional":true,"previous":"font-size","prefix":"\/","shorthand":"font"},"font-family":{"type":"font-family","multiple":true,"separator":",","shorthand":"font"},"outline":{"shorthand":"outline","pattern":["outline-style outline-width outline-color"],"properties":["outline-style","outline-width","outline-color"],"settings":{"compute":true}},"outline-style":{"type":"outline-style","optional":true,"shorthand":"outline"},"outline-width":{"type":"outline-width","optional":true,"shorthand":"outline"},"outline-color":{"type":"outline-color","optional":true,"shorthand":"outline"}},"properties":{"background-repeat":{"pattern":["background-repeat","background-repeat background-repeat"],"value_map":[],"separator":","},"background-size":{"shorthand":"background","pattern":["background-size","unit unit"],"value_map":[],"separator":","},"background-color":{"shorthand":"background","pattern":["background-color"],"value_map":[],"separator":","},"background-image":{"shorthand":"background","pattern":["background-image"],"value_map":[],"separator":","},"background-position":{"shorthand":"background","pattern":["background-position"],"value_map":[],"separator":","},"margin":{"shorthand":"margin","pattern":["unit unit unit unit"],"value_map":{"margin-left":[1,0],"margin-bottom":[0],"margin-right":[0]},"properties":["margin-top","margin-right","margin-bottom","margin-left"]},"margin-top":{"type":"unit","shorthand":"margin"},"margin-right":{"type":"unit","shorthand":"margin"},"margin-bottom":{"type":"unit","shorthand":"margin"},"margin-left":{"type":"unit","shorthand":"margin"},"padding":{"shorthand":"padding","pattern":["unit unit unit unit"],"value_map":{"padding-left":[1,0],"padding-bottom":[0],"padding-right":[0]},"properties":["padding-top","padding-right","padding-bottom","padding-left"]},"padding-top":{"type":"unit","shorthand":"padding"},"padding-right":{"type":"unit","shorthand":"padding"},"padding-bottom":{"type":"unit","shorthand":"padding"},"padding-left":{"type":"unit","shorthand":"padding"},"border-radius":{"shorthand":"border-radius","pattern":["unit unit unit unit"],"value_map":{"border-bottom-left-radius":[1,0],"border-bottom-right-radius":[0],"border-top-right-radius":[0]},"properties":["border-top-left-radius","border-top-right-radius","border-bottom-right-radius","border-bottom-left-radius"],"separator":"\/"},"border-top-left-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"border-top-right-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"border-bottom-right-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"border-bottom-left-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"-moz-border-radius":{"shorthand":"-moz-border-radius","pattern":["unit unit unit unit"],"value_map":{"-moz-border-radius-bottomleft":[1,0],"-moz-border-radius-bottomright":[0],"-moz-border-radius-topright":[0]},"properties":["-moz-border-radius-topleft","-moz-border-radius-topright","-moz-border-radius-bottomright","-moz-border-radius-bottomleft"],"separator":"\/"},"-moz-border-radius-topleft":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-moz-border-radius-topright":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-moz-border-radius-bottomright":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-moz-border-radius-bottomleft":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-webkit-border-radius":{"shorthand":"-webkit-border-radius","pattern":["unit unit unit unit"],"value_map":{"-webkit-border-bottom-left-radius":[1,0],"-webkit-border-bottom-right-radius":[0],"-webkit-border-top-right-radius":[0]},"properties":["-webkit-border-top-left-radius","-webkit-border-top-right-radius","-webkit-border-bottom-right-radius","-webkit-border-bottom-left-radius"],"separator":"\/"},"-webkit-border-top-left-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"},"-webkit-border-top-right-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"},"-webkit-border-bottom-right-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"},"-webkit-border-bottom-left-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"}}} \ No newline at end of file +{"map":{"background":{"shorthand":"background","pattern":["background","background-image background-color background-position background-size background-repeat background-attachment background-clip background-origin"],"properties":["background-image","background-color","background-position","background-size","background-repeat","background-attachment","background-clip","background-origin"],"separator":","},"background-image":{"type":"background-image","optional":true,"shorthand":"background"},"background-color":{"type":"background-color","optional":true,"shorthand":"background"},"background-position":{"type":"background-position","multiple":true,"optional":true,"shorthand":"background"},"background-size":{"type":"background-size","multiple":true,"optional":true,"prefix":[{"type":"background-position"},"\/"],"shorthand":"background"},"background-repeat":{"type":"background-repeat","multiple":true,"optional":true,"shorthand":"background"},"background-attachment":{"type":"background-attachment","optional":true,"shorthand":"background"},"background-clip":{"type":"background-clip","optional":true,"shorthand":"background"},"background-origin":{"type":"background-origin","multiple":true,"optional":true,"shorthand":"background"},"font":{"shorthand":"font","pattern":["font","font-weight font-style font-variant font-stretch font-size line-height font-family"],"properties":["font-weight","font-style","font-variant","font-stretch","font-size","line-height","font-family"]},"font-weight":{"type":"font-weight","optional":true,"shorthand":"font"},"font-style":{"type":"font-style","optional":true,"shorthand":"font"},"font-variant":{"type":"font-variant","optional":true,"shorthand":"font"},"font-stretch":{"type":"font-stretch","optional":true,"shorthand":"font"},"font-size":{"type":"font-size","shorthand":"font"},"line-height":{"type":"line-height","optional":true,"previous":"font-size","prefix":"\/","shorthand":"font"},"font-family":{"type":"font-family","multiple":true,"separator":",","shorthand":"font"},"outline":{"shorthand":"outline","pattern":["outline-style outline-width outline-color"],"properties":["outline-style","outline-width","outline-color"],"settings":{"compute":true}},"outline-style":{"type":"outline-style","optional":true,"shorthand":"outline"},"outline-width":{"type":"outline-width","optional":true,"shorthand":"outline"},"outline-color":{"type":"outline-color","optional":true,"shorthand":"outline"},"text-decoration":{"shorthand":"text-decoration","pattern":["text-decoration-line text-decoration-color text-decoration-style text-decoration-thickness"],"properties":["text-decoration-thickness","text-decoration-line","text-decoration-color","text-decoration-style"],"settings":{"compute":true,"optional-shorthand":true}},"text-decoration-thickness":{"type":"unit","shorthand":"text-decoration"},"text-decoration-line":{"type":"text-decoration-line","multiple":true,"shorthand":"text-decoration"},"text-decoration-color":{"type":"color","shorthand":"text-decoration"},"text-decoration-style":{"type":"text-decoration-style","shorthand":"text-decoration"}},"properties":{"background-repeat":{"shorthand":"","pattern":["background-repeat","background-repeat background-repeat"],"value_map":[],"separator":","},"background-size":{"shorthand":"background","pattern":["background-size","unit unit"],"value_map":[],"separator":","},"background-color":{"shorthand":"background","pattern":["background-color"],"value_map":[],"separator":","},"background-image":{"shorthand":"background","pattern":["background-image"],"value_map":[],"separator":","},"background-position":{"shorthand":"background","pattern":["background-position"],"value_map":[],"separator":","},"margin":{"shorthand":"margin","pattern":["unit unit unit unit"],"value_map":{"margin-left":[1,0],"margin-bottom":[0],"margin-right":[0]},"properties":["margin-top","margin-right","margin-bottom","margin-left"]},"margin-top":{"type":"unit","shorthand":"margin"},"margin-right":{"type":"unit","shorthand":"margin"},"margin-bottom":{"type":"unit","shorthand":"margin"},"margin-left":{"type":"unit","shorthand":"margin"},"padding":{"shorthand":"padding","pattern":["unit unit unit unit"],"value_map":{"padding-left":[1,0],"padding-bottom":[0],"padding-right":[0]},"properties":["padding-top","padding-right","padding-bottom","padding-left"]},"padding-top":{"type":"unit","shorthand":"padding"},"padding-right":{"type":"unit","shorthand":"padding"},"padding-bottom":{"type":"unit","shorthand":"padding"},"padding-left":{"type":"unit","shorthand":"padding"},"border-radius":{"shorthand":"border-radius","pattern":["unit unit unit unit"],"value_map":{"border-bottom-left-radius":[1,0],"border-bottom-right-radius":[0],"border-top-right-radius":[0]},"properties":["border-top-left-radius","border-top-right-radius","border-bottom-right-radius","border-bottom-left-radius"],"separator":"\/"},"border-top-left-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"border-top-right-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"border-bottom-right-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"border-bottom-left-radius":{"type":"unit","separator":" ","shorthand":"border-radius"},"-moz-border-radius":{"shorthand":"-moz-border-radius","pattern":["unit unit unit unit"],"value_map":{"-moz-border-radius-bottomleft":[1,0],"-moz-border-radius-bottomright":[0],"-moz-border-radius-topright":[0]},"properties":["-moz-border-radius-topleft","-moz-border-radius-topright","-moz-border-radius-bottomright","-moz-border-radius-bottomleft"],"separator":"\/"},"-moz-border-radius-topleft":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-moz-border-radius-topright":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-moz-border-radius-bottomright":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-moz-border-radius-bottomleft":{"type":"unit","separator":" ","shorthand":"-moz-border-radius"},"-webkit-border-radius":{"shorthand":"-webkit-border-radius","pattern":["unit unit unit unit"],"value_map":{"-webkit-border-bottom-left-radius":[1,0],"-webkit-border-bottom-right-radius":[0],"-webkit-border-top-right-radius":[0]},"properties":["-webkit-border-top-left-radius","-webkit-border-top-right-radius","-webkit-border-bottom-right-radius","-webkit-border-bottom-left-radius"],"separator":"\/"},"-webkit-border-top-left-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"},"-webkit-border-top-right-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"},"-webkit-border-bottom-right-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"},"-webkit-border-bottom-left-radius":{"type":"unit","separator":" ","shorthand":"-webkit-border-radius"}}} \ No newline at end of file diff --git a/test/src/BackgroundTest.php b/test/src/BackgroundTest.php index 0a65d179..fe415f14 100755 --- a/test/src/BackgroundTest.php +++ b/test/src/BackgroundTest.php @@ -2,8 +2,8 @@ declare(strict_types=1); use PHPUnit\Framework\TestCase; +use TBela\CSS\Element\Declaration\PropertyList; use TBela\CSS\Parser; -use TBela\CSS\Property\PropertyList; use TBela\CSS\Value; final class BackgroundTest extends TestCase diff --git a/test/src/FontTest.php b/test/src/FontTest.php index 88e42efe..8c704046 100755 --- a/test/src/FontTest.php +++ b/test/src/FontTest.php @@ -2,10 +2,9 @@ declare(strict_types=1); use PHPUnit\Framework\TestCase; -use TBela\CSS\Element; use TBela\CSS\Compiler; +use TBela\CSS\Element\Declaration\PropertyList; use TBela\CSS\Parser; -use TBela\CSS\Property\PropertyList; final class FontTest extends TestCase { diff --git a/test/src/PropertiesTest.php b/test/src/PropertiesTest.php index bb689141..83b5eeb1 100755 --- a/test/src/PropertiesTest.php +++ b/test/src/PropertiesTest.php @@ -2,7 +2,7 @@ declare(strict_types=1); use PHPUnit\Framework\TestCase; -use TBela\CSS\Property\PropertyList; +use TBela\CSS\Element\Declaration\PropertyList; require_once __DIR__.'/../bootstrap.php'; @@ -114,12 +114,19 @@ public function propertySetProvider() $data[] = [$property1, 'margin-left', '0', 'margin: 15px 0']; $data[] = [$property1, 'margin', '0 auto', 'margin: 0 auto']; - $property4 = new PropertyList(); + $property4 = new PropertyList(); - $data[] = [$property4, 'margin-top', '5px \\9', 'margin-top: 5px \\9']; - $data[] = [$property4, 'margin-left', '5px \\9', "margin-top: 5px \\9;\nmargin-left: 5px \\9"]; - $data[] = [$property4, 'margin-bottom', '5px \\9', "margin-top: 5px \\9;\nmargin-left: 5px \\9;\nmargin-bottom: 5px \\9"]; - $data[] = [$property4, 'margin-right', '5px \\9', 'margin: 5px \\9']; + $data[] = [$property4, 'margin-top', '5px \\9', 'margin-top: 5px \\9']; + $data[] = [$property4, 'margin-left', '5px \\9', "margin-top: 5px \\9;\nmargin-left: 5px \\9"]; + $data[] = [$property4, 'margin-bottom', '5px \\9', "margin-top: 5px \\9;\nmargin-left: 5px \\9;\nmargin-bottom: 5px \\9"]; + $data[] = [$property4, 'margin-right', '5px \\9', 'margin: 5px \\9']; + + $property5 = new PropertyList(); + + $data[] = [$property5, 'text-decoration-line', 'line-through ', 'text-decoration-line: line-through']; + $data[] = [$property5, 'text-decoration-color', 'red ', "text-decoration-line: line-through;\ntext-decoration-color: red"]; + $data[] = [$property5, 'text-decoration-style', ' double', "text-decoration-line: line-through;\ntext-decoration-color: red;\ntext-decoration-style: double"]; + $data[] = [$property5, 'text-decoration-thickness', ' 3px ', "text-decoration: line-through red double 3px"]; return $data; } diff --git a/test/src/RendererTest.php b/test/src/RendererTest.php index c039ecdd..73f201cb 100755 --- a/test/src/RendererTest.php +++ b/test/src/RendererTest.php @@ -6,11 +6,8 @@ use TBela\CSS\Compiler; use TBela\CSS\Element\AtRule; use TBela\CSS\Element\Declaration; -use TBela\CSS\Property\PropertyList; -use TBela\CSS\Renderer as RendererClass; use TBela\CSS\Interfaces\ObjectInterface; -use TBela\CSS\Value; -use TBela\CSS\Value\CSSFunction; +use TBela\CSS\Renderer as RendererClass; require_once __DIR__.'/../bootstrap.php'; diff --git a/tool/BuildConfig.php b/tool/BuildConfig.php index c1d417d5..553a3f53 100755 --- a/tool/BuildConfig.php +++ b/tool/BuildConfig.php @@ -10,7 +10,7 @@ require __DIR__ . '/../test/autoload.php'; // properties order is important! -use TBela\CSS\Property\Config; +use TBela\CSS\Element\Declaration\Config; $config = [ // shorthand that can be computed only when every shorthand property is defined because it will override properties that are not directly handled. @@ -60,18 +60,6 @@ ] ], ',')); -//$config['map'] = array_merge($config['map'], makePropertySet('background-attachment', ['background-attachment'], [ -// ['background-attachment', -// ['type' => 'background-attachment', 'optional' => true] -// ] -//], ',', false)); - -//$config['properties'] = array_merge($config['properties'], makePropertySet('background-image', ['background-image'], [ -// ['background-image', -// ['type' => 'background-image', 'optional' => true] -// ] -//], ',', false, null, 'background')); - $config['properties'] = array_merge($config['properties'], makePropertySet('background-size', ['background-size', 'unit unit'], [], ',', false, null,'background')); $config['properties'] = array_merge($config['properties'], makePropertySet('background-color', ['background-color'], [], ',', false, null,'background')); $config['properties'] = array_merge($config['properties'], makePropertySet('background-image', ['background-image'], [], ',', false, null,'background')); @@ -116,19 +104,25 @@ *compute shorthand property */ ['compute' => true])); -// -//$config['properties'] = array_merge($config['properties'], makePropertySet('background-position', -// [ -// 'background-position-x background-position-y', -// 'background-position-y background-position-x' -// ], [ -// ['background-position-x', -// ['type' => 'background-position-x', 'multiple' => true, 'separator' => ',', 'optional' => true] -// ], -// ['background-position-y', -// ['type' => 'background-position-y', 'multiple' => true, 'separator' => ',', 'optional' => true] -// ] -// ], ',', false)); + +$config['map'] = array_merge($config['map'], makePropertySet('text-decoration', ['text-decoration-line text-decoration-color text-decoration-style text-decoration-thickness'], [ + ['text-decoration-thickness', + ['type' => 'unit'] + ], + ['text-decoration-line', + ['type' => 'text-decoration-line', 'multiple' => true] + ], + ['text-decoration-color', + ['type' => 'color'] + ], + ['text-decoration-style', + ['type' => 'text-decoration-style'] + ] +], null, false, + /** + *compute shorthand property + */ + ['compute' => true, 'optional-shorthand' => true])); $config['properties'] = array_merge($config['properties'], makePropertySet('margin', ['unit unit unit unit'], [ ['margin-top', 'unit'], @@ -267,13 +261,13 @@ unset($config['alias']); -$file = dirname(__DIR__) . '/src/TBela/CSS/config.json'; -file_put_contents($file, json_encode($config)); +$file = dirname(__DIR__) . '/src/config.json'; + -echo "the configuration has been stored in '$file' ...\n"; +echo file_put_contents($file, json_encode($config))? "the configuration has been stored in '$file' ...\n" : "failed to save the confg file in $file\n"; -function addAlias($property) +function addAlias(string $property): array { $result = []; $args = func_get_args(); @@ -303,15 +297,16 @@ function addAlias($property) * @param array $pattern * @param array $props * @param null|string $separator - * @param bool $map_properties + * @param bool $map_properties remove properties with identical values: margin: 2px 2px 2px => margin: 2px * @param array|null $settings - * @param string|null + * @param string|null $shorthandOverride * @return array */ -function makePropertySet(string $shorthand, array $pattern, array $props, ?string $separator = null, bool $map_properties = true, ?array $settings = null, $shorthandOverride = null): array +function makePropertySet(string $shorthand, array $pattern, array $props, ?string $separator = null, bool $map_properties = true, ?array $settings = null, string $shorthandOverride = null): array { $properties = []; + foreach ($props as $key => $prop) { // properties definition From 60ea6f7190782752b18ee646d06097fb666c1213 Mon Sep 17 00:00:00 2001 From: Shish Date: Fri, 18 Aug 2023 15:13:00 +0100 Subject: [PATCH 02/10] Remove an optimisation which breaks relative URLs This optimisation disables relative paths when the output path is longer than the input path - but the result of that is that the generated CSS ends up pointing to URLs that are relative to the current directory instead of being relative to the generated CSS file. input: test-in/style.css ``` .foo { background-image: url("./local.png"); } ``` output: test-out/style.css ``` .foo { background-image: url("../test-in/local.png"); } ``` output: test-out/nested/path/style.css ``` .foo { background-image: url("test-in/local.png"); } ``` --- src/Parser/Helper.php | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Parser/Helper.php b/src/Parser/Helper.php index cbf503b0..2cd71210 100755 --- a/src/Parser/Helper.php +++ b/src/Parser/Helper.php @@ -265,11 +265,6 @@ public static function relativePath(string $file, string $ref) } } - if (count($file) < count($ref)) { - - return static::toUrl($fileUrl); - } - while ($ref) { $r = $ref[0]; @@ -430,4 +425,4 @@ public static function fetchContent(string $url, array $options = [], array $cur ] ])); } -} \ No newline at end of file +} From 0baabc177c2a72fe851fe208910223b4704a04c3 Mon Sep 17 00:00:00 2001 From: Shish Date: Fri, 18 Aug 2023 16:24:37 +0100 Subject: [PATCH 03/10] use relative paths in sourcemap --- src/Renderer.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Renderer.php b/src/Renderer.php index 941a0092..3a3fd586 100755 --- a/src/Renderer.php +++ b/src/Renderer.php @@ -1105,7 +1105,7 @@ protected function addPosition(object $generated, object $ast): static 'column' => $generated->column, ], 'source' => [ - 'fileName' => $ast->src, + 'fileName' => Helper::relativePath($ast->src, $this->outFile === '' ? Helper::getCurrentDirectory() : dirname($this->outFile)), 'line' => $position->line - 1, 'column' => $position->column - 1, ], @@ -1337,4 +1337,4 @@ public function flatten(object $node): object return $node; } -} \ No newline at end of file +} From 1de04ece7173986c02ee3e630bfd3f21820d1585 Mon Sep 17 00:00:00 2001 From: Shish Date: Fri, 18 Aug 2023 17:32:25 +0100 Subject: [PATCH 04/10] Fix deprecation warnings I'm getting a ton of error messages in my logs like: ``` Deprecated: Return type of TBela\CSS\Element::offsetUnset($offset) should either be compatible with ArrayAccess::offsetUnset(mixed $offset): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice in [...]/src/ArrayTrait.php on line 72 ``` and ``` Deprecated: strtolower(): Passing null to parameter #1 ($string) of type string is deprecated in [...]/src/Value.php on line 590 ``` --- src/ArrayTrait.php | 10 +++++----- src/Element.php | 4 ++-- src/Element/AtRule.php | 4 ++-- src/Element/RuleList.php | 4 ++-- src/Parser/AccessTrait.php | 4 ++-- src/Property/PropertyList.php | 2 +- src/Value.php | 8 ++++---- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ArrayTrait.php b/src/ArrayTrait.php index d8768471..e778942b 100755 --- a/src/ArrayTrait.php +++ b/src/ArrayTrait.php @@ -44,7 +44,7 @@ public function __unset($name) { * @param string $value * @ignore */ - public function offsetSet($offset, $value) + public function offsetSet(mixed $offset, mixed $value): void { if (is_callable([$this, 'set' . $offset])) { @@ -58,7 +58,7 @@ public function offsetSet($offset, $value) * @return bool * @ignore */ - public function offsetExists($offset) + public function offsetExists(mixed $offset): bool { return is_callable([$this, 'get' . $offset]) || is_callable([$this, 'set' . $offset]) || @@ -69,7 +69,7 @@ public function offsetExists($offset) * @param string $offset * @ignore */ - public function offsetUnset($offset) + public function offsetUnset(mixed $offset): void { if (is_callable([$this, 'set' . $offset])) { @@ -83,7 +83,7 @@ public function offsetUnset($offset) * @return mixed|null * @ignore */ - public function offsetGet($offset) + public function offsetGet(mixed $offset): mixed { if (is_callable([$this, 'get' . $offset])) { @@ -116,4 +116,4 @@ public function offsetGet($offset) return null; } -} \ No newline at end of file +} diff --git a/src/Element.php b/src/Element.php index 4983effd..6cd043b9 100755 --- a/src/Element.php +++ b/src/Element.php @@ -613,7 +613,7 @@ public function getAst() * @return stdClass * @ignore */ - public function jsonSerialize () { + public function jsonSerialize (): mixed { return $this->getAst(); } @@ -652,4 +652,4 @@ public function toObject() { return $this->ast; } -} \ No newline at end of file +} diff --git a/src/Element/AtRule.php b/src/Element/AtRule.php index 36a7786a..3b6034ab 100755 --- a/src/Element/AtRule.php +++ b/src/Element/AtRule.php @@ -100,7 +100,7 @@ public function addDeclaration ($name, $value) { * @return \stdClass * @ignore */ - public function jsonSerialize () { + public function jsonSerialize (): mixed { $ast = parent::jsonSerialize(); @@ -116,4 +116,4 @@ public function jsonSerialize () { return $ast; } -} \ No newline at end of file +} diff --git a/src/Element/RuleList.php b/src/Element/RuleList.php index 540e5bd6..93fd6f03 100755 --- a/src/Element/RuleList.php +++ b/src/Element/RuleList.php @@ -281,9 +281,9 @@ public function remove(ElementInterface $element) * return an iterator of child nodes * @return ArrayIterator|Traversable */ - public function getIterator() + public function getIterator(): \Traversable { return new ArrayIterator($this->ast->children ?? []); } -} \ No newline at end of file +} diff --git a/src/Parser/AccessTrait.php b/src/Parser/AccessTrait.php index b7b3c8b2..190a54fd 100755 --- a/src/Parser/AccessTrait.php +++ b/src/Parser/AccessTrait.php @@ -52,8 +52,8 @@ public function __clone() { /** * @return array */ - public function jsonSerialize() + public function jsonSerialize(): mixed { return get_object_vars($this); } -} \ No newline at end of file +} diff --git a/src/Property/PropertyList.php b/src/Property/PropertyList.php index d9fde4bf..041fdd2e 100755 --- a/src/Property/PropertyList.php +++ b/src/Property/PropertyList.php @@ -360,7 +360,7 @@ public function isEmpty() { /** * @inheritDoc */ - public function getIterator() + public function getIterator(): \Traversable { return $this->getProperties(); } diff --git a/src/Value.php b/src/Value.php index c5050752..fad6084d 100755 --- a/src/Value.php +++ b/src/Value.php @@ -581,13 +581,13 @@ public static function parse($string, $property = null, bool $capture_whitespace return $string; } - if (trim($property) === '') { + if (trim((string)$property) === '') { $property = null; } $string = trim($string); - $property = strtolower($property); + $property = strtolower((string)$property); if ($property !== '') { @@ -1466,8 +1466,8 @@ public function __toString() return $this->render(); } - public function jsonSerialize() + public function jsonSerialize(): mixed { return $this->render(); } -} \ No newline at end of file +} From 48edbbf0371d3e10f1076775cc65f6788b3b18b4 Mon Sep 17 00:00:00 2001 From: Shish Date: Fri, 18 Aug 2023 19:26:28 +0100 Subject: [PATCH 05/10] fix another incompatible type hint --- src/Element/NestingRule.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Element/NestingRule.php b/src/Element/NestingRule.php index c9995c77..18c95d7c 100755 --- a/src/Element/NestingRule.php +++ b/src/Element/NestingRule.php @@ -10,9 +10,9 @@ class NestingRule extends Rule /** * @inheritDoc */ - public function support(ElementInterface $child) + public function support(ElementInterface $child): bool { return true; } -} \ No newline at end of file +} From 64c2d29e17b3dc0e0f2de84303ef6dd0fdc6478c Mon Sep 17 00:00:00 2001 From: 8ctopus Date: Tue, 25 Nov 2025 17:58:52 +0400 Subject: [PATCH 06/10] Fix implicitly marking parameter as nullable is deprecated, the explicit nullable type must be used instead --- src/Event/EventTrait.php | 2 +- src/Parser/Lexer.php | 2 +- src/Process/MultiProcessing/Process.php | 2 +- src/Process/ProcessInterface.php | 2 +- src/Process/Thread/PCNTL/Thread.php | 2 +- src/Property/PropertyList.php | 2 +- src/Renderer.php | 2 +- src/Value.php | 4 ++-- src/Value/BackgroundColor.php | 2 +- src/Value/BackgroundImage.php | 2 +- src/Value/BackgroundPosition.php | 2 +- src/Value/BackgroundRepeat.php | 2 +- src/Value/BackgroundSize.php | 4 ++-- src/Value/FontFamily.php | 2 +- src/Value/FontStyle.php | 2 +- src/Value/FontVariant.php | 2 +- src/Value/FontWeight.php | 2 +- src/Value/LineHeight.php | 2 +- src/Value/OutlineColor.php | 2 +- src/Value/OutlineWidth.php | 2 +- 20 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Event/EventTrait.php b/src/Event/EventTrait.php index 89eca92d..d8df1332 100755 --- a/src/Event/EventTrait.php +++ b/src/Event/EventTrait.php @@ -31,7 +31,7 @@ public function on(string $event, callable $callable): static { * @param callable|null $callable * @return $this */ - public function off(string $event = null, callable $callable = null): static { + public function off(?string $event = null, ?callable $callable = null): static { if (is_null($event)) { diff --git a/src/Parser/Lexer.php b/src/Parser/Lexer.php index aabfdd64..0ca5668f 100755 --- a/src/Parser/Lexer.php +++ b/src/Parser/Lexer.php @@ -36,7 +36,7 @@ class Lexer * @param string $css * @param object|null $context */ - public function __construct(string $css = '', object $context = null) + public function __construct(string $css = '', ?object $context = null) { $this->css = rtrim($css); diff --git a/src/Process/MultiProcessing/Process.php b/src/Process/MultiProcessing/Process.php index 5e1e276e..539baa4b 100644 --- a/src/Process/MultiProcessing/Process.php +++ b/src/Process/MultiProcessing/Process.php @@ -125,7 +125,7 @@ public function start(): void /** * @throws IllegalStateException */ - public function stop(float $timeout = 10, int $signal = null): void + public function stop(float $timeout = 10, ?int $signal = null): void { if (!$this->started) { diff --git a/src/Process/ProcessInterface.php b/src/Process/ProcessInterface.php index 0ce369c6..0eba9279 100644 --- a/src/Process/ProcessInterface.php +++ b/src/Process/ProcessInterface.php @@ -12,7 +12,7 @@ interface ProcessInterface extends EventInterface public function start(): void; - public function stop(float $timeout = 10, int $signal = null): void; + public function stop(float $timeout = 10, ?int $signal = null): void; public static function isSupported(): bool; diff --git a/src/Process/Thread/PCNTL/Thread.php b/src/Process/Thread/PCNTL/Thread.php index 9aaa3cfb..8c3cb0d0 100644 --- a/src/Process/Thread/PCNTL/Thread.php +++ b/src/Process/Thread/PCNTL/Thread.php @@ -79,7 +79,7 @@ public function start(): void } } - public function stop(float $timeout = 10, int $signal = null): void + public function stop(float $timeout = 10, ?int $signal = null): void { if ($this->stopped || $this->terminated) { diff --git a/src/Property/PropertyList.php b/src/Property/PropertyList.php index d9fde4bf..a1848436 100755 --- a/src/Property/PropertyList.php +++ b/src/Property/PropertyList.php @@ -36,7 +36,7 @@ class PropertyList implements IteratorAggregate * @param RuleList|null $list * @param array $options */ - public function __construct(RuleList $list = null, array $options = []) + public function __construct(?RuleList $list = null, array $options = []) { $this->options = array_merge($this->options, $options); diff --git a/src/Renderer.php b/src/Renderer.php index 941a0092..eca46a69 100755 --- a/src/Renderer.php +++ b/src/Renderer.php @@ -1066,7 +1066,7 @@ public function setOptions(array $options): static * @param mixed|null $default return value * @return array|string|bool */ - public function getOptions(string $name = null, mixed $default = null): array|string|bool + public function getOptions(?string $name = null, mixed $default = null): array|string|bool { if (is_null($name)) { diff --git a/src/Value.php b/src/Value.php index c5050752..e58eb8aa 100755 --- a/src/Value.php +++ b/src/Value.php @@ -285,7 +285,7 @@ protected static function matchDefaults($token): bool * @param array $tokens * @return bool */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == static::type() || isset($token->value) && static::matchKeyword($token->value); @@ -1380,7 +1380,7 @@ public static function keywords(): array * @return string|null * @ignore */ - public static function matchKeyword(string $string, array $keywords = null): ?string + public static function matchKeyword(string $string, ?array $keywords = null): ?string { if (is_null($keywords)) { diff --git a/src/Value/BackgroundColor.php b/src/Value/BackgroundColor.php index a15b67b9..bb9f800e 100755 --- a/src/Value/BackgroundColor.php +++ b/src/Value/BackgroundColor.php @@ -31,7 +31,7 @@ public static function doParse(string $string, bool $capture_whitespace = true, return static::reduce($tokens); } - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == 'color'; } diff --git a/src/Value/BackgroundImage.php b/src/Value/BackgroundImage.php index 7b59bf11..a0ea7689 100755 --- a/src/Value/BackgroundImage.php +++ b/src/Value/BackgroundImage.php @@ -37,7 +37,7 @@ public static function doRender(object $data, array $options = []) return $data->value ?? parent::doRender($data, $options); } - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == static::type() || (isset($token->name) && diff --git a/src/Value/BackgroundPosition.php b/src/Value/BackgroundPosition.php index 38befb39..31f3a6e3 100755 --- a/src/Value/BackgroundPosition.php +++ b/src/Value/BackgroundPosition.php @@ -71,7 +71,7 @@ protected function __construct($data) * @inheritDoc */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { $test = false; diff --git a/src/Value/BackgroundRepeat.php b/src/Value/BackgroundRepeat.php index b8148d37..5c8a186b 100755 --- a/src/Value/BackgroundRepeat.php +++ b/src/Value/BackgroundRepeat.php @@ -51,7 +51,7 @@ class BackgroundRepeat extends Value */ protected static array $defaults = ['repeat']; - public static function matchKeyword(string $string, array $keywords = null): ?string + public static function matchKeyword(string $string, ?array $keywords = null): ?string { $key = preg_replace('~(\s+)~', ' ', trim($string, ";\n\t\r ")); diff --git a/src/Value/BackgroundSize.php b/src/Value/BackgroundSize.php index c284ebf6..d3972218 100755 --- a/src/Value/BackgroundSize.php +++ b/src/Value/BackgroundSize.php @@ -34,7 +34,7 @@ class BackgroundSize extends Value ] ]; - public static function matchKeyword(string $string, array $keywords = null): ?string + public static function matchKeyword(string $string, ?array $keywords = null): ?string { $string = trim($string, ";\n\t\r "); $string = preg_replace('#\s+#', ' ', $string); @@ -47,7 +47,7 @@ public static function matchKeyword(string $string, array $keywords = null): ?st return parent::matchKeyword($string, $keywords); } - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == 'unit' || ($token->type == 'css-string' && in_array($token->value, static::$keywords)); diff --git a/src/Value/FontFamily.php b/src/Value/FontFamily.php index e3df16d8..6dd192ea 100755 --- a/src/Value/FontFamily.php +++ b/src/Value/FontFamily.php @@ -11,7 +11,7 @@ class FontFamily extends ShortHand /** * @inheritDoc */ - public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool { + public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == 'css-string' || $token->type == static::type(); } diff --git a/src/Value/FontStyle.php b/src/Value/FontStyle.php index 87067e5e..4ad2d6dc 100755 --- a/src/Value/FontStyle.php +++ b/src/Value/FontStyle.php @@ -34,7 +34,7 @@ public static function match(object $data, $type): bool /** * @inheritDoc */ - public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool { + public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { if ($token->type == 'css-string' && in_array(strtolower($token->value), static::$keywords)) { diff --git a/src/Value/FontVariant.php b/src/Value/FontVariant.php index 177bfc93..4500e2cc 100755 --- a/src/Value/FontVariant.php +++ b/src/Value/FontVariant.php @@ -29,7 +29,7 @@ class FontVariant extends Value /** * @inheritDoc */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { if ($token->type == 'css-string' && in_array(strtolower($token->value), static::$keywords)) { diff --git a/src/Value/FontWeight.php b/src/Value/FontWeight.php index 89d3c584..2493ef4e 100755 --- a/src/Value/FontWeight.php +++ b/src/Value/FontWeight.php @@ -81,7 +81,7 @@ public static function match(object $data, $type): bool /** * @inheritDoc */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { if ($token->type == 'number' && $token->value > 0 && $token->value <= 1000) { diff --git a/src/Value/LineHeight.php b/src/Value/LineHeight.php index f0d94cb9..ac40da0f 100755 --- a/src/Value/LineHeight.php +++ b/src/Value/LineHeight.php @@ -23,7 +23,7 @@ class LineHeight extends Value * @inheritDoc * @throws Exception */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { if (!is_null($previousToken) && $previousToken->type != 'separator' && (!isset($previousToken->value) || $previousToken->value != '/')) { diff --git a/src/Value/OutlineColor.php b/src/Value/OutlineColor.php index dda5b0e7..ebcdd4c0 100755 --- a/src/Value/OutlineColor.php +++ b/src/Value/OutlineColor.php @@ -13,7 +13,7 @@ class OutlineColor extends Color /** * @inheritDoc */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == 'color'; } diff --git a/src/Value/OutlineWidth.php b/src/Value/OutlineWidth.php index bffca121..10f995a7 100755 --- a/src/Value/OutlineWidth.php +++ b/src/Value/OutlineWidth.php @@ -19,7 +19,7 @@ class OutlineWidth extends Unit /** * @inheritDoc */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == 'unit' || ($token->type == 'number' && $token->value == 0); From 3b92a3e51114588695b9aa59598ffd5c07e7fccb Mon Sep 17 00:00:00 2001 From: 8ctopus Date: Tue, 25 Nov 2025 19:02:07 +0400 Subject: [PATCH 07/10] Fix case statements followed by a semicolon (;) are deprecated, use a colon (:) instead --- src/Color.php | 8 ++++---- src/Value/BackgroundPosition.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Color.php b/src/Color.php index 8e8d5fd0..42abbb83 100755 --- a/src/Color.php +++ b/src/Color.php @@ -342,19 +342,19 @@ public static function hex2rgba_values($hex) switch (strlen($hex)) { - case 4; + case 4: return [hexdec($hex[1] . $hex[1]), hexdec($hex[2] . $hex[2]), hexdec($hex[3] . $hex[3])]; - case 5; + case 5: return [hexdec($hex[1] . $hex[1]), hexdec($hex[2] . $hex[2]), hexdec($hex[3] . $hex[3]), ValueNumber::compress(round(hexdec($hex[4] . $hex[4]) / 255, 2))]; - case 7; + case 7: return [hexdec($hex[1] . $hex[2]), hexdec($hex[3] . $hex[4]), hexdec($hex[5] . $hex[6])]; - case 9; + case 9: return [hexdec($hex[1] . $hex[2]), hexdec($hex[3] . $hex[4]), hexdec($hex[5] . $hex[6]), ValueNumber::compress(round(hexdec($hex[7] . $hex[8]) / 255, 2))]; } diff --git a/src/Value/BackgroundPosition.php b/src/Value/BackgroundPosition.php index 38befb39..0701ef68 100755 --- a/src/Value/BackgroundPosition.php +++ b/src/Value/BackgroundPosition.php @@ -117,7 +117,7 @@ public static function matchToken($token, $previousToken = null, $previousValue switch (count($values)) { // two values - case 1; + case 1: // must not be the same coordinates if (in_array($values[0]->value, static::$x)) { From 7e4480e8c8098c49c41d4c93cf7a6efd8e11635b Mon Sep 17 00:00:00 2001 From: 8ctopus Date: Tue, 25 Nov 2025 19:09:05 +0400 Subject: [PATCH 08/10] Fix return type of TBela\CSS\Property\Property::offsetSet(, ) should either be compatible with ArrayAccess::offsetSet(mixed , mixed ): void, or the #[\ReturnTypeWillChange] attribute should be used to temporarily suppress the notice --- src/ArrayTrait.php | 4 ++++ src/Element.php | 1 + src/Element/RuleList.php | 1 + src/Property/PropertyList.php | 1 + src/Value.php | 1 + 5 files changed, 8 insertions(+) diff --git a/src/ArrayTrait.php b/src/ArrayTrait.php index d8768471..87f25f40 100755 --- a/src/ArrayTrait.php +++ b/src/ArrayTrait.php @@ -44,6 +44,7 @@ public function __unset($name) { * @param string $value * @ignore */ + #[\ReturnTypeWillChange] public function offsetSet($offset, $value) { @@ -58,6 +59,7 @@ public function offsetSet($offset, $value) * @return bool * @ignore */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { return is_callable([$this, 'get' . $offset]) || @@ -69,6 +71,7 @@ public function offsetExists($offset) * @param string $offset * @ignore */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { @@ -83,6 +86,7 @@ public function offsetUnset($offset) * @return mixed|null * @ignore */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { diff --git a/src/Element.php b/src/Element.php index 4983effd..8ac13e20 100755 --- a/src/Element.php +++ b/src/Element.php @@ -613,6 +613,7 @@ public function getAst() * @return stdClass * @ignore */ + #[\ReturnTypeWillChange] public function jsonSerialize () { return $this->getAst(); diff --git a/src/Element/RuleList.php b/src/Element/RuleList.php index 540e5bd6..08b35db6 100755 --- a/src/Element/RuleList.php +++ b/src/Element/RuleList.php @@ -281,6 +281,7 @@ public function remove(ElementInterface $element) * return an iterator of child nodes * @return ArrayIterator|Traversable */ + #[\ReturnTypeWillChange] public function getIterator() { diff --git a/src/Property/PropertyList.php b/src/Property/PropertyList.php index d9fde4bf..f2be2f1b 100755 --- a/src/Property/PropertyList.php +++ b/src/Property/PropertyList.php @@ -360,6 +360,7 @@ public function isEmpty() { /** * @inheritDoc */ + #[\ReturnTypeWillChange] public function getIterator() { return $this->getProperties(); diff --git a/src/Value.php b/src/Value.php index c5050752..385ac0d4 100755 --- a/src/Value.php +++ b/src/Value.php @@ -1466,6 +1466,7 @@ public function __toString() return $this->render(); } + #[\ReturnTypeWillChange] public function jsonSerialize() { return $this->render(); From fe83395bd56a2b3b8658752278246584d3b4d963 Mon Sep 17 00:00:00 2001 From: Thierry Bela Date: Tue, 25 Nov 2025 17:37:15 -0500 Subject: [PATCH 09/10] update ci scripts --- .github/workflows/php.yml | 11 +++++------ .github/workflows/php8.1.yml | 9 ++++----- .github/workflows/php8.2.yml | 9 ++++----- .github/workflows/{php5.6.yml => php8.3.yml} | 11 +++++------ .github/workflows/{php7.4.yml => php8.4.yml} | 11 +++++------ 5 files changed, 23 insertions(+), 28 deletions(-) rename .github/workflows/{php5.6.yml => php8.3.yml} (82%) rename .github/workflows/{php7.4.yml => php8.4.yml} (82%) diff --git a/.github/workflows/php.yml b/.github/workflows/php.yml index a548fd86..043b1cd7 100644 --- a/.github/workflows/php.yml +++ b/.github/workflows/php.yml @@ -1,15 +1,14 @@ -name: PHP8.0-CI +name: PHP8.5-CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: - - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -17,7 +16,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.0' + php-version: "8.5" extensions: mbstring, xml, curl tools: phpunit, composer diff --git a/.github/workflows/php8.1.yml b/.github/workflows/php8.1.yml index 9347e48b..e96f3580 100644 --- a/.github/workflows/php8.1.yml +++ b/.github/workflows/php8.1.yml @@ -2,14 +2,13 @@ name: PHP8.1-CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: - - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -17,7 +16,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.1' + php-version: "8.1" extensions: mbstring, xml, curl tools: phpunit, composer diff --git a/.github/workflows/php8.2.yml b/.github/workflows/php8.2.yml index 2f7c0c5e..638fc312 100644 --- a/.github/workflows/php8.2.yml +++ b/.github/workflows/php8.2.yml @@ -2,14 +2,13 @@ name: PHP8.2-CI on: push: - branches: [ master ] + branches: [master] pull_request: - branches: [ master ] + branches: [master] jobs: build: - - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -17,7 +16,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '8.2' + php-version: "8.2" extensions: mbstring, xml, curl tools: phpunit, composer diff --git a/.github/workflows/php5.6.yml b/.github/workflows/php8.3.yml similarity index 82% rename from .github/workflows/php5.6.yml rename to .github/workflows/php8.3.yml index 8a81edff..3d4864ab 100644 --- a/.github/workflows/php5.6.yml +++ b/.github/workflows/php8.3.yml @@ -1,15 +1,14 @@ -name: PHP5.6-CI +name: PHP8.3-CI on: push: - branches: [ php56-backport ] + branches: [master] pull_request: - branches: [ php56-backport ] + branches: [master] jobs: build: - - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -17,7 +16,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '5.6' + php-version: "8.3" extensions: mbstring, xml, curl tools: phpunit, composer diff --git a/.github/workflows/php7.4.yml b/.github/workflows/php8.4.yml similarity index 82% rename from .github/workflows/php7.4.yml rename to .github/workflows/php8.4.yml index b15192e9..7557ab80 100644 --- a/.github/workflows/php7.4.yml +++ b/.github/workflows/php8.4.yml @@ -1,15 +1,14 @@ -name: PHP7.4-CI +name: PHP8.4-CI on: push: - branches: [ php56-backport ] + branches: [master] pull_request: - branches: [ php56-backport ] + branches: [master] jobs: build: - - runs-on: ubuntu-20.04 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v2 @@ -17,7 +16,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.4' + php-version: "8.4" extensions: mbstring, xml, curl tools: phpunit, composer From bdfbd9af2caae79a6a7e0f8dba2a114db27aed60 Mon Sep 17 00:00:00 2001 From: 8ctopus Date: Wed, 26 Nov 2025 15:27:17 +0400 Subject: [PATCH 10/10] Fix deprecations on v.next branch Fix FontFamily unclosed method --- src/ArrayTrait.php | 3 +++ src/Element/Declaration/Config.php | 4 ++-- src/Value/FontFamily.php | 2 ++ src/Value/ParsableTrait.php | 2 +- src/Value/Unit.php | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/ArrayTrait.php b/src/ArrayTrait.php index cbc11a98..b9c76120 100755 --- a/src/ArrayTrait.php +++ b/src/ArrayTrait.php @@ -59,6 +59,7 @@ public function offsetSet(mixed $offset, mixed $value): void * @return bool * @ignore */ + #[\ReturnTypeWillChange] public function offsetExists($offset) { return is_callable([$this, 'get' . $offset]) || @@ -70,6 +71,7 @@ public function offsetExists($offset) * @param string $offset * @ignore */ + #[\ReturnTypeWillChange] public function offsetUnset($offset) { @@ -84,6 +86,7 @@ public function offsetUnset($offset) * @return mixed|null * @ignore */ + #[\ReturnTypeWillChange] public function offsetGet($offset) { diff --git a/src/Element/Declaration/Config.php b/src/Element/Declaration/Config.php index 079fe7ca..428cd772 100755 --- a/src/Element/Declaration/Config.php +++ b/src/Element/Declaration/Config.php @@ -109,7 +109,7 @@ public static function getPath(string $path, mixed $default = null): mixed * @param mixed|null $default * @return array|mixed|null */ - public static function getProperty (string $name = null, mixed $default = null): mixed + public static function getProperty (?string $name = null, mixed $default = null): mixed { if (is_null($name)) { @@ -140,7 +140,7 @@ public static function getProperty (string $name = null, mixed $default = null): * @return array * @ignore */ - public static function addSet ($shorthand, $pattern, array $properties, string $separator = null, string $shorthandOverride = null): array + public static function addSet ($shorthand, $pattern, array $properties, ?string $separator = null, ?string $shorthandOverride = null): array { $config = []; diff --git a/src/Value/FontFamily.php b/src/Value/FontFamily.php index 26e416dd..986fc5f0 100755 --- a/src/Value/FontFamily.php +++ b/src/Value/FontFamily.php @@ -12,6 +12,8 @@ class FontFamily extends ShortHand * @inheritDoc */ public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { + return false; + } protected static string $propertyType = 'css-string'; } diff --git a/src/Value/ParsableTrait.php b/src/Value/ParsableTrait.php index a2cc0c73..f587b9bd 100644 --- a/src/Value/ParsableTrait.php +++ b/src/Value/ParsableTrait.php @@ -8,7 +8,7 @@ trait ParsableTrait /** * @inheritDoc */ - public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool { + public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == static::$propertyType || (isset($token->value) && in_array($token->value, static::$keywords)) || $token->type == static::type(); } diff --git a/src/Value/Unit.php b/src/Value/Unit.php index 2d62303d..e32877da 100755 --- a/src/Value/Unit.php +++ b/src/Value/Unit.php @@ -29,7 +29,7 @@ public static function match (object $data, $type): bool { /** * @inheritDoc */ - public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, int $index = null, array $tokens = []): bool + public static function matchToken($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { return $token->type == 'unit' || in_array($token->value, static::$keywords) || $token->type == static::type();