From a0c9d6d2b764160360ea18b82b296f05c9e9e553 Mon Sep 17 00:00:00 2001 From: Pierre PLAZANET Date: Mon, 25 Sep 2023 14:57:43 +0200 Subject: [PATCH] feat: allow to enable @PER* rulesets with ruleset builder (#204) --- .php-cs-fixer.dist.php | 1 + doc/rule-set-factory.md | 6 +- .../CS/Fixer/RuleSetFactorySpec.php | 48 +++-- src/PedroTroller/CS/Fixer/RuleSetFactory.php | 187 ++++++++---------- 4 files changed, 126 insertions(+), 116 deletions(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 001dda6..fdb4fa6 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -9,6 +9,7 @@ ->setRiskyAllowed(true) ->setRules( RuleSetFactory::create() + ->per(2, true) ->phpCsFixer(true) ->php(8.0, true) ->pedrotroller(true) diff --git a/doc/rule-set-factory.md b/doc/rule-set-factory.md index a132bc0..a8787b2 100644 --- a/doc/rule-set-factory.md +++ b/doc/rule-set-factory.md @@ -11,7 +11,7 @@ return PhpCsFixer\Config::create() ->setRules(RuleSetFactory::create() ->symfony() // Activate the @Symfony ruleset ->phpCsFixer() // Activate the @PhpCsFixer ruleset - ->php(5.6, true) // Activate php 5.6 risky rules + ->php(8.2, true) // Activate php 8.2 risky rules ->pedrotroller(true) // Activate my own ruleset (with risky rules) ->enable('ordered_imports') // Add an other rule ->disable('yoda_style') // Disable a rule @@ -26,6 +26,10 @@ return PhpCsFixer\Config::create() ## Methods +### `->per([int|float $version = null, [bool $risky = false]])` + +Activate the `@PER` (`@PER-CS1.0`, `@PER-CS1.0:risky`, `@PER-CS2.0`, `@PER-CS2.0:risky`, ...) rule. + ### `->psr0()` Activate the `@psr0` rule. diff --git a/spec/PedroTroller/CS/Fixer/RuleSetFactorySpec.php b/spec/PedroTroller/CS/Fixer/RuleSetFactorySpec.php index 7dfedb2..5d1c0bc 100644 --- a/spec/PedroTroller/CS/Fixer/RuleSetFactorySpec.php +++ b/spec/PedroTroller/CS/Fixer/RuleSetFactorySpec.php @@ -10,11 +10,46 @@ final class RuleSetFactorySpec extends ObjectBehavior { + function let() + { + $this->beConstructedThrough('create'); + } + function it_is_initializable() { $this->shouldHaveType(RuleSetFactory::class); } + function it_adds_a_per_set() + { + $this->per()->getRules()->shouldReturn(['@PER' => true]); + } + + function it_adds_a_per_risky_set() + { + $this->per(risky: true)->getRules()->shouldReturn(['@PER:risky' => true]); + } + + function it_adds_a_per1_0_set() + { + $this->per(1)->getRules()->shouldReturn(['@PER-CS1.0' => true]); + } + + function it_adds_a_per1_0_risky_set() + { + $this->per(1, true)->getRules()->shouldReturn(['@PER-CS1.0:risky' => true]); + } + + function it_adds_a_per2_0_set() + { + $this->per(2)->getRules()->shouldReturn(['@PER-CS2.0' => true]); + } + + function it_adds_a_per2_0_risky_set() + { + $this->per(2, true)->getRules()->shouldReturn(['@PER-CS2.0:risky' => true]); + } + function it_adds_a_psr0_set() { $this->psr0()->getRules()->shouldReturn(['@psr0' => true]); @@ -144,15 +179,6 @@ function it_adds_a_php_version_support() ]); } - function it_can_also_parse_versions_as_string() - { - $this->php('5.6.2')->getRules()->shouldReturn([ - '@PHP54Migration' => true, - 'array_syntax' => ['syntax' => 'short'], - 'list_syntax' => ['syntax' => 'long'], - ]); - } - function it_adds_a_phpunit_version_support() { $this->phpUnit(2.0, false)->getRules()->shouldReturn([]); @@ -310,8 +336,6 @@ function it_adds_my_own_fixer_set() $rules[$fixer->getName()] = true; } - ksort($rules); - $this->pedrotroller(true)->getRules()->shouldReturn($rules); } @@ -327,8 +351,6 @@ function it_adds_my_own_fixer_set_except_privates() $rules[$fixer->getName()] = true; } - ksort($rules); - $this->pedrotroller(false)->getRules()->shouldReturn($rules); } diff --git a/src/PedroTroller/CS/Fixer/RuleSetFactory.php b/src/PedroTroller/CS/Fixer/RuleSetFactory.php index 1145cc9..6e75b76 100644 --- a/src/PedroTroller/CS/Fixer/RuleSetFactory.php +++ b/src/PedroTroller/CS/Fixer/RuleSetFactory.php @@ -4,44 +4,85 @@ namespace PedroTroller\CS\Fixer; +use Exception; +use IteratorAggregate; use PhpCsFixer\RuleSet\RuleSets; +use Traversable; -final class RuleSetFactory +/** + * @IteratorAggregate> + */ +final class RuleSetFactory implements IteratorAggregate { /** - * @var array[] + * @var array|bool> */ private $rules; - public function __construct(array $rules = []) + /** + * @var array + */ + private array $cache; + + /** + * @param array|bool> $rules + * @param array $cache + */ + private function __construct(array $rules, array $cache) { $this->rules = $rules; + $this->cache = $cache; } /** - * @return array + * @return array|bool> */ - public function getRules() + public function getRules(): array { - $rules = $this->rules; + return $this->rules; + } - ksort($rules); + public function getIterator(): Traversable + { + yield from $this->rules; + } - return $rules; + public static function create(array $rules = []): self + { + return new self( + $rules, + (new RuleSets())->getSetDefinitionNames(), + ); } - /** - * @return RuleSetFactory - */ - public static function create(array $rules = []) + public function per(int|float $version = null, bool $risky = false): self { - return new self($rules); + $candidates = null !== $version + ? ['@PER-CS'.number_format($version, 1, '.', '')] + : ['@PER']; + + if (true === $risky) { + $candidates = [ + $candidates[0].':risky', + ...$candidates, + ]; + } + + foreach ($candidates as $candidate) { + if (false === \in_array($candidate, $this->cache, true)) { + continue; + } + + return self::create(array_merge( + $this->rules, + [$candidate => true], + )); + } + + throw new Exception('RuleSet not found: '.implode(', ', $candidates)); } - /** - * @return RuleSetFactory - */ - public function psr0() + public function psr0(): self { return self::create(array_merge( $this->rules, @@ -49,10 +90,7 @@ public function psr0() )); } - /** - * @return RuleSetFactory - */ - public function psr1() + public function psr1(): self { return self::create(array_merge( $this->rules, @@ -60,10 +98,7 @@ public function psr1() )); } - /** - * @return RuleSetFactory - */ - public function psr2() + public function psr2(): self { return self::create(array_merge( $this->rules, @@ -71,10 +106,7 @@ public function psr2() )); } - /** - * @return RuleSetFactory - */ - public function psr4() + public function psr4(): self { return self::create(array_merge( $this->rules, @@ -82,12 +114,7 @@ public function psr4() )); } - /** - * @param bool $risky - * - * @return RuleSetFactory - */ - public function symfony($risky = false) + public function symfony(bool $risky = false): self { $rules = ['@Symfony' => true]; @@ -101,12 +128,7 @@ public function symfony($risky = false) )); } - /** - * @param bool $risky - * - * @return RuleSetFactory - */ - public function phpCsFixer($risky = false) + public function phpCsFixer(bool $risky = false): self { $rules = ['@PhpCsFixer' => true]; @@ -120,10 +142,7 @@ public function phpCsFixer($risky = false) )); } - /** - * @return RuleSetFactory - */ - public function doctrineAnnotation() + public function doctrineAnnotation(): self { return self::create(array_merge( $this->rules, @@ -131,27 +150,20 @@ public function doctrineAnnotation() )); } - /** - * @param float|string $version - * @param bool $risky - * - * @return RuleSetFactory - */ - public function php($version, $risky = false) + public function php(float $version, bool $risky = false): self { $config = $this->migration('php', $version, $risky)->getRules(); - switch (true) { - case $version >= 7.1: - $config = array_merge(['list_syntax' => ['syntax' => 'short']], $config); + $config['array_syntax'] = ['syntax' => 'long']; + $config['list_syntax'] = ['syntax' => 'long']; - // no break - case $version >= 5.4: - $config = array_merge(['array_syntax' => ['syntax' => 'short']], $config); + if ($version >= 7.1) { + $config['list_syntax'] = ['syntax' => 'short']; } - $config = array_merge(['list_syntax' => ['syntax' => 'long']], $config); - $config = array_merge(['array_syntax' => ['syntax' => 'long']], $config); + if ($version >= 5.4) { + $config['array_syntax'] = ['syntax' => 'short']; + } return self::create(array_merge( $this->rules, @@ -159,23 +171,12 @@ public function php($version, $risky = false) )); } - /** - * @param float $version - * @param bool $risky - * - * @return RuleSetFactory - */ - public function phpUnit($version, $risky = false) + public function phpUnit(float $version, bool $risky = false): self { return $this->migration('phpunit', $version, $risky); } - /** - * @param bool $risky - * - * @return RuleSetFactory - */ - public function pedrotroller($risky = false) + public function pedrotroller(bool $risky = false): self { $rules = []; @@ -191,20 +192,13 @@ public function pedrotroller($risky = false) $rules[$fixer->getName()] = true; } - ksort($rules); - return self::create(array_merge( $this->rules, $rules )); } - /** - * @param string $name - * - * @return RuleSetFactory - */ - public function enable($name, array $config = null) + public function enable(string $name, array $config = null): self { return self::create(array_merge( $this->rules, @@ -212,12 +206,7 @@ public function enable($name, array $config = null) )); } - /** - * @param string $name - * - * @return RuleSetFactory - */ - public function disable($name) + public function disable(string $name): self { return self::create(array_merge( $this->rules, @@ -225,23 +214,17 @@ public function disable($name) )); } - /** - * @param string $package - * @param float $version - * @param bool $risky - * - * @return RuleSetFactory - */ - private function migration($package, $version, $risky) + private function migration(string $package, float $version, bool $risky): self { - $rules = (new RuleSets())->getSetDefinitionNames(); - $rules = array_combine($rules, $rules); - - $rules = array_map(static function ($name) { - preg_match('/^@([A-Za-z]+)(\d+)Migration(:risky|)$/', $name, $matches); + $rules = array_combine($this->cache, $this->cache); + $rules = array_map( + static function ($name) { + preg_match('/^@([A-Za-z]+)(\d+)Migration(:risky|)$/', $name, $matches); - return $matches; - }, $rules); + return $matches; + }, + $rules + ); $rules = array_filter($rules);