From 79fa8fda0034314570ae37a330843e5d23ae1c99 Mon Sep 17 00:00:00 2001 From: dpi Date: Wed, 17 Dec 2025 17:01:00 +0800 Subject: [PATCH] Allow silencing exceptions for globbed assets #64 --- src/Attribute/Asset/Css.php | 6 +++-- src/Attribute/Asset/Js.php | 6 +++-- tests/PintoAssetGlobTest.php | 43 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/src/Attribute/Asset/Css.php b/src/Attribute/Asset/Css.php index 20c735a..8d3d2ee 100644 --- a/src/Attribute/Asset/Css.php +++ b/src/Attribute/Asset/Css.php @@ -30,6 +30,7 @@ public function __construct( public bool $preprocess = false, public string $category = 'component', public readonly array $attributes = [], + public readonly bool $silenceNoMatches = false, ) { if (str_starts_with($path, '/')) { throw new \LogicException('Path must not begin with forward-slash'); @@ -49,8 +50,9 @@ public function getLibraryPaths(): AssetLibraryPaths $glob = \glob($pattern); if (false === $glob || [] === $glob) { if (!\file_exists($pattern)) { - // No exceptions when globs are used, no files are allowed. - throw new \LogicException('File does not exist: ' . $pattern); + return $this->silenceNoMatches + ? new AssetLibraryPaths() + : throw new \LogicException('File does not exist: ' . $pattern); } return new AssetLibraryPaths([['css', $this->category, $pattern]]); diff --git a/src/Attribute/Asset/Js.php b/src/Attribute/Asset/Js.php index 12abd26..9b12988 100644 --- a/src/Attribute/Asset/Js.php +++ b/src/Attribute/Asset/Js.php @@ -27,6 +27,7 @@ public function __construct( public bool $minified = false, public bool $preprocess = false, public readonly array $attributes = [], + public readonly bool $silenceNoMatches = false, ) { if (str_starts_with($path, '/')) { throw new \LogicException('Path must not begin with forward-slash'); @@ -46,8 +47,9 @@ public function getLibraryPaths(): AssetLibraryPaths $glob = \glob($pattern); if (false === $glob || [] === $glob) { if (!\file_exists($pattern)) { - // No exceptions when globs are used, no files are allowed. - throw new \LogicException('File does not exist: ' . $pattern); + return $this->silenceNoMatches + ? new AssetLibraryPaths() + : throw new \LogicException('File does not exist: ' . $pattern); } return new AssetLibraryPaths([['js', $pattern]]); diff --git a/tests/PintoAssetGlobTest.php b/tests/PintoAssetGlobTest.php index 038f482..f090d81 100644 --- a/tests/PintoAssetGlobTest.php +++ b/tests/PintoAssetGlobTest.php @@ -3,11 +3,14 @@ declare(strict_types=1); use PHPUnit\Framework\TestCase; +use Pinto\Asset\AssetLibraryPaths; use Pinto\Attribute\Asset\Css; use Pinto\Attribute\Asset\Js; use Pinto\Library\LibraryBuilder; use Pinto\tests\fixtures\Lists\AssetGlob\PintoListAssetGlob; +use function Safe\realpath; + /** * Test asset globs. * @@ -47,4 +50,44 @@ public function testGlob(): void ]], ], iterator_to_array(LibraryBuilder::expandLibraryPaths(PintoListAssetGlob::Wildcard))); } + + public function testGlobNoMatchesExceptionCss(): void + { + $css = new Css('no-styles*.css'); + $css->setPath(realpath(__DIR__ . '/fixtures/Assets/PintoListAssetGlob')); + static::expectExceptionMessage('File does not exist'); + $css->getLibraryPaths(); + } + + public function testGlobNoMatchesExceptionJs(): void + { + $js = new Js('no-styles*.js'); + $js->setPath(realpath(__DIR__ . '/fixtures/Assets/PintoListAssetGlob')); + static::expectExceptionMessage('File does not exist'); + $js->getLibraryPaths(); + } + + public function testGlobNoMatchesExceptionSilencedCss(): void + { + $css = new Css('no-styles*.css', silenceNoMatches: true); + $css->setPath(realpath(__DIR__ . '/fixtures/Assets/PintoListAssetGlob')); + static::assertEquals(new AssetLibraryPaths(), $css->getLibraryPaths()); + + // When no glob is used, but glob is silenced, and no matches, ensure exception is still thrown: + $css = new Css('no-styles.css', silenceNoMatches: true); + $css->setPath(realpath(__DIR__ . '/fixtures/Assets/PintoListAssetGlob')); + static::assertEquals(new AssetLibraryPaths(), $css->getLibraryPaths()); + } + + public function testGlobNoMatchesExceptionSilencedJs(): void + { + $js = new Js('no-styles*.css', silenceNoMatches: true); + $js->setPath(realpath(__DIR__ . '/fixtures/Assets/PintoListAssetGlob')); + static::assertEquals(new AssetLibraryPaths(), $js->getLibraryPaths()); + + // When no glob is used, but glob is silenced, and no matches, ensure exception is still thrown: + $js = new Js('no-styles.css', silenceNoMatches: true); + $js->setPath(realpath(__DIR__ . '/fixtures/Assets/PintoListAssetGlob')); + static::assertEquals(new AssetLibraryPaths(), $js->getLibraryPaths()); + } }