Skip to content

Commit 2368ce6

Browse files
authored
Add TrimKeyFixer (#1021)
1 parent 284feac commit 2368ce6

File tree

4 files changed

+223
-1
lines changed

4 files changed

+223
-1
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
## v3.25.0
44
- Add ForeachUseValueFixer
55
- Add NoUselessWriteVisibilityFixer
6+
- Add TrimKeyFixer
67
- ReadonlyPromotedPropertiesFixer - support asymmetric visibility
78

89
## v3.24.0

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[![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)
66
[![PHP version](https://img.shields.io/packagist/php-v/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://php.net)
77
[![License](https://img.shields.io/github/license/kubawerlos/php-cs-fixer-custom-fixers.svg)](LICENSE)
8-
![Tests](https://img.shields.io/badge/tests-3666-brightgreen.svg)
8+
![Tests](https://img.shields.io/badge/tests-3691-brightgreen.svg)
99
[![Downloads](https://img.shields.io/packagist/dt/kubawerlos/php-cs-fixer-custom-fixers.svg)](https://packagist.org/packages/kubawerlos/php-cs-fixer-custom-fixers)
1010

1111
[![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
712712
}
713713
```
714714

715+
#### TrimKeyFixer
716+
A string array and yield keys must be trimmed and have no double spaces.
717+
```diff
718+
<?php
719+
$array = [
720+
- 'option 1 ' => 'v1',
721+
- 'option 2 or 3' => 'v23',
722+
+ 'option 1' => 'v1',
723+
+ 'option 2 or 3' => 'v23',
724+
];
725+
```
726+
715727

716728
## Contributing
717729
Request a feature or report a bug by creating an [issue](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/issues).

src/Fixer/TrimKeyFixer.php

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<?php declare(strict_types=1);
2+
3+
/*
4+
* This file is part of PHP CS Fixer: custom fixers.
5+
*
6+
* (c) 2018 Kuba Werłos
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace PhpCsFixerCustomFixers\Fixer;
13+
14+
use PhpCsFixer\FixerDefinition\CodeSample;
15+
use PhpCsFixer\FixerDefinition\FixerDefinition;
16+
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
17+
use PhpCsFixer\Preg;
18+
use PhpCsFixer\Tokenizer\Token;
19+
use PhpCsFixer\Tokenizer\Tokens;
20+
21+
final class TrimKeyFixer extends AbstractFixer
22+
{
23+
public function getDefinition(): FixerDefinitionInterface
24+
{
25+
return new FixerDefinition(
26+
'A string array and yield keys must be trimmed and have no double spaces.',
27+
[new CodeSample(<<<'PHP'
28+
<?php
29+
$array = [
30+
'option 1 ' => 'v1',
31+
'option 2 or 3' => 'v23',
32+
];
33+
34+
PHP)],
35+
);
36+
}
37+
38+
public function getPriority(): int
39+
{
40+
return 0;
41+
}
42+
43+
public function isCandidate(Tokens $tokens): bool
44+
{
45+
return $tokens->isAnyTokenKindsFound([\T_CONSTANT_ENCAPSED_STRING]);
46+
}
47+
48+
public function isRisky(): bool
49+
{
50+
return false;
51+
}
52+
53+
public function fix(\SplFileInfo $file, Tokens $tokens): void
54+
{
55+
for ($index = $tokens->count() - 1; $index > 0; $index--) {
56+
if (!$tokens[$index]->isGivenKind(\T_DOUBLE_ARROW)) {
57+
continue;
58+
}
59+
60+
$indexToFix = $tokens->getPrevMeaningfulToken($index);
61+
\assert(\is_int($indexToFix));
62+
63+
if (!$tokens[$indexToFix]->isGivenKind([\T_CONSTANT_ENCAPSED_STRING])) {
64+
continue;
65+
}
66+
67+
$content = $tokens[$indexToFix]->getContent();
68+
$stringBorderQuote = $content[0];
69+
$innerContent = \substr($content, 1, -1);
70+
71+
$newInnerContent = Preg::replace('/\\s{2,}/', ' ', $innerContent);
72+
73+
$prevIndex = $tokens->getPrevMeaningfulToken($indexToFix);
74+
if (!$tokens[$prevIndex]->equals('.')) {
75+
$newInnerContent = \ltrim($newInnerContent);
76+
}
77+
78+
$nextIndex = $tokens->getNextMeaningfulToken($indexToFix);
79+
if (!$tokens[$nextIndex]->equals('.')) {
80+
$newInnerContent = \rtrim($newInnerContent);
81+
}
82+
83+
if ($newInnerContent === '') {
84+
continue;
85+
}
86+
87+
$newContent = $stringBorderQuote . $newInnerContent . $stringBorderQuote;
88+
89+
if ($content === $newContent) {
90+
continue;
91+
}
92+
93+
$tokens[$indexToFix] = new Token([\T_CONSTANT_ENCAPSED_STRING, $newContent]);
94+
}
95+
}
96+
}

tests/Fixer/TrimKeyFixerTest.php

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
<?php declare(strict_types=1);
2+
3+
/*
4+
* This file is part of PHP CS Fixer: custom fixers.
5+
*
6+
* (c) 2018 Kuba Werłos
7+
*
8+
* For the full copyright and license information, please view
9+
* the LICENSE file that was distributed with this source code.
10+
*/
11+
12+
namespace Tests\Fixer;
13+
14+
/**
15+
* @internal
16+
*
17+
* @covers \PhpCsFixerCustomFixers\Fixer\TrimKeyFixer
18+
*/
19+
final class TrimKeyFixerTest extends AbstractFixerTestCase
20+
{
21+
public function testIsRisky(): void
22+
{
23+
self::assertRiskiness(false);
24+
}
25+
26+
/**
27+
* @dataProvider provideFixCases
28+
*/
29+
public function testFix(string $expected, ?string $input = null): void
30+
{
31+
$this->doTest($expected, $input);
32+
}
33+
34+
/**
35+
* @return iterable<array{0: string, 1?: string}>
36+
*/
37+
public static function provideFixCases(): iterable
38+
{
39+
yield 'do not trim when with concatenation' => [
40+
<<<'PHP'
41+
<?php return [
42+
'foo '. $a => 'v',
43+
$b . ' foo' => 'v',
44+
$c . ' foo ' . $d => 'v',
45+
];
46+
PHP,
47+
];
48+
49+
yield 'trim array' => [
50+
<<<'PHP'
51+
<?php return [
52+
'k1' => 'v ',
53+
"k2" => "v",
54+
'k3' => ' v',
55+
"k4" => "v",
56+
'k5' => 'v',
57+
];
58+
PHP,
59+
<<<'PHP'
60+
<?php return [
61+
'k1 ' => 'v ',
62+
"k2 " => "v",
63+
' k3' => ' v',
64+
" k4" => "v",
65+
' k5 ' => 'v',
66+
];
67+
PHP,
68+
];
69+
70+
yield 'trim generator' => [
71+
<<<'PHP'
72+
<?php function g() {
73+
yield 'k1' => 'v';
74+
yield 'k2' => 'v';
75+
yield 'k3' => ' v ';
76+
yield 'k4' => 'v';
77+
yield 'k5' => 'v';
78+
yield 'k6' => 'v';
79+
}
80+
PHP,
81+
<<<'PHP'
82+
<?php function g() {
83+
yield 'k1 ' => 'v';
84+
yield 'k2 ' => 'v';
85+
yield 'k3' => ' v ';
86+
yield ' k4' => 'v';
87+
yield ' k5' => 'v';
88+
yield ' k6 ' => 'v';
89+
}
90+
PHP,
91+
];
92+
yield 'trim strings having non-whitespace characters' => [
93+
<<<'PHP'
94+
<?php return [
95+
'k1' => true,
96+
0 => 0,
97+
' ' => 1,
98+
' ' => 2,
99+
'k2' => false,
100+
];
101+
PHP,
102+
<<<'PHP'
103+
<?php return [
104+
' k1 ' => true,
105+
0 => 0,
106+
' ' => 1,
107+
' ' => 2,
108+
' k2 ' => false,
109+
];
110+
PHP,
111+
];
112+
}
113+
}

0 commit comments

Comments
 (0)