Skip to content

Commit

Permalink
Introduce MacroArgumentNameRule (#337)
Browse files Browse the repository at this point in the history
  • Loading branch information
VincentLanglet authored Dec 4, 2024
1 parent d742797 commit de965b7
Show file tree
Hide file tree
Showing 11 changed files with 136 additions and 13 deletions.
58 changes: 58 additions & 0 deletions src/Rules/Function/MacroArgumentNameRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
<?php

declare(strict_types=1);

namespace TwigCsFixer\Rules\Function;

use TwigCsFixer\Rules\AbstractRule;
use TwigCsFixer\Rules\ConfigurableRuleInterface;
use TwigCsFixer\Token\Token;
use TwigCsFixer\Token\Tokens;
use TwigCsFixer\Util\StringUtil;

/**
* Ensures that named argument are in snake_case (Configurable).
*/
final class MacroArgumentNameRule extends AbstractRule implements ConfigurableRuleInterface
{
// Kebab case is not a valid case for argument.
public const SNAKE_CASE = 'snake_case';
public const CAMEL_CASE = 'camelCase';
public const PASCAL_CASE = 'PascalCase';

/**
* @param self::* $case
*/
public function __construct(private string $case = self::SNAKE_CASE)
{
}

public function getConfiguration(): array
{
return [
'case' => $this->case,
];
}

protected function process(int $tokenIndex, Tokens $tokens): void
{
$token = $tokens->get($tokenIndex);
if (!$token->isMatching(Token::MACRO_VAR_NAME_TYPE)) {
return;
}

$name = $token->getValue();
$expected = match ($this->case) {
self::SNAKE_CASE => StringUtil::toSnakeCase($name),
self::CAMEL_CASE => StringUtil::toCamelCase($name),
self::PASCAL_CASE => StringUtil::toPascalCase($name),
};

if ($expected !== $name) {
$this->addError(
\sprintf('The macro argument must use %s; expected %s.', $this->case, $expected),
$token,
);
}
}
}
1 change: 0 additions & 1 deletion src/Rules/Function/NamedArgumentNameRule.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ public function getConfiguration(): array
protected function process(int $tokenIndex, Tokens $tokens): void
{
$token = $tokens->get($tokenIndex);

if (!$token->isMatching(Token::NAMED_ARGUMENT_SEPARATOR_TYPE)) {
return;
}
Expand Down
2 changes: 2 additions & 0 deletions src/Standard/Twig.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace TwigCsFixer\Standard;

use TwigCsFixer\Rules\Delimiter\DelimiterSpacingRule;
use TwigCsFixer\Rules\Function\MacroArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentSeparatorRule;
use TwigCsFixer\Rules\Function\NamedArgumentSpacingRule;
Expand All @@ -24,6 +25,7 @@ public function getRules(): array
{
return [
new DelimiterSpacingRule(),
new MacroArgumentNameRule(),
new NamedArgumentNameRule(),
new NamedArgumentSeparatorRule(),
new NamedArgumentSpacingRule(),
Expand Down
2 changes: 1 addition & 1 deletion src/Token/Tokenizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ private function lexName(string $name): void
} elseif (
self::STATE_BLOCK === $this->getState()
&& 'macro' === $this->getStateParam('blockName')
&& $this->lastBracketMatch('(')
&& $lastNonEmptyToken->isMatching(Token::PUNCTUATION_TYPE, ['(', ','])
) {
$this->pushToken(Token::MACRO_VAR_NAME_TYPE, $name);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<?php

declare(strict_types=1);

namespace TwigCsFixer\Tests\Rules\Function\MacroArgumentName;

use TwigCsFixer\Rules\Function\MacroArgumentNameRule;
use TwigCsFixer\Test\AbstractRuleTestCase;

final class MacroArgumentNameRuleTest extends AbstractRuleTestCase
{
public function testConfiguration(): void
{
static::assertSame(
[
'case' => MacroArgumentNameRule::SNAKE_CASE,
],
(new MacroArgumentNameRule())->getConfiguration()
);
static::assertSame(
[
'case' => MacroArgumentNameRule::CAMEL_CASE,
],
(new MacroArgumentNameRule(MacroArgumentNameRule::CAMEL_CASE))->getConfiguration()
);
}

public function testRule(): void
{
$this->checkRule(new MacroArgumentNameRule(), [
'MacroArgumentName.Error:1:14' => 'The macro argument must use snake_case; expected foo_bar1.',
'MacroArgumentName.Error:1:33' => 'The macro argument must use snake_case; expected foo_bar3.',
]);
}

public function testRulePascalCase(): void
{
$this->checkRule(new MacroArgumentNameRule(MacroArgumentNameRule::PASCAL_CASE), [
'MacroArgumentName.Error:1:14' => 'The macro argument must use PascalCase; expected FooBar1.',
'MacroArgumentName.Error:1:23' => 'The macro argument must use PascalCase; expected FooBar2.',
]);
}

public function testRuleCamelCase(): void
{
$this->checkRule(new MacroArgumentNameRule(MacroArgumentNameRule::CAMEL_CASE), [
'MacroArgumentName.Error:1:23' => 'The macro argument must use camelCase; expected fooBar2.',
'MacroArgumentName.Error:1:33' => 'The macro argument must use camelCase; expected fooBar3.',
]);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{% macro foo(fooBar1, foo_bar2, FooBar3 = true) %}
{% endmacro %}
2 changes: 2 additions & 0 deletions tests/Standard/SymfonyTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use TwigCsFixer\Rules\File\DirectoryNameRule;
use TwigCsFixer\Rules\File\FileExtensionRule;
use TwigCsFixer\Rules\File\FileNameRule;
use TwigCsFixer\Rules\Function\MacroArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentSeparatorRule;
use TwigCsFixer\Rules\Function\NamedArgumentSpacingRule;
Expand All @@ -26,6 +27,7 @@ public function testGetRules(): void

static::assertEquals([
new DelimiterSpacingRule(),
new MacroArgumentNameRule(),
new NamedArgumentNameRule(),
new NamedArgumentSeparatorRule(),
new NamedArgumentSpacingRule(),
Expand Down
2 changes: 2 additions & 0 deletions tests/Standard/TwigCsFixerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use TwigCsFixer\Rules\Delimiter\BlockNameSpacingRule;
use TwigCsFixer\Rules\Delimiter\DelimiterSpacingRule;
use TwigCsFixer\Rules\Function\IncludeFunctionRule;
use TwigCsFixer\Rules\Function\MacroArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentSeparatorRule;
use TwigCsFixer\Rules\Function\NamedArgumentSpacingRule;
Expand All @@ -33,6 +34,7 @@ public function testGetRules(): void

static::assertEquals([
new DelimiterSpacingRule(),
new MacroArgumentNameRule(),
new NamedArgumentNameRule(),
new NamedArgumentSeparatorRule(),
new NamedArgumentSpacingRule(),
Expand Down
2 changes: 2 additions & 0 deletions tests/Standard/TwigTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use PHPUnit\Framework\TestCase;
use TwigCsFixer\Rules\Delimiter\DelimiterSpacingRule;
use TwigCsFixer\Rules\Function\MacroArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentNameRule;
use TwigCsFixer\Rules\Function\NamedArgumentSeparatorRule;
use TwigCsFixer\Rules\Function\NamedArgumentSpacingRule;
Expand All @@ -23,6 +24,7 @@ public function testGetRules(): void

static::assertEquals([
new DelimiterSpacingRule(),
new MacroArgumentNameRule(),
new NamedArgumentNameRule(),
new NamedArgumentSeparatorRule(),
new NamedArgumentSpacingRule(),
Expand Down
2 changes: 1 addition & 1 deletion tests/Token/Tokenizer/Fixtures/test15.twig
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
{{ foo(foo:1) }}
{{ foo({foo:1}) }}
{{ (foo==1) }}
{% macro input(name='foo', opts={foo: 1}) %}{{ name }}{% endmacro %}
{% macro input(name='foo', opts={foo: 1}, bool=false) %}{{ name }}{% endmacro %}
25 changes: 15 additions & 10 deletions tests/Token/Tokenizer/TokenizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -768,19 +768,24 @@ public static function tokenizeDataProvider(): iterable
73 => Token::PUNCTUATION_TYPE,
74 => Token::PUNCTUATION_TYPE,
75 => Token::WHITESPACE_TYPE,
76 => Token::BLOCK_END_TYPE,
77 => Token::VAR_START_TYPE,
78 => Token::WHITESPACE_TYPE,
79 => Token::NAME_TYPE,
76 => Token::MACRO_VAR_NAME_TYPE,
77 => Token::OPERATOR_TYPE,
78 => Token::NAME_TYPE,
79 => Token::PUNCTUATION_TYPE,
80 => Token::WHITESPACE_TYPE,
81 => Token::VAR_END_TYPE,
82 => Token::BLOCK_START_TYPE,
81 => Token::BLOCK_END_TYPE,
82 => Token::VAR_START_TYPE,
83 => Token::WHITESPACE_TYPE,
84 => Token::BLOCK_NAME_TYPE,
84 => Token::NAME_TYPE,
85 => Token::WHITESPACE_TYPE,
86 => Token::BLOCK_END_TYPE,
87 => Token::EOL_TYPE,
88 => Token::EOF_TYPE,
86 => Token::VAR_END_TYPE,
87 => Token::BLOCK_START_TYPE,
88 => Token::WHITESPACE_TYPE,
89 => Token::BLOCK_NAME_TYPE,
90 => Token::WHITESPACE_TYPE,
91 => Token::BLOCK_END_TYPE,
92 => Token::EOL_TYPE,
93 => Token::EOF_TYPE,
],
];

Expand Down

0 comments on commit de965b7

Please sign in to comment.