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
14 changes: 14 additions & 0 deletions .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,20 @@ Contributing needs **PHP 8.5+** — the development dependencies require it. Usi
| `composer check` | Code style, Rector dry-run on this repository's own sources, and the missing-rule guard |
| `composer fix` | Apply Rector and code-style fixes |
| `composer check:missing-rules` | Report rules that are in neither file |
| `composer phpcs` / `composer phpcs:fix` | Code style only |
| `composer rector` / `composer rector:fix` | Rector on this repository's own sources |
| `composer build` | Runs `composer check fix`, `composer check`, then `composer ai-olympus:install` |
| `composer ai-olympus:install` | Reinstall [pekral/ai-olympus](https://github.com/pekral/ai-olympus) agent rules and skills |

`composer fix`, `composer phpcs:fix`, and `composer rector:fix` rewrite files in `rules/`, `build/`, and
`rector.php` in place.

### CI

Pull requests and pushes to `master` run the missing-rule guard, code style, the Rector dry run, and
`composer audit` on PHP 8.5. A separate job on the declared minimum PHP 8.4 validates `composer.json`, checks
that the runtime dependencies resolve, and lints `rules/rules.php`. A weekly job refreshes dependencies and
opens a pull request; another audits dependencies for known vulnerabilities every Monday.

## Pull requests

Expand Down
210 changes: 54 additions & 156 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,33 @@
# rector-rules

[![Latest Stable Version](https://poser.pugx.org/pekral/rector-rules/v/stable)](https://packagist.org/packages/pekral/rector-rules)
[![License](https://poser.pugx.org/pekral/rector-rules/license)](LICENSE)
[![Checks](https://github.com/pekral/rector-rules/actions/workflows/pr.yml/badge.svg)](https://github.com/pekral/rector-rules/actions/workflows/pr.yml)
[![Total Downloads](https://poser.pugx.org/pekral/rector-rules/downloads)](https://packagist.org/packages/pekral/rector-rules)
[![Latest Version on Packagist](https://img.shields.io/packagist/v/pekral/rector-rules.svg?style=flat-square)](https://packagist.org/packages/pekral/rector-rules)
[![MIT Licensed](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
![Checks](https://github.com/pekral/rector-rules/workflows/Checks/badge.svg)
[![Total Downloads](https://img.shields.io/packagist/dt/pekral/rector-rules.svg?style=flat-square)](https://packagist.org/packages/pekral/rector-rules)

A curated, ready-to-use [Rector](https://github.com/rectorphp/rector) rule set for PHP 8.4+ projects.

Rector ships over 500 rules. Picking the useful ones — and re-checking them on every Rector release — is a
recurring chore. This package does that curation for you: **one import, 216 hand-picked rules**, with every
other rule Rector offers listed as skipped, so a new Rector release cannot add a rule nobody looked at.

---
A curated [Rector](https://github.com/rectorphp/rector) rule set for PHP 8.4+ projects: one import registers
216 hand-picked rules. Every other rule Rector ships is recorded in this repository as deliberately left out,
and a CI guard fails until someone decides about each rule a new Rector release adds.

## Requirements

| | Version |
| --- | --- |
| PHP | `^8.4` |
| `rector/rector` | `^2.8.1` |

Contributing to this repository needs **PHP 8.5+**, because the development dependencies require it. Using
the package only needs 8.4.
| `rector/rector` | `^2.8.4` |

---
`rector/rector` is the only runtime dependency. Developing this repository needs PHP 8.5+ — see
[Testing](#testing).

## Installation

```bash
composer require --dev pekral/rector-rules
```

---
## Configuration

## Usage

Import the package's `rector.php` into your own configuration. Both Rector config styles work:

**Rector 2 builder style**
Import the package's `rector.php` in your project's `rector.php` and set the paths Rector should process:

```php
<?php
Expand All @@ -51,53 +41,29 @@ return RectorConfig::configure()
->withSets([__DIR__ . '/vendor/pekral/rector-rules/rector.php']);
```

**Closure style**

```php
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;
The closure style (`$rectorConfig->import(...)`) works too. The set raises Rector's parallel process timeout
to 180 s and leaves the worker count at Rector's default. Skipping rules, combining this set with other sets,
and overriding the timeout are covered in [docs/configuration.md](docs/configuration.md).

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/vendor/pekral/rector-rules/rector.php');
$rectorConfig->paths([__DIR__ . '/src']);
};
```
## Quick start

Then run Rector:
Preview what would change, without touching a file:

```bash
# Preview the changes without touching a file
vendor/bin/rector process --dry-run

# Apply them
vendor/bin/rector process
```

### Skipping a rule you disagree with

The set is opinionated. Turn off anything that does not fit your codebase:
Apply the changes:

```php
return RectorConfig::configure()
->withPaths([__DIR__ . '/src'])
->withSets([__DIR__ . '/vendor/pekral/rector-rules/rector.php'])
->withSkip([
// Disable a rule everywhere
Rector\CodeQuality\Rector\CallLike\AddNameToBooleanArgumentRector::class,

// …or only in specific paths
Rector\Php82\Rector\Class_\ReadOnlyClassRector::class => [
__DIR__ . '/src/Legacy',
],
]);
```bash
vendor/bin/rector process
```

---
> [!WARNING]
> `vendor/bin/rector process` rewrites the files under the configured paths in place. Run the dry run first
> and commit your work before applying.

## What is in the set
## What it does

216 rules, grouped by what they do:

Expand All @@ -111,124 +77,56 @@ return RectorConfig::configure()
| `Php53` – `Php86` | 36 | Upgrade syntax to newer PHP versions |
| Other | 11 | `Privatization`, `CodingStyle`, `EarlyReturn`, `Visibility` |

The authoritative list is [`rules/rules.php`](rules/rules.php) — a plain array of rule class names.

### Curation model
The set is opinionated: turn off any rule that does not fit your codebase with `withSkip()`. The
authoritative list is [`rules/rules.php`](rules/rules.php), a plain array of rule class names.

| File | Role |
| --- | --- |
| [`rector.php`](rector.php) | Entry point — registers every rule from `rules/rules.php` and raises the Rector parallel process timeout to 180 s |
| [`rules/rules.php`](rules/rules.php) | The 216 enabled rules (shipped) |
| `build/ignored-rules.php` | The 221 rules that do not ship (development only). 2 JMS Serializer rules sit under a PHP 8.5 heading; the other 219 are grouped under a plain `// Ignored rules` heading. Rules deprecated in Rector are listed nowhere — they are deleted |
| `build/find-missing-rules.php` | CI guard: fails if a rule is neither enabled nor listed as ignored, or if a deprecated rule is listed in either file (development only) |

Because of that guard, every rule Rector adds in a new release shows up as a build failure until someone
decides about it. Nothing is silently ignored.
## Documentation

`build/`, `.github/`, `assets/`, the dotfiles, and the repository-only documents (`CHANGELOG.md`,
`UPGRADING.md`) are marked `export-ignore`, so `composer require` pulls down exactly five files:
`rector.php`, `rules/rules.php`, `composer.json`, `README.md`, and `LICENSE`.
- [Configuration](docs/configuration.md) — closure style, skipping rules, combining with Rector's own and
third-party sets, the parallel timeout
- [How the set is curated](docs/rule-set.md) — the ignore list, the missing-rule guard, why a rule is not
included, and which files the package ships
- [Rector documentation](https://getrector.com/) and the [Rector rule catalog](https://getrector.com/find-rule)
- [Discussions](https://github.com/pekral/rector-rules/discussions)

---
## Testing

## Development
Developing this repository needs PHP 8.5+, because the development dependencies require it.

```bash
composer install
composer check
```

| Command | What it does |
| --- | --- |
| `composer check` | Full check: code style, Rector dry-run, missing-rule guard |
| `composer fix` | Apply Rector and code-style fixes |
| `composer build` | `check`, then reinstall the AI agent rules — it applies no fixes; use `composer fix` for that |
| `composer phpcs` / `composer phpcs:fix` | Code style only |
| `composer rector` / `composer rector:fix` | Rector on this repository's own sources |
| `composer check:missing-rules` | Report rules that are neither enabled nor ignored |
| `composer ai-olympus:install` | Reinstall [pekral/ai-olympus](https://github.com/pekral/ai-olympus) agent rules and skills |

### Adding a rule

1. Add the class to `rules/rules.php`, or to `build/ignored-rules.php` if it should stay off.
2. Run `composer check`.

`composer check:missing-rules` fails when a rule is in neither file, so every rule Rector ships has to be
decided about.

See [CONTRIBUTING.md](.github/CONTRIBUTING.md) for how the guard works and the reasons rules are left out.

### CI

Pull requests and pushes to `master` run the same `composer check` steps plus a `composer audit`, and
separately validate `composer.json` and lint the shipped sources on the declared minimum PHP 8.4. A weekly job
refreshes dependencies and opens a PR; another audits dependencies for known vulnerabilities every Monday.

---

## FAQ
`composer check` runs the code style check, a Rector dry run on this repository's own sources, and the
missing-rule guard. The other development commands are listed in [CONTRIBUTING.md](.github/CONTRIBUTING.md).

**How do I preview what would change?**
`vendor/bin/rector process --dry-run`.
## Upgrading

**How do I disable a single rule?**
Use `withSkip()` — see [Skipping a rule you disagree with](#skipping-a-rule-you-disagree-with).
Most releases so far have changed the set, patch releases included, so an upgrade can make Rector rewrite
more of your code than before. Run `vendor/bin/rector process --dry-run` after upgrading and read
[UPGRADING.md](UPGRADING.md).

**Can I combine this with Rector's own sets?**
Yes. Add `->withPhpSets()` or any other set alongside `withSets()`. A rule that ends up registered twice is
not an error.
## Changelog

**Can I add rules from another package, for example Laravel?**
Yes, and nothing in this package has to change. Install the package and list its sets next to this one:
See [CHANGELOG.md](CHANGELOG.md).

```php
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelSetList;

return RectorConfig::configure()
->withPaths([__DIR__ . '/app'])
->withSets([
__DIR__ . '/vendor/pekral/rector-rules/rector.php',
LaravelSetList::LARAVEL_CODE_QUALITY,
LaravelSetList::LARAVEL_COLLECTION,
])
->withComposerBased(laravel: true);
```

List only the sets that apply to your code permanently. `driftingly/rector-laravel` also ships per-version
upgrade sets, in `LaravelSetList` and in `LaravelLevelSetList`, and that package deprecates every one of
them. `withComposerBased(laravel: true)` replaces them: it reads the installed `laravel/framework` version
and applies the upgrade rules bound to it.
## Contributing

**Why is rule X not included?**
Check `build/ignored-rules.php` in the repository — every rule that does not ship is listed there, except
rules deprecated in Rector. Those are never shipped and never listed. Rules waiting on PHP 8.5 sit under a
heading that says so; the rest are grouped under a plain `// Ignored rules` heading, which records the
decision without a reason.
To propose a change, open an
[Enable a rule](https://github.com/pekral/rector-rules/issues/new?template=enable-rule.yml) or
[Disable a rule](https://github.com/pekral/rector-rules/issues/new?template=disable-rule.yml) issue, or see
[CONTRIBUTING.md](.github/CONTRIBUTING.md). Participation is governed by the
[code of conduct](.github/CODE_OF_CONDUCT.md).

**What happens when I upgrade?**
Most releases so far have changed the set, patch releases included, so Rector may rewrite more of your code
than before. Run `--dry-run` first and read [UPGRADING.md](UPGRADING.md).
## Security

**How do I contribute?**
Open an [Enable a rule](https://github.com/pekral/rector-rules/issues/new?template=enable-rule.yml) or
[Disable a rule](https://github.com/pekral/rector-rules/issues/new?template=disable-rule.yml) issue, ask in
[Discussions](https://github.com/pekral/rector-rules/discussions), or send a pull request — see
[CONTRIBUTING.md](.github/CONTRIBUTING.md).
See [the security policy](.github/SECURITY.md).

---
## Credits

## Links

* [Packagist](https://packagist.org/packages/pekral/rector-rules)
* [Changelog](CHANGELOG.md) · [Upgrade guide](UPGRADING.md) · [Contributing](.github/CONTRIBUTING.md) · [Code of conduct](.github/CODE_OF_CONDUCT.md) · [Security policy](.github/SECURITY.md)
* [Discussions](https://github.com/pekral/rector-rules/discussions)
* [Rector documentation](https://getrector.com/)
* [Rector rule catalog](https://getrector.com/find-rule)

---
Maintained by [Petr Král](https://github.com/pekral).

## License

MIT — see [LICENSE](LICENSE).

Maintained by [Petr Král](https://github.com/pekral).
91 changes: 91 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Configuration

The package's [`rector.php`](../rector.php) registers every rule in [`rules/rules.php`](../rules/rules.php)
and raises the Rector parallel process timeout to 180 s. Import it into your own `rector.php`; both Rector
config styles work.

## Builder style

```php
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;

return RectorConfig::configure()
->withPaths([__DIR__ . '/src'])
->withSets([__DIR__ . '/vendor/pekral/rector-rules/rector.php']);
```

## Closure style

```php
<?php

declare(strict_types=1);

use Rector\Config\RectorConfig;

return static function (RectorConfig $rectorConfig): void {
$rectorConfig->import(__DIR__ . '/vendor/pekral/rector-rules/rector.php');
$rectorConfig->paths([__DIR__ . '/src']);
};
```

## Skipping a rule you disagree with

The set is opinionated. Turn off anything that does not fit your codebase in your own `rector.php` — never by
editing the package:

```php
return RectorConfig::configure()
->withPaths([__DIR__ . '/src'])
->withSets([__DIR__ . '/vendor/pekral/rector-rules/rector.php'])
->withSkip([
// Disable a rule everywhere
Rector\CodeQuality\Rector\CallLike\AddNameToBooleanArgumentRector::class,

// …or only in specific paths
Rector\Php82\Rector\Class_\ReadOnlyClassRector::class => [
__DIR__ . '/src/Legacy',
],
]);
```

## Combining with other sets

Add `->withPhpSets()` or any other Rector set alongside `withSets()`. A rule that ends up registered twice is
not an error.

Rules from another package, for example Laravel, need no change in this package. Install that package and list
its sets next to this one:

```php
use Rector\Config\RectorConfig;
use RectorLaravel\Set\LaravelSetList;

return RectorConfig::configure()
->withPaths([__DIR__ . '/app'])
->withSets([
__DIR__ . '/vendor/pekral/rector-rules/rector.php',
LaravelSetList::LARAVEL_CODE_QUALITY,
LaravelSetList::LARAVEL_COLLECTION,
])
->withComposerBased(laravel: true);
```

List only the sets that apply to your code permanently. `driftingly/rector-laravel` also ships per-version
upgrade sets, in `LaravelSetList` and in `LaravelLevelSetList`, and that package deprecates every one of
them. `withComposerBased(laravel: true)` replaces them: it reads the installed `laravel/framework` version
and applies the upgrade rules bound to it.

## Parallel process timeout

`rector.php` raises the parallel process timeout to 180 seconds, so a worker that needs longer than Rector's
120-second default does not kill the run on a slow CI machine. The number of worker processes and the job size
stay at Rector's own defaults.

A project that imports `rector.php` inherits the timeout. In the builder style, `withParallel()` or
`withoutParallel()` overrides it. In the closure style, the override has to come after the `import()` call,
because the last call wins.
Loading
Loading