Description
Problem
Currently, the rector.php configuration is effectively treated as a fully replaceable file. Any project that needs to add, remove, or adjust rules must copy the whole configuration instead of building on top of the default one.
This creates a few problems:
- Configuration duplication: even small customizations require copying the entire base file
- Upstream drift: improvements to the original rector.php do not flow automatically to consuming projects
- Higher maintenance cost: consumers need to manually keep their custom file in sync with repository changes
- Limited flexibility: there is no clean way to extend the default sets, skips, paths, or rules incrementally
Proposed Solution
Allow rector.php to be extensible instead of replaceable, so consumers can reuse the default configuration and only customize what they need.
Possible approaches:
1. Return a reusable configurator or closure
Instead of making the file only usable as a standalone replacement, expose the default Rector configuration in a way that can be imported and extended:
$configure = require __DIR__ . '/vendor/fast-forward/dev-tools/rector.php';
return static function (\Rector\Config\RectorConfig $rectorConfig): void {
$configure($rectorConfig);
$rectorConfig->rules([
// project-specific rules
]);
$rectorConfig->skip([
// project-specific skips
]);
};
This would let consumers start from the package defaults and append their own changes.
2. Provide a factory/helper class
Expose a dedicated entry point such as a factory or helper:
use FastForward\DevTools\Rector\RectorConfigFactory;
use Rector\Config\RectorConfig;
return static function (RectorConfig $rectorConfig): void {
RectorConfigFactory::configure($rectorConfig);
$rectorConfig->rules([
// custom rules
]);
};
This reduces coupling to a file path and makes the extension mechanism explicit.
3. Accept override callbacks or extra config files
Allow the base package to load an extra config layer after applying its defaults, so projects can augment the base behavior without redefining it entirely.
For example, consumers could provide a second file containing only project-specific adjustments.
4. Split the default config into reusable pieces
Another option would be to separate reusable concerns such as:
- default sets
- default skips
- default rules
- default paths/cache setup
This would let consumers compose only what they need while still relying on the shared defaults.
Expected Behavior
- Consumers SHOULD be able to reuse the default rector.php configuration without copying it
- Consumers SHOULD be able to append or override sets, rules, skips, and paths
- Upstream improvements SHOULD continue to apply automatically unless explicitly overridden
Benefits
- Less duplication
- Easier upgrades
- Lower maintenance burden
- Better composability
- More predictable project-level customization
Additional Context
This is especially useful for projects that want to keep the package defaults but add a few custom Rector rules, skip specific directories, or tailor behavior for framework- or domain-specific code.
Today, even a small customization requires replacing the whole file, which makes long-term maintenance harder than necessary.
Description
Problem
Currently, the
rector.phpconfiguration is effectively treated as a fully replaceable file. Any project that needs to add, remove, or adjust rules must copy the whole configuration instead of building on top of the default one.This creates a few problems:
Proposed Solution
Allow
rector.phpto be extensible instead of replaceable, so consumers can reuse the default configuration and only customize what they need.Possible approaches:
1. Return a reusable configurator or closure
Instead of making the file only usable as a standalone replacement, expose the default Rector configuration in a way that can be imported and extended:
This would let consumers start from the package defaults and append their own changes.
2. Provide a factory/helper class
Expose a dedicated entry point such as a factory or helper:
This reduces coupling to a file path and makes the extension mechanism explicit.
3. Accept override callbacks or extra config files
Allow the base package to load an extra config layer after applying its defaults, so projects can augment the base behavior without redefining it entirely.
For example, consumers could provide a second file containing only project-specific adjustments.
4. Split the default config into reusable pieces
Another option would be to separate reusable concerns such as:
This would let consumers compose only what they need while still relying on the shared defaults.
Expected Behavior
Benefits
Additional Context
This is especially useful for projects that want to keep the package defaults but add a few custom Rector rules, skip specific directories, or tailor behavior for framework- or domain-specific code.
Today, even a small customization requires replacing the whole file, which makes long-term maintenance harder than necessary.