ew_base/Classes/Services/Tailwindcss4Merger.php
2025-04-26 20:03:17 +02:00

148 lines
5.1 KiB
PHP

<?php
declare(strict_types=1);
/*
* This file is developed by evoWeb.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*/
namespace Evoweb\EwBase\Services;
class Tailwindcss4Merger
{
public function cssUnique(string $styles): string
{
$atLayerOrder = $this->getLayerOrder($styles);
$atLayerBase = $this->getLayerBase($styles);
$atLayerTheme = $this->getLayerTheme($styles);
$atLayerUtilities = $this->getLayerUtilities($styles);
$atLayerComponents = $this->getLayerComponents($styles);
$atProperty = $this->getProperties($styles);
$atLayerProperties = $this->getLayerProperties($styles);
return implode(chr(10), [
$atLayerOrder,
$atLayerBase,
$atLayerTheme,
$atLayerUtilities,
$atLayerComponents,
$atProperty,
$atLayerProperties,
]);
}
protected function getLayerOrder(string $styles): string
{
preg_match_all('/(?<layer>@layer[^;{]+;)/i', $styles, $matches);
return implode(chr(10), array_unique($matches['layer'] ?? []));
}
protected function getLayerBase(string $styles): string
{
$matches = $this->getLayerByName($styles, 'base');
$base = [];
foreach ($matches as $match) {
$match = $this->unwrapLayer($match, 'base');
$match = preg_replace('/}\n *\./', "}\n||.", $match);
$match = preg_replace('/}\n\W*@/', "}\n||@", $match);
$parts = explode('||', $match);
$base = array_merge($base, $parts);
}
return $this->wrapLayer('base', array_unique($base));
}
protected function getLayerTheme(string $styles): string
{
$matches = $this->getLayerByName($styles, 'theme');
$themes = [];
foreach ($matches as $match) {
preg_match_all('/(?<theme>--[^;]+;)/i', $match, $subMatches);
$themes = array_merge($themes, $subMatches['theme'] ?? []);
}
return '@layer theme {
:root, :host {'
. chr(10)
. implode(chr(10), array_unique($themes))
. chr(10)
. ' }
}';
}
protected function getLayerUtilities(string $styles): string
{
$matches = $this->getLayerByName($styles, 'utilities');
$utilities = [];
foreach ($matches as $match) {
$match = $this->unwrapLayer($match, 'utilities');
$match = preg_replace('/}\n *\./', "}\n||.", $match);
$parts = explode('||', $match);
$utilities = array_merge($utilities, $parts);
}
return $this->wrapLayer('utilities', array_unique($utilities));
}
protected function getLayerComponents(string $styles): string
{
$matches = $this->getLayerByName($styles, 'components');
$components = [];
foreach ($matches as $match) {
$match = $this->unwrapLayer($match, 'components');
$match = preg_replace('/}\n *\./', "}\n||.", $match);
$parts = explode('||', $match);
$components = array_merge($components, $parts);
}
return $this->wrapLayer('components', array_unique($components));
}
protected function getLayerByName(string $styles, string $name): array
{
preg_match_all('/@layer[^{;]+\{.+?(?=\n})\n}/s', $styles, $matches);
$layer = [];
foreach ($matches['0'] as $match) {
if (str_starts_with($match, '@layer ' . $name) !== false) {
$layer[] = $match;
}
}
return $layer;
}
protected function getProperties(string $styles): string
{
preg_match_all('/(?<property>@property[^{]+\{[^}]+})/i', $styles, $matches);
return implode(chr(10), array_unique($matches['property'] ?? []));
}
protected function getLayerProperties(string $styles): string
{
$matches = $this->getLayerByName($styles, 'properties');
$properties = [
' @supports ((-webkit-hyphens: none) and (not (margin-trim: inline))) or ((-moz-orient: inline) and (not (color:rgb(from red r g b)))) {
*, ::before, ::after, ::backdrop {'
];
foreach ($matches as $match) {
preg_match_all('/(?<properties>--tw[^ ]+: [^;]+;)/i', $match, $subMatches);
$properties = array_merge($properties, $subMatches['properties']);
}
$properties = array_unique($properties);
$properties[] = ' }
}';
return $this->wrapLayer('properties', $properties);
}
protected function unwrapLayer(string $styles, string $name): string
{
return trim(str_replace('@layer ' . $name . ' {', '', substr($styles, 0, -1)));
}
protected function wrapLayer(string $name, array $styles): string
{
return '@layer ' . $name . " {\n" . implode("\n", $styles) . "\n}";
}
}