Skip to content

Commit

Permalink
Add NoTrailingCommaInSinglelineFixer (#727)
Browse files Browse the repository at this point in the history
  • Loading branch information
kubawerlos committed Jan 21, 2022
1 parent f5105e4 commit aa1bbd9
Show file tree
Hide file tree
Showing 7 changed files with 294 additions and 3 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,8 @@
# CHANGELOG for PHP CS Fixer: custom fixers

## v3.7.0
- Add NoTrailingCommaInSinglelineFixer
-
## v3.6.0
- Add IssetToArrayKeyExistsFixer
- Add PhpdocVarAnnotationToAssertFixer
Expand Down
10 changes: 9 additions & 1 deletion README.md
Expand Up @@ -3,7 +3,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-3322-brightgreen.svg)
![Tests](https://img.shields.io/badge/tests-3365-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/workflows/CI/badge.svg?branch=main)](https://github.com/kubawerlos/php-cs-fixer-custom-fixers/actions)
Expand Down Expand Up @@ -291,6 +291,14 @@ Configuration options:
+echo 'foobar';
```

#### NoTrailingCommaInSinglelineFixer
Trailing comma in the list on the same line as the end of the block must be removed.
```diff
<?php
-$x = ['foo', 'bar', ];
+$x = ['foo', 'bar'];
```

#### NoUselessCommentFixer
There must be no useless comments.
```diff
Expand Down
74 changes: 74 additions & 0 deletions src/Fixer/NoTrailingCommaInSinglelineFixer.php
@@ -0,0 +1,74 @@
<?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\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Tokens;

final class NoTrailingCommaInSinglelineFixer extends AbstractFixer
{
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Trailing comma in the list on the same line as the end of the block must be removed.',
[
new CodeSample("<?php\n\$x = ['foo', 'bar', ];\n"),
]
);
}

/**
* Must run after MethodArgumentSpaceFixer, TrailingCommaInMultilineFixer.
*/
public function getPriority(): int
{
return -1;
}

public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound([\T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, '(']);
}

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]->equalsAny([')', [CT::T_ARRAY_SQUARE_BRACE_CLOSE], [CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE]])) {
continue;
}

$commaIndex = $tokens->getPrevMeaningfulToken($index);
\assert(\is_int($commaIndex));

while ($tokens[$commaIndex]->equals(',')) {
if ($tokens->isPartialCodeMultiline($commaIndex, $index)) {
break;
}

$tokens->removeLeadingWhitespace($commaIndex);
$tokens->removeTrailingWhitespace($commaIndex);
$tokens->clearAt($commaIndex);

$commaIndex = $tokens->getPrevMeaningfulToken($index);
\assert(\is_int($commaIndex));
}
}
}
}
167 changes: 167 additions & 0 deletions tests/Fixer/NoTrailingCommaInSinglelineFixerTest.php
@@ -0,0 +1,167 @@
<?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\NoTrailingCommaInSinglelineFixer
*/
final class NoTrailingCommaInSinglelineFixerTest extends AbstractFixerTestCase
{
public function testIsRisky(): void
{
self::assertFalse($this->fixer->isRisky());
}

/**
* @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 [
'<?php $x = [
1,
2,
];',
];

yield [
'<?php $x = [1, 2,// foo
];',
];

yield [
'<?php $array = [1, 2];',
'<?php $array = [1, 2,];',
];

yield [
'<?php $array = [1, 2];',
'<?php $array = [1, 2, ];',
];

yield [
'<?php $array = [1, 2,
3, 4];',
'<?php $array = [1, 2,
3, 4, ];',
];

yield [
'<?php $array = [1, 2] + [3, 4] + [5, 6];',
'<?php $array = [1, 2, ] + [3, 4, ] + [5, 6, ];',
];

yield [
'<?php $array = [1, 2/* foo */];',
'<?php $array = [1, 2, /* foo */];',
];

yield [
'<?php $array = array(1, 2);',
'<?php $array = array(1, 2, );',
];

yield [
'<?php list($x, $y) = $list;',
'<?php list($x, $y,) = $list;',
];

yield [
'<?php [$x, $y] = $list;',
'<?php [$x, $y,] = $list;',
];

yield [
'<?php list($x, $y) = $list;',
'<?php list($x, $y, , ,) = $list;',
];

yield [
'<?php list($x, $y) = $list;',
'<?php list($x, $y , , , ) = $list;',
];
}

/**
* @requires PHP ^7.3
* @dataProvider provideFix73Cases
*/
public function testFix73(string $expected, ?string $input = null): void
{
$this->doTest($expected, $input);
}

/**
* @return iterable<array{0: string, 1?: string}>
*/
public static function provideFix73Cases(): iterable
{
yield [
'<?php foo($x, $y);',
'<?php foo($x, $y, );',
];

yield [
'<?php
$array = [1, 2] + [3, 4] + [5, 6];
foo(
1,
2,
);
list($x, $y) = $list;
',
'<?php
$array = [1, 2, ] + [3, 4] + [5, 6, ];
foo(
1,
2,
);
list($x, $y,) = $list;
',
];
}

/**
* @requires PHP ^8.0
* @dataProvider provideFix80Cases
*/
public function testFix80(string $expected, ?string $input = null): void
{
$this->doTest($expected, $input);
}

/**
* @return iterable<array{0: string, 1?: string}>
*/
public static function provideFix80Cases(): iterable
{
yield [
'<?php function foo($x, $y) {}',
'<?php function foo($x, $y, ) {}',
];

yield [
'<?php $f = function ($x, $y) {};',
'<?php $f = function ($x, $y, ) {};',
];
}
}
4 changes: 2 additions & 2 deletions tests/Fixer/PhpdocNoIncorrectVarAnnotationFixerTest.php
Expand Up @@ -45,13 +45,13 @@ public static function provideFixCases(): iterable
'<?php
/** @var \Foo $foo */
$foo = new Foo();
', ];
'];

yield 'keep correct PHPDoc with nullable' => [
'<?php
/** @var ?Foo $foo */
$foo = new Foo();
', ];
'];

yield 'remove PHPDoc when variable name is different' => [
'<?php
Expand Down
@@ -0,0 +1,20 @@
--CONFIGURATION--
{ "method_argument_space": {"on_multiline": "ensure_single_line"}, "PhpCsFixerCustomFixers/no_trailing_comma_in_singleline": true }
--EXPECTED--
<?php

foo(1, 2, 3);

function bar($x, $y, $x) {}

--INPUT--
<?php

foo(1, 2,
3,
);

function bar($x,
$y,
$x,
) {}
@@ -0,0 +1,19 @@
--CONFIGURATION--
{ "trailing_comma_in_multiline": true, "PhpCsFixerCustomFixers/no_trailing_comma_in_singleline": true }
--EXPECTED--
<?php
$foo = [1, 2,
3, 4];
$bar = [5, 6,
7, 8];
$baz = [11, 12,
13, 14];

--INPUT--
<?php
$foo = [1, 2,
3, 4];
$bar = [5, 6,
7, 8,];
$baz = [11, 12,
13, 14, ];

0 comments on commit aa1bbd9

Please sign in to comment.