Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions docs/configuration/overriding-defaults.rst
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,31 @@ To customize Rector for one library, create ``rector.php`` in the consumer
project root. The ``refactor`` command and the Rector phase inside ``phpdoc``
will use that file instead of the packaged default.

Extending ECS Configuration
----------------------------

Instead of copying the entire ``ecs.php`` file, consumers can extend the
default configuration using the ``ECSConfig`` class:

.. code-block:: php

<?php

use FastForward\DevTools\Config\ECSConfig;
use PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer;

$config = ECSConfig::configure();
$config->withRules([CustomRule::class]);
$config->withConfiguredRule(PhpdocAlignFixer::class, ['align' => 'right']);

return $config;

This approach:

- Eliminates duplication of the base configuration
- Automatically receives upstream updates
- Only requires overriding what is needed

What Is Not Overwritten Automatically
-------------------------------------

Expand Down
18 changes: 18 additions & 0 deletions docs/faq.rst
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,24 @@ Create only the local configuration file you want to customize, such as
``rector.php`` or ``phpunit.xml``. DevTools will prefer that file and keep the
rest on the packaged defaults.

How do I extend the ECS configuration without copying the whole file?
----------------------------------------------------------------------

Use the ``ECSConfig`` class to extend instead of replace:

.. code-block:: php

<?php

use FastForward\DevTools\Config\ECSConfig;

$config = ECSConfig::configure();
$config->withRules([CustomRule::class]);

return $config;

This approach automatically receives upstream updates while allowing additive customization.

Can I generate coverage without running the full ``standards`` pipeline?
------------------------------------------------------------------------

Expand Down
40 changes: 2 additions & 38 deletions ecs.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,42 +16,6 @@
* @see https://datatracker.ietf.org/doc/html/rfc2119
*/

use PhpCsFixer\Fixer\Import\GlobalNamespaceImportFixer;
use PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer;
use PhpCsFixer\Fixer\Phpdoc\NoEmptyPhpdocFixer;
use PhpCsFixer\Fixer\Phpdoc\NoSuperfluousPhpdocTagsFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocAddMissingParamAnnotationFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocNoEmptyReturnFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocToCommentFixer;
use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer;
use Symplify\EasyCodingStandard\Config\ECSConfig;
use FastForward\DevTools\Config\ECSConfig;

use function Safe\getcwd;

return ECSConfig::configure()
->withPaths([getcwd()])
->withSkip([
getcwd() . '/public',
getcwd() . '/resources',
getcwd() . '/vendor',
getcwd() . '/tmp',
PhpdocToCommentFixer::class,
NoSuperfluousPhpdocTagsFixer::class,
NoEmptyPhpdocFixer::class,
PhpdocNoEmptyReturnFixer::class,
GlobalNamespaceImportFixer::class,
GeneralPhpdocAnnotationRemoveFixer::class,
])
->withRootFiles()
->withPhpCsFixerSets(symfony: true, symfonyRisky: true, auto: true, autoRisky: true)
->withPreparedSets(psr12: true, common: true, symplify: true, strict: true, cleanCode: true)
->withConfiguredRule(PhpdocAlignFixer::class, [
'align' => 'left',
])
->withConfiguredRule(PhpUnitTestCaseStaticMethodCallsFixer::class, [
'call_type' => 'self',
])
->withConfiguredRule(PhpdocAddMissingParamAnnotationFixer::class, [
'only_untyped' => false,
]);
return ECSConfig::configure();
85 changes: 85 additions & 0 deletions src/Config/ECSConfig.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);

/**
* This file is part of fast-forward/dev-tools.
*
* This source file is subject to the license bundled
* with this source code in the file LICENSE.
*
* @copyright Copyright (c) 2026 Felipe Sayão Lobato Abreu <github@mentordosnerds.com>
* @license https://opensource.org/licenses/MIT MIT License
*
* @see https://github.com/php-fast-forward/dev-tools
* @see https://github.com/php-fast-forward
* @see https://datatracker.ietf.org/doc/html/rfc2119
*/

namespace FastForward\DevTools\Config;

use PhpCsFixer\Fixer\Import\GlobalNamespaceImportFixer;
use PhpCsFixer\Fixer\Phpdoc\GeneralPhpdocAnnotationRemoveFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocAlignFixer;
use PhpCsFixer\Fixer\Phpdoc\NoEmptyPhpdocFixer;
use PhpCsFixer\Fixer\Phpdoc\NoSuperfluousPhpdocTagsFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocAddMissingParamAnnotationFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocNoEmptyReturnFixer;
use PhpCsFixer\Fixer\Phpdoc\PhpdocToCommentFixer;
use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer;
use Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder;

use function Safe\getcwd;

/**
* Provides the default ECS configuration.
*
* Consumers can use this as a starting point and extend it:
*
* $config = \FastForward\DevTools\Config\ECSConfig::configure();
* $config->withRules([CustomRule::class]);
* $config->withConfiguredRule(PhpdocAlignFixer::class, ['align' => 'right']);
* return $config;
*
* @see https://github.com/symplify/easy-coding-standard
*/
final class ECSConfig
{
/**
* Creates the default ECS configuration.
*
* @return ECSConfigBuilder the configured ECS configuration builder
*/
public static function configure(): ECSConfigBuilder
{
$cwd = getcwd();
$config = new ECSConfigBuilder();

return $config
->withPaths([$cwd])
->withSkip([
$cwd . '/public',
$cwd . '/resources',
$cwd . '/vendor',
$cwd . '/tmp',
PhpdocToCommentFixer::class,
NoSuperfluousPhpdocTagsFixer::class,
NoEmptyPhpdocFixer::class,
PhpdocNoEmptyReturnFixer::class,
GlobalNamespaceImportFixer::class,
GeneralPhpdocAnnotationRemoveFixer::class,
])
->withRootFiles()
->withPhpCsFixerSets(symfony: true, symfonyRisky: true, auto: true, autoRisky: true)
->withPreparedSets(psr12: true, common: true, symplify: true, strict: true, cleanCode: true)
->withConfiguredRule(PhpdocAlignFixer::class, [
'align' => 'left',
])
->withConfiguredRule(PhpUnitTestCaseStaticMethodCallsFixer::class, [
'call_type' => 'self',
])
->withConfiguredRule(PhpdocAddMissingParamAnnotationFixer::class, [
'only_untyped' => false,
]);
}
}
Loading