add RecipeOption to prevent typos; first attempt to use constant-named parameters

This commit is contained in:
TomasVotruba 2020-07-28 16:10:36 +02:00
parent f845935e4a
commit cdd3935ef6
8 changed files with 272 additions and 31 deletions

View File

@ -5,6 +5,7 @@ declare(strict_types=1);
namespace Rector\RectorGenerator\Command;
use Nette\Utils\Strings;
use Rector\Core\Configuration\Option;
use Rector\RectorGenerator\Composer\ComposerPackageAutoloadUpdater;
use Rector\RectorGenerator\Config\ConfigFilesystem;
use Rector\RectorGenerator\Configuration\ConfigurationFactory;
@ -20,6 +21,7 @@ use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symplify\PackageBuilder\Console\Command\CommandNaming;
use Symplify\PackageBuilder\Console\ShellCode;
use Symplify\PackageBuilder\Parameter\ParameterProvider;
use Symplify\SmartFileSystem\SmartFileInfo;
use Symplify\SmartFileSystem\SmartFileSystem;
@ -35,11 +37,6 @@ final class CreateRectorCommand extends Command
*/
private $generatedFiles = [];
/**
* @var mixed[]
*/
private $rectorRecipe = [];
/**
* @var SymfonyStyle
*/
@ -91,8 +88,10 @@ final class CreateRectorCommand extends Command
private $smartFileSystem;
/**
* @param mixed[] $rectorRecipe
* @var ParameterProvider
*/
private $parameterProvider;
public function __construct(
SymfonyStyle $symfonyStyle,
ConfigurationFactory $configurationFactory,
@ -103,15 +102,14 @@ final class CreateRectorCommand extends Command
TemplateFactory $templateFactory,
ConfigFilesystem $configFilesystem,
OverrideGuard $overrideGuard,
array $rectorRecipe,
SmartFileSystem $smartFileSystem
SmartFileSystem $smartFileSystem,
ParameterProvider $parameterProvider
) {
parent::__construct();
$this->symfonyStyle = $symfonyStyle;
$this->configurationFactory = $configurationFactory;
$this->templateVariablesFactory = $templateVariablesFactory;
$this->rectorRecipe = $rectorRecipe;
$this->composerPackageAutoloadUpdater = $composerPackageAutoloadUpdater;
$this->templateFinder = $templateFinder;
$this->templateFileSystem = $templateFileSystem;
@ -119,6 +117,7 @@ final class CreateRectorCommand extends Command
$this->configFilesystem = $configFilesystem;
$this->overrideGuard = $overrideGuard;
$this->smartFileSystem = $smartFileSystem;
$this->parameterProvider = $parameterProvider;
}
protected function configure(): void
@ -130,7 +129,12 @@ final class CreateRectorCommand extends Command
protected function execute(InputInterface $input, OutputInterface $output): int
{
$configuration = $this->configurationFactory->createFromRectorRecipe($this->rectorRecipe);
$rectorRecipe = $this->parameterProvider->provideParameter(Option::RECTOR_RECIPE);
$configuration = $this->configurationFactory->createFromRectorRecipe($rectorRecipe);
dump($configuration);
die;
$templateVariables = $this->templateVariablesFactory->createFromConfiguration($configuration);
// setup psr-4 autoload, if not already in

View File

@ -8,6 +8,7 @@ use Nette\Utils\Strings;
use Rector\Core\Set\SetResolver;
use Rector\RectorGenerator\Guard\RecipeGuard;
use Rector\RectorGenerator\ValueObject\Configuration;
use Rector\RectorGenerator\ValueObject\RecipeOption;
final class ConfigurationFactory
{
@ -34,35 +35,39 @@ final class ConfigurationFactory
{
$this->recipeGuard->ensureRecipeIsValid($rectorRecipe);
$nodeTypeClasses = $rectorRecipe['node_types'];
$nodeTypeClasses = $rectorRecipe[RecipeOption::NODE_TYPES];
$category = $this->resolveCategoryFromFqnNodeTypes($nodeTypeClasses);
$extraFileContent = isset($rectorRecipe['extra_file_content']) ? $this->normalizeCode(
$rectorRecipe['extra_file_content']
$extraFileContent = isset($rectorRecipe[RecipeOption::EXTRA_FILE_CONTENT]) ? $this->normalizeCode(
$rectorRecipe[RecipeOption::EXTRA_FILE_CONTENT]
) : null;
$set = $rectorRecipe['set'] ? $this->setResolver->resolveSetByName($rectorRecipe['set']) : null;
return new Configuration(
$rectorRecipe['package'],
$rectorRecipe['name'],
$rectorRecipe[RecipeOption::PACKAGE],
$rectorRecipe[RecipeOption::NAME],
$category,
$nodeTypeClasses,
$rectorRecipe['description'],
$this->normalizeCode($rectorRecipe['code_before']),
$this->normalizeCode($rectorRecipe['code_after']),
$rectorRecipe[RecipeOption::DESCRIPTION],
$this->normalizeCode($rectorRecipe[RecipeOption::CODE_BEFORE]),
$this->normalizeCode($rectorRecipe[RecipeOption::CODE_AFTER]),
$extraFileContent,
$rectorRecipe['extra_file_name'] ?? null,
array_filter((array) $rectorRecipe['source']),
$rectorRecipe[RecipeOption::EXTRA_FILE_NAME] ?? null,
(array) $rectorRecipe[RecipeOption::CONFIGURATION],
array_filter((array) $rectorRecipe[RecipeOption::SOURCE]),
$set,
$this->detectPhpSnippet($rectorRecipe['code_before'])
$this->isPhpSnippet($rectorRecipe[RecipeOption::CODE_BEFORE])
);
}
/**
* @param string[] $fqnNodeTypes
* @param class-string[] $nodeTypes
*/
private function resolveCategoryFromFqnNodeTypes(array $fqnNodeTypes): string
private function resolveCategoryFromFqnNodeTypes(array $nodeTypes): string
{
return (string) Strings::after($fqnNodeTypes[0], '\\', -1);
return (string) Strings::after($nodeTypes[0], '\\', -1);
}
private function normalizeCode(string $code): string
@ -74,7 +79,7 @@ final class ConfigurationFactory
return trim($code);
}
private function detectPhpSnippet(string $code): bool
private function isPhpSnippet(string $code): bool
{
return Strings::startsWith($code, '<?php');
}

View File

@ -4,7 +4,10 @@ declare(strict_types=1);
namespace Rector\RectorGenerator\Guard;
use PhpParser\Node\Expr\FuncCall;
use Rector\Core\Configuration\Option;
use Rector\RectorGenerator\Exception\ConfigurationException;
use Rector\RectorGenerator\ValueObject\RecipeOption;
final class RecipeGuard
{
@ -30,19 +33,22 @@ final class RecipeGuard
$requiredKeysCount = count(self::REQUIRED_KEYS);
if (count(array_intersect(array_keys($rectorRecipe), self::REQUIRED_KEYS)) === $requiredKeysCount) {
if (count($rectorRecipe['node_types']) < 1) {
if (count($rectorRecipe[RecipeOption::NODE_TYPES]) < 1) {
throw new ConfigurationException(sprintf(
'"%s" option requires at least one node, e.g. "FuncCall"',
'node_types'
'"%s" option requires at least one node, e.g. "%s"',
FuncCall::class,
RecipeOption::NODE_TYPES
));
}
return;
}
throw new ConfigurationException(sprintf(
'Make sure "%s" keys are present in "parameters > rector_recipe"',
$message = sprintf(
'Make sure "%s" keys are present in "parameters > %s"',
Option::RECTOR_RECIPE,
implode('", "', self::REQUIRED_KEYS)
));
);
throw new ConfigurationException($message);
}
}

View File

@ -70,6 +70,10 @@ final class Configuration
* @var string[]
*/
private $source = [];
/**
* @var array
*/
private $configuration;
/**
* @param string[] $nodeTypes
@ -85,6 +89,7 @@ final class Configuration
string $codeAfter,
?string $extraFileContent,
?string $extraFileName,
array $configuration,
array $source,
?Set $set,
bool $isPhpSnippet
@ -101,6 +106,7 @@ final class Configuration
$this->isPhpSnippet = $isPhpSnippet;
$this->extraFileContent = $extraFileContent;
$this->extraFileName = $extraFileName;
$this->configuration = $configuration;
}
public function getDescription(): string
@ -191,4 +197,12 @@ final class Configuration
$this->name = $name;
}
/**
* @return mixed[]
*/
public function getConfiguration(): array
{
return $this->configuration;
}
}

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace Rector\RectorGenerator\ValueObject;
final class RecipeOption
{
/**
* @var string
*/
public const PACKAGE = 'package';
/**
* @var string
*/
public const NAME = 'name';
/**
* @var string
*/
public const NODE_TYPES = 'node_types';
/**
* @var string
*/
public const DESCRIPTION = 'description';
/**
* @var string
*/
public const CODE_BEFORE = 'code_before';
/**
* @var string
*/
public const CODE_AFTER = 'code_after';
/**
* @var string
*/
public const CONFIGURATION = 'configuration';
/**
* @var string
*/
public const SOURCE = 'source';
/**
* @var string
*/
public const SET = 'set';
/**
* @var string
*/
public const EXTRA_FILE_CONTENT = 'extra_file_content';
/**
* @var string
*/
public const EXTRA_FILE_NAME = 'extra_file_name';
}

View File

@ -0,0 +1,77 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Rector\MethodCall;
use PhpParser\Node;
use PhpParser\Node\Expr\MethodCall;
use Rector\Core\Rector\AbstractRector;
use Rector\Core\RectorDefinition\CodeSample;
use Rector\Core\RectorDefinition\RectorDefinition;
/**
* @see \Rector\Core\Tests\Rector\MethodCall\MethodCallToStaticCallRector\MethodCallToStaticCallRectorTest
*/
final class MethodCallToStaticCallRector extends AbstractRector
{
public function getDefinition(): RectorDefinition
{
return new RectorDefinition('Change method call to desired static call', [
new CodeSample(
<<<'PHP'
final class SomeClass
{
private $anotherDependency;
public function __construct(AnotherDependency $anotherDependency)
{
$this->anotherDependency = $anotherDependency;
}
public function loadConfiguration()
{
return $this->anotherDependency->process('value');
}
}
PHP
,
<<<'PHP'
final class SomeClass
{
private $anotherDependency;
public function __construct(AnotherDependency $anotherDependency)
{
$this->anotherDependency = $anotherDependency;
}
public function loadConfiguration()
{
return StaticCaller::anotherMethod('value');
}
}
PHP
),
]);
}
/**
* @return string[]
*/
public function getNodeTypes(): array
{
return [MethodCall::class];
}
/**
* @param MethodCall $node
*/
public function refactor(Node $node): ?Node
{
// change the node
return $node;
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace Rector\Core\Tests\Rector\MethodCall\MethodCallToStaticCallRector\Fixture;
final class SomeClass
{
private $anotherDependency;
public function __construct(AnotherDependency $anotherDependency)
{
$this->anotherDependency = $anotherDependency;
}
public function loadConfiguration()
{
return $this->anotherDependency->process('value');
}
}
?>
-----
<?php
namespace Rector\Core\Tests\Rector\MethodCall\MethodCallToStaticCallRector\Fixture;
final class SomeClass
{
private $anotherDependency;
public function __construct(AnotherDependency $anotherDependency)
{
$this->anotherDependency = $anotherDependency;
}
public function loadConfiguration()
{
return StaticCaller::anotherMethod('value');
}
}
?>

View File

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Rector\Core\Tests\Rector\MethodCall\MethodCallToStaticCallRector;
use Iterator;
use Rector\Core\Rector\MethodCall\MethodCallToStaticCallRector;
use Rector\Core\Testing\PHPUnit\AbstractRectorTestCase;
use Symplify\SmartFileSystem\SmartFileInfo;
final class MethodCallToStaticCallRectorTest extends AbstractRectorTestCase
{
/**
* @dataProvider provideData()
*/
public function test(SmartFileInfo $fileInfo): void
{
$this->doTestFileInfo($fileInfo);
}
public function provideData(): Iterator
{
return $this->yieldFilesFromDirectory(__DIR__ . '/Fixture');
}
protected function getRectorClass(): string
{
return MethodCallToStaticCallRector::class;
}
}