Files
herolib/lib/web/docusaurus/dsite_generate_docs__.v
2025-11-30 08:24:36 +01:00

443 lines
14 KiB
V

module docusaurus
import incubaid.herolib.core.pathlib
// import incubaid.herolib.data.atlas.client as atlas_client
// import incubaid.herolib.web.site { Page, Section, Site }
// import incubaid.herolib.data.markdown.tools as markdowntools
// import incubaid.herolib.ui.console
// struct SiteGenerator {
// mut:
// siteconfig_name string
// path pathlib.Path
// client IDocClient
// flat bool // if flat then won't use sitenames as subdir's
// site Site
// errors []string // collect errors here
// }
// // Generate docs from site configuration
// pub fn (mut docsite DocSite) generate_docs() ! {
// c := config()!
// // we generate the docs in the build path
// docs_path := '${c.path_build.path}/docs'
// // Create the appropriate client based on configuration
// mut client_instance := atlas_client.new(export_dir: c.atlas_dir)!
// mut client := IDocClient(client_instance)
// mut gen := SiteGenerator{
// path: pathlib.get_dir(path: docs_path, create: true)!
// client: client
// flat: true
// site: docsite.website
// }
// for section in gen.site.sections {
// gen.section_generate(section)!
// }
// for page in gen.site.pages {
// gen.page_generate(page)!
// }
// if gen.errors.len > 0 {
// println('Page List: is header collection and page name per collection.\nAvailable pages:\n${gen.client.list_markdown()!}')
// return error('Errors occurred during site generation:\n${gen.errors.join('\n\n')}\n')
// }
// }
// fn (mut generator SiteGenerator) error(msg string) ! {
// console.print_stderr('Error: ${msg}')
// generator.errors << msg
// }
// fn (mut generator SiteGenerator) page_generate(args_ Page) ! {
// mut args := args_
// mut content := ['---']
// mut parts := args.src.split(':')
// if parts.len != 2 {
// generator.error("Invalid src format for page '${args.src}', expected format: collection:page_name, TODO: fix in ${args.path}, check the collection & page_name exists in the pagelist")!
// return
// }
// collection_name := parts[0]
// page_name := parts[1]
// mut page_content := generator.client.get_page_content(collection_name, page_name) or {
// generator.error("Couldn't find page '${collection_name}:${page_name}' is formatted as collectionname:pagename. TODO: fix in ${args.path}, check the collection & page_name exists in the pagelist. ")!
// return
// }
// if args.description.len == 0 {
// descnew := markdowntools.extract_title(page_content)
// if descnew != '' {
// args.description = descnew
// } else {
// args.description = page_name
// }
// }
// if args.title.len == 0 {
// descnew := markdowntools.extract_title(page_content)
// if descnew != '' {
// args.title = descnew
// } else {
// args.title = page_name
// }
// }
// // Escape single quotes in YAML by doubling them
// escaped_title := args.title.replace("'", "''")
// content << "title: '${escaped_title}'"
// if args.description.len > 0 {
// escaped_description := args.description.replace("'", "''")
// content << "description: '${escaped_description}'"
// }
// if args.slug.len > 0 {
// escaped_slug := args.slug.replace("'", "''")
// content << "slug: '${escaped_slug}'"
// }
// if args.hide_title {
// content << 'hide_title: ${args.hide_title}'
// }
// if args.draft {
// content << 'draft: ${args.draft}'
// }
// if args.position > 0 {
// content << 'sidebar_position: ${args.position}'
// }
// content << '---'
// mut c := content.join('\n')
// if args.title_nr > 0 {
// // Set the title number in the page content
// page_content = markdowntools.set_titles(page_content, args.title_nr)
// }
// // Fix links to account for nested categories
// page_content = generator.fix_links(page_content, args.path)
// c += '\n${page_content}\n'
// if args.path.ends_with('/') || args.path.trim_space() == '' {
// // means is dir
// args.path += page_name
// }
// if !args.path.ends_with('.md') {
// args.path += '.md'
// }
// mut pagepath := '${generator.path.path}/${args.path}'
// mut pagefile := pathlib.get_file(path: pagepath, create: true)!
// pagefile.write(c)!
// generator.client.copy_pages(collection_name, page_name, pagefile.path_dir()) or {
// generator.error("Couldn't copy pages for page:'${page_name}' in collection:'${collection_name}'\nERROR:${err}")!
// return
// }
// generator.client.copy_images(collection_name, page_name, pagefile.path_dir()) or {
// generator.error("Couldn't copy images for page:'${page_name}' in collection:'${collection_name}'\nERROR:${err}")!
// return
// }
// generator.client.copy_files(collection_name, page_name, pagefile.path_dir()) or {
// generator.error("Couldn't copy files for page:'${page_name}' in collection:'${collection_name}'\nERROR:${err}")!
// return
// }
// }
// fn (mut generator SiteGenerator) section_generate(args_ Section) ! {
// mut args := args_
// mut c := ''
// if args.description.len > 0 {
// c = '{
// "label": "${args.label}",
// "position": ${args.position},
// "link": {
// "type": "generated-index",
// "description": "${args.description}"
// }
// }'
// } else {
// c = '{
// "label": "${args.label}",
// "position": ${args.position},
// "link": {
// "type": "generated-index"
// }
// }'
// }
// mut category_path := '${generator.path.path}/${args.path}/_category_.json'
// mut catfile := pathlib.get_file(path: category_path, create: true)!
// catfile.write(c)!
// }
// // Strip numeric prefix from filename (e.g., "03_linux_installation" -> "linux_installation")
// // Docusaurus automatically strips these prefixes from URLs
// fn strip_numeric_prefix(name string) string {
// // Match pattern: digits followed by underscore at the start
// if name.len > 2 && name[0].is_digit() {
// for i := 1; i < name.len; i++ {
// if name[i] == `_` {
// // Found the underscore, return everything after it
// return name[i + 1..]
// }
// if !name[i].is_digit() {
// // Not a numeric prefix pattern, return as-is
// return name
// }
// }
// }
// return name
// }
// // Calculate relative path from current directory to target directory
// // current_dir: directory of the current page (e.g., '' for root, 'tokens' for tokens/, 'farming/advanced' for nested)
// // target_dir: directory of the target page
// // page_name: name of the target page
// // Returns: relative path (e.g., './page', '../dir/page', '../../page')
// fn calculate_relative_path(current_dir string, target_dir string, page_name string) string {
// // Both at root level
// if current_dir == '' && target_dir == '' {
// return './${page_name}'
// }
// // Current at root, target in subdirectory
// if current_dir == '' && target_dir != '' {
// return './${target_dir}/${page_name}'
// }
// // Current in subdirectory, target at root
// if current_dir != '' && target_dir == '' {
// // Count directory levels to go up
// levels := current_dir.split('/').len
// up := '../'.repeat(levels)
// return '${up}${page_name}'
// }
// // Both in subdirectories
// current_parts := current_dir.split('/')
// target_parts := target_dir.split('/')
// // Find common prefix
// mut common_len := 0
// for i := 0; i < current_parts.len && i < target_parts.len; i++ {
// if current_parts[i] == target_parts[i] {
// common_len++
// } else {
// break
// }
// }
// // Calculate how many levels to go up
// up_levels := current_parts.len - common_len
// mut path_parts := []string{}
// // Add ../ for each level up
// for _ in 0 .. up_levels {
// path_parts << '..'
// }
// // Add remaining target path parts
// for i in common_len .. target_parts.len {
// path_parts << target_parts[i]
// }
// // Add page name
// path_parts << page_name
// return path_parts.join('/')
// }
// // Fix links to account for nested categories and Docusaurus URL conventions
// fn (generator SiteGenerator) fix_links(content string, current_page_path string) string {
// mut result := content
// // Extract current page's directory path
// mut current_dir := current_page_path.trim('/')
// if current_dir.contains('/') && !current_dir.ends_with('/') {
// last_part := current_dir.all_after_last('/')
// if last_part.contains('.') {
// current_dir = current_dir.all_before_last('/')
// }
// }
// // If path is just a filename or empty, current_dir should be empty (root level)
// if !current_dir.contains('/') && current_dir.contains('.') {
// current_dir = ''
// }
// // Build maps for link fixing
// mut collection_paths := map[string]string{} // collection -> directory path (for nested collections)
// mut page_to_path := map[string]string{} // page_name -> full directory path in Docusaurus
// mut collection_page_map := map[string]string{} // "collection:page" -> directory path
// for page in generator.site.pages {
// parts := page.src.split(':')
// if parts.len != 2 {
// continue
// }
// collection := parts[0]
// page_name := parts[1]
// // Extract directory path from page.path
// mut dir_path := page.path.trim('/')
// if dir_path.contains('/') && !dir_path.ends_with('/') {
// last_part := dir_path.all_after_last('/')
// if last_part.contains('.') || last_part == page_name {
// dir_path = dir_path.all_before_last('/')
// }
// }
// // Store collection -> directory mapping for nested collections
// if dir_path != collection && dir_path != '' {
// collection_paths[collection] = dir_path
// }
// // Store page_name -> directory path for fixing same-collection links
// // Strip numeric prefix from page_name for the map key
// clean_page_name := strip_numeric_prefix(page_name)
// page_to_path[clean_page_name] = dir_path
// // Store collection:page -> directory path for fixing collection:page format links
// collection_page_map['${collection}:${clean_page_name}'] = dir_path
// }
// // STEP 1: Strip numeric prefixes from all page references in links FIRST
// mut lines := result.split('\n')
// for i, line in lines {
// if !line.contains('](') {
// continue
// }
// mut new_line := line
// parts := line.split('](')
// if parts.len < 2 {
// continue
// }
// for j := 1; j < parts.len; j++ {
// close_idx := parts[j].index(')') or { continue }
// link_url := parts[j][..close_idx]
// mut new_url := link_url
// if link_url.contains('/') {
// path_part := link_url.all_before_last('/')
// file_part := link_url.all_after_last('/')
// new_file := strip_numeric_prefix(file_part)
// if new_file != file_part {
// new_url = '${path_part}/${new_file}'
// }
// } else {
// new_url = strip_numeric_prefix(link_url)
// }
// if new_url != link_url {
// new_line = new_line.replace('](${link_url})', '](${new_url})')
// }
// }
// lines[i] = new_line
// }
// result = lines.join('\n')
// // STEP 2: Replace ../collection/ with ../actual/nested/path/ for cross-collection links
// for collection, actual_path in collection_paths {
// result = result.replace('../${collection}/', '../${actual_path}/')
// }
// // STEP 3: Fix same-collection links: ./page -> correct path based on Docusaurus structure
// for page_name, target_dir in page_to_path {
// old_link := './${page_name}'
// if result.contains(old_link) {
// new_link := calculate_relative_path(current_dir, target_dir, page_name)
// result = result.replace(old_link, new_link)
// }
// }
// // STEP 4: Convert collection:page format to proper relative paths
// // Calculate relative path from current page to target page
// for collection_page, target_dir in collection_page_map {
// old_pattern := collection_page
// if result.contains(old_pattern) {
// // Extract just the page name from "collection:page"
// page_name := collection_page.all_after(':')
// new_link := calculate_relative_path(current_dir, target_dir, page_name)
// result = result.replace(old_pattern, new_link)
// }
// }
// // STEP 5: Fix bare page references (from atlas self-contained exports)
// // Atlas exports convert cross-collection links to simple relative links like "token_system2.md"
// // We need to transform these to proper relative paths based on Docusaurus structure
// for page_name, target_dir in page_to_path {
// // Match links in the format ](page_name) or ](page_name.md)
// old_link_with_md := '](${page_name}.md)'
// old_link_without_md := '](${page_name})'
// if result.contains(old_link_with_md) || result.contains(old_link_without_md) {
// new_link := calculate_relative_path(current_dir, target_dir, page_name)
// // Replace both .md and non-.md versions
// result = result.replace(old_link_with_md, '](${new_link})')
// result = result.replace(old_link_without_md, '](${new_link})')
// }
// }
// // STEP 6: Remove .md extensions from all remaining links (Docusaurus doesn't use them in URLs)
// result = result.replace('.md)', ')')
// // STEP 7: Fix image links to point to img/ subdirectory
// // Images are copied to img/ subdirectory by copy_images(), so we need to update the links
// // Transform ![alt](image.png) to ![alt](img/image.png) for local images only
// mut image_lines := result.split('\n')
// for i, line in image_lines {
// // Find image links: ![...](...) but skip external URLs
// if line.contains('![') {
// mut pos := 0
// for {
// img_start := line.index_after('![', pos) or { break }
// alt_end := line.index_after(']', img_start) or { break }
// if alt_end + 1 >= line.len || line[alt_end + 1] != `(` {
// pos = alt_end + 1
// continue
// }
// url_start := alt_end + 2
// url_end := line.index_after(')', url_start) or { break }
// url := line[url_start..url_end]
// // Skip external URLs and already-prefixed img/ paths
// if url.starts_with('http://') || url.starts_with('https://')
// || url.starts_with('img/') || url.starts_with('./img/') {
// pos = url_end + 1
// continue
// }
// // Skip absolute paths and paths with ../
// if url.starts_with('/') || url.starts_with('../') {
// pos = url_end + 1
// continue
// }
// // This is a local image reference - add img/ prefix
// new_url := 'img/${url}'
// image_lines[i] = line[0..url_start] + new_url + line[url_end..]
// break
// }
// }
// }
// result = image_lines.join('\n')
// return result
// }