From 547a973a6c050cf1f0b5c6391bdbd78eb4ec8b5c Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Tue, 20 Jan 2026 16:02:22 +0100 Subject: [PATCH] add exact pattern strings --- src/ValueObject/PatternCollection.php | 51 +++++++++++++++++++++ tests/ValueObject/PatternCollectionTest.php | 37 +++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 tests/ValueObject/PatternCollectionTest.php diff --git a/src/ValueObject/PatternCollection.php b/src/ValueObject/PatternCollection.php index a93f73c27..c3affacb5 100644 --- a/src/ValueObject/PatternCollection.php +++ b/src/ValueObject/PatternCollection.php @@ -4,7 +4,10 @@ namespace Rector\Behastan\ValueObject; +use InvalidArgumentException; use Rector\Behastan\ValueObject\Pattern\AbstractPattern; +use Rector\Behastan\ValueObject\Pattern\ExactPattern; +use Rector\Behastan\ValueObject\Pattern\RegexPattern; final readonly class PatternCollection { @@ -38,6 +41,16 @@ public function all(): array return $this->patterns; } + /** + * @return string[] + */ + public function exactPatternStrings(): array + { + $exactPatterns = $this->byType(ExactPattern::class); + + return array_map(fn (ExactPattern $exactPattern): string => $exactPattern->pattern, $exactPatterns); + } + /** * @template TPattern as AbstractPattern * @@ -48,4 +61,42 @@ public function byType(string $type): array { return array_filter($this->patterns, fn (AbstractPattern $pattern): bool => $pattern instanceof $type); } + + public function regexPatternString(): string + { + $regexPatterns = $this->byType(RegexPattern::class); + + $regexPatternStrings = array_map( + fn (RegexPattern $regexPattern): string => $regexPattern->pattern, + $regexPatterns + ); + + return $this->combineRegexes($regexPatternStrings, '#'); + } + + /** + * @param string[] $regexes Like ['/foo/i', '~bar\d+~', '#baz#u'] + */ + private function combineRegexes(array $regexes, string $delimiter = '#'): string + { + $parts = []; + + foreach ($regexes as $regex) { + // Very common case: regex is given like "/pattern/flags" + // Parse: delimiter + pattern + delimiter + flags + if (! preg_match('~^(.)(.*)\\1([a-zA-Z]*)$~s', $regex, $m)) { + throw new InvalidArgumentException('Invalid regex: ' . $regex); + } + + $pattern = $m[2]; + $flags = $m[3]; + + // If you truly have mixed flags per-regex, you can't naively merge them. + // Best practice: normalize flags beforehand (same for all). + // We'll ignore per-regex flags here and let the caller decide final flags. + $parts[] = '(?:' . $pattern . ')'; + } + + return $delimiter . '(?:' . implode('|', $parts) . ')' . $delimiter; + } } diff --git a/tests/ValueObject/PatternCollectionTest.php b/tests/ValueObject/PatternCollectionTest.php new file mode 100644 index 000000000..1b3ab5d6b --- /dev/null +++ b/tests/ValueObject/PatternCollectionTest.php @@ -0,0 +1,37 @@ +assertSame(['pattern1', 'pattern2'], $patternCollection->exactPatternStrings()); + } + + public function testRegexPatterns(): void + { + $patternCollection = new PatternCollection([ + new ExactPattern('pattern1', 'file1.php', 10, 'SomeClass', 'someMethod'), + new RegexPattern('#this is it#', 'file1.php', 10, 'SomeClass', 'someMethod'), + new RegexPattern('#here is more#', 'file1.php', 10, 'SomeClass', 'someMethod'), + ]); + + $this->assertSame('#(?:(?:this is it)|(?:here is more))#', $patternCollection->regexPatternString()); + + } +}