diff --git a/src/Collectors/Collector.php b/src/Collectors/Collector.php index bde78941..8ec5a4d0 100644 --- a/src/Collectors/Collector.php +++ b/src/Collectors/Collector.php @@ -3,6 +3,7 @@ namespace Spatie\TypeScriptTransformer\Collectors; use ReflectionClass; +use Spatie\TypeScriptTransformer\Compactors\ConfigCompactor; use Spatie\TypeScriptTransformer\Structures\TransformedType; use Spatie\TypeScriptTransformer\TypeScriptTransformerConfig; @@ -10,9 +11,12 @@ abstract class Collector { protected TypeScriptTransformerConfig $config; + protected ConfigCompactor $compactor; + public function __construct(TypeScriptTransformerConfig $config) { $this->config = $config; + $this->compactor = new ConfigCompactor($config); } abstract public function getTransformedType(ReflectionClass $class): ?TransformedType; diff --git a/src/Collectors/DefaultCollector.php b/src/Collectors/DefaultCollector.php index 5fcb2a11..311ab5e9 100644 --- a/src/Collectors/DefaultCollector.php +++ b/src/Collectors/DefaultCollector.php @@ -49,6 +49,7 @@ protected function resolveAlreadyTransformedType(ClassTypeReflector $reflector): $reflector->getReflectionClass(), $reflector->getName(), $transpiler->execute($reflector->getType()), + $this->compactor, $missingSymbols ); } diff --git a/src/Compactors/Compactor.php b/src/Compactors/Compactor.php new file mode 100644 index 00000000..9a6c1459 --- /dev/null +++ b/src/Compactors/Compactor.php @@ -0,0 +1,13 @@ +config = $config; + } + + /** + * @return string[] + */ + protected function getPrefixes(): array { + if ($this->prefixes === null) { + $this->prefixes = array_map( + function (string $prefix): string { + if (str_ends_with($prefix, "\\")) { + $prefix = rtrim($prefix, "\\"); + } + return $prefix; + }, + $this->config->getCompactorPrefixes() + ); + } + return $this->prefixes; + } + + /** + * @return string[] + */ + protected function getSuffixes(): array { + if ($this->suffixes === null) { + $this->suffixes = $this->config->getCompactorSuffixes(); + } + return $this->suffixes; + } + + public function removeSuffix(string $typeName): string { + $matchingSuffix = ''; + foreach ($this->getSuffixes() as $suffix) { + if (str_ends_with($typeName, $suffix)) { + $matchingSuffix = $suffix; + break; + } + } + if ($matchingSuffix !== '') { + $typeName = substr($typeName, 0, -strlen($matchingSuffix)); + } + return $typeName; + } + + public function removePrefix(string $namespace): string { + $matchingPrefix = ''; + foreach ($this->getPrefixes() as $prefix) { + if (str_starts_with($namespace, $prefix)) { + $matchingPrefix = $prefix; + break; + } + } + $substr = substr($namespace, strlen($matchingPrefix)); + return ltrim($substr, '\\'); + } + +} \ No newline at end of file diff --git a/src/Compactors/IdentityCompactor.php b/src/Compactors/IdentityCompactor.php new file mode 100644 index 00000000..2d75f78e --- /dev/null +++ b/src/Compactors/IdentityCompactor.php @@ -0,0 +1,15 @@ +removeSuffix($name), $transformed, $compactor, $missingSymbols ?? new MissingSymbolsCollection(), $inline, $keyword, $trailingSemicolon); } public static function createInline( ReflectionClass $class, string $transformed, + Compactor $compactor, ?MissingSymbolsCollection $missingSymbols = null ): self { - return new self($class, null, $transformed, $missingSymbols ?? new MissingSymbolsCollection(), true); + return new self($class, null, $transformed, $compactor, $missingSymbols ?? new MissingSymbolsCollection(), true); } public function __construct( ReflectionClass $class, ?string $name, string $transformed, + Compactor $compactor, MissingSymbolsCollection $missingSymbols, bool $isInline, string $keyword = 'type', @@ -53,6 +59,7 @@ public function __construct( $this->name = $name; $this->transformed = $transformed; $this->missingSymbols = $missingSymbols; + $this->compactor = $compactor; $this->isInline = $isInline; $this->keyword = $keyword; $this->trailingSemicolon = $trailingSemicolon; @@ -70,6 +77,12 @@ public function getNamespaceSegments(): array return []; } + $namespace = $this->compactor->removePrefix($namespace); + + if ($namespace === '') { + return []; + } + return explode('\\', $namespace); } diff --git a/src/Transformers/DtoTransformer.php b/src/Transformers/DtoTransformer.php index a39fbdee..b4ba00bd 100644 --- a/src/Transformers/DtoTransformer.php +++ b/src/Transformers/DtoTransformer.php @@ -6,6 +6,7 @@ use ReflectionProperty; use Spatie\TypeScriptTransformer\Attributes\Hidden; use Spatie\TypeScriptTransformer\Attributes\Optional; +use Spatie\TypeScriptTransformer\Compactors\ConfigCompactor; use Spatie\TypeScriptTransformer\Structures\MissingSymbolsCollection; use Spatie\TypeScriptTransformer\Structures\TransformedType; use Spatie\TypeScriptTransformer\TypeProcessors\DtoCollectionTypeProcessor; @@ -18,9 +19,12 @@ class DtoTransformer implements Transformer protected TypeScriptTransformerConfig $config; + protected ConfigCompactor $compactor; + public function __construct(TypeScriptTransformerConfig $config) { $this->config = $config; + $this->compactor = new ConfigCompactor($config); } public function transform(ReflectionClass $class, string $name): ?TransformedType @@ -30,7 +34,6 @@ public function transform(ReflectionClass $class, string $name): ?TransformedTyp } $missingSymbols = new MissingSymbolsCollection(); - $type = join([ $this->transformProperties($class, $missingSymbols), $this->transformMethods($class, $missingSymbols), @@ -41,6 +44,7 @@ public function transform(ReflectionClass $class, string $name): ?TransformedTyp $class, $name, "{" . PHP_EOL . $type . "}", + $this->compactor, $missingSymbols ); } diff --git a/src/Transformers/EnumTransformer.php b/src/Transformers/EnumTransformer.php index d9fdc351..5e3e3cf2 100644 --- a/src/Transformers/EnumTransformer.php +++ b/src/Transformers/EnumTransformer.php @@ -5,13 +5,17 @@ use ReflectionClass; use ReflectionEnum; use ReflectionEnumBackedCase; +use Spatie\TypeScriptTransformer\Compactors\ConfigCompactor; use Spatie\TypeScriptTransformer\Structures\TransformedType; use Spatie\TypeScriptTransformer\TypeScriptTransformerConfig; class EnumTransformer implements Transformer { + protected ConfigCompactor $compactor; + public function __construct(protected TypeScriptTransformerConfig $config) { + $this->compactor = new ConfigCompactor($config); } public function transform(ReflectionClass $class, string $name): ?TransformedType @@ -46,6 +50,7 @@ protected function toEnum(ReflectionEnum $enum, string $name): TransformedType $enum, $name, implode(', ', $options), + $this->compactor, keyword: 'enum' ); } @@ -60,7 +65,8 @@ protected function toType(ReflectionEnum $enum, string $name): TransformedType return TransformedType::create( $enum, $name, - implode(' | ', $options) + implode(' | ', $options), + $this->compactor ); } diff --git a/src/Transformers/MyclabsEnumTransformer.php b/src/Transformers/MyclabsEnumTransformer.php index cab53b62..2fa6d8be 100644 --- a/src/Transformers/MyclabsEnumTransformer.php +++ b/src/Transformers/MyclabsEnumTransformer.php @@ -4,13 +4,17 @@ use MyCLabs\Enum\Enum; use ReflectionClass; +use Spatie\TypeScriptTransformer\Compactors\ConfigCompactor; use Spatie\TypeScriptTransformer\Structures\TransformedType; use Spatie\TypeScriptTransformer\TypeScriptTransformerConfig; class MyclabsEnumTransformer implements Transformer { + protected ConfigCompactor $compactor; + public function __construct(protected TypeScriptTransformerConfig $config) { + $this->compactor = new ConfigCompactor($config); } public function transform(ReflectionClass $class, string $name): ?TransformedType @@ -39,6 +43,7 @@ protected function toEnum(ReflectionClass $class, string $name): TransformedType $class, $name, implode(', ', $options), + $this->compactor, keyword: 'enum' ); } @@ -56,7 +61,8 @@ protected function toType(ReflectionClass $class, string $name): TransformedType return TransformedType::create( $class, $name, - implode(' | ', $options) + implode(' | ', $options), + $this->compactor ); } } diff --git a/src/Transformers/SpatieEnumTransformer.php b/src/Transformers/SpatieEnumTransformer.php index 5824c67b..3042ed93 100644 --- a/src/Transformers/SpatieEnumTransformer.php +++ b/src/Transformers/SpatieEnumTransformer.php @@ -4,13 +4,17 @@ use ReflectionClass; use Spatie\Enum\Enum; +use Spatie\TypeScriptTransformer\Compactors\ConfigCompactor; use Spatie\TypeScriptTransformer\Structures\TransformedType; use Spatie\TypeScriptTransformer\TypeScriptTransformerConfig; class SpatieEnumTransformer implements Transformer { + protected ConfigCompactor $compactor; + public function __construct(protected TypeScriptTransformerConfig $config) { + $this->compactor = new ConfigCompactor($config); } public function transform(ReflectionClass $class, string $name): ?TransformedType @@ -39,6 +43,7 @@ protected function toEnum(ReflectionClass $class, string $name): TransformedType $class, $name, implode(', ', $options), + $this->compactor, keyword: 'enum' ); } @@ -56,7 +61,8 @@ private function toType(ReflectionClass $class, string $name): TransformedType return TransformedType::create( $class, $name, - implode(' | ', $options) + implode(' | ', $options), + $this->compactor ); } } diff --git a/src/TypeScriptTransformerConfig.php b/src/TypeScriptTransformerConfig.php index 68ec6002..3f4ba099 100644 --- a/src/TypeScriptTransformerConfig.php +++ b/src/TypeScriptTransformerConfig.php @@ -27,6 +27,10 @@ class TypeScriptTransformerConfig private ?string $formatter = null; + private array $compactorPrefixes = []; + + private array $compactorSuffixes = []; + private bool $transformToNativeEnums = false; private bool $nullToOptional = false; @@ -85,6 +89,34 @@ public function formatter(?string $formatter): self return $this; } + /** + * @param string[]|string $prefixes + * @return $this + */ + public function compactorPrefixes(array|string $prefixes): self + { + if (!is_array($prefixes)) { + $prefixes = [$prefixes]; + } + $this->compactorPrefixes = $prefixes; + + return $this; + } + + /** + * @param string[]|string $suffixes + * @return $this + */ + public function compactorSuffixes(array|string $suffixes): self + { + if (!is_array($suffixes)) { + $suffixes = [$suffixes]; + } + $this->compactorSuffixes = $suffixes; + + return $this; + } + public function transformToNativeEnums(bool $transformToNativeEnums = true): self { $this->transformToNativeEnums = $transformToNativeEnums; @@ -122,7 +154,7 @@ public function buildTransformer(string $transformer): Transformer public function getWriter(): Writer { - return new $this->writer; + return new $this->writer($this); } public function getOutputFile(): string @@ -167,6 +199,22 @@ public function getFormatter(): ?Formatter return new $this->formatter; } + /** + * @return string[] + */ + public function getCompactorPrefixes(): array + { + return $this->compactorPrefixes ?? []; + } + + /** + * @return string[] + */ + public function getCompactorSuffixes(): array + { + return $this->compactorSuffixes ?? []; + } + public function shouldTransformToNativeEnums(): bool { return $this->transformToNativeEnums; diff --git a/src/Writers/TypeDefinitionWriter.php b/src/Writers/TypeDefinitionWriter.php index 1a029894..401aa9c0 100644 --- a/src/Writers/TypeDefinitionWriter.php +++ b/src/Writers/TypeDefinitionWriter.php @@ -3,11 +3,20 @@ namespace Spatie\TypeScriptTransformer\Writers; use Spatie\TypeScriptTransformer\Actions\ReplaceSymbolsInCollectionAction; +use Spatie\TypeScriptTransformer\Compactors\Compactor; +use Spatie\TypeScriptTransformer\Compactors\ConfigCompactor; use Spatie\TypeScriptTransformer\Structures\TransformedType; use Spatie\TypeScriptTransformer\Structures\TypesCollection; +use Spatie\TypeScriptTransformer\TypeScriptTransformerConfig; class TypeDefinitionWriter implements Writer { + protected Compactor $compactor; + + public function __construct(TypeScriptTransformerConfig $config) { + $this->compactor = new ConfigCompactor($config); + } + public function format(TypesCollection $collection): string { (new ReplaceSymbolsInCollectionAction())->execute($collection); @@ -18,6 +27,7 @@ public function format(TypesCollection $collection): string foreach ($namespaces as $namespace => $types) { asort($types); + $namespace = $this->compactor->removePrefix($namespace); $output .= "declare namespace {$namespace} {".PHP_EOL; diff --git a/tests/Fakes/FakeTransformedType.php b/tests/Fakes/FakeTransformedType.php index 80fc4f41..71ab2b40 100644 --- a/tests/Fakes/FakeTransformedType.php +++ b/tests/Fakes/FakeTransformedType.php @@ -4,17 +4,19 @@ use Exception; use ReflectionClass; +use Spatie\TypeScriptTransformer\Compactors\Compactor; +use Spatie\TypeScriptTransformer\Compactors\IdentityCompactor; use Spatie\TypeScriptTransformer\Structures\MissingSymbolsCollection; use Spatie\TypeScriptTransformer\Structures\TransformedType; class FakeTransformedType extends TransformedType { - public static function create(ReflectionClass $class, string $name, string $transformed, ?MissingSymbolsCollection $missingSymbols = null, bool $inline = false, string $keyword = 'type', bool $trailingSemicolon = true): TransformedType + public static function create(ReflectionClass $class, string $name, string $transformed, Compactor $compactor, ?MissingSymbolsCollection $missingSymbols = null, bool $inline = false, string $keyword = 'type', bool $trailingSemicolon = true): TransformedType { throw new Exception("Fake type"); } - public static function createInline(ReflectionClass $class, string $transformed, ?MissingSymbolsCollection $missingSymbols = null): TransformedType + public static function createInline(ReflectionClass $class, string $transformed, Compactor $compactor, ?MissingSymbolsCollection $missingSymbols = null): TransformedType { throw new Exception("Fake type"); } @@ -27,6 +29,7 @@ public static function fake(?string $name = null): self FakeReflectionClass::create()->withName($name), $name, 'fake-transformed', + new IdentityCompactor(), new MissingSymbolsCollection(), false ); diff --git a/tests/Fakes/FakeTypeScriptCollector.php b/tests/Fakes/FakeTypeScriptCollector.php index 1e646870..b345ff99 100644 --- a/tests/Fakes/FakeTypeScriptCollector.php +++ b/tests/Fakes/FakeTypeScriptCollector.php @@ -21,6 +21,7 @@ public function getTransformedType(ReflectionClass $class): TransformedType $class, $class->getShortName(), 'fake-collected-class', + $this->compactor, new MissingSymbolsCollection(), false ); diff --git a/tests/Transformers/DtoTransformerTest.php b/tests/Transformers/DtoTransformerTest.php index 5ba756b6..75f4c0f0 100644 --- a/tests/Transformers/DtoTransformerTest.php +++ b/tests/Transformers/DtoTransformerTest.php @@ -161,3 +161,61 @@ class DummyOptionalDto $this->assertMatchesSnapshot($type->transformed); }); + +it('compacts namespaces', function () { + $reflectionClass = new ReflectionClass(Dto::class); + assertEquals( + 'Dto', + (new DtoTransformer( + TypeScriptTransformerConfig::create() + ->compactorPrefixes([ + "Spatie\\TypeScriptTransformer\\Tests\\FakeClasses\\Integration" + ]) + ))->transform( + $reflectionClass, + 'Dto' + )->getTypeScriptName(true) + ); + + assertEquals( + 'Integration.Dto', + (new DtoTransformer( + TypeScriptTransformerConfig::create() + ->compactorPrefixes([ + "Spatie\\TypeScriptTransformer\\Tests\\FakeClasses" + ]) + ))->transform( + $reflectionClass, + 'Dto' + )->getTypeScriptName(true) + ); + assertEquals( + 'Integration.Dto', + (new DtoTransformer( + TypeScriptTransformerConfig::create() + ->compactorPrefixes([ + "Spatie\\TypeScriptTransformer\\Tests\\RealClasses", + "Spatie\\TypeScriptTransformer\\Tests\\FakeClasses" + ]) + ))->transform( + $reflectionClass, + 'Dto' + )->getTypeScriptName(true) + ); +}); +it('compacts type names', function () { + $reflectionClass = new ReflectionClass(DtoWithChildren::class); + assertEquals( + 'Dto', + (new DtoTransformer( + TypeScriptTransformerConfig::create() + ->compactorPrefixes("Spatie\\TypeScriptTransformer\\Tests\\FakeClasses\\Integration") + ->compactorSuffixes([ + 'WithChildren' + ]) + ))->transform( + $reflectionClass, + 'DtoWithChildren' + )->getTypeScriptName(true) + ); +}); diff --git a/tests/TypeScriptTransformerConfigTest.php b/tests/TypeScriptTransformerConfigTest.php index 03a0cddd..16a9d7cc 100644 --- a/tests/TypeScriptTransformerConfigTest.php +++ b/tests/TypeScriptTransformerConfigTest.php @@ -68,3 +68,9 @@ $config->getDefaultTypeReplacements() ); }); + +it('can handle string as compactor_prefixes parameter', function () { + $config = TypeScriptTransformerConfig::create()->compactorPrefixes('asdf.asdf'); + + assertEquals(['asdf.asdf'], $config->getCompactorPrefixes()); +});