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 diff --git a/src/ArrayTrait.php b/src/ArrayTrait.php index d8768471..b9c76120 100755 --- a/src/ArrayTrait.php +++ b/src/ArrayTrait.php @@ -44,7 +44,8 @@ public function __unset($name) { * @param string $value * @ignore */ - public function offsetSet($offset, $value) + #[\ReturnTypeWillChange] + public function offsetSet(mixed $offset, mixed $value): void { if (is_callable([$this, 'set' . $offset])) { @@ -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) { @@ -116,4 +120,4 @@ public function offsetGet($offset) return null; } -} \ No newline at end of file +} 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/Element.php b/src/Element.php index 4983effd..a4e31647 100755 --- a/src/Element.php +++ b/src/Element.php @@ -613,7 +613,8 @@ public function getAst() * @return stdClass * @ignore */ - public function jsonSerialize () { + #[\ReturnTypeWillChange] + public function jsonSerialize (): mixed { return $this->getAst(); } @@ -652,4 +653,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/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 @@ options = array_merge($this->options, $options); @@ -360,7 +359,8 @@ public function isEmpty() { /** * @inheritDoc */ - public function getIterator() + #[\ReturnTypeWillChange] + public function getIterator(): \Traversable { return $this->getProperties(); } diff --git a/src/Element/Declaration/PropertyMap.php b/src/Element/Declaration/PropertyMap.php new file mode 100755 index 00000000..6501d6a3 --- /dev/null +++ b/src/Element/Declaration/PropertyMap.php @@ -0,0 +1,473 @@ +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 @@ ast->children ?? []); } -} \ No newline at end of file +} 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.php b/src/Parser.php index e6c155ec..cf155dab 100755 --- a/src/Parser.php +++ b/src/Parser.php @@ -197,6 +197,9 @@ public function parallelize(string $content, object $root, string $file): void then(function (array $result, int $index) use (&$data) { $data[$index] = $result; + })->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/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/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 +} 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/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/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/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/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/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..e0d733af 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; /** @@ -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)) { @@ -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 +} diff --git a/src/Value.php b/src/Value.php index c5050752..140563c1 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); @@ -285,7 +290,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); @@ -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; @@ -581,13 +586,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 !== '') { @@ -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'; @@ -1380,7 +1385,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)) { @@ -1466,8 +1471,9 @@ public function __toString() return $this->render(); } - public function jsonSerialize() + #[\ReturnTypeWillChange] + public function jsonSerialize(): mixed { return $this->render(); } -} \ No newline at end of file +} 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..d6e432a5 100755 --- a/src/Value/BackgroundImage.php +++ b/src/Value/BackgroundImage.php @@ -27,17 +27,12 @@ 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); } - 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..4141c0c4 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; @@ -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)) { @@ -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..848535c4 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; /** @@ -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/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..986fc5f0 100755 --- a/src/Value/FontFamily.php +++ b/src/Value/FontFamily.php @@ -11,34 +11,9 @@ 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 $token->type == 'css-string' || $token->type == static::type(); + public static function matchToken ($token, $previousToken = null, $previousValue = null, $nextToken = null, $nextValue = null, ?int $index = null, array $tokens = []): bool { + return false; } - /** - * @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/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..92784bc2 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 = []) { @@ -81,7 +72,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/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..931eb417 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 != '/')) { @@ -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/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); diff --git a/src/Value/ParsableTrait.php b/src/Value/ParsableTrait.php new file mode 100644 index 00000000..f587b9bd --- /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