module docusaurus import incubaid.herolib.core.pathlib import incubaid.herolib.web.doctree.client as doctree_client import incubaid.herolib.data.markdown.tools as markdowntools import incubaid.herolib.ui.console import incubaid.herolib.web.site import os // ============================================================================ // Doc Linking - Generate Docusaurus docs from DocTree collections // ============================================================================ // get_first_doc_from_sidebar recursively finds the first doc ID in the sidebar. // Used to determine which page should get slug: / in frontmatter when url_home ends with "/". fn get_first_doc_from_sidebar(items []site.NavItem) string { for item in items { match item { site.NavDoc { return site.extract_page_id(item.id) } site.NavCat { // Recursively search in category items doc := get_first_doc_from_sidebar(item.items) if doc.len > 0 { return doc } } site.NavLink { // Skip links, we want docs continue } } } return '' } // generate_docs generates markdown files from site page definitions. // Pages are fetched from DocTree collections and written with frontmatter. pub fn (mut docsite DocSite) generate_docs() ! { c := config()! docs_path := '${c.path_build.path}/docs' reset_docs_dir(docs_path)! console.print_header('Write doc: ${docs_path}') mut client := doctree_client.new(export_dir: c.doctree_dir)! mut errors := []string{} // Determine if we need to set a docs landing page (when url_home ends with "/") first_doc_page := if docsite.website.siteconfig.url_home.ends_with('/') { get_first_doc_from_sidebar(docsite.website.nav.my_sidebar) } else { '' } for _, page in docsite.website.pages { process_page(mut client, docs_path, page, first_doc_page, mut errors) } if errors.len > 0 { report_errors(mut client, errors)! } console.print_green('Successfully linked ${docsite.website.pages.len} pages to docs folder') } fn reset_docs_dir(docs_path string) ! { if os.exists(docs_path) { os.rmdir_all(docs_path) or {} } os.mkdir_all(docs_path)! } fn report_errors(mut client doctree_client.DocTreeClient, errors []string) ! { available := client.list_markdown() or { 'Could not list available pages' } console.print_stderr('Available pages:\n${available}') return error('Errors during doc generation:\n${errors.join('\n\n')}') } // ============================================================================ // Page Processing // ============================================================================ fn process_page(mut client doctree_client.DocTreeClient, docs_path string, page site.Page, first_doc_page string, mut errors []string) { collection, page_name := parse_page_src(page.src) or { errors << err.msg() return } content := client.get_page_content(collection, page_name) or { errors << "Page not found: '${collection}:${page_name}'" return } // Check if this page is the docs landing page is_landing_page := first_doc_page.len > 0 && page_name == first_doc_page write_page(docs_path, page_name, page, content, is_landing_page) or { errors << "Failed to write page '${page_name}': ${err.msg()}" return } copy_page_assets(mut client, docs_path, collection, page_name) console.print_item('Generated: ${page_name}.md') } fn parse_page_src(src string) !(string, string) { parts := src.split(':') if parts.len != 2 { return error("Invalid src format '${src}' - expected 'collection:page_name'") } return parts[0], parts[1] } fn write_page(docs_path string, page_name string, page site.Page, content string, is_landing_page bool) ! { frontmatter := build_frontmatter(page, content, is_landing_page) final_content := frontmatter + '\n\n' + content output_path := '${docs_path}/${page_name}.md' mut file := pathlib.get_file(path: output_path, create: true)! file.write(final_content)! } fn copy_page_assets(mut client doctree_client.DocTreeClient, docs_path string, collection string, page_name string) { client.copy_images(collection, page_name, docs_path) or {} client.copy_files(collection, page_name, docs_path) or {} } // ============================================================================ // Frontmatter Generation // ============================================================================ fn build_frontmatter(page site.Page, content string, is_landing_page bool) string { title := get_title(page, content) description := get_description(page, title) mut lines := ['---'] lines << "title: '${title}'" lines << "description: '${description}'" // if page.id.contains('tfhowto_tools'){ // println('extracted title: ${title}') // println('page.src: ${lines}') // $dbg; // } // Add slug: / for the docs landing page so /docs/ works directly if is_landing_page { lines << 'slug: /' } if page.draft { lines << 'draft: true' } if page.hide_title { lines << 'hide_title: true' } lines << '---' return lines.join('\n') }