Skip to content

Commit

Permalink
Add inspection for positional macro arguments after named ones
Browse files Browse the repository at this point in the history
  • Loading branch information
drjayvee committed Dec 12, 2024
1 parent edc222d commit 303e066
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 1 deletion.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ no explicit default value as required.
* ✅ Call with *too many* arguments (except if `varargs` is used)
* ✅ Call with *too few* arguments
* ✅ Required argument declared after optional
* ✅ Positional argument after named in call expression
* ⌛ Type mismatch in macro call

# Acknowledgments
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"name": "Jeroen Versteeg"
}
],
"version": "1.0.6",
"version": "1.0.7",
"autoload": {
"psr-4": {
"AlisQI\\TwigQI\\": "src/"
Expand Down
2 changes: 2 additions & 0 deletions src/Extension.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use AlisQI\TwigQI\Inspection\BadArgumentCountInMacroCall;
use AlisQI\TwigQI\Inspection\InvalidConstant;
use AlisQI\TwigQI\Inspection\InvalidDotOperation;
use AlisQI\TwigQI\Inspection\PositionalMacroArgumentAfterNamed;
use AlisQI\TwigQI\Inspection\RequiredMacroArgumentAfterOptional;
use AlisQI\TwigQI\Inspection\UndeclaredVariableInMacro;
use AlisQI\TwigQI\Inspection\InvalidTypes;
Expand All @@ -25,6 +26,7 @@ public function getNodeVisitors(): array
new InvalidConstant(),

new BadArgumentCountInMacroCall(),
new PositionalMacroArgumentAfterNamed(),
new RequiredMacroArgumentAfterOptional(),
new UndeclaredVariableInMacro(),
];
Expand Down
57 changes: 57 additions & 0 deletions src/Inspection/PositionalMacroArgumentAfterNamed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

declare(strict_types=1);

namespace AlisQI\TwigQI\Inspection;

use AlisQI\TwigQI\Helper\NodeLocation;
use Twig\Environment;
use Twig\Node\Expression\MacroReferenceExpression;
use Twig\Node\Node;
use Twig\NodeVisitor\NodeVisitorInterface;

class PositionalMacroArgumentAfterNamed implements NodeVisitorInterface
{
public function enterNode(Node $node, Environment $env): Node
{
if ($node instanceof MacroReferenceExpression) {
if (!$this->checkCall($node)) {
trigger_error(
sprintf("Positional macro argument after named (at %s)", new NodeLocation($node)),
E_USER_ERROR
);
}
}

return $node;
}

private function checkCall(MacroReferenceExpression $node): bool
{
$namedArgumentEncountered = false;
foreach ($node->getNode('arguments')->getKeyValuePairs() as ['key' => $key]) {
$name = $key->getAttribute('name');

if (is_int($name)) {
if ($namedArgumentEncountered) {
return false;
}
} else {
$namedArgumentEncountered = true;
}
}

return true;
}

public function leaveNode(Node $node, Environment $env): ?Node
{
return $node;
}

public function getPriority(): int
{
return 0;
}

}
29 changes: 29 additions & 0 deletions tests/PositionalMacroArgumentAfterNamedTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

declare(strict_types=1);

namespace AlisQI\TwigQI\Tests;

class PositionalMacroArgumentAfterNamedTest extends AbstractTestCase
{
public function test_itSupportsNamedArguments(): void
{
$this->env->createTemplate(<<<EOF
{% macro marco(po, lo) %}{% endmacro %}
{{ _self.polo(po=13, lo: 37) }}
EOF);

self::assertEmpty($this->errors, implode(', ', $this->errors));
}

public function test_itErrorsForPositionalArgumentAfterNamed(): void
{
$this->env->createTemplate(<<<EOF
{% macro marco(po, lo) %}{% endmacro %}
{{ _self.polo(po: 13, 37) }}
EOF);

self::assertNotEmpty($this->errors);
}

}

0 comments on commit 303e066

Please sign in to comment.