Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TrailingCommaInMultilineFixer - introduction #4238

Merged
merged 1 commit into from May 3, 2021
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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;
}
}