From 40eaa1dd9fa53d44a94d78d5da6b774aafffe9ae Mon Sep 17 00:00:00 2001 From: Tomas Votruba Date: Sun, 4 May 2025 21:38:02 +0200 Subject: [PATCH] [llm] kick of llms.txt --- resources/docs/composer-based-sets.md | 2 - resources/views/llm/llms-txt.blade.php | 59 +++++++++++++++++++ routes/web.php | 3 + src/Controller/DocumentationController.php | 6 +- src/Controller/Llm/LlmsTxtController.php | 27 +++++++++ .../DocumentationMenuFactory.php | 3 +- src/Documentation/DocumentationMenuItem.php | 24 ++++++++ .../DocumentationMenuItemFactory.php | 12 +++- src/Repository/PostRepository.php | 8 +++ .../DocumentationMenuFactoryTest.php | 2 +- 10 files changed, 137 insertions(+), 9 deletions(-) create mode 100644 resources/views/llm/llms-txt.blade.php create mode 100644 src/Controller/Llm/LlmsTxtController.php diff --git a/resources/docs/composer-based-sets.md b/resources/docs/composer-based-sets.md index 10ca7c7d0..067c35eba 100644 --- a/resources/docs/composer-based-sets.md +++ b/resources/docs/composer-based-sets.md @@ -12,5 +12,3 @@ return RectorConfig::configure() * and run those If you upgrade to Doctrine 4, Twig 4, or Symfony 10 later, Rector will pick up sets for you. - - diff --git a/resources/views/llm/llms-txt.blade.php b/resources/views/llm/llms-txt.blade.php new file mode 100644 index 000000000..6bdd0307b --- /dev/null +++ b/resources/views/llm/llms-txt.blade.php @@ -0,0 +1,59 @@ +@php + /** @var \App\Entity\Post[] $posts */ + /** @var array $documentationMenuItemsBySection */ +@endphp + + +# Rector + +We help successful and growing companies to get the most out of the code they already have. + +Reduce maintenance cost, make feature delivery cheaper +and turn legacy code into sustainable code. + + +## How does Rector Improve your Business? + +Rector is a PHP tool that you can run on any PHP project to get an instant upgrade or automated refactoring. + +It helps you with: + +* PHP and framework upgrades, +* in-house framework migrations, +* improving your code quality to deliver features faster than competition + +In the hands of an expert, Rector massively reduces your work-time. +Where project upgrade PHP 8.0 to 8.4 would take 3 months, Rector is done in 3 days. + +You can learn it yourself from documentation, or to save time and start upgrading today, hire our upgrade team. + +========================================= + +# Documentation + +@foreach ($documentationMenuItemsBySection as $section => $documentationMenuItems) + @foreach ($documentationMenuItems as $documentationMenuItem) + @continue ($documentationMenuItem->getSlug() === null) + +## {{ $section }}: {{ $documentationMenuItem->getLabel() }} + +{!! $documentationMenuItem->getMarkdownContents() !!} + +----------------------------------------- + + @endforeach +@endforeach + +========================================= + +# Blog posts + +@foreach ($posts as $post) +## {{ $post->getTitle() }} + +Perex: {!! $post->getPerex() !!} + +{!! $post->getContents() !!} + +----------------------------------------- +@endforeach diff --git a/routes/web.php b/routes/web.php index 11fcb219c..32b5e417d 100644 --- a/routes/web.php +++ b/routes/web.php @@ -2,6 +2,7 @@ declare(strict_types=1); +use App\Controller\Llm\LlmsTxtController; use App\Controller\Stats\FindRuleStatsController; use App\Ast\Controller\AstController; use App\Ast\Controller\AstDetailController; @@ -25,6 +26,8 @@ Route::get('/', HomepageController::class); +Route::get('llms.txt', LlmsTxtController::class); + // old pages redirect Route::redirect('/documentation/rules-overview', '/find-rule'); Route::redirect('step-by-step', '/hire-team'); diff --git a/src/Controller/DocumentationController.php b/src/Controller/DocumentationController.php index 04faf8d8b..93b0d18fc 100644 --- a/src/Controller/DocumentationController.php +++ b/src/Controller/DocumentationController.php @@ -8,6 +8,7 @@ use Illuminate\Contracts\View\View; use Illuminate\Routing\Controller; use Nette\Utils\FileSystem; +use Webmozart\Assert\Assert; final class DocumentationController extends Controller { @@ -18,7 +19,10 @@ public function __construct( public function __invoke(string $section = 'introduction'): View { - $markdownContents = FileSystem::read(__DIR__ . '/../../resources/docs/' . $section . '.md'); + $documentationFile = __DIR__ . '/../../resources/docs/' . $section . '.md'; + Assert::fileExists($documentationFile); + + $markdownContents = FileSystem::read($documentationFile); return \view('docs/section', [ 'section_title' => $this->documentationMenuFactory->createSectionTitle($section), diff --git a/src/Controller/Llm/LlmsTxtController.php b/src/Controller/Llm/LlmsTxtController.php new file mode 100644 index 000000000..92149aab3 --- /dev/null +++ b/src/Controller/Llm/LlmsTxtController.php @@ -0,0 +1,27 @@ +view('llm/llms-txt', [ + 'posts' => $this->postRepository->fetchAll(), + 'documentationMenuItemsBySection' => $this->documentationMenuFactory->create(), + ])->header('Content-Type', 'text/plain'); + } +} diff --git a/src/Documentation/DocumentationMenuFactory.php b/src/Documentation/DocumentationMenuFactory.php index 1b5fcb560..46d8eee68 100644 --- a/src/Documentation/DocumentationMenuFactory.php +++ b/src/Documentation/DocumentationMenuFactory.php @@ -12,7 +12,7 @@ final readonly class DocumentationMenuFactory { public function __construct( - private DocumentationMenuItemFactory $documentationMenuItemFactory + private DocumentationMenuItemFactory $documentationMenuItemFactory, ) { } @@ -68,7 +68,6 @@ public function create(): array 'writing-tests-for-custom-rule', 'Writing Tests For Custom Rule' ), - $this->documentationMenuItemFactory->createSection('rules-overview', 'Rules Overview'), $this->documentationMenuItemFactory->createSection('creating-a-node-visitor', 'Creating Node Visitor'), $this->documentationMenuItemFactory->createSection('how-to-run-on-php-53', 'Run on PHP 5.3'), $this->documentationMenuItemFactory->createSection( diff --git a/src/Documentation/DocumentationMenuItem.php b/src/Documentation/DocumentationMenuItem.php index 1399f9efd..3e28aea48 100644 --- a/src/Documentation/DocumentationMenuItem.php +++ b/src/Documentation/DocumentationMenuItem.php @@ -4,11 +4,18 @@ namespace App\Documentation; +use Nette\Utils\FileSystem; +use Webmozart\Assert\Assert; + final readonly class DocumentationMenuItem { + /** + * @param non-empty-string|null $slug + */ public function __construct( private string $href, private string $label, + private ?string $slug, private bool $isNew = false, ) { } @@ -27,4 +34,21 @@ public function isNew(): bool { return $this->isNew; } + + /** + * @return non-empty-string|null + */ + public function getSlug(): ?string + { + return $this->slug; + } + + public function getMarkdownContents(): string + { + Assert::notNull($this->slug); + $documentationFilePath = __DIR__ . '/../../resources/docs/' . $this->slug . '.md'; + + Assert::fileExists($documentationFilePath); + return FileSystem::read($documentationFilePath); + } } diff --git a/src/Documentation/DocumentationMenuItemFactory.php b/src/Documentation/DocumentationMenuItemFactory.php index 6d1602b10..c7e154f09 100644 --- a/src/Documentation/DocumentationMenuItemFactory.php +++ b/src/Documentation/DocumentationMenuItemFactory.php @@ -15,17 +15,23 @@ public function __construct( ) { } + /** + * @param non-empty-string $slugOrUrl + */ public function createSection(string $slugOrUrl, string $name, bool $isNew = false): DocumentationMenuItem { - if (str_starts_with($slugOrUrl, 'https://')) { + if (str_starts_with($slugOrUrl, 'https://') || str_starts_with($slugOrUrl, 'http://')) { $url = $slugOrUrl; + $slug = null; } else { $url = $this->urlGenerator->action(DocumentationController::class, [ 'section' => $slugOrUrl, ]); + + $slug = $slugOrUrl; } - return new DocumentationMenuItem($url, $name, $isNew); + return new DocumentationMenuItem($url, $name, $slug, $isNew); } /** @@ -35,6 +41,6 @@ public function createInternalLink(string $controllerClass, string $label): Docu { $href = $this->urlGenerator->action($controllerClass); - return new DocumentationMenuItem($href, $label); + return new DocumentationMenuItem($href, $label, null); } } diff --git a/src/Repository/PostRepository.php b/src/Repository/PostRepository.php index ae55c4396..28e023c92 100644 --- a/src/Repository/PostRepository.php +++ b/src/Repository/PostRepository.php @@ -56,6 +56,14 @@ public function fetchLast(int $count): array return array_slice($this->posts, 0, $count); } + /** + * @return Post[] + */ + public function fetchAll(): array + { + return $this->posts; + } + private function createPosts(): void { $posts = []; diff --git a/tests/Documentation/DocumentationMenuFactoryTest.php b/tests/Documentation/DocumentationMenuFactoryTest.php index 806b5d412..e9dd1d769 100644 --- a/tests/Documentation/DocumentationMenuFactoryTest.php +++ b/tests/Documentation/DocumentationMenuFactoryTest.php @@ -22,7 +22,7 @@ protected function setUp(): void ->willReturn('/index.html'); $this->documentationMenuFactory = new DocumentationMenuFactory( - new DocumentationMenuItemFactory($urlGenerator) + new DocumentationMenuItemFactory($urlGenerator), ); }