diff --git a/ecs.php b/ecs.php index a808d47..b92f42d 100644 --- a/ecs.php +++ b/ecs.php @@ -26,16 +26,44 @@ use PhpCsFixer\Fixer\Phpdoc\PhpdocToCommentFixer; use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestCaseStaticMethodCallsFixer; use Symplify\EasyCodingStandard\Config\ECSConfig; +use Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder; use function Safe\getcwd; +/** + * Base ECS configuration for dev-tools. + * + * This configuration can be extended in consumer projects using one of the following patterns: + * + * 1. Use directly (recommended): + * ```php + * return require __DIR__ . '/vendor/fast-forward/dev-tools/ecs.php'; + * ``` + * + * 2. Extend with custom rules: + * ```php + * $builder = require __DIR__ . '/vendor/fast-forward/dev-tools/ecs.php'; + * return $builder->withRules([CustomRule::class]); + * ``` + * + * 3. Using the factory (recommended for advanced use cases): + * ```php + * use FastForward\DevTools\Config\EcsConfigFactory; + * + * return EcsConfigFactory::create(); + * ``` + * + * @return ECSConfigBuilder the pre-configured ECS configuration builder + */ +$cwd = getcwd(); + return ECSConfig::configure() - ->withPaths([getcwd()]) + ->withPaths([$cwd]) ->withSkip([ - getcwd() . '/public', - getcwd() . '/resources', - getcwd() . '/vendor', - getcwd() . '/tmp', + $cwd . '/public', + $cwd . '/resources', + $cwd . '/vendor', + $cwd . '/tmp', PhpdocToCommentFixer::class, NoSuperfluousPhpdocTagsFixer::class, NoEmptyPhpdocFixer::class, diff --git a/src/Config/EcsConfigFactory.php b/src/Config/EcsConfigFactory.php new file mode 100644 index 0000000..ec64bad --- /dev/null +++ b/src/Config/EcsConfigFactory.php @@ -0,0 +1,146 @@ + + * @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\Config\ECSConfig; +use Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder; + +use function Safe\getcwd; + +/** + * Factory for creating and extending the ECS (EasyCodingStandard) configuration. + * + * This factory allows consumers to build on top of the base configuration provided + * by the dev-tools package instead of replacing it entirely. Consumers can extend + * the configuration with custom rules, paths, skips, and other options while + * preserving the ability to receive upstream updates automatically. + * + * Usage examples: + * + * 1. Using the factory method (recommended): + * ```php + * use FastForward\DevTools\Config\EcsConfigFactory; + * + * return EcsConfigFactory::create(); + * ``` + * + * 2. Using the require pattern: + * ```php + * return require __DIR__ . '/vendor/fast-forward/dev-tools/ecs.php'; + * ``` + * + * 3. Extending the base configuration: + * ```php + * $builder = require __DIR__ . '/vendor/fast-forward/dev-tools/ecs.php'; + * return $builder->withRules([CustomRule::class]); + * ``` + */ +final class EcsConfigFactory +{ + /** + * Creates and returns a pre-configured ECSConfigBuilder with the base dev-tools rules. + * + * This method returns the base configuration builder that consumers can further + * customize with additional rules, paths, skips, or configured rules. + * + * @return ECSConfigBuilder the pre-configured ECS configuration builder + */ + public static function create(): ECSConfigBuilder + { + $cwd = getcwd(); + + return ECSConfig::configure() + ->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, + ]); + } + + /** + * Loads and returns the base ECS configuration from the dev-tools package. + * + * This method can be used to require the base configuration file directly, + * providing full control over the configuration object. + * + * @param string|null $workingDirectory the working directory to use (defaults to cwd) + * + * @return ECSConfigBuilder the pre-configured ECS configuration builder + */ + public static function loadBaseConfiguration(?string $workingDirectory = null): ECSConfigBuilder + { + $cwd = $workingDirectory ?? getcwd(); + + return ECSConfig::configure() + ->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, + ]); + } +} diff --git a/tests/Config/EcsConfigFactoryTest.php b/tests/Config/EcsConfigFactoryTest.php new file mode 100644 index 0000000..a2ab104 --- /dev/null +++ b/tests/Config/EcsConfigFactoryTest.php @@ -0,0 +1,76 @@ + + * @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\Tests\Config; + +use FastForward\DevTools\Config\EcsConfigFactory; +use PHPUnit\Framework\Attributes\CoversClass; +use PHPUnit\Framework\Attributes\Test; +use PHPUnit\Framework\TestCase; +use Prophecy\PhpUnit\ProphecyTrait; +use Symplify\EasyCodingStandard\Configuration\ECSConfigBuilder; + +#[CoversClass(EcsConfigFactory::class)] +final class EcsConfigFactoryTest extends TestCase +{ + use ProphecyTrait; + + /** + * @return void + */ + #[Test] + public function createWillReturnEcsConfigBuilderInstance(): void + { + $config = EcsConfigFactory::create(); + + self::assertInstanceOf(ECSConfigBuilder::class, $config); + } + + /** + * @return void + */ + #[Test] + public function loadBaseConfigurationWillReturnEcsConfigBuilderInstance(): void + { + $config = EcsConfigFactory::loadBaseConfiguration(); + + self::assertInstanceOf(ECSConfigBuilder::class, $config); + } + + /** + * @return void + */ + #[Test] + public function loadBaseConfigurationWithCustomWorkingDirectory(): void + { + $config = EcsConfigFactory::loadBaseConfiguration('/custom/path'); + + self::assertInstanceOf(ECSConfigBuilder::class, $config); + } + + /** + * @return void + */ + #[Test] + public function createWithCustomWorkingDirectoryWillReturnEcsConfigBuilderInstance(): void + { + $config = EcsConfigFactory::create(); + + self::assertInstanceOf(ECSConfigBuilder::class, $config); + } +}