Skip to content

Commit bd749fb

Browse files
authored
Merge pull request #71 from yoeunes/dev
Enhances regex parsing and analysis
2 parents 674f40c + 39eb968 commit bd749fb

File tree

195 files changed

+508
-294
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

195 files changed

+508
-294
lines changed

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
"ext-mbstring": "*"
1515
},
1616
"require-dev": {
17-
"phpunit/phpunit": "^12.4.5",
18-
"phpstan/phpstan": "^2.1.32",
19-
"phpstan/phpstan-phpunit": "^2.0.8",
17+
"phpunit/phpunit": "^12.5.0",
18+
"phpstan/phpstan": "^2.1.33",
19+
"phpstan/phpstan-phpunit": "^2.0.9",
2020
"symfony/console": "^8.0",
2121
"symfony/http-kernel": "^8.0",
2222
"symfony/dependency-injection": "^8.0",

rector/Rule/PHPUnit/PreferStaticPHPUnitAssertRector.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
/**
2626
* Converts PHPUnit assertions from $this->assert*() and static::assert*() to explicit Assert::assert*() static calls.
2727
*/
28-
class PreferStaticPHPUnitAssertRector extends AbstractRector
28+
final class PreferStaticPHPUnitAssertRector extends AbstractRector
2929
{
3030
public function __construct(private AssertMethodAnalyzer $assertMethodAnalyzer) {}
3131

src/Bridge/PHPStan/PregValidationRule.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@
3636
*
3737
* @implements Rule<FuncCall>
3838
*/
39-
class PregValidationRule implements Rule
39+
final class PregValidationRule implements Rule
4040
{
4141
// Identifiers for user configuration in phpstan.neon
42-
public const IDENTIFIER_SYNTAX_INVALID = 'regex.syntax.invalid';
43-
public const IDENTIFIER_SYNTAX_DELIMITER = 'regex.syntax.delimiter';
44-
public const IDENTIFIER_SYNTAX_EMPTY = 'regex.syntax.empty';
45-
public const IDENTIFIER_REDOS_CRITICAL = 'regex.redos.critical';
46-
public const IDENTIFIER_REDOS_HIGH = 'regex.redos.high';
47-
public const IDENTIFIER_REDOS_MEDIUM = 'regex.redos.medium';
48-
public const IDENTIFIER_REDOS_LOW = 'regex.redos.low';
42+
public const string IDENTIFIER_SYNTAX_INVALID = 'regex.syntax.invalid';
43+
public const string IDENTIFIER_SYNTAX_DELIMITER = 'regex.syntax.delimiter';
44+
public const string IDENTIFIER_SYNTAX_EMPTY = 'regex.syntax.empty';
45+
public const string IDENTIFIER_REDOS_CRITICAL = 'regex.redos.critical';
46+
public const string IDENTIFIER_REDOS_HIGH = 'regex.redos.high';
47+
public const string IDENTIFIER_REDOS_MEDIUM = 'regex.redos.medium';
48+
public const string IDENTIFIER_REDOS_LOW = 'regex.redos.low';
4949

5050
private const array PREG_FUNCTION_MAP = [
5151
'preg_match' => 0,

src/Bridge/Rector/RegexOptimizationRector.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
* This rule parses the regex string, applies AST optimizations (like flattening groups
3232
* or merging character classes), and recompiles it back to a cleaner string.
3333
*/
34-
class RegexOptimizationRector extends AbstractRector implements ConfigurableRectorInterface
34+
final class RegexOptimizationRector extends AbstractRector implements ConfigurableRectorInterface
3535
{
3636
public const string EXTRA_FUNCTIONS = 'extra_functions';
3737

src/Bridge/Symfony/DependencyInjection/Configuration.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
*
2929
* @see https://symfony.com/doc/current/bundles/configuration.html
3030
*/
31-
class Configuration implements ConfigurationInterface
31+
final readonly class Configuration implements ConfigurationInterface
3232
{
3333
/**
3434
* Creates a new instance of the bundle's configuration schema.
@@ -41,7 +41,7 @@ class Configuration implements ConfigurationInterface
4141
* @param bool $debug The value of the `kernel.debug` parameter.
4242
*/
4343
public function __construct(
44-
private readonly bool $debug = false,
44+
private bool $debug = false,
4545
) {}
4646

4747
/**

src/Bridge/Symfony/DependencyInjection/RegexParserExtension.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
* 4. Conditionally loading debug-only services (like the Web Profiler collector)
3131
* based on the application's environment and configuration.
3232
*/
33-
class RegexParserExtension extends Extension
33+
final class RegexParserExtension extends Extension
3434
{
3535
/**
3636
* Loads the bundle's services and processes its configuration.

src/Bridge/Symfony/RegexParserBundle.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
* @see \RegexParser\Bridge\Symfony\DependencyInjection\RegexParserExtension
2828
* @see \RegexParser\Bridge\Symfony\DependencyInjection\Configuration
2929
*/
30-
class RegexParserBundle extends Bundle
30+
final class RegexParserBundle extends Bundle
3131
{
3232
/**
3333
* Overrides the default bundle path to correctly locate resources.

src/Cache/FilesystemCache.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
namespace RegexParser\Cache;
1515

16-
readonly class FilesystemCache implements RemovableCacheInterface
16+
final readonly class FilesystemCache implements RemovableCacheInterface
1717
{
1818
private string $directory;
1919

src/Cache/NullCache.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313

1414
namespace RegexParser\Cache;
1515

16-
readonly class NullCache implements RemovableCacheInterface
16+
final readonly class NullCache implements RemovableCacheInterface
1717
{
1818
#[\Override]
1919
public function generateKey(string $regex): string

src/Cache/PsrCacheAdapter.php

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,17 @@
1414
namespace RegexParser\Cache;
1515

1616
use Psr\Cache\CacheItemPoolInterface;
17+
use RegexParser\Node\RegexNode;
1718

1819
/**
1920
* PSR-6 bridge for AST caching.
2021
*
21-
* Uses the configured pool to store serialized AST payloads.
22+
* This adapter lets you plug a PSR-6 cache pool into the RegexParser cache
23+
* system. The Regex service passes a compiled cache payload string
24+
* (generated by {@see \RegexParser\Regex::compileCachePayload()}); this
25+
* adapter evaluates that payload once and stores the resulting RegexNode
26+
* instance directly in the pool so that subsequent reads are fast and
27+
* type-safe.
2228
*/
2329
final readonly class PsrCacheAdapter implements RemovableCacheInterface
2430
{
@@ -42,7 +48,10 @@ public function generateKey(string $regex): string
4248
public function write(string $key, string $content): void
4349
{
4450
$item = $this->pool->getItem($key);
45-
$item->set($content);
51+
52+
$value = $this->decodePayload($content);
53+
$item->set($value ?? $content);
54+
4655
$this->pool->save($item);
4756
}
4857

@@ -69,4 +78,31 @@ public function clear(?string $regex = null): void
6978

7079
$this->pool->clear();
7180
}
81+
82+
/**
83+
* Decodes the compiled cache payload string into a RegexNode instance.
84+
*
85+
* The Regex service passes a small PHP script generated by
86+
* {@see \RegexParser\Regex::compileCachePayload()}. For PSR-6 caches we
87+
* execute this script once and store the resulting AST object directly
88+
* in the pool so that subsequent reads return a RegexNode instead of
89+
* the raw payload string.
90+
*/
91+
private function decodePayload(string $content): ?RegexNode
92+
{
93+
$code = ltrim($content);
94+
95+
if (str_starts_with($code, '<?php')) {
96+
$code = substr($code, 5);
97+
}
98+
99+
try {
100+
$result = eval($code);
101+
102+
return $result instanceof RegexNode ? $result : null;
103+
} catch (\Throwable) {
104+
// If anything goes wrong we just fall back to storing the raw payload.
105+
return null;
106+
}
107+
}
72108
}

0 commit comments

Comments
 (0)