feat: Refactor docusaurus playbook and sidebar JSON serialization

- Extract playbook action processing into separate functions
- Add auto-export for Atlas collections
- Simplify sidebar JSON serialization
- Update sidebar navigation item structure
This commit is contained in:
Mahmoud-Emad
2025-11-30 17:31:41 +02:00
parent 0ca87c5f32
commit e2c2a560c8
3 changed files with 259 additions and 126 deletions

View File

@@ -1,26 +1,139 @@
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.atlas.client as atlas_client
import incubaid.herolib.data.markdown.tools as markdowntools
import incubaid.herolib.ui.console
import incubaid.herolib.web.site
import os
// Generate docs from site configuration
// ============================================================================
// Doc Linking - Generate Docusaurus docs from Atlas collections
// ============================================================================
// link_docs generates markdown files from site page definitions.
// Pages are fetched from Atlas collections and written with frontmatter.
pub fn (mut docsite DocSite) link_docs() ! {
c := config()!
// we generate the docs in the build path
docs_path := '${c.path_build.path}/docs'
//reset it
os.rmdir_all(docs_path)!
os.mkdir(docs_path)!
reset_docs_dir(docs_path)!
console.print_header('Linking docs to ${docs_path}')
//TODO: now link all the collections to the docs folder
mut client := atlas_client.new(export_dir: c.atlas_dir)!
mut errors := []string{}
println(c)
for _, page in docsite.website.pages {
process_page(mut client, docs_path, page, mut errors)
}
$dbg;
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 atlas_client.AtlasClient, 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 atlas_client.AtlasClient, docs_path string, page site.Page, 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
}
write_page(docs_path, page_name, page, content) 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) ! {
frontmatter := build_frontmatter(page, content)
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 atlas_client.AtlasClient, 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) string {
title := get_title(page, content)
description := get_description(page, title)
mut lines := ['---']
lines << "title: '${escape_yaml(title)}'"
lines << "description: '${escape_yaml(description)}'"
if page.draft {
lines << 'draft: true'
}
if page.hide_title {
lines << 'hide_title: true'
}
lines << '---'
return lines.join('\n')
}
fn get_title(page site.Page, content string) string {
if page.title.len > 0 {
return page.title
}
extracted := markdowntools.extract_title(content)
if extracted.len > 0 {
return extracted
}
return page.src.split(':').last()
}
fn get_description(page site.Page, title string) string {
if page.description.len > 0 {
return page.description
}
return title
}
fn escape_yaml(s string) string {
return s.replace("'", "''")
}

View File

@@ -1,6 +1,8 @@
module docusaurus
import incubaid.herolib.core.playbook { PlayBook }
import incubaid.herolib.data.atlas
import incubaid.herolib.ui.console
import os
pub fn play(mut plbook PlayBook) ! {
@@ -8,61 +10,78 @@ pub fn play(mut plbook PlayBook) ! {
return
}
// there should be 1 define section
mut action_define := plbook.ensure_once(filter: 'docusaurus.define')!
mut param_define := action_define.params
config_set(
path_build: param_define.get_default('path_build', '')!
path_publish: param_define.get_default('path_publish', '')!
reset: param_define.get_default_false('reset')
template_update: param_define.get_default_false('template_update')
install: param_define.get_default_false('install')
atlas_dir: param_define.get_default('atlas_dir', '${os.home_dir()}/hero/var/atlas_export')!
)!
site_name := param_define.get('name') or {
return error('In docusaurus.define, param "name" is required.')
}
dsite_define(site_name)!
action_define.done = true
mut dsite := dsite_get(site_name)!
mut dsite := process_define(mut plbook)!
dsite.generate()!
mut actions_build := plbook.find(filter: 'docusaurus.build')!
if actions_build.len > 1 {
return error('Multiple "docusaurus.build" actions found. Only one is allowed.')
}
for mut action in actions_build {
dsite.build()!
action.done = true
}
mut actions_export := plbook.find(filter: 'docusaurus.publish')!
if actions_export.len > 1 {
return error('Multiple "docusaurus.publish" actions found. Only one is allowed.')
}
for mut action in actions_export {
dsite.build_publish()!
action.done = true
}
mut actions_dev := plbook.find(filter: 'docusaurus.dev')!
if actions_dev.len > 1 {
return error('Multiple "docusaurus.dev" actions found. Only one is allowed.')
}
for mut action in actions_dev {
mut p := action.params
dsite.dev(
host: p.get_default('host', 'localhost')!
port: p.get_int_default('port', 3000)!
open: p.get_default_false('open')
)!
action.done = true
}
process_build(mut plbook, mut dsite)!
process_publish(mut plbook, mut dsite)!
process_dev(mut plbook, mut dsite)!
plbook.ensure_processed(filter: 'docusaurus.')!
}
fn process_define(mut plbook PlayBook) !&DocSite {
mut action := plbook.ensure_once(filter: 'docusaurus.define')!
p := action.params
atlas_dir := p.get_default('atlas_dir', '${os.home_dir()}/hero/var/atlas_export')!
config_set(
path_build: p.get_default('path_build', '')!
path_publish: p.get_default('path_publish', '')!
reset: p.get_default_false('reset')
template_update: p.get_default_false('template_update')
install: p.get_default_false('install')
atlas_dir: atlas_dir
)!
site_name := p.get('name') or { return error('docusaurus.define: "name" is required') }
atlas_name := p.get_default('atlas', 'main')!
export_atlas(atlas_name, atlas_dir)!
dsite_define(site_name)!
action.done = true
return dsite_get(site_name)!
}
fn process_build(mut plbook PlayBook, mut dsite DocSite) ! {
if !plbook.max_once(filter: 'docusaurus.build')! {
return
}
mut action := plbook.get(filter: 'docusaurus.build')!
dsite.build()!
action.done = true
}
fn process_publish(mut plbook PlayBook, mut dsite DocSite) ! {
if !plbook.max_once(filter: 'docusaurus.publish')! {
return
}
mut action := plbook.get(filter: 'docusaurus.publish')!
dsite.build_publish()!
action.done = true
}
fn process_dev(mut plbook PlayBook, mut dsite DocSite) ! {
if !plbook.max_once(filter: 'docusaurus.dev')! {
return
}
mut action := plbook.get(filter: 'docusaurus.dev')!
p := action.params
dsite.dev(
host: p.get_default('host', 'localhost')!
port: p.get_int_default('port', 3000)!
open: p.get_default_false('open')
)!
action.done = true
}
fn export_atlas(name string, dir string) ! {
if !atlas.exists(name) {
return
}
console.print_debug('Auto-exporting Atlas "${name}" to ${dir}')
mut a := atlas.get(name)!
a.export(destination: dir, reset: true, include: true, redis: false)!
}