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/bin/Utils.php b/bin/Utils.php index 871d946..913820e 100644 --- a/bin/Utils.php +++ b/bin/Utils.php @@ -15,7 +15,7 @@ public static function arrayToString(array $array = null) if (array_values($array) === $array) { $string .= implode(', ', array_map([self::class, 'valueToString'], $array)); } else { - $string .= implode(', ', array_map(fn ($value, $key) => '\''.$key.'\' => '.self::valueToString($value), $array, array_keys($array))); + $string .= implode(', ', array_map(static fn ($value, $key) => '\''.$key.'\' => '.self::valueToString($value), $array, array_keys($array))); } $string .= ' ]'; diff --git a/bin/doc b/bin/doc index 2a9eb34..09dd9df 100755 --- a/bin/doc +++ b/bin/doc @@ -14,7 +14,7 @@ include sprintf('%s/../vendor/autoload.php', __DIR__); include 'Utils.php'; -$fixers = array_map(function (AbstractFixer $fixer) { +$fixers = array_map(static function (AbstractFixer $fixer) { $samples = $fixer->getDefinition()->getCodeSamples(); return [ @@ -25,7 +25,7 @@ $fixers = array_map(function (AbstractFixer $fixer) { 'deprecated' => $fixer->isDeprecated(), 'replacement' => $fixer->getDeprecationReplacement(), 'options' => array_map( - function (FixerOptionInterface $option) { + static function (FixerOptionInterface $option) { return [ 'name' => $option->getName(), 'description' => $option->getDescription(), @@ -39,7 +39,7 @@ $fixers = array_map(function (AbstractFixer $fixer) { ? $fixer->getConfigurationDefinition()->getOptions() : [] ), - 'samples' => array_map(function (CodeSample $sample) use ($fixer) { + 'samples' => array_map(static function (CodeSample $sample) use ($fixer) { if ($fixer instanceof ConfigurableFixerInterface) { $fixer->configure($sample->getConfiguration()); } @@ -57,13 +57,13 @@ $fixers = array_map(function (AbstractFixer $fixer) { } while (strlen($line) < 80 + 1) { - $line = $line.' '; + $line .= ' '; } if (0 === $num) { - $line = $line.'// 80 chars'; + $line .= '// 80 chars'; } else { - $line = $line.'//'; + $line .= '//'; } $diff[$num] = $line; diff --git a/composer.json b/composer.json index af442f9..6815fc0 100644 --- a/composer.json +++ b/composer.json @@ -6,7 +6,7 @@ "php": "^8.0" }, "require-dev": { - "friendsofphp/php-cs-fixer": "^3.17", + "friendsofphp/php-cs-fixer": "^3.28", "phpspec/phpspec": "^7.0", "sebastian/diff": "^4.0", "twig/twig": "^3.3", 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/ClassNotation/OrderedWithGetterAndSetterFirstFixer.php b/src/PedroTroller/CS/Fixer/ClassNotation/OrderedWithGetterAndSetterFirstFixer.php index 487f44e..10552ea 100644 --- a/src/PedroTroller/CS/Fixer/ClassNotation/OrderedWithGetterAndSetterFirstFixer.php +++ b/src/PedroTroller/CS/Fixer/ClassNotation/OrderedWithGetterAndSetterFirstFixer.php @@ -164,8 +164,8 @@ private function getMethodsNames(array $elements): array private function getPropertiesNames(array $elements): array { - $properties = array_filter($elements, fn ($element) => 'property' === $element['type']); + $properties = array_filter($elements, static fn ($element) => 'property' === $element['type']); - return array_map(fn ($element) => ltrim($element['propertyName'], '$'), $properties); + return array_map(static fn ($element) => ltrim($element['propertyName'], '$'), $properties); } } diff --git a/src/PedroTroller/CS/Fixer/CodingStyle/LineBreakBetweenMethodArgumentsFixer.php b/src/PedroTroller/CS/Fixer/CodingStyle/LineBreakBetweenMethodArgumentsFixer.php index 3c7115a..a50ded6 100644 --- a/src/PedroTroller/CS/Fixer/CodingStyle/LineBreakBetweenMethodArgumentsFixer.php +++ b/src/PedroTroller/CS/Fixer/CodingStyle/LineBreakBetweenMethodArgumentsFixer.php @@ -7,7 +7,9 @@ use PedroTroller\CS\Fixer\AbstractFixer; use PedroTroller\CS\Fixer\Priority; use PhpCsFixer\Fixer\Basic\BracesFixer; +use PhpCsFixer\Fixer\Basic\SingleLineEmptyBodyFixer; use PhpCsFixer\Fixer\ConfigurableFixerInterface; +use PhpCsFixer\Fixer\FunctionNotation\MethodArgumentSpaceFixer; use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver; use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface; @@ -22,7 +24,11 @@ final class LineBreakBetweenMethodArgumentsFixer extends AbstractFixer implement public function getPriority(): int { - return Priority::after(BracesFixer::class); + return min( + Priority::after(BracesFixer::class), + Priority::after(MethodArgumentSpaceFixer::class), + Priority::after(SingleLineEmptyBodyFixer::class), + ); } public function getSampleConfigurations(): array diff --git a/src/PedroTroller/CS/Fixer/Comment/CommentLineToPhpdocBlockFixer.php b/src/PedroTroller/CS/Fixer/Comment/CommentLineToPhpdocBlockFixer.php index 8407552..5e0cf3a 100644 --- a/src/PedroTroller/CS/Fixer/Comment/CommentLineToPhpdocBlockFixer.php +++ b/src/PedroTroller/CS/Fixer/Comment/CommentLineToPhpdocBlockFixer.php @@ -148,7 +148,7 @@ private function formatComments(array $comments, string $indentation): string array_pop($comments); } - $comments = array_map(fn ($comment) => rtrim($indentation.' * '.ltrim($comment, ' /')), $comments); + $comments = array_map(static fn ($comment) => rtrim($indentation.' * '.ltrim($comment, ' /')), $comments); $comments = implode("\n", $comments); $comments = trim($comments, " \n"); diff --git a/src/PedroTroller/CS/Fixer/DeadCode/UselessCodeAfterReturnFixer.php b/src/PedroTroller/CS/Fixer/DeadCode/UselessCodeAfterReturnFixer.php index d68461f..4b6d20a 100644 --- a/src/PedroTroller/CS/Fixer/DeadCode/UselessCodeAfterReturnFixer.php +++ b/src/PedroTroller/CS/Fixer/DeadCode/UselessCodeAfterReturnFixer.php @@ -83,7 +83,7 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void $possible = array_merge($possible, array_keys($ends)); } - $possible = array_filter($possible, fn ($value) => null !== $value); + $possible = array_filter($possible, static fn ($value) => null !== $value); if (empty($possible)) { continue; diff --git a/src/PedroTroller/CS/Fixer/Fixers.php b/src/PedroTroller/CS/Fixer/Fixers.php index 3f16380..aeac81f 100644 --- a/src/PedroTroller/CS/Fixer/Fixers.php +++ b/src/PedroTroller/CS/Fixer/Fixers.php @@ -23,7 +23,7 @@ public function getIterator(): Generator ; $files = array_map( - fn ($file) => $file->getPathname(), + static fn ($file) => $file->getPathname(), iterator_to_array($finder) ); diff --git a/src/PedroTroller/CS/Fixer/Priority.php b/src/PedroTroller/CS/Fixer/Priority.php index 6d6d5ae..005fe98 100644 --- a/src/PedroTroller/CS/Fixer/Priority.php +++ b/src/PedroTroller/CS/Fixer/Priority.php @@ -6,9 +6,7 @@ final class Priority { - private function __construct() - { - } + private function __construct() {} /** * @param array $classes @@ -18,7 +16,7 @@ private function __construct() public static function before(...$classes) { $priorities = array_map( - fn ($class) => (new $class())->getPriority(), + static fn ($class) => (new $class())->getPriority(), $classes ); @@ -33,7 +31,7 @@ public static function before(...$classes) public static function after(...$classes) { $priorities = array_map( - fn ($class) => (new $class())->getPriority(), + static fn ($class) => (new $class())->getPriority(), $classes ); diff --git a/src/PedroTroller/CS/Fixer/RuleSetFactory.php b/src/PedroTroller/CS/Fixer/RuleSetFactory.php index 66b5f52..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,39 +214,33 @@ 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(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); - $rules = array_filter($rules, function ($versionAndRisky) use ($package) { + $rules = array_filter($rules, static function ($versionAndRisky) use ($package) { [$rule, $rulePackage, $ruleVersion, $ruleRisky] = $versionAndRisky; return strtoupper($package) === strtoupper($rulePackage); }); - $rules = array_filter($rules, function ($versionAndRisky) use ($version) { + $rules = array_filter($rules, static function ($versionAndRisky) use ($version) { [$rule, $rulePackage, $ruleVersion, $ruleRisky] = $versionAndRisky; return ((float) $ruleVersion / 10) <= $version; }); - $rules = array_filter($rules, function ($versionAndRisky) use ($risky) { + $rules = array_filter($rules, static function ($versionAndRisky) use ($risky) { [$rule, $rulePackage, $ruleVersion, $ruleRisky] = $versionAndRisky; if ($risky) { @@ -269,7 +252,7 @@ private function migration($package, $version, $risky) return self::create(array_merge( $this->rules, - array_map(fn () => true, $rules) + array_map(static fn () => true, $rules) )); } } diff --git a/src/PedroTroller/CS/Fixer/TokenSignatures.php b/src/PedroTroller/CS/Fixer/TokenSignatures.php index 06ad2b6..3e535d2 100644 --- a/src/PedroTroller/CS/Fixer/TokenSignatures.php +++ b/src/PedroTroller/CS/Fixer/TokenSignatures.php @@ -9,7 +9,5 @@ final class TokenSignatures public const TYPINT_OPTIONAL = 10022; public const TYPINT_DOUBLE_DOTS = 10025; - public function __construct() - { - } + public function __construct() {} } diff --git a/tests/Orchestra.php b/tests/Orchestra.php index 0501f4a..568fb62 100644 --- a/tests/Orchestra.php +++ b/tests/Orchestra.php @@ -5,10 +5,14 @@ namespace tests; use PedroTroller\CS\Fixer\ClassNotation\OrderedWithGetterAndSetterFirstFixer; +use PedroTroller\CS\Fixer\CodingStyle\LineBreakBetweenMethodArgumentsFixer; use PedroTroller\CS\Fixer\DoctrineMigrationsFixer; +use PhpCsFixer\Fixer\Basic\BracesFixer; +use PhpCsFixer\Fixer\Basic\SingleLineEmptyBodyFixer; use PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer; use PhpCsFixer\Fixer\ClassNotation\OrderedClassElementsFixer; use PhpCsFixer\Fixer\FixerInterface; +use PhpCsFixer\Fixer\FunctionNotation\MethodArgumentSpaceFixer; use PhpCsFixer\Fixer\Import\SingleLineAfterImportsFixer; use PhpCsFixer\Fixer\Phpdoc\NoEmptyPhpdocFixer; use PhpCsFixer\Fixer\Whitespace\NoExtraBlankLinesFixer; @@ -41,6 +45,12 @@ public static function run(): void ->before(new NoWhitespaceInBlankLineFixer()) ; + self::assert(new LineBreakBetweenMethodArgumentsFixer()) + ->after(new BracesFixer()) + ->after(new MethodArgumentSpaceFixer()) + ->after(new SingleLineEmptyBodyFixer()) + ; + echo "\n"; } diff --git a/tests/Runner.php b/tests/Runner.php index 66f70ff..e8da806 100644 --- a/tests/Runner.php +++ b/tests/Runner.php @@ -18,7 +18,7 @@ public static function run(): void $deprecations = []; set_error_handler( - function ($type, $message, $file, $line) use (&$deprecations): void { + static function ($type, $message, $file, $line) use (&$deprecations): void { $deprecations[$message][] = sprintf('%s at line %d', $file, $line); $deprecations[$message] = array_unique($deprecations[$message]); @@ -40,7 +40,7 @@ function ($type, $message, $file, $line) use (&$deprecations): void { implode( "\n\n", array_map( - fn ($message, array $files) => sprintf("%s\n%s", $message, implode("\n", $files)), + static fn ($message, array $files) => sprintf("%s\n%s", $message, implode("\n", $files)), array_keys($deprecations), $deprecations ) diff --git a/tests/TokensAnalyzerIntegration/MethodArguments.php b/tests/TokensAnalyzerIntegration/MethodArguments.php index d379637..c307cbe 100644 --- a/tests/TokensAnalyzerIntegration/MethodArguments.php +++ b/tests/TokensAnalyzerIntegration/MethodArguments.php @@ -49,7 +49,7 @@ public function assertions(TokensAnalyzer $analyzer, Tokens $tokens): void { $methods = array_filter( $analyzer->getClassyElements(), - fn ($element) => 'method' === $element['type'] + static fn ($element) => 'method' === $element['type'] ); Assert::count($methods, 3);