From 5e5e578e8f2cc2ee9296837047b3085eff66db3f Mon Sep 17 00:00:00 2001 From: Krzysztof Rewak Date: Thu, 31 Mar 2022 10:43:56 +0200 Subject: [PATCH] #51 - removing ecs (#52) * #51 - ECS removal first attempt * #51 - docs update * #51 - double quotes fixer fixed * #51 - almost done * #51 - units 1/4 * #51 - unit tests + docs * #51 - cr fixes --- .github/workflows/check.yml | 2 +- .gitignore | 1 + ecs.php => codestyle.php | 2 +- composer.json | 15 +- readme.md | 49 ++- src/Config.php | 97 +++--- src/Configuration/AdditionalRules.php | 10 - .../Defaults/CommonAdditionalRules.php | 82 ----- src/Configuration/Defaults/CommonRules.php | 201 ++++++++++++ src/Configuration/Defaults/CommonSetLists.php | 53 ---- .../Defaults/CommonSkippedRules.php | 23 -- src/Configuration/Defaults/LaravelPaths.php | 8 +- src/Configuration/Defaults/Rules.php | 13 +- src/Configuration/{SetLists.php => Rules.php} | 2 +- src/Configuration/SkippedRules.php | 10 - src/Fixers/BinaryOperatorSpacesFixer.php | 59 ---- src/Fixers/DoubleQuoteFixer.php | 35 ++- src/Fixers/FixerWorkaround.php | 74 ----- src/Fixers/NoSpacesAfterFunctionNameFixer.php | 90 ------ tests/codestyle/CodestyleTest.php | 34 ++- tests/codestyle/config.php | 2 +- .../codestyle/fixtures/references/actual.php | 2 + .../codestyle/fixtures/unionTypes/actual.php | 3 +- .../unit/AdditionalRulesConfigurationTest.php | 288 ------------------ tests/unit/LaravelPathsConfigurationTest.php | 17 +- tests/unit/RulesConfigurationTest.php | 119 ++++++++ tests/unit/SetsConfigurationTest.php | 52 ---- tests/unit/SkippedRulesConfigurationTest.php | 98 ------ 28 files changed, 516 insertions(+), 925 deletions(-) rename ecs.php => codestyle.php (92%) delete mode 100644 src/Configuration/AdditionalRules.php delete mode 100644 src/Configuration/Defaults/CommonAdditionalRules.php create mode 100644 src/Configuration/Defaults/CommonRules.php delete mode 100644 src/Configuration/Defaults/CommonSetLists.php delete mode 100644 src/Configuration/Defaults/CommonSkippedRules.php rename src/Configuration/{SetLists.php => Rules.php} (85%) delete mode 100644 src/Configuration/SkippedRules.php delete mode 100644 src/Fixers/BinaryOperatorSpacesFixer.php delete mode 100644 src/Fixers/FixerWorkaround.php delete mode 100644 src/Fixers/NoSpacesAfterFunctionNameFixer.php delete mode 100644 tests/unit/AdditionalRulesConfigurationTest.php create mode 100644 tests/unit/RulesConfigurationTest.php delete mode 100644 tests/unit/SetsConfigurationTest.php delete mode 100644 tests/unit/SkippedRulesConfigurationTest.php diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index ae5c9c3..97f75e5 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -39,7 +39,7 @@ jobs: run: composer install --prefer-dist --no-progress - name: Run code style checker - run: composer ecs + run: composer cs - name: Run tests run: composer test diff --git a/.gitignore b/.gitignore index 7224874..93c920b 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ composer.lock .env +.php-cs-fixer.cache diff --git a/ecs.php b/codestyle.php similarity index 92% rename from ecs.php rename to codestyle.php index 9d778d2..5d2794f 100644 --- a/ecs.php +++ b/codestyle.php @@ -7,7 +7,7 @@ $config = new Config( paths: new Paths( - "ecs.php", + "codestyle.php", "src", "tests/unit", "tests/codestyle/CodestyleTest.php", diff --git a/composer.json b/composer.json index 5e05ca0..3327873 100644 --- a/composer.json +++ b/composer.json @@ -5,14 +5,13 @@ "type": "library", "require": { "php": "^8.0", - "kubawerlos/php-cs-fixer-custom-fixers": "^3.7", - "symplify/easy-coding-standard": "10.1.0" + "friendsofphp/php-cs-fixer": "^3.8.0", + "kubawerlos/php-cs-fixer-custom-fixers": "^3.7" }, "require-dev": { - "composer/composer": "2.*", "jetbrains/phpstorm-attributes": "^1.0", "phpunit/phpunit": "^9.5", - "symfony/console": "^5.3" + "symfony/console": "^6.0" }, "authors": [ { @@ -30,12 +29,10 @@ } }, "scripts": { - "ecs": "./vendor/bin/ecs check", - "ecsf": "./vendor/bin/ecs check --fix", + "cs": "./vendor/bin/php-cs-fixer fix --dry-run --diff --config codestyle.php", + "csf": "./vendor/bin/php-cs-fixer fix --diff --config codestyle.php", "test": "./vendor/bin/phpunit tests --colors always", "unit": "./vendor/bin/phpunit tests/unit --colors always", - "e2e": "./vendor/bin/phpunit tests/codestyle --colors always", - "ecs-tmp": "./vendor/bin/ecs check --config ./tests/codestyle/config.php", - "ecsf-tmp": "./vendor/bin/ecs check --config ./tests/codestyle/config.php --fix" + "e2e": "./vendor/bin/phpunit tests/codestyle --colors always" } } diff --git a/readme.md b/readme.md index 3e69c10..26c3526 100644 --- a/readme.md +++ b/readme.md @@ -9,7 +9,7 @@ Add package to our project: composer require blumilksoftware/codestyle --dev ``` -Then create `ecs.php` file in your project's root directory: +Then create `codestyle.php` file in your project's root directory: ```php config(); +return new Config(); ``` #### Configuration -You can configure paths, set lists, skipped and additional rules in `Config` constructor: +You can configure paths and rules in `Config` class constructor: ```php config(); ``` +Or: +```php +config(); +``` + + Or: ```php paths = $paths ?? new LaravelPaths(); - $this->sets = $sets ?? new CommonSetLists(); - $this->skipped = $skipped ?? new CommonSkippedRules(); - $this->rules = $rules ?? new CommonAdditionalRules(); + $this->rules = $rules ?? new CommonRules(); + $this->rootPath = $rootPath ?? getcwd(); } - public function config(): callable + public function config(): PhpCsFixerConfig { - list("paths" => $paths, "sets" => $sets, "skipped" => $skipped, "rules" => $rules) = $this->options(); + list("paths" => $paths, "rules" => $rules) = $this->options(); - return static function (Container $container) use ($sets, $skipped, $rules, $paths): void { - $parameters = $container->parameters(); - $parameters->set(Option::SKIP, $skipped); - $parameters->set(Option::PATHS, $paths); + $files = []; + foreach ($paths as $path) { + $directory = $this->rootPath . "/" . $path; + $this->getAllFiles($files, $directory); + } - foreach ($sets as $set) { - $container->import($set); - } + $finder = Finder::create()->directories()->append($files); - $services = $container->services(); - foreach ($rules as $rule => $configuration) { - $service = $services->set($rule); - if ($configuration) { - $service->call("configure", [$configuration]); - } - } - }; + $config = new PhpCsFixerConfig("Blumilk codestyle standard"); + return $config->setFinder($finder) + ->setUsingCache(false) + ->registerCustomFixers(new PhpCsFixerCustomFixers()) + ->registerCustomFixers($this->getCustomFixers()) + ->setRiskyAllowed(true) + ->setRules($rules); } - #[ArrayShape([ - "paths" => "array", - "sets" => "array", - "skipped" => "array", - "rules" => "array", - ])] + #[ArrayShape(["paths" => "array", "rules" => "array"])] public function options(): array { return [ "paths" => $this->paths->get(), - "sets" => $this->sets->get(), - "skipped" => $this->skipped->get(), "rules" => $this->rules->get(), ]; } + + protected function getAllFiles(array &$paths, string $path): void + { + if (is_file($path) || !is_dir($path)) { + $paths[] = $path; + return; + } + + $files = array_diff(scandir($path), [".", ".."]); + + foreach ($files as $file) { + $directory = $path . "/" . $file; + + if (is_file($directory)) { + $paths[] = $directory; + } else { + $this->getAllFiles($paths, $directory); + } + } + } + + protected function getCustomFixers(): array + { + return [ + new DoubleQuoteFixer(), + ]; + } } diff --git a/src/Configuration/AdditionalRules.php b/src/Configuration/AdditionalRules.php deleted file mode 100644 index 1b9b857..0000000 --- a/src/Configuration/AdditionalRules.php +++ /dev/null @@ -1,10 +0,0 @@ - null, - CastSpacesFixer::class => [ - "space" => "none", - ], - DoubleQuoteFixer::class => null, - VoidReturnFixer::class => null, - UseArrowFunctionsFixer::class => null, - NoSpacesAfterFunctionNameFixer::class => null, - FullyQualifiedStrictTypesFixer::class => null, - OrderedImportsFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - PhpdocLineSpanFixer::class => [ - "const" => "single", - "property" => "single", - ], - GeneralPhpdocAnnotationRemoveFixer::class => [ - "annotations" => [ - "package", - "author", - ], - ], - NoExtraBlankLinesFixer::class => [ - "tokens" => [ - "extra", - "curly_brace_block", - "parenthesis_brace_block", - "square_brace_block", - ], - ], - OperatorSpacingSniff::class => null, - TrailingCommaInMultilineFixer::class => [ - "elements" => [ - "arrays", - "parameters", - "arguments", - ], - ], - NullableTypeDeclarationForDefaultNullValueFixer::class => null, - ConstructorEmptyBracesFixer::class => null, - MultilinePromotedPropertiesFixer::class => null, - NoUselessCommentFixer::class => null, - PhpdocArrayStyleFixer::class => null, - PromotedConstructorPropertyFixer::class => null, - SingleSpaceAfterStatementFixer::class => null, - SingleSpaceBeforeStatementFixer::class => null, - StringableInterfaceFixer::class => null, - ]; -} diff --git a/src/Configuration/Defaults/CommonRules.php b/src/Configuration/Defaults/CommonRules.php new file mode 100644 index 0000000..a93db6f --- /dev/null +++ b/src/Configuration/Defaults/CommonRules.php @@ -0,0 +1,201 @@ + true, + ArrayIndentationFixer::class => true, + TrimArraySpacesFixer::class => true, + WhitespaceAfterCommaInArrayFixer::class => true, + NoTrailingCommaInSinglelineArrayFixer::class => true, + ArraySyntaxFixer::class => ["syntax" => "short"], + PhpUnitMethodCasingFixer::class => true, + FunctionToConstantFixer::class => true, + ExplicitStringVariableFixer::class => true, + ExplicitIndirectVariableFixer::class => true, + SingleClassElementPerStatementFixer::class => ["elements" => ["const", "property"]], + NewWithBracesFixer::class => true, + ClassDefinitionFixer::class => ["single_line" => true], + StandardizeIncrementFixer::class => true, + SelfAccessorFixer::class => true, + MagicConstantCasingFixer::class => true, + NoUselessElseFixer::class => true, + OrderedClassElementsFixer::class => true, + NoTrailingWhitespaceInCommentFixer::class => true, + PhpdocTrimConsecutiveBlankLineSeparationFixer::class => true, + PhpdocTrimFixer::class => true, + NoEmptyPhpdocFixer::class => true, + PhpdocNoEmptyReturnFixer::class => true, + PhpdocIndentFixer::class => true, + PhpdocTypesFixer::class => true, + PhpdocReturnSelfReferenceFixer::class => true, + PhpdocVarWithoutNameFixer::class => true, + NoSuperfluousPhpdocTagsFixer::class => ["remove_inheritdoc" => true, "allow_mixed" => true], + SingleBlankLineBeforeNamespaceFixer::class => true, + PhpUnitTestAnnotationFixer::class => true, + PhpUnitSetUpTearDownVisibilityFixer::class => true, + BlankLineAfterOpeningTagFixer::class => true, + MethodChainingIndentationFixer::class => true, + ConcatSpaceFixer::class => ["spacing" => "one"], + BinaryOperatorSpacesFixer::class => ["operators" => ["=>" => "single_space", "=" => "single_space", "&" => "no_space"]], + SingleTraitInsertPerStatementFixer::class => true, + FunctionTypehintSpaceFixer::class => true, + NoBlankLinesAfterClassOpeningFixer::class => true, + NoSinglelineWhitespaceBeforeSemicolonsFixer::class => true, + PhpdocSingleLineVarSpacingFixer::class => true, + NoLeadingNamespaceWhitespaceFixer::class => true, + NoSpacesAroundOffsetFixer::class => true, + NoWhitespaceInBlankLineFixer::class => true, + ReturnTypeDeclarationFixer::class => true, + SpaceAfterSemicolonFixer::class => true, + TernaryOperatorSpacesFixer::class => true, + MethodArgumentSpaceFixer::class => true, + StrictComparisonFixer::class => true, + IsNullFixer::class => true, + StrictParamFixer::class => true, + NoUnusedImportsFixer::class => null, + NoEmptyStatementFixer::class => null, + NoUnneededControlParenthesesFixer::class => null, + NoUnneededCurlyBracesFixer::class => null, + DeclareStrictTypesFixer::class => null, + CastSpacesFixer::class => [ + "space" => "none", + ], + DoubleQuoteFixer::class => null, + VoidReturnFixer::class => null, + UseArrowFunctionsFixer::class => null, + FullyQualifiedStrictTypesFixer::class => null, + OrderedImportsFixer::class => null, + PhpdocLineSpanFixer::class => [ + "const" => "single", + "property" => "single", + ], + GeneralPhpdocAnnotationRemoveFixer::class => [ + "annotations" => [ + "package", + "author", + ], + ], + NoExtraBlankLinesFixer::class => [ + "tokens" => [ + "extra", + "curly_brace_block", + "parenthesis_brace_block", + "square_brace_block", + ], + ], + TrailingCommaInMultilineFixer::class => [ + "elements" => [ + "arrays", + "parameters", + "arguments", + ], + ], + NullableTypeDeclarationForDefaultNullValueFixer::class => null, + ConstructorEmptyBracesFixer::class => null, + MultilinePromotedPropertiesFixer::class => null, + NoUselessCommentFixer::class => null, + PhpdocArrayStyleFixer::class => null, + PromotedConstructorPropertyFixer::class => null, + SingleSpaceAfterStatementFixer::class => null, + SingleSpaceBeforeStatementFixer::class => null, + StringableInterfaceFixer::class => null, + VisibilityRequiredFixer::class => null, + NoLeadingImportSlashFixer::class => null, + LowercaseCastFixer::class => null, + LowercaseStaticReferenceFixer::class => null, + CompactNullableTypehintFixer::class => null, + DeclareEqualNormalizeFixer::class => null, + ShortScalarCastFixer::class => null, + CleanNamespaceFixer::class => null, + UnaryOperatorSpacesFixer::class => null, + ]; +} diff --git a/src/Configuration/Defaults/CommonSetLists.php b/src/Configuration/Defaults/CommonSetLists.php deleted file mode 100644 index 533c5e6..0000000 --- a/src/Configuration/Defaults/CommonSetLists.php +++ /dev/null @@ -1,53 +0,0 @@ -setLists; - } - - public function add(string ...$setLists): static - { - foreach ($setLists as $setList) { - if (!in_array($setList, $this->setLists, true)) { - $this->setLists[] = $setList; - } - } - - return $this; - } - - public function clear(): static - { - $this->setLists = []; - - return $this; - } - - public function filter(string ...$setLists): static - { - foreach ($this->setLists as $index => $setList) { - if (in_array($setList, $setLists, true)) { - unset($this->setLists[$index]); - } - } - - $this->setLists = array_values($this->setLists); - - return $this; - } -} diff --git a/src/Configuration/Defaults/CommonSkippedRules.php b/src/Configuration/Defaults/CommonSkippedRules.php deleted file mode 100644 index 45bc837..0000000 --- a/src/Configuration/Defaults/CommonSkippedRules.php +++ /dev/null @@ -1,23 +0,0 @@ - null, - ClassAttributesSeparationFixer::class => null, - NotOperatorWithSuccessorSpaceFixer::class => null, - ReturnAssignmentFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - ]; -} diff --git a/src/Configuration/Defaults/LaravelPaths.php b/src/Configuration/Defaults/LaravelPaths.php index 19ef568..afacef0 100644 --- a/src/Configuration/Defaults/LaravelPaths.php +++ b/src/Configuration/Defaults/LaravelPaths.php @@ -6,5 +6,11 @@ class LaravelPaths extends Paths { - protected array $paths = ["app", "config", "database", "resources/lang", "routes", "tests"]; + public const LARAVEL_8_PATHS = ["app", "bootstrap/app.php", "config", "database", "public/index.php", "resources/lang", "routes", "tests"]; + public const LARAVEL_9_PATHS = ["app", "bootstrap/app.php", "config", "database", "lang", "public/index.php", "routes", "tests"]; + + public function __construct(array $paths = self::LARAVEL_9_PATHS) + { + parent::__construct(...$paths); + } } diff --git a/src/Configuration/Defaults/Rules.php b/src/Configuration/Defaults/Rules.php index 330201d..be34feb 100644 --- a/src/Configuration/Defaults/Rules.php +++ b/src/Configuration/Defaults/Rules.php @@ -4,15 +4,24 @@ namespace Blumilk\Codestyle\Configuration\Defaults; +use Blumilk\Codestyle\Configuration\Rules as RulesContract; use Blumilk\Codestyle\Configuration\Utils\Rule; +use PhpCsFixerCustomFixers\Fixer\AbstractFixer; -class Rules +abstract class Rules implements RulesContract { protected array $rules = []; public function get(): array { - return $this->rules; + $rules = []; + foreach ($this->rules as $fixer => $options) { + /** @var AbstractFixer $fixer */ + $fixer = new $fixer(); + $rules[$fixer->getName()] = $options === null ? true : $options; + } + + return $rules; } public function add(Rule ...$rules): static diff --git a/src/Configuration/SetLists.php b/src/Configuration/Rules.php similarity index 85% rename from src/Configuration/SetLists.php rename to src/Configuration/Rules.php index bc36ddd..3e60292 100644 --- a/src/Configuration/SetLists.php +++ b/src/Configuration/Rules.php @@ -4,7 +4,7 @@ namespace Blumilk\Codestyle\Configuration; -interface SetLists +interface Rules { public function get(): array; } diff --git a/src/Configuration/SkippedRules.php b/src/Configuration/SkippedRules.php deleted file mode 100644 index ab43ab3..0000000 --- a/src/Configuration/SkippedRules.php +++ /dev/null @@ -1,10 +0,0 @@ -fixer = new BaseBinaryOperatorSpacesFixer(); - parent::__construct(); - } - - protected function getFixer(): BaseBinaryOperatorSpacesFixer - { - return $this->fixer; - } - - protected function applyFix(SplFileInfo $file, Tokens $tokens): void - { - $this->tokensAnalyzer = new TokensAnalyzer($tokens); - - for ($index = $tokens->count() - 2; $index > 0; --$index) { - if ($tokens[$index]->getContent() === "|" && $tokens[$index]->getId() === CT::T_TYPE_ALTERNATION) { - continue; - } - - if (!$this->tokensAnalyzer->isBinaryOperator($index)) { - continue; - } - - if ($tokens[$index]->getContent() === "=") { - $isDeclare = $this->isEqualPartOfDeclareStatement($tokens, $index); - if ($isDeclare === false) { - $this->fixWhiteSpaceAroundOperator($tokens, $index); - } else { - $index = $isDeclare; - } - } else { - $this->fixWhiteSpaceAroundOperator($tokens, $index); - } - - --$index; - } - - if (\count($this->alignOperatorTokens)) { - $this->fixAlignment($tokens, $this->alignOperatorTokens); - } - } -} diff --git a/src/Fixers/DoubleQuoteFixer.php b/src/Fixers/DoubleQuoteFixer.php index 75a55a5..6d36696 100644 --- a/src/Fixers/DoubleQuoteFixer.php +++ b/src/Fixers/DoubleQuoteFixer.php @@ -4,14 +4,14 @@ namespace Blumilk\Codestyle\Fixers; -use PhpCsFixer\AbstractFixer; +use PhpCsFixer\Fixer\FixerInterface; use PhpCsFixer\FixerDefinition\CodeSample; use PhpCsFixer\FixerDefinition\FixerDefinition; use PhpCsFixer\Tokenizer\Token; use PhpCsFixer\Tokenizer\Tokens; use SplFileInfo; -final class DoubleQuoteFixer extends AbstractFixer +final class DoubleQuoteFixer implements FixerInterface { public function getDefinition(): FixerDefinition { @@ -33,6 +33,33 @@ public function isCandidate(Tokens $tokens): bool return $tokens->isTokenKindFound(T_CONSTANT_ENCAPSED_STRING); } + public function isRisky(): bool + { + return false; + } + + public function fix(SplFileInfo $file, Tokens $tokens): void + { + if ($tokens->count() > 0 && $this->isCandidate($tokens) && $this->supports($file)) { + $this->applyFix($file, $tokens); + } + } + + public function getName(): string + { + return "Blumilk/double_quote"; + } + + public function getPriority(): int + { + return 0; + } + + public function supports(SplFileInfo $file): bool + { + return true; + } + protected function applyFix(SplFileInfo $file, Tokens $tokens): void { foreach ($tokens as $index => $token) { @@ -50,9 +77,9 @@ protected function applyFix(SplFileInfo $file, Tokens $tokens): void ) { $content = substr($content, 1, -1); $content = str_replace("\\'", "'", $content); - $content = str_replace("\\$", "$", $content); + $content = str_replace("$", "$", $content); - $tokens[$index] = new Token([T_CONSTANT_ENCAPSED_STRING, $prefix . "\"" . $content . "\""]); + $tokens[$index] = new Token([T_CONSTANT_ENCAPSED_STRING, $prefix . '"' . $content . '"']); } } } diff --git a/src/Fixers/FixerWorkaround.php b/src/Fixers/FixerWorkaround.php deleted file mode 100644 index 0025ba5..0000000 --- a/src/Fixers/FixerWorkaround.php +++ /dev/null @@ -1,74 +0,0 @@ -reflection = new ReflectionClass(get_class($this->getFixer())); - } - - /** - * @throws ReflectionException - */ - public function __call(string $name, array $arguments = []): void - { - if (method_exists($this, $name)) { - $this->{$name}(...$arguments); - } - - $reflectedMethod = $this->reflection->getMethod($name); - $reflectedMethod->setAccessible(true); - $reflectedMethod->invoke($this->getFixer(), ...$arguments); - } - - /** - * @throws ReflectionException - */ - public function __get(string $name): mixed - { - $reflectedProperty = $this->reflection->getProperty($name); - $reflectedProperty->setAccessible(true); - return $reflectedProperty->getValue($this->getFixer()); - } - - /** - * @throws ReflectionException - */ - public function __set(string $name, mixed $value): void - { - $reflectedProperty = $this->reflection->getProperty($name); - $reflectedProperty->setAccessible(true); - $reflectedProperty->setValue($this->getFixer(), $value); - } - - public function getDefinition(): FixerDefinition - { - return $this->getFixer()->getDefinition(); - } - - public function isCandidate(Tokens $tokens): bool - { - return $this->getFixer()->isCandidate($tokens); - } - - abstract protected function applyFix(SplFileInfo $file, Tokens $tokens): void; - - abstract protected function getFixer(): AbstractFixer; -} diff --git a/src/Fixers/NoSpacesAfterFunctionNameFixer.php b/src/Fixers/NoSpacesAfterFunctionNameFixer.php deleted file mode 100644 index fc49712..0000000 --- a/src/Fixers/NoSpacesAfterFunctionNameFixer.php +++ /dev/null @@ -1,90 +0,0 @@ -fixer = new BaseNoSpacesAfterFunctionNameFixer(); - parent::__construct(); - } - - protected function getFixer(): BaseNoSpacesAfterFunctionNameFixer - { - return $this->fixer; - } - - protected function applyFix(SplFileInfo $file, Tokens $tokens): void - { - $functionyTokens = $this->getFunctionyTokenKinds(); - $languageConstructionTokens = $this->getLanguageConstructionTokenKinds(); - $braceTypes = $this->getBraceAfterVariableKinds(); - - foreach ($tokens as $index => $token) { - if (!$token->equals("(")) { - continue; - } - - $lastTokenIndex = $tokens->getPrevNonWhitespace($index); - - $endParenthesisIndex = $tokens->findBlockEnd(Tokens::BLOCK_TYPE_PARENTHESIS_BRACE, $index); - $nextNonWhiteSpace = $tokens->getNextMeaningfulToken($endParenthesisIndex); - if ( - $nextNonWhiteSpace !== null - && $tokens[$nextNonWhiteSpace]->equals("?") - && $tokens[$lastTokenIndex]->isGivenKind($languageConstructionTokens) - ) { - continue; - } - - if ($tokens[$lastTokenIndex]->isGivenKind($functionyTokens)) { - $this->fixFunctionCall($tokens, $index); - } elseif ($tokens[$lastTokenIndex]->isGivenKind(T_STRING)) { - $possibleDefinitionIndex = $tokens->getPrevMeaningfulToken($lastTokenIndex); - if (!$tokens[$possibleDefinitionIndex]->isGivenKind(T_FUNCTION)) { - $this->fixFunctionCall($tokens, $index); - } - } elseif ($tokens[$lastTokenIndex]->equalsAny($braceTypes ?? [])) { - $block = Tokens::detectBlockType($tokens[$lastTokenIndex]); - if ( - $block["type"] === 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 - ) { - $this->fixFunctionCall($tokens, $index); - } - } - } - } - - protected function getFunctionyTokenKinds(): array - { - return [ - T_ARRAY, - T_ECHO, - T_EMPTY, - T_EVAL, - T_EXIT, - T_INCLUDE, - T_INCLUDE_ONCE, - T_ISSET, - T_LIST, - T_PRINT, - T_REQUIRE, - T_REQUIRE_ONCE, - T_UNSET, - T_VARIABLE, - T_FN, - ]; - } -} diff --git a/tests/codestyle/CodestyleTest.php b/tests/codestyle/CodestyleTest.php index b99e264..67149c5 100644 --- a/tests/codestyle/CodestyleTest.php +++ b/tests/codestyle/CodestyleTest.php @@ -2,7 +2,10 @@ declare(strict_types=1); +use PhpCsFixer\Console\Application; use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Input\StringInput; +use Symfony\Component\Console\Output\BufferedOutput; class CodestyleTest extends TestCase { @@ -23,7 +26,6 @@ protected function tearDown(): void public function testPhp80Fixtures(): void { $fixtures = [ - "noExtraBlankLines", "noExtraBlankLines", "nullableTypeForDefaultNull", "operatorSpacing", @@ -58,13 +60,15 @@ public function testPhp81Fixtures(): void /** * @throws Exception */ - protected function runComposerEcsCommand(bool $fix = false): bool + protected function runFixer(bool $fix = false): bool { - $command = $fix ? "ecsf-tmp" : "ecs-tmp"; - $result = 0; - $output = null; + $dryRun = $fix ? "" : "--dry-run"; + + $application = new Application(); + $application->setAutoExit(false); - exec("./vendor/bin/composer " . $command . " 2> /dev/null", $output, $result); + $output = new BufferedOutput(); + $result = $application->run(new StringInput("fix ${dryRun} --diff --config ./tests/codestyle/config.php"), $output); return $result === 0; } @@ -76,9 +80,21 @@ protected function testFixture(string $name): void { copy(__DIR__ . "/fixtures/${name}/actual.php", __DIR__ . "/tmp/${name}.php"); - $this->assertFalse($this->runComposerEcsCommand(), "Fixture fixtures/${name} returned invalid true result."); - $this->assertTrue($this->runComposerEcsCommand(true), "Fixture fixtures/${name} was not proceeded properly."); - $this->assertFileEquals(__DIR__ . "/fixtures/${name}/expected.php", __DIR__ . "/tmp/${name}.php", "Result of proceeded fixture fixtures/${name} is not equal to expected."); + $this->assertFalse( + $this->runFixer(), + "Fixture fixtures/${name} returned invalid true result.", + ); + + $this->assertTrue( + $this->runFixer(fix: true), + "Fixture fixtures/${name} was not proceeded properly.", + ); + + $this->assertFileEquals( + __DIR__ . "/fixtures/${name}/expected.php", + __DIR__ . "/tmp/${name}.php", + "Result of proceeded fixture fixtures/${name} is not equal to expected.", + ); } protected function clearTempDirectory(): void diff --git a/tests/codestyle/config.php b/tests/codestyle/config.php index 0a76ba6..6d01a8c 100644 --- a/tests/codestyle/config.php +++ b/tests/codestyle/config.php @@ -6,7 +6,7 @@ use Blumilk\Codestyle\Configuration\Defaults\Paths; $config = new Config( - paths: new Paths("./tests/codestyle/tmp"), + paths: new Paths("tests/codestyle/tmp"), ); return $config->config(); diff --git a/tests/codestyle/fixtures/references/actual.php b/tests/codestyle/fixtures/references/actual.php index 05370ce..f287541 100644 --- a/tests/codestyle/fixtures/references/actual.php +++ b/tests/codestyle/fixtures/references/actual.php @@ -1,5 +1,7 @@ assertSame( - [ - DeclareStrictTypesFixer::class => null, - CastSpacesFixer::class => [ - "space" => "none", - ], - DoubleQuoteFixer::class => null, - VoidReturnFixer::class => null, - UseArrowFunctionsFixer::class => null, - NoSpacesAfterFunctionNameFixer::class => null, - FullyQualifiedStrictTypesFixer::class => null, - OrderedImportsFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - PhpdocLineSpanFixer::class => [ - "const" => "single", - "property" => "single", - ], - GeneralPhpdocAnnotationRemoveFixer::class => [ - "annotations" => [ - "package", - "author", - ], - ], - NoExtraBlankLinesFixer::class => [ - "tokens" => [ - "extra", - "curly_brace_block", - "parenthesis_brace_block", - "square_brace_block", - ], - ], - OperatorSpacingSniff::class => null, - TrailingCommaInMultilineFixer::class => [ - "elements" => [ - "arrays", - "parameters", - "arguments", - ], - ], - NullableTypeDeclarationForDefaultNullValueFixer::class => null, - ConstructorEmptyBracesFixer::class => null, - MultilinePromotedPropertiesFixer::class => null, - NoUselessCommentFixer::class => null, - PhpdocArrayStyleFixer::class => null, - PromotedConstructorPropertyFixer::class => null, - SingleSpaceAfterStatementFixer::class => null, - SingleSpaceBeforeStatementFixer::class => null, - StringableInterfaceFixer::class => null, - ], - $config->options()["rules"], - ); - } - - public function testClearingAdditionalRulesConfiguration(): void - { - $rules = new CommonAdditionalRules(); - $config = new Config(rules: $rules->clear()); - - $this->assertSame([], $config->options()["rules"]); - } - - public function testFilteringAdditionalRulesConfiguration(): void - { - $rules = new CommonAdditionalRules(); - $config = new Config(rules: $rules->filter(CastSpacesFixer::class)); - - $this->assertSame( - [ - DeclareStrictTypesFixer::class => null, - DoubleQuoteFixer::class => null, - VoidReturnFixer::class => null, - UseArrowFunctionsFixer::class => null, - NoSpacesAfterFunctionNameFixer::class => null, - FullyQualifiedStrictTypesFixer::class => null, - OrderedImportsFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - PhpdocLineSpanFixer::class => [ - "const" => "single", - "property" => "single", - ], - GeneralPhpdocAnnotationRemoveFixer::class => [ - "annotations" => [ - "package", - "author", - ], - ], - NoExtraBlankLinesFixer::class => [ - "tokens" => [ - "extra", - "curly_brace_block", - "parenthesis_brace_block", - "square_brace_block", - ], - ], - OperatorSpacingSniff::class => null, - TrailingCommaInMultilineFixer::class => [ - "elements" => [ - "arrays", - "parameters", - "arguments", - ], - ], - NullableTypeDeclarationForDefaultNullValueFixer::class => null, - ConstructorEmptyBracesFixer::class => null, - MultilinePromotedPropertiesFixer::class => null, - NoUselessCommentFixer::class => null, - PhpdocArrayStyleFixer::class => null, - PromotedConstructorPropertyFixer::class => null, - SingleSpaceAfterStatementFixer::class => null, - SingleSpaceBeforeStatementFixer::class => null, - StringableInterfaceFixer::class => null, - ], - $config->options()["rules"], - ); - } - - public function testExtendingAdditionalRulesConfiguration(): void - { - $rules = new CommonAdditionalRules(); - $config = new Config( - rules: $rules->add(new Rule(HeredocToNowdocFixer::class)), - ); - - $this->assertSame( - [ - DeclareStrictTypesFixer::class => null, - CastSpacesFixer::class => [ - "space" => "none", - ], - DoubleQuoteFixer::class => null, - VoidReturnFixer::class => null, - UseArrowFunctionsFixer::class => null, - NoSpacesAfterFunctionNameFixer::class => null, - FullyQualifiedStrictTypesFixer::class => null, - OrderedImportsFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - PhpdocLineSpanFixer::class => [ - "const" => "single", - "property" => "single", - ], - GeneralPhpdocAnnotationRemoveFixer::class => [ - "annotations" => [ - "package", - "author", - ], - ], - NoExtraBlankLinesFixer::class => [ - "tokens" => [ - "extra", - "curly_brace_block", - "parenthesis_brace_block", - "square_brace_block", - ], - ], - OperatorSpacingSniff::class => null, - TrailingCommaInMultilineFixer::class => [ - "elements" => [ - "arrays", - "parameters", - "arguments", - ], - ], - NullableTypeDeclarationForDefaultNullValueFixer::class => null, - ConstructorEmptyBracesFixer::class => null, - MultilinePromotedPropertiesFixer::class => null, - NoUselessCommentFixer::class => null, - PhpdocArrayStyleFixer::class => null, - PromotedConstructorPropertyFixer::class => null, - SingleSpaceAfterStatementFixer::class => null, - SingleSpaceBeforeStatementFixer::class => null, - StringableInterfaceFixer::class => null, - HeredocToNowdocFixer::class => null, - ], - $config->options()["rules"], - ); - } - - public function testExtendingWithOptionsAdditionalRulesConfiguration(): void - { - $rules = new CommonAdditionalRules(); - $rule = new Rule( - NoMixedEchoPrintFixer::class, - [ - "use" => "echo", - ], - ); - - $config = new Config( - rules: $rules->add($rule), - ); - - $this->assertSame( - [ - DeclareStrictTypesFixer::class => null, - CastSpacesFixer::class => [ - "space" => "none", - ], - DoubleQuoteFixer::class => null, - VoidReturnFixer::class => null, - UseArrowFunctionsFixer::class => null, - NoSpacesAfterFunctionNameFixer::class => null, - FullyQualifiedStrictTypesFixer::class => null, - OrderedImportsFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - PhpdocLineSpanFixer::class => [ - "const" => "single", - "property" => "single", - ], - GeneralPhpdocAnnotationRemoveFixer::class => [ - "annotations" => [ - "package", - "author", - ], - ], - NoExtraBlankLinesFixer::class => [ - "tokens" => [ - "extra", - "curly_brace_block", - "parenthesis_brace_block", - "square_brace_block", - ], - ], - OperatorSpacingSniff::class => null, - TrailingCommaInMultilineFixer::class => [ - "elements" => [ - "arrays", - "parameters", - "arguments", - ], - ], - NullableTypeDeclarationForDefaultNullValueFixer::class => null, - ConstructorEmptyBracesFixer::class => null, - MultilinePromotedPropertiesFixer::class => null, - NoUselessCommentFixer::class => null, - PhpdocArrayStyleFixer::class => null, - PromotedConstructorPropertyFixer::class => null, - SingleSpaceAfterStatementFixer::class => null, - SingleSpaceBeforeStatementFixer::class => null, - StringableInterfaceFixer::class => null, - NoMixedEchoPrintFixer::class => [ - "use" => "echo", - ], - ], - $config->options()["rules"], - ); - } -} diff --git a/tests/unit/LaravelPathsConfigurationTest.php b/tests/unit/LaravelPathsConfigurationTest.php index ab91e37..7702641 100644 --- a/tests/unit/LaravelPathsConfigurationTest.php +++ b/tests/unit/LaravelPathsConfigurationTest.php @@ -14,7 +14,18 @@ public function testLaravelPathsConfiguration(): void $config = new Config(paths: $paths); $this->assertSame( - ["app", "config", "database", "resources/lang", "routes", "tests"], + ["app", "bootstrap/app.php", "config", "database", "lang", "public/index.php", "routes", "tests"], + $config->options()["paths"], + ); + } + + public function testPreviousLaravelVersionPathsConfiguration(): void + { + $paths = new LaravelPaths(LaravelPaths::LARAVEL_8_PATHS); + $config = new Config(paths: $paths); + + $this->assertSame( + ["app", "bootstrap/app.php", "config", "database", "public/index.php", "resources/lang", "routes", "tests"], $config->options()["paths"], ); } @@ -22,10 +33,10 @@ public function testLaravelPathsConfiguration(): void public function testFilteredLaravelPathsConfiguration(): void { $paths = new LaravelPaths(); - $config = new Config(paths: $paths->filter("resources/lang")); + $config = new Config(paths: $paths->filter("lang")); $this->assertSame( - ["app", "config", "database", "routes", "tests"], + ["app", "bootstrap/app.php", "config", "database", "public/index.php", "routes", "tests"], $config->options()["paths"], ); } diff --git a/tests/unit/RulesConfigurationTest.php b/tests/unit/RulesConfigurationTest.php new file mode 100644 index 0000000..f71bb11 --- /dev/null +++ b/tests/unit/RulesConfigurationTest.php @@ -0,0 +1,119 @@ + true, + ArrayIndentationFixer::class => true, + ]; + }; + $config = new Config(rules: $rules); + + $this->assertSame( + [ + "no_whitespace_before_comma_in_array" => true, + "array_indentation" => true, + ], + $config->options()["rules"], + ); + } + + public function testClearingRulesConfiguration(): void + { + $rules = new class() extends Rules { + protected array $rules = [ + NoWhitespaceBeforeCommaInArrayFixer::class => true, + ArrayIndentationFixer::class => true, + ]; + }; + $config = new Config(rules: $rules->clear()); + + $this->assertSame([], $config->options()["rules"]); + } + + public function testFilteringRulesConfiguration(): void + { + $rules = new class() extends Rules { + protected array $rules = [ + NoWhitespaceBeforeCommaInArrayFixer::class => true, + ArrayIndentationFixer::class => true, + ]; + }; + $config = new Config(rules: $rules->filter(NoWhitespaceBeforeCommaInArrayFixer::class)); + + $this->assertSame( + [ + "array_indentation" => true, + ], + $config->options()["rules"], + ); + } + + public function testExtendingRulesConfiguration(): void + { + $rules = new class() extends Rules { + protected array $rules = [ + NoWhitespaceBeforeCommaInArrayFixer::class => true, + ArrayIndentationFixer::class => true, + ]; + }; + + $config = new Config( + rules: $rules->add(new Rule(TrimArraySpacesFixer::class)), + ); + + $this->assertSame( + [ + "no_whitespace_before_comma_in_array" => true, + "array_indentation" => true, + "trim_array_spaces" => true, + ], + $config->options()["rules"], + ); + } + + public function testExtendingWithOptionsRulesConfiguration(): void + { + $rules = new class() extends Rules { + protected array $rules = [ + NoWhitespaceBeforeCommaInArrayFixer::class => true, + ArrayIndentationFixer::class => true, + ]; + }; + $rule = new Rule( + NoMixedEchoPrintFixer::class, + [ + "use" => "echo", + ], + ); + + $config = new Config( + rules: $rules->add($rule), + ); + + $this->assertSame( + [ + "no_whitespace_before_comma_in_array" => true, + "array_indentation" => true, + "no_mixed_echo_print" => [ + "use" => "echo", + ], + ], + $config->options()["rules"], + ); + } +} diff --git a/tests/unit/SetsConfigurationTest.php b/tests/unit/SetsConfigurationTest.php deleted file mode 100644 index 2858f54..0000000 --- a/tests/unit/SetsConfigurationTest.php +++ /dev/null @@ -1,52 +0,0 @@ -assertSame([ - SetList::CLEAN_CODE, - SetList::PSR_12, - SetList::COMMON, - ], $config->options()["sets"]); - } - - public function testClearingSetsConfiguration(): void - { - $sets = new CommonSetLists(); - $config = new Config(sets: $sets->clear()); - - $this->assertSame([], $config->options()["sets"]); - } - - public function testFilteringSetsConfiguration(): void - { - $sets = new CommonSetLists(); - $config = new Config(sets: $sets->filter(SetList::CLEAN_CODE)); - - $this->assertSame([SetList::PSR_12, SetList::COMMON], $config->options()["sets"]); - } - - public function testExtendingSetsConfiguration(): void - { - $sets = new CommonSetLists(); - $config = new Config(sets: $sets->add(SetList::COMMENTS)); - - $this->assertSame([ - SetList::CLEAN_CODE, - SetList::PSR_12, - SetList::COMMON, - SetList::COMMENTS, - ], $config->options()["sets"]); - } -} diff --git a/tests/unit/SkippedRulesConfigurationTest.php b/tests/unit/SkippedRulesConfigurationTest.php deleted file mode 100644 index f78c7f2..0000000 --- a/tests/unit/SkippedRulesConfigurationTest.php +++ /dev/null @@ -1,98 +0,0 @@ -assertSame( - [ - SingleQuoteFixer::class => null, - ClassAttributesSeparationFixer::class => null, - NotOperatorWithSuccessorSpaceFixer::class => null, - ReturnAssignmentFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - ], - $config->options()["skipped"], - ); - } - - public function testClearingSkippedRulesConfiguration(): void - { - $skipped = new CommonSkippedRules(); - $config = new Config(skipped: $skipped->clear()); - - $this->assertSame([], $config->options()["skipped"]); - } - - public function testFilteringSkippedRulesConfiguration(): void - { - $skipped = new CommonSkippedRules(); - $config = new Config(skipped: $skipped->filter(ReturnAssignmentFixer::class, SingleQuoteFixer::class)); - - $this->assertSame( - [ - ClassAttributesSeparationFixer::class => null, - NotOperatorWithSuccessorSpaceFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - ], - $config->options()["skipped"], - ); - } - - public function testExtendingSkippedRulesConfiguration(): void - { - $skipped = new CommonSkippedRules(); - $config = new Config( - skipped: $skipped->add(new Rule(LogicalOperatorsFixer::class)), - ); - - $this->assertSame( - [ - SingleQuoteFixer::class => null, - ClassAttributesSeparationFixer::class => null, - NotOperatorWithSuccessorSpaceFixer::class => null, - ReturnAssignmentFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - LogicalOperatorsFixer::class => null, - ], - $config->options()["skipped"], - ); - } - - public function testExtendingWithOptionsSkippedRulesConfiguration(): void - { - $skipped = new CommonSkippedRules(); - $config = new Config( - skipped: $skipped->add(new Rule(ArraySyntaxFixer::class, [__DIR__ . "/test"])), - ); - - $this->assertSame( - [ - SingleQuoteFixer::class => null, - ClassAttributesSeparationFixer::class => null, - NotOperatorWithSuccessorSpaceFixer::class => null, - ReturnAssignmentFixer::class => null, - BinaryOperatorSpacesFixer::class => null, - ArraySyntaxFixer::class => [__DIR__ . "/test"], - ], - $config->options()["skipped"], - ); - } -}