Created
November 9, 2023 03:22
-
-
Save mstrelan/4ebedc887ba0b7ea6d7b27784e316216 to your computer and use it in GitHub Desktop.
FormattableMarkupToSprintfRector
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
use PhpParser\Node; | |
use PhpParser\Node\Arg; | |
use PhpParser\Node\Expr\FuncCall; | |
use PhpParser\Node\Expr\MethodCall; | |
use PhpParser\Node\Name; | |
use PhpParser\Node\Scalar\String_; | |
use Rector\Core\Contract\Rector\RectorInterface; | |
use Rector\Core\NodeFactory\NodeFactory; | |
use Rector\Core\Rector\AbstractRector; | |
use Rector\Drupal\CodeSample; | |
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; | |
final class FormattableMarkupToSprintfRector extends AbstractRector implements RectorInterface | |
{ | |
public function getRuleDefinition() : RuleDefinition | |
{ | |
return new RuleDefinition('Replace FormattableMarkup with sprintf', [new CodeSample(<<<'CODE_SAMPLE' | |
function testSomething() | |
{ | |
$this->assertSame($expected, $actual, new FormattableMarkup('Expected @expected but found @actual.', ['@expected' => $expected, '@actual' => $actual])); | |
} | |
CODE_SAMPLE | |
, <<<'CODE_SAMPLE' | |
function testSomething() | |
{ | |
$this->assertSame($expected, $actual, sprintf('Expected %s but found %s.', $expected, $actual)); | |
} | |
CODE_SAMPLE | |
)]); | |
} | |
public function getNodeTypes(): array | |
{ | |
return [MethodCall::class]; | |
} | |
public function refactor(Node $node): ?Node | |
{ | |
/** @var \PhpParser\Node\Expr\MethodCall $node */ | |
$methodCallName = $this->getName($node->name); | |
if ($methodCallName === null) { | |
return null; | |
} | |
// we only care about "assert*" method names | |
if (!str_starts_with($methodCallName, 'assert')) { | |
return NULL; | |
} | |
foreach ($node->args as $index => $argument) { | |
if (!$argument->value instanceof Node\Expr\New_) { | |
continue; | |
} | |
if ($argument->value->class->toCodeString() === '\Drupal\Component\Render\FormattableMarkup') { | |
$this->replaceFormattableMarkupArgumentWithSprintf($node, $index); | |
} | |
} | |
return $node; | |
} | |
// @todo handle cases where replacements are in different order or appear multiple times. | |
private function replaceFormattableMarkupArgumentWithSprintf(MethodCall $node, int $argumentIndex): void | |
{ | |
/** @var \PhpParser\Node\Expr\New_ $formattableMarkupArgument */ | |
$formattableMarkupArgument = $node->args[$argumentIndex]->value; | |
$args = $formattableMarkupArgument->getArgs(); | |
$formatString = $args[0]->value->value; | |
$replacementArgs = $args[1]->value->items; | |
$placeholders = []; | |
$replacements = []; | |
foreach ($replacementArgs as $replacementArg) { | |
$placeholders[] = $replacementArg->key->value; | |
$replacements[] = $replacementArg->value; | |
} | |
$formatString = str_replace($placeholders, '%s', $formatString); | |
// Replace the FormattableMarkup argument with the sprintf call | |
$node->args[$argumentIndex]->value = new FuncCall( | |
new Name('sprintf'), | |
[ | |
new Arg(new String_($formatString)), | |
... array_map(fn ($value) => new Arg($value), $replacements), | |
] | |
); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment