diff --git a/CHANGELOG.md b/CHANGELOG.md index deca8bce..cb802792 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## v3.25.0 - Add ForeachUseValueFixer - Add NoUselessWriteVisibilityFixer +- Add TrimKeyFixer - ReadonlyPromotedPropertiesFixer - support asymmetric visibility ## v3.24.0 diff --git a/README.md b/README.md index 08ce7ba8..ec461e0a 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-3666-brightgreen.svg) +![Tests](https://img.shields.io/badge/tests-3691-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) @@ -712,6 +712,18 @@ A class that implements the `__toString()` method must explicitly implement the } ``` +#### TrimKeyFixer +A string array and yield keys must be trimmed and have no double spaces. +```diff + 'v1', +- 'option 2 or 3' => 'v23', ++ 'option 1' => 'v1', ++ 'option 2 or 3' => 'v23', + ]; +``` + ## Contributing Request a feature or report a bug by creating an [issue](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues). diff --git a/src/Fixer/TrimKeyFixer.php b/src/Fixer/TrimKeyFixer.php new file mode 100644 index 00000000..f90a7c9e --- /dev/null +++ b/src/Fixer/TrimKeyFixer.php @@ -0,0 +1,96 @@ + 'v1', + 'option 2 or 3' => 'v23', + ]; + + PHP)], + ); + } + + public function getPriority(): int + { + return 0; + } + + public function isCandidate(Tokens $tokens): bool + { + return $tokens->isAnyTokenKindsFound([\T_CONSTANT_ENCAPSED_STRING]); + } + + public function isRisky(): bool + { + return false; + } + + public function fix(\SplFileInfo $file, Tokens $tokens): void + { + for ($index = $tokens->count() - 1; $index > 0; $index--) { + if (!$tokens[$index]->isGivenKind(\T_DOUBLE_ARROW)) { + continue; + } + + $indexToFix = $tokens->getPrevMeaningfulToken($index); + \assert(\is_int($indexToFix)); + + if (!$tokens[$indexToFix]->isGivenKind([\T_CONSTANT_ENCAPSED_STRING])) { + continue; + } + + $content = $tokens[$indexToFix]->getContent(); + $stringBorderQuote = $content[0]; + $innerContent = \substr($content, 1, -1); + + $newInnerContent = Preg::replace('/\\s{2,}/', ' ', $innerContent); + + $prevIndex = $tokens->getPrevMeaningfulToken($indexToFix); + if (!$tokens[$prevIndex]->equals('.')) { + $newInnerContent = \ltrim($newInnerContent); + } + + $nextIndex = $tokens->getNextMeaningfulToken($indexToFix); + if (!$tokens[$nextIndex]->equals('.')) { + $newInnerContent = \rtrim($newInnerContent); + } + + if ($newInnerContent === '') { + continue; + } + + $newContent = $stringBorderQuote . $newInnerContent . $stringBorderQuote; + + if ($content === $newContent) { + continue; + } + + $tokens[$indexToFix] = new Token([\T_CONSTANT_ENCAPSED_STRING, $newContent]); + } + } +} diff --git a/tests/Fixer/TrimKeyFixerTest.php b/tests/Fixer/TrimKeyFixerTest.php new file mode 100644 index 00000000..a16f10e5 --- /dev/null +++ b/tests/Fixer/TrimKeyFixerTest.php @@ -0,0 +1,113 @@ +doTest($expected, $input); + } + + /** + * @return iterable + */ + public static function provideFixCases(): iterable + { + yield 'do not trim when with concatenation' => [ + <<<'PHP' + 'v', + $b . ' foo' => 'v', + $c . ' foo ' . $d => 'v', + ]; + PHP, + ]; + + yield 'trim array' => [ + <<<'PHP' + 'v ', + "k2" => "v", + 'k3' => ' v', + "k4" => "v", + 'k5' => 'v', + ]; + PHP, + <<<'PHP' + 'v ', + "k2 " => "v", + ' k3' => ' v', + " k4" => "v", + ' k5 ' => 'v', + ]; + PHP, + ]; + + yield 'trim generator' => [ + <<<'PHP' + 'v'; + yield 'k2' => 'v'; + yield 'k3' => ' v '; + yield 'k4' => 'v'; + yield 'k5' => 'v'; + yield 'k6' => 'v'; + } + PHP, + <<<'PHP' + 'v'; + yield 'k2 ' => 'v'; + yield 'k3' => ' v '; + yield ' k4' => 'v'; + yield ' k5' => 'v'; + yield ' k6 ' => 'v'; + } + PHP, + ]; + yield 'trim strings having non-whitespace characters' => [ + <<<'PHP' + true, + 0 => 0, + ' ' => 1, + ' ' => 2, + 'k2' => false, + ]; + PHP, + <<<'PHP' + true, + 0 => 0, + ' ' => 1, + ' ' => 2, + ' k2 ' => false, + ]; + PHP, + ]; + } +}