Fixes #13. Implemented Ely\multiline_if_statement_braces fixer

This commit is contained in:
ErickSkrauch 2023-04-08 21:07:29 +02:00
parent e9ad4a94ab
commit 7d36ce912c
No known key found for this signature in database
GPG Key ID: 669339FCBB30EE0E
7 changed files with 195 additions and 9 deletions

View File

@ -7,7 +7,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased] ## [Unreleased]
### Added ### Added
- Enh #12: Implemented `Ely\align_multiline_parameters` fixer. - Enh #12: Implemented `Ely\align_multiline_parameters` fixer.
- Enh #13: Implemented `Ely\multiline_if_statement_braces` fixer.
- Enabled `Ely\align_multiline_parameters` for Ely.by codestyle in `['types' => false, 'defaults' => false]` mode. - Enabled `Ely\align_multiline_parameters` for Ely.by codestyle in `['types' => false, 'defaults' => false]` mode.
- Enabled `Ely\multiline_if_statement_braces` for Ely.by codestyle in `['keep_on_own_line' => true]` mode.
- Enabled - Enabled
[`PhpCsFixerCustomFixers/multiline_promoted_properties`](https://github.com/kubawerlos/php-cs-fixer-custom-fixers#multilinepromotedpropertiesfixer) [`PhpCsFixerCustomFixers/multiline_promoted_properties`](https://github.com/kubawerlos/php-cs-fixer-custom-fixers#multilinepromotedpropertiesfixer)
fixer for Ely.by codestyle in 2+ parameters mode. fixer for Ely.by codestyle in 2+ parameters mode.

View File

@ -286,6 +286,28 @@ and `do-while`.
$c = 'next statement'; $c = 'next statement';
``` ```
### `Ely/multiline_if_statement_braces`
Ensures that multiline if statement body curly brace placed on the right line.
```diff
--- Original
+++ New
@@ @@
<?php
if ($condition1 === 123
- && $condition2 = 321) {
+ && $condition2 = 321
+) {
// Do something here
}
```
**Configuration:**
* `keep_on_own_line` - should this place closing bracket on its own line? If it's set to `false`, than
curly bracket will be placed right after the last condition statement. **Default**: `true`.
### `Ely/remove_class_name_method_usages` (Yii2) ### `Ely/remove_class_name_method_usages` (Yii2)
Replaces Yii2 [`BaseObject::className()`](https://github.com/yiisoft/yii2/blob/e53fc0ded1/framework/base/BaseObject.php#L84) Replaces Yii2 [`BaseObject::className()`](https://github.com/yiisoft/yii2/blob/e53fc0ded1/framework/base/BaseObject.php#L84)

View File

@ -21,7 +21,8 @@
"require": { "require": {
"php": "^7.4 || ^8.0", "php": "^7.4 || ^8.0",
"friendsofphp/php-cs-fixer": "^3.13", "friendsofphp/php-cs-fixer": "^3.13",
"kubawerlos/php-cs-fixer-custom-fixers": "^3.13" "kubawerlos/php-cs-fixer-custom-fixers": "^3.13",
"symfony/polyfill-php80": "^1.15"
}, },
"require-dev": { "require-dev": {
"ergebnis/composer-normalize": "^2.28", "ergebnis/composer-normalize": "^2.28",

16
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9fc362b1a074bf1a33695018a2b1b198", "content-hash": "8f031e395244dc0c0de0135b5c34ceda",
"packages": [ "packages": [
{ {
"name": "composer/pcre", "name": "composer/pcre",
@ -1708,16 +1708,16 @@
}, },
{ {
"name": "symfony/polyfill-php80", "name": "symfony/polyfill-php80",
"version": "v1.26.0", "version": "v1.27.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/polyfill-php80.git", "url": "https://github.com/symfony/polyfill-php80.git",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace" "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/cfa0ae98841b9e461207c13ab093d76b0fa7bace", "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"reference": "cfa0ae98841b9e461207c13ab093d76b0fa7bace", "reference": "7a6ff3f1959bb01aefccb463a0f2cd3d3d2fd936",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1726,7 +1726,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "1.26-dev" "dev-main": "1.27-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@ -1771,7 +1771,7 @@
"shim" "shim"
], ],
"support": { "support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.26.0" "source": "https://github.com/symfony/polyfill-php80/tree/v1.27.0"
}, },
"funding": [ "funding": [
{ {
@ -1787,7 +1787,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2022-05-10T07:21:04+00:00" "time": "2022-11-03T14:55:06+00:00"
}, },
{ {
"name": "symfony/polyfill-php81", "name": "symfony/polyfill-php81",

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace Ely\CS\Fixer\Whitespace;
use Ely\CS\Fixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;
use SplFileInfo;
final class MultilineIfStatementBracesFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface {
/**
* @internal
*/
public const C_KEEP_ON_OWN_LINE = 'keep_on_own_line';
public function getDefinition(): FixerDefinitionInterface {
return new FixerDefinition(
'Ensures that multiline if statement body curly brace placed on the right line.',
[
new CodeSample(
'<?php
if ($condition1 == true
&& $condition2 === false) {}
',
),
new CodeSample(
'<?php
if ($condition1 == true
&& $condition2 === false
) {}
',
[self::C_KEEP_ON_OWN_LINE => false],
),
],
);
}
public function isCandidate(Tokens $tokens): bool {
return $tokens->isTokenKindFound(T_IF);
}
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface {
return new FixerConfigurationResolver([
(new FixerOptionBuilder(self::C_KEEP_ON_OWN_LINE, 'adjusts the position of condition closing brace.'))
->setAllowedTypes(['bool'])
->setDefault(true)
->getOption(),
]);
}
protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
$keepOnOwnLine = $this->configuration[self::C_KEEP_ON_OWN_LINE];
$tokensAnalyzer = new TokensAnalyzer($tokens);
$eol = $this->whitespacesConfig->getLineEnding();
foreach ($tokens as $i => $token) {
if (!$token->isGivenKind(T_IF)) {
continue;
}
$openBraceIndex = $tokens->getNextTokenOfKind($i, ['(']);
if (!$tokensAnalyzer->isBlockMultiline($tokens, $openBraceIndex)) {
continue;
}
$closingBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $openBraceIndex);
/** @var \PhpCsFixer\Tokenizer\Token $statementBeforeClosingBrace */
$statementBeforeClosingBrace = $tokens[$closingBraceIndex - 1];
if ($keepOnOwnLine) {
if (!$statementBeforeClosingBrace->isWhitespace()
|| !str_contains($statementBeforeClosingBrace->getContent(), $eol)
) {
$indent = WhitespacesAnalyzer::detectIndent($tokens, $i);
$tokens->ensureWhitespaceAtIndex($closingBraceIndex, 0, $eol . $indent);
}
} else {
$tokens->removeLeadingWhitespace($closingBraceIndex);
}
}
}
}

View File

@ -228,6 +228,7 @@ class Rules {
], ],
'Ely/blank_line_before_return' => true, 'Ely/blank_line_before_return' => true,
'Ely/line_break_after_statements' => true, 'Ely/line_break_after_statements' => true,
'Ely/multiline_if_statement_braces' => true,
'Ely/remove_class_name_method_usages' => true, 'Ely/remove_class_name_method_usages' => true,
], $overwrittenRules); ], $overwrittenRules);
} }

