mirror of
https://github.com/elyby/php-code-style.git
synced 2025-04-14 06:49:07 +05:30
166 lines
6.6 KiB
PHP
166 lines
6.6 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
namespace Ely\CS\Fixer\FunctionNotation;
|
|
|
|
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\FunctionsAnalyzer;
|
|
use PhpCsFixer\Tokenizer\Analyzer\WhitespacesAnalyzer;
|
|
use PhpCsFixer\Tokenizer\Tokens;
|
|
use PhpCsFixer\Tokenizer\TokensAnalyzer;
|
|
use SplFileInfo;
|
|
|
|
final class AlignMultilineParametersFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface {
|
|
|
|
private const C_VARIABLES = 'variables';
|
|
private const C_DEFAULTS = 'defaults';
|
|
|
|
public function getDefinition(): FixerDefinitionInterface {
|
|
return new FixerDefinition(
|
|
'Aligns parameters in multiline function declaration.',
|
|
[
|
|
new CodeSample(
|
|
'<?php
|
|
function test(
|
|
string $a,
|
|
int $b = 0
|
|
): void {};
|
|
',
|
|
),
|
|
new CodeSample(
|
|
'<?php
|
|
function test(
|
|
string $string,
|
|
int $int = 0
|
|
): void {};
|
|
',
|
|
[self::C_VARIABLES => false, self::C_DEFAULTS => false],
|
|
),
|
|
],
|
|
);
|
|
}
|
|
|
|
public function isCandidate(Tokens $tokens): bool {
|
|
return $tokens->isAnyTokenKindsFound([T_FUNCTION, T_FN]);
|
|
}
|
|
|
|
/**
|
|
* Must run after StatementIndentationFixer, MethodArgumentSpaceFixer
|
|
*/
|
|
public function getPriority(): int {
|
|
return -10;
|
|
}
|
|
|
|
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface {
|
|
return new FixerConfigurationResolver([
|
|
(new FixerOptionBuilder(self::C_VARIABLES, 'on null no value alignment, on bool forces alignment'))
|
|
->setAllowedTypes(['bool', 'null'])
|
|
->setDefault(true)
|
|
->getOption(),
|
|
(new FixerOptionBuilder(self::C_DEFAULTS, 'on null no value alignment, on bool forces alignment'))
|
|
->setAllowedTypes(['bool', 'null'])
|
|
->setDefault(null)
|
|
->getOption(),
|
|
]);
|
|
}
|
|
|
|
protected function applyFix(SplFileInfo $file, Tokens $tokens): void {
|
|
// There is nothing to do
|
|
if ($this->configuration[self::C_VARIABLES] === null && $this->configuration[self::C_DEFAULTS] === null) {
|
|
return;
|
|
}
|
|
|
|
$tokensAnalyzer = new TokensAnalyzer($tokens);
|
|
$functionsAnalyzer = new FunctionsAnalyzer();
|
|
/** @var \PhpCsFixer\Tokenizer\Token $functionToken */
|
|
foreach ($tokens as $i => $functionToken) {
|
|
if (!$functionToken->isGivenKind([T_FUNCTION, T_FN])) {
|
|
continue;
|
|
}
|
|
|
|
$openBraceIndex = $tokens->getNextTokenOfKind($i, ['(']);
|
|
$isMultiline = $tokensAnalyzer->isBlockMultiline($tokens, $openBraceIndex);
|
|
if (!$isMultiline) {
|
|
continue;
|
|
}
|
|
|
|
/** @var \PhpCsFixer\Tokenizer\Analyzer\Analysis\ArgumentAnalysis[] $arguments */
|
|
$arguments = $functionsAnalyzer->getFunctionArguments($tokens, $i);
|
|
if (empty($arguments)) {
|
|
continue;
|
|
}
|
|
|
|
$longestType = 0;
|
|
$longestVariableName = 0;
|
|
$hasAtLeastOneTypedArgument = false;
|
|
foreach ($arguments as $argument) {
|
|
$typeAnalysis = $argument->getTypeAnalysis();
|
|
if ($typeAnalysis) {
|
|
$hasAtLeastOneTypedArgument = true;
|
|
$typeLength = strlen($typeAnalysis->getName());
|
|
if ($typeLength > $longestType) {
|
|
$longestType = $typeLength;
|
|
}
|
|
}
|
|
|
|
$variableNameLength = strlen($argument->getName());
|
|
if ($variableNameLength > $longestVariableName) {
|
|
$longestVariableName = $variableNameLength;
|
|
}
|
|
}
|
|
|
|
$argsIndent = WhitespacesAnalyzer::detectIndent($tokens, $i) . $this->whitespacesConfig->getIndent();
|
|
foreach ($arguments as $argument) {
|
|
if ($this->configuration[self::C_VARIABLES] !== null) {
|
|
$whitespaceIndex = $argument->getNameIndex() - 1;
|
|
if ($this->configuration[self::C_VARIABLES] === true) {
|
|
$typeLen = 0;
|
|
if ($argument->getTypeAnalysis() !== null) {
|
|
$typeLen = strlen($argument->getTypeAnalysis()->getName());
|
|
}
|
|
|
|
$appendix = str_repeat(' ', $longestType - $typeLen + (int)$hasAtLeastOneTypedArgument);
|
|
if ($argument->hasTypeAnalysis()) {
|
|
$whitespace = $appendix;
|
|
} else {
|
|
$whitespace = $this->whitespacesConfig->getLineEnding() . $argsIndent . $appendix;
|
|
}
|
|
} else {
|
|
if ($argument->hasTypeAnalysis()) {
|
|
$whitespace = ' ';
|
|
} else {
|
|
$whitespace = $this->whitespacesConfig->getLineEnding() . $argsIndent;
|
|
}
|
|
}
|
|
|
|
$tokens->ensureWhitespaceAtIndex($whitespaceIndex, 0, $whitespace);
|
|
}
|
|
|
|
if ($this->configuration[self::C_DEFAULTS] !== null) {
|
|
// Can't use $argument->hasDefault() because it's null when it's default for a type (e.g. 0 for int)
|
|
/** @var \PhpCsFixer\Tokenizer\Token $equalToken */
|
|
$equalToken = $tokens[$tokens->getNextMeaningfulToken($argument->getNameIndex())];
|
|
if ($equalToken->getContent() === '=') {
|
|
$nameLen = strlen($argument->getName());
|
|
$whitespaceIndex = $argument->getNameIndex() + 1;
|
|
if ($this->configuration[self::C_DEFAULTS] === true) {
|
|
$tokens->ensureWhitespaceAtIndex($whitespaceIndex, 0, str_repeat(' ', $longestVariableName - $nameLen + 1));
|
|
} else {
|
|
$tokens->ensureWhitespaceAtIndex($whitespaceIndex, 0, ' ');
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|