From efc1fd3a44a46628263403358fa16ac4ef73faf9 Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Fri, 27 Dec 2024 17:15:15 +0100 Subject: [PATCH] add headline docs --- resources/css/app.scss | 5 + resources/docs/integration-to-new-project.md | 96 ++----------------- resources/docs/levels.md | 76 +++++++++++++++ resources/docs/set-lists.md | 15 ++- .../DocumentationMenuFactory.php | 1 + src/Markdown/GithubMarkdownConverter.php | 33 +++++++ src/Thumbnail/ThumbnailGenerator.php | 10 +- src/functions.php | 11 ++- 8 files changed, 151 insertions(+), 96 deletions(-) create mode 100644 resources/docs/levels.md create mode 100644 src/Markdown/GithubMarkdownConverter.php diff --git a/resources/css/app.scss b/resources/css/app.scss index 94a6e9693..70b5f042c 100644 --- a/resources/css/app.scss +++ b/resources/css/app.scss @@ -612,3 +612,8 @@ label.required:before { .text-right { text-align: right; } + +.anchor-link { + margin-left: .1em; + padding: .1em .3em; +} diff --git a/resources/docs/integration-to-new-project.md b/resources/docs/integration-to-new-project.md index 959d5aee1..810caf36b 100644 --- a/resources/docs/integration-to-new-project.md +++ b/resources/docs/integration-to-new-project.md @@ -93,97 +93,13 @@ Again, we run Rector, apply changes, create pull-request, and go for merge. Slow
-Every codebase is different, and sometimes, we come across a rule that is not safe to apply. We can skip it for now: +### Skip what you don't need -```diff - withPaths([__DIR__ . '/src', __DIR__ . '/tests']) -+ ->withSkip([RemoveReferenceFromCallRector::class]) - ->withPhpSets(php54: true); -``` - -This is an entirely valid upgrade process. We will deal with skips later once our codebase is upgraded to our PHP version and much more robust. - -Check [other ways to use `withSkip()`](/documentation/ignoring-rules-or-paths). - -## 4. Type Coverage Level - -What is a PHP 8.3 project without a single type declaration? - -A horse with Tesla bodywork. - -
- -Type coverage is one of the most influential metrics in a modern PHP project. We can have a high PHP version in `composer.json`, but our code can still be full of `mixed` types, giving us zero confidence. There is a PHPStan package - [`type-coverage`](https://github.com/TomasVotruba/type-coverage)- that helps raise the bar 1% at a time. - -How can we use Rector to help out with type coverage? We can add a prepared set: - -```diff - withPaths([__DIR__ . '/src', __DIR__ . '/tests']) -+ ->withPreparedSets(typeDeclarations: true); -``` - -Let's run Rector: - -```bash -vendor/bin/rector --dry-run -``` - -Wow, over 90 % of files were changed. That's going to be a very long review. We can do better than that. - -## 5. One Level at a Time - -Instead of applying ~50 type declaration rules at once, we can apply them individually. This is much easier to review and explain to your team. But which one should we start with? - -We took the liberty of sorting the rules from the easy-pick to more complex ones. You can enable them yourself and go one level at a time: - -```diff - withPaths([__DIR__ . '/src', __DIR__ . '/tests']) -- ->withPreparedSets(typeDeclaration: true); -+ ->withTypeCoverageLevel(1); -``` - -Now run Rector to see the changed files: - -```php -vendor/bin/rector -``` - -Only five files? We can do that in a day. We create a pull request, get a review, and merge. The next day, we can continue with level 2. You get the idea. - -## 6. Dead Code Level - -Are you done with the type level and reached [99 % type coverage](https://github.com/tomasVotruba/type-coverage)? It's time to move on to dead code removal. - -Again, we could use the prepared dead-code set, but the number of changes would be huge. Instead, we make use of the dead-code level: - -```php -withPaths([__DIR__ . '/src', __DIR__ . '/tests']) - ->withTypeCoverageLevel(40) - ->withDeadCodeLevel(1); -``` +Every codebase is different, and sometimes, we come across a rule that is not safe to apply, or files we want to skip. +Use [ignoring](/documentation/ignoring-rules-or-paths) for that. +## Prepared sets, one level at a time -We increase it by 1, run Rector, create a pull request, get a review, and merge. +Rector provides dozens of [prepared sets](/documentation/set-lists). But the same way we don't read every book in library we visit for first time, we don't enable all prepared sets at once. -Once we reach the highest dead code level, we can move on to [next prepared sets](/documentation/set-lists). +Instead, **use [level methods](/documentation/levels) and take it step by step**. It more relaxing path to reach the goal. diff --git a/resources/docs/levels.md b/resources/docs/levels.md new file mode 100644 index 000000000..a20e2deb1 --- /dev/null +++ b/resources/docs/levels.md @@ -0,0 +1,76 @@ +What is a PHP 8.3 project without a single type declaration? + +A horse with Tesla bodywork. + +
+ +Type coverage is one of the most influential metrics in a modern PHP project. We can have a high PHP version in `composer.json`, but our code can still be full of `mixed` types, giving us zero confidence. There is a [`type-coverage`](https://github.com/TomasVotruba/type-coverage) package that helps raise the bar 1 % at a time. + +How can we use Rector to help out with type coverage? + +**What happens if we add full set:** + +```diff + withPaths([__DIR__ . '/src', __DIR__ . '/tests']) ++ ->withPreparedSets(typeDeclarations: true); +``` + +Let's run Rector: + +```bash +vendor/bin/rector --dry-run +``` + +Wow, over **90 % of files have changed**. That's going to be a very long review. We can do better than that. + +## One Level at a Time + +Instead of applying ~50 type declaration rules at once, we can apply them individually. This is much easier to review and explain to your team. But which one should we start with? + +We took the liberty of sorting the rules from the easy-pick to more complex ones. You can enable them yourself and go one level at a time: + +```diff + withPaths([__DIR__ . '/src', __DIR__ . '/tests']) +- ->withPreparedSets(typeDeclaration: true); ++ ->withTypeCoverageLevel(1); +``` + +Now run Rector to see the changed files: + +```php +vendor/bin/rector +``` + +Only five files? We can do that in a day. We create a pull request, get a review, and merge. The next day, we can continue with level 2. You get the idea. + +## Dead Code and Code Quality Level + +Are you done with the type level and reached [99 % type coverage](https://github.com/tomasVotruba/type-coverage)? It's time to move on to dead code removal and improve code quality. + +Again, we avoid full-blown prepared set, and make use of level methods: + +```php +withPaths([__DIR__ . '/src', __DIR__ . '/tests']) + ->withTypeCoverageLevel(1) + ->withDeadCodeLevel(1) + ->withCodeQualityLevel(1); +``` + +We increase it by 1, run Rector, create a pull request, get a review, and merge. + +Once we reach the highest level, we can move on to [next prepared sets](/documentation/set-lists#content-prepared-sets). diff --git a/resources/docs/set-lists.md b/resources/docs/set-lists.md index 404ed71f9..26e0c392c 100644 --- a/resources/docs/set-lists.md +++ b/resources/docs/set-lists.md @@ -1,3 +1,5 @@ +## Prepared Sets + You can use particular single rules, or whole list of rules, called "set lists": ```php @@ -6,11 +8,22 @@ You can use particular single rules, or whole list of rules, called "set lists": use Rector\Config\RectorConfig; return RectorConfig::configure() - ->withPreparedSets(deadCode: true, codeQuality: true); + ->withPreparedSets( + deadCode: true, + codeQuality: true, + codingStyle: true, + naming: true, + privatization: true, + typeDeclarations: true, + rectorPreset: true, + // ... + ); ``` That way you can include group of rules that focus on certain topic, e.g. in this case on dead detection. It makes config small and clear. +Try autocomplete in your IDE to see all available prepared sets. + ## PHP Sets The best practise is to use PHP version defined in `composer.json`. Rector will automatically pick it up with empty `->withPhpSets()` method: diff --git a/src/Documentation/DocumentationMenuFactory.php b/src/Documentation/DocumentationMenuFactory.php index 37402a9aa..fc2aa4b5c 100644 --- a/src/Documentation/DocumentationMenuFactory.php +++ b/src/Documentation/DocumentationMenuFactory.php @@ -26,6 +26,7 @@ public function create(): array $this->documentationMenuItemFactory->createSection('integration-to-new-project', 'New Project', true), $this->documentationMenuItemFactory->createSection('define-paths', 'Define Paths'), $this->documentationMenuItemFactory->createSection('set-lists', 'Set Lists'), + $this->documentationMenuItemFactory->createSection('levels', 'Levels', true), $this->documentationMenuItemFactory->createSection('composer-based-sets', 'Composer-Based Sets', true), $this->documentationMenuItemFactory->createInternalLink(FindRuleController::class, 'Find Rules'), $this->documentationMenuItemFactory->createSection( diff --git a/src/Markdown/GithubMarkdownConverter.php b/src/Markdown/GithubMarkdownConverter.php new file mode 100644 index 000000000..05175ec4b --- /dev/null +++ b/src/Markdown/GithubMarkdownConverter.php @@ -0,0 +1,33 @@ + $config + */ + public function __construct(array $config = []) + { + $environment = new Environment($config); + $environment->addExtension(new CommonMarkCoreExtension()); + $environment->addExtension(new GithubFlavoredMarkdownExtension()); + + // @see https://commonmark.thephpleague.com/1.5/extensions/heading-permalinks/ + $environment->addExtension(new HeadingPermalinkExtension()); + + parent::__construct($environment); + } +} diff --git a/src/Thumbnail/ThumbnailGenerator.php b/src/Thumbnail/ThumbnailGenerator.php index 9f4db1f4b..9bf97f11c 100644 --- a/src/Thumbnail/ThumbnailGenerator.php +++ b/src/Thumbnail/ThumbnailGenerator.php @@ -45,10 +45,14 @@ public function addRectorLogo(ImageInterface $image): void { $rectorLogoImage = $this->imagine->open(__DIR__ . '/../../public/assets/images/new-logo/rector-square.png'); - $currentWidth = $rectorLogoImage->getSize()->getWidth(); - $currentHeight = $rectorLogoImage->getSize()->getHeight(); + $currentWidth = $rectorLogoImage->getSize() + ->getWidth(); + $currentHeight = $rectorLogoImage->getSize() + ->getHeight(); - $rectorLogoImage->resize(new Box($currentWidth * self::RESIZE_LOGO_RATIO, $currentHeight * self::RESIZE_LOGO_RATIO)); + $rectorLogoImage->resize( + new Box($currentWidth * self::RESIZE_LOGO_RATIO, $currentHeight * self::RESIZE_LOGO_RATIO) + ); $image->paste($rectorLogoImage, new Point(1450, 50)); } diff --git a/src/functions.php b/src/functions.php index a9a2b95af..10b5450cc 100644 --- a/src/functions.php +++ b/src/functions.php @@ -5,8 +5,8 @@ // @see https://github.com/thephpleague/commonmark use App\Enum\FlashType; +use App\Markdown\GithubMarkdownConverter; use Illuminate\Http\RedirectResponse; -use League\CommonMark\GithubFlavoredMarkdownConverter; function latestPhp(): string { @@ -21,8 +21,15 @@ function slugify(string $value): string function markdown(string $contents): Stringable { - $markdownConverter = new GithubFlavoredMarkdownConverter([ + // @see https://commonmark.thephpleague.com/1.5/extensions/heading-permalinks/ + $markdownConverter = new GithubMarkdownConverter([ 'allow_unsafe_links' => false, + 'heading_permalink' => [ + 'html_class' => 'anchor-link', // CSS class for the anchor + 'symbol' => '#', // Symbol for the link + 'id_prefix' => 'content', // Prefix for the ID + 'insert' => 'after', // Where to insert the link: 'before', 'after', or 'none' + ], ]); return $markdownConverter->convert($contents);