View File

@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
namespace Ely\CS\Test\Fixer\Whitespace;
use Ely\CS\Fixer\Whitespace\MultilineIfStatementBracesFixer;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Tests\Test\AbstractFixerTestCase;
/**
* @covers \Ely\CS\Fixer\Whitespace\MultilineIfStatementBracesFixer
*/
class MultilineIfStatementBracesFixerTest extends AbstractFixerTestCase {
/**
* @dataProvider provideFixCases
*/
public function testFixOnNewLine(string $expected, ?string $input = null): void {
$this->doTest($expected, $input);
}
public function provideFixCases(): iterable {
yield 'simple' => [
'<?php
if ($condition1
&& $condition2
) {}',
'<?php
if ($condition1
&& $condition2) {}',
];
yield 'nested' => [
'<?php
function foo() {
if ($condition1
&& $condition2
) {}
}',
'<?php
function foo() {
if ($condition1
&& $condition2) {}
}',
];
}
/**
* @dataProvider provideInvertedFixCases
*/
public function testFixOnSameLine(string $expected, ?string $input = null): void {
$this->fixer->configure([
MultilineIfStatementBracesFixer::C_KEEP_ON_OWN_LINE => false,
]);
$this->doTest($expected, $input);
}
public function provideInvertedFixCases(): iterable {
foreach ($this->provideFixCases() as $name => $case) {
yield $name => [$case[1], $case[0]];
}
}
protected function createFixer(): AbstractFixer {
return new MultilineIfStatementBracesFixer();
}
}