mirror of
https://github.com/rectorphp/rector.git
synced 2025-01-18 22:08:00 +01:00
add RecipeOption to prevent typos; first attempt to use constant-named parameters
This commit is contained in:
parent
f845935e4a
commit
cdd3935ef6
@ -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
|
||||
|
@ -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');
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
63
packages/rector-generator/src/ValueObject/RecipeOption.php
Normal file
63
packages/rector-generator/src/ValueObject/RecipeOption.php
Normal 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';
|
||||
}
|
77
src/Rector/MethodCall/MethodCallToStaticCallRector.php
Normal file
77
src/Rector/MethodCall/MethodCallToStaticCallRector.php
Normal 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;
|
||||
}
|
||||
}
|
@ -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');
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
@ -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;
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user