$name, 'title' => $this->title($content, $name), ]; } usort($items, fn (array $a, array $b): int => strcmp($a['name'], $b['name'])); return $items; } public function read(string $name): array { $safeName = basename($name); $path = base_path('apidoc/' . $safeName); if (!is_file($path) || pathinfo($path, PATHINFO_EXTENSION) !== 'md') { throw new RuntimeException('API doc not found.'); } $content = (string) file_get_contents($path); return [ 'name' => $safeName, 'title' => $this->title($content, $safeName), 'content' => $content, 'html' => $this->renderer()->render($content), ]; } public function readScriptDoc(string $name): array { $safeName = basename($name); $path = base_path('scriptdoc/' . $safeName); if (!is_file($path) || pathinfo($path, PATHINFO_EXTENSION) !== 'md') { throw new RuntimeException('Script doc not found.'); } $content = (string) file_get_contents($path); return [ 'name' => $safeName, 'title' => $this->title($content, $safeName), 'content' => $content, 'html' => $this->renderer()->render($content), ]; } private function title(string $content, string $fallback): string { if (preg_match('/^#\s+(.+)$/m', $content, $matches)) { return trim($matches[1]); } return $fallback; } private function renderer(): MarkdownRenderer { return $this->renderer ?? new MarkdownRenderer(); } }