Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
96.55% covered (success)
96.55%
28 / 29
66.67% covered (warning)
66.67%
2 / 3
CRAP
0.00% covered (danger)
0.00%
0 / 1
ECSConfig
96.55% covered (success)
96.55%
28 / 29
66.67% covered (warning)
66.67%
2 / 3
5
0.00% covered (danger)
0.00%
0 / 1
 configure
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
2.01
 applyDefaultPathsAndSkips
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 applyDefaultRulesAndSets
100.00% covered (success)
100.00%
18 / 18
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3declare(strict_types=1);
4
5/**
6 * Fast Forward Development Tools for PHP projects.
7 *
8 * This file is part of fast-forward/dev-tools project.
9 *
10 * @author   Felipe SayĆ£o Lobato Abreu <github@mentordosnerds.com>
11 * @license  https://opensource.org/licenses/MIT MIT License
12 *
13 * @see      https://github.com/php-fast-forward/
14 * @see      https://github.com/php-fast-forward/dev-tools
15 * @see      https://github.com/php-fast-forward/dev-tools/issues
16 * @see      https://php-fast-forward.github.io/dev-tools/
17 * @see      https://datatracker.ietf.org/doc/html/rfc2119
18 */
19
20namespace FastForward\DevTools\Config;
21
22use FastForward\DevTools\Path\WorkingProjectPathResolver;
23use PhpCsFixer\Fixer\Import\GlobalNamespaceImportFixer;
24use PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer;
25use PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer;
26use PhpCsFixer\Fixer\Phpdoc\NoEmptyPhpdocFixer;
27use PhpCsFixer\Fixer\Phpdoc\NoSuperfluousPhpdocTagsFixer;
28use PhpCsFixer\Fixer\Phpdoc\PhpdocAddMissingParamAnnotationFixer;
29use PhpCsFixer\Fixer\Phpdoc\PhpdocNoEmptyReturnFixer;
30use PhpCsFixer\Fixer\Phpdoc\PhpdocToCommentFixer;
31use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer;
32use Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder;
33
34use function Safe\getcwd;
35
36/**
37 * Provides the default ECS configuration.
38 *
39 * Consumers can use this as a starting point and extend it:
40 *
41 *     $config = \FastForward\DevTools\Config\ECSConfig::configure();
42 *     $config->withRules([CustomRule::class]);
43 *     $config->withConfiguredRule(PhpdocAlignFixer::class, ['align' => 'right']);
44 *     return $config;
45 *
46 * @see https://github.com/symplify/easy-coding-standard
47 */
48 class ECSConfig
49{
50    /**
51     * @var array{symfony: bool, symfonyRisky: bool, auto: bool, autoRisky: bool} the PHP-CS-Fixer sets applied by default
52     */
53    public const array DEFAULT_PHP_CS_FIXER_SETS = [
54        'symfony' => true,
55        'symfonyRisky' => true,
56        'auto' => true,
57        'autoRisky' => true,
58    ];
59
60    /**
61     * @var array{psr12: bool, common: bool, symplify: bool, strict: bool, cleanCode: bool} the prepared ECS sets applied by default
62     */
63    public const array DEFAULT_PREPARED_SETS = [
64        'psr12' => true,
65        'common' => true,
66        'symplify' => true,
67        'strict' => true,
68        'cleanCode' => true,
69    ];
70
71    /**
72     * @var list<class-string> the ECS/CS Fixer rules that SHOULD be skipped by default
73     */
74    public const array DEFAULT_SKIPPED_RULES = [
75        PhpdocToCommentFixer::class,
76        NoSuperfluousPhpdocTagsFixer::class,
77        NoEmptyPhpdocFixer::class,
78        PhpdocNoEmptyReturnFixer::class,
79        GlobalNamespaceImportFixer::class,
80        GeneralPhpdocAnnotationRemoveFixer::class,
81    ];
82
83    /**
84     * @var array<class-string, array<string, mixed>> the configured ECS rules applied by default
85     */
86    public const array DEFAULT_CONFIGURED_RULES = [
87        PhpdocAlignFixer::class => [
88            'align' => 'left',
89        ],
90        PhpUnitTestCaseStaticMethodCallsFixer::class => [
91            'call_type' => 'self',
92        ],
93        PhpdocAddMissingParamAnnotationFixer::class => [
94            'only_untyped' => false,
95        ],
96    ];
97
98    /**
99     * Creates the default ECS configuration.
100     *
101     * @param callable|null $customize optional callback to customize the configuration builder
102     *
103     * @return ECSConfigBuilder the configured ECS configuration builder
104     */
105    public static function configure(?callable $customize = null): ECSConfigBuilder
106    {
107        $workingDirectory = getcwd();
108        $config = new ECSConfigBuilder();
109
110        self::applyDefaultPathsAndSkips($config, $workingDirectory);
111        self::applyDefaultRulesAndSets($config);
112
113        if (null !== $customize) {
114            $customize($config);
115        }
116
117        return $config;
118    }
119
120    /**
121     * Applies the default repository paths and skipped rules to an ECS builder.
122     *
123     * @param ECSConfigBuilder $config
124     * @param string $workingDirectory
125     */
126    public static function applyDefaultPathsAndSkips(
127        ECSConfigBuilder $config,
128        string $workingDirectory
129    ): ECSConfigBuilder {
130        $skipPaths = WorkingProjectPathResolver::getToolingExcludedDirectories($workingDirectory);
131
132        return $config
133            ->withPaths([$workingDirectory])
134            ->withSkip([...$skipPaths, ...self::DEFAULT_SKIPPED_RULES]);
135    }
136
137    /**
138     * Applies the default ECS sets, root files, and configured rules to an ECS builder.
139     *
140     * @param ECSConfigBuilder $config
141     */
142    public static function applyDefaultRulesAndSets(ECSConfigBuilder $config): ECSConfigBuilder
143    {
144        $config
145            ->withRootFiles()
146            ->withPhpCsFixerSets(
147                symfony: self::DEFAULT_PHP_CS_FIXER_SETS['symfony'],
148                symfonyRisky: self::DEFAULT_PHP_CS_FIXER_SETS['symfonyRisky'],
149                auto: self::DEFAULT_PHP_CS_FIXER_SETS['auto'],
150                autoRisky: self::DEFAULT_PHP_CS_FIXER_SETS['autoRisky'],
151            )
152            ->withPreparedSets(
153                psr12: self::DEFAULT_PREPARED_SETS['psr12'],
154                common: self::DEFAULT_PREPARED_SETS['common'],
155                symplify: self::DEFAULT_PREPARED_SETS['symplify'],
156                strict: self::DEFAULT_PREPARED_SETS['strict'],
157                cleanCode: self::DEFAULT_PREPARED_SETS['cleanCode'],
158            );
159
160        foreach (self::DEFAULT_CONFIGURED_RULES as $rule => $configuration) {
161            $config->withConfiguredRule($rule, $configuration);
162        }
163
164        return $config;
165    }
166}