Skip to content

Make rector.php extensible instead of fully replaceable #7

@coisa

Description

@coisa

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.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions