diff --git a/.dev-tools/src/Readme/ReadmeCommand.php b/.dev-tools/src/Readme/ReadmeCommand.php index 0b241217..4d061f98 100644 --- a/.dev-tools/src/Readme/ReadmeCommand.php +++ b/.dev-tools/src/Readme/ReadmeCommand.php @@ -221,7 +221,7 @@ private function fixers(): string "\n- `%s` (`%s`): %s; defaults to `%s`", $option->getName(), \implode('`, `', $allowed), - $option->getDescription(), + \lcfirst(\rtrim($option->getDescription(), '.')), Utils::toString($option->getDefault()), ); } diff --git a/CHANGELOG.md b/CHANGELOG.md index 36ffcd30..cfa7db42 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # CHANGELOG for PHP CS Fixer: custom fixers +## v3.28.0 +- Deprecate MultilinePromotedPropertiesFixer - use "multiline_promoted_properties" +- Update minimum PHP CS Fixer version to 3.76.1 + ## v3.27.0 - Add PhpdocTagNoNamedArgumentsFixer diff --git a/README.md b/README.md index 639752a9..d084d14b 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Latest stable version](https://img.shields.io/packagist/v/kubawerlos/php-cs-fixer-custom-fixers.svg?label=current%20version)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net) [![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE) -![Tests](https://img.shields.io/badge/tests-3796-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3798-brightgreen.svg) [![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers) [![CI status](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/actions/workflows/ci.yaml/badge.svg)](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/actions/workflows/ci.yaml) @@ -210,11 +210,13 @@ Multiline comments or PHPDocs must contain an opening and closing line with no a #### MultilinePromotedPropertiesFixer Promoted properties must be on separate lines. + DEPRECATED: use `multiline_promoted_properties` instead. Configuration options: - `keep_blank_lines` (`bool`): whether to keep blank lines between properties; defaults to `false` - `minimum_number_of_parameters` (`int`): minimum number of parameters in the constructor to fix; defaults to `1` ```diff - * * @phpstan-type _InputConfig array{keep_blank_lines?: bool, minimum_number_of_parameters?: int} @@ -34,41 +30,23 @@ * * @no-named-arguments */ -final class MultilinePromotedPropertiesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface +final class MultilinePromotedPropertiesFixer extends AbstractFixer implements ConfigurableFixerInterface, DeprecatedFixerInterface, WhitespacesAwareFixerInterface { - private int $minimumNumberOfParameters = 1; - private bool $keepBlankLines = false; - private WhitespacesFixerConfig $whitespacesConfig; + private PhpCsFixerMultilinePromotedPropertiesFixer $multilinePromotedPropertiesFixer; + + public function __construct() + { + $this->multilinePromotedPropertiesFixer = new PhpCsFixerMultilinePromotedPropertiesFixer(); + } public function getDefinition(): FixerDefinitionInterface { - return new FixerDefinition( - 'Promoted properties must be on separate lines.', - [ - new VersionSpecificCodeSample( - 'multilinePromotedPropertiesFixer->getDefinition(); } public function getConfigurationDefinition(): FixerConfigurationResolverInterface { - return new FixerConfigurationResolver([ - (new FixerOptionBuilder('keep_blank_lines', 'whether to keep blank lines between properties')) - ->setAllowedTypes(['bool']) - ->setDefault($this->keepBlankLines) - ->getOption(), - (new FixerOptionBuilder('minimum_number_of_parameters', 'minimum number of parameters in the constructor to fix')) - ->setAllowedTypes(['int']) - ->setDefault($this->minimumNumberOfParameters) - ->getOption(), - ]); + return $this->multilinePromotedPropertiesFixer->getConfigurationDefinition(); } /** @@ -76,17 +54,12 @@ public function getConfigurationDefinition(): FixerConfigurationResolverInterfac */ public function configure(array $configuration): void { - if (\array_key_exists('minimum_number_of_parameters', $configuration)) { - $this->minimumNumberOfParameters = $configuration['minimum_number_of_parameters']; - } - if (\array_key_exists('keep_blank_lines', $configuration)) { - $this->keepBlankLines = $configuration['keep_blank_lines']; - } + $this->multilinePromotedPropertiesFixer->configure($configuration); } public function setWhitespacesConfig(WhitespacesFixerConfig $config): void { - $this->whitespacesConfig = $config; + $this->multilinePromotedPropertiesFixer->setWhitespacesConfig($config); } /** @@ -95,112 +68,29 @@ public function setWhitespacesConfig(WhitespacesFixerConfig $config): void */ public function getPriority(): int { - return 0; + return $this->multilinePromotedPropertiesFixer->getPriority(); } public function isCandidate(Tokens $tokens): bool { - return $tokens->isAnyTokenKindsFound([ - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, - ]); + return $this->multilinePromotedPropertiesFixer->isCandidate($tokens); } public function isRisky(): bool { - return false; + return $this->multilinePromotedPropertiesFixer->isRisky(); } public function fix(\SplFileInfo $file, Tokens $tokens): void { - $constructorAnalyzer = new ConstructorAnalyzer(); - - for ($index = $tokens->count() - 1; $index > 0; $index--) { - if (!$tokens[$index]->isGivenKind(\T_CLASS)) { - continue; - } - - $constructorAnalysis = $constructorAnalyzer->findNonAbstractConstructor($tokens, $index); - if ($constructorAnalysis === null) { - continue; - } - - $openParenthesis = $tokens->getNextTokenOfKind($constructorAnalysis->getConstructorIndex(), ['(']); - \assert(\is_int($openParenthesis)); - $closeParenthesis = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openParenthesis); - - if (!$this->shouldBeFixed($tokens, $openParenthesis, $closeParenthesis)) { - continue; - } - - $this->fixParameters($tokens, $openParenthesis, $closeParenthesis); - } - } - - private function shouldBeFixed(Tokens $tokens, int $openParenthesis, int $closeParenthesis): bool - { - $promotedParameterFound = false; - $minimumNumberOfParameters = 0; - for ($index = $openParenthesis + 1; $index < $closeParenthesis; $index++) { - if ($tokens[$index]->isGivenKind(\T_VARIABLE)) { - $minimumNumberOfParameters++; - } - if ( - $tokens[$index]->isGivenKind([ - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PRIVATE, - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PROTECTED, - CT::T_CONSTRUCTOR_PROPERTY_PROMOTION_PUBLIC, - ]) - ) { - $promotedParameterFound = true; - } - } - - return $promotedParameterFound && $minimumNumberOfParameters >= $this->minimumNumberOfParameters; + $this->multilinePromotedPropertiesFixer->fix($file, $tokens); } - private function fixParameters(Tokens $tokens, int $openParenthesis, int $closeParenthesis): void - { - $indent = WhitespacesAnalyzer::detectIndent($tokens, $openParenthesis); - - $tokens->ensureWhitespaceAtIndex( - $closeParenthesis - 1, - 1, - $this->whitespacesConfig->getLineEnding() . $indent, - ); - - $index = $tokens->getPrevMeaningfulToken($closeParenthesis); - \assert(\is_int($index)); - - while ($index > $openParenthesis) { - $index = $tokens->getPrevMeaningfulToken($index); - \assert(\is_int($index)); - - $blockType = Tokens::detectBlockType($tokens[$index]); - if ($blockType !== null && !$blockType['isStart']) { - $index = $tokens->findBlockStart($blockType['type'], $index); - continue; - } - - if (!$tokens[$index]->equalsAny(['(', ','])) { - continue; - } - - $this->fixParameter($tokens, $index + 1, $indent); - } - } - - private function fixParameter(Tokens $tokens, int $index, string $indent): void + /** + * @return list + */ + public function getSuccessorsNames(): array { - if ($this->keepBlankLines && $tokens[$index]->isWhitespace() && \str_contains($tokens[$index]->getContent(), "\n")) { - return; - } - - $tokens->ensureWhitespaceAtIndex( - $index, - 0, - $this->whitespacesConfig->getLineEnding() . $indent . $this->whitespacesConfig->getIndent(), - ); + return [$this->multilinePromotedPropertiesFixer->getName()]; } } diff --git a/tests/Fixer/MultilinePromotedPropertiesFixerTest.php b/tests/Fixer/MultilinePromotedPropertiesFixerTest.php index d7ff62be..443651fd 100644 --- a/tests/Fixer/MultilinePromotedPropertiesFixerTest.php +++ b/tests/Fixer/MultilinePromotedPropertiesFixerTest.php @@ -11,6 +11,8 @@ namespace Tests\Fixer; +use PhpCsFixer\WhitespacesFixerConfig; + /** * @internal * @@ -20,6 +22,11 @@ */ final class MultilinePromotedPropertiesFixerTest extends AbstractFixerTestCase { + public function testSuccessorName(): void + { + self::assertSuccessorName('multiline_promoted_properties'); + } + public function testConfiguration(): void { $options = self::getConfigurationOptions(); @@ -40,13 +47,13 @@ public function testIsRisky(): void * * @dataProvider provideFixCases */ - public function testFix(string $expected, ?string $input = null, array $configuration = []): void + public function testFix(string $expected, ?string $input = null, array $configuration = [], ?WhitespacesFixerConfig $whitespacesFixerConfig = null): void { - $this->doTest($expected, $input, $configuration); + $this->doTest($expected, $input, $configuration, $whitespacesFixerConfig); } /** - * @return iterable}> + * @return iterable, 3?: WhitespacesFixerConfig}> */ public static function provideFixCases(): iterable { @@ -252,5 +259,18 @@ public function __construct( }', ['keep_blank_lines' => true], ]; + + yield '2 spaces intent and windows line endings' => [ + \str_replace("\n", "\r\n", '