diff --git a/CHANGELOG.md b/CHANGELOG.md index 55132de..3bbc3f7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,8 +7,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- The views also answer to the canonical `laranail/confetti` namespace + (`view('laranail/confetti::components.scripts')`), registered by + package-tools over the same paths as `laranail-confetti`, published overrides + included. A naming test asserts both forms against the live view finder. + ### Changed +- The package renders through `laranail/confetti::` (`ConfettiTags::VIEW`). + `laranail-confetti::` still resolves the same files. +- Requires `laranail/package-tools ^0.1.3`, the first release that registers + both namespace forms. - `laranail::confetti.install` now extends laranail/package-tools' `InstallCommand` and takes laranail/console's display API and run lifecycle from its `InteractsWithConsoleServices` and `InteractsWithConsoleWriter` diff --git a/composer.json b/composer.json index a4c27de..660ee9a 100644 --- a/composer.json +++ b/composer.json @@ -45,7 +45,7 @@ "illuminate/view": "^13.0", "laranail/console": "^0.1", "laranail/enumerator": "^0.1", - "laranail/package-tools": "^0.1" + "laranail/package-tools": "^0.1.3" }, "require-dev": { "filament/filament": "^4.0 || ^5.0", diff --git a/docs/architecture.md b/docs/architecture.md index 4bb155d..56b2f81 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -196,11 +196,17 @@ Everything this package registers is prefixed, and none of it is called just | Surface | Name | Used as | |---|---|---| | Blade component | `laranail-confetti` | `` | -| View namespace | `laranail-confetti` | `view('laranail-confetti::components.scripts')` | +| View namespace | `laranail/confetti` (canonical), `laranail-confetti` (alias) | `view('laranail/confetti::components.scripts')` | | Route middleware | `laranail-confetti` | `->middleware('laranail-confetti')` | | Artisan commands | `laranail::confetti.` | `php artisan laranail::confetti.doctor` | | Alpine component | `laranailConfetti` | `
` | +The view namespace answers to both spellings over the same paths. `laranail/confetti` +is canonical, because it is the composer package name, and the package renders +through it. `laranail-confetti` is kept, not deprecated: it is the spelling a +Blade tag needs, and overrides published to +`resources/views/vendor/laranail-confetti` keep winning under either name. + Laravel keeps view namespaces, component prefixes and middleware aliases in flat maps keyed by that name. Two packages claiming the same key do not collide loudly; the second silently replaces the first, and it surfaces much later as a diff --git a/src/Providers/ConfettiServiceProvider.php b/src/Providers/ConfettiServiceProvider.php index dac0044..995a685 100644 --- a/src/Providers/ConfettiServiceProvider.php +++ b/src/Providers/ConfettiServiceProvider.php @@ -42,6 +42,10 @@ public function configurePackage(Package $package): void $package ->name('laranail/confetti') ->hasConfigFile() + // Declared under the hyphen form so overrides already published to + // resources/views/vendor/laranail-confetti keep winning; package-tools + // registers the canonical `laranail/confetti` namespace over the same + // paths, and the package renders through that one. ->hasViews('laranail-confetti') ->hasAssets() ->hasBladeComponentNamespace( diff --git a/src/View/ConfettiTags.php b/src/View/ConfettiTags.php index 531ed8c..0dede80 100644 --- a/src/View/ConfettiTags.php +++ b/src/View/ConfettiTags.php @@ -20,7 +20,11 @@ */ final readonly class ConfettiTags { - public const string VIEW = 'laranail-confetti::components.scripts'; + /** + * The view, under the canonical `laranail/confetti` namespace. The `laranail-confetti` namespace + * still resolves the same file, including an override published under it. + */ + public const string VIEW = 'laranail/confetti::components.scripts'; public function __construct( private ConfettiConfig $config, diff --git a/tests/Feature/FilamentPluginTest.php b/tests/Feature/FilamentPluginTest.php index ebab72d..a4f2794 100644 --- a/tests/Feature/FilamentPluginTest.php +++ b/tests/Feature/FilamentPluginTest.php @@ -76,7 +76,7 @@ function renderPanelHook(Panel $panel, string $hook): string ConfettiPlugin::make()->register($panel); - $expected = view('laranail-confetti::components.scripts', [ + $expected = view('laranail/confetti::components.scripts', [ 'enabled' => true, 'bootJson' => app(BootConfig::class)->toJson(), 'scriptTag' => app(ScriptTagBuilder::class)->render(), diff --git a/tests/Feature/InjectionTest.php b/tests/Feature/InjectionTest.php index 5b04099..50fcaaa 100644 --- a/tests/Feature/InjectionTest.php +++ b/tests/Feature/InjectionTest.php @@ -19,7 +19,7 @@ // A page that already carries the component. Route::get('/explicit', fn (): string => '' - . view('laranail-confetti::components.scripts', [ + . view('laranail/confetti::components.scripts', [ 'enabled' => true, 'bootJson' => app(BootConfig::class)->toJson(), 'scriptTag' => app(ScriptTagBuilder::class)->render(), diff --git a/tests/Feature/NamingConventionTest.php b/tests/Feature/NamingConventionTest.php index 62aacf1..c533991 100644 --- a/tests/Feature/NamingConventionTest.php +++ b/tests/Feature/NamingConventionTest.php @@ -4,6 +4,11 @@ use Illuminate\Support\Facades\View; use Illuminate\Support\Facades\Blade; +use Simtabi\Laranail\Confetti\View\ConfettiTags; +use Simtabi\Laranail\Package\Tools\Testing\NamingScope; +use Simtabi\Laranail\Package\Tools\Testing\AssertsRegisteredNames; + +uses(AssertsRegisteredNames::class); /** * Every public name this package claims is prefixed with the org and the slug. @@ -29,6 +34,22 @@ expect($hints)->not->toHaveKey('confetti'); }); +it('registers both view namespace forms over the same paths, and renders through the canonical one', function (): void { + // basePath is resources/: package-tools v0.1.3 defaults ownership to the + // package root, which also claims vendor/ and tests/ registrations (fixed in v0.1.4). + $scope = NamingScope::for('laranail/confetti', 'Simtabi\\Laranail\\Confetti\\', basePath: dirname(__DIR__, 2) . '/resources'); + + expect($this->assertViewNamespacesScoped($scope, atLeast: 2)) + ->toContain('laranail/confetti', PREFIX); + + $hints = View::getFinder()->getHints(); + + expect($hints['laranail/confetti'])->toBe($hints[PREFIX]); + expect(ConfettiTags::VIEW)->toStartWith('laranail/confetti::'); + expect(view('laranail-confetti::components.scripts')->getPath()) + ->toBe(view(ConfettiTags::VIEW)->getPath()); +}); + it('registers its Blade components under the org-scoped prefix', function (): void { $namespaces = new ReflectionProperty(Blade::getFacadeRoot(), 'classComponentNamespaces') ->getValue(Blade::getFacadeRoot()); diff --git a/tests/Feature/SessionTransportTest.php b/tests/Feature/SessionTransportTest.php index c19d102..9a46c92 100644 --- a/tests/Feature/SessionTransportTest.php +++ b/tests/Feature/SessionTransportTest.php @@ -75,7 +75,7 @@ return redirect('/page'); }); - Route::middleware('web')->get('/page', fn (): Factory|View => view('laranail-confetti::components.scripts', [ + Route::middleware('web')->get('/page', fn (): Factory|View => view('laranail/confetti::components.scripts', [ 'enabled' => true, 'bootJson' => app(BootConfig::class)->toJson(), 'scriptTag' => app(ScriptTagBuilder::class)->render(),