Skip to content

Commit

Permalink
feature #4238 TrailingCommaInMultilineFixer - introduction (kubawerlos)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 2.19-dev branch.

Discussion
----------

TrailingCommaInMultilineFixer - introduction

Resolves #4135

Commits
-------

5b36241 TrailingCommaInMultilineFixer - introduction
  • Loading branch information
keradus committed May 3, 2021
2 parents 3d7e47c + 5b36241 commit e9c4f77
Show file tree
Hide file tree
Showing 15 changed files with 1,095 additions and 109 deletions.
2 changes: 1 addition & 1 deletion doc/ruleSets/PHP73Migration.rst
Expand Up @@ -15,6 +15,6 @@ Rules
- `no_whitespace_before_comma_in_array <./../rules/array_notation/no_whitespace_before_comma_in_array.rst>`_
config:
``['after_heredoc' => true]``
- `trailing_comma_in_multiline_array <./../rules/array_notation/trailing_comma_in_multiline_array.rst>`_
- `trailing_comma_in_multiline <./../rules/control_structure/trailing_comma_in_multiline.rst>`_
config:
``['after_heredoc' => true]``
2 changes: 1 addition & 1 deletion doc/ruleSets/Symfony.rst
Expand Up @@ -119,7 +119,7 @@ Rules
- `standardize_increment <./../rules/operator/standardize_increment.rst>`_
- `standardize_not_equals <./../rules/operator/standardize_not_equals.rst>`_
- `switch_continue_to_break <./../rules/control_structure/switch_continue_to_break.rst>`_
- `trailing_comma_in_multiline_array <./../rules/array_notation/trailing_comma_in_multiline_array.rst>`_
- `trailing_comma_in_multiline <./../rules/control_structure/trailing_comma_in_multiline.rst>`_
- `trim_array_spaces <./../rules/array_notation/trim_array_spaces.rst>`_
- `unary_operator_spaces <./../rules/operator/unary_operator_spaces.rst>`_
- `visibility_required <./../rules/class_notation/visibility_required.rst>`_
Expand Down
30 changes: 4 additions & 26 deletions doc/rules/array_notation/trailing_comma_in_multiline_array.rst
Expand Up @@ -2,6 +2,10 @@
Rule ``trailing_comma_in_multiline_array``
==========================================

.. warning:: This rule is deprecated and will be removed on next major version.

You should use ``trailing_comma_in_multiline`` instead.

PHP multi-line arrays should have a trailing comma.

Configuration
Expand Down Expand Up @@ -52,29 +56,3 @@ With configuration: ``['after_heredoc' => true]``.
- EOD
+ EOD,
];
Rule sets
---------

The rule is part of the following rule sets:

@PHP73Migration
Using the `@PHP73Migration <./../../ruleSets/PHP73Migration.rst>`_ rule set will enable the ``trailing_comma_in_multiline_array`` rule with the config below:

``['after_heredoc' => true]``

@PHP74Migration
Using the `@PHP74Migration <./../../ruleSets/PHP74Migration.rst>`_ rule set will enable the ``trailing_comma_in_multiline_array`` rule with the config below:

``['after_heredoc' => true]``

@PHP80Migration
Using the `@PHP80Migration <./../../ruleSets/PHP80Migration.rst>`_ rule set will enable the ``trailing_comma_in_multiline_array`` rule with the config below:

``['after_heredoc' => true]``

@PhpCsFixer
Using the `@PhpCsFixer <./../../ruleSets/PhpCsFixer.rst>`_ rule set will enable the ``trailing_comma_in_multiline_array`` rule with the default config.

@Symfony
Using the `@Symfony <./../../ruleSets/Symfony.rst>`_ rule set will enable the ``trailing_comma_in_multiline_array`` rule with the default config.
125 changes: 125 additions & 0 deletions doc/rules/control_structure/trailing_comma_in_multiline.rst
@@ -0,0 +1,125 @@
====================================
Rule ``trailing_comma_in_multiline``
====================================

Multi-line arrays, arguments list and parameters list must have a trailing
comma.

Configuration
-------------

``after_heredoc``
~~~~~~~~~~~~~~~~~

Whether a trailing comma should also be placed after heredoc end.

