countdown-8.x-1.8/src/Utility/CdnUrlBuilder.php
src/Utility/CdnUrlBuilder.php
<?php
declare(strict_types=1);
namespace Drupal\countdown\Utility;
/**
* Builds CDN URLs for countdown libraries.
*
* This utility centralizes CDN URL construction logic previously scattered
* across plugins and the library manager.
*/
class CdnUrlBuilder {
/**
* CDN URL templates by provider.
*
* @var array
*/
protected const CDN_TEMPLATES = [
'jsdelivr' => [
'npm' => '//cdn.jsdelivr.net/npm/@package@version/dist/@file',
'github' => '//cdn.jsdelivr.net/gh/@owner/@repo@tag/@file',
],
'unpkg' => [
'npm' => '//unpkg.com/@package@version/dist/@file',
],
'cdnjs' => [
'library' => '//cdnjs.cloudflare.com/ajax/libs/@library/@version/@file',
],
];
/**
* Builds a CDN URL for a library asset.
*
* @param string $provider
* The CDN provider (jsdelivr, unpkg, cdnjs).
* @param string $package
* The package identifier (npm package or library name).
* @param string $version
* The version string.
* @param string $file
* The file path within the package.
* @param bool $minified
* Whether to use minified version.
*
* @return string
* The complete CDN URL.
*/
public function buildUrl(string $provider, string $package, string $version, string $file, bool $minified = TRUE): string {
// Apply minification to file name if needed.
if ($minified && !str_contains($file, '.min.')) {
$file = $this->minifyFileName($file);
}
// Handle special cases for each provider.
switch ($provider) {
case 'jsdelivr':
return $this->buildJsdelivrUrl($package, $version, $file);
case 'unpkg':
return $this->buildUnpkgUrl($package, $version, $file);
case 'cdnjs':
return $this->buildCdnjsUrl($package, $version, $file);
default:
// For custom or unknown providers, return as-is.
return "//{$provider}/{$package}@{$version}/{$file}";
}
}
/**
* Builds a jsDelivr URL.
*
* @param string $package
* The npm package name.
* @param string $version
* The version string.
* @param string $file
* The file path.
*
* @return string
* The jsDelivr URL.
*/
protected function buildJsdelivrUrl(string $package, string $version, string $file): string {
// Clean version (remove 'v' prefix if present).
$version = ltrim($version, 'v');
// Handle scoped packages.
if (str_starts_with($package, '@')) {
return "//cdn.jsdelivr.net/npm/{$package}@{$version}/{$file}";
}
return "//cdn.jsdelivr.net/npm/{$package}@{$version}/{$file}";
}
/**
* Builds an unpkg URL.
*
* @param string $package
* The npm package name.
* @param string $version
* The version string.
* @param string $file
* The file path.
*
* @return string
* The unpkg URL.
*/
protected function buildUnpkgUrl(string $package, string $version, string $file): string {
// Clean version.
$version = ltrim($version, 'v');
return "//unpkg.com/{$package}@{$version}/{$file}";
}
/**
* Builds a cdnjs URL.
*
* @param string $library
* The library name (without scope).
* @param string $version
* The version string.
* @param string $file
* The file path.
*
* @return string
* The cdnjs URL.
*/
protected function buildCdnjsUrl(string $library, string $version, string $file): string {
// Remove scope from package name if present.
if (str_contains($library, '/')) {
$parts = explode('/', $library);
$library = end($parts);
}
// Clean version.
$version = ltrim($version, 'v');
return "//cdnjs.cloudflare.com/ajax/libs/{$library}/{$version}/{$file}";
}
/**
* Converts a file name to its minified version.
*
* @param string $file
* The original file name.
*
* @return string
* The minified file name.
*/
protected function minifyFileName(string $file): string {
// Handle .js files.
if (str_ends_with($file, '.js')) {
return substr($file, 0, -3) . '.min.js';
}
// Handle .css files.
if (str_ends_with($file, '.css')) {
return substr($file, 0, -4) . '.min.css';
}
// Return as-is for other file types.
return $file;
}
/**
* Extracts CDN parameters from a URL template.
*
* @param string $url
* The CDN URL to parse.
*
* @return array|null
* Array with 'provider', 'package', 'version', 'file' keys, or NULL.
*/
public function parseUrl(string $url): ?array {
// Pattern for jsdelivr.
if (preg_match('#//cdn\.jsdelivr\.net/npm/([^@]+)@([^/]+)/(.+)#', $url, $matches)) {
return [
'provider' => 'jsdelivr',
'package' => $matches[1],
'version' => $matches[2],
'file' => $matches[3],
];
}
// Pattern for unpkg.
if (preg_match('#//unpkg\.com/([^@]+)@([^/]+)/(.+)#', $url, $matches)) {
return [
'provider' => 'unpkg',
'package' => $matches[1],
'version' => $matches[2],
'file' => $matches[3],
];
}
// Pattern for cdnjs.
if (preg_match('#//cdnjs\.cloudflare\.com/ajax/libs/([^/]+)/([^/]+)/(.+)#', $url, $matches)) {
return [
'provider' => 'cdnjs',
'package' => $matches[1],
'version' => $matches[2],
'file' => $matches[3],
];
}
return NULL;
}
}
