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); $unlayered = $this->getUnlayered($styles); return implode(chr(10), [ $atLayerOrder, $atLayerBase, $atLayerTheme, $atLayerUtilities, $atLayerComponents, $atProperty, $atLayerProperties, $unlayered, ]); } protected function getLayerOrder(string $styles): string { preg_match_all('/(?@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('/(?--[^;]+;)/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[^{]+\{[^}]+})/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('/(?--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}"; } protected function getUnlayered(string $styles): string { $unlayered = preg_replace('/(?@layer[^;{]+;)/i', '', $styles, -1); $unlayered = preg_replace('/@layer[^{;]+\{.+?(?=\n})\n}/s', '', $unlayered, -1); return preg_replace('/(?@property[^{]+\{[^}]+})/i', '', $unlayered, -1); } }