From a5b158c0f5565712c2f788eab63944dd18547eb2 Mon Sep 17 00:00:00 2001 From: Thierry Bela Date: Fri, 11 Nov 2022 22:32:22 -0500 Subject: [PATCH] #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