Allowed types: ``bool``

Default value: ``false``

``elements``
~~~~~~~~~~~~

Where to fix multiline trailing comma (PHP >= 7.3 required for ``arguments``,
PHP >= 8.0 for ``parameters``).

Allowed values: a subset of ``['arrays', 'arguments', 'parameters']``

Default value: ``['arrays']``

Examples
--------

Example #1
~~~~~~~~~~

*Default* configuration.

.. code-block:: diff
--- Original
+++ New
<?php
array(
1,
- 2
+ 2,
);
Example #2
~~~~~~~~~~

With configuration: ``['after_heredoc' => true]``.

.. code-block:: diff
--- Original
+++ New
<?php
$x = [
'foo',
<<<EOD
bar
- EOD
+ EOD,
];
Example #3
~~~~~~~~~~

With configuration: ``['elements' => ['arguments']]``.

.. code-block:: diff
--- Original
+++ New
<?php
foo(
1,
- 2
+ 2,
);
Example #4
~~~~~~~~~~

With configuration: ``['elements' => ['parameters']]``.

.. code-block:: diff
--- Original
+++ New
<?php
function foo(
$x,
- $y
+ $y,
)
{
}
Rule sets
---------

The rule is part of the following rule sets:

@PHP73Migration
Using the `@PHP73Migration <./../../ruleSets/PHP73Migration.rst>`_ rule set will enable the ``trailing_comma_in_multiline`` rule with the config below:

``['after_heredoc' => true]``

@PHP74Migration
Using the `@PHP74Migration <./../../ruleSets/PHP74Migration.rst>`_ rule set will enable the ``trailing_comma_in_multiline`` rule with the config below:

``['after_heredoc' => true]``

@PHP80Migration
Using the `@PHP80Migration <./../../ruleSets/PHP80Migration.rst>`_ rule set will enable the ``trailing_comma_in_multiline`` rule with the config below:

``['after_heredoc' => true]``

@PhpCsFixer
Using the `@PhpCsFixer <./../../ruleSets/PhpCsFixer.rst>`_ rule set will enable the ``trailing_comma_in_multiline`` rule with the default config.

@Symfony
Using the `@Symfony <./../../ruleSets/Symfony.rst>`_ rule set will enable the ``trailing_comma_in_multiline`` rule with the default config.
4 changes: 3 additions & 1 deletion doc/rules/index.rst
Expand Up @@ -39,7 +39,7 @@ Array Notation
In array declaration, there MUST NOT be a whitespace before each comma.
- `normalize_index_brace <./array_notation/normalize_index_brace.rst>`_
Array index should always be written by using square braces.
- `trailing_comma_in_multiline_array <./array_notation/trailing_comma_in_multiline_array.rst>`_
- `trailing_comma_in_multiline_array <./array_notation/trailing_comma_in_multiline_array.rst>`_ *(deprecated)*
PHP multi-line arrays should have a trailing comma.
- `trim_array_spaces <./array_notation/trim_array_spaces.rst>`_
Arrays should be formatted like function/method arguments, without leading or trailing single line space.
Expand Down Expand Up @@ -201,6 +201,8 @@ Control Structure
Removes extra spaces between colon and case value.
- `switch_continue_to_break <./control_structure/switch_continue_to_break.rst>`_
Switch case must not be ended with ``continue`` but with ``break``.
- `trailing_comma_in_multiline <./control_structure/trailing_comma_in_multiline.rst>`_
Multi-line arrays, arguments list and parameters list must have a trailing comma.
- `yoda_style <./control_structure/yoda_style.rst>`_
Write conditions in Yoda style (``true``), non-Yoda style (``['equal' => false, 'identical' => false, 'less_and_greater' => false]``) or ignore those conditions (``null``) based on configuration.

