Missing dependancies

This commit is contained in:
tokslaw7
2023-06-21 12:19:22 +00:00
parent fbf3f180c2
commit 421f25c80d
2356 changed files with 342670 additions and 4743 deletions
@@ -0,0 +1,267 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractProxyFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\ControlStructure\ControlStructureBracesFixer;
use PhpCsFixer\Fixer\ControlStructure\ControlStructureContinuationPositionFixer;
use PhpCsFixer\Fixer\LanguageConstruct\DeclareParenthesesFixer;
use PhpCsFixer\Fixer\LanguageConstruct\SingleSpaceAfterConstructFixer;
use PhpCsFixer\Fixer\Whitespace\NoExtraBlankLinesFixer;
use PhpCsFixer\Fixer\Whitespace\StatementIndentationFixer;
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\CT;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Fixer for rules defined in PSR2 ¶4.1, ¶4.4, ¶5.
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
final class BracesFixer extends AbstractProxyFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
{
/**
* @internal
*/
public const LINE_NEXT = 'next';
/**
* @internal
*/
public const LINE_SAME = 'same';
/**
* @var null|CurlyBracesPositionFixer
*/
private $curlyBracesPositionFixer;
/**
* @var null|ControlStructureContinuationPositionFixer
*/
private $controlStructureContinuationPositionFixer;
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'The body of each structure MUST be enclosed by braces. Braces should be properly placed. Body of braces should be properly indented.',
[
new CodeSample(
'<?php
class Foo {
public function bar($baz) {
if ($baz = 900) echo "Hello!";
if ($baz = 9000)
echo "Wait!";
if ($baz == true)
{
echo "Why?";
}
else
{
echo "Ha?";
}
if (is_array($baz))
foreach ($baz as $b)
{
echo $b;
}
}
}
'
),
new CodeSample(
'<?php
$positive = function ($item) { return $item >= 0; };
$negative = function ($item) {
return $item < 0; };
',
['allow_single_line_closure' => true]
),
new CodeSample(
'<?php
class Foo
{
public function bar($baz)
{
if ($baz = 900) echo "Hello!";
if ($baz = 9000)
echo "Wait!";
if ($baz == true)
{
echo "Why?";
}
else
{
echo "Ha?";
}
if (is_array($baz))
foreach ($baz as $b)
{
echo $b;
}
}
}
',
['position_after_functions_and_oop_constructs' => self::LINE_SAME]
),
]
);
}
/**
* {@inheritdoc}
*
* Must run before HeredocIndentationFixer.
* Must run after ClassAttributesSeparationFixer, ClassDefinitionFixer, EmptyLoopBodyFixer, NoAlternativeSyntaxFixer, NoEmptyStatementFixer, NoUselessElseFixer, SingleLineThrowFixer, SingleSpaceAfterConstructFixer, SingleTraitInsertPerStatementFixer.
*/
public function getPriority(): int
{
return 35;
}
public function configure(array $configuration = null): void
{
parent::configure($configuration);
$this->getCurlyBracesPositionFixer()->configure([
'control_structures_opening_brace' => $this->translatePositionOption($this->configuration['position_after_control_structures']),
'functions_opening_brace' => $this->translatePositionOption($this->configuration['position_after_functions_and_oop_constructs']),
'anonymous_functions_opening_brace' => $this->translatePositionOption($this->configuration['position_after_anonymous_constructs']),
'classes_opening_brace' => $this->translatePositionOption($this->configuration['position_after_functions_and_oop_constructs']),
'anonymous_classes_opening_brace' => $this->translatePositionOption($this->configuration['position_after_anonymous_constructs']),
'allow_single_line_empty_anonymous_classes' => $this->configuration['allow_single_line_anonymous_class_with_empty_body'],
'allow_single_line_anonymous_functions' => $this->configuration['allow_single_line_closure'],
]);
$this->getControlStructureContinuationPositionFixer()->configure([
'position' => self::LINE_NEXT === $this->configuration['position_after_control_structures']
? ControlStructureContinuationPositionFixer::NEXT_LINE
: ControlStructureContinuationPositionFixer::SAME_LINE,
]);
$this->configuration = $configuration;
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = \count($tokens) - 1; $index > 0; --$index) {
if ($tokens[$index]->isGivenKind(CT::T_USE_LAMBDA)) {
$tokens->ensureWhitespaceAtIndex($index - 1, 1, ' ');
}
}
parent::applyFix($file, $tokens);
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('allow_single_line_anonymous_class_with_empty_body', 'Whether single line anonymous class with empty body notation should be allowed.'))
->setAllowedTypes(['bool'])
->setDefault(false)
->getOption(),
(new FixerOptionBuilder('allow_single_line_closure', 'Whether single line lambda notation should be allowed.'))
->setAllowedTypes(['bool'])
->setDefault(false)
->getOption(),
(new FixerOptionBuilder('position_after_functions_and_oop_constructs', 'whether the opening brace should be placed on "next" or "same" line after classy constructs (non-anonymous classes, interfaces, traits, methods and non-lambda functions).'))
->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
->setDefault(self::LINE_NEXT)
->getOption(),
(new FixerOptionBuilder('position_after_control_structures', 'whether the opening brace should be placed on "next" or "same" line after control structures.'))
->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
->setDefault(self::LINE_SAME)
->getOption(),
(new FixerOptionBuilder('position_after_anonymous_constructs', 'whether the opening brace should be placed on "next" or "same" line after anonymous constructs (anonymous classes and lambda functions).'))
->setAllowedValues([self::LINE_NEXT, self::LINE_SAME])
->setDefault(self::LINE_SAME)
->getOption(),
]);
}
protected function createProxyFixers(): array
{
$singleSpaceAfterConstructFixer = new SingleSpaceAfterConstructFixer();
$singleSpaceAfterConstructFixer->configure([
'constructs' => ['elseif', 'for', 'foreach', 'if', 'match', 'while', 'use_lambda'],
]);
$noExtraBlankLinesFixer = new NoExtraBlankLinesFixer();
$noExtraBlankLinesFixer->configure([
'tokens' => ['curly_brace_block'],
]);
return [
$singleSpaceAfterConstructFixer,
new ControlStructureBracesFixer(),
$noExtraBlankLinesFixer,
$this->getCurlyBracesPositionFixer(),
$this->getControlStructureContinuationPositionFixer(),
new DeclareParenthesesFixer(),
new NoMultipleStatementsPerLineFixer(),
new StatementIndentationFixer(true),
];
}
private function getCurlyBracesPositionFixer(): CurlyBracesPositionFixer
{
if (null === $this->curlyBracesPositionFixer) {
$this->curlyBracesPositionFixer = new CurlyBracesPositionFixer();
}
return $this->curlyBracesPositionFixer;
}
private function getControlStructureContinuationPositionFixer(): ControlStructureContinuationPositionFixer
{
if (null === $this->controlStructureContinuationPositionFixer) {
$this->controlStructureContinuationPositionFixer = new ControlStructureContinuationPositionFixer();
}
return $this->controlStructureContinuationPositionFixer;
}
private function translatePositionOption(string $option): string
{
return self::LINE_NEXT === $option
? CurlyBracesPositionFixer::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END
: CurlyBracesPositionFixer::SAME_LINE
;
}
}
@@ -0,0 +1,429 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\Fixer\Indentation;
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\FixerDefinition\VersionSpecification;
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;
final class CurlyBracesPositionFixer extends AbstractFixer implements ConfigurableFixerInterface, WhitespacesAwareFixerInterface
{
use Indentation;
/**
* @internal
*/
public const NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END = 'next_line_unless_newline_at_signature_end';
/**
* @internal
*/
public const SAME_LINE = 'same_line';
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Curly braces must be placed as configured.',
[
new CodeSample(
'<?php
class Foo {
}
function foo() {
}
$foo = function()
{
};
if (foo())
{
bar();
}
'
),
new VersionSpecificCodeSample(
'<?php
$foo = new class
{
};
',
new VersionSpecification(70000)
),
new CodeSample(
'<?php
if (foo()) {
bar();
}
',
['control_structures_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
),
new CodeSample(
'<?php
function foo()
{
}
',
['functions_opening_brace' => self::SAME_LINE]
),
new CodeSample(
'<?php
$foo = function () {
};
',
['anonymous_functions_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
),
new CodeSample(
'<?php
class Foo
{
}
',
['classes_opening_brace' => self::SAME_LINE]
),
new VersionSpecificCodeSample(
'<?php
$foo = new class {
};
',
new VersionSpecification(70000),
['anonymous_classes_opening_brace' => self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END]
),
new VersionSpecificCodeSample(
'<?php
$foo = new class { };
$bar = new class { private $baz; };
',
new VersionSpecification(70000),
['allow_single_line_empty_anonymous_classes' => true]
),
new CodeSample(
'<?php
$foo = function () { return true; };
$bar = function () { $result = true;
return $result; };
',
['allow_single_line_anonymous_functions' => true]
),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound('{');
}
/**
* {@inheritdoc}
*
* Must run after ControlStructureBracesFixer.
*/
public function getPriority(): int
{
return parent::getPriority();
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$classyTokens = Token::getClassyTokenKinds();
$controlStructureTokens = [T_DECLARE, T_DO, T_ELSE, T_ELSEIF, T_FINALLY, T_FOR, T_FOREACH, T_IF, T_WHILE, T_TRY, T_CATCH, T_SWITCH];
// @TODO: drop condition when PHP 8.0+ is required
if (\defined('T_MATCH')) {
$controlStructureTokens[] = T_MATCH;
}
$tokensAnalyzer = new TokensAnalyzer($tokens);
$allowSingleLineUntil = null;
foreach ($tokens as $index => $token) {
$allowSingleLine = false;
$allowSingleLineIfEmpty = false;
if ($token->isGivenKind($classyTokens)) {
$openBraceIndex = $tokens->getNextTokenOfKind($index, ['{']);
if ($tokensAnalyzer->isAnonymousClass($index)) {
$allowSingleLineIfEmpty = $this->configuration['allow_single_line_empty_anonymous_classes'];
$positionOption = 'anonymous_classes_opening_brace';
} else {
$positionOption = 'classes_opening_brace';
}
} elseif ($token->isGivenKind(T_FUNCTION)) {
$openBraceIndex = $tokens->getNextTokenOfKind($index, ['{', ';']);
if ($tokens[$openBraceIndex]->equals(';')) {
continue;
}
if ($tokensAnalyzer->isLambda($index)) {
$allowSingleLine = $this->configuration['allow_single_line_anonymous_functions'];
$positionOption = 'anonymous_functions_opening_brace';
} else {
$positionOption = 'functions_opening_brace';
}
} elseif ($token->isGivenKind($controlStructureTokens)) {
$parenthesisEndIndex = $this->findParenthesisEnd($tokens, $index);
$openBraceIndex = $tokens->getNextMeaningfulToken($parenthesisEndIndex);
if (!$tokens[$openBraceIndex]->equals('{')) {
continue;
}
$positionOption = 'control_structures_opening_brace';
} else {
continue;
}
$closeBraceIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_CURLY_BRACE, $openBraceIndex);
$addNewlinesInsideBraces = true;
if ($allowSingleLine || $allowSingleLineIfEmpty || $index < $allowSingleLineUntil) {
$addNewlinesInsideBraces = false;
for ($indexInsideBraces = $openBraceIndex + 1; $indexInsideBraces < $closeBraceIndex; ++$indexInsideBraces) {
$tokenInsideBraces = $tokens[$indexInsideBraces];
if (
($allowSingleLineIfEmpty && !$tokenInsideBraces->isWhitespace() && !$tokenInsideBraces->isComment())
|| ($tokenInsideBraces->isWhitespace() && 1 === Preg::match('/\R/', $tokenInsideBraces->getContent()))
) {
$addNewlinesInsideBraces = true;
break;
}
}
if (!$addNewlinesInsideBraces && null === $allowSingleLineUntil) {
$allowSingleLineUntil = $closeBraceIndex;
}
}
if (
$addNewlinesInsideBraces
&& !$this->isFollowedByNewLine($tokens, $openBraceIndex)
&& !$this->hasCommentOnSameLine($tokens, $openBraceIndex)
&& !$tokens[$tokens->getNextMeaningfulToken($openBraceIndex)]->isGivenKind(T_CLOSE_TAG)
) {
$whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
if ($tokens->ensureWhitespaceAtIndex($openBraceIndex + 1, 0, $whitespace)) {
++$closeBraceIndex;
}
}
$whitespace = ' ';
if (self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END === $this->configuration[$positionOption]) {
$whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $index);
$previousTokenIndex = $openBraceIndex;
do {
$previousTokenIndex = $tokens->getPrevMeaningfulToken($previousTokenIndex);
} while ($tokens[$previousTokenIndex]->isGivenKind([CT::T_TYPE_COLON, CT::T_NULLABLE_TYPE, T_STRING, T_NS_SEPARATOR, CT::T_ARRAY_TYPEHINT, T_STATIC, CT::T_TYPE_ALTERNATION, CT::T_TYPE_INTERSECTION]));
if ($tokens[$previousTokenIndex]->equals(')')) {
if ($tokens[--$previousTokenIndex]->isComment()) {
--$previousTokenIndex;
}
if (
$tokens[$previousTokenIndex]->isWhitespace()
&& 1 === Preg::match('/\R/', $tokens[$previousTokenIndex]->getContent())
) {
$whitespace = ' ';
}
}
}
$moveBraceToIndex = null;
if (' ' === $whitespace) {
$previousMeaningfulIndex = $tokens->getPrevMeaningfulToken($openBraceIndex);
for ($indexBeforeOpenBrace = $openBraceIndex - 1; $indexBeforeOpenBrace > $previousMeaningfulIndex; --$indexBeforeOpenBrace) {
if (!$tokens[$indexBeforeOpenBrace]->isComment()) {
continue;
}
$tokenBeforeOpenBrace = $tokens[--$indexBeforeOpenBrace];
if ($tokenBeforeOpenBrace->isWhitespace()) {
$moveBraceToIndex = $indexBeforeOpenBrace;
} elseif ($indexBeforeOpenBrace === $previousMeaningfulIndex) {
$moveBraceToIndex = $previousMeaningfulIndex + 1;
}
}
} elseif (!$tokens[$openBraceIndex - 1]->isWhitespace() || !Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
for ($indexAfterOpenBrace = $openBraceIndex + 1; $indexAfterOpenBrace < $closeBraceIndex; ++$indexAfterOpenBrace) {
if ($tokens[$indexAfterOpenBrace]->isWhitespace() && Preg::match('/\R/', $tokens[$indexAfterOpenBrace]->getContent())) {
break;
}
if ($tokens[$indexAfterOpenBrace]->isComment() && !str_starts_with($tokens[$indexAfterOpenBrace]->getContent(), '/*')) {
$moveBraceToIndex = $indexAfterOpenBrace + 1;
}
}
}
if (null !== $moveBraceToIndex) {
/** @var Token $movedToken */
$movedToken = clone $tokens[$openBraceIndex];
$delta = $openBraceIndex < $moveBraceToIndex ? 1 : -1;
if ($tokens[$openBraceIndex + $delta]->isWhitespace()) {
if (-1 === $delta && Preg::match('/\R/', $tokens[$openBraceIndex - 1]->getContent())) {
$content = Preg::replace('/^(\h*?\R)?\h*/', '', $tokens[$openBraceIndex + 1]->getContent());
if ('' !== $content) {
$tokens[$openBraceIndex + 1] = new Token([T_WHITESPACE, $content]);
} else {
$tokens->clearAt($openBraceIndex + 1);
}
} else {
$tokens->clearAt($openBraceIndex - 1);
}
}
for (; $openBraceIndex !== $moveBraceToIndex; $openBraceIndex += $delta) {
/** @var Token $siblingToken */
$siblingToken = $tokens[$openBraceIndex + $delta];
$tokens[$openBraceIndex] = $siblingToken;
}
$tokens[$openBraceIndex] = $movedToken;
$openBraceIndex = $moveBraceToIndex;
}
if ($tokens->ensureWhitespaceAtIndex($openBraceIndex - 1, 1, $whitespace)) {
++$closeBraceIndex;
if (null !== $allowSingleLineUntil) {
++$allowSingleLineUntil;
}
}
if (
!$addNewlinesInsideBraces
|| $tokens[$tokens->getPrevMeaningfulToken($closeBraceIndex)]->isGivenKind(T_OPEN_TAG)
) {
continue;
}
for ($prevIndex = $closeBraceIndex - 1; $tokens->isEmptyAt($prevIndex); --$prevIndex);
$prevToken = $tokens[$prevIndex];
if ($prevToken->isWhitespace() && 1 === Preg::match('/\R/', $prevToken->getContent())) {
continue;
}
$whitespace = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $openBraceIndex);
$tokens->ensureWhitespaceAtIndex($prevIndex, 1, $whitespace);
}
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('control_structures_opening_brace', 'the position of the opening brace of control structures body.'))
->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
->setDefault(self::SAME_LINE)
->getOption(),
(new FixerOptionBuilder('functions_opening_brace', 'the position of the opening brace of functions body.'))
->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
->getOption(),
(new FixerOptionBuilder('anonymous_functions_opening_brace', 'the position of the opening brace of anonymous functions body.'))
->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
->setDefault(self::SAME_LINE)
->getOption(),
(new FixerOptionBuilder('classes_opening_brace', 'the position of the opening brace of classes body.'))
->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
->setDefault(self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END)
->getOption(),
(new FixerOptionBuilder('anonymous_classes_opening_brace', 'the position of the opening brace of anonymous classes body.'))
->setAllowedValues([self::NEXT_LINE_UNLESS_NEWLINE_AT_SIGNATURE_END, self::SAME_LINE])
->setDefault(self::SAME_LINE)
->getOption(),
(new FixerOptionBuilder('allow_single_line_empty_anonymous_classes', 'allow anonymous classes to have opening and closing braces on the same line.'))
->setAllowedTypes(['bool'])
->setDefault(true)
->getOption(),
(new FixerOptionBuilder('allow_single_line_anonymous_functions', 'allow anonymous functions to have opening and closing braces on the same line.'))
->setAllowedTypes(['bool'])
->setDefault(true)
->getOption(),
]);
}
private function findParenthesisEnd(Tokens $tokens, int $structureTokenIndex): int
{
$nextIndex = $tokens->getNextMeaningfulToken($structureTokenIndex);
$nextToken = $tokens[$nextIndex];
// return if next token is not opening parenthesis
if (!$nextToken->equals('(')) {
return $structureTokenIndex;
}
return $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $nextIndex);
}
private function isFollowedByNewLine(Tokens $tokens, int $index): bool
{
for (++$index, $max = \count($tokens) - 1; $index < $max; ++$index) {
$token = $tokens[$index];
if (!$token->isComment()) {
return $token->isWhitespace() && 1 === Preg::match('/\R/', $token->getContent());
}
}
return false;
}
private function hasCommentOnSameLine(Tokens $tokens, int $index): bool
{
$token = $tokens[$index + 1];
if ($token->isWhitespace() && 1 !== Preg::match('/\R/', $token->getContent())) {
$token = $tokens[$index + 2];
}
return $token->isComment();
}
}
@@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Fixer for rules defined in PSR1 ¶2.2.
*
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
*/
final class EncodingFixer extends AbstractFixer
{
private string $BOM;
public function __construct()
{
parent::__construct();
$this->BOM = pack('CCC', 0xEF, 0xBB, 0xBF);
}
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'PHP code MUST use only UTF-8 without BOM (remove BOM).',
[
new CodeSample(
$this->BOM.'<?php
echo "Hello!";
'
),
]
);
}
/**
* {@inheritdoc}
*/
public function getPriority(): int
{
// must run first (at least before Fixers that using Tokens) - for speed reason of whole fixing process
return 100;
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return true;
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$content = $tokens[0]->getContent();
if (0 === strncmp($content, $this->BOM, 3)) {
$newContent = substr($content, 3);
if ('' === $newContent) {
$tokens->clearAt(0);
} else {
$tokens[0] = new Token([$tokens[0]->getId(), $newContent]);
}
}
}
}
@@ -0,0 +1,109 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\Indentation;
use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
use PhpCsFixer\FixerDefinition\CodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Fixer for rules defined in PSR2 ¶2.3 Lines: There must not be more than one statement per line.
*/
final class NoMultipleStatementsPerLineFixer extends AbstractFixer implements WhitespacesAwareFixerInterface
{
use Indentation;
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'There must not be more than one statement per line.',
[new CodeSample("<?php\nfoo(); bar();\n")]
);
}
/**
* {@inheritdoc}
*
* Must run after ControlStructureBracesFixer, NoEmptyStatementFixer.
*/
public function getPriority(): int
{
return -1;
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isTokenKindFound(';');
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = 1, $max = \count($tokens) - 1; $index < $max; ++$index) {
if ($tokens[$index]->isGivenKind(T_FOR)) {
$index = $tokens->findBlockEnd(
Tokens::BLOCK_TYPE_PARENTHESIS_BRACE,
$tokens->getNextTokenOfKind($index, ['('])
);
continue;
}
if (!$tokens[$index]->equals(';')) {
continue;
}
for ($nextIndex = $index + 1; $nextIndex < $max; ++$nextIndex) {
$token = $tokens[$nextIndex];
if ($token->isWhitespace() || $token->isComment()) {
if (1 === Preg::match('/\R/', $token->getContent())) {
break;
}
continue;
}
if (!$token->equalsAny(['}', [T_CLOSE_TAG], [T_ENDIF], [T_ENDFOR], [T_ENDSWITCH], [T_ENDWHILE], [T_ENDFOREACH]])) {
$whitespaceIndex = $index;
do {
$token = $tokens[++$whitespaceIndex];
} while ($token->isComment());
$newline = $this->whitespacesConfig->getLineEnding().$this->getLineIndentation($tokens, $index);
if ($tokens->ensureWhitespaceAtIndex($whitespaceIndex, 0, $newline)) {
++$max;
}
}
break;
}
}
}
}
@@ -0,0 +1,163 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\FixerConfiguration\AllowedValueSubset;
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\AttributeAnalyzer;
use PhpCsFixer\Tokenizer\CT;
use PhpCsFixer\Tokenizer\Tokens;
final class NoTrailingCommaInSinglelineFixer extends AbstractFixer implements ConfigurableFixerInterface
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'If a list of values separated by a comma is contained on a single line, then the last item MUST NOT have a trailing comma.',
[
new CodeSample("<?php\nfoo(\$a,);\n\$foo = array(1,);\n[\$foo, \$bar,] = \$array;\nuse a\\{ClassA, ClassB,};\n"),
new CodeSample("<?php\nfoo(\$a,);\n[\$foo, \$bar,] = \$array;\n", ['elements' => ['array_destructuring']]),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return
$tokens->isTokenKindFound(',')
&& $tokens->isAnyTokenKindsFound([')', CT::T_ARRAY_SQUARE_BRACE_CLOSE, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, CT::T_GROUP_IMPORT_BRACE_CLOSE])
;
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
$elements = ['arguments', 'array_destructuring', 'array', 'group_import'];
return new FixerConfigurationResolver([
(new FixerOptionBuilder('elements', 'Which elements to fix.'))
->setAllowedTypes(['array'])
->setAllowedValues([new AllowedValueSubset($elements)])
->setDefault($elements)
->getOption(),
]);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
for ($index = $tokens->count() - 1; $index >= 0; --$index) {
if (!$tokens[$index]->equals(')') && !$tokens[$index]->isGivenKind([CT::T_ARRAY_SQUARE_BRACE_CLOSE, CT::T_DESTRUCTURING_SQUARE_BRACE_CLOSE, CT::T_GROUP_IMPORT_BRACE_CLOSE])) {
continue;
}
$commaIndex = $tokens->getPrevMeaningfulToken($index);
if (!$tokens[$commaIndex]->equals(',')) {
continue;
}
$block = Tokens::detectBlockType($tokens[$index]);
$blockOpenIndex = $tokens->findBlockStart($block['type'], $index);
if ($tokens->isPartialCodeMultiline($blockOpenIndex, $index)) {
continue;
}
if (!$this->shouldBeCleared($tokens, $blockOpenIndex)) {
continue;
}
do {
$tokens->clearTokenAndMergeSurroundingWhitespace($commaIndex);
$commaIndex = $tokens->getPrevMeaningfulToken($commaIndex);
} while ($tokens[$commaIndex]->equals(','));
$tokens->removeTrailingWhitespace($commaIndex);
}
}
private function shouldBeCleared(Tokens $tokens, int $openIndex): bool
{
/** @var string[] $elements */
$elements = $this->configuration['elements'];
if ($tokens[$openIndex]->isGivenKind(CT::T_ARRAY_SQUARE_BRACE_OPEN)) {
return \in_array('array', $elements, true);
}
if ($tokens[$openIndex]->isGivenKind(CT::T_DESTRUCTURING_SQUARE_BRACE_OPEN)) {
return \in_array('array_destructuring', $elements, true);
}
if ($tokens[$openIndex]->isGivenKind(CT::T_GROUP_IMPORT_BRACE_OPEN)) {
return \in_array('group_import', $elements, true);
}
if (!$tokens[$openIndex]->equals('(')) {
return false;
}
$beforeOpen = $tokens->getPrevMeaningfulToken($openIndex);
if ($tokens[$beforeOpen]->isGivenKind(T_ARRAY)) {
return \in_array('array', $elements, true);
}
if ($tokens[$beforeOpen]->isGivenKind(T_LIST)) {
return \in_array('array_destructuring', $elements, true);
}
if ($tokens[$beforeOpen]->isGivenKind([T_UNSET, T_ISSET, T_VARIABLE, T_CLASS])) {
return \in_array('arguments', $elements, true);
}
if ($tokens[$beforeOpen]->isGivenKind(T_STRING)) {
return !AttributeAnalyzer::isAttribute($tokens, $beforeOpen) && \in_array('arguments', $elements, true);
}
if ($tokens[$beforeOpen]->equalsAny([')', ']', [CT::T_DYNAMIC_VAR_BRACE_CLOSE], [CT::T_ARRAY_INDEX_CURLY_BRACE_CLOSE]])) {
$block = Tokens::detectBlockType($tokens[$beforeOpen]);
return
(
Tokens::BLOCK_TYPE_ARRAY_INDEX_CURLY_BRACE === $block['type']
|| Tokens::BLOCK_TYPE_DYNAMIC_VAR_BRACE === $block['type']
|| Tokens::BLOCK_TYPE_INDEX_SQUARE_BRACE === $block['type']
|| Tokens::BLOCK_TYPE_PARENTHESIS_BRACE === $block['type']
) && \in_array('arguments', $elements, true)
;
}
return false;
}
}
@@ -0,0 +1,193 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
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\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
/**
* Removes Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.
*
* @author Ivan Boprzenkov <ivan.borzenkov@gmail.com>
*/
final class NonPrintableCharacterFixer extends AbstractFixer implements ConfigurableFixerInterface
{
/**
* @var array<string, string[]>
*/
private array $symbolsReplace;
/**
* @var int[]
*/
private static array $tokens = [
T_STRING_VARNAME,
T_INLINE_HTML,
T_VARIABLE,
T_COMMENT,
T_ENCAPSED_AND_WHITESPACE,
T_CONSTANT_ENCAPSED_STRING,
T_DOC_COMMENT,
];
public function __construct()
{
parent::__construct();
$this->symbolsReplace = [
pack('H*', 'e2808b') => ['', '200b'], // ZWSP U+200B
pack('H*', 'e28087') => [' ', '2007'], // FIGURE SPACE U+2007
pack('H*', 'e280af') => [' ', '202f'], // NBSP U+202F
pack('H*', 'e281a0') => ['', '2060'], // WORD JOINER U+2060
pack('H*', 'c2a0') => [' ', 'a0'], // NO-BREAK SPACE U+A0
];
}
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Remove Zero-width space (ZWSP), Non-breaking space (NBSP) and other invisible unicode symbols.',
[
new CodeSample(
'<?php echo "'.pack('H*', 'e2808b').'Hello'.pack('H*', 'e28087').'World'.pack('H*', 'c2a0')."!\";\n"
),
new CodeSample(
'<?php echo "'.pack('H*', 'e2808b').'Hello'.pack('H*', 'e28087').'World'.pack('H*', 'c2a0')."!\";\n",
['use_escape_sequences_in_strings' => false]
),
],
null,
'Risky when strings contain intended invisible characters.'
);
}
/**
* {@inheritdoc}
*/
public function isRisky(): bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound(self::$tokens);
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('use_escape_sequences_in_strings', 'Whether characters should be replaced with escape sequences in strings.'))
->setAllowedTypes(['bool'])
->setDefault(true)
->getOption(),
]);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$replacements = [];
$escapeSequences = [];
foreach ($this->symbolsReplace as $character => [$replacement, $codepoint]) {
$replacements[$character] = $replacement;
$escapeSequences[$character] = '\u{'.$codepoint.'}';
}
foreach ($tokens as $index => $token) {
$content = $token->getContent();
if (
$this->configuration['use_escape_sequences_in_strings']
&& $token->isGivenKind([T_CONSTANT_ENCAPSED_STRING, T_ENCAPSED_AND_WHITESPACE])
) {
if (!Preg::match('/'.implode('|', array_keys($escapeSequences)).'/', $content)) {
continue;
}
$previousToken = $tokens[$index - 1];
$stringTypeChanged = false;
$swapQuotes = false;
if ($previousToken->isGivenKind(T_START_HEREDOC)) {
$previousTokenContent = $previousToken->getContent();
if (str_contains($previousTokenContent, '\'')) {
$tokens[$index - 1] = new Token([T_START_HEREDOC, str_replace('\'', '', $previousTokenContent)]);
$stringTypeChanged = true;
}
} elseif (str_starts_with($content, "'")) {
$stringTypeChanged = true;
$swapQuotes = true;
}
if ($swapQuotes) {
$content = str_replace("\\'", "'", $content);
}
if ($stringTypeChanged) {
$content = Preg::replace('/(\\\\{1,2})/', '\\\\\\\\', $content);
$content = str_replace('$', '\$', $content);
}
if ($swapQuotes) {
$content = str_replace('"', '\"', $content);
$content = Preg::replace('/^\'(.*)\'$/s', '"$1"', $content);
}
$tokens[$index] = new Token([$token->getId(), strtr($content, $escapeSequences)]);
continue;
}
if ($token->isGivenKind(self::$tokens)) {
$newContent = strtr($content, $replacements);
// variable name cannot contain space
if ($token->isGivenKind([T_STRING_VARNAME, T_VARIABLE]) && str_contains($newContent, ' ')) {
continue;
}
// multiline comment must have "*/" only at the end
if ($token->isGivenKind([T_COMMENT, T_DOC_COMMENT]) && str_starts_with($newContent, '/*') && strpos($newContent, '*/') !== \strlen($newContent) - 2) {
continue;
}
$tokens[$index] = new Token([$token->getId(), $newContent]);
}
}
}
}
@@ -0,0 +1,74 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\FixerDefinition\VersionSpecification;
use PhpCsFixer\FixerDefinition\VersionSpecificCodeSample;
use PhpCsFixer\Preg;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
final class OctalNotationFixer extends AbstractFixer
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Literal octal must be in `0o` notation.',
[
new VersionSpecificCodeSample(
"<?php \$foo = 0123;\n",
new VersionSpecification(80100)
),
]
);
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return \PHP_VERSION_ID >= 80100 && $tokens->isTokenKindFound(T_LNUMBER);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
foreach ($tokens as $index => $token) {
if (!$token->isGivenKind(T_LNUMBER)) {
continue;
}
$content = $token->getContent();
if (1 !== Preg::match('#^0\d+$#', $content)) {
continue;
}
$tokens[$index] = 1 === Preg::match('#^0+$#', $content)
? new Token([T_LNUMBER, '0'])
: new Token([T_LNUMBER, '0o'.substr($content, 1)])
;
}
}
}
@@ -0,0 +1,298 @@
<?php
declare(strict_types=1);
/*
* This file is part of PHP CS Fixer.
*
* (c) Fabien Potencier <fabien@symfony.com>
* Dariusz Rumiński <dariusz.ruminski@gmail.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace PhpCsFixer\Fixer\Basic;
use PhpCsFixer\AbstractFixer;
use PhpCsFixer\Fixer\ConfigurableFixerInterface;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolver;
use PhpCsFixer\FixerConfiguration\FixerConfigurationResolverInterface;
use PhpCsFixer\FixerConfiguration\FixerOptionBuilder;
use PhpCsFixer\FixerDefinition\FileSpecificCodeSample;
use PhpCsFixer\FixerDefinition\FixerDefinition;
use PhpCsFixer\FixerDefinition\FixerDefinitionInterface;
use PhpCsFixer\Preg;
use PhpCsFixer\StdinFileInfo;
use PhpCsFixer\Tokenizer\Token;
use PhpCsFixer\Tokenizer\Tokens;
use PhpCsFixer\Tokenizer\TokensAnalyzer;
/**
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
* @author Bram Gotink <bram@gotink.me>
* @author Graham Campbell <hello@gjcampbell.co.uk>
* @author Kuba Werłos <werlos@gmail.com>
*/
final class PsrAutoloadingFixer extends AbstractFixer implements ConfigurableFixerInterface
{
/**
* {@inheritdoc}
*/
public function getDefinition(): FixerDefinitionInterface
{
return new FixerDefinition(
'Classes must be in a path that matches their namespace, be at least one namespace deep and the class name should match the file name.',
[
new FileSpecificCodeSample(
'<?php
namespace PhpCsFixer\FIXER\Basic;
class InvalidName {}
',
new \SplFileInfo(__FILE__)
),
new FileSpecificCodeSample(
'<?php
namespace PhpCsFixer\FIXER\Basic;
class InvalidName {}
',
new \SplFileInfo(__FILE__),
['dir' => './src']
),
],
null,
'This fixer may change your class name, which will break the code that depends on the old name.'
);
}
/**
* {@inheritdoc}
*/
public function configure(array $configuration): void
{
parent::configure($configuration);
if (null !== $this->configuration['dir']) {
$realpath = realpath($this->configuration['dir']);
if (false === $realpath) {
throw new \InvalidArgumentException(sprintf('Failed to resolve configured directory "%s".', $this->configuration['dir']));
}
$this->configuration['dir'] = $realpath;
}
}
/**
* {@inheritdoc}
*/
public function isCandidate(Tokens $tokens): bool
{
return $tokens->isAnyTokenKindsFound(Token::getClassyTokenKinds());
}
/**
* {@inheritdoc}
*/
public function isRisky(): bool
{
return true;
}
/**
* {@inheritdoc}
*/
public function getPriority(): int
{
return -10;
}
/**
* {@inheritdoc}
*/
public function supports(\SplFileInfo $file): bool
{
if ($file instanceof StdinFileInfo) {
return false;
}
if (
// ignore file with extension other than php
('php' !== $file->getExtension())
// ignore file with name that cannot be a class name
|| 0 === Preg::match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $file->getBasename('.php'))
) {
return false;
}
try {
$tokens = Tokens::fromCode(sprintf('<?php class %s {}', $file->getBasename('.php')));
if ($tokens[3]->isKeyword() || $tokens[3]->isMagicConstant()) {
// name cannot be a class name - detected by PHP 5.x
return false;
}
} catch (\ParseError $e) {
// name cannot be a class name - detected by PHP 7.x
return false;
}
// ignore stubs/fixtures, since they typically contain invalid files for various reasons
return !Preg::match('{[/\\\\](stub|fixture)s?[/\\\\]}i', $file->getRealPath());
}
/**
* {@inheritdoc}
*/
protected function createConfigurationDefinition(): FixerConfigurationResolverInterface
{
return new FixerConfigurationResolver([
(new FixerOptionBuilder('dir', 'If provided, the directory where the project code is placed.'))
->setAllowedTypes(['null', 'string'])
->setDefault(null)
->getOption(),
]);
}
/**
* {@inheritdoc}
*/
protected function applyFix(\SplFileInfo $file, Tokens $tokens): void
{
$tokenAnalyzer = new TokensAnalyzer($tokens);
if (null !== $this->configuration['dir'] && !str_starts_with($file->getRealPath(), $this->configuration['dir'])) {
return;
}
$namespace = null;
$namespaceStartIndex = null;
$namespaceEndIndex = null;
$classyName = null;
$classyIndex = null;
foreach ($tokens as $index => $token) {
if ($token->isGivenKind(T_NAMESPACE)) {
if (null !== $namespace) {
return;
}
$namespaceStartIndex = $tokens->getNextMeaningfulToken($index);
$namespaceEndIndex = $tokens->getNextTokenOfKind($namespaceStartIndex, [';']);
$namespace = trim($tokens->generatePartialCode($namespaceStartIndex, $namespaceEndIndex - 1));
} elseif ($token->isClassy()) {
if ($tokenAnalyzer->isAnonymousClass($index)) {
continue;
}
if (null !== $classyName) {
return;
}
$classyIndex = $tokens->getNextMeaningfulToken($index);
$classyName = $tokens[$classyIndex]->getContent();
}
}
if (null === $classyName) {
return;
}
$expectedClassyName = $this->calculateClassyName($file, $namespace, $classyName);
if ($classyName !== $expectedClassyName) {
$tokens[$classyIndex] = new Token([T_STRING, $expectedClassyName]);
}
if (null === $this->configuration['dir'] || null === $namespace) {
return;
}
if (!is_dir($this->configuration['dir'])) {
return;
}
$configuredDir = realpath($this->configuration['dir']);
$fileDir = \dirname($file->getRealPath());
if (\strlen($configuredDir) >= \strlen($fileDir)) {
return;
}
$newNamespace = substr(str_replace('/', '\\', $fileDir), \strlen($configuredDir) + 1);
$originalNamespace = substr($namespace, -\strlen($newNamespace));
if ($originalNamespace !== $newNamespace && strtolower($originalNamespace) === strtolower($newNamespace)) {
$tokens->clearRange($namespaceStartIndex, $namespaceEndIndex);
$namespace = substr($namespace, 0, -\strlen($newNamespace)).$newNamespace;
$newNamespace = Tokens::fromCode('<?php namespace '.$namespace.';');
$newNamespace->clearRange(0, 2);
$newNamespace->clearEmptyTokens();
$tokens->insertAt($namespaceStartIndex, $newNamespace);
}
}
private function calculateClassyName(\SplFileInfo $file, ?string $namespace, string $currentName): string
{
$name = $file->getBasename('.php');
$maxNamespace = $this->calculateMaxNamespace($file, $namespace);
if (null !== $this->configuration['dir']) {
return ('' !== $maxNamespace ? (str_replace('\\', '_', $maxNamespace).'_') : '').$name;
}
$namespaceParts = array_reverse(explode('\\', $maxNamespace));
foreach ($namespaceParts as $namespacePart) {
$nameCandidate = sprintf('%s_%s', $namespacePart, $name);
if (strtolower($nameCandidate) !== strtolower(substr($currentName, -\strlen($nameCandidate)))) {
break;
}
$name = $nameCandidate;
}
return $name;
}
private function calculateMaxNamespace(\SplFileInfo $file, ?string $namespace): string
{
if (null === $this->configuration['dir']) {
$root = \dirname($file->getRealPath());
while ($root !== \dirname($root)) {
$root = \dirname($root);
}
} else {
$root = realpath($this->configuration['dir']);
}
$namespaceAccordingToFileLocation = trim(str_replace(\DIRECTORY_SEPARATOR, '\\', substr(\dirname($file->getRealPath()), \strlen($root))), '\\');
if (null === $namespace) {
return $namespaceAccordingToFileLocation;
}
$namespaceAccordingToFileLocationPartsReversed = array_reverse(explode('\\', $namespaceAccordingToFileLocation));
$namespacePartsReversed = array_reverse(explode('\\', $namespace));
foreach ($namespacePartsReversed as $key => $namespaceParte) {
if (!isset($namespaceAccordingToFileLocationPartsReversed[$key])) {
break;
}
if (strtolower($namespaceParte) !== strtolower($namespaceAccordingToFileLocationPartsReversed[$key])) {
break;
}
unset($namespaceAccordingToFileLocationPartsReversed[$key]);
}
return implode('\\', array_reverse($namespaceAccordingToFileLocationPartsReversed));
}
}