Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## v3.25.0
- Add ForeachUseValueFixer
- Add NoUselessWriteVisibilityFixer
- Add TrimKeyFixer
- ReadonlyPromotedPropertiesFixer - support asymmetric visibility

## v3.24.0
Expand Down
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
<?php
$array = [
- 'option 1 ' => '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).
Expand Down
96 changes: 96 additions & 0 deletions src/Fixer/TrimKeyFixer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
<?php declare(strict_types=1);

/*
* This file is part of PHP CS Fixer: custom fixers.
*
* (c) 2018 Kuba Werłos
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace PhpCsFixerCustomFixers\Fixer;

use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;

final class TrimKeyFixer extends AbstractFixer
{
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'A string array and yield keys must be trimmed and have no double spaces.',
[new CodeSample(<<<'PHP'
<?php
$array = [
'option 1 ' => '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]);
}
}
}
113 changes: 113 additions & 0 deletions tests/Fixer/TrimKeyFixerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?php declare(strict_types=1);

/*
* This file is part of PHP CS Fixer: custom fixers.
*
* (c) 2018 Kuba Werłos
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/

namespace Tests\Fixer;

/**
* @internal
*
* @covers \PhpCsFixerCustomFixers\Fixer\TrimKeyFixer
*/
final class TrimKeyFixerTest extends AbstractFixerTestCase
{
public function testIsRisky(): void
{
self::assertRiskiness(false);
}

/**
* @dataProvider provideFixCases
*/
public function testFix(string $expected, ?string $input = null): void
{
$this->doTest($expected, $input);
}

/**
* @return iterable<array{0: string, 1?: string}>
*/
public static function provideFixCases(): iterable
{
yield 'do not trim when with concatenation' => [
<<<'PHP'
<?php return [
'foo '. $a => 'v',
$b . ' foo' => 'v',
$c . ' foo ' . $d => 'v',
];
PHP,
];

yield 'trim array' => [
<<<'PHP'
<?php return [
'k1' => 'v ',
"k2" => "v",
'k3' => ' v',
"k4" => "v",
'k5' => 'v',
];
PHP,
<<<'PHP'
<?php return [
'k1 ' => 'v ',
"k2 " => "v",
' k3' => ' v',
" k4" => "v",
' k5 ' => 'v',
];
PHP,
];

yield 'trim generator' => [
<<<'PHP'
<?php function g() {
yield 'k1' => 'v';
yield 'k2' => 'v';
yield 'k3' => ' v ';
yield 'k4' => 'v';
yield 'k5' => 'v';
yield 'k6' => 'v';
}
PHP,
<<<'PHP'
<?php function g() {
yield 'k1 ' => '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'
<?php return [
'k1' => true,
0 => 0,
' ' => 1,
' ' => 2,
'k2' => false,
];
PHP,
<<<'PHP'
<?php return [
' k1 ' => true,
0 => 0,
' ' => 1,
' ' => 2,
' k2 ' => false,
];
PHP,
];
}
}