From a786f9bc50a1f10c471db5670eeadda1b089b90c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Th=C3=A9o=20FIDRY?= Date: Sun, 16 Jun 2024 16:11:27 +0200 Subject: [PATCH] refactor: Introduce a Prefix value object --- src/Configuration/Configuration.php | 31 ++++----------- src/Configuration/Prefix.php | 35 +++++++++++++++++ src/Configuration/PrefixValidator.php | 39 +++++++++++++++++++ src/Console/ScoperLogger.php | 3 +- src/Patcher/Patcher.php | 3 ++ src/Patcher/PatcherChain.php | 5 ++- src/PhpParser/Node/FullyQualifiedFactory.php | 12 ++++-- src/PhpParser/Node/NameFactory.php | 9 +++-- .../NodeVisitor/ClassIdentifierRecorder.php | 3 +- .../ExcludedFunctionExistsEnricher.php | 11 +++--- .../FunctionIdentifierRecorder.php | 3 +- .../NodeVisitor/NameStmtPrefixer.php | 5 ++- .../NamespaceStmt/NamespaceStmtPrefixer.php | 7 ++-- .../NodeVisitor/StringScalarPrefixer.php | 7 ++-- .../NodeVisitor/UseStmt/UseStmtPrefixer.php | 9 +++-- src/PhpParser/TraverserFactory.php | 10 ++++- src/Scoper/Composer/AutoloadPrefixer.php | 14 +++++-- src/Scoper/PatchScoper.php | 10 ++++- src/Scoper/Symfony/XmlScoper.php | 14 +++++-- src/Scoper/Symfony/YamlScoper.php | 10 ++++- src/Scoper/SymfonyScoper.php | 3 +- .../ConfigurationFactoryTest.php | 4 +- tests/Configuration/ConfigurationTest.php | 2 +- tests/PhpParser/UseStmtNameTest.php | 3 +- 24 files changed, 180 insertions(+), 72 deletions(-) create mode 100644 src/Configuration/Prefix.php create mode 100644 src/Configuration/PrefixValidator.php diff --git a/src/Configuration/Configuration.php b/src/Configuration/Configuration.php index 723c8dea1..e6bd6ce5d 100644 --- a/src/Configuration/Configuration.php +++ b/src/Configuration/Configuration.php @@ -16,16 +16,10 @@ use Humbug\PhpScoper\Configuration\Throwable\InvalidConfigurationValue; use Humbug\PhpScoper\Patcher\Patcher; -use function Safe\preg_match; final class Configuration { - private const PREFIX_PATTERN = '/^[\p{L}\d_\\\\]+$/u'; - - /** - * @var non-empty-string - */ - private readonly string $prefix; + private readonly Prefix $prefix; /** * @param non-empty-string|null $path Absolute canonical path to the configuration file loaded. @@ -43,15 +37,15 @@ final class Configuration public function __construct( private ?string $path, private ?string $outputDir, - string $prefix, + string|Prefix $prefix, private array $filesWithContents, private array $excludedFilesWithContents, private Patcher $patcher, private SymbolsConfiguration $symbolsConfiguration ) { - self::validatePrefix($prefix); - - $this->prefix = $prefix; + $this->prefix = $prefix instanceof Prefix + ? $prefix + : new Prefix($prefix); } /** @@ -89,9 +83,9 @@ public function withPrefix(string $prefix): self } /** - * @return non-empty-string + * @return non-empty-string|Prefix */ - public function getPrefix(): string + public function getPrefix(): string|Prefix { return $this->prefix; } @@ -150,15 +144,4 @@ public function getSymbolsConfiguration(): SymbolsConfiguration { return $this->symbolsConfiguration; } - - private static function validatePrefix(string $prefix): void - { - if (1 !== preg_match(self::PREFIX_PATTERN, $prefix)) { - throw InvalidConfigurationValue::forInvalidPrefixPattern($prefix); - } - - if (preg_match('/\\\{2,}/', $prefix)) { - throw InvalidConfigurationValue::forInvalidNamespaceSeparator($prefix); - } - } } diff --git a/src/Configuration/Prefix.php b/src/Configuration/Prefix.php new file mode 100644 index 000000000..f3eb5ae66 --- /dev/null +++ b/src/Configuration/Prefix.php @@ -0,0 +1,35 @@ +, + * Pádraic Brady + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Humbug\PhpScoper\Configuration; + +use Stringable; + +final readonly class Prefix implements Stringable +{ + public function __construct(private string $prefix) + { + PrefixValidator::validate($this->prefix); + } + + public function __toString(): string + { + return $this->prefix; + } + + public function toString(): string + { + return (string) $this; + } +} diff --git a/src/Configuration/PrefixValidator.php b/src/Configuration/PrefixValidator.php new file mode 100644 index 000000000..9a8167031 --- /dev/null +++ b/src/Configuration/PrefixValidator.php @@ -0,0 +1,39 @@ +, + * Pádraic Brady + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Humbug\PhpScoper\Configuration; + +use Humbug\PhpScoper\Configuration\Throwable\InvalidConfigurationValue; +use function Safe\preg_match; + +final class PrefixValidator +{ + private const PREFIX_PATTERN = '/^[\p{L}\d_\\\\]+$/u'; + + /** + * @phpstan-assert non-empty-string $prefix + * + * @throws InvalidConfigurationValue + */ + public static function validate(string $prefix): void + { + if (1 !== preg_match(self::PREFIX_PATTERN, $prefix)) { + throw InvalidConfigurationValue::forInvalidPrefixPattern($prefix); + } + + if (preg_match('/\\\{2,}/', $prefix)) { + throw InvalidConfigurationValue::forInvalidNamespaceSeparator($prefix); + } + } +} diff --git a/src/Console/ScoperLogger.php b/src/Console/ScoperLogger.php index 4439b28d3..d9621deec 100644 --- a/src/Console/ScoperLogger.php +++ b/src/Console/ScoperLogger.php @@ -16,6 +16,7 @@ use Fidry\Console\Application\Application as FidryApplication; use Fidry\Console\IO; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Throwable\Exception\ParsingException; use PHPUnit\Framework\Attributes\CodeCoverageIgnore; use Symfony\Component\Console\Helper\ProgressBar; @@ -49,7 +50,7 @@ public function __construct( /** * @param string[] $paths */ - public function outputScopingStart(?string $prefix, array $paths): void + public function outputScopingStart(Prefix|string|null $prefix, array $paths): void { $this->io->writeln($this->application->getHelp()); diff --git a/src/Patcher/Patcher.php b/src/Patcher/Patcher.php index 791b0da39..722037447 100644 --- a/src/Patcher/Patcher.php +++ b/src/Patcher/Patcher.php @@ -14,6 +14,9 @@ namespace Humbug\PhpScoper\Patcher; +/** + * @phpstan-type PatcherCallable callable(string, string, string): string + */ interface Patcher { public function __invoke(string $filePath, string $prefix, string $contents): string; diff --git a/src/Patcher/PatcherChain.php b/src/Patcher/PatcherChain.php index 27806bae4..e39ba9bf1 100644 --- a/src/Patcher/PatcherChain.php +++ b/src/Patcher/PatcherChain.php @@ -16,10 +16,13 @@ use function array_reduce; +/** + * @phpstan-import-type PatcherCallable from Patcher + */ final readonly class PatcherChain implements Patcher { /** - * @param array<(callable(string, string, string): string)|Patcher> $patchers + * @param array $patchers */ public function __construct(private array $patchers = []) { diff --git a/src/PhpParser/Node/FullyQualifiedFactory.php b/src/PhpParser/Node/FullyQualifiedFactory.php index 881fea05c..38450e51a 100644 --- a/src/PhpParser/Node/FullyQualifiedFactory.php +++ b/src/PhpParser/Node/FullyQualifiedFactory.php @@ -18,18 +18,19 @@ use InvalidArgumentException; use PhpParser\Node\Name; use PhpParser\Node\Name\FullyQualified; +use Stringable; final class FullyQualifiedFactory { use NotInstantiable; /** - * @param string|Name|string[]|null $name1 - * @param string|Name|string[]|null $name2 + * @param string|Name|string[]|Stringable|null $name1 + * @param string|Name|string[]|Stringable|null $name2 */ public static function concat( - array|Name|string|null $name1, - array|Name|string|null $name2, + array|Name|string|Stringable|null $name1, + array|Name|string|Stringable|null $name2, ?array $attributes = null, ): FullyQualified { if (null === $name1 && null === $name2) { @@ -38,6 +39,9 @@ public static function concat( $newAttributes = NameFactory::getConcatenatedNamesAttributes($name1, $name2, $attributes); + $name1 = $name1 instanceof Stringable ? (string) $name1 : $name1; + $name2 = $name2 instanceof Stringable ? (string) $name2 : $name2; + return FullyQualified::concat($name1, $name2, $newAttributes); } } diff --git a/src/PhpParser/Node/NameFactory.php b/src/PhpParser/Node/NameFactory.php index eca55ea3c..91cdb6ff5 100644 --- a/src/PhpParser/Node/NameFactory.php +++ b/src/PhpParser/Node/NameFactory.php @@ -17,6 +17,7 @@ use Humbug\PhpScoper\NotInstantiable; use InvalidArgumentException; use PhpParser\Node\Name; +use Stringable; final class NameFactory { @@ -41,12 +42,12 @@ public static function concat( } /** - * @param string|string[]|Name|null $name1 - * @param string|string[]|Name|null $name2 + * @param string|Stringable|string[]|Name|null $name1 + * @param string|Stringable|string[]|Name|null $name2 */ public static function getConcatenatedNamesAttributes( - string|array|Name|null $name1, - string|array|Name|null $name2, + string|Stringable|array|Name|null $name1, + string|Stringable|array|Name|null $name2, ?array $attributes = null, ): array { return match (true) { diff --git a/src/PhpParser/NodeVisitor/ClassIdentifierRecorder.php b/src/PhpParser/NodeVisitor/ClassIdentifierRecorder.php index 63b8114ce..e66537ee8 100644 --- a/src/PhpParser/NodeVisitor/ClassIdentifierRecorder.php +++ b/src/PhpParser/NodeVisitor/ClassIdentifierRecorder.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser\NodeVisitor; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\PhpParser\Node\FullyQualifiedFactory; use Humbug\PhpScoper\PhpParser\NodeVisitor\AttributeAppender\ParentNodeAppender; use Humbug\PhpScoper\PhpParser\NodeVisitor\Resolver\IdentifierResolver; @@ -35,7 +36,7 @@ final class ClassIdentifierRecorder extends NodeVisitorAbstract { public function __construct( - private readonly string $prefix, + private readonly Prefix $prefix, private readonly IdentifierResolver $identifierResolver, private readonly SymbolsRegistry $symbolsRegistry, private readonly EnrichedReflector $enrichedReflector, diff --git a/src/PhpParser/NodeVisitor/ExcludedFunctionExistsEnricher.php b/src/PhpParser/NodeVisitor/ExcludedFunctionExistsEnricher.php index 82a4cb38a..f87419e54 100644 --- a/src/PhpParser/NodeVisitor/ExcludedFunctionExistsEnricher.php +++ b/src/PhpParser/NodeVisitor/ExcludedFunctionExistsEnricher.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser\NodeVisitor; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\PhpParser\NodeVisitor\AttributeAppender\ParentNodeAppender; use Humbug\PhpScoper\PhpParser\UnexpectedParsingScenario; use PhpParser\Node\Arg; @@ -57,7 +58,7 @@ final class ExcludedFunctionExistsEnricher extends NodeVisitorAbstract { public function __construct( - private readonly string $prefix, + private readonly Prefix $prefix, private readonly ExcludedFunctionExistsStringNodeStack $excludedFunctionExistsStringNodeStack, ) { } @@ -76,7 +77,7 @@ public function afterTraverse(array $nodes): array return $nodes; } - private static function addScopedFunctionExistsCondition(string $prefix, String_ $string): void + private static function addScopedFunctionExistsCondition(Prefix $prefix, String_ $string): void { $parentNodes = self::findFlattenedParentIfStmt($string); @@ -154,7 +155,7 @@ private static function findFlattenedParentIfStmt(String_ $string): ?array } private static function replaceCondition( - string $prefix, + Prefix $prefix, If_ $ifStmt, BooleanAnd|BooleanOr|null $ifCondition, BooleanNot|Equal|Identical $boolExpr, @@ -217,11 +218,11 @@ private static function createNewArgument(Arg $previous, String_ $string): Arg return $newArg; } - private static function prefixString(string $prefix, String_ $previous): String_ + private static function prefixString(Prefix $prefix, String_ $previous): String_ { return new String_( (string) FullyQualified::concat( - $prefix, + $prefix->toString(), $previous->value, ), $previous->getAttributes(), diff --git a/src/PhpParser/NodeVisitor/FunctionIdentifierRecorder.php b/src/PhpParser/NodeVisitor/FunctionIdentifierRecorder.php index 9fbfb51db..0898b80f9 100644 --- a/src/PhpParser/NodeVisitor/FunctionIdentifierRecorder.php +++ b/src/PhpParser/NodeVisitor/FunctionIdentifierRecorder.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser\NodeVisitor; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\PhpParser\Node\FullyQualifiedFactory; use Humbug\PhpScoper\PhpParser\NodeVisitor\AttributeAppender\ParentNodeAppender; use Humbug\PhpScoper\PhpParser\NodeVisitor\Resolver\IdentifierResolver; @@ -38,7 +39,7 @@ final class FunctionIdentifierRecorder extends NodeVisitorAbstract { public function __construct( - private readonly string $prefix, + private readonly Prefix $prefix, private readonly IdentifierResolver $identifierResolver, private readonly SymbolsRegistry $symbolsRegistry, private readonly EnrichedReflector $enrichedReflector, diff --git a/src/PhpParser/NodeVisitor/NameStmtPrefixer.php b/src/PhpParser/NodeVisitor/NameStmtPrefixer.php index ddd2d4209..86756a73e 100644 --- a/src/PhpParser/NodeVisitor/NameStmtPrefixer.php +++ b/src/PhpParser/NodeVisitor/NameStmtPrefixer.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser\NodeVisitor; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\PhpParser\Node\FullyQualifiedFactory; use Humbug\PhpScoper\PhpParser\NodeVisitor\AttributeAppender\ParentNodeAppender; use Humbug\PhpScoper\PhpParser\NodeVisitor\NamespaceStmt\NamespaceStmtCollection; @@ -95,7 +96,7 @@ final class NameStmtPrefixer extends NodeVisitorAbstract ]; public function __construct( - private readonly string $prefix, + private readonly Prefix $prefix, private readonly NamespaceStmtCollection $namespaceStatements, private readonly UseStmtCollection $useStatements, private readonly EnrichedReflector $enrichedReflector, @@ -233,7 +234,7 @@ private function isNamePrefixable(Name $resolvedName): bool return false; } - $isAlreadyPrefixed = $this->prefix === $resolvedName->getFirst(); + $isAlreadyPrefixed = $this->prefix->toString() === $resolvedName->getFirst(); return ( $isAlreadyPrefixed diff --git a/src/PhpParser/NodeVisitor/NamespaceStmt/NamespaceStmtPrefixer.php b/src/PhpParser/NodeVisitor/NamespaceStmt/NamespaceStmtPrefixer.php index c9736d592..35a6eeb31 100644 --- a/src/PhpParser/NodeVisitor/NamespaceStmt/NamespaceStmtPrefixer.php +++ b/src/PhpParser/NodeVisitor/NamespaceStmt/NamespaceStmtPrefixer.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser\NodeVisitor\NamespaceStmt; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Symbol\EnrichedReflector; use PhpParser\Node; use PhpParser\Node\Name; @@ -38,7 +39,7 @@ final class NamespaceStmtPrefixer extends NodeVisitorAbstract { public function __construct( - private readonly string $prefix, + private readonly Prefix $prefix, private readonly EnrichedReflector $enrichedReflector, private readonly NamespaceStmtCollection $namespaceStatements, ) { @@ -75,11 +76,11 @@ private function shouldPrefixStmt(Namespace_ $namespace): bool return $this->prefix !== $nameFirstPart; } - private static function prefixStmt(Namespace_ $namespace, string $prefix): void + private static function prefixStmt(Namespace_ $namespace, Prefix $prefix): void { $originalName = $namespace->name; - $namespace->name = Name::concat($prefix, $originalName); + $namespace->name = Name::concat($prefix->toString(), $originalName); NamespaceManipulator::setOriginalName($namespace, $originalName); } diff --git a/src/PhpParser/NodeVisitor/StringScalarPrefixer.php b/src/PhpParser/NodeVisitor/StringScalarPrefixer.php index 5e8ff9ae7..6c78ed227 100644 --- a/src/PhpParser/NodeVisitor/StringScalarPrefixer.php +++ b/src/PhpParser/NodeVisitor/StringScalarPrefixer.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser\NodeVisitor; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\PhpParser\NodeVisitor\AttributeAppender\ParentNodeAppender; use Humbug\PhpScoper\PhpParser\UnexpectedParsingScenario; use Humbug\PhpScoper\Symbol\EnrichedReflector; @@ -123,7 +124,7 @@ final class StringScalarPrefixer extends NodeVisitorAbstract REGEX; public function __construct( - private readonly string $prefix, + private readonly Prefix $prefix, private readonly EnrichedReflector $enrichedReflector, private readonly ExcludedFunctionExistsStringNodeStack $excludedFunctionExistsStringNodeStack, ) { @@ -384,7 +385,7 @@ private function createPrefixedString(String_ $previous): String_ ), ); - $previousValueAlreadyPrefixed = $this->prefix === $previousValueParts[0]; + $previousValueAlreadyPrefixed = $this->prefix->toString() === $previousValueParts[0]; if ($previousValueAlreadyPrefixed) { // Remove the prefix and proceed as usual: this ensures that even @@ -396,7 +397,7 @@ private function createPrefixedString(String_ $previous): String_ $previousValue = implode('\\', $previousValueParts); $string = new String_( - (string) FullyQualified::concat($this->prefix, $previousValue), + (string) FullyQualified::concat($this->prefix->toString(), $previousValue), $previous->getAttributes(), ); diff --git a/src/PhpParser/NodeVisitor/UseStmt/UseStmtPrefixer.php b/src/PhpParser/NodeVisitor/UseStmt/UseStmtPrefixer.php index b4c8837ec..d16945c58 100644 --- a/src/PhpParser/NodeVisitor/UseStmt/UseStmtPrefixer.php +++ b/src/PhpParser/NodeVisitor/UseStmt/UseStmtPrefixer.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser\NodeVisitor\UseStmt; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\PhpParser\NodeVisitor\AttributeAppender\ParentNodeAppender; use Humbug\PhpScoper\PhpParser\UnexpectedParsingScenario; use Humbug\PhpScoper\Symbol\EnrichedReflector; @@ -31,7 +32,7 @@ final class UseStmtPrefixer extends NodeVisitorAbstract { public function __construct( - private readonly string $prefix, + private readonly Prefix $prefix, private readonly EnrichedReflector $enrichedReflector, ) { } @@ -50,7 +51,7 @@ private function shouldPrefixUseStmt(UseUse $use): bool $useType = self::findUseType($use); $nameString = $use->name->toString(); - $alreadyPrefixed = $this->prefix === $use->name->getFirst(); + $alreadyPrefixed = $this->prefix->toString() === $use->name->getFirst(); if ($alreadyPrefixed) { return false; @@ -72,12 +73,12 @@ private function shouldPrefixUseStmt(UseUse $use): bool || !$this->enrichedReflector->isClassInternal($nameString); } - private static function prefixStmt(UseUse $use, string $prefix): void + private static function prefixStmt(UseUse $use, Prefix $prefix): void { $previousName = $use->name; $prefixedName = Name::concat( - $prefix, + $prefix->toString(), $use->name, $use->name->getAttributes(), ); diff --git a/src/PhpParser/TraverserFactory.php b/src/PhpParser/TraverserFactory.php index ebdba0df3..9c76117af 100644 --- a/src/PhpParser/TraverserFactory.php +++ b/src/PhpParser/TraverserFactory.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\PhpParser\NodeVisitor\ExcludedFunctionExistsEnricher; use Humbug\PhpScoper\PhpParser\NodeVisitor\ExcludedFunctionExistsStringNodeStack; use Humbug\PhpScoper\PhpParser\NodeVisitor\NamespaceStmt\NamespaceStmtCollection; @@ -32,11 +33,16 @@ */ class TraverserFactory { + private readonly Prefix $prefix; + public function __construct( private readonly EnrichedReflector $reflector, - private readonly string $prefix, + string|Prefix $prefix, private readonly SymbolsRegistry $symbolsRegistry, ) { + $this->prefix = $prefix instanceof Prefix + ? $prefix + : new Prefix($prefix); } public function create(PhpScoper $scoper): NodeTraverserInterface @@ -71,7 +77,7 @@ private static function createTraverser(array $nodeVisitors): NodeTraverserInter * @return PhpParserNodeVisitor[] */ private static function createNodeVisitors( - string $prefix, + Prefix $prefix, EnrichedReflector $reflector, PhpScoper $scoper, SymbolsRegistry $symbolsRegistry diff --git a/src/Scoper/Composer/AutoloadPrefixer.php b/src/Scoper/Composer/AutoloadPrefixer.php index a5e57a841..98ad60f48 100644 --- a/src/Scoper/Composer/AutoloadPrefixer.php +++ b/src/Scoper/Composer/AutoloadPrefixer.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\Scoper\Composer; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Symbol\EnrichedReflector; use stdClass; use function array_map; @@ -31,10 +32,15 @@ */ final readonly class AutoloadPrefixer { + private Prefix $prefix; + public function __construct( - private string $prefix, + string|Prefix $prefix, private EnrichedReflector $enrichedReflector, ) { + $this->prefix = $prefix instanceof Prefix + ? $prefix + : new Prefix($prefix); } /** @@ -73,7 +79,7 @@ public function prefixPackageAutoloadStatements(stdClass $contents): stdClass private static function prefixAutoloadStatements( stdClass $autoload, - string $prefix, + Prefix $prefix, EnrichedReflector $enrichedReflector ): stdClass { if (!isset($autoload->{'psr-4'}) && !isset($autoload->{'psr-0'})) { @@ -114,7 +120,7 @@ private static function prefixAutoloadStatements( private static function prefixAutoload( array $autoload, - string $prefix, + Prefix $prefix, EnrichedReflector $enrichedReflector ): array { $loader = []; @@ -239,7 +245,7 @@ private static function mergeNamespaces(string $psr0Namespace, array|string $psr private static function prefixLaravelProviders( array $providers, - string $prefix, + Prefix $prefix, EnrichedReflector $enrichedReflector ): array { return array_map( diff --git a/src/Scoper/PatchScoper.php b/src/Scoper/PatchScoper.php index 9ccd9d045..a31f62139 100644 --- a/src/Scoper/PatchScoper.php +++ b/src/Scoper/PatchScoper.php @@ -14,23 +14,29 @@ namespace Humbug\PhpScoper\Scoper; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Patcher\Patcher; use function func_get_args; final readonly class PatchScoper implements Scoper { + private Prefix $prefix; + public function __construct( private Scoper $decoratedScoper, - private string $prefix, + string|Prefix $prefix, private Patcher $patcher, ) { + $this->prefix = $prefix instanceof Prefix + ? $prefix + : new Prefix($prefix); } public function scope(string $filePath, string $contents): string { return ($this->patcher)( $filePath, - $this->prefix, + $this->prefix->toString(), $this->decoratedScoper->scope(...func_get_args()), ); } diff --git a/src/Scoper/Symfony/XmlScoper.php b/src/Scoper/Symfony/XmlScoper.php index fa7b150ce..dd6eed892 100644 --- a/src/Scoper/Symfony/XmlScoper.php +++ b/src/Scoper/Symfony/XmlScoper.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\Scoper\Symfony; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Scoper\Scoper; use Humbug\PhpScoper\Symbol\EnrichedReflector; use Humbug\PhpScoper\Symbol\SymbolsRegistry; @@ -37,12 +38,17 @@ private const NAMESPACE_PATTERN = '/(?:[^\\\\]+(?\\\\(?:\\\\)?))))"/'; private const SINGLE_CLASS_PATTERN = '/(?:(?(?:[\p{L}_][\p{L}_\d]*(?\\\\(?:\\\\)?))):)|(?(?:[\p{L}_][\p{L}_\d]*(?\\\\(?:\\\\)?)+)+[\p{L}_\d]+)/u'; + private Prefix $prefix; + public function __construct( private Scoper $decoratedScoper, - private string $prefix, + string|Prefix $prefix, private EnrichedReflector $enrichedReflector, private SymbolsRegistry $symbolsRegistry, ) { + $this->prefix = $prefix instanceof Prefix + ? $prefix + : new Prefix($prefix); } public function scope(string $filePath, string $contents): string @@ -68,7 +74,7 @@ public function scope(string $filePath, string $contents): string private static function scopeClasses( string $contents, - string $prefix, + Prefix $prefix, EnrichedReflector $enrichedReflector, SymbolsRegistry $symbolsRegistry ): string { @@ -97,7 +103,7 @@ private static function scopeClasses( private static function scopeNamespaces( string $contents, - string $prefix, + Prefix $prefix, EnrichedReflector $enrichedReflector, SymbolsRegistry $symbolsRegistry ): string { @@ -122,7 +128,7 @@ private static function scopeNamespaces( private static function replaceClasses( array $classes, array $separators, - string $prefix, + Prefix $prefix, string $contents, EnrichedReflector $enrichedReflector, SymbolsRegistry $symbolsRegistry diff --git a/src/Scoper/Symfony/YamlScoper.php b/src/Scoper/Symfony/YamlScoper.php index 67f154944..60adfc00f 100644 --- a/src/Scoper/Symfony/YamlScoper.php +++ b/src/Scoper/Symfony/YamlScoper.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\Scoper\Symfony; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Scoper\Scoper; use Humbug\PhpScoper\Symbol\EnrichedReflector; use Humbug\PhpScoper\Symbol\SymbolsRegistry; @@ -36,12 +37,17 @@ private const YAML_EXTENSION_REGEX = '/\.ya?ml$/i'; private const CLASS_PATTERN = '/(?:(?(?:[\p{L}_][\p{L}_\d]*(?\\\\(?:\\\\)?))):)|(?(?:[\p{L}_][\p{L}_\d]*(?\\\\(?:\\\\)?)+)+[\p{L}_\d]+)/u'; + private Prefix $prefix; + public function __construct( private Scoper $decoratedScoper, - private string $prefix, + string|Prefix $prefix, private EnrichedReflector $enrichedReflector, private SymbolsRegistry $symbolsRegistry, ) { + $this->prefix = $prefix instanceof Prefix + ? $prefix + : new Prefix($prefix); } public function scope(string $filePath, string $contents): string @@ -80,7 +86,7 @@ public function scope(string $filePath, string $contents): string private static function replaceClasses( array $classes, array $separators, - string $prefix, + Prefix $prefix, string $contents, EnrichedReflector $enrichedReflector, SymbolsRegistry $symbolsRegistry diff --git a/src/Scoper/SymfonyScoper.php b/src/Scoper/SymfonyScoper.php index 7104db5fc..7990c9488 100644 --- a/src/Scoper/SymfonyScoper.php +++ b/src/Scoper/SymfonyScoper.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\Scoper; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Scoper\Symfony\XmlScoper as SymfonyXmlScoper; use Humbug\PhpScoper\Scoper\Symfony\YamlScoper as SymfonyYamlScoper; use Humbug\PhpScoper\Symbol\EnrichedReflector; @@ -30,7 +31,7 @@ final class SymfonyScoper implements Scoper public function __construct( Scoper $decoratedScoper, - string $prefix, + string|Prefix $prefix, EnrichedReflector $enrichedReflector, SymbolsRegistry $symbolsRegistry ) { diff --git a/tests/Configuration/ConfigurationFactoryTest.php b/tests/Configuration/ConfigurationFactoryTest.php index 2902dafc0..501d77db9 100644 --- a/tests/Configuration/ConfigurationFactoryTest.php +++ b/tests/Configuration/ConfigurationFactoryTest.php @@ -56,7 +56,7 @@ public function test_it_can_be_created_without_a_file(): void $configuration->getSymbolsConfiguration(), ); self::assertNull($configuration->getPath()); - self::assertMatchesRegularExpression('/_PhpScoper[a-z\d]{12}/', $configuration->getPrefix()); + self::assertMatchesRegularExpression('/_PhpScoper[a-z\d]{12}/', (string) $configuration->getPrefix()); self::assertSame([], $configuration->getFilesWithContents()); self::assertEquals( new PatcherChain([ @@ -127,7 +127,7 @@ public function test_it_can_create_a_complete_configuration(): void $configuration = $this->createConfigFromStandardFile(); self::assertSame($this->tmp.DIRECTORY_SEPARATOR.'scoper.inc.php', $configuration->getPath()); - self::assertSame('MyPrefix', $configuration->getPrefix()); + self::assertEquals(new Prefix('MyPrefix'), $configuration->getPrefix()); self::assertSame('dist', $configuration->getOutputDir()); self::assertSame([], $configuration->getFilesWithContents()); self::assertSame( diff --git a/tests/Configuration/ConfigurationTest.php b/tests/Configuration/ConfigurationTest.php index 2c19ac6dd..3e7a4efd3 100644 --- a/tests/Configuration/ConfigurationTest.php +++ b/tests/Configuration/ConfigurationTest.php @@ -128,7 +128,7 @@ private static function assertStateIs( ): void { self::assertSame($expectedPath, $configuration->getPath()); self::assertSame($expectedOutputDir, $configuration->getOutputDir()); - self::assertSame($expectedPrefix, $configuration->getPrefix()); + self::assertEquals($expectedPrefix, $configuration->getPrefix()); self::assertEqualsCanonicalizing( $expectedFilesWithContents, $configuration->getFilesWithContents(), diff --git a/tests/PhpParser/UseStmtNameTest.php b/tests/PhpParser/UseStmtNameTest.php index f4921c10d..f655b085b 100644 --- a/tests/PhpParser/UseStmtNameTest.php +++ b/tests/PhpParser/UseStmtNameTest.php @@ -14,6 +14,7 @@ namespace Humbug\PhpScoper\PhpParser; +use Humbug\PhpScoper\Configuration\Prefix; use Humbug\PhpScoper\Configuration\SymbolsConfiguration; use Humbug\PhpScoper\PhpParser\NodeVisitor\NamespaceStmt\NamespaceStmtCollection; use Humbug\PhpScoper\PhpParser\NodeVisitor\UseStmt\UseStmtCollection; @@ -189,7 +190,7 @@ private static function parseUseStmtName(string $php): Name $traverser->addVisitor(new NodeVisitor\AttributeAppender\ParentNodeAppender()); $traverser->addVisitor( new NodeVisitor\NamespaceStmt\NamespaceStmtPrefixer( - 'Humbug', + new Prefix('Humbug'), new EnrichedReflector( Reflector::createWithPhpStormStubs(), SymbolsConfiguration::create(),