load rector.php config

This commit is contained in:
TomasVotruba 2020-07-18 20:26:57 +02:00
parent 7bb09e7ed1
commit bda3e5aa28
14 changed files with 123 additions and 152 deletions

2
.gitignore vendored
View File

@ -9,7 +9,7 @@ composer.lock
.phpunit.result.cache
# often customized locally - example on Github is just fine
create-rector.yaml
create-rector.php
# tests - travis
/laravel-dir

View File

@ -119,6 +119,23 @@ parameters:
- code-quality
```
You can also use `rector.php` as new [Symfony best practice](https://twitter.com/symfony_en/status/1284538366147678208):
```php
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::SETS, ['code-quality']);
};
```
### B. Standalone Rules
In the end, it's best to combine few of basic sets and drop [particular rules](/docs/rector_rules_overview.md) that you want to try:

View File

@ -196,7 +196,7 @@ final class RectorConfigsResolver
// And from --config or default one
$inputOrFallbackConfig = $this->configResolver->resolveFromInputWithFallback(
$input,
['rector.yml', 'rector.yaml']
['rector.yml', 'rector.yaml', 'rector.php']
);
if ($inputOrFallbackConfig !== null) {
$configs[] = $inputOrFallbackConfig;

49
create-rector.php.dist Normal file
View File

@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
use PhpParser\Node\Stmt\ClassMethod;
use Rector\Core\Configuration\Option;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$parameters = $containerConfigurator->parameters();
$parameters->set(Option::RECTOR_RECIPE, [
# run "bin/rector create" to create a new Rector + tests from this config
'package' => 'Symfony',
'name' => 'RemoveDefaultGetBlockPrefixRector',
'node_types' => [
ClassMethod::class,
],
'description' => 'Rename `getBlockPrefix()` if it returns the default value - class to underscore, e.g. UserFormType = user_form',
'code_before' => <<<'CODE_SAMPLE'
<?php
use Symfony\Component\Form\AbstractType;
class TaskType extends AbstractType
{
public function getBlockPrefix()
{
return 'task';
}
}
CODE_SAMPLE,
'code_after' => <<<'CODE_SAMPLE'
<?php
use Symfony\Component\Form\AbstractType;
class TaskType extends AbstractType
{
}
CODE_SAMPLE,
'source' => [
# e.g. link to RFC or headline in upgrade guide, 1 or more in the list
'https://github.com/symfony/symfony/blob/3.4/UPGRADE-3.0.md',
],
# e.g. symfony30, target config to append this rector to
'set' => 'symfony30',
]);
};

View File

@ -33,9 +33,11 @@ return static function (ContainerConfigurator $containerConfigurator): void {
$services->set(StandaloneLineInMultilineArrayFixer::class);
$services->set(GeneralPhpdocAnnotationRemoveFixer::class)
->call('configure', [[
'annotations' => ['throws', 'author', 'package', 'group'],
]]);
->call('configure', [
[
'annotations' => ['throws', 'author', 'package', 'group'],
],
]);
$services->set(LineLengthFixer::class);

View File

@ -6,6 +6,7 @@ namespace Rector\RectorGenerator\Config;
use Nette\Utils\FileSystem;
use Nette\Utils\Strings;
use Rector\Core\Exception\NotImplementedYetException;
use Rector\RectorGenerator\TemplateFactory;
use Rector\RectorGenerator\ValueObject\Configuration;
@ -47,18 +48,8 @@ final class ConfigFilesystem
return;
}
$newSetConfigContent = trim($setConfigContent) . sprintf(
'%s%s: null%s',
PHP_EOL,
$this->indentFourSpaces($rectorFqnName),
PHP_EOL
);
throw new NotImplementedYetException('Add *.php config rule append support');
FileSystem::write($configuration->getSetConfig(), $newSetConfigContent);
}
private function indentFourSpaces(string $string): string
{
return Strings::indent($string, 4, ' ');
// FileSystem::write($configuration->getSetConfig(), $newSetConfigContent);
}
}

View File

@ -40,7 +40,7 @@ final class ConfigResolver
*/
private function getSetFileInfos(string $set): array
{
$fileSet = sprintf('#^%s(\.yaml)?$#', $set);
$fileSet = sprintf('#^%s\.php)?$#', $set);
$finder = Finder::create()->files()
->in(Set::SET_DIRECTORY)
->name($fileSet);

View File

@ -5,20 +5,12 @@ declare(strict_types=1);
namespace Rector\RectorGenerator\Configuration;
use Nette\Utils\Strings;
use PhpParser\Node;
use Rector\Core\Exception\ShouldNotHappenException;
use Rector\RectorGenerator\ConfigResolver;
use Rector\RectorGenerator\Guard\RecipeGuard;
use Rector\RectorGenerator\Node\NodeClassProvider;
use Rector\RectorGenerator\ValueObject\Configuration;
final class ConfigurationFactory
{
/**
* @var NodeClassProvider
*/
private $nodeClassProvider;
/**
* @var RecipeGuard
*/
@ -29,12 +21,8 @@ final class ConfigurationFactory
*/
private $configResolver;
public function __construct(
NodeClassProvider $nodeClassProvider,
RecipeGuard $recipeGuard,
ConfigResolver $configResolver
) {
$this->nodeClassProvider = $nodeClassProvider;
public function __construct(RecipeGuard $recipeGuard, ConfigResolver $configResolver)
{
$this->recipeGuard = $recipeGuard;
$this->configResolver = $configResolver;
}
@ -46,14 +34,14 @@ final class ConfigurationFactory
{
$this->recipeGuard->ensureRecipeIsValid($rectorRecipe);
$fqnNodeTypes = $this->resolveFullyQualifiedNodeTypes($rectorRecipe['node_types']);
$category = $this->resolveCategoryFromFqnNodeTypes($fqnNodeTypes);
$nodeTypeClasses = $rectorRecipe['node_types'];
$category = $this->resolveCategoryFromFqnNodeTypes($nodeTypeClasses);
return new Configuration(
$rectorRecipe['package'],
$rectorRecipe['name'],
$category,
$this->resolveFullyQualifiedNodeTypes($rectorRecipe['node_types']),
$nodeTypeClasses,
$rectorRecipe['description'],
$this->normalizeCode($rectorRecipe['code_before']),
$this->normalizeCode($rectorRecipe['code_after']),
@ -67,34 +55,6 @@ final class ConfigurationFactory
);
}
/**
* @param string[] $nodeTypes
* @return string[]
*/
private function resolveFullyQualifiedNodeTypes(array $nodeTypes): array
{
$nodeClasses = $this->nodeClassProvider->getNodeClasses();
$fqnNodeTypes = [];
foreach ($nodeTypes as $nodeType) {
if ($nodeType === 'Node') {
$fqnNodeTypes[] = Node::class;
continue;
}
foreach ($nodeClasses as $nodeClass) {
if ($this->isNodeClassMatch($nodeClass, $nodeType)) {
$fqnNodeTypes[] = $nodeClass;
continue 2;
}
}
throw new ShouldNotHappenException(sprintf('Node endings with "%s" was not found', $nodeType));
}
return array_unique($fqnNodeTypes);
}
/**
* @param string[] $fqnNodeTypes
*/
@ -116,19 +76,4 @@ final class ConfigurationFactory
{
return Strings::startsWith($code, '<?php');
}
private function isNodeClassMatch(string $nodeClass, string $nodeType): bool
{
// skip "magic", they're used less than rarely
if (Strings::contains($nodeClass, 'MagicConst')) {
return false;
}
if (Strings::endsWith($nodeClass, '\\' . $nodeType)) {
return true;
}
// in case of forgotten _
return Strings::endsWith($nodeClass, '\\' . $nodeType . '_');
}
}

View File

@ -1,33 +0,0 @@
<?php
declare(strict_types=1);
namespace Rector\RectorGenerator\Node;
use Nette\Loaders\RobotLoader;
final class NodeClassProvider
{
/**
* @return string[]
*/
public function getNodeClasses(): array
{
$robotLoader = new RobotLoader();
$robotLoader->addDirectory($this->getDirectoryPath());
$robotLoader->setTempDirectory(sys_get_temp_dir() . '/_robotloader_nodes');
$robotLoader->rebuild();
return array_keys($robotLoader->getIndexedClasses());
}
private function getDirectoryPath(): string
{
$pathUsedAsStandaloneProject = __DIR__ . '/../../../../vendor/nikic/php-parser/lib/PhpParser/Node';
$pathUsedAsDependency = __DIR__ . '/../../../../../../nikic/php-parser/lib/PhpParser/Node';
return ! file_exists($pathUsedAsStandaloneProject)
? $pathUsedAsDependency
: $pathUsedAsStandaloneProject;
}
}

View File

@ -81,8 +81,8 @@ final class Configuration
string $description,
string $codeBefore,
string $codeAfter,
?string $extraFileContent = null,
?string $extraFileName = null,
?string $extraFileContent,
?string $extraFileName,
array $source,
?string $setConfig,
bool $isPhpSnippet

30
rector.php Normal file
View File

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
use Rector\Core\Configuration\Option;
use Rector\Decomplex\Rector\MethodCall\UseMessageVariableForSprintfInSymfonyStyleRector;
use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator;
return static function (ContainerConfigurator $containerConfigurator): void {
$containerConfigurator->import(__DIR__ . '/create-rector.php', null, 'not_found');
$services = $containerConfigurator->services();
$services->set(UseMessageVariableForSprintfInSymfonyStyleRector::class);
$parameters = $containerConfigurator->parameters();
# Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector: null
# Rector\Autodiscovery\Rector\FileSystem\MoveInterfacesToContractNamespaceDirectoryRector: null
# bleeding edge feature
# is_cache_enabled: true
$parameters->set(Option::AUTO_IMPORT_NAMES, true);
$parameters->set(Option::PATHS, [__DIR__ . '/src', __DIR__ . '/tests', __DIR__ . '/rules', __DIR__ . '/utils', __DIR__ . '/packages']);
$parameters->set(Option::EXCLUDE_PATHS, ['/Source/', '/*Source/', '/Fixture/', '/Expected/', __DIR__ . '/packages/doctrine-annotation-generated/src/*', '*.php.inc']);
# so Rector code is still PHP 7.2 compatible
$parameters->set(Option::PHP_VERSION_FEATURES, '7.2');
};

View File

@ -1,35 +0,0 @@
imports:
- { resource: "create-rector.yaml", ignore_errors: 'not_found' }
services:
Rector\Decomplex\Rector\MethodCall\UseMessageVariableForSprintfInSymfonyStyleRector: null
# Rector\Naming\Rector\ClassMethod\RenameVariableToMatchNewTypeRector: null
# Rector\Autodiscovery\Rector\FileSystem\MoveInterfacesToContractNamespaceDirectoryRector: null
parameters:
# bleeding edge feature
# is_cache_enabled: true
auto_import_names: true
paths:
- src
- tests
- rules
- utils
- packages
exclude_paths:
- "/Source/"
- "/*Source/"
- "/Fixture/"
- "/Expected/"
# generated
- 'packages/doctrine-annotation-generated/src/*'
# autoload-buggy cases
- "*.php.inc"
# so Rector code is still PHP 7.2 compatible
php_version_features: '7.2'

View File

@ -125,4 +125,9 @@ final class Option
* @var string
*/
public const FILE_EXTENSIONS = 'file_extensions';
/**
* @var string
*/
public const RECTOR_RECIPE = 'rector_recipe';
}

View File

@ -6,6 +6,8 @@ namespace Rector\Core\Tests\Configuration;
use Iterator;
use Rector\Core\Configuration\MinimalVersionChecker;
use Rector\Core\Configuration\MinimalVersionChecker\ComposerJsonParser;
use Rector\Core\Configuration\MinimalVersionChecker\ComposerJsonReader;
use Rector\Core\Exception\Application\PhpVersionException;
use Symplify\PackageBuilder\Tests\AbstractKernelTestCase;
@ -16,12 +18,10 @@ final class MinimalVersionCheckerTest extends AbstractKernelTestCase
*/
public function test(string $version, bool $shouldThrowException): void
{
$composerJsonReader = new MinimalVersionChecker\ComposerJsonReader(
__DIR__ . '/MinimalVersionChecker/composer-7.2.0.json'
);
$composerJsonReader = new ComposerJsonReader(__DIR__ . '/MinimalVersionChecker/composer-7.2.0.json');
$minimalVersionChecker = new MinimalVersionChecker(
$version,
new MinimalVersionChecker\ComposerJsonParser($composerJsonReader->read())
new ComposerJsonParser($composerJsonReader->read())
);
if ($shouldThrowException) {