diff --git a/packages/vite-plugin-tempest/src/config.ts b/packages/vite-plugin-tempest/src/config.ts index 187623b66..8370cd279 100644 --- a/packages/vite-plugin-tempest/src/config.ts +++ b/packages/vite-plugin-tempest/src/config.ts @@ -1,12 +1,13 @@ +import type { Options } from './plugin' import type { TempestViteConfiguration } from './types' import { exec, php } from './utils' const TEMPEST_BIN = 'tempest' const VITE_CONFIG_COMMAND = 'vite:config' -export async function loadTempestConfiguration(): Promise { +export async function loadTempestConfiguration(options: Options = {}): Promise { try { - const { stdout } = await exec(`${php.value} ${TEMPEST_BIN} ${VITE_CONFIG_COMMAND}`) + const { stdout } = await exec(`${php.value} ${TEMPEST_BIN} ${VITE_CONFIG_COMMAND} --tag=${options.tag ?? 'null'}`) const json = stdout.match(/\{.*\}/s) return JSON.parse(json?.[0] as string) diff --git a/packages/vite-plugin-tempest/src/plugin.ts b/packages/vite-plugin-tempest/src/plugin.ts index b359e6591..057c56dd7 100644 --- a/packages/vite-plugin-tempest/src/plugin.ts +++ b/packages/vite-plugin-tempest/src/plugin.ts @@ -15,7 +15,11 @@ const TEMPEST_ORIGIN_PLACEHOLDER = 'http://__tempest_placeholder__.test' let exitHandlersBound = false -export default function tempest(): Plugin { +export interface Options { + tag?: string +} + +export default function tempest(options: Options = {}): Plugin { let viteDevServerUrl: DevelopmentServerUrl let bridgeFilePath: string let resolvedConfig: ResolvedConfig @@ -30,7 +34,7 @@ export default function tempest(): Plugin { name: 'tempest', enforce: 'post', config: async (config, { command, mode }) => { - tempestConfig = await loadTempestConfiguration() + tempestConfig = await loadTempestConfiguration(options) userConfig = config const ssr = !!userConfig.build?.ssr diff --git a/src/Tempest/Container/src/AllowDynamicTags.php b/src/Tempest/Container/src/AllowDynamicTags.php new file mode 100644 index 000000000..6f491af65 --- /dev/null +++ b/src/Tempest/Container/src/AllowDynamicTags.php @@ -0,0 +1,13 @@ + $className * @return null|TClassName */ - public function get(string $className, ?string $tag = null, mixed ...$params): mixed; + public function get(string $className, null|string|UnitEnum $tag = null, mixed ...$params): mixed; - public function has(string $className, ?string $tag = null): bool; + public function has(string $className, null|string|UnitEnum $tag = null): bool; public function invoke(ClassReflector|MethodReflector|FunctionReflector|callable|string $method, mixed ...$params): mixed; diff --git a/src/Tempest/Container/src/CurrentTag.php b/src/Tempest/Container/src/CurrentTag.php new file mode 100644 index 000000000..362ff4ebf --- /dev/null +++ b/src/Tempest/Container/src/CurrentTag.php @@ -0,0 +1,13 @@ +definitions[$className]) || isset($this->singletons[$this->resolveTaggedName($className, $tag)]); } - public function singleton(string $className, mixed $definition, ?string $tag = null): self + public function singleton(string $className, mixed $definition, null|string|UnitEnum $tag = null): self { $className = $this->resolveTaggedName($className, $tag); @@ -103,16 +104,20 @@ public function singleton(string $className, mixed $definition, ?string $tag = n public function config(object $config): self { - $this->singleton($config::class, $config); + $tag = ($config instanceof TaggedConfig) + ? $config->tag + : null; + + $this->singleton($config::class, $config, $tag); foreach (new ClassReflector($config)->getInterfaces() as $interface) { - $this->singleton($interface->getName(), $config); + $this->singleton($interface->getName(), $config, $tag); } return $this; } - public function get(string $className, ?string $tag = null, mixed ...$params): ?object + public function get(string $className, null|string|UnitEnum $tag = null, mixed ...$params): ?object { $this->resolveChain(); @@ -232,7 +237,7 @@ public function addInitializer(ClassReflector|string $initializerClass): Contain return $this; } - private function resolve(string $className, ?string $tag = null, mixed ...$params): ?object + private function resolve(string $className, null|string|UnitEnum $tag = null, mixed ...$params): ?object { $class = new ClassReflector($className); @@ -277,13 +282,14 @@ private function resolve(string $className, ?string $tag = null, mixed ...$param return $object; } - // If we're requesting a tagged dependency and haven't resolved it at this point, something's wrong - if ($tag) { - throw new CannotResolveTaggedDependency($this->chain, new Dependency($className), $tag); + // If we're requesting a non-dynamic tagged dependency and + // haven't resolved it at this point, something's wrong + if ($tag !== null && ! $class->getAttribute(AllowDynamicTags::class)) { + throw new CannotResolveTaggedDependency($this->chain, new Dependency($className), $this->resolveTag($tag)); } // Finally, autowire the class. - return $this->autowire($className, ...$params); + return $this->autowire($className, $params, $tag); } private function initializerForBuiltin(TypeReflector $target, string $tag): ?Initializer @@ -295,7 +301,7 @@ private function initializerForBuiltin(TypeReflector $target, string $tag): ?Ini return null; } - private function initializerForClass(ClassReflector $target, ?string $tag = null): null|Initializer|DynamicInitializer + private function initializerForClass(ClassReflector $target, null|string|UnitEnum $tag = null): null|Initializer|DynamicInitializer { // Initializers themselves can't be initialized, // otherwise you'd end up with infinite loops @@ -303,10 +309,17 @@ private function initializerForClass(ClassReflector $target, ?string $tag = null return null; } + // If an initializer is registered for the specified dependency and tag, we use it. if ($initializerClass = $this->initializers[$this->resolveTaggedName($target->getName(), $tag)] ?? null) { return $this->resolve($initializerClass); } + // If the dependency allows dynamic tags, we look for the original + // initializer (without tag) and we resolve it, specifying the dynamic tag. + if ($target->getAttribute(AllowDynamicTags::class) && ($initializerClass = $this->initializers[$target->getName()] ?? null)) { + return $this->resolve($initializerClass, $tag); + } + // Loop through the registered initializers to see if // we have something to handle this class. foreach ($this->dynamicInitializers as $initializerClass) { @@ -323,7 +336,7 @@ private function initializerForClass(ClassReflector $target, ?string $tag = null return null; } - private function autowire(string $className, mixed ...$params): object + private function autowire(string $className, array $params, null|string|UnitEnum $tag): object { $classReflector = new ClassReflector($className); @@ -340,7 +353,7 @@ private function autowire(string $className, mixed ...$params): object : // Otherwise, use our autowireDependencies helper to automagically // build up each parameter. $classReflector->newInstanceArgs( - $this->autowireDependencies($constructor, $params), + $this->autowireDependencies($constructor, $params, $tag), ); if ( @@ -352,6 +365,7 @@ private function autowire(string $className, mixed ...$params): object } foreach ($classReflector->getProperties() as $property) { + // Injects to the property the specified dependency if ($property->hasAttribute(Inject::class) && ! $property->isInitialized($instance)) { if ($property->hasAttribute(Lazy::class)) { $property->set($instance, $property->getType()->asClass()->getReflection()->newLazyProxy( @@ -361,6 +375,11 @@ private function autowire(string $className, mixed ...$params): object $property->set($instance, $this->get($property->getType()->getName())); } } + + // Injects to the property the tag the class has been resolved with + if ($property->hasAttribute(CurrentTag::class) && ! $property->isInitialized($instance)) { + $property->set($instance, $property->accepts(UnitEnum::class) ? $tag : $this->resolveTag($tag)); + } } return $instance; @@ -369,7 +388,7 @@ private function autowire(string $className, mixed ...$params): object /** * @return ParameterReflector[] */ - private function autowireDependencies(MethodReflector|FunctionReflector $method, array $parameters = []): array + private function autowireDependencies(MethodReflector|FunctionReflector $method, array $parameters = [], null|string|UnitEnum $tag = null): array { $this->resolveChain()->add($method); @@ -378,9 +397,16 @@ private function autowireDependencies(MethodReflector|FunctionReflector $method, // Build the class by iterating through its // dependencies and resolving them. foreach ($method->getParameters() as $parameter) { + // If the `ForwardTag` attribute is used on a constructor parameter, we + // instantiate this parameter with the current tag. Otherwise we look + // for a `Tag` attribute, and if specified, we use this one instead. + $dependencyTag = $parameter->getAttribute(ForwardTag::class) && $tag + ? $tag + : $parameter->getAttribute(Tag::class)?->name; + $dependencies[] = $this->clone()->autowireDependency( parameter: $parameter, - tag: $parameter->getAttribute(Tag::class)?->name, + tag: $dependencyTag, providedValue: $parameters[$parameter->getName()] ?? null, ); } @@ -388,7 +414,7 @@ private function autowireDependencies(MethodReflector|FunctionReflector $method, return $dependencies; } - private function autowireDependency(ParameterReflector $parameter, ?string $tag, mixed $providedValue = null): mixed + private function autowireDependency(ParameterReflector $parameter, null|string|UnitEnum $tag, mixed $providedValue = null): mixed { $parameterType = $parameter->getType(); @@ -428,7 +454,7 @@ private function autowireDependency(ParameterReflector $parameter, ?string $tag, throw $lastThrowable ?? new CannotAutowireException($this->chain, new Dependency($parameter)); } - private function autowireObjectDependency(TypeReflector $type, ?string $tag, mixed $providedValue, bool $lazy): mixed + private function autowireObjectDependency(TypeReflector $type, null|string|UnitEnum $tag, mixed $providedValue, bool $lazy): mixed { // If the provided value is of the right type, // don't waste time autowiring, return it! @@ -525,10 +551,19 @@ public function __clone(): void $this->chain = $this->chain?->clone(); } - private function resolveTaggedName(string $className, ?string $tag): string + private function resolveTag(null|string|UnitEnum $tag): ?string + { + if ($tag instanceof UnitEnum) { + return $tag->name; + } + + return $tag; + } + + private function resolveTaggedName(string $className, null|string|UnitEnum $tag): string { return $tag - ? "{$className}#{$tag}" + ? "{$className}#{$this->resolveTag($tag)}" : $className; } } diff --git a/src/Tempest/Container/src/Singleton.php b/src/Tempest/Container/src/Singleton.php index caaaca656..ffb96b072 100644 --- a/src/Tempest/Container/src/Singleton.php +++ b/src/Tempest/Container/src/Singleton.php @@ -5,11 +5,12 @@ namespace Tempest\Container; use Attribute; +use UnitEnum; #[Attribute] final readonly class Singleton { public function __construct( - public ?string $tag = null, + public null|string|UnitEnum $tag = null, ) {} } diff --git a/src/Tempest/Container/src/TaggedConfig.php b/src/Tempest/Container/src/TaggedConfig.php new file mode 100644 index 000000000..6da0ea85d --- /dev/null +++ b/src/Tempest/Container/src/TaggedConfig.php @@ -0,0 +1,12 @@ + $className * @return TClassName */ - function get(string $className, ?string $tag = null, mixed ...$params): object + function get(string $className, null|string|UnitEnum $tag = null, mixed ...$params): object { $container = GenericContainer::instance(); diff --git a/src/Tempest/Container/tests/ContainerTest.php b/src/Tempest/Container/tests/ContainerTest.php index bbb703d1a..7ce83adbe 100644 --- a/src/Tempest/Container/tests/ContainerTest.php +++ b/src/Tempest/Container/tests/ContainerTest.php @@ -6,6 +6,7 @@ use PHPUnit\Framework\TestCase; use ReflectionClass; +use Tempest\Container\Container; use Tempest\Container\Exceptions\CannotAutowireException; use Tempest\Container\Exceptions\CannotInstantiateDependencyException; use Tempest\Container\Exceptions\CannotResolveTaggedDependency; @@ -32,6 +33,7 @@ use Tempest\Container\Tests\Fixtures\ContainerObjectE; use Tempest\Container\Tests\Fixtures\ContainerObjectEInitializer; use Tempest\Container\Tests\Fixtures\DependencyWithBuiltinDependencies; +use Tempest\Container\Tests\Fixtures\DependencyWithDynamicTag; use Tempest\Container\Tests\Fixtures\DependencyWithTaggedDependency; use Tempest\Container\Tests\Fixtures\ImplementsInterfaceA; use Tempest\Container\Tests\Fixtures\InjectA; @@ -45,6 +47,7 @@ use Tempest\Container\Tests\Fixtures\SingletonClass; use Tempest\Container\Tests\Fixtures\SingletonInitializer; use Tempest\Container\Tests\Fixtures\SlowDependency; +use Tempest\Container\Tests\Fixtures\SubdependencyWithDynamicTag; use Tempest\Container\Tests\Fixtures\TaggedDependency; use Tempest\Container\Tests\Fixtures\TaggedDependencyCliInitializer; use Tempest\Container\Tests\Fixtures\TaggedDependencyWebInitializer; @@ -557,4 +560,24 @@ public function test_lazy_property_dependency(): void $this->assertSame('value1', $this->assertSlowerThan(fn () => $instance->dependency->value, $delay)); } + + public function test_dynamic_tag_with_forward(): void + { + $container = new GenericContainer(); + $dependency = $container->get(DependencyWithDynamicTag::class, tag: 'foo'); + + $this->assertEquals('foo', $dependency->tag); + $this->assertInstanceOf(SubdependencyWithDynamicTag::class, $dependency->subependency); + $this->assertEquals('foo', $dependency->subependency->tag); + } + + public function test_dynamic_tag_with_forward_without_tag(): void + { + $container = new GenericContainer(); + $dependency = $container->get(DependencyWithDynamicTag::class); + + $this->assertNull($dependency->tag); + $this->assertInstanceOf(SubdependencyWithDynamicTag::class, $dependency->subependency); + $this->assertNull($dependency->subependency->tag); + } } diff --git a/src/Tempest/Container/tests/Fixtures/DependencyWithDynamicTag.php b/src/Tempest/Container/tests/Fixtures/DependencyWithDynamicTag.php new file mode 100644 index 000000000..d3e2e6445 --- /dev/null +++ b/src/Tempest/Container/tests/Fixtures/DependencyWithDynamicTag.php @@ -0,0 +1,20 @@ +get(DatabaseConfig::class); + $databaseConfig = $container->get(DatabaseConfig::class, $this->tag); $connection = new PDOConnection($databaseConfig); $connection->connect(); diff --git a/src/Tempest/Database/src/Database.php b/src/Tempest/Database/src/Database.php index 27e7053e8..94776cf3e 100644 --- a/src/Tempest/Database/src/Database.php +++ b/src/Tempest/Database/src/Database.php @@ -4,6 +4,9 @@ namespace Tempest\Database; +use Tempest\Container\AllowDynamicTags; + +#[AllowDynamicTags] interface Database { public function execute(Query $query): void; diff --git a/src/Tempest/Database/src/DatabaseInitializer.php b/src/Tempest/Database/src/DatabaseInitializer.php index 7f63fa1e2..6c0674d74 100644 --- a/src/Tempest/Database/src/DatabaseInitializer.php +++ b/src/Tempest/Database/src/DatabaseInitializer.php @@ -4,20 +4,26 @@ namespace Tempest\Database; +use Tempest\Container\AllowDynamicTags; use Tempest\Container\Container; +use Tempest\Container\CurrentTag; use Tempest\Container\Initializer; use Tempest\Container\Singleton; use Tempest\Database\Connection\Connection; use Tempest\Database\Transactions\TransactionManager; -final readonly class DatabaseInitializer implements Initializer +#[AllowDynamicTags] +final class DatabaseInitializer implements Initializer { + #[CurrentTag] + private ?string $tag; // @phpstan-ignore-line this is injected + #[Singleton] public function initialize(Container $container): Database { return new GenericDatabase( - $container->get(Connection::class), - $container->get(TransactionManager::class), + $container->get(Connection::class, $this->tag), + $container->get(TransactionManager::class, $this->tag), ); } } diff --git a/src/Tempest/Database/src/Transactions/TransactionManager.php b/src/Tempest/Database/src/Transactions/TransactionManager.php index f12c915a6..f8f537da7 100644 --- a/src/Tempest/Database/src/Transactions/TransactionManager.php +++ b/src/Tempest/Database/src/Transactions/TransactionManager.php @@ -4,6 +4,9 @@ namespace Tempest\Database\Transactions; +use Tempest\Container\AllowDynamicTags; + +#[AllowDynamicTags] interface TransactionManager { public function begin(): void; diff --git a/src/Tempest/Database/src/Transactions/TransactionManagerInitializer.php b/src/Tempest/Database/src/Transactions/TransactionManagerInitializer.php index eeaffc850..510f50b91 100644 --- a/src/Tempest/Database/src/Transactions/TransactionManagerInitializer.php +++ b/src/Tempest/Database/src/Transactions/TransactionManagerInitializer.php @@ -4,16 +4,22 @@ namespace Tempest\Database\Transactions; +use Tempest\Container\AllowDynamicTags; use Tempest\Container\Container; +use Tempest\Container\CurrentTag; use Tempest\Container\Initializer; use Tempest\Container\Singleton; use Tempest\Database\Connection\Connection; -final readonly class TransactionManagerInitializer implements Initializer +#[AllowDynamicTags] +final class TransactionManagerInitializer implements Initializer { + #[CurrentTag] + private ?string $tag; // @phpstan-ignore-line this is injected + #[Singleton] public function initialize(Container $container): TransactionManager { - return new GenericTransactionManager($container->get(Connection::class)); + return new GenericTransactionManager($container->get(Connection::class, $this->tag)); } } diff --git a/src/Tempest/Vite/src/Vite.php b/src/Tempest/Vite/src/Vite.php index 73e1b72fb..2a8bb6caf 100644 --- a/src/Tempest/Vite/src/Vite.php +++ b/src/Tempest/Vite/src/Vite.php @@ -4,7 +4,10 @@ namespace Tempest\Vite; +use Tempest\Container\AllowDynamicTags; use Tempest\Container\Container; +use Tempest\Container\ForwardTag; +use Tempest\Container\Singleton; use Tempest\Core\AppConfig; use Tempest\Vite\Exceptions\DevelopmentServerNotRunningException; use Tempest\Vite\Exceptions\ManifestNotFoundException; @@ -17,6 +20,7 @@ use function Tempest\root_path; use function Tempest\Support\arr; +#[AllowDynamicTags] final class Vite { public const string CLIENT_SCRIPT_PATH = '@vite/client'; @@ -26,8 +30,9 @@ final class Vite private static ?Manifest $manifest = null; public function __construct( - private readonly AppConfig $appConfig, + #[ForwardTag] private readonly ViteConfig $viteConfig, + private readonly AppConfig $appConfig, private readonly Container $container, private readonly TagCompiler $tagCompiler, ) {} diff --git a/src/Tempest/Vite/src/ViteConfig.php b/src/Tempest/Vite/src/ViteConfig.php index 231ce5b57..7cd224a5e 100644 --- a/src/Tempest/Vite/src/ViteConfig.php +++ b/src/Tempest/Vite/src/ViteConfig.php @@ -4,7 +4,10 @@ namespace Tempest\Vite; -final class ViteConfig +use Tempest\Container\TaggedConfig; +use UnitEnum; + +final class ViteConfig implements TaggedConfig { /** * @param PrefetchConfig $prefetching Strategy for prefetching assets at runtime. @@ -25,6 +28,7 @@ public function __construct( public string $bridgeFileName = 'vite-tempest', public string $manifest = 'manifest.json', public array $entrypoints = [], + public readonly null|UnitEnum|string $tag = null, ) {} public function addEntrypoint(string $path): void diff --git a/src/Tempest/Vite/src/ViteConfigCommand.php b/src/Tempest/Vite/src/ViteConfigCommand.php index 290c69feb..a6448b36b 100644 --- a/src/Tempest/Vite/src/ViteConfigCommand.php +++ b/src/Tempest/Vite/src/ViteConfigCommand.php @@ -6,22 +6,25 @@ use Tempest\Console\Console; use Tempest\Console\ConsoleCommand; +use Tempest\Container\Container; final readonly class ViteConfigCommand { public function __construct( private Console $console, - private ViteConfig $viteConfig, + private Container $container, ) {} #[ConsoleCommand(name: 'vite:config', hidden: true)] - public function __invoke(): void + public function __invoke(?string $tag = null): void { + $config = $this->container->get(ViteConfig::class, $tag); + $this->console->writeRaw(json_encode([ - 'build_directory' => $this->viteConfig->buildDirectory, - 'bridge_file_name' => $this->viteConfig->bridgeFileName, - 'manifest' => $this->viteConfig->manifest, - 'entrypoints' => $this->viteConfig->entrypoints, + 'build_directory' => $config->buildDirectory, + 'bridge_file_name' => $config->bridgeFileName, + 'manifest' => $config->manifest, + 'entrypoints' => $config->entrypoints, ])); } } diff --git a/src/Tempest/Vite/src/ViteTagsComponent.php b/src/Tempest/Vite/src/ViteTagsComponent.php index 5af5ad9cb..c804c02bc 100644 --- a/src/Tempest/Vite/src/ViteTagsComponent.php +++ b/src/Tempest/Vite/src/ViteTagsComponent.php @@ -26,8 +26,13 @@ public function compile(ViewComponentElement $element): string default => var_export($this->viteConfig->entrypoints, return: true), // @mago-expect best-practices/no-debug-symbols }; + $config = match (true) { + $element->hasAttribute('config') => '$config', + default => 'null', + }; + return << + HTML; } } diff --git a/src/Tempest/Vite/src/functions.php b/src/Tempest/Vite/src/functions.php index 7340fda94..bec1b4c04 100644 --- a/src/Tempest/Vite/src/functions.php +++ b/src/Tempest/Vite/src/functions.php @@ -5,14 +5,15 @@ namespace Tempest { use Tempest\Support\Html\HtmlString; use Tempest\Vite\Vite; + use UnitEnum; /** * Inject tags for the specified or configured `$entrypoints`. */ - function vite_tags(null|string|array $entrypoints = null): HtmlString + function vite_tags(null|string|array $entrypoints = null, null|string|UnitEnum $tag = null): HtmlString { return new HtmlString( - string: implode('', get(Vite::class)->getTags(is_array($entrypoints) ? $entrypoints : [$entrypoints])), + string: implode('', get(Vite::class, $tag)->getTags(is_array($entrypoints) ? $entrypoints : [$entrypoints])), ); } } diff --git a/tests/Fixtures/Config/tagged1.config.php b/tests/Fixtures/Config/tagged1.config.php new file mode 100644 index 000000000..a913cc934 --- /dev/null +++ b/tests/Fixtures/Config/tagged1.config.php @@ -0,0 +1,10 @@ +tag); + } +} diff --git a/tests/Fixtures/TaggedConfigExample.php b/tests/Fixtures/TaggedConfigExample.php new file mode 100644 index 000000000..8063f9b07 --- /dev/null +++ b/tests/Fixtures/TaggedConfigExample.php @@ -0,0 +1,13 @@ +container->get(DependencyWithDynamicTag::class, tag: 'bar'); + + $this->assertEquals('bar', $dependency->tag); + } + + public function test_dynamic_tag_with_initializer_without_specifying_tag(): void + { + $dependency = $this->container->get(DependencyWithDynamicTag::class); + + $this->assertNull($dependency->tag); + } +} diff --git a/tests/Integration/Core/Fixtures/ConfigTagEnum.php b/tests/Integration/Core/Fixtures/ConfigTagEnum.php new file mode 100644 index 000000000..9c07e8b7f --- /dev/null +++ b/tests/Integration/Core/Fixtures/ConfigTagEnum.php @@ -0,0 +1,9 @@ +container->get(TaggedConfigExample::class, tag: 'tagged1'); + $tagged2 = $this->container->get(TaggedConfigExample::class, tag: 'tagged2'); + + $this->assertSame('tagged1', $tagged1->property); + $this->assertSame('tagged2', $tagged2->property); + + $class = $this->container->get(HasTaggedConfig::class); + + $this->assertSame('tagged1', $class->config1->property); + $this->assertSame('tagged2', $class->config2->property); + } + + public function test_load_enum_tagged_config(): void + { + $this->container->config(new TaggedEnumConfigExample(tag: ConfigTagEnum::CONFIG1, property: 'foo')); + $this->container->config(new TaggedEnumConfigExample(tag: ConfigTagEnum::CONFIG2, property: 'bar')); + + $tagged1 = $this->container->get(TaggedEnumConfigExample::class, tag: ConfigTagEnum::CONFIG1); + $tagged2 = $this->container->get(TaggedEnumConfigExample::class, tag: ConfigTagEnum::CONFIG2); + + $this->assertSame('foo', $tagged1->property); + $this->assertSame('bar', $tagged2->property); + } +} diff --git a/tests/Integration/Vite/ViteConfigCommandTestCase.php b/tests/Integration/Vite/ViteConfigCommandTest.php similarity index 54% rename from tests/Integration/Vite/ViteConfigCommandTestCase.php rename to tests/Integration/Vite/ViteConfigCommandTest.php index fe77b399a..03a11ee63 100644 --- a/tests/Integration/Vite/ViteConfigCommandTestCase.php +++ b/tests/Integration/Vite/ViteConfigCommandTest.php @@ -11,7 +11,7 @@ /** * @internal */ -final class ViteConfigCommandTestCase extends FrameworkIntegrationTestCase +final class ViteConfigCommandTest extends FrameworkIntegrationTestCase { public function test_outputs_json_default_config(): void { @@ -33,4 +33,23 @@ public function test_outputs_json_custom_config(): void ->call(ViteConfigCommand::class) ->assertSee('{"build_directory":"build\/website","bridge_file_name":".website","manifest":"website.json","entrypoints":["src\/website\/main.ts"]}'); } + + public function test_outputs_json_custom_tagged_config(): void + { + $this->container->config(new ViteConfig( + tag: 'custom', + buildDirectory: 'build/website', + bridgeFileName: '.website', + manifest: 'website.json', + entrypoints: ['src/website/main.ts'], + )); + + $this->console + ->call(ViteConfigCommand::class) + ->assertSee('{"build_directory":"build","bridge_file_name":"vite-tempest","manifest":"manifest.json","entrypoints":[]}'); + + $this->console + ->call(ViteConfigCommand::class, ['tag' => 'custom']) + ->assertSee('{"build_directory":"build\/website","bridge_file_name":".website","manifest":"website.json","entrypoints":["src\/website\/main.ts"]}'); + } }