• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

keradus / PHP-CS-Fixer / 17642215709

11 Sep 2025 10:50AM UTC coverage: 94.689% (+0.003%) from 94.686%
17642215709

push

github

keradus
Merge remote-tracking branch 'upstream/master' into __modifier_keywords

10 of 10 new or added lines in 2 files covered. (100.0%)

77 existing lines in 10 files now uncovered.

28421 of 30015 relevant lines covered (94.69%)

45.51 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.87
/src/RuleSet/RuleSet.php
1
<?php
2

3
declare(strict_types=1);
4

5
/*
6
 * This file is part of PHP CS Fixer.
7
 *
8
 * (c) Fabien Potencier <fabien@symfony.com>
9
 *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
10
 *
11
 * This source file is subject to the MIT license that is bundled
12
 * with this source code in the file LICENSE.
13
 */
14

15
namespace PhpCsFixer\RuleSet;
16

17
use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
18
use PhpCsFixer\Future;
19
use PhpCsFixer\Utils;
20

21
/**
22
 * Set of rules to be used by fixer.
23
 *
24
 * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
25
 *
26
 * @readonly
27
 *
28
 * @internal
29
 *
30
 * @no-named-arguments Parameter names are not covered by the backward compatibility promise.
31
 */
32
final class RuleSet implements RuleSetInterface
33
{
34
    /**
35
     * Group of rules generated from input set.
36
     *
37
     * The key is name of rule, value is configuration array or true.
38
     * The key must not point to any set.
39
     *
40
     * @var array<string, array<string, mixed>|true>
41
     */
42
    private array $rules;
43

44
    public function __construct(array $set = [])
45
    {
46
        foreach ($set as $name => $value) {
62✔
47
            if ('' === $name) {
61✔
48
                throw new \InvalidArgumentException('Rule/set name must not be empty.');
1✔
49
            }
50

51
            if (\is_int($name)) {
60✔
52
                throw new \InvalidArgumentException(\sprintf('Missing value for "%s" rule/set.', $value));
1✔
53
            }
54

55
            if (!\is_bool($value) && !\is_array($value)) {
59✔
56
                $message = str_starts_with($name, '@') ? 'Set must be enabled (true) or disabled (false). Other values are not allowed.' : 'Rule must be enabled (true), disabled (false) or configured (non-empty, assoc array). Other values are not allowed.';
1✔
57

58
                if (null === $value) {
1✔
59
                    $message .= ' To disable the '.(str_starts_with($name, '@') ? 'set' : 'rule').', use "FALSE" instead of "NULL".';
1✔
60
                }
61

62
                throw new InvalidFixerConfigurationException($name, $message);
1✔
63
            }
64
        }
65

66
        $this->rules = $this->resolveSet($set);
59✔
67
    }
68

69
    public function hasRule(string $rule): bool
70
    {
71
        return \array_key_exists($rule, $this->rules);
54✔
72
    }
73

74
    public function getRuleConfiguration(string $rule): ?array
75
    {
76
        if (!$this->hasRule($rule)) {
54✔
77
            throw new \InvalidArgumentException(\sprintf('Rule "%s" is not in the set.', $rule));
1✔
78
        }
79

80
        if (true === $this->rules[$rule]) {
53✔
81
            return null;
39✔
82
        }
83

84
        return $this->rules[$rule];
42✔
85
    }
86

87
    public function getRules(): array
88
    {
89
        return $this->rules;
56✔
90
    }
91

92
    /**
93
     * Resolve input set into group of rules.
94
     *
95
     * @param array<string, array<string, mixed>|bool> $rules
96
     *
97
     * @return array<string, array<string, mixed>|true>
98
     */
99
    private function resolveSet(array $rules): array
100
    {
101
        $resolvedRules = [];
59✔
102

103
        // expand sets
104
        foreach ($rules as $name => $value) {
59✔
105
            if (str_starts_with($name, '@')) {
58✔
106
                if (!\is_bool($value)) {
58✔
107
                    throw new \UnexpectedValueException(\sprintf('Nested rule set "%s" configuration must be a boolean.', $name));
1✔
108
                }
109

110
                $set = $this->resolveSubset($name, $value);
57✔
111
                $resolvedRules = array_merge($resolvedRules, $set);
56✔
112
            } else {
113
                $resolvedRules[$name] = $value;
3✔
114
            }
115
        }
116

117
        // filter out all resolvedRules that are off
118
        $resolvedRules = array_filter(
57✔
119
            $resolvedRules,
57✔
120
            static fn ($value): bool => false !== $value
57✔
121
        );
57✔
122

123
        return $resolvedRules;
57✔
124
    }
125

126
    /**
127
     * Resolve set rules as part of another set.
128
     *
129
     * If set value is false then disable all fixers in set,
130
     * if not then get value from set item.
131
     *
132
     * @return array<string, array<string, mixed>|bool>
133
     */
134
    private function resolveSubset(string $setName, bool $setValue): array
135
    {
136
        $ruleSet = RuleSets::getSetDefinition($setName);
57✔
137

138
        if ($ruleSet instanceof DeprecatedRuleSetDescriptionInterface) {
56✔
139
            $messageEnd = [] === $ruleSet->getSuccessorsNames()
2✔
UNCOV
140
                ? 'No replacement available'
×
141
                : \sprintf('Use %s instead', Utils::naturalLanguageJoin($ruleSet->getSuccessorsNames()));
2✔
142

143
            Future::triggerDeprecation(new \RuntimeException("Rule set \"{$setName}\" is deprecated. {$messageEnd}."));
2✔
144
        }
145

146
        $rules = $ruleSet->getRules();
56✔
147

148
        foreach ($rules as $name => $value) {
56✔
149
            if (str_starts_with($name, '@')) {
56✔
150
                $set = $this->resolveSubset($name, $setValue);
49✔
151
                unset($rules[$name]);
49✔
152
                $rules = array_merge($rules, $set);
49✔
153
            } elseif (!$setValue) {
56✔
154
                $rules[$name] = false;
2✔
155
            } else {
156
                $rules[$name] = $value;
56✔
157
            }
158
        }
159

160
        return $rules;
56✔
161
    }
162
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc