diff --git a/src/Factories/LayerFactory.php b/src/Factories/LayerFactory.php index 77e4575..888f92d 100644 --- a/src/Factories/LayerFactory.php +++ b/src/Factories/LayerFactory.php @@ -60,7 +60,9 @@ public function make(LayerOptions $options, string $name, bool $onlyUserDefinedU return $object; }, $this->objectsStorage->allByNamespace($name, $onlyUserDefinedUses)); - $layer = Layer::fromBase($objects)->leaveByNameStart($name); + $layer = str_contains($name, '*') + ? Layer::fromBase($objects)->leaveByNameRegex('/'.strtr(preg_quote($name, '/'), ['\\*' => '[^\\\\]+']).'/') + : Layer::fromBase($objects)->leaveByNameStart($name); foreach ($options->exclude as $exclude) { $layer = $layer->excludeByNameStart($exclude); diff --git a/src/Layer.php b/src/Layer.php index 2a87939..9f06012 100644 --- a/src/Layer.php +++ b/src/Layer.php @@ -13,6 +13,7 @@ * @method Layer assertDoesNotDependOn(string ...$objects) * @method Layer excludeByNameStart(string $name) * @method Layer exclude(callable $callback) + * @method Layer leaveByNameRegex(string $name) * @method Layer leaveByNameStart(string $name) * * @implements IteratorAggregate diff --git a/src/Repositories/ObjectsRepository.php b/src/Repositories/ObjectsRepository.php index 4970287..d7fdcdc 100644 --- a/src/Repositories/ObjectsRepository.php +++ b/src/Repositories/ObjectsRepository.php @@ -103,7 +103,7 @@ public function allByNamespace(string $namespace, bool $onlyUserDefinedUses = tr $objectsPerPrefix = array_values(array_filter(array_reduce($directories, fn (array $files, string $fileOrDirectory): array => array_merge($files, array_values(array_map( static fn (SplFileInfo $file): ?ObjectDescription => ObjectDescriptionFactory::make($file->getPathname(), $onlyUserDefinedUses), - is_dir($fileOrDirectory) ? iterator_to_array(Finder::create()->files()->in($fileOrDirectory)->name('*.php')) : [new SplFileInfo($fileOrDirectory)], + is_dir($fileOrDirectory) || str_contains($fileOrDirectory, '*') ? iterator_to_array(Finder::create()->files()->in($fileOrDirectory)->name('*.php')) : [new SplFileInfo($fileOrDirectory)], ))), []))); $objects = [...$objects, ...$this->cachedObjectsPerPrefix[$prefix][(int) $onlyUserDefinedUses] = $objectsPerPrefix]; @@ -151,13 +151,15 @@ private function directoriesByNamespace(string $name): array $directoriesByNamespace[$name] = [...$directoriesByNamespace[$name] ?? [], ...array_values(array_filter(array_map(static function (string $directory) use ($prefix): string { $fileOrDirectory = $directory.DIRECTORY_SEPARATOR.$prefix; - if (is_dir($fileOrDirectory)) { return $fileOrDirectory; } + if (str_contains($fileOrDirectory, '*')) { + return $fileOrDirectory; + } return $fileOrDirectory.'.php'; - }, $directories), static fn (string $fileOrDirectory): bool => is_dir($fileOrDirectory) || file_exists($fileOrDirectory)))]; + }, $directories), static fn (string $fileOrDirectory): bool => is_dir($fileOrDirectory) || str_contains($fileOrDirectory, '*') || file_exists($fileOrDirectory)))]; } } diff --git a/tests/Arch.php b/tests/Arch.php index 0e2aaae..36142c3 100644 --- a/tests/Arch.php +++ b/tests/Arch.php @@ -11,6 +11,8 @@ use Pest\Expectation; use Whoops\Exception\Frame; +arch('strict types')->expect('*')->toUseStrictTypes(); + arch('base') ->expect('Pest\Arch') ->classes->toBeFinal() diff --git a/tests/Fixtures/Domains/A/Contracts/Models/Bazable.php b/tests/Fixtures/Domains/A/Contracts/Models/Bazable.php new file mode 100644 index 0000000..d8070f1 --- /dev/null +++ b/tests/Fixtures/Domains/A/Contracts/Models/Bazable.php @@ -0,0 +1,10 @@ +toOnlyUse('Pest\Support\Str'); }); +it('loads namespaces', function () { + expect('Tests\Fixtures\Domains\A\Models') + ->getTargets() + ->toBe([ArticleDomainA::class]); +}); + +it('loads namespaces using wildcards', function () { + expect('Tests\Fixtures\Domains\*\Models') + ->getTargets() + ->toBe([ArticleDomainA::class, ArticleDomainB::class]); +}); + +it('loads namespaces using multiple wildcards', function () { + expect('Tests\Fixtures\Domains\*\*\Models') + ->getTargets() + ->toBe([BazableDomainA::class, BazableDomainB::class]); +}); + it('does support enums', function () { expect(Color::class)->toUseNothing() ->and(ColorThatDependsOnColor::class)->toUse([Color::class]); diff --git a/tests/Pest.php b/tests/Pest.php index a88d89a..821b304 100644 --- a/tests/Pest.php +++ b/tests/Pest.php @@ -1,6 +1,8 @@ beforeEach(function () { $this->arch()->ignore([ @@ -23,3 +25,20 @@ ->toBe($line); }); }); + +expect()->extend('getTargets', function () { + $classes = []; + Targeted::make( + $this, + function (ObjectDescription $object) use (&$classes): bool { + $classes[] = $object->name; + + return true; + }, + '', + fn ($path) => 0, + ); + $this->value = $classes; + + return $this; +});