Expand Down
Expand Up @@ -39,7 +39,7 @@ public function getDefinition()
/**
* {@inheritdoc}
*
* Must run before BinaryOperatorSpacesFixer, TrailingCommaInMultilineArrayFixer.
* Must run before BinaryOperatorSpacesFixer, TrailingCommaInMultilineFixer.
*/
public function getPriority()
{
Expand Down
97 changes: 27 additions & 70 deletions src/Fixer/ArrayNotation/TrailingCommaInMultilineArrayFixer.php
Expand Up @@ -12,27 +12,29 @@

namespace PhpCsFixer\Fixer\ArrayNotation;

use PhpCsFixer\AbstractFixer;
use PhpCsFixer\AbstractProxyFixer;
use PhpCsFixer\Fixer\ConfigurationDefinitionFixerInterface;
use PhpCsFixer\Fixer\ControlStructure\TrailingCommaInMultilineFixer;
use PhpCsFixer\Fixer\DeprecatedFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerConfiguration\InvalidOptionsForEnvException;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\VersionSpecification;
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;
use Symfony\Component\OptionsResolver\Options;

/**
* @author Sebastiaan Stok <s.stok@rollerscapes.net>
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* @deprecated
*/
final class TrailingCommaInMultilineArrayFixer extends AbstractFixer implements ConfigurationDefinitionFixerInterface
final class TrailingCommaInMultilineArrayFixer extends AbstractProxyFixer implements ConfigurationDefinitionFixerInterface, DeprecatedFixerInterface
{
/**
* @var TrailingCommaInMultilineFixer
*/
private $fixer;

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -61,87 +63,42 @@ public function getDefinition()
);
}

/**
* {@inheritdoc}
*
* Must run after NoMultilineWhitespaceAroundDoubleArrowFixer.
*/
public function getPriority()
public function configure(array $configuration = null)
{
return 0;
$configuration['elements'] = [TrailingCommaInMultilineFixer::ELEMENTS_ARRAYS];
$this->getFixer()->configure($configuration);
$this->configuration = $configuration;
}

/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens)
public function getConfigurationDefinition()
{
return $tokens->isAnyTokenKindsFound([T_ARRAY, CT::T_ARRAY_SQUARE_BRACE_OPEN]);
return new FixerConfigurationResolver([
$this->getFixer()->getConfigurationDefinition()->getOptions()[0],
]);
}

/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens)
public function getSuccessorsNames()
{
$tokensAnalyzer = new TokensAnalyzer($tokens);

for ($index = $tokens->count() - 1; $index >= 0; --$index) {
if ($tokensAnalyzer->isArray($index) && $tokensAnalyzer->isArrayMultiLine($index)) {
$this->fixArray($tokens, $index);
}
}
return array_keys($this->proxyFixers);
}

/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition()
protected function createProxyFixers()
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('after_heredoc', 'Whether a trailing comma should also be placed after heredoc end.'))
->setAllowedTypes(['bool'])
->setDefault(false)
->setNormalizer(static function (Options $options, $value) {
if (\PHP_VERSION_ID < 70300 && $value) {
throw new InvalidOptionsForEnvException('"after_heredoc" option can only be enabled with PHP 7.3+.');
}

return $value;
})
->getOption(),
]);
return [$this->getFixer()];
}

/**
* @param int $index
*/
private function fixArray(Tokens $tokens, $index)
private function getFixer()
{
$startIndex = $index;

if ($tokens[$startIndex]->isGivenKind(T_ARRAY)) {
$startIndex = $tokens->getNextTokenOfKind($startIndex, ['(']);
$endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $startIndex);
} else {
$endIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_ARRAY_SQUARE_BRACE, $startIndex);
if (null === $this->fixer) {
$this->fixer = new TrailingCommaInMultilineFixer();
}

$beforeEndIndex = $tokens->getPrevMeaningfulToken($endIndex);
$beforeEndToken = $tokens[$beforeEndIndex];

// if there is some item between braces then add `,` after it
if (
$startIndex !== $beforeEndIndex && !$beforeEndToken->equals(',')
&& ($this->configuration['after_heredoc'] || !$beforeEndToken->isGivenKind(T_END_HEREDOC))
) {
$tokens->insertAt($beforeEndIndex + 1, new Token(','));

$endToken = $tokens[$endIndex];

if (!$endToken->isComment() && !$endToken->isWhitespace()) {
$tokens->ensureWhitespaceAtIndex($endIndex, 1, ' ');
}
}
return $this->fixer;
}
}

0 comments on commit e9c4f77

Please sign in to comment.