This commit is contained in:
2025-10-26 22:24:18 +04:00
parent 9d1c347da7
commit 46ce903d4d
8 changed files with 126 additions and 57 deletions

View File

@@ -6,4 +6,7 @@
!!atlas.scan
git_url: 'https://git.ourworld.tf/tfgrid/docs_tfgrid4/src/branch/main/collections/authentic_web'
// !!atlas.scan
// git_url: 'https://git.ourworld.tf/geomind/docs_geomind/src/branch/main/collections/usecases'
!!atlas.export destination: '/tmp/atlas_export'

View File

@@ -38,7 +38,7 @@ fn (mut self Atlas) add_collection(mut path pathlib.Path) !Collection {
error_cache: map[string]bool{}
}
c.init()!
c.init_pre()!
self.collections[name] = &c
@@ -56,16 +56,9 @@ pub fn (a Atlas) get_collection(name string) !&Collection {
}
// Validate all links in all collections
pub fn (mut a Atlas) validate_links() ! {
pub fn (mut a Atlas) init_post() ! {
for _, mut col in a.collections {
col.validate_links()!
}
}
// Fix all links in all collections
pub fn (mut a Atlas) fix_links() ! {
for _, mut col in a.collections {
col.fix_links()!
col.init_post()!
}
}
@@ -97,12 +90,6 @@ pub fn (a Atlas) groups_get(session Session) []&Group {
return matching
}
pub fn (mut a Atlas) validate() ! {
a.validate_links()!
a.fix_links()!
}
//////////////////SCAN
// Scan a path for collections

View File

@@ -1,7 +1,7 @@
module atlas
import incubaid.herolib.core.pathlib
import incubaid.herolib.core.texttools
// import incubaid.herolib.core.texttools
import incubaid.herolib.develop.gittools
import incubaid.herolib.data.paramsparser { Params }
import incubaid.herolib.ui.console
@@ -34,12 +34,18 @@ pub fn (mut c Collection) path() !pathlib.Path {
return pathlib.get_dir(path: c.path, create: false)!
}
fn (mut c Collection) init() ! {
fn (mut c Collection) init_pre() ! {
mut p := mut c.path()!
c.scan(mut p)!
c.scan_acl()!
}
fn (mut c Collection) init_post() ! {
c.validate_links()!
c.init_git_info()!
}
////////////////////////////////////////////////////////////////////////////////////////////////////////
// Add a page to the collection
@@ -62,7 +68,7 @@ fn (mut c Collection) add_page(mut path pathlib.Path) ! {
// Add an image to the collection
fn (mut c Collection) add_file(mut p pathlib.Path) ! {
name := p.name_fix_no_ext()
name := p.name_fix_keepext()
if name in c.files {
return error('Page ${name} already exists in collection ${c.name}')
}
@@ -115,6 +121,15 @@ pub fn (c Collection) file_get(name string) !&File {
return f
}
pub fn (c Collection) file_or_image_get(name string) !&File {
mut f := c.files[name] or { return FileNotFound{
collection: c.name
file: name
} }
return f
}
// Check if page exists
pub fn (c Collection) page_exists(name string) bool {
return name in c.pages
@@ -132,6 +147,14 @@ pub fn (c Collection) file_exists(name string) bool {
return f.ftype == .file
}
pub fn (c Collection) file_or_image_exists(name string) bool {
f := c.files[name] or { return false }
return true
}
@[params]
pub struct CollectionErrorArgs {
pub mut:
@@ -220,7 +243,7 @@ pub fn (c Collection) print_errors() {
pub fn (mut c Collection) validate_links() ! {
for _, mut page in c.pages {
content := page.content(include: true)!
page.find_links(content)! // will walk over links see if errors and add errors
page.links=page.find_links(content)! // will walk over links see if errors and add errors
}
}

View File

@@ -8,6 +8,7 @@ pub enum CollectionErrorCategory {
missing_include
include_syntax_error
invalid_page_reference
invalid_file_reference
file_not_found
invalid_collection
general_error
@@ -55,6 +56,7 @@ pub fn (e CollectionError) category_str() string {
.missing_include { 'Missing Include' }
.include_syntax_error { 'Include Syntax Error' }
.invalid_page_reference { 'Invalid Page Reference' }
.invalid_file_reference { 'Invalid File Reference' }
.file_not_found { 'File Not Found' }
.invalid_collection { 'Invalid Collection' }
.general_error { 'General Error' }

View File

@@ -23,7 +23,7 @@ pub fn (mut a Atlas) export(args ExportArgs) ! {
}
// Validate links before export
a.validate_links()!
// a.validate_links()!
for _, mut col in a.collections {
col.export(
@@ -61,7 +61,7 @@ pub fn (mut c Collection) export(args CollectionExportArgs) ! {
col_dir_meta.empty()!
}
c.init_git_info()!
if c.has_errors() {
c.print_errors()

View File

@@ -33,6 +33,16 @@ pub fn (a Atlas) file_get(key string) !&File {
return col.file_get(parts[1])!
}
// Get a file (can be image) from any collection using format "collection:file"
pub fn (a Atlas) file_or_image_get(key string) !&File {
parts := key.split(':')
if parts.len != 2 {
return error('Invalid file key format. Use "collection:file"')
}
col := a.get_collection(parts[0])!
return col.file_or_image_get(parts[1])!
}
// Check if page exists
pub fn (a Atlas) page_exists(key string) bool {
parts := key.split(':')
@@ -66,6 +76,16 @@ pub fn (a Atlas) file_exists(key string) bool {
return col.file_exists(parts[1])
}
pub fn (a Atlas) file_or_image_exists(key string) bool {
parts := key.split(':')
if parts.len != 2 {
return false
}
col := a.get_collection(parts[0]) or { return false }
return col.file_or_image_exists(parts[1])
}
// List all pages in Atlas
pub fn (a Atlas) list_pages() map[string][]string {
mut result := map[string][]string{}

View File

@@ -11,24 +11,23 @@ pub mut:
target string // Original link target (the source text)
line int // Line number where link was found
target_collection_name string
target_page_name string
target_item_name string
status LinkStatus
is_file_link bool // is the link pointing to a file
page &Page @[skip; str: skip] // Reference to page where this link is found
}
pub enum LinkStatus {
init
external
page_found
page_not_found
file_found
file_not_found
found
not_found
anchor
error
}
fn (mut self Link) key() string {
return '${self.target_collection_name}:${self.target_page_name}'
return '${self.target_collection_name}:${self.target_item_name}'
}
// is the link in the same collection as the page containing the link
@@ -57,6 +56,8 @@ fn (mut p Page) find_links(content string) ![]Link {
for line_idx, line in lines {
mut pos := 0
for {
mut image_open := line.index_after('!', pos) or { break }
// Find next [
open_bracket := line.index_after('[', pos) or { break }
@@ -69,6 +70,10 @@ fn (mut p Page) find_links(content string) ![]Link {
continue
}
if image_open + 1 != open_bracket {
image_open = -1
}
// Find matching )
open_paren := close_bracket + 1
close_paren := line.index_after(')', open_paren) or { break }
@@ -77,11 +82,14 @@ fn (mut p Page) find_links(content string) ![]Link {
text := line[open_bracket + 1..close_bracket]
target := line[open_paren + 1..close_paren]
islink_file_link := (image_open != -1)
mut link := Link{
src: line[open_bracket..close_paren + 1]
text: text
target: target.trim_space()
line: line_idx + 1
is_file_link: islink_file_link
page: &p
}
@@ -96,7 +104,7 @@ fn (mut p Page) find_links(content string) ![]Link {
// Parse link target to extract collection and page
fn (mut p Page) parse_link_target(mut link Link) {
target := link.target
mut target := link.target
// Skip external links
if target.starts_with('http://') || target.starts_with('https://')
@@ -111,28 +119,43 @@ fn (mut p Page) parse_link_target(mut link Link) {
return
}
if target.contains('/') {
parts9 := target.split('/')
if parts9.len >= 1 {
target = parts9[1]
}
}
// Format: $collection:$pagename or $collection:$pagename.md
if target.contains(':') {
parts := target.split(':')
if parts.len >= 2 {
link.target_collection_name = texttools.name_fix(parts[0])
link.target_page_name = normalize_page_name(parts[1])
link.target_item_name = normalize_page_name(parts[1])
}
} else {
link.target_page_name = normalize_page_name(target).trim_space()
link.target_item_name = normalize_page_name(target).trim_space()
link.target_collection_name = p.collection.name
}
if !p.collection.atlas.page_exists(link.key()) {
if link.is_file_link == false && !p.collection.atlas.page_exists(link.key()) {
p.collection.error(
category: .invalid_page_reference
page_key: p.key()
message: 'Broken link to `${link.key()}` at line ${link.line}: `${link.src}`'
show_console: false
show_console: true
)
link.status = .page_not_found
link.status = .not_found
} else if link.is_file_link && !p.collection.atlas.file_or_image_exists(link.key()) {
p.collection.error(
category: .invalid_file_reference
page_key: p.key()
message: 'Broken file link to `${link.key()}` at line ${link.line}: `${link.src}`'
show_console: true
)
link.status = .not_found
} else {
link.status = .page_found
link.status = .found
}
}
@@ -148,7 +171,7 @@ fn (mut p Page) content_with_fixed_links() !string {
// Process links in reverse order to maintain positions
for mut link in p.links.reverse() {
// if page not existing no point in fixing
if link.status != .page_found {
if link.status != .found {
continue
}
// if not local then no point in fixing
@@ -183,7 +206,7 @@ fn (mut p Page) process_cross_collection_links(mut export_dir pathlib.Path) !str
// Process links in reverse order to maintain string positions
for mut link in links.reverse() {
if link.status != .page_found {
if link.status != .found {
continue
}
mut target_page := link.target_page()!
@@ -206,11 +229,11 @@ fn (mut p Page) process_cross_collection_links(mut export_dir pathlib.Path) !str
panic('need to do for files too')
}
for mut link in links.reverse() {
if link.status != . {
continue
}
}
// for mut link in links.reverse() {
// if link.status != . {
// continue
// }
// }
return c
}

View File

@@ -12,11 +12,13 @@ pub fn play(mut plbook PlayBook) ! {
mut atlases := map[string]&Atlas{}
mut name := ""
// Process scan actions - scan directories for collections
mut scan_actions := plbook.find(filter: 'atlas.scan')!
for mut action in scan_actions {
mut p := action.params
name := p.get_default('name', 'main')!
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
@@ -48,13 +50,22 @@ pub fn play(mut plbook PlayBook) ! {
set(atlas_instance)
}
mut atlas_instance_post := atlases[name] or {
return error("Atlas '${name}' not found. Use !!atlas.scan first.")
}
atlas_instance_post.init_post()!
println(atlas_instance_post)
// Process export actions - export collections to destination
mut export_actions := plbook.find(filter: 'atlas.export')!
// Process explicit export actions
for mut action in export_actions {
mut p := action.params
name := p.get_default('name', 'main')!
name = p.get_default('name', 'main')!
destination := p.get('destination')!
reset := p.get_default_true('reset')
include := p.get_default_true('include')