refactor: Remove docusaurus dev server and path_meta flag

- Remove 'dev' flag from run command
- Remove 'path_meta' flag from run command
- Remove docusaurus integration from playcmds
- Add `validate_links` and `fix_links` to Atlas
- Refactor page link processing for clarity and export mode
This commit is contained in:
Mahmoud-Emad
2025-11-05 15:25:50 +02:00
parent a2ac8c0027
commit 04e1e2375f
7 changed files with 128 additions and 142 deletions

View File

@@ -63,6 +63,20 @@ pub fn (mut a Atlas) init_post() ! {
}
}
// Validate all links in all collections
pub fn (mut a Atlas) validate_links() ! {
for _, mut col in a.collections {
col.validate_links()!
}
}
// Fix all links in all collections (rewrite source files)
pub fn (mut a Atlas) fix_links() ! {
for _, mut col in a.collections {
col.fix_links()!
}
}
// Add a group to the atlas
pub fn (mut a Atlas) group_add(mut group Group) ! {
if group.name in a.groups {

View File

@@ -68,13 +68,15 @@ pub fn (mut c Collection) export(args CollectionExportArgs) ! {
json_file.write(meta)!
for _, mut page in c.pages {
content := page.content(include: args.include)!
// NEW: Process cross-collection links
processed_content := page.process_links(mut col_dir)!
// Get content with includes processed and links transformed for export
content := page.content_with_fixed_links(
include: args.include
cross_collection: true
export_mode: true
)!
mut dest_file := pathlib.get_file(path: '${col_dir.path}/${page.name}.md', create: true)!
dest_file.write(processed_content)!
dest_file.write(content)!
// Redis operations...
if args.redis {

View File

@@ -19,19 +19,20 @@ pub mut:
pub fn new(args AtlasNewArgs) !&Atlas {
mut name := texttools.name_fix(args.name)
mut a := Atlas{
mut a := &Atlas{
name: name
}
set(a)
return &a
return a
}
// Get Atlas from global map
pub fn get(name string) !&Atlas {
mut fixed_name := texttools.name_fix(name)
rlock atlases {
if name in atlases {
return atlases[name] or { return error('Atlas ${name} not found') }
if fixed_name in atlases {
return atlases[fixed_name] or { return error('Atlas ${name} not found') }
}
}
return error("Atlas '${name}' not found")
@@ -39,8 +40,9 @@ pub fn get(name string) !&Atlas {
// Check if Atlas exists
pub fn exists(name string) bool {
mut fixed_name := texttools.name_fix(name)
rlock atlases {
return name in atlases
return fixed_name in atlases
}
}
@@ -52,8 +54,8 @@ pub fn list() []string {
}
// Store Atlas in global map
fn set(atlas Atlas) {
fn set(atlas &Atlas) {
lock atlases {
atlases[atlas.name] = &atlas
atlases[atlas.name] = atlas
}
}

View File

@@ -1,8 +1,6 @@
module atlas
import incubaid.herolib.core.texttools
import incubaid.herolib.core.pathlib
import os
// Link represents a markdown link found in content
pub struct Link {
@@ -10,7 +8,8 @@ pub mut:
src string // Source content where link was found (what to replace)
text string // Link text [text]
target string // Original link target (the source text)
line int // Line number where link was found
line int // Line number where link was found (1-based)
pos int // Character position in line where link starts (0-based)
target_collection_name string
target_item_name string
status LinkStatus
@@ -103,11 +102,15 @@ fn (mut p Page) find_links(content string) ![]Link {
is_image_link = false // means it's a file link, not an image link
}
// Store position - use image_open if it's an image, otherwise open_bracket
link_start_pos := if is_image_link { image_open } else { open_bracket }
mut link := Link{
src: line[open_bracket..close_paren + 1]
text: text
target: target.trim_space()
line: line_idx + 1
pos: link_start_pos
is_file_link: is_file_link
is_image_link: is_image_link
page: &p
@@ -185,88 +188,96 @@ fn (mut p Page) parse_link_target(mut link Link) {
////////////////FIX PAGES FOR THE LINKS///////////////////////
@[params]
pub struct FixLinksArgs {
include bool // Process includes before fixing links
cross_collection bool // Process cross-collection links (for export)
export_mode bool // Use export-style simple paths instead of filesystem paths
}
// Fix links in page content - rewrites links with proper relative paths
fn (mut p Page) content_with_fixed_links() !string {
mut content := p.content(include: false)!
if p.links.len == 0 {
return content
fn (mut p Page) content_with_fixed_links(args FixLinksArgs) !string {
mut content := p.content(include: args.include)!
// Get links - either re-find them (if includes processed) or use cached
mut links := if args.include {
p.find_links(content)! // Re-find links in processed content
} else {
p.links // Use cached links from validation
}
// Process links in reverse order to maintain positions
for mut link in p.links.reverse() {
// if page not existing no point in fixing
// Filter and transform links
for mut link in links {
// Skip invalid links
if link.status != .found {
continue
}
// if not local then no point in fixing
if !link.is_local_in_collection() {
// Skip cross-collection links unless enabled
if !args.cross_collection && !link.is_local_in_collection() {
continue
}
// Get target page
mut target_page := link.target_page()!
mut target_path := target_page.path()!
relative_path := target_path.path_relative(p.path()!.path)!
// Calculate new link path
new_link := p.calculate_link_path(mut link, args) or { continue }
new_link := '[${link.text}](${relative_path})'
// Build the complete link markdown
prefix := if link.is_file_link { '!' } else { '' }
new_link_md := '${prefix}[${link.text}](${new_link})'
// Replace in content
content = content.replace(link.src, new_link)
content = content.replace(link.src, new_link_md)
}
return content
}
// process_cross_collection_links handles exporting cross-collection references
// It:
// 1. Finds all cross-collection links (collection:page format)
// 2. Copies the target page to the export directory
// 3. Renames the link to avoid conflicts (collectionname_pagename.md)
// 4. Rewrites the link in the content
fn (mut p Page) process_links(mut export_dir pathlib.Path) !string {
mut c := p.content(include: true)!
// calculate_link_path returns the relative path for a link
fn (mut p Page) calculate_link_path(mut link Link, args FixLinksArgs) !string {
if args.export_mode {
// Export mode: simple flat structure
return p.export_link_path(mut link)!
}
// Fix mode: filesystem paths
return p.filesystem_link_path(mut link)!
}
mut links := p.find_links(c)!
// export_link_path calculates path for export (flat structure: collection/file.md)
fn (mut p Page) export_link_path(mut link Link) !string {
mut target_collection := ''
mut target_filename := ''
// Process links in reverse order to maintain string positions
for mut link in links.reverse() {
if link.status != .found {
continue
}
mut exported_filename := ''
if link.is_file_link {
mut target_file := link.target_file()!
mut target_path := target_file.path()!
// Copy target page with renamed filename
exported_filename = 'files/${target_file.collection.name}_${target_file.name}'
os.mkdir_all('${export_dir.path}/files')!
os.cp(target_path.path, '${export_dir.path}/${exported_filename}')!
} else {
mut target_page := link.target_page()!
mut target_path := target_page.path()!
// Copy target page with renamed filename
exported_filename = '${target_page.collection.name}_${target_page.name}.md'
page_content := target_page.content(include: true)!
mut exported_file := pathlib.get_file(
path: '${export_dir.path}/${exported_filename}'
create: true
)!
exported_file.write(page_content)!
}
mut pre := ''
if link.is_file_link {
pre = '!'
}
// Update link in source content
new_link := '${pre}[${link.text}](${exported_filename})'
c = c.replace(link.src, new_link)
if link.is_file_link {
mut tf := link.target_file()!
target_collection = tf.collection.name
target_filename = tf.name
} else {
mut tp := link.target_page()!
target_collection = tp.collection.name
target_filename = '${tp.name}.md'
}
return c
// Same collection: just filename, different collection: ../collection/filename
return if link.is_local_in_collection() {
target_filename
} else {
'../${target_collection}/${target_filename}'
}
}
// filesystem_link_path calculates path using actual filesystem paths
fn (mut p Page) filesystem_link_path(mut link Link) !string {
source_path := p.path()!
mut target_path := if link.is_file_link {
mut tf := link.target_file()!
tf.path()!
} else {
mut tp := link.target_page()!
tp.path()!
}
return target_path.path_relative(source_path.path)!
}
/////////////TOOLS//////////////////////////////////

View File

@@ -10,7 +10,8 @@ pub fn play(mut plbook PlayBook) ! {
return
}
mut atlases := map[string]&Atlas{}
// Track which atlases we've processed in this playbook
mut processed_atlases := map[string]bool{}
mut name := ''
@@ -20,14 +21,15 @@ pub fn play(mut plbook PlayBook) ! {
mut p := action.params
name = p.get_default('name', 'main')!
ignore := p.get_list_default('ignore', [])!
console.print_item("Scanning Atlas '${name}' with ignore patterns: ${ignore}\n${p}")
// Get or create atlas
mut atlas_instance := atlases[name] or {
console.print_item("Scanning Atlas '${name}' with ignore patterns: ${ignore}")
// Get or create atlas from global map
mut atlas_instance := if exists(name) {
get(name)!
} else {
console.print_debug('Atlas not found, creating a new one')
mut new_atlas := new(name: name)!
atlases[name] = new_atlas
new_atlas
new(name: name)!
}
processed_atlases[name] = true
mut path := p.get_default('path', '')!
@@ -47,15 +49,16 @@ pub fn play(mut plbook PlayBook) ! {
atlas_instance.scan(path: path, ignore: ignore)!
action.done = true
set(atlas_instance)
// No need to call set() again - atlas is already in global map from new()
// and we're modifying it by reference
}
mut atlas_instance_post := atlases[name] or {
return error("Atlas '${name}' not found. Use !!atlas.scan first.")
// Run init_post on all processed atlases
for atlas_name, _ in processed_atlases {
mut atlas_instance_post := get(atlas_name)!
atlas_instance_post.init_post()!
}
atlas_instance_post.init_post()!
// Process export actions - export collections to destination
mut export_actions := plbook.find(filter: 'atlas.export')!
@@ -68,7 +71,7 @@ pub fn play(mut plbook PlayBook) ! {
include := p.get_default_true('include')
redis := p.get_default_true('redis')
mut atlas_instance := atlases[name] or {
mut atlas_instance := get(name) or {
return error("Atlas '${name}' not found. Use !!atlas.scan first.")
}