diff --git a/.github/workflows/qa.yaml b/.github/workflows/qa.yaml index 2d585472..3aaf2f75 100644 --- a/.github/workflows/qa.yaml +++ b/.github/workflows/qa.yaml @@ -54,5 +54,5 @@ jobs: dependency-versions: highest composer-options: --prefer-dist --prefer-stable - - name: Run PHP Code Sniffer + - name: Run Psalm run: vendor/bin/psalm --no-progress --output-format=github --shepherd diff --git a/docs/configuration.md b/docs/configuration.md index c31f8dd8..dc27e94d 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -34,6 +34,21 @@ If your config is not located in your current directory, you can specify its pat vendor/bin/twig-cs-fixer lint --config=dir/.twig-cs-fixer.php /path/to/code ``` +## Non fixable rules + +Most of the rules are automatically fixable but some of them are not. +By default, the twig-cs-fixer disable all the non-fixable-rules, but you can still allow them in the config file: + +```php +allowNonFixableRules(); + +return $config; +``` + + ## Files By default, all `.twig` files in the current directory are linted, except the ones in the `vendor` directory. diff --git a/docs/rules.md b/docs/rules.md index 0812b023..6ca21cc1 100644 --- a/docs/rules.md +++ b/docs/rules.md @@ -2,10 +2,10 @@ ## Rules +### Fixable + - **BlockNameSpacingRule**: ensures there is one space before and after block names. - **DelimiterSpacingRule**: ensures there is one space before '}}', '%}' and '#}', and after '{{', '{%', '{#'. -- **DirectoryNameRule**: ensures directory name is snake_case (configurable). -- **FileNameRule**: ensures file name is snake_case (configurable). - **OperatorNameSpacingRule**: ensures there is no consecutive spaces inside operator names. - **OperatorSpacingRule**: ensures there is one space before and after an operator except for '..'. - **PunctuationSpacingRule**: ensures there is no space before and after a punctuation except for ':' and ','. @@ -15,6 +15,12 @@ - **IndentRule**: ensures that files are not indented with tabs. - **TrailingSpaceRule**: ensures that files have no trailing spaces. +### Non-fixable + +- **DirectoryNameRule**: ensures that directory name use snake_case (configurable). +- **FileNameRule**: ensures that file name use snake_case (configurable). +- **VariableNameRule**: ensures that variable name use snake_case (configurable). + ## Standards **Twig**: @@ -22,6 +28,7 @@ - OperatorNameSpacingRule - OperatorSpacingRule - PunctuationSpacingRule +- VariableNameRule **TwigCsFixer**: - Twig diff --git a/src/Command/TwigCsFixerCommand.php b/src/Command/TwigCsFixerCommand.php index b2f4e208..2642bda1 100644 --- a/src/Command/TwigCsFixerCommand.php +++ b/src/Command/TwigCsFixerCommand.php @@ -107,7 +107,7 @@ private function resolveConfig(InputInterface $input, OutputInterface $output): $config = $configResolver->resolveConfig( $input->getArgument('paths'), $input->getOption('config'), - $input->getOption('no-cache') + $input->getOption('no-cache'), ); $cacheFile = $config->getCacheFile(); @@ -130,7 +130,7 @@ private function runLinter(Config $config, InputInterface $input, OutputInterfac $report = $linter->run( $config->getFinder(), $config->getRuleset(), - $input->getOption('fix') ? new Fixer($tokenizer) : null + $input->getOption('fix') ? new Fixer($tokenizer) : null, ); $reporterFactory = new ReporterFactory(); diff --git a/src/Config/Config.php b/src/Config/Config.php index 40fa78aa..95f2b8d1 100644 --- a/src/Config/Config.php +++ b/src/Config/Config.php @@ -39,6 +39,8 @@ final class Config */ private array $tokenParsers = []; + private bool $allowNonFixableRules = false; + public function __construct(private string $name = 'Default') { $this->ruleset = new Ruleset(); @@ -143,4 +145,19 @@ public function getTokenParsers(): array { return $this->tokenParsers; } + + /** + * @return $this + */ + public function allowNonFixableRules(bool $allowNonFixableRules = true): self + { + $this->allowNonFixableRules = $allowNonFixableRules; + + return $this; + } + + public function areNonFixableRulesAllowed(): bool + { + return $this->allowNonFixableRules; + } } diff --git a/src/Config/ConfigResolver.php b/src/Config/ConfigResolver.php index aa5a30aa..e0dc62a1 100644 --- a/src/Config/ConfigResolver.php +++ b/src/Config/ConfigResolver.php @@ -34,11 +34,14 @@ public function __construct(private string $workingDir) public function resolveConfig( array $paths = [], ?string $configPath = null, - bool $disableCache = false + bool $disableCache = false, ): Config { $config = $this->getConfig($configPath); $config->setFinder($this->resolveFinder($config->getFinder(), $paths)); + // Override ruleset with config + $config->getRuleset()->allowNonFixableRules($config->areNonFixableRulesAllowed()); + if ($disableCache) { $config->setCacheFile(null); $config->setCacheManager(null); @@ -46,7 +49,7 @@ public function resolveConfig( $config->setCacheManager($this->resolveCacheManager( $config->getCacheManager(), $config->getCacheFile(), - $config->getRuleset() + $config->getRuleset(), )); } @@ -132,7 +135,7 @@ private function resolveFinder(Finder $finder, array $paths): Finder private function resolveCacheManager( ?CacheManagerInterface $cacheManager, ?string $cacheFile, - Ruleset $ruleset + Ruleset $ruleset, ): ?CacheManagerInterface { if (null !== $cacheManager) { return $cacheManager; @@ -147,7 +150,7 @@ private function resolveCacheManager( Signature::fromRuleset( \PHP_VERSION, InstalledVersions::getReference(self::PACKAGE_NAME) ?? '0', - $ruleset + $ruleset, ) ); } diff --git a/src/Rules/AbstractFixableRule.php b/src/Rules/AbstractFixableRule.php new file mode 100644 index 00000000..7438d48d --- /dev/null +++ b/src/Rules/AbstractFixableRule.php @@ -0,0 +1,58 @@ +fixer = $fixer; + } + + public function fixFile(array $stream, FixerInterface $fixer, array $ignoredViolations = []): void + { + $this->init(null, $ignoredViolations, $fixer); + + foreach (array_keys($stream) as $index) { + $this->process($index, $stream); + } + } + + protected function addFixableWarning( + string $message, + Token $token, + ?string $messageId = null + ): ?FixerInterface { + $added = $this->addWarning($message, $token, $messageId); + if (!$added) { + return null; + } + + return $this->fixer; + } + + protected function addFixableError( + string $message, + Token $token, + ?string $messageId = null + ): ?FixerInterface { + $added = $this->addError($message, $token, $messageId); + if (!$added) { + return null; + } + + return $this->fixer; + } +} diff --git a/src/Rules/AbstractRule.php b/src/Rules/AbstractRule.php index 45b58a9c..d51b84c8 100644 --- a/src/Rules/AbstractRule.php +++ b/src/Rules/AbstractRule.php @@ -8,15 +8,12 @@ use TwigCsFixer\Report\Report; use TwigCsFixer\Report\Violation; use TwigCsFixer\Report\ViolationId; -use TwigCsFixer\Runner\FixerInterface; use TwigCsFixer\Token\Token; abstract class AbstractRule implements RuleInterface { private ?Report $report = null; - private ?FixerInterface $fixer = null; - /** * @var list */ @@ -36,24 +33,20 @@ public function getShortName(): string public function lintFile(array $stream, Report $report, array $ignoredViolations = []): void { - $this->report = $report; - $this->fixer = null; - $this->ignoredViolations = $ignoredViolations; + $this->init($report, $ignoredViolations); foreach (array_keys($stream) as $index) { $this->process($index, $stream); } } - public function fixFile(array $stream, FixerInterface $fixer, array $ignoredViolations = []): void + /** + * @param list $ignoredViolations + */ + protected function init(?Report $report, array $ignoredViolations = []): void { - $this->report = null; - $this->fixer = $fixer; + $this->report = $report; $this->ignoredViolations = $ignoredViolations; - - foreach (array_keys($stream) as $index) { - $this->process($index, $stream); - } } /** @@ -170,32 +163,6 @@ protected function addFileError(string $message, Token $token, ?string $messageI ); } - protected function addFixableWarning( - string $message, - Token $token, - ?string $messageId = null - ): ?FixerInterface { - $added = $this->addWarning($message, $token, $messageId); - if (!$added) { - return null; - } - - return $this->fixer; - } - - protected function addFixableError( - string $message, - Token $token, - ?string $messageId = null - ): ?FixerInterface { - $added = $this->addError($message, $token, $messageId); - if (!$added) { - return null; - } - - return $this->fixer; - } - private function addMessage( int $messageType, string $message, diff --git a/src/Rules/AbstractSpacingRule.php b/src/Rules/AbstractSpacingRule.php index 3e379689..6d4e3996 100644 --- a/src/Rules/AbstractSpacingRule.php +++ b/src/Rules/AbstractSpacingRule.php @@ -9,7 +9,7 @@ /** * Ensures there is one space before or after some tokens */ -abstract class AbstractSpacingRule extends AbstractRule +abstract class AbstractSpacingRule extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { diff --git a/src/Rules/ConfigurableRuleInterface.php b/src/Rules/ConfigurableRuleInterface.php index 679c55d8..92480167 100644 --- a/src/Rules/ConfigurableRuleInterface.php +++ b/src/Rules/ConfigurableRuleInterface.php @@ -7,7 +7,7 @@ interface ConfigurableRuleInterface extends RuleInterface { /** - * @return array + * @return array */ public function getConfiguration(): array; } diff --git a/src/Rules/File/DirectoryNameRule.php b/src/Rules/File/DirectoryNameRule.php index 9bed608d..2e3a2603 100644 --- a/src/Rules/File/DirectoryNameRule.php +++ b/src/Rules/File/DirectoryNameRule.php @@ -10,7 +10,7 @@ use TwigCsFixer\Rules\ConfigurableRuleInterface; /** - * Ensures directory name is snake_case (Configurable). + * Ensures that directory name use snake_case (Configurable). */ final class DirectoryNameRule extends AbstractRule implements ConfigurableRuleInterface { diff --git a/src/Rules/File/FileNameRule.php b/src/Rules/File/FileNameRule.php index 3448f82d..2220f52b 100644 --- a/src/Rules/File/FileNameRule.php +++ b/src/Rules/File/FileNameRule.php @@ -10,7 +10,7 @@ use TwigCsFixer\Rules\ConfigurableRuleInterface; /** - * Ensures file name is snake_case (Configurable). + * Ensures that file name use snake_case (Configurable). */ final class FileNameRule extends AbstractRule implements ConfigurableRuleInterface { diff --git a/src/Rules/FixableRuleInterface.php b/src/Rules/FixableRuleInterface.php new file mode 100644 index 00000000..ce4d68e8 --- /dev/null +++ b/src/Rules/FixableRuleInterface.php @@ -0,0 +1,18 @@ + $stream + * @param list $ignoredViolations + */ + public function fixFile(array $stream, FixerInterface $fixer, array $ignoredViolations = []): void; +} diff --git a/src/Rules/Operator/OperatorNameSpacingRule.php b/src/Rules/Operator/OperatorNameSpacingRule.php index 2a36610f..e0b4cf0d 100644 --- a/src/Rules/Operator/OperatorNameSpacingRule.php +++ b/src/Rules/Operator/OperatorNameSpacingRule.php @@ -4,13 +4,13 @@ namespace TwigCsFixer\Rules\Operator; -use TwigCsFixer\Rules\AbstractRule; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Token\Token; /** * Ensures there is no consecutive spaces inside operator names. */ -final class OperatorNameSpacingRule extends AbstractRule +final class OperatorNameSpacingRule extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { diff --git a/src/Rules/Punctuation/TrailingCommaSingleLineRule.php b/src/Rules/Punctuation/TrailingCommaSingleLineRule.php index 3717ea9b..8d94f920 100644 --- a/src/Rules/Punctuation/TrailingCommaSingleLineRule.php +++ b/src/Rules/Punctuation/TrailingCommaSingleLineRule.php @@ -4,14 +4,14 @@ namespace TwigCsFixer\Rules\Punctuation; -use TwigCsFixer\Rules\AbstractRule; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Token\Token; use Webmozart\Assert\Assert; /** * Ensures that single-line arrays, objects and argument lists do not have a trailing comma. */ -final class TrailingCommaSingleLineRule extends AbstractRule +final class TrailingCommaSingleLineRule extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { diff --git a/src/Rules/RuleInterface.php b/src/Rules/RuleInterface.php index adb5d72c..dbf9579b 100644 --- a/src/Rules/RuleInterface.php +++ b/src/Rules/RuleInterface.php @@ -6,7 +6,6 @@ use TwigCsFixer\Report\Report; use TwigCsFixer\Report\ViolationId; -use TwigCsFixer\Runner\FixerInterface; use TwigCsFixer\Token\Token; interface RuleInterface @@ -18,10 +17,4 @@ interface RuleInterface * @param list $ignoredViolations */ public function lintFile(array $stream, Report $report, array $ignoredViolations = []): void; - - /** - * @param array $stream - * @param list $ignoredViolations - */ - public function fixFile(array $stream, FixerInterface $fixer, array $ignoredViolations = []): void; } diff --git a/src/Rules/Variable/VariableNameRule.php b/src/Rules/Variable/VariableNameRule.php new file mode 100644 index 00000000..2f6e89a8 --- /dev/null +++ b/src/Rules/Variable/VariableNameRule.php @@ -0,0 +1,62 @@ + $this->case, + ]; + } + + protected function process(int $tokenPosition, array $tokens): void + { + $token = $tokens[$tokenPosition]; + + if (!$this->isTokenMatching($token, Token::BLOCK_NAME_TYPE, 'set')) { + return; + } + + $nameTokenPosition = $this->findNext(Token::NAME_TYPE, $tokens, $tokenPosition); + Assert::notFalse($nameTokenPosition, 'A BLOCK_NAME_TYPE set must be followed by a name'); + $name = $tokens[$nameTokenPosition]->getValue(); + + $expected = match ($this->case) { + self::SNAKE_CASE => (new UnicodeString($name))->snake()->toString(), + self::CAMEL_CASE => (new UnicodeString($name))->camel()->toString(), + self::PASCAL_CASE => ucfirst((new UnicodeString($name))->camel()->toString()), + }; + + if ($expected !== $name) { + $this->addError( + sprintf('The var name must use %s; expected %s.', $this->case, $expected), + $token, + ); + } + } +} diff --git a/src/Rules/Whitespace/BlankEOFRule.php b/src/Rules/Whitespace/BlankEOFRule.php index ccea4573..1b8bf8c1 100644 --- a/src/Rules/Whitespace/BlankEOFRule.php +++ b/src/Rules/Whitespace/BlankEOFRule.php @@ -4,13 +4,13 @@ namespace TwigCsFixer\Rules\Whitespace; -use TwigCsFixer\Rules\AbstractRule; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Token\Token; /** * Ensures that files end with one blank line. */ -final class BlankEOFRule extends AbstractRule +final class BlankEOFRule extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { diff --git a/src/Rules/Whitespace/EmptyLinesRule.php b/src/Rules/Whitespace/EmptyLinesRule.php index 1ede69e9..1703f66d 100644 --- a/src/Rules/Whitespace/EmptyLinesRule.php +++ b/src/Rules/Whitespace/EmptyLinesRule.php @@ -4,14 +4,14 @@ namespace TwigCsFixer\Rules\Whitespace; -use TwigCsFixer\Rules\AbstractRule; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Token\Token; use Webmozart\Assert\Assert; /** * Ensures that 2 empty lines do not follow each other. */ -final class EmptyLinesRule extends AbstractRule +final class EmptyLinesRule extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { diff --git a/src/Rules/Whitespace/IndentRule.php b/src/Rules/Whitespace/IndentRule.php index 0d88ff70..47e75690 100644 --- a/src/Rules/Whitespace/IndentRule.php +++ b/src/Rules/Whitespace/IndentRule.php @@ -4,14 +4,14 @@ namespace TwigCsFixer\Rules\Whitespace; -use TwigCsFixer\Rules\AbstractRule; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Rules\ConfigurableRuleInterface; use TwigCsFixer\Token\Token; /** * Ensures that files are not indented with tabs. */ -final class IndentRule extends AbstractRule implements ConfigurableRuleInterface +final class IndentRule extends AbstractFixableRule implements ConfigurableRuleInterface { public function __construct(private int $spaceRatio = 4) { diff --git a/src/Rules/Whitespace/TrailingSpaceRule.php b/src/Rules/Whitespace/TrailingSpaceRule.php index 17a97215..21ed6529 100644 --- a/src/Rules/Whitespace/TrailingSpaceRule.php +++ b/src/Rules/Whitespace/TrailingSpaceRule.php @@ -4,13 +4,13 @@ namespace TwigCsFixer\Rules\Whitespace; -use TwigCsFixer\Rules\AbstractRule; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Token\Token; /** * Ensures that files have no trailing spaces. */ -final class TrailingSpaceRule extends AbstractRule +final class TrailingSpaceRule extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { diff --git a/src/Ruleset/Ruleset.php b/src/Ruleset/Ruleset.php index 92e02984..a6018727 100644 --- a/src/Ruleset/Ruleset.php +++ b/src/Ruleset/Ruleset.php @@ -4,6 +4,7 @@ namespace TwigCsFixer\Ruleset; +use TwigCsFixer\Rules\FixableRuleInterface; use TwigCsFixer\Rules\RuleInterface; use TwigCsFixer\Standard\StandardInterface; @@ -17,11 +18,27 @@ final class Ruleset */ private array $rules = []; + private bool $allowNonFixableRules = true; + + public function allowNonFixableRules(bool $allowNonFixableRules = true): self + { + $this->allowNonFixableRules = $allowNonFixableRules; + + return $this; + } + /** * @return array, RuleInterface> */ public function getRules(): array { + if (!$this->allowNonFixableRules) { + return array_filter( + $this->rules, + static fn (RuleInterface $rule): bool => $rule instanceof FixableRuleInterface, + ); + } + return $this->rules; } diff --git a/src/Runner/Fixer.php b/src/Runner/Fixer.php index 701316d1..6273961a 100644 --- a/src/Runner/Fixer.php +++ b/src/Runner/Fixer.php @@ -7,6 +7,7 @@ use BadMethodCallException; use Twig\Source; use TwigCsFixer\Exception\CannotFixFileException; +use TwigCsFixer\Rules\FixableRuleInterface; use TwigCsFixer\Ruleset\Ruleset; use TwigCsFixer\Token\Token; use TwigCsFixer\Token\TokenizerInterface; @@ -89,7 +90,9 @@ public function fixFile(string $content, Ruleset $ruleset): string $rules = $ruleset->getRules(); foreach ($rules as $rule) { - $rule->fixFile($stream, $this, $ignoredViolations); + if ($rule instanceof FixableRuleInterface) { + $rule->fixFile($stream, $this, $ignoredViolations); + } } $this->loops++; diff --git a/src/Standard/Twig.php b/src/Standard/Twig.php index 0f7e5492..c76d709f 100644 --- a/src/Standard/Twig.php +++ b/src/Standard/Twig.php @@ -8,6 +8,7 @@ use TwigCsFixer\Rules\Operator\OperatorNameSpacingRule; use TwigCsFixer\Rules\Operator\OperatorSpacingRule; use TwigCsFixer\Rules\Punctuation\PunctuationSpacingRule; +use TwigCsFixer\Rules\Variable\VariableNameRule; /** * Standard from twig. @@ -23,6 +24,7 @@ public function getRules(): array new OperatorNameSpacingRule(), new OperatorSpacingRule(), new PunctuationSpacingRule(), + new VariableNameRule(), ]; } } diff --git a/src/Token/Tokenizer.php b/src/Token/Tokenizer.php index ffdc0a50..b1dab986 100644 --- a/src/Token/Tokenizer.php +++ b/src/Token/Tokenizer.php @@ -12,7 +12,7 @@ use Webmozart\Assert\Assert; /** - * An override of Twig's Lexer to add whitespace and new line detection. + * An override of Twig\Lexer to add whitespace and new line detection. */ final class Tokenizer implements TokenizerInterface { diff --git a/tests/Config/ConfigTest.php b/tests/Config/ConfigTest.php index 277a2aba..ad4d2fa0 100644 --- a/tests/Config/ConfigTest.php +++ b/tests/Config/ConfigTest.php @@ -99,4 +99,17 @@ public function testConfigTwigExtensions(): void static::assertSame([$twigExtension, $twigExtension2], $config->getTwigExtensions()); } + + public function testAllowNonFixableRules(): void + { + $config = new Config(); + + static::assertFalse($config->areNonFixableRulesAllowed()); + + $config->allowNonFixableRules(); + static::assertTrue($config->areNonFixableRulesAllowed()); + + $config->allowNonFixableRules(false); + static::assertFalse($config->areNonFixableRulesAllowed()); + } } diff --git a/tests/Rules/RuleTest.php b/tests/Rules/RuleTest.php index 669484b4..7f320fa8 100644 --- a/tests/Rules/RuleTest.php +++ b/tests/Rules/RuleTest.php @@ -9,7 +9,7 @@ use TwigCsFixer\Environment\StubbedEnvironment; use TwigCsFixer\Report\Report; use TwigCsFixer\Report\Violation; -use TwigCsFixer\Rules\AbstractRule; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Ruleset\Ruleset; use TwigCsFixer\Runner\Linter; use TwigCsFixer\Tests\Rules\Fixtures\FakeRule; @@ -22,7 +22,7 @@ public function testRuleWithReport(): void { $report = new Report([new SplFileInfo('fakeFile.html.twig')]); - $rule = new class () extends AbstractRule { + $rule = new class () extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { $token = $tokens[$tokenPosition]; @@ -55,7 +55,7 @@ public function testRuleWithReport2(): void { $report = new Report([new SplFileInfo('fakeFile.html.twig')]); - $rule = new class () extends AbstractRule { + $rule = new class () extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { $token = $tokens[$tokenPosition]; diff --git a/tests/Rules/Variable/VariableName/VariableNameRuleTest.php b/tests/Rules/Variable/VariableName/VariableNameRuleTest.php new file mode 100644 index 00000000..68d68020 --- /dev/null +++ b/tests/Rules/Variable/VariableName/VariableNameRuleTest.php @@ -0,0 +1,49 @@ + VariableNameRule::SNAKE_CASE], + (new VariableNameRule())->getConfiguration() + ); + + static::assertSame( + ['case' => VariableNameRule::PASCAL_CASE], + (new VariableNameRule(VariableNameRule::PASCAL_CASE))->getConfiguration() + ); + } + + public function testRule(): void + { + $this->checkRule(new VariableNameRule(), [ + 'VariableName.Error:2:4', + 'VariableName.Error:4:4', + ]); + } + + public function testRuleCamelCase(): void + { + $this->checkRule(new VariableNameRule(VariableNameRule::CAMEL_CASE), [ + 'VariableName.Error:3:4', + 'VariableName.Error:4:4', + ]); + } + + public function testRulePascalCase(): void + { + $this->checkRule(new VariableNameRule(VariableNameRule::PASCAL_CASE), [ + 'VariableName.Error:1:4', + 'VariableName.Error:2:4', + 'VariableName.Error:3:4', + ]); + } +} diff --git a/tests/Rules/Variable/VariableName/VariableNameRuleTest.twig b/tests/Rules/Variable/VariableName/VariableNameRuleTest.twig new file mode 100644 index 00000000..38bf67a2 --- /dev/null +++ b/tests/Rules/Variable/VariableName/VariableNameRuleTest.twig @@ -0,0 +1,4 @@ +{% set foo = 'foo' %} +{% set fooBar = 'foo' %} +{% set foo_bar = 'foo' %} +{% set FooBar = 'foo' %} diff --git a/tests/Runner/FixerTest.php b/tests/Runner/FixerTest.php index 5bb59a08..93f6b013 100644 --- a/tests/Runner/FixerTest.php +++ b/tests/Runner/FixerTest.php @@ -5,10 +5,12 @@ namespace TwigCsFixer\Tests\Runner; use BadMethodCallException; +use LogicException; use PHPUnit\Framework\TestCase; use TwigCsFixer\Environment\StubbedEnvironment; use TwigCsFixer\Exception\CannotFixFileException; use TwigCsFixer\Exception\CannotTokenizeException; +use TwigCsFixer\Rules\AbstractFixableRule; use TwigCsFixer\Rules\AbstractRule; use TwigCsFixer\Ruleset\Ruleset; use TwigCsFixer\Runner\Fixer; @@ -51,7 +53,7 @@ public function testReplaceToken(): void { $tokenizer = new Tokenizer(new StubbedEnvironment()); - $rule = new class () extends AbstractRule { + $rule = new class () extends AbstractFixableRule { private bool $isAlreadyExecuted = false; protected function process(int $tokenPosition, array $tokens): void @@ -97,7 +99,7 @@ public function testReplaceTokenIsDesignedAgainstInfiniteLoop(): void { $tokenizer = new Tokenizer(new StubbedEnvironment()); - $rule = new class () extends AbstractRule { + $rule = new class () extends AbstractFixableRule { protected function process(int $tokenPosition, array $tokens): void { $fixer = $this->addFixableError('Error', $tokens[$tokenPosition]); @@ -122,7 +124,7 @@ public function testReplaceTokenIsDesignedAgainstConflict(): void { $tokenizer = new Tokenizer(new StubbedEnvironment()); - $rule1 = new class () extends AbstractRule { + $rule1 = new class () extends AbstractFixableRule { private bool $isAlreadyExecuted = false; protected function process(int $tokenPosition, array $tokens): void @@ -140,7 +142,7 @@ protected function process(int $tokenPosition, array $tokens): void $fixer->replaceToken($tokenPosition, 'rule'); } }; - $rule2 = new class () extends AbstractRule { + $rule2 = new class () extends AbstractFixableRule { private int $error = 0; protected function process(int $tokenPosition, array $tokens): void @@ -172,7 +174,7 @@ protected function process(int $tokenPosition, array $tokens): void $fixer->endChangeSet(); } }; - $rule3 = new class () extends AbstractRule { + $rule3 = new class () extends AbstractFixableRule { private bool $isAlreadyExecuted = false; protected function process(int $tokenPosition, array $tokens): void @@ -210,7 +212,7 @@ public function testIgnoredViolations(): void { $tokenizer = new Tokenizer(new StubbedEnvironment()); - $rule = new class () extends AbstractRule { + $rule = new class () extends AbstractFixableRule { public function getShortName(): string { return 'Rule'; @@ -237,7 +239,7 @@ protected function process(int $tokenPosition, array $tokens): void $content = '{# twig-cs-fixer-disable Rule #}'; // The rule should produce an infinite loop but the comment disable it - static::assertSame($content, $fixer->fixFile('{# twig-cs-fixer-disable Rule #}', $ruleset)); + static::assertSame($content, $fixer->fixFile($content, $ruleset)); } /** @@ -247,7 +249,7 @@ public function testAddContentMethods(string $content, string $expected): void { $tokenizer = new Tokenizer(new StubbedEnvironment()); - $rule = new class () extends AbstractRule { + $rule = new class () extends AbstractFixableRule { private bool $isAlreadyExecuted = false; protected function process(int $tokenPosition, array $tokens): void @@ -308,4 +310,24 @@ public function testEndChangeSetException(): void $this->expectException(BadMethodCallException::class); $fixer->endChangeSet(); } + + public function testNonFixableRulesAreSkipped(): void + { + $tokenizer = new Tokenizer(new StubbedEnvironment()); + + $rule = new class () extends AbstractRule { + protected function process(int $tokenPosition, array $tokens): void + { + throw new LogicException('Should be skipped'); + } + }; + + $ruleset = new Ruleset(); + $ruleset->addRule($rule); + + $fixer = new Fixer($tokenizer); + + $content = ''; + static::assertSame($content, $fixer->fixFile($content, $ruleset)); + } } diff --git a/tests/Standard/SymfonyTest.php b/tests/Standard/SymfonyTest.php index 36462638..6c1c7ca0 100644 --- a/tests/Standard/SymfonyTest.php +++ b/tests/Standard/SymfonyTest.php @@ -11,6 +11,7 @@ use TwigCsFixer\Rules\Operator\OperatorNameSpacingRule; use TwigCsFixer\Rules\Operator\OperatorSpacingRule; use TwigCsFixer\Rules\Punctuation\PunctuationSpacingRule; +use TwigCsFixer\Rules\Variable\VariableNameRule; use TwigCsFixer\Standard\Symfony; final class SymfonyTest extends TestCase @@ -24,6 +25,7 @@ public function testGetRules(): void new OperatorNameSpacingRule(), new OperatorSpacingRule(), new PunctuationSpacingRule(), + new VariableNameRule(), new FileNameRule(baseDirectory: 'templates', ignoredSubDirectories: ['bundles']), new DirectoryNameRule(baseDirectory: 'templates', ignoredSubDirectories: ['bundles']), ], $standard->getRules()); diff --git a/tests/Standard/TwigCsFixerTest.php b/tests/Standard/TwigCsFixerTest.php index e86261d3..18f3d63a 100644 --- a/tests/Standard/TwigCsFixerTest.php +++ b/tests/Standard/TwigCsFixerTest.php @@ -11,6 +11,7 @@ use TwigCsFixer\Rules\Operator\OperatorSpacingRule; use TwigCsFixer\Rules\Punctuation\PunctuationSpacingRule; use TwigCsFixer\Rules\Punctuation\TrailingCommaSingleLineRule; +use TwigCsFixer\Rules\Variable\VariableNameRule; use TwigCsFixer\Rules\Whitespace\BlankEOFRule; use TwigCsFixer\Rules\Whitespace\EmptyLinesRule; use TwigCsFixer\Rules\Whitespace\IndentRule; @@ -28,6 +29,7 @@ public function testGetRules(): void new OperatorNameSpacingRule(), new OperatorSpacingRule(), new PunctuationSpacingRule(), + new VariableNameRule(), new BlankEOFRule(), new BlockNameSpacingRule(), new EmptyLinesRule(), diff --git a/tests/Standard/TwigTest.php b/tests/Standard/TwigTest.php index f67d7409..27d8a82c 100644 --- a/tests/Standard/TwigTest.php +++ b/tests/Standard/TwigTest.php @@ -9,6 +9,7 @@ use TwigCsFixer\Rules\Operator\OperatorNameSpacingRule; use TwigCsFixer\Rules\Operator\OperatorSpacingRule; use TwigCsFixer\Rules\Punctuation\PunctuationSpacingRule; +use TwigCsFixer\Rules\Variable\VariableNameRule; use TwigCsFixer\Standard\Twig; final class TwigTest extends TestCase @@ -22,6 +23,7 @@ public function testGetRules(): void new OperatorNameSpacingRule(), new OperatorSpacingRule(), new PunctuationSpacingRule(), + new VariableNameRule(), ], $standard->getRules()); } }