-
-
Notifications
You must be signed in to change notification settings - Fork 449
Expand file tree
/
Copy pathOnlyRuleResolver.php
More file actions
130 lines (109 loc) · 3.99 KB
/
Copy pathOnlyRuleResolver.php
File metadata and controls
130 lines (109 loc) · 3.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<?php
declare(strict_types=1);
namespace Rector\Configuration;
use Rector\Contract\Rector\RectorInterface;
use Rector\Exception\Configuration\RectorRuleNameAmbiguousException;
use Rector\Exception\Configuration\RectorRuleNotFoundException;
use ReflectionClass;
/**
* @see \Rector\Tests\Configuration\OnlyRuleResolverTest
*/
final readonly class OnlyRuleResolver
{
/**
* @param RectorInterface[] $rectors
*/
public function __construct(
private array $rectors,
) {
}
public function resolve(string $rule): string
{
// fix wrongly double escaped backslashes
$rule = str_replace('\\\\', '\\', $rule);
// remove single quotes appearing when single-quoting arguments on windows
if (str_starts_with($rule, "'") && str_ends_with($rule, "'")) {
$rule = substr($rule, 1, -1);
}
$rule = ltrim($rule, '\\');
foreach ($this->rectors as $rector) {
if ($rector::class === $rule) {
return $rule;
}
}
// allow short rule names if there are not duplicates
$matching = [];
foreach ($this->rectors as $rector) {
if (str_ends_with($rector::class, '\\' . $rule)) {
$matching[] = $rector::class;
}
}
$matching = array_unique($matching);
if (count($matching) === 1) {
return $matching[0];
}
if (count($matching) > 1) {
sort($matching);
$message = sprintf(
'Short rule name "%s" is ambiguous. Specify the full rule name:' . PHP_EOL
. '- ' . implode(PHP_EOL . '- ', $matching),
$rule
);
throw new RectorRuleNameAmbiguousException($message);
}
if (! str_contains($rule, '\\')) {
// the shell has eaten unescaped backslashes, e.g. --only=\Rector\Some\Rule
$flattenMatching = [];
foreach ($this->rectors as $rector) {
if (str_replace('\\', '', $rector::class) === $rule) {
$flattenMatching[] = $rector::class;
}
}
$flattenMatching = array_unique($flattenMatching);
if (count($flattenMatching) === 1) {
return $flattenMatching[0];
}
$message = sprintf(
'Rule "%s" was not found.%sThe rule has no namespace. Make sure to escape the backslashes, and add quotes around the rule name: --only="My\\Rector\\Rule"',
$rule,
PHP_EOL
);
} else {
// the rule class exists, it is just missing in the config
if ($this->isRectorRuleClass($rule)) {
throw new RectorRuleNotFoundException($this->createUnregisteredMessage($rule));
}
$message = sprintf(
'Rule "%s" was not found.%sMake sure it is registered in your config or in one of the sets',
$rule,
PHP_EOL
);
}
throw new RectorRuleNotFoundException($message);
}
/**
* Is this an existing rule class, that is just not registered in the config?
*/
private function isRectorRuleClass(string $className): bool
{
if (! class_exists($className)) {
return false;
}
$reflectionClass = new ReflectionClass($className);
if ($reflectionClass->isAbstract()) {
return false;
}
return $reflectionClass->implementsInterface(RectorInterface::class);
}
private function createUnregisteredMessage(string $ruleClass): string
{
$shortRuleClass = substr((string) strrchr($ruleClass, '\\'), 1);
return sprintf(
'Rule "%s" exists, but is not registered in your Rector config.%sRegister it in your rector.php:'
. PHP_EOL . PHP_EOL . ' ->withRules([%s::class])',
$ruleClass,
PHP_EOL,
$shortRuleClass
);
